summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortnn <tnn>2008-05-23 17:15:14 +0000
committertnn <tnn>2008-05-23 17:15:14 +0000
commit9ccf1cb51c7b5103e05fcad024018dff64ecaa5c (patch)
treea7ba750f0b8b832b526df15d6fa2caa48e8927e0
parenteb251400c83183cc86a281508938084246f4c3ef (diff)
downloadpkgsrc-MRENDEL.tar.gz
Import subset of pdksh-5.2.14 distribution.MRENDEL
Only the files required to build it, for pkgsrc bootstrap purposes.
-rw-r--r--shells/pdksh/files/LEGAL34
-rw-r--r--shells/pdksh/files/Makefile.in330
-rw-r--r--shells/pdksh/files/acconfig.h185
-rw-r--r--shells/pdksh/files/aclocal.m41365
-rw-r--r--shells/pdksh/files/alloc.c776
-rw-r--r--shells/pdksh/files/c_ksh.c1471
-rw-r--r--shells/pdksh/files/c_sh.c904
-rw-r--r--shells/pdksh/files/c_test.c662
-rw-r--r--shells/pdksh/files/c_test.h53
-rw-r--r--shells/pdksh/files/c_ulimit.c271
-rw-r--r--shells/pdksh/files/check-fd.c89
-rw-r--r--shells/pdksh/files/check-pgrp.c101
-rw-r--r--shells/pdksh/files/check-sigs.c255
-rw-r--r--shells/pdksh/files/conf-end.h55
-rw-r--r--shells/pdksh/files/config.h.in360
-rwxr-xr-xshells/pdksh/files/configure4447
-rw-r--r--shells/pdksh/files/configure.in328
-rw-r--r--shells/pdksh/files/edit.c1021
-rw-r--r--shells/pdksh/files/edit.h84
-rwxr-xr-xshells/pdksh/files/emacs-gen.sh43
-rw-r--r--shells/pdksh/files/emacs.c2201
-rw-r--r--shells/pdksh/files/eval.c1376
-rw-r--r--shells/pdksh/files/exec.c1687
-rw-r--r--shells/pdksh/files/expand.h106
-rw-r--r--shells/pdksh/files/expr.c605
-rw-r--r--shells/pdksh/files/history.c1190
-rwxr-xr-xshells/pdksh/files/install-sh119
-rw-r--r--shells/pdksh/files/io.c551
-rw-r--r--shells/pdksh/files/jobs.c1874
-rw-r--r--shells/pdksh/files/ksh.Man3532
-rw-r--r--shells/pdksh/files/ksh_dir.h25
-rw-r--r--shells/pdksh/files/ksh_limval.h23
-rw-r--r--shells/pdksh/files/ksh_stat.h58
-rw-r--r--shells/pdksh/files/ksh_time.h25
-rw-r--r--shells/pdksh/files/ksh_times.h18
-rw-r--r--shells/pdksh/files/ksh_wait.h50
-rw-r--r--shells/pdksh/files/lex.c1393
-rw-r--r--shells/pdksh/files/lex.h130
-rw-r--r--shells/pdksh/files/mail.c194
-rw-r--r--shells/pdksh/files/main.c841
-rw-r--r--shells/pdksh/files/misc.c1345
-rw-r--r--shells/pdksh/files/missing.c293
-rwxr-xr-xshells/pdksh/files/mkman44
-rw-r--r--shells/pdksh/files/path.c348
-rw-r--r--shells/pdksh/files/proto.h300
-rw-r--r--shells/pdksh/files/sh.h744
-rw-r--r--shells/pdksh/files/shf.c1294
-rw-r--r--shells/pdksh/files/shf.h85
-rw-r--r--shells/pdksh/files/sigact.c482
-rw-r--r--shells/pdksh/files/sigact.h129
-rw-r--r--shells/pdksh/files/siglist.in55
-rwxr-xr-xshells/pdksh/files/siglist.sh41
-rw-r--r--shells/pdksh/files/stamp-h.in1
-rw-r--r--shells/pdksh/files/syn.c945
-rw-r--r--shells/pdksh/files/table.c237
-rw-r--r--shells/pdksh/files/table.h181
-rw-r--r--shells/pdksh/files/trap.c433
-rw-r--r--shells/pdksh/files/tree.c758
-rw-r--r--shells/pdksh/files/tree.h140
-rw-r--r--shells/pdksh/files/tty.c177
-rw-r--r--shells/pdksh/files/tty.h108
-rw-r--r--shells/pdksh/files/var.c1229
-rw-r--r--shells/pdksh/files/version.c8
-rw-r--r--shells/pdksh/files/vi.c2173
64 files changed, 40382 insertions, 0 deletions
diff --git a/shells/pdksh/files/LEGAL b/shells/pdksh/files/LEGAL
new file mode 100644
index 00000000000..f3dfbfb05b5
--- /dev/null
+++ b/shells/pdksh/files/LEGAL
@@ -0,0 +1,34 @@
+pdksh is provided AS IS, with NO WARRANTY, either expressed or implied.
+
+The vast majority of the code that makes pdksh is in the public domain.
+The exceptions are:
+ sigact.c and sigact.h
+ These are covered by copyrighten by Simon J. Gerraty;
+ the copyright notice for these files is as follows:
+ This is free software. It comes with NO WARRANTY.
+ Permission to use, modify and distribute this source code
+ is granted subject to the following conditions.
+ 1/ that that the above copyright notice and this notice
+ are preserved in all copies and that due credit be given
+ to the author.
+ 2/ that any changes to this code are clearly commented
+ as such so that the author does get blamed for bugs
+ other than his own.
+ aclocal.m4
+ This is covered by the GNU General Public Licence (GPL)
+ as it contains modified versions of macros that come with
+ GNU autoconf. As this is used solely for configuration,
+ the pdksh code itself is not covered by the GPL.
+ The following is taken from autoconf 2.x documentation
+ (info autoconf questions distributing) concerning use
+ of autoconf in programs:
+
+ There are no restrictions on how the configuration
+ scripts that Autoconf produces may be distributed
+ or used. In Autoconf version 1, they were covered by
+ the GNU General Public License. We still encourage
+ software authors to distribute their work under terms
+ like those of the GPL, but doing so is not required
+ to use Autoconf.
+
+That's it. Short and simple.
diff --git a/shells/pdksh/files/Makefile.in b/shells/pdksh/files/Makefile.in
new file mode 100644
index 00000000000..10d7b325c70
--- /dev/null
+++ b/shells/pdksh/files/Makefile.in
@@ -0,0 +1,330 @@
+#
+# @configure_input@
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+CC = @CC@
+CPP = @CPP@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+DEFS = @DEFS@
+LIBS = @LIBS@
+
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDSTATIC = @LDSTATIC@
+LDFLAGS = @LDFLAGS@
+
+SHELL_PROG = @SHELL_PROG@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+transform=@program_transform_name@
+
+bindir = $(exec_prefix)/bin
+mandir = $(prefix)/man/man$(manext)
+manext = 1
+
+# Suffix for executables: nothing for unix, .exe for os/2.
+exe_suffix=@ac_exe_suffix@
+
+SHELL = /bin/sh
+
+SRCS = alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c \
+ eval.c exec.c expr.c history.c io.c jobs.c lex.c mail.c \
+ main.c misc.c missing.c path.c shf.c sigact.c syn.c table.c trap.c \
+ tree.c tty.c var.c version.c vi.c
+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 misc.o missing.o path.o shf.o sigact.o syn.o table.o trap.o \
+ tree.o tty.o var.o version.o vi.o
+HDRS = c_test.h edit.h expand.h ksh_dir.h ksh_limval.h ksh_stat.h ksh_time.h \
+ ksh_times.h ksh_wait.h lex.h proto.h sh.h shf.h sigact.h \
+ table.h tree.h tty.h
+DISTFILES = $(SRCS) $(HDRS) ksh.Man Makefile.in configure.in \
+ config.h.in conf-end.h acconfig.h aclocal.m4 emacs-gen.sh \
+ mkinstalldirs install-sh new-version.sh siglist.in siglist.sh mkman \
+ check-fd.c check-pgrp.c check-sigs.c \
+ README NEWS CONTRIBUTORS LEGAL PROJECTS INSTALL NOTES BUG-REPORTS \
+ IAFA-PACKAGE ChangeLog ChangeLog.0 configure stamp-h.in
+# ETCFILES also disted, but handled differently
+ETCFILES = etc/ksh.kshrc etc/profile etc/sys_config.sh
+# MISCFILES also disted, but handled differently
+MISCFILES = misc/ChangeLog.sjg misc/Changes.jrm misc/Changes.mlj \
+ misc/Changes.pc misc/README.sjg misc/ReadMe.eg misc/ReadMe.emacs \
+ misc/ReadMe.jrm misc/Bugs
+# TESTFILES also disted, but handled differently
+TESTFILES = tests/README tests/th tests/th-sh tests/alias.t tests/arith.t \
+ tests/bksl-nl.t tests/brkcont.t tests/cdhist.t tests/eglob.t \
+ tests/glob.t tests/heredoc.t tests/history.t tests/ifs.t \
+ tests/integer.t tests/lineno.t tests/read.t tests/regress.t \
+ tests/syntax.t tests/unclass1.t tests/unclass2.t \
+ tests/version.t
+# OS2FILES also disted, but handled differently
+OS2FILES = os2/Makefile os2/config.h os2/config.status os2/configure.cmd \
+ os2/emacs.out os2/kshrc.ksh os2/make.sed os2/os2.c os2/os2siglist.out \
+ os2/README.os2 os2/NEWS.os2 os2/os2bugs os2/th.cmd os2/config.cache
+
+all: $(SHELL_PROG)$(exe_suffix) $(SHELL_PROG).1
+
+# This shouldn't be first - some makes don't know about PRECIOUS and assume it
+# is the default target.
+.PRECIOUS: configure config.h.in Makefile config.status
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS) $<
+
+install: installdirs all
+ $(INSTALL_PROGRAM) $(SHELL_PROG)$(exe_suffix) $(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix)
+ -$(INSTALL_DATA) $(SHELL_PROG).1 $(mandir)/`echo $(SHELL_PROG)|sed '$(transform)'`.$(manext)
+ -@prog=$(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix);\
+ test -f /etc/shells \
+ && (grep "^$$prog\$$" /etc/shells > /dev/null \
+ || echo \
+"NOTE: /etc/shells does not contain $$prog \
+ you should add it if you want to set your shell to $(SHELL_PROG)")
+
+installdirs:
+ $(srcdir)/mkinstalldirs $(bindir) $(mandir)
+
+uninstall:
+ rm -f $(bindir)/`echo $(SHELL_PROG)|sed '$(transform)'`$(exe_suffix)
+ rm -f $(mandir)/`echo $(SHELL_PROG)|sed '$(transform)'`.$(manext)
+
+check test:
+ $(srcdir)/tests/th-sh $(srcdir)/tests/th -s $(srcdir)/tests -p ./$(SHELL_PROG)$(exe_suffix) -C pdksh,sh,ksh,posix,posix-upu $(TESTARGS)
+
+$(SHELL_PROG)$(exe_suffix): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+# two steps to prevent the creation of a bogus tmpksh.1
+$(SHELL_PROG).1: $(srcdir)/ksh.Man
+ $(srcdir)/mkman $(SHELL_PROG) $(srcdir)/ksh.Man > tmpksh.1
+ mv tmpksh.1 $(SHELL_PROG).1
+
+info:
+ @echo "No info (yet)"
+
+dvi:
+
+$(srcdir)/configure: configure.in aclocal.m4
+ cd $(srcdir) && autoconf
+
+$(srcdir)/config.h.in: stamp-h.in
+$(srcdir)/stamp-h.in: configure.in aclocal.m4 acconfig.h
+ cd $(srcdir) && autoheader
+ date > $(srcdir)/stamp-h.in
+
+config.h: stamp-h
+stamp-h: config.h.in config.status
+ CONFIG_FILES="" CONFIG_HEADERS=config.h ./config.status
+ date > stamp-h
+
+Makefile: Makefile.in config.status
+ CONFIG_FILES=Makefile CONFIG_HEADERS= ./config.status
+
+config.status: configure
+ LDSTATIC="$(LDSTATIC)" ./config.status --recheck
+
+# two steps to prevent the creation of a bogus siglist.out
+siglist.out: config.h sh.h siglist.in siglist.sh
+ $(srcdir)/siglist.sh "$(CPP) $(CPPFLAGS) $(DEFS) -I. -I$(srcdir)" < $(srcdir)/siglist.in > tmpsiglist.out
+ mv tmpsiglist.out siglist.out
+
+# two steps to prevent the creation of a bogus emacs.out
+emacs.out: emacs.c
+ $(srcdir)/emacs-gen.sh $(srcdir)/emacs.c > tmpemacs.out
+ mv tmpemacs.out emacs.out
+
+debugtools: check-fd$(exe_suffix) check-sigs$(exe_suffix) \
+ check-pgrp$(exe_suffix)
+
+check-fd.o check-pgrp.o check-sigs.o: config.h
+check-fd$(exe_suffix): check-fd.o
+ $(CC) $(LDFLAGS) -o $@ check-fd.o $(LIBS)
+
+check-pgrp$(exe_suffix): check-pgrp.o
+ $(CC) $(LDFLAGS) -o $@ check-pgrp.o $(LIBS)
+
+check-sigs$(exe_suffix): check-sigs.o
+ $(CC) $(LDFLAGS) -o $@ check-sigs.o $(LIBS)
+
+TAGS: $(SRCS) $(HDRS)
+ cd $(srcdir) && etags $(SRCS) $(HDRS)
+
+tags: $(SRCS) $(HDRS)
+ cd $(srcdir) && ctags -wt $(SRCS) $(HDRS)
+
+clean:
+ rm -f ksh$(exe_suffix) sh$(exe_suffix) ksh.1 sh.1 $(OBJS) siglist.out \
+ emacs.out core a.out mon.out gmon.out \
+ version.c.bak Makefile.bak Makefile.tmp check-fd$(exe_suffix) \
+ check-pgrp$(exe_suffix) check-sigs$(exe_suffix)
+
+mostlyclean: clean
+
+distclean: clean
+ rm -f Makefile config.h stamp-h config.status config.log config.cache \
+ tags TAGS *~
+
+realclean: distclean
+
+dist: $(DISTFILES) $(ETCFILES) $(MISCFILES) $(TESTFILES) $(OS2FILES)
+ cd $(srcdir) && \
+ { \
+ ./new-version.sh; \
+ FNAME=pdksh-`sed -e '/"@(.)/!d' \
+ -e 's/[^0-9]*\([0-9.]*\).*/\1/' -e q version.c`; \
+ if test `echo $$FNAME|tr . ' '|wc -w|sed 's/[ ]*//g'` -gt 3; \
+ then \
+ FNAME=`echo $$FNAME | sed 's/pdksh-/pdksh-unstable-/'`; \
+ fi; \
+ echo Creating version $$FNAME; \
+ rm -rf $$FNAME; \
+ mkdir $$FNAME $$FNAME/etc $$FNAME/misc $$FNAME/tests $$FNAME/os2; \
+ cp -p $(DISTFILES) $$FNAME; \
+ cp -p $(ETCFILES) $$FNAME/etc; \
+ cp -p $(MISCFILES) $$FNAME/misc; \
+ cp -p $(TESTFILES) $$FNAME/tests; \
+ cp -p $(OS2FILES) $$FNAME/os2; \
+ ./emacs-gen.sh emacs.c > os2/emacs.out; \
+ test -x ./Dist-fixup && ./Dist-fixup $$FNAME; \
+ sed -f os2/make.sed < $$FNAME/Makefile.in > $$FNAME/os2/Makefile; \
+ chmod -R a+rX,u+w,og-w $$FNAME; \
+ tar chzf $$FNAME.tar.gz $$FNAME; \
+ find $$FNAME -print | xargs pathchk -p; \
+ }
+
+depend: $(SRCS)
+ sed -n '1,/[ ]PUT ANYTHING BELOW THIS LINE/p' < Makefile > Makefile.tmp
+ srcs=; for i in $(SRCS) ; do srcs="$$srcs $(srcdir)/$$i"; done; \
+ $(CC) -M $(DEFS) -I. -I$(srcdir) $(CFLAGS) $$srcs | \
+ sed -e 's?[ ]/[^ ]*??g' -e 's?[ ]./? ?g' \
+ -e 's?[ ]$(srcdir)//*? ?g' -e 's?^$(srcdir)//*??' \
+ -e '/^[ ]*\\[ ]*$$/d' -e '/^[^:]*:[ ]*$$/d' \
+ -e 's/^\([ ]*\)$$/ sh.h/' \
+ >> Makefile.tmp
+ mv Makefile.tmp Makefile
+ @echo 'Make depend done (stopping make)'; false
+
+# DON'T PUT ANYTHING BELOW THIS LINE (and don't delete it - its for make depend)
+alloc.o: alloc.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h
+c_ksh.o: c_ksh.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h \
+ sh.h
+c_sh.o: c_sh.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_time.h \
+ ksh_times.h \
+ sh.h
+c_test.o: c_test.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h c_test.h
+c_ulimit.o: c_ulimit.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_time.h \
+ sh.h
+edit.o: edit.c config.h conf-end.h sh.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h tty.h \
+ edit.h \
+ ksh_stat.h
+emacs.o: emacs.c config.h conf-end.h sh.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_dir.h \
+ edit.h emacs.out
+eval.o: eval.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h \
+ ksh_dir.h \
+ ksh_stat.h
+exec.o: exec.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h c_test.h \
+ ksh_stat.h
+expr.o: expr.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h \
+ sh.h
+history.o: history.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h
+io.o: io.c \
+ sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h
+jobs.o: jobs.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_wait.h \
+ ksh_times.h ksh_time.h \
+ tty.h \
+ sh.h
+lex.o: lex.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h \
+ sh.h
+mail.o: mail.c config.h conf-end.h sh.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_time.h \
+ sh.h
+main.o: main.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_time.h \
+ sh.h
+misc.o: misc.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h \
+ sh.h
+missing.o: missing.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_dir.h \
+ ksh_time.h \
+ ksh_times.h \
+ sh.h
+path.o: path.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h
+shf.o: shf.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h ksh_limval.h \
+ sh.h
+sigact.o: sigact.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h
+syn.o: syn.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h c_test.h
+table.o: table.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h
+trap.o: trap.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h siglist.out
+tree.o: tree.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h
+tty.o: tty.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_stat.h tty.h \
+ sh.h
+var.o: var.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h ksh_time.h \
+ ksh_limval.h \
+ ksh_stat.h \
+ sh.h
+version.o: version.c sh.h config.h conf-end.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h
+vi.o: vi.c config.h conf-end.h sh.h \
+ shf.h table.h tree.h expand.h lex.h \
+ proto.h \
+ ksh_stat.h edit.h
diff --git a/shells/pdksh/files/acconfig.h b/shells/pdksh/files/acconfig.h
new file mode 100644
index 00000000000..9d83ece9bc0
--- /dev/null
+++ b/shells/pdksh/files/acconfig.h
@@ -0,0 +1,185 @@
+/*
+ * This file, acconfig.h, which is a part of pdksh (the public domain ksh),
+ * is placed in the public domain. It comes with no licence, warranty
+ * or guarantee of any kind (i.e., at your own risk).
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+@TOP@
+
+/* Define if your kernal doesn't handle scripts starting with #! */
+#undef SHARPBANG
+
+/* Define if dup2() preserves the close-on-exec flag (ultrix does this) */
+#undef DUP2_BROKEN
+
+/* Define as the return value of signal handlers (0 or ). */
+#undef RETSIGVAL
+
+/* Define if you have posix signal routines (sigaction(), et. al.) */
+#undef POSIX_SIGNALS
+
+/* Define if you have BSD4.2 signal routines (sigsetmask(), et. al.) */
+#undef BSD42_SIGNALS
+
+/* Define if you have BSD4.1 signal routines (sigset(), et. al.) */
+#undef BSD41_SIGNALS
+
+/* Define if you have v7 signal routines (signal(), signal reset on delivery) */
+#undef V7_SIGNALS
+
+/* Define to use the fake posix signal routines (sigact.[ch]) */
+#undef USE_FAKE_SIGACT
+
+/* Define if signals don't interrupt read() */
+#undef SIGNALS_DONT_INTERRUPT
+
+/* Define if you have bsd versions of the setpgrp() and getpgrp() routines */
+#undef BSD_PGRP
+
+/* Define if you have POSIX versions of the setpgid() and getpgrp() routines */
+#undef POSIX_PGRP
+
+/* Define if you have sysV versions of the setpgrp() and getpgrp() routines */
+#undef SYSV_PGRP
+
+/* Define if you don't have setpgrp(), setpgid() or getpgrp() routines */
+#undef NO_PGRP
+
+/* Define to char if your compiler doesn't like the void keyword */
+#undef void
+
+/* Define to nothing if compiler doesn't like the volatile keyword */
+#undef volatile
+
+/* Define if C compiler groks function prototypes */
+#undef HAVE_PROTOTYPES
+
+/* Define if C compiler groks __attribute__((...)) (const, noreturn, format) */
+#undef HAVE_GCC_FUNC_ATTR
+
+/* Define to 32-bit signed integer type */
+#undef INT32
+
+/* Define to 32-bit signed integer type if <sys/types.h> doesn't define */
+#undef clock_t
+
+/* Define to the type of struct rlimit fields if the rlim_t type is missing */
+#undef rlim_t
+
+/* Define if time() is declared in <time.h> */
+#undef TIME_DECLARED
+
+/* Define to `unsigned' if <signal.h> doesn't define */
+#undef sigset_t
+
+/* Define if sys_errlist[] and sys_nerr are in the C library */
+#undef HAVE_SYS_ERRLIST
+
+/* Define if sys_errlist[] and sys_nerr are defined in <errno.h> */
+#undef SYS_ERRLIST_DECLARED
+
+/* Define if sys_siglist[] is in the C library */
+#undef HAVE_SYS_SIGLIST
+
+/* Define if you have a sane <termios.h> header file */
+#undef HAVE_TERMIOS_H
+
+/* Define if you can include <sys/ioctl.h> with <termios.h> */
+#undef SYS_IOCTL_WITH_TERMIOS
+
+/* Define if you can include <sys/ioctl.h> with <termio.h> */
+#undef SYS_IOCTL_WITH_TERMIO
+
+/* Define if you have a memset() function in your C library */
+#undef HAVE_MEMSET
+
+/* Define if you have a memmove() function in your C library */
+#undef HAVE_MEMMOVE
+
+/* Define if you have a bcopy() function in your C library */
+#undef HAVE_BCOPY
+
+/* Define if you have a lstat() function in your C library */
+#undef HAVE_LSTAT
+
+/* Define if you have a sane <termio.h> header file */
+#undef HAVE_TERMIO_H
+
+/* Define if you don't have times() or if it always returns 0 */
+#undef TIMES_BROKEN
+
+/* Define if opendir() will open non-directory files */
+#undef OPENDIR_DOES_NONDIR
+
+/* Define if the pgrp of setpgrp() can't be the pid of a zombie process */
+#undef NEED_PGRP_SYNC
+
+/* Define if you arg running SCO unix */
+#undef OS_SCO
+
+/* Define if you arg running ISC unix */
+#undef OS_ISC
+
+/* Define if you arg running OS2 with the EMX library */
+#undef OS2
+
+/* Define if you have a POSIX.1 compatiable <sys/wait.h> */
+#undef POSIX_SYS_WAIT
+
+/* Define if your OS maps references to /dev/fd/n to file descriptor n */
+#undef HAVE_DEV_FD
+
+/* Define if your C library's getwd/getcwd function dumps core in unreadable
+ * directories. */
+#undef HPUX_GETWD_BUG
+
+/* ------- ------ ----- ---- --- -- - - -- --- ---- ----- ------ ------- */
+/* Defines from here on down are enable/disable options to configure */
+
+/* Default PATH (see comments in configure.in for more details) */
+#undef DEFAULT_PATH
+
+/* Include ksh features? (see comments in configure.in for more details) */
+#undef KSH
+
+/* Include emacs editing? (see comments in configure.in for more details) */
+#undef EMACS
+
+/* Include vi editing? (see comments in configure.in for more details) */
+#undef VI
+
+/* Include job control? (see comments in configure.in for more details) */
+#undef JOBS
+
+/* Include brace-expansion? (see comments in configure.in for more details) */
+#undef BRACE_EXPAND
+
+/* Include any history? (see comments in configure.in for more details) */
+#undef HISTORY
+
+/* Include complex history? (see comments in configure.in for more details) */
+#undef COMPLEX_HISTORY
+
+/* Strict POSIX behaviour? (see comments in configure.in for more details) */
+#undef POSIXLY_CORRECT
+
+/* Specify default $ENV? (see comments in configure.in for more details) */
+#undef DEFAULT_ENV
+
+/* Include shl(1) support? (see comments in configure.in for more details) */
+#undef SWTCH
+
+/* Include game-of-life? (see comments in configure.in for more details) */
+#undef SILLY
+
+@BOTTOM@
+
+/* Need to use a separate file to keep the configure script from commenting
+ * out the undefs....
+ */
+#include "conf-end.h"
+
+#endif /* CONFIG_H */
diff --git a/shells/pdksh/files/aclocal.m4 b/shells/pdksh/files/aclocal.m4
new file mode 100644
index 00000000000..43731c5d770
--- /dev/null
+++ b/shells/pdksh/files/aclocal.m4
@@ -0,0 +1,1365 @@
+dnl Copyright (C) 1996, Memorial University of Newfoundland.
+dnl This file is covered by the GNU General Public License, version 2, see
+dnl the file misc/COPYING for details.
+dnl
+dnl This file is covered by the GPL 'cause it contains some modified versions
+dnl of autoconf's macros, in particular:
+dnl AC_FUNC_MMAP AC_LANG_C AC_LANG_CPLUXPLUS AC_TRY_RUN KSH_HEADER_SYS_WAIT
+dnl AC_HEADER_STAT AC_PROG_CC
+dnl
+dnl
+dnl Like AC_CHECK_TYPE(), only
+dnl - user gets to specify header file(s) in addition to the default
+dnl headers (<sys/types.h> and <stdlib.h>)
+dnl - user gets to specify the message
+dnl - word boundary checks are put at beginning/end of pattern
+dnl (ie, \<pattern\>)
+dnl - default argument is optional
+dnl uses ac_cv_type_X 'cause this is used in other autoconf macros...
+dnl KSH_CHECK_H_TYPE(type, message, header files, default)
+AC_DEFUN(KSH_CHECK_H_TYPE,
+ [AC_CACHE_CHECK($2, ac_cv_type_$1,
+ [AC_EGREP_CPP([(^|[^a-zA-Z0-9_])]$1[([^a-zA-Z0-9_]|\$)],
+ [#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+$3
+ ], ac_cv_type_$1=yes, ac_cv_type_$1=no)])
+ ifelse($#, 4, [if test $ac_cv_type_$1 = no; then
+ AC_DEFINE($1, $4)
+ fi
+ ])dnl
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for memmove and if not found, check for bcopy. AC_CHECK_FUNCS()
+dnl not used 'cause it confuses some compilers that have memmove/bcopy builtin;
+dnl Also want to check if the function deals with overlapping src/dst properly.
+AC_DEFUN(KSH_MEMMOVE,
+ [AC_CACHE_CHECK(for working memmove, ksh_cv_func_memmove,
+ [AC_TRY_RUN([
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+ int
+ main()
+ {
+ char buf[16];
+ strcpy(buf, "abcdefABCDEF");
+ memmove(buf + 4, buf, 6);
+ if (strcmp(buf, "abcdabcdefEF"))
+ exit(1);
+ memmove(buf, buf + 4, 6);
+ if (strcmp(buf, "abcdefcdefEF"))
+ exit(2);
+ exit(0);
+ return 0;
+ }],
+ ksh_cv_func_memmove=yes, ksh_cv_func_memmove=no,
+ AC_MSG_WARN(assuming memmove broken); ksh_cv_func_memmove=no)])
+ if test $ksh_cv_func_memmove = yes; then
+ AC_DEFINE(HAVE_MEMMOVE)
+ else
+ AC_CACHE_CHECK(for working bcopy, ksh_cv_func_bcopy,
+ [AC_TRY_RUN([
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+ int
+ main()
+ {
+ char buf[16];
+ strcpy(buf, "abcdefABCDEF");
+ bcopy(buf, buf + 4, 6);
+ if (strcmp(buf, "abcdabcdefEF"))
+ exit(1);
+ bcopy(buf + 4, buf, 6);
+ if (strcmp(buf, "abcdefcdefEF"))
+ exit(2);
+ exit(0);
+ }],
+ ksh_cv_func_bcopy=yes, ksh_cv_func_bcopy=no,
+ AC_MSG_WARN(assuming bcopy broken); ksh_cv_func_bcopy=no)])
+ if test $ksh_cv_func_bcopy = yes; then
+ AC_DEFINE(HAVE_BCOPY)
+ fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for sigsetjmp()/siglongjmp() and _setjmp()/_longjmp() pairs.
+dnl Can't use simple library check as QNX 422 has _setjmp() but not _longjmp()
+dnl (go figure).
+AC_DEFUN(KSH_SETJMP,
+ [AC_CACHE_CHECK(for sigsetjmp()/siglongjmp(), ksh_cv_func_sigsetjmp,
+ [AC_TRY_LINK([], [sigsetjmp(); siglongjmp()],
+ ksh_cv_func_sigsetjmp=yes, ksh_cv_func_sigsetjmp=no)])
+ if test $ksh_cv_func_sigsetjmp = yes; then
+ AC_DEFINE(HAVE_SIGSETJMP)
+ else
+ AC_CACHE_CHECK(for _setjmp()/_longjmp(), ksh_cv_func__setjmp,
+ [AC_TRY_LINK([], [_setjmp(); _longjmp();],
+ ksh_cv_func__setjmp=yes, ksh_cv_func__setjmp=no)])
+ if test $ksh_cv_func__setjmp = yes; then
+ AC_DEFINE(HAVE__SETJMP)
+ fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for memset function. AC_CHECK_FUNCS() not used 'cause it confuses
+dnl some compilers that have memset builtin.
+AC_DEFUN(KSH_MEMSET,
+ [AC_CACHE_CHECK(for memset, ksh_cv_func_memset,
+ [AC_TRY_LINK([
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+ ], [
+ char buf[16]; memset(buf, 'x', 7); printf("%7s", buf);],
+ ksh_cv_func_memset=yes, ksh_cv_func_memset=no)])
+ if test $ksh_cv_func_memset = yes; then
+ AC_DEFINE(HAVE_MEMSET)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for rlim_t in a few places, and if not found, figure out the
+dnl size rlim_t should be by looking at struct rlimit.rlim_cur.
+AC_DEFUN(KSH_RLIM_CHECK,
+ [KSH_CHECK_H_TYPE(rlim_t, for rlim_t in <sys/types.h> and <sys/resource.h>,
+ [#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif])dnl
+ if test $ac_cv_type_rlim_t = no; then
+ AC_MSG_CHECKING(what to set rlim_t to)
+ if test $ac_cv_header_sys_resource_h = yes; then
+ AC_CACHE_VAL(ksh_cv_rlim_check,
+ [AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+ main()
+ {
+ struct rlimit rl;
+ if (sizeof(rl.rlim_cur) == sizeof(quad_t))
+ exit(0);
+ exit(1);
+ }
+ ], ksh_cv_rlim_check=quad_t, ksh_cv_rlim_check=long,
+ AC_MSG_ERROR(cannot determine type for rlimt_t when cross compiling)
+ )])dnl
+ else
+ ksh_cv_rlim_check=long
+ fi
+ AC_MSG_RESULT($ksh_cv_rlim_check)
+ AC_DEFINE_UNQUOTED(rlim_t, $ksh_cv_rlim_check)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+AC_DEFUN(KSH_DEV_FD,
+ [AC_CACHE_CHECK(if you have /dev/fd/n, ksh_cv_dev_fd,
+ [AC_TRY_RUN([
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+ main()
+ {
+ struct stat s1, s2;
+ FILE *fp1, *fp2;
+ char *file = "conftest.file";
+ char devfd[32];
+
+ if (!(fp1 = fopen(file, "w")))
+ exit(1);
+ if (fstat(fileno(fp1), &s1) < 0)
+ exit(2);
+ sprintf(devfd, "/dev/fd/%d", fileno(fp1));
+ if (!(fp2 = fopen(devfd, "w")))
+ exit(3);
+ if (fstat(fileno(fp2), &s2) < 0)
+ exit(4);
+ if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
+ exit(5);
+ exit(0);
+ }
+ ], ksh_cv_dev_fd=yes, ksh_cv_dev_fd=no,
+ AC_MSG_WARN(cannot determine if you have /dev/fd support, assuming not)
+ ksh_cv_dev_fd=no)])
+ if test $ksh_cv_dev_fd = yes; then
+ AC_DEFINE(HAVE_DEV_FD)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for sys_siglist[] declaration and existence.
+AC_DEFUN(KSH_SYS_SIGLIST,
+ [AC_DECL_SYS_SIGLIST
+ if test ac_cv_decl_sys_siglist = yes; then
+ AC_DEFINE(HAVE_SYS_SIGLIST)
+ else
+ AC_CACHE_CHECK(for sys_siglist in library, ksh_cv_var_sys_siglist,
+ [AC_TRY_LINK(, [
+ extern char *sys_siglist[];
+ char *p = sys_siglist[2];
+ if (p)
+ return 12;
+ ], ksh_cv_var_sys_siglist=yes, ksh_cv_var_sys_siglist=no)])
+ if test $ksh_cv_var_sys_siglist = yes; then
+ AC_DEFINE(HAVE_SYS_SIGLIST)
+ fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for sys_errlist[] declaration and existence.
+AC_DEFUN(KSH_SYS_ERRLIST,
+ [AC_CACHE_CHECK(for sys_errlist declaration in errno.h, ksh_cv_decl_sys_errlist,
+ [AC_TRY_COMPILE([#include <errno.h>],
+ [char *msg = *(sys_errlist + 1); if (msg && *msg) return 12; ],
+ ksh_cv_decl_sys_errlist=yes, ksh_cv_decl_sys_errlist=no)])
+ if test $ksh_cv_decl_sys_errlist = yes; then
+ AC_DEFINE(SYS_ERRLIST_DECLARED)
+ AC_DEFINE(HAVE_SYS_ERRLIST)
+ else
+ AC_CACHE_CHECK(for sys_errlist in library, ksh_cv_var_sys_errlist,
+ [AC_TRY_LINK(, [
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ char *p;
+ p = sys_errlist[sys_nerr - 1];
+ if (p) return 12;
+ ], ksh_cv_var_sys_errlist=yes, ksh_cv_var_sys_errlist=no)])
+ if test $ksh_cv_var_sys_errlist = yes; then
+ AC_DEFINE(HAVE_SYS_ERRLIST)
+ fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check if time() declared in time.h
+AC_DEFUN(KSH_TIME_DECLARED,
+ [AC_CACHE_CHECK(time() declaration in time.h, ksh_cv_time_delcared,
+ [AC_TRY_COMPILE([#include <sys/types.h>
+#include <time.h>], [time_t (*f)() = time; if (f) return 12;],
+ ksh_cv_time_delcared=yes, ksh_cv_time_delcared=no)])
+ if test $ksh_cv_time_delcared = yes; then
+ AC_DEFINE(TIME_DECLARED)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check for working times (ie, it exists and doesn't always return 0).
+dnl Defines TIMES_BROKEN if it doesn't exist or if it always returns 0
+dnl (also checks for existance of getrusage if times doesn't work).
+dnl XXX: requires clock_t to be typedefed/defined...
+AC_DEFUN(KSH_TIMES_CHECK,
+ [AC_CACHE_CHECK(if times() is present/working, ksh_cv_func_times_ok,
+ [AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/times.h>
+/* if missing, clock_t is defined to be INT32 */
+#if SIZEOF_INT == 4
+# define INT32 int
+#else /* SIZEOF_INT */
+# if SIZEOF_LONG == 4
+# define INT32 long
+# else /* SIZEOF_LONG */
+ #error cannot find 32 bit type...
+# endif /* SIZEOF_LONG */
+#endif /* SIZEOF_INT */
+ main()
+ {
+ extern clock_t times();
+ struct tms tms;
+ times(&tms);
+ sleep(1);
+ if (times(&tms) == 0)
+ exit(1);
+ exit(0);
+ }
+ ], ksh_cv_func_times_ok=yes, ksh_cv_func_times_ok=no,
+ AC_MSG_ERROR(cannot determine if times works when cross compiling)
+ )])
+ if test $ksh_cv_func_times_ok = no; then
+ AC_DEFINE(TIMES_BROKEN)
+ AC_CHECK_FUNCS(getrusage)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+AC_DEFUN(KSH_C_VOID,
+ [AC_CACHE_CHECK(if compiler understands void, ksh_cv_c_void,
+ [AC_TRY_COMPILE(
+ [
+ void foo() { }
+ /* Some compilers (old pcc ones) like "void *a;", but a can't be used */
+ void *bar(a) void *a; { int *b = (int *) a; *b = 1; return a; }
+ ], , ksh_cv_c_void=yes, ksh_cv_c_void=no)])
+ if test $ksh_cv_c_void = yes; then
+ :
+ else
+ AC_DEFINE(void, char)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Early MIPS compilers (used in Ultrix 4.2) don't like
+dnl "int x; int *volatile a = &x; *a = 0;"
+AC_DEFUN(KSH_C_VOLATILE,
+ [AC_CACHE_CHECK(if compiler understands volatile, ksh_cv_c_volatile,
+ [AC_TRY_COMPILE([int x, y, z;],
+ [volatile int a; int * volatile b = x ? &y : &z;
+ /* Older MIPS compilers (eg., in Ultrix 4.2) don't like *b = 0 */
+ *b = 0;], ksh_cv_c_volatile=yes, ksh_cv_c_volatile=no)])
+ if test $ksh_cv_c_volatile = yes; then
+ :
+ else
+ AC_DEFINE(volatile, )
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check if function prototypes work (including stdc vararg prototypes)
+AC_DEFUN(KSH_C_PROTOTYPES,
+ [AC_CACHE_CHECK(if compiler understands prototypes, ksh_cv_c_prototypes,
+ [AC_TRY_COMPILE([
+#include <stdarg.h>
+void foo(char *fmt, ...);
+int bar(int a, char b, char *c);
+int bar(a, b, c) int a; char b; char *c;
+{ foo("%d%c%s\n", a, b, c); return a + b + *c; }
+void foo(char *fmt, ...) { va_list a; va_start(a, fmt); va_end(a); }
+ ], , ksh_cv_c_prototypes=yes, ksh_cv_c_prototypes=no)])
+ if test $ksh_cv_c_prototypes = yes; then
+ AC_DEFINE(HAVE_PROTOTYPES)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check if C compiler understands gcc's __attribute((...)).
+dnl checks for noreturn, const, and format(type,fmt,param), also checks
+dnl that the compiler doesn't die when it sees an unknown attribute (this
+dnl isn't perfect since gcc doesn't parse unknown attributes with parameters)
+AC_DEFUN(KSH_C_FUNC_ATTR,
+ [AC_CACHE_CHECK(if C compiler groks __attribute__(( .. )), ksh_cv_c_func_attr,
+ [AC_TRY_COMPILE([
+#include <stdarg.h>
+void test_fmt(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void test_fmt(char *fmt, ...) { return; }
+int test_cnst(int) __attribute__((const));
+int test_cnst(int x) { return x + 1; }
+void test_nr() __attribute__((noreturn));
+void test_nr() { exit(1); }
+void test_uk() __attribute__((blah));
+void test_uk() { return; }
+ ], [test_nr("%d", 10); test_cnst(2); test_uk(); test_nr(); ],
+ ksh_cv_c_func_attr=yes, ksh_cv_c_func_attr=no)])
+ if test $ksh_cv_c_func_attr = yes; then
+ AC_DEFINE(HAVE_GCC_FUNC_ATTR)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check if dup2() does not clear the close on exec flag
+AC_DEFUN(KSH_DUP2_CLEXEC_CHECK,
+ [AC_CACHE_CHECK([if dup2() works (ie, resets the close-on-exec flag)], ksh_cv_dup2_clexec_ok,
+ [AC_TRY_RUN([
+#include <sys/types.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#ifndef F_GETFD
+# define F_GETFD 1
+#endif
+#ifndef F_SETFD
+# define F_SETFD 2
+#endif
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+/* On some systems (Ultrix 2.1..4.2 (and more?)), dup2() does not clear
+ the close on exec flag */
+main()
+{
+ int fd1, fd2;
+ fd1 = open("/dev/null", O_RDONLY);
+ if (fcntl(fd1, F_SETFD, 1) < 0)
+ exit(1);
+ fd2 = dup2(fd1, fd1 + 1);
+ if (fd2 < 0)
+ exit(2);
+ exit(fcntl(fd2, F_GETFD, 0) == 0 ? 0 : 3);
+}
+ ], ksh_cv_dup2_clexec_ok=yes, ksh_cv_dup2_clexec_ok=no,
+ AC_MSG_WARN(cannot test if dup2 is broken when cross compiling - assuming it is)
+ ksh_cv_dup2_clexec_ok=no)])
+ if test $ksh_cv_dup2_clexec_ok = no; then
+ AC_DEFINE(DUP2_BROKEN)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check type of signal routines (posix, 4.2bsd, 4.1bsd or v7)
+AC_DEFUN(KSH_SIGNAL_CHECK,
+ [AC_CACHE_CHECK(flavour of signal routines, ksh_cv_signal_check,
+ [AC_TRY_LINK([#include <signal.h>], [
+ sigset_t ss;
+ struct sigaction sa;
+ sigemptyset(&ss); sigsuspend(&ss);
+ sigaction(SIGINT, &sa, (struct sigaction *) 0);
+ sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+ ], ksh_cv_signal_check=posix,
+ AC_TRY_LINK([#include <signal.h>], [
+ int mask = sigmask(SIGINT);
+ sigsetmask(mask); sigblock(mask); sigpause(mask);
+ ], ksh_cv_signal_check=bsd42,
+ AC_TRY_LINK([#include <signal.h>
+ RETSIGTYPE foo() { }],
+ [
+ int mask = sigmask(SIGINT);
+ sigset(SIGINT, foo); sigrelse(SIGINT);
+ sighold(SIGINT); sigpause(SIGINT);
+ ], ksh_cv_signal_check=bsd41, ksh_cv_signal_check=v7)))])
+ if test $ksh_cv_signal_check = posix; then
+ AC_DEFINE(POSIX_SIGNALS)
+ else
+ AC_DEFINE(USE_FAKE_SIGACT)
+ if test $ksh_cv_signal_check = bsd42; then
+ AC_DEFINE(BSD42_SIGNALS)
+ elif test $ksh_cv_signal_check = bsd41; then
+ AC_DEFINE(BSD41_SIGNALS)
+ AC_CACHE_CHECK(if signals interrupt read(), ksh_cv_signals_interrupt,
+ [AC_TRY_RUN([
+#include <errno.h>
+#include <signal.h>
+
+ extern int errno;
+ int flag = 0;
+
+ RETSIGTYPE
+ catcher(int sig)
+ {
+ flag = 1;
+ return RETSIGVAL;
+ }
+
+ int
+ main()
+ {
+ int pid;
+ int fdc[2]; /* child writes to parent */
+ int fdp[2]; /* parent writes to child */
+ char buf;
+ int nread;
+
+ if (pipe(fdc) < 0)
+ exit(1);
+ if (pipe(fdp) < 0)
+ exit(2);
+ if ((pid = fork()) < 0)
+ exit(3);
+ if (pid == 0) {
+ close(fdc[0]);
+ close(fdp[1]);
+ if (read(fdp[0], &buf, 1) != 0)
+ exit(10);
+ sleep(1); /* let parent into read */
+ if (kill(getppid(), SIGALRM) < 0)
+ exit(11);
+ sleep(1); /* ensure parent gets to run */
+ write(fdc[1], "1", 1);
+ close(fdc[1]);
+ exit(0);
+ }
+ close(fdc[1]);
+ close(fdp[0]);
+
+ /* Use native routines for test as this is what the shell
+ * will be using...
+ */
+#ifdef POSIX_SIGNALS
+ {
+ struct sigaction sa, osa;
+ sa.sa_handler = catcher;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, &osa);
+ }
+#else /* POSIX_SIGNALS */
+# ifdef BSD42_SIGNALS
+ {
+ struct sigvec vec, ovec;
+ vec.sv_handler = catcher;
+ vec.sv_mask = 0;
+ vec.sv_flags = 0;
+# ifdef SV_INTERRUPT
+ vec.sv_flags |= SV_INTERRUPT;
+# endif /* SV_INTERRUPT */
+ sigvec(SIGALRM, &vec, &ovec);
+ }
+# else /* BSD42_SIGNALS */
+# ifdef BSD41_SIGNALS
+ sigset(SIGALRM, catcher);
+# else /* BSD41_SIGNALS */
+# ifdef V7_SIGNALS
+ signal(SIGALRM, catcher);
+# else /* V7_SIGNALS */
+ what kind of signals do you have?
+# endif /* V7_SIGNALS */
+# endif /* BSD41_SIGNALS */
+# endif /* BSD42_SIGNALS */
+#endif /* POSIX_SIGNALS */
+ close(fdp[1]); /* start child */
+ nread = read(fdc[0], &buf, 1);
+ if (nread == 0)
+ exit(4);
+ if (nread > 0)
+ exit(5);
+ if (errno != EINTR)
+ exit(6);
+ if (!flag)
+ exit(7);
+ exit(0);
+ return 0;
+ }
+ ], ksh_cv_signals_interrupt=yes, ksh_cv_signals_interrupt=no,
+ AC_MSG_ERROR(cannot determine if signals interrupt read() when cross compiling)
+ )])
+ if test $ksh_cv_signals_interrupt = no ; then
+ AC_DEFINE(SIGNALS_DONT_INTERRUPT)
+ fi
+ else
+ AC_DEFINE(V7_SIGNALS)
+ fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl What kind of process groups: POSIX, BSD, SYSV or none
+dnl BSD uses setpgrp(pid, pgrp), getpgrp(pid)
+dnl POSIX uses setpid(pid, pgrp), getpgrp(void)
+dnl SYSV uses setpgrp(void), getpgrp(void)
+dnl Checks for BSD first since the posix test may succeed on BSDish systems
+dnl (depends on what random value gets passed to getpgrp()).
+AC_DEFUN(KSH_PGRP_CHECK,
+ [AC_CACHE_CHECK(flavour of pgrp routines, ksh_cv_pgrp_check,
+ [AC_TRY_RUN([
+/* Check for BSD process groups */
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+ main()
+ {
+ int ecode = 0, child = fork();
+ if (child < 0)
+ exit(1);
+ if (child == 0) {
+ signal(SIGTERM, SIG_DFL); /* just to make sure */
+ sleep(10);
+ exit(9);
+ }
+ if (setpgrp(child, child) < 0)
+ ecode = 2;
+ else if (getpgrp(child) != child)
+ ecode = 3;
+ kill(child, SIGTERM);
+ exit(ecode);
+ }
+ ], ksh_cv_pgrp_check=bsd,
+ [AC_TRY_RUN([
+/* Check for POSIX process groups */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+ main()
+ {
+ int child;
+ int n, p1[2], p2[2];
+ char buf[1];
+ if (pipe(p1) < 0 || pipe(p2) < 0)
+ exit(1);
+ if ((child = fork()) < 0)
+ exit(2);
+ if (child == 0) {
+ n = read(p1[0], buf, sizeof(buf)); /* wait for parent to setpgid */
+ buf[0] = (n != 1 ? 10 : (getpgrp() != getpid() ? 11 : 0));
+ if (write(p2[1], buf, sizeof(buf)) != 1)
+ exit(12);
+ exit(0);
+ }
+ if (setpgid(child, child) < 0)
+ exit(3);
+ if (write(p1[1], buf, 1) != 1)
+ exit(4);
+ if (read(p2[0], buf, 1) != 1)
+ exit(5);
+ exit((int) buf[0]);
+ }
+ ], ksh_cv_pgrp_check=posix,
+ [AC_TRY_RUN([
+/* Check for SYSV process groups */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+ main()
+ {
+ int child;
+ int n, p[2];
+ char buf[1];
+ if (pipe(p) < 0)
+ exit(1);
+ if ((child = fork()) < 0)
+ exit(2);
+ if (child == 0) {
+ buf[0] = (setpgrp() < 0 ? 10 : (getpgrp() != getpid() ? 11 : 0));
+ if (write(p[1], buf, sizeof(buf)) != 1)
+ exit(11);
+ exit(0);
+ }
+ if (read(p[0], buf, 1) != 1)
+ exit(3);
+ exit((int) buf[0]);
+ }
+ ], ksh_cv_pgrp_check=sysv, ksh_cv_pgrp_check=none,
+ AC_MSG_ERROR(cannot taste pgrp routines when cross compiling))],
+ AC_MSG_ERROR(cannot taste pgrp routines when cross compiling))],
+ AC_MSG_ERROR(cannot taste pgrp routines when cross compiling))])
+ if test $ksh_cv_pgrp_check = bsd; then
+ AC_DEFINE(BSD_PGRP)
+ elif test $ksh_cv_pgrp_check = posix; then
+ AC_DEFINE(POSIX_PGRP)
+ elif test $ksh_cv_pgrp_check = sysv; then
+ AC_DEFINE(SYSV_PGRP)
+ else
+ AC_DEFINE(NO_PGRP)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check if the pgrp of setpgrp() can't be the pid of a zombie process.
+dnl On some systems, the kernel doesn't count zombie processes when checking
+dnl if a process group is valid, which can cause problems in creating the
+dnl pipeline "cmd1 | cmd2": if cmd1 can die (and go into the zombie state)
+dnl before cmd2 is started, the kernel doesn't allow the setpgrp() for cmd2
+dnl to succeed. This test defines NEED_PGRP_SYNC if the kernel has this bug.
+dnl (pgrp_sync test doesn't mean much if don't have bsd or posix pgrps)
+AC_DEFUN(KSH_PGRP_SYNC,
+ [AC_REQUIRE([KSH_PGRP_CHECK])dnl
+ if test $ksh_cv_pgrp_check = bsd || test $ksh_cv_pgrp_check = posix ; then
+ AC_CACHE_CHECK(if process group synchronization is required, ksh_cv_need_pgrp_sync,
+ [AC_TRY_RUN([
+ main()
+ {
+#ifdef POSIX_PGRP
+# define getpgID() getpgrp()
+#else
+# define getpgID() getpgrp(0)
+# define setpgid(x,y) setpgrp(x,y)
+#endif
+ int pid1, pid2, fds[2];
+ int status;
+ char ok;
+ switch (pid1 = fork()) {
+ case -1:
+ exit(1);
+ case 0:
+ setpgid(0, getpid());
+ exit(0);
+ }
+ setpgid(pid1, pid1);
+ sleep(2); /* let first child die */
+ if (pipe(fds) < 0)
+ exit(2);
+ switch (pid2 = fork()) {
+ case -1:
+ exit(3);
+ case 0:
+ setpgid(0, pid1);
+ ok = getpgID() == pid1;
+ write(fds[1], &ok, 1);
+ exit(0);
+ }
+ setpgid(pid2, pid1);
+ close(fds[1]);
+ if (read(fds[0], &ok, 1) != 1)
+ exit(4);
+ wait(&status);
+ wait(&status);
+ exit(ok ? 0 : 5);
+ }
+ ], ksh_cv_need_pgrp_sync=no, ksh_cv_need_pgrp_sync=yes,
+ AC_MSG_WARN(cannot test if pgrp synchronization needed when cross compiling - assuming it is)
+ ksh_cv_need_pgrp_sync=yes)])
+ if test $ksh_cv_need_pgrp_sync = yes; then
+ AC_DEFINE(NEED_PGRP_SYNC)
+ fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check to see if opendir will open non-directories (not a nice thing)
+AC_DEFUN(KSH_OPENDIR_CHECK,
+ [AC_CACHE_CHECK(if opendir() fails to open non-directories, ksh_cv_opendir_ok,
+ [AC_TRY_RUN([
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef SYSNDIR
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef SYSDIR
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef NDIR
+# include <ndir.h>
+# endif /* NDIR */
+#endif /* DIRENT */
+ main()
+ {
+ int i, ret = 0;
+ FILE *fp;
+ char *fname = "conftestod", buf[256];
+ for (i = 0; i < sizeof(buf); i++) /* memset(buf, 0, sizeof(buf)) */
+ buf[i] = 0;
+ unlink(fname); /* paranoia */
+ i = ((fp = fopen(fname, "w")) == (FILE *) 0 && (ret = 1))
+ || (fwrite(buf, sizeof(buf), 1, fp) != 1 && (ret = 2))
+ || (fclose(fp) == EOF && (ret = 3))
+ || (opendir(fname) && (ret = 4))
+ || (opendir("/dev/null") && (ret = 5));
+ unlink(fname);
+ exit(ret);
+ }
+ ], ksh_cv_opendir_ok=yes, ksh_cv_opendir_ok=no,
+ AC_MSG_WARN(cannot test if opendir opens non-directories when cross compiling - assuming it does)
+ ksh_cv_opendir_ok=no)])
+ if test $ksh_cv_opendir_ok = no; then
+ AC_DEFINE(OPENDIR_DOES_NONDIR)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Like AC_HAVE_HEADER(unistd.h) but only defines HAVE_UNISTD_H if
+dnl the header file is sane (MIPS RISC/os 5.0 (and later?) has a unistd.h
+dnl in the bsd43 environ that is incorrect - it defines POSIX_VERSION even
+dnl though its non-posix).
+AC_DEFUN(KSH_UNISTD_H,
+ [AC_CACHE_CHECK(for sane unistd.h, ksh_cv_header_unistd,
+ [AC_TRY_COMPILE([
+#include <unistd.h>
+#if defined(_POSIX_VERSION)
+# include <sys/types.h>
+# include <dirent.h> /* _POSIX_VERSION => HAVE_DIRENT_H test not needed */
+#endif
+ ], , ksh_cv_header_unistd=yes, ksh_cv_header_unistd=no)])
+ if test $ksh_cv_header_unistd = yes; then
+ AC_DEFINE(HAVE_UNISTD_H)
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Several OSes need to be detected and symbols defined so the shell can
+dnl deal with them. This is a bit kludgy, but...
+dnl Currently tests for:
+dnl AIX, ISC (Interactive systems corp), MINIX, OS2 using EMX library,
+dnl SCO (santa cruz operation), NEXT
+dnl DO NOT USE with AC_AIX, AC_MINIX or AC_ISC_POSIX tests as these are
+dnl incorperated in this test.
+AC_DEFUN(KSH_OS_TYPE,
+ [AC_BEFORE([$0], [AC_TRY_COMPILE])dnl
+ AC_BEFORE([$0], [AC_TRY_LINK])dnl
+ AC_BEFORE([$0], [AC_TRY_RUN])dnl
+ AC_CACHE_CHECK(if this is a problematic os, ksh_cv_os_type,
+ [ ksh_cv_os_type=no
+ # Some tests below add -C to CPPFLAGS
+ saveCPPFLAGS="$CPPFLAGS"
+ for i in AIX ISC MINIX SCO OS2_EMX TITANOS NEXT HPUX; do
+ case $i in #((
+ AIX)
+ AC_EGREP_CPP(yes,
+ [
+#ifdef _AIX
+yes
+#endif
+ ], ksh_cv_os_type=$i)
+ ;; #(
+ ISC)
+ # Both native ISC cpp and gcc understand this (leave comments in)
+ CPPFLAGS="$CPPFLAGS -C"
+ #XXX grep part won't work if cross-compiling...
+ AC_EGREP_CPP(INTERACTIVE Systems Corporation,
+ [#include <unistd.h>],
+ [if grep _POSIX_VERSION /usr/include/sys/unistd.h > /dev/null 2>&1; then
+ ksh_cv_os_type="$i-posix"
+ else
+ ksh_cv_os_type=$i
+ fi])dnl
+ CPPFLAGS="$saveCPPFLAGS"
+ ;; #(
+ MINIX)
+ AC_CHECK_HEADER(minix/config.h, ksh_cv_os_type=$i)dnl
+ ;; #(
+ SCO)
+ # Both native SCO cpp and gcc understand this (leave comments in)
+ CPPFLAGS="$CPPFLAGS -C"
+ AC_EGREP_CPP(The Santa Cruz Operation,
+ [#include <unistd.h>], ksh_cv_os_type=$i)dnl
+ CPPFLAGS="$saveCPPFLAGS"
+ ;; #(
+ OS2_EMX)
+ AC_EGREP_CPP(yes,
+ [
+#ifdef __EMX__
+yes
+#endif
+ ], ksh_cv_os_type=$i)dnl
+ ;; #(
+ TITANOS)
+ AC_EGREP_CPP(YesTitan,
+ [
+#if defined(titan) || defined(_titan) || defined(__titan)
+YesTitan
+#endif
+ ], ksh_cv_os_type=$i)dnl
+ ;; #(
+ NEXT)
+ #
+ # NeXT 3.2 (other versions?) - cc -E doesn't work and /lib/cpp
+ # doesn't define things that need defining, so tests that rely
+ # on $CPP will break.
+ #
+ # Hmmm - can't safely use CPP to test for NeXT defines, so have
+ # to use a program that won't compile on a NeXT and one that will
+ # only compile on a NeXT...
+ AC_TRY_COMPILE([], [
+ #if defined(__NeXT) || defined(NeXT)
+ this is a NeXT box and the compile should fail
+ #endif
+ ], , AC_TRY_COMPILE([], [
+ #if !defined(__NeXT) && !defined(NeXT)
+ this is NOT a NeXT box and the compile should fail
+ #endif
+ ], ksh_cv_os_type=$i))dnl
+ ;; #(
+ HPUX)
+ AC_EGREP_CPP(yes,
+ [
+#ifdef __hpux
+yes
+#endif
+ ], ksh_cv_os_type=$i)
+ ;; #(
+ esac #))
+ test $ksh_cv_os_type != no && break
+ done
+ ])
+ case $ksh_cv_os_type in #((
+ AIX)
+ AC_DEFINE(_ALL_SOURCE)dnl
+ ;; #(
+ ISC)
+ AC_DEFINE(OS_ISC)dnl
+ ;; #(
+ ISC-posix)
+ AC_DEFINE(OS_ISC)dnl
+ AC_DEFINE(_POSIX_SOURCE)dnl
+ if test "$GCC" = yes; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+ ;; #(
+ MINIX)
+ AC_DEFINE(_POSIX_SOURCE)dnl
+ AC_DEFINE(_POSIX_1_SOURCE, 2)dnl
+ AC_DEFINE(_MINIX)dnl
+ ;; #(
+ SCO)
+ AC_DEFINE(OS_SCO)dnl
+ ;; #(
+ OS2_EMX)
+ # XXX change this to OS_OS2 or OS_OS2_EMX?
+ AC_DEFINE(OS2)dnl
+ ac_exe_suffix=.exe
+ ;; #(
+ TITANOS)
+ # Need to use cc -43 to get a shell with job control
+ case "$CC" in #((
+ *-43*) # Already have -43 option?
+ ;; #(
+ */cc|*/cc' '|*/cc' '|cc|cc' '|cc' ') # Using stock compiler?
+ CC="$CC -43"
+ ;; #(
+ esac #))
+ #
+ # Force dirent check to find the right thing. There is a dirent.h
+ # (and a sys/dirent.h) file which compiles, but generates garbage...
+ #
+ ac_cv_header_dirent_dirent_h=no
+ ac_cv_header_dirent_sys_ndir_h=no
+ ac_cv_header_dirent_sys_dir_h=yes
+ ;; #(
+ NEXT)
+ #
+ # NeXT 3.2 (other versions?) - cc -E doesn't work and /lib/cpp
+ # doesn't define things that need defining, so tests that rely
+ # on $CPP will break.
+ #
+ AC_EGREP_CPP([Bad NeXT], [#include <signal.h>
+ #if !defined(SIGINT) || !defined(SIGQUIT)
+ Bad NeXT
+ #endif
+ ], AC_MSG_ERROR([
+There is a problem on NeXT boxes resulting in a bad siglist.out file being
+generated (which breaks the trap and kill commands) and probably resulting
+in many configuration tests not working correctly.
+
+You appear to have this problem - see the comments on NeXT in the pdksh
+README file for work arounds.]))dnl
+ ;; #(
+ HPUX)
+ #
+ # In some versions of hpux (eg, 10.2), getwd & getcwd will dump core
+ # if directory is not readble.
+ #
+ # name is used in test program
+ AC_CACHE_CHECK(for bug in getwd, ksh_cv_hpux_getwd_bug,
+ [ tmpdir=conftest.dir
+ if mkdir $tmpdir ; then
+ AC_TRY_RUN([
+ int
+ main()
+ {
+ char buf[8 * 1024];
+ char *dirname = "conftest.dir";
+ int ok = 0;
+ if (chdir(dirname) < 0)
+ exit(2);
+ if (chmod(".", 0) < 0)
+ exit(3);
+ /* Test won't work if run as root - so don't be root */
+ if (getuid() == 0 || geteuid() == 0)
+ setresuid(1, 1, 1); /* hpux has this */
+#ifdef HAVE_GETWD /* silly since HAVE_* tests haven't been done yet */
+ {
+ extern char *getwd();
+ ok = getwd(buf) == 0;
+ }
+#else
+ {
+ extern char *getcwd();
+ ok = getcwd(buf, sizeof(buf)) == 0;
+ }
+#endif
+ exit(ok ? 0 : 10);
+ return ok ? 0 : 10;
+ }],
+ ksh_cv_hpux_getwd_bug=no, ksh_cv_hpux_getwd_bug=yes,
+ AC_MSG_WARN(assuming getwd broken); ksh_cv_hpux_getwd_bug=yes)
+ test -d $tmpdir && rmdir $tmpdir
+ else
+ AC_MSG_ERROR(could not make temp directory for test); ksh_cv_hpux_getwd_bug=yes
+ fi])
+ if test $ksh_cv_hpux_getwd_bug = yes; then
+ AC_DEFINE(HPUX_GETWD_BUG)
+ fi
+ ;; #(
+ esac #))
+ ])dnl
+dnl
+dnl
+dnl
+dnl Some systems (eg, SunOS 4.0.3) have <termios.h> and <termio.h> but don't
+dnl have the related functions/defines (eg, tcsetattr(), TCSADRAIN, etc.)
+dnl or the functions don't work well with tty process groups. Sun's bad
+dnl termios can be detected by the lack of tcsetattr(), but its bad termio
+dnl is harder to detect - so check for (sane) termios first, then check for
+dnl BSD, then termio.
+AC_DEFUN(KSH_TERM_CHECK,
+ [AC_CACHE_CHECK(terminal interface, ksh_cv_term_check,
+ [AC_TRY_LINK([#include <termios.h>], [
+ struct termios t;
+#if defined(ultrix) || defined(__ultrix__)
+ Termios in ultrix 4.2 botches type-ahead when going from cooked to
+ cbreak mode. The BSD tty interface works fine though, so use it
+ (would be good to know if alter versions of ultrix work).
+#endif /* ultrix */
+ tcgetattr(0, &t); tcsetattr(0, TCSADRAIN, &t);
+ ], ksh_cv_term_check=termios,
+ [AC_TRY_LINK([#include <sys/ioctl.h>], [
+ struct sgttyb sb; ioctl(0, TIOCGETP, &sb);
+#ifdef TIOCGATC
+ { struct ttychars lc; ioctl(0, TIOCGATC, &lc); }
+#else /* TIOCGATC */
+ { struct tchars tc; ioctl(0, TIOCGETC, &tc); }
+# ifdef TIOCGLTC
+ { struct ltchars ltc; ioctl(0, TIOCGLTC, &ltc); }
+# endif /* TIOCGLTC */
+#endif /* TIOCGATC */
+ ], ksh_cv_term_check=bsd,
+ [AC_CHECK_HEADER(termio.h, ksh_cv_term_check=termio,
+ ksh_cv_term_check=sgtty)])])])
+ if test $ksh_cv_term_check = termios; then
+ AC_DEFINE(HAVE_TERMIOS_H)
+dnl Don't know of a system on which this fails...
+dnl AC_CACHE_CHECK(sys/ioctl.h can be included with termios.h,
+dnl ksh_cv_sys_ioctl_with_termios,
+dnl [AC_TRY_COMPILE([#include <termios.h>
+dnl #include <sys/ioctl.h>], , ksh_cv_sys_ioctl_with_termios=yes,
+dnl ksh_cv_sys_ioctl_with_termios=no)])
+dnl if test $ksh_cv_sys_ioctl_with_termios = yes; then
+dnl AC_DEFINE(SYS_IOCTL_WITH_TERMIOS)
+dnl fi
+ elif test $ksh_cv_term_check = termio; then
+ AC_DEFINE(HAVE_TERMIO_H)
+dnl Don't know of a system on which this fails...
+dnl AC_CACHE_CHECK(sys/ioctl.h can be included with termio.h,
+dnl ksh_cv_sys_ioctl_with_termio,
+dnl [AC_TRY_COMPILE([#include <termio.h>
+dnl #include <sys/ioctl.h>], , ksh_cv_sys_ioctl_with_termio=yes,
+dnl ksh_cv_sys_ioctl_with_termio=no)])
+dnl if test $ksh_cv_sys_ioctl_with_termio = yes; then
+dnl AC_DEFINE(SYS_IOCTL_WITH_TERMIO)
+dnl fi
+ fi
+ ])dnl
+dnl
+dnl
+dnl
+dnl Check if lstat() is available - special test needed 'cause lstat only
+dnl becomes visable if <sys/stat.h> is included (linux 1.3.x)...
+AC_DEFUN(KSH_FUNC_LSTAT,
+[AC_CACHE_CHECK(for lstat, ksh_cv_func_lstat,
+[AC_TRY_LINK([
+#include <sys/types.h>
+#include <sys/stat.h>
+ ], [
+ struct stat statb;
+ lstat("/", &statb);
+ ],
+ ksh_cv_func_lstat=yes, ksh_cv_func_lstat=no)])
+if test $ksh_cv_func_lstat = yes; then
+ AC_DEFINE(HAVE_LSTAT)
+fi
+])
+dnl
+dnl
+dnl
+dnl Modified test from autoconf's acspecific.m4: MMAP test needs to check
+dnl for/use the MAP_FILE flag. (Needed for older NetBSD systems).
+undefine([AC_FUNC_MMAP])dnl
+AC_DEFUN(AC_FUNC_MMAP,
+[AC_CHECK_FUNCS(valloc getpagesize)
+AC_CACHE_CHECK(for working mmap, ac_cv_func_mmap,
+[AC_TRY_RUN([
+/* Thanks to Mike Haertel and Jim Avera for this test. */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifndef HAVE_GETPAGESIZE
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define getpagesize() EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# define getpagesize() NBPG * CLSIZE
+# ifndef CLSIZE
+# define CLSIZE 1
+# endif
+# else
+# ifdef NBPC
+# define getpagesize() NBPC
+# else
+# define getpagesize() PAGESIZE /* SVR4 */
+# endif
+# endif
+# endif
+#endif
+
+#ifndef HAVE_VALLOC
+# define valloc malloc
+#endif
+
+#ifdef __cplusplus
+extern "C" { void *valloc(unsigned), *malloc(unsigned); }
+#else
+char *valloc(), *malloc();
+#endif
+
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif /* MAP_FILE */
+
+int
+main()
+{
+ char *buf1, *buf2, *buf3;
+ int i = getpagesize(), j;
+ int i2 = i * 2;
+ int fd;
+
+ buf1 = (char *)valloc(i2);
+ buf2 = (char *)valloc(i);
+ buf3 = (char *)malloc(i2);
+ for (j = 0; j < i2; ++j)
+ *(buf1 + j) = rand();
+ fd = open("conftestmmap", O_CREAT | O_RDWR, 0666);
+ write(fd, buf1, i2);
+ mmap(buf2, i, PROT_READ | PROT_WRITE, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, 0);
+ for (j = 0; j < i; ++j)
+ if (*(buf1 + j) != *(buf2 + j))
+ exit(1);
+ lseek(fd, (long)i, 0);
+ read(fd, buf2, i); /* read into mapped memory -- file should not change */
+ /* (it does in i386 SVR4.0 - Jim Avera, jima@netcom.com) */
+ lseek(fd, (long)0, 0);
+ read(fd, buf3, i2);
+ for (j = 0; j < i2; ++j)
+ if (*(buf1 + j) != *(buf3 + j))
+ exit(1);
+ exit(0);
+}
+], ac_cv_func_mmap=yes, ac_cv_func_mmap=no, ac_cv_func_mmap=no)])
+if test $ac_cv_func_mmap = yes; then
+ AC_DEFINE(HAVE_MMAP)
+fi
+])
+dnl
+dnl
+dnl
+dnl Modified AC_LANG_C, AC_LANG_CPLUSPLUS, AC_TRY_RUN to handle executable
+dnl extensions.
+undefine([AC_LANG_C])dnl
+undefine([AC_LANG_CPLUXPLUS])dnl
+undefine([AC_TRY_RUN])dnl
+dnl AC_LANG_C()
+AC_DEFUN(AC_LANG_C,
+[define([AC_LANG], [C])dnl
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='echo $CPP $CPPFLAGS 1>&AC_FD_CC;
+$CPP $CPPFLAGS'
+ac_compile='echo ${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC;
+${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC 2>&AC_FD_CC'
+ac_link='echo ${CC-cc} -o conftest$ac_exe_suffix $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC;
+${CC-cc} -o conftest$ac_exe_suffix $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC 2>&AC_FD_CC'
+])
+
+dnl AC_LANG_CPLUSPLUS()
+AC_DEFUN(AC_LANG_CPLUSPLUS,
+[define([AC_LANG], [CPLUSPLUS])dnl
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='echo $CXXCPP $CPPFLAGS 1>&AC_FD_CC;
+$CXXCPP $CPPFLAGS'
+ac_compile='echo ${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC;
+${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&AC_FD_CC 2>&AC_FD_CC'
+ac_link='echo ${CXX-g++} -o conftest$ac_exe_suffix $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC;
+${CXX-g++} -o conftest$ac_exe_suffix $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC 2>&AC_FD_CC'
+])
+dnl AC_TRY_RUN(PROGRAM, [ACTION-IF-TRUE [, ACTION-IF-FALSE
+dnl [, ACTION-IF-CROSS-COMPILING]]])
+AC_DEFUN(AC_TRY_RUN,
+[AC_REQUIRE([AC_PROG_CC])dnl
+if test "$cross_compiling" = yes; then
+ ifelse([$4], ,
+ [errprint(__file__:__line__: warning: [AC_TRY_RUN] called without default to allow cross compiling
+)dnl
+ AC_MSG_ERROR(can not run test program while cross compiling)],
+ [$4])
+else
+cat > conftest.$ac_ext <<EOF
+[#]line __oline__ "configure"
+#include "confdefs.h"
+ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus
+extern "C" void exit(int);
+#endif
+])dnl
+[$1]
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ifelse([$2], , :, [$2])
+ifelse([$3], , , [else
+ $3
+])dnl
+fi
+fi
+rm -fr conftest*])
+dnl
+dnl
+dnl Like AC_HEADER_SYS_WAIT, only HAVE_SYS_WAIT_H if sys/wait.h exists and
+dnl defines POSIX_SYS_WAIT if it is posix compatable. This way things
+dnl like WNOHANG, WUNTRACED can still be used.
+AC_DEFUN(KSH_HEADER_SYS_WAIT,
+[AC_CACHE_CHECK([for sys/wait.h that is POSIX.1 compatible], ksh_cv_header_sys_wait_h,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif], [int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;],
+ksh_cv_header_sys_wait_h=yes, ksh_cv_header_sys_wait_h=no)])
+if test $ksh_cv_header_sys_wait_h = yes; then
+ AC_DEFINE(POSIX_SYS_WAIT)dnl
+ AC_DEFINE(HAVE_SYS_WAIT_H)dnl
+else
+ AC_CHECK_HEADERS(sys/wait.h)dnl
+fi
+])
+dnl
+dnl
+dnl Modified test from autoconf's acspecific.m4(AC_HEADER_STAT) test: need
+dnl to check if S_ISSOCK == S_ISFIFO (FreeBSD).
+undefine([AC_HEADER_STAT])dnl
+AC_DEFUN(AC_HEADER_STAT,
+[AC_CACHE_CHECK(whether stat file-mode macros are broken,
+ ac_cv_header_stat_broken,
+[AC_EGREP_CPP([You lose], [#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFIFO)
+# if S_ISSOCK (S_IFIFO)
+You lose.
+# endif
+#endif
+], ac_cv_header_stat_broken=yes, ac_cv_header_stat_broken=no)])
+if test $ac_cv_header_stat_broken = yes; then
+ AC_DEFINE(STAT_MACROS_BROKEN)
+fi
+])
+dnl
+dnl
+dnl Need to change the "accepts -g" test - some broken systems
+dnl allow "cc -c -g ..." but fail on the link (missing -lg).
+dnl LaserMoon's linux/FT is such a broken system...
+undefine([AC_PROG_CC])dnl
+AC_DEFUN(AC_PROG_CC,
+[AC_BEFORE([$0], [AC_PROG_CPP])dnl
+AC_CHECK_PROG(CC, gcc, gcc, cc)
+
+AC_CACHE_CHECK(whether we are using GNU C, ac_cv_prog_gcc,
+[dnl The semicolon is to pacify NeXT's syntax-checking cpp.
+cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if ${CC-cc} -E conftest.c 2>&AC_FD_CC | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi])
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ if test "${CFLAGS+set}" != set; then
+ AC_CACHE_CHECK(whether ${CC-cc} accepts -g, ac_cv_prog_gcc_g,
+[echo 'int main(){ return 0; }' > conftest.c
+if test -z "`${CC-cc} -g conftest.c 2>&1`"; then
+ ac_cv_prog_gcc_g=yes
+else
+ ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+])
+ if test $ac_cv_prog_gcc_g = yes; then
+ CFLAGS="-g -O"
+ else
+ CFLAGS="-O"
+ fi
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+])
+dnl
+dnl
+dnl Need to change to check for ndir
+dnl
+undefine([AC_HEADER_DIRENT])dnl
+AC_DEFUN(AC_HEADER_DIRENT,
+[ac_header_dirent=no
+AC_CHECK_HEADERS_DIRENT(dirent.h sys/ndir.h sys/dir.h ndir.h,
+ [ac_header_dirent=$ac_hdr; break])
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+AC_CHECK_LIB(dir, opendir, LIBS="$LIBS -ldir", AC_CHECK_LIB(ndir, opendir, LIBS="$LIBS -lndir"))
+else
+AC_CHECK_LIB(x, opendir, LIBS="$LIBS -lx")
+fi
+])
diff --git a/shells/pdksh/files/alloc.c b/shells/pdksh/files/alloc.c
new file mode 100644
index 00000000000..722a88fe3f4
--- /dev/null
+++ b/shells/pdksh/files/alloc.c
@@ -0,0 +1,776 @@
+/*
+ * area-based allocation built on malloc/free
+ */
+
+#include "sh.h"
+
+#ifdef TEST_ALLOC
+# define shellf printf
+# ifndef DEBUG_ALLOC
+# define DEBUG_ALLOC
+# endif /* DEBUG_ALLOC */
+#endif /* TEST_ALLOC */
+
+#ifdef MEM_DEBUG
+
+/*
+ * Special versions of alloc routines if doing mem_debug
+ */
+Area *
+_chmem_ainit(ap, file, line)
+ Area *ap;
+ const char *file;
+ int line;
+{
+ ap->freelist = (struct Block *) _chmem_newpool("ainit", (char *) 0, -1,
+ file, line);
+ if (!ap->freelist)
+ aerror(ap, "ainit failed (ie, newpool)");
+ return ap;
+}
+
+/* free all object in Area */
+void
+_chmem_afreeall(ap, file, line)
+ Area *ap;
+ const char *file;
+ int line;
+{
+ _chmem_delpool((Chmem_poolp) ap->freelist, 0, file, line);
+ /* Kind of ugly, but it works */
+ _chmem_ainit(ap, file, line);
+}
+
+/* allocate object from Area */
+void *
+_chmem_alloc(size, ap, file, line)
+ size_t size;
+ Area *ap;
+ const char *file;
+ int line;
+{
+ return _chmem_mallocp((Chmem_poolp) ap->freelist, size, file, line);
+}
+
+/* change size of object -- like realloc */
+void *
+_chmem_aresize(ptr, size, ap, file, line)
+ void *ptr;
+ size_t size;
+ Area *ap;
+ const char *file;
+ int line;
+{
+ if (!ptr)
+ /* Done as realloc(0, size) is not portable */
+ return _chmem_mallocp((Chmem_poolp) ap->freelist, size,
+ file, line);
+ else
+ return _chmem_reallocp((Chmem_poolp) ap->freelist, ptr, size,
+ file, line);
+}
+
+void
+_chmem_afree(ptr, ap, file, line)
+ void *ptr;
+ Area *ap;
+ const char *file;
+ int line;
+{
+ return _chmem_freep((Chmem_poolp) ap->freelist, ptr, file, line);
+}
+
+#else /* MEM_DEBUG */
+
+# if DEBUG_ALLOC
+void acheck ARGS((Area *ap));
+# define ACHECK(ap) acheck(ap)
+# else /* DEBUG_ALLOC */
+# define ACHECK(ap)
+# endif /* DEBUG_ALLOC */
+
+#define ICELLS 200 /* number of Cells in small Block */
+
+typedef union Cell Cell;
+typedef struct Block Block;
+
+/*
+ * The Cells in a Block are organized as a set of objects.
+ * Each object (pointed to by dp) begins with the block it is in
+ * (dp-2)->block, then has a size in (dp-1)->size, which is
+ * followed with "size" data Cells. Free objects are
+ * linked together via dp->next.
+ */
+
+#define NOBJECT_FIELDS 2 /* the block and size `fields' */
+
+union Cell {
+ size_t size;
+ Cell *next;
+ Block *block;
+ struct {int _;} junk; /* alignment */
+ double djunk; /* alignment */
+};
+
+struct Block {
+ Block *next; /* list of Blocks in Area */
+ Block *prev; /* previous block in list */
+ Cell *freelist; /* object free list */
+ Cell *last; /* &b.cell[size] */
+ Cell cell [1]; /* [size] Cells for allocation */
+};
+
+static Block aempty = {&aempty, &aempty, aempty.cell, aempty.cell};
+
+static void ablockfree ARGS((Block *bp, Area *ap));
+static void *asplit ARGS((Area *ap, Block *bp, Cell *fp, Cell *fpp, int cells));
+
+/* create empty Area */
+Area *
+ainit(ap)
+ register Area *ap;
+{
+ ap->freelist = &aempty;
+ ACHECK(ap);
+ return ap;
+}
+
+/* free all object in Area */
+void
+afreeall(ap)
+ register Area *ap;
+{
+ register Block *bp;
+ register Block *tmp;
+
+ ACHECK(ap);
+ bp = ap->freelist;
+ if (bp != NULL && bp != &aempty) {
+ do {
+ tmp = bp;
+ bp = bp->next;
+ free((void*)tmp);
+ } while (bp != ap->freelist);
+ ap->freelist = &aempty;
+ }
+ ACHECK(ap);
+}
+
+/* allocate object from Area */
+void *
+alloc(size, ap)
+ size_t size;
+ register Area *ap;
+{
+ int cells, acells;
+ Block *bp = 0;
+ Cell *fp = 0, *fpp = 0;
+
+ ACHECK(ap);
+ if (size <= 0)
+ aerror(ap, "allocate bad size");
+ cells = (unsigned)(size + sizeof(Cell) - 1) / sizeof(Cell);
+
+ /* allocate at least this many cells */
+ acells = cells + NOBJECT_FIELDS;
+
+ /*
+ * Only attempt to track small objects - let malloc deal
+ * with larger objects. (this way we don't have to deal with
+ * coalescing memory, or with releasing it to the system)
+ */
+ if (cells <= ICELLS) {
+ /* find free Cell large enough */
+ for (bp = ap->freelist; ; bp = bp->next) {
+ for (fpp = NULL, fp = bp->freelist;
+ fp != bp->last; fpp = fp, fp = fp->next)
+ {
+ if ((fp-1)->size >= cells)
+ goto Found;
+ }
+ /* wrapped around Block list, create new Block */
+ if (bp->next == ap->freelist) {
+ bp = 0;
+ break;
+ }
+ }
+ /* Not much free space left? Allocate a big object this time */
+ acells += ICELLS;
+ }
+ if (bp == 0) {
+ bp = (Block*) malloc(offsetof(Block, cell[acells]));
+ if (bp == NULL)
+ aerror(ap, "cannot allocate");
+ if (ap->freelist == &aempty) {
+ ap->freelist = bp->next = bp->prev = bp;
+ } else {
+ bp->next = ap->freelist->next;
+ ap->freelist->next->prev = bp;
+ ap->freelist->next = bp;
+ bp->prev = ap->freelist;
+ }
+ bp->last = bp->cell + acells;
+ /* initial free list */
+ fp = bp->freelist = bp->cell + NOBJECT_FIELDS;
+ (fp-1)->size = acells - NOBJECT_FIELDS;
+ (fp-2)->block = bp;
+ fp->next = bp->last;
+ fpp = NULL;
+ }
+
+ Found:
+ return asplit(ap, bp, fp, fpp, cells);
+}
+
+/* Do the work of splitting an object into allocated and (possibly) unallocated
+ * objects. Returns the `allocated' object.
+ */
+static void *
+asplit(ap, bp, fp, fpp, cells)
+ Area *ap;
+ Block *bp;
+ Cell *fp;
+ Cell *fpp;
+ int cells;
+{
+ Cell *dp = fp; /* allocated object */
+ int split = (fp-1)->size - cells;
+
+ ACHECK(ap);
+ if (split < 0)
+ aerror(ap, "allocated object too small");
+ if (split <= NOBJECT_FIELDS) { /* allocate all */
+ fp = fp->next;
+ } else { /* allocate head, free tail */
+ Cell *next = fp->next; /* needed, as cells may be 0 */
+ ap->freelist = bp; /* next time, start looking for space here */
+ (fp-1)->size = cells;
+ fp += cells + NOBJECT_FIELDS;
+ (fp-1)->size = split - NOBJECT_FIELDS;
+ (fp-2)->block = bp;
+ fp->next = next;
+ }
+ if (fpp == NULL)
+ bp->freelist = fp;
+ else
+ fpp->next = fp;
+ ACHECK(ap);
+ return (void*) dp;
+}
+
+/* change size of object -- like realloc */
+void *
+aresize(ptr, size, ap)
+ register void *ptr;
+ size_t size;
+ Area *ap;
+{
+ int cells;
+ Cell *dp = (Cell*) ptr;
+ int oldcells = dp ? (dp-1)->size : 0;
+
+ ACHECK(ap);
+ if (size <= 0)
+ aerror(ap, "allocate bad size");
+ /* New size (in cells) */
+ cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
+
+ /* Is this a large object? If so, let malloc deal with it
+ * directly (unless we are crossing the ICELLS border, in
+ * which case the alloc/free below handles it - this should
+ * cut down on fragmentation, and will also keep the code
+ * working (as it assumes size < ICELLS means it is not
+ * a `large object').
+ */
+ if (oldcells > ICELLS && cells > ICELLS) {
+ Block *bp = (dp-2)->block;
+ Block *nbp;
+ /* Saved in case realloc fails.. */
+ Block *next = bp->next, *prev = bp->prev;
+
+ if (bp->freelist != bp->last)
+ aerror(ap, "allocation resizing free pointer");
+ nbp = realloc((void *) bp,
+ offsetof(Block, cell[cells + NOBJECT_FIELDS]));
+ if (!nbp) {
+ /* Have to clean up... */
+ /* NOTE: If this code changes, similar changes may be
+ * needed in ablockfree().
+ */
+ if (next == bp) /* only block */
+ ap->freelist = &aempty;
+ else {
+ next->prev = prev;
+ prev->next = next;
+ if (ap->freelist == bp)
+ ap->freelist = next;
+ }
+ aerror(ap, "cannot re-allocate");
+ }
+ /* If location changed, keep pointers straight... */
+ if (nbp != bp) {
+ if (next == bp) /* only one block */
+ nbp->next = nbp->prev = nbp;
+ else {
+ next->prev = nbp;
+ prev->next = nbp;
+ }
+ if (ap->freelist == bp)
+ ap->freelist = nbp;
+ dp = nbp->cell + NOBJECT_FIELDS;
+ (dp-2)->block = nbp;
+ }
+ (dp-1)->size = cells;
+ nbp->last = nbp->cell + cells + NOBJECT_FIELDS;
+ nbp->freelist = nbp->last;
+
+ ACHECK(ap);
+ return (void*) dp;
+ }
+
+ /* Check if we can just grow this cell
+ * (need to check that cells < ICELLS so we don't make an
+ * object a `large' - that would mess everything up).
+ */
+ if (dp && cells > oldcells && cells <= ICELLS) {
+ Cell *fp, *fpp;
+ Block *bp = (dp-2)->block;
+ int need = cells - oldcells - NOBJECT_FIELDS;
+
+ /* XXX if we had a flag in an object indicating
+ * if the object was free/allocated, we could
+ * avoid this loop (perhaps)
+ */
+ for (fpp = NULL, fp = bp->freelist;
+ fp != bp->last
+ && dp + oldcells + NOBJECT_FIELDS <= fp
+ ; fpp = fp, fp = fp->next)
+ {
+ if (dp + oldcells + NOBJECT_FIELDS == fp
+ && (fp-1)->size >= need)
+ {
+ Cell *np = asplit(ap, bp, fp, fpp, need);
+ /* May get more than we need here */
+ (dp-1)->size += (np-1)->size + NOBJECT_FIELDS;
+ ACHECK(ap);
+ return ptr;
+ }
+ }
+ }
+
+ /* Check if we can just shrink this cell
+ * (if oldcells > ICELLS, this is a large object and we leave
+ * it to malloc...)
+ * Note: this also handles cells == oldcells (a no-op).
+ */
+ if (dp && cells <= oldcells && oldcells <= ICELLS) {
+ int split;
+
+ split = oldcells - cells;
+ if (split <= NOBJECT_FIELDS) /* cannot split */
+ ;
+ else { /* shrink head, free tail */
+ Block *bp = (dp-2)->block;
+
+ (dp-1)->size = cells;
+ dp += cells + NOBJECT_FIELDS;
+ (dp-1)->size = split - NOBJECT_FIELDS;
+ (dp-2)->block = bp;
+ afree((void*)dp, ap);
+ }
+ /* ACHECK() done in afree() */
+ return ptr;
+ }
+
+ /* Have to do it the hard way... */
+ ptr = alloc(size, ap);
+ if (dp != NULL) {
+ size_t s = (dp-1)->size * sizeof(Cell);
+ if (s > size)
+ s = size;
+ memcpy(ptr, dp, s);
+ afree((void *) dp, ap);
+ }
+ /* ACHECK() done in alloc()/afree() */
+ return ptr;
+}
+
+void
+afree(ptr, ap)
+ void *ptr;
+ register Area *ap;
+{
+ register Block *bp;
+ register Cell *fp, *fpp;
+ register Cell *dp = (Cell*)ptr;
+
+ ACHECK(ap);
+ if (ptr == 0)
+ aerror(ap, "freeing null pointer");
+ bp = (dp-2)->block;
+
+ /* If this is a large object, just free it up... */
+ /* Release object... */
+ if ((dp-1)->size > ICELLS) {
+ ablockfree(bp, ap);
+ ACHECK(ap);
+ return;
+ }
+
+ if (dp < &bp->cell[NOBJECT_FIELDS] || dp >= bp->last)
+ aerror(ap, "freeing memory outside of block (corrupted?)");
+
+ /* find position in free list */
+ /* XXX if we had prev/next pointers for objects, this loop could go */
+ for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fp->next)
+ ;
+
+ if (fp == dp)
+ aerror(ap, "freeing free object");
+
+ /* join object with next */
+ if (dp + (dp-1)->size == fp-NOBJECT_FIELDS) { /* adjacent */
+ (dp-1)->size += (fp-1)->size + NOBJECT_FIELDS;
+ dp->next = fp->next;
+ } else /* non-adjacent */
+ dp->next = fp;
+
+ /* join previous with object */
+ if (fpp == NULL)
+ bp->freelist = dp;
+ else if (fpp + (fpp-1)->size == dp-NOBJECT_FIELDS) { /* adjacent */
+ (fpp-1)->size += (dp-1)->size + NOBJECT_FIELDS;
+ fpp->next = dp->next;
+ } else /* non-adjacent */
+ fpp->next = dp;
+
+ /* If whole block is free (and we have some other blocks
+ * around), release this block back to the system...
+ */
+ if (bp->next != bp && bp->freelist == bp->cell + NOBJECT_FIELDS
+ && bp->freelist + (bp->freelist-1)->size == bp->last
+ /* XXX and the other block has some free memory? */
+ )
+ ablockfree(bp, ap);
+ ACHECK(ap);
+}
+
+static void
+ablockfree(bp, ap)
+ Block *bp;
+ Area *ap;
+{
+ /* NOTE: If this code changes, similar changes may be
+ * needed in alloc() (where realloc fails).
+ */
+
+ if (bp->next == bp) /* only block */
+ ap->freelist = &aempty;
+ else {
+ bp->next->prev = bp->prev;
+ bp->prev->next = bp->next;
+ if (ap->freelist == bp)
+ ap->freelist = bp->next;
+ }
+ free((void*) bp);
+}
+
+# if DEBUG_ALLOC
+void
+acheck(ap)
+ Area *ap;
+{
+ Block *bp, *bpp;
+ Cell *dp, *dptmp, *fp;
+ int ok = 1;
+ int isfree;
+ static int disabled;
+
+ if (disabled)
+ return;
+
+ if (!ap) {
+ disabled = 1;
+ aerror(ap, "acheck: null area pointer");
+ }
+
+ bp = ap->freelist;
+ if (!bp) {
+ disabled = 1;
+ aerror(ap, "acheck: null area freelist");
+ }
+
+ /* Nothing to check... */
+ if (bp == &aempty)
+ return;
+
+ bpp = ap->freelist->prev;
+ while (1) {
+ if (bp->prev != bpp) {
+ shellf("acheck: bp->prev != previous\n");
+ ok = 0;
+ }
+ fp = bp->freelist;
+ for (dp = &bp->cell[NOBJECT_FIELDS]; dp != bp->last; ) {
+ if ((dp-2)->block != bp) {
+ shellf("acheck: fragment's block is wrong\n");
+ ok = 0;
+ }
+ isfree = dp == fp;
+ if ((dp-1)->size == 0 && isfree) {
+ shellf("acheck: 0 size frag\n");
+ ok = 0;
+ }
+ if ((dp-1)->size > ICELLS
+ && !isfree
+ && (dp != &bp->cell[NOBJECT_FIELDS]
+ || dp + (dp-1)->size != bp->last))
+ {
+ shellf("acheck: big cell doesn't make up whole block\n");
+ ok = 0;
+ }
+ if (isfree) {
+ if (dp->next <= dp) {
+ shellf("acheck: free fragment's next <= self\n");
+ ok = 0;
+ }
+ if (dp->next > bp->last) {
+ shellf("acheck: free fragment's next > last\n");
+ ok = 0;
+ }
+ fp = dp->next;
+ }
+ dptmp = dp + (dp-1)->size;
+ if (dptmp > bp->last) {
+ shellf("acheck: next frag out of range\n");
+ ok = 0;
+ break;
+ } else if (dptmp != bp->last) {
+ dptmp += NOBJECT_FIELDS;
+ if (dptmp > bp->last) {
+ shellf("acheck: next frag just out of range\n");
+ ok = 0;
+ break;
+ }
+ }
+ if (isfree && dptmp == fp && dptmp != bp->last) {
+ shellf("acheck: adjacent free frags\n");
+ ok = 0;
+ } else if (dptmp > fp) {
+ shellf("acheck: free frag list messed up\n");
+ ok = 0;
+ }
+ dp = dptmp;
+ }
+ bpp = bp;
+ bp = bp->next;
+ if (bp == ap->freelist)
+ break;
+ }
+ if (!ok) {
+ disabled = 1;
+ aerror(ap, "acheck failed");
+ }
+}
+
+void
+aprint(ap, ptr, size)
+ register Area *ap;
+ void *ptr;
+ size_t size;
+{
+ Block *bp;
+
+ if (!ap)
+ shellf("aprint: null area pointer\n");
+ else if (!(bp = ap->freelist))
+ shellf("aprint: null area freelist\n");
+ else if (bp == &aempty)
+ shellf("aprint: area is empty\n");
+ else {
+ int i;
+ Cell *dp, *fp;
+ Block *bpp;
+
+ bpp = ap->freelist->prev;
+ for (i = 0; ; i++) {
+ if (ptr) {
+ void *eptr = (void *) (((char *) ptr) + size);
+ /* print block only if it overlaps ptr/size */
+ if (!((ptr >= (void *) bp
+ && ptr <= (void *) bp->last)
+ || (eptr >= (void *) bp
+ && eptr <= (void *) bp->last)))
+ continue;
+ shellf("aprint: overlap of 0x%p .. 0x%p\n",
+ ptr, eptr);
+ }
+ if (bp->prev != bpp || bp->next->prev != bp)
+ shellf(
+ "aprint: BAD prev pointer: bp %p, bp->prev %p, bp->next %p, bpp=%p\n",
+ bp, bp->prev, bp->next, bpp);
+ shellf("aprint: block %2d (p=%p,%p,n=%p): 0x%p .. 0x%p (%ld)\n", i,
+ bp->prev, bp, bp->next,
+ bp->cell, bp->last,
+ (long) ((char *) bp->last - (char *) bp->cell));
+ fp = bp->freelist;
+ if (bp->last <= bp->cell + NOBJECT_FIELDS)
+ shellf(
+ "aprint: BAD bp->last too small: %p <= %p\n",
+ bp->last, bp->cell + NOBJECT_FIELDS);
+ if (bp->freelist < bp->cell + NOBJECT_FIELDS
+ || bp->freelist > bp->last)
+ shellf(
+ "aprint: BAD bp->freelist %p out of range: %p .. %p\n",
+ bp->freelist,
+ bp->cell + NOBJECT_FIELDS, bp->last);
+ for (dp = bp->cell; dp != bp->last ; ) {
+ dp += NOBJECT_FIELDS;
+ shellf(
+ "aprint: 0x%p .. 0x%p (%ld) %s\n",
+ (dp-NOBJECT_FIELDS),
+ (dp-NOBJECT_FIELDS) + (dp-1)->size
+ + NOBJECT_FIELDS,
+ (long) ((dp-1)->size + NOBJECT_FIELDS)
+ * sizeof(Cell),
+ dp == fp ? "free" : "allocated");
+ if ((dp-2)->block != bp)
+ shellf(
+ "aprint: BAD dp->block %p != bp %p\n",
+ (dp-2)->block, bp);
+ if (dp > bp->last)
+ shellf(
+ "aprint: BAD dp gone past block: %p > %p\n",
+ dp, bp->last);
+ if (dp > fp)
+ shellf(
+ "aprint: BAD dp gone past free: %p > %p\n",
+ dp, fp);
+ if (dp == fp) {
+ fp = fp->next;
+ if (fp < dp || fp > bp->last)
+ shellf(
+ "aprint: BAD free object %p out of range: %p .. %p\n",
+ fp,
+ dp, bp->last);
+ }
+ dp += (dp-1)->size;
+ }
+ bpp = bp;
+ bp = bp->next;
+ if (bp == ap->freelist)
+ break;
+ }
+ }
+}
+# endif /* DEBUG_ALLOC */
+
+# ifdef TEST_ALLOC
+
+Area a;
+FILE *myout;
+
+int
+main(int argc, char **argv)
+{
+ char buf[1024];
+ struct info {
+ int size;
+ void *value;
+ };
+ struct info info[1024 * 2];
+ int size, ident;
+ int lineno = 0;
+
+ myout = stdout;
+ ainit(&a);
+ while (fgets(buf, sizeof(buf), stdin)) {
+ lineno++;
+ if (buf[0] == '\n' || buf[0] == '#')
+ continue;
+ if (sscanf(buf, " alloc %d = i%d", &size, &ident) == 2) {
+ if (ident < 0 || ident > NELEM(info)) {
+ fprintf(stderr, "bad ident (%d) on line %d\n",
+ ident, lineno);
+ exit(1);
+ }
+ info[ident].value = alloc(info[ident].size = size, &a);
+ printf("%p = alloc(%d) [%d,i%d]\n",
+ info[ident].value, info[ident].size,
+ lineno, ident);
+ memset(info[ident].value, 1, size);
+ continue;
+ }
+ if (sscanf(buf, " afree i%d", &ident) == 1) {
+ if (ident < 0 || ident > NELEM(info)) {
+ fprintf(stderr, "bad ident (%d) on line %d\n",
+ ident, lineno);
+ exit(1);
+ }
+ afree(info[ident].value, &a);
+ printf("afree(%p) [%d,i%d]\n", info[ident].value,
+ lineno, ident);
+ continue;
+ }
+ if (sscanf(buf, " aresize i%d , %d", &ident, &size) == 2) {
+ void *value;
+ if (ident < 0 || ident > NELEM(info)) {
+ fprintf(stderr, "bad ident (%d) on line %d\n",
+ ident, lineno);
+ exit(1);
+ }
+ value = info[ident].value;
+ info[ident].value = aresize(value,
+ info[ident].size = size,
+ &a);
+ printf("%p = aresize(%p, %d) [%d,i%d]\n",
+ info[ident].value, value, info[ident].size,
+ lineno, ident);
+ memset(info[ident].value, 1, size);
+ continue;
+ }
+ if (sscanf(buf, " aprint i%d , %d", &ident, &size) == 2) {
+ if (ident < 0 || ident > NELEM(info)) {
+ fprintf(stderr, "bad ident (%d) on line %d\n",
+ ident, lineno);
+ exit(1);
+ }
+ printf("aprint(%p, %d) [%d,i%d]\n",
+ info[ident].value, size, lineno, ident);
+ aprint(&a, info[ident].value, size);
+ continue;
+ }
+ if (sscanf(buf, " aprint %d", &ident) == 1) {
+ if (ident < 0 || ident > NELEM(info)) {
+ fprintf(stderr, "bad ident (%d) on line %d\n",
+ ident, lineno);
+ exit(1);
+ }
+ printf("aprint(0, 0) [%d]\n", lineno);
+ aprint(&a, 0, 0);
+ continue;
+ }
+ if (sscanf(buf, " afreeall %d", &ident) == 1) {
+ printf("afreeall() [%d]\n", lineno);
+ afreeall(&a);
+ memset(info, 0, sizeof(info));
+ continue;
+ }
+ fprintf(stderr, "unrecognized line (line %d)\n",
+ lineno);
+ exit(1);
+ }
+ return 0;
+}
+
+void
+aerror(Area *ap, const char *msg)
+{
+ printf("aerror: %s\n", msg);
+ fflush(stdout);
+ abort();
+}
+
+# endif /* TEST_ALLOC */
+
+#endif /* MEM_DEBUG */
diff --git a/shells/pdksh/files/c_ksh.c b/shells/pdksh/files/c_ksh.c
new file mode 100644
index 00000000000..95c25564ce9
--- /dev/null
+++ b/shells/pdksh/files/c_ksh.c
@@ -0,0 +1,1471 @@
+/*
+ * built-in Korn commands: c_*
+ */
+
+#include "sh.h"
+#include "ksh_stat.h"
+#include <ctype.h>
+
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif /* __CYGWIN__ */
+
+int
+c_cd(wp)
+ char **wp;
+{
+ int optc;
+ int physical = Flag(FPHYSICAL);
+ int cdnode; /* was a node from cdpath added in? */
+ int printpath = 0; /* print where we cd'd? */
+ int rval;
+ struct tbl *pwd_s, *oldpwd_s;
+ XString xs;
+ char *xp;
+ char *dir, *try, *pwd;
+ int phys_path;
+ char *cdpath;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF)
+ switch (optc) {
+ case 'L':
+ physical = 0;
+ break;
+ case 'P':
+ physical = 1;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+ if (Flag(FRESTRICTED)) {
+ bi_errorf("restricted shell - can't cd");
+ return 1;
+ }
+
+ pwd_s = global("PWD");
+ oldpwd_s = global("OLDPWD");
+
+ if (!wp[0]) {
+ /* No arguments - go home */
+ if ((dir = str_val(global("HOME"))) == null) {
+ bi_errorf("no home directory (HOME not set)");
+ return 1;
+ }
+ } else if (!wp[1]) {
+ /* One argument: - or dir */
+ dir = wp[0];
+ if (strcmp(dir, "-") == 0) {
+ dir = str_val(oldpwd_s);
+ if (dir == null) {
+ bi_errorf("no OLDPWD");
+ return 1;
+ }
+ printpath++;
+ }
+ } else if (!wp[2]) {
+ /* Two arguments - substitute arg1 in PWD for arg2 */
+ int ilen, olen, nlen, elen;
+ char *cp;
+
+ if (!current_wd[0]) {
+ bi_errorf("don't know current directory");
+ return 1;
+ }
+ /* substitue arg1 for arg2 in current path.
+ * if the first substitution fails because the cd fails
+ * we could try to find another substitution. For now
+ * we don't
+ */
+ if ((cp = strstr(current_wd, wp[0])) == (char *) 0) {
+ bi_errorf("bad substitution");
+ return 1;
+ }
+ ilen = cp - current_wd;
+ olen = strlen(wp[0]);
+ nlen = strlen(wp[1]);
+ elen = strlen(current_wd + ilen + olen) + 1;
+ dir = alloc(ilen + nlen + elen, ATEMP);
+ memcpy(dir, current_wd, ilen);
+ memcpy(dir + ilen, wp[1], nlen);
+ memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
+ printpath++;
+ } else {
+ bi_errorf("too many arguments");
+ return 1;
+ }
+
+ Xinit(xs, xp, PATH, ATEMP);
+ /* xp will have a bogus value after make_path() - set it to 0
+ * so that if it's used, it will cause a dump
+ */
+ xp = (char *) 0;
+
+ cdpath = str_val(global("CDPATH"));
+ do {
+ cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
+#ifdef S_ISLNK
+ if (physical)
+ rval = chdir(try = Xstring(xs, xp) + phys_path);
+ else
+#endif /* S_ISLNK */
+ {
+ simplify_path(Xstring(xs, xp));
+ rval = chdir(try = Xstring(xs, xp));
+ }
+ } while (rval < 0 && cdpath != (char *) 0);
+
+ if (rval < 0) {
+ if (cdnode)
+ bi_errorf("%s: bad directory", dir);
+ else
+ bi_errorf("%s - %s", try, strerror(errno));
+ return 1;
+ }
+
+ /* Clear out tracked aliases with relative paths */
+ flushcom(0);
+
+ /* Set OLDPWD (note: unsetting OLDPWD does not disable this
+ * setting in at&t ksh)
+ */
+ if (current_wd[0])
+ /* Ignore failure (happens if readonly or integer) */
+ setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
+
+ if (!ISABSPATH(Xstring(xs, xp))) {
+#ifdef OS2
+ /* simplify_path() doesn't know about os/2's drive contexts,
+ * so it can't set current_wd when changing to a:foo.
+ * Handle this by calling getcwd()...
+ */
+ pwd = ksh_get_wd((char *) 0, 0);
+#else /* OS2 */
+ pwd = (char *) 0;
+#endif /* OS2 */
+ } else
+#ifdef S_ISLNK
+ if (!physical || !(pwd = get_phys_path(Xstring(xs, xp))))
+#endif /* S_ISLNK */
+ pwd = Xstring(xs, xp);
+
+ /* Set PWD */
+ if (pwd) {
+#ifdef __CYGWIN__
+ char ptmp[PATH]; /* larger than MAX_PATH */
+ cygwin_conv_to_full_posix_path(pwd, ptmp);
+#else /* __CYGWIN__ */
+ char *ptmp = pwd;
+#endif /* __CYGWIN__ */
+ set_current_wd(ptmp);
+ /* Ignore failure (happens if readonly or integer) */
+ setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
+ } else {
+ set_current_wd(null);
+ pwd = Xstring(xs, xp);
+ /* XXX unset $PWD? */
+ }
+ if (printpath || cdnode)
+ shprintf("%s\n", pwd);
+
+ return 0;
+}
+
+int
+c_pwd(wp)
+ char **wp;
+{
+ int optc;
+ int physical = Flag(FPHYSICAL);
+ char *p;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF)
+ switch (optc) {
+ case 'L':
+ physical = 0;
+ break;
+ case 'P':
+ physical = 1;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+ if (wp[0]) {
+ bi_errorf("too many arguments");
+ return 1;
+ }
+#ifdef S_ISLNK
+ p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd)
+ : (char *) 0;
+#else /* S_ISLNK */
+ p = current_wd[0] ? current_wd : (char *) 0;
+#endif /* S_ISLNK */
+ if (p && eaccess(p, R_OK) < 0)
+ p = (char *) 0;
+ if (!p) {
+ p = ksh_get_wd((char *) 0, 0);
+ if (!p) {
+ bi_errorf("can't get current directory - %s",
+ strerror(errno));
+ return 1;
+ }
+ }
+ shprintf("%s\n", p);
+ return 0;
+}
+
+int
+c_print(wp)
+ char **wp;
+{
+#define PO_NL BIT(0) /* print newline */
+#define PO_EXPAND BIT(1) /* expand backslash sequences */
+#define PO_PMINUSMINUS BIT(2) /* print a -- argument */
+#define PO_HIST BIT(3) /* print to history instead of stdout */
+#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
+#define PO_FSLASH BIT(5) /* swap slash for backslash (for os2 ) */
+ int fd = 1;
+ int flags = PO_EXPAND|PO_NL;
+ char *s;
+ const char *emsg;
+ XString xs;
+ char *xp;
+
+ if (wp[0][0] == 'e') { /* echo command */
+ int nflags = flags;
+
+ /* A compromise between sysV and BSD echo commands:
+ * escape sequences are enabled by default, and
+ * -n, -e and -E are recognized if they appear
+ * in arguments with no illegal options (ie, echo -nq
+ * will print -nq).
+ * Different from sysV echo since options are recognized,
+ * different from BSD echo since escape sequences are enabled
+ * by default.
+ */
+ wp += 1;
+ while ((s = *wp) && *s == '-' && s[1]) {
+ while (*++s)
+ if (*s == 'n')
+ nflags &= ~PO_NL;
+ else if (*s == 'e')
+ nflags |= PO_EXPAND;
+ else if (*s == 'E')
+ nflags &= ~PO_EXPAND;
+ else
+ /* bad option: don't use nflags, print
+ * argument
+ */
+ break;
+ if (*s)
+ break;
+ wp++;
+ flags = nflags;
+ }
+ } else {
+ int optc;
+#if OS2
+ const char *options = "Rnpfrsu,"; /* added f flag */
+#else
+ const char *options = "Rnprsu,";
+#endif
+ while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
+ switch (optc) {
+ case 'R': /* fake BSD echo command */
+ flags |= PO_PMINUSMINUS;
+ flags &= ~PO_EXPAND;
+ options = "ne";
+ break;
+ case 'e':
+ flags |= PO_EXPAND;
+ break;
+#ifdef OS2
+ case 'f':
+ flags |= PO_FSLASH;
+ break;
+#endif
+ case 'n':
+ flags &= ~PO_NL;
+ break;
+#ifdef KSH
+ case 'p':
+ if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
+ bi_errorf("-p: %s", emsg);
+ return 1;
+ }
+ break;
+#endif /* KSH */
+ case 'r':
+ flags &= ~PO_EXPAND;
+ break;
+ case 's':
+ flags |= PO_HIST;
+ break;
+ case 'u':
+ if (!*(s = builtin_opt.optarg))
+ fd = 0;
+ else if ((fd = check_fd(s, W_OK, &emsg)) < 0) {
+ bi_errorf("-u: %s: %s", s, emsg);
+ return 1;
+ }
+ break;
+ case '?':
+ return 1;
+ }
+ if (!(builtin_opt.info & GI_MINUSMINUS)) {
+ /* treat a lone - like -- */
+ if (wp[builtin_opt.optind]
+ && strcmp(wp[builtin_opt.optind], "-") == 0)
+ builtin_opt.optind++;
+ } else if (flags & PO_PMINUSMINUS)
+ builtin_opt.optind--;
+ wp += builtin_opt.optind;
+ }
+
+ Xinit(xs, xp, 128, ATEMP);
+
+ while (*wp != NULL) {
+ register int c;
+ s = *wp;
+ while ((c = *s++) != '\0') {
+ Xcheck(xs, xp);
+#ifdef OS2
+ if ((flags & PO_FSLASH) && c == '\\')
+ if (*s == '\\')
+ *s++;
+ else
+ c = '/';
+#endif /* OS2 */
+ if ((flags & PO_EXPAND) && c == '\\') {
+ int i;
+
+ switch ((c = *s++)) {
+ /* Oddly enough, \007 seems more portable than
+ * \a (due to HP-UX cc, Ultrix cc, old pcc's,
+ * etc.).
+ */
+ case 'a': c = '\007'; break;
+ case 'b': c = '\b'; break;
+ case 'c': flags &= ~PO_NL;
+ continue; /* AT&T brain damage */
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = 0x0B; break;
+ case '0':
+ /* Look for an octal number: can have
+ * three digits (not counting the
+ * leading 0). Truely burnt.
+ */
+ c = 0;
+ for (i = 0; i < 3; i++) {
+ if (*s >= '0' && *s <= '7')
+ c = c*8 + *s++ - '0';
+ else
+ break;
+ }
+ break;
+ case '\0': s--; c = '\\'; break;
+ case '\\': break;
+ default:
+ Xput(xs, xp, '\\');
+ }
+ }
+ Xput(xs, xp, c);
+ }
+ if (*++wp != NULL)
+ Xput(xs, xp, ' ');
+ }
+ if (flags & PO_NL)
+ Xput(xs, xp, '\n');
+
+ if (flags & PO_HIST) {
+ Xput(xs, xp, '\0');
+ source->line++;
+ histsave(source->line, Xstring(xs, xp), 1);
+ Xfree(xs, xp);
+ } else {
+ int n, len = Xlength(xs, xp);
+#ifdef KSH
+ int UNINITIALIZED(opipe);
+
+ /* Ensure we aren't killed by a SIGPIPE while writing to
+ * a coprocess. at&t ksh doesn't seem to do this (seems
+ * to just check that the co-process is alive, which is
+ * not enough).
+ */
+ if (coproc.write >= 0 && coproc.write == fd) {
+ flags |= PO_COPROC;
+ opipe = block_pipe();
+ }
+#endif /* KSH */
+ for (s = Xstring(xs, xp); len > 0; ) {
+ n = write(fd, s, len);
+ if (n < 0) {
+#ifdef KSH
+ if (flags & PO_COPROC)
+ restore_pipe(opipe);
+#endif /* KSH */
+ if (errno == EINTR) {
+ /* allow user to ^C out */
+ intrcheck();
+#ifdef KSH
+ if (flags & PO_COPROC)
+ opipe = block_pipe();
+#endif /* KSH */
+ continue;
+ }
+#ifdef KSH
+ /* This doesn't really make sense - could
+ * break scripts (print -p generates
+ * error message).
+ *if (errno == EPIPE)
+ * coproc_write_close(fd);
+ */
+#endif /* KSH */
+ return 1;
+ }
+ s += n;
+ len -= n;
+ }
+#ifdef KSH
+ if (flags & PO_COPROC)
+ restore_pipe(opipe);
+#endif /* KSH */
+ }
+
+ return 0;
+}
+
+int
+c_whence(wp)
+ char **wp;
+{
+ struct tbl *tp;
+ char *id;
+ int pflag = 0, vflag = 0, Vflag = 0;
+ int ret = 0;
+ int optc;
+ int iam_whence = wp[0][0] == 'w';
+ int fcflags;
+ const char *options = iam_whence ? "pv" : "pvV";
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
+ switch (optc) {
+ case 'p':
+ pflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'V':
+ Vflag = 1;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+
+ fcflags = FC_BI | FC_PATH | FC_FUNC;
+ if (!iam_whence) {
+ /* Note that -p on its own is deal with in comexec() */
+ if (pflag)
+ fcflags |= FC_DEFPATH;
+ /* Convert command options to whence options - note that
+ * command -pV uses a different path search than whence -v
+ * or whence -pv. This should be considered a feature.
+ */
+ vflag = Vflag;
+ }
+ if (pflag)
+ fcflags &= ~(FC_BI | FC_FUNC);
+
+ while ((vflag || ret == 0) && (id = *wp++) != NULL) {
+ tp = NULL;
+ if ((iam_whence || vflag) && !pflag)
+ tp = tsearch(&keywords, id, hash(id));
+ if (!tp && !pflag) {
+ tp = tsearch(&aliases, id, hash(id));
+ if (tp && !(tp->flag & ISSET))
+ tp = NULL;
+ }
+ if (!tp)
+ tp = findcom(id, fcflags);
+ if (vflag || (tp->type != CALIAS && tp->type != CEXEC
+ && tp->type != CTALIAS))
+ shprintf("%s", id);
+ switch (tp->type) {
+ case CKEYWD:
+ if (vflag)
+ shprintf(" is a reserved word");
+ break;
+ case CALIAS:
+ if (vflag)
+ shprintf(" is an %salias for ",
+ (tp->flag & EXPORT) ? "exported "
+ : null);
+ if (!iam_whence && !vflag)
+ shprintf("alias %s=", id);
+ print_value_quoted(tp->val.s);
+ break;
+ case CFUNC:
+ if (vflag) {
+ shprintf(" is a");
+ if (tp->flag & EXPORT)
+ shprintf("n exported");
+ if (tp->flag & TRACE)
+ shprintf(" traced");
+ if (!(tp->flag & ISSET)) {
+ shprintf(" undefined");
+ if (tp->u.fpath)
+ shprintf(" (autoload from %s)",
+ tp->u.fpath);
+ }
+ shprintf(" function");
+ }
+ break;
+ case CSHELL:
+ if (vflag)
+ shprintf(" is a%s shell builtin",
+ (tp->flag & SPEC_BI) ? " special" : null);
+ break;
+ case CTALIAS:
+ case CEXEC:
+ if (tp->flag & ISSET) {
+ if (vflag) {
+ shprintf(" is ");
+ if (tp->type == CTALIAS)
+ shprintf(
+ "a tracked %salias for ",
+ (tp->flag & EXPORT) ?
+ "exported "
+ : null);
+ }
+ shprintf("%s", tp->val.s);
+ } else {
+ if (vflag)
+ shprintf(" not found");
+ ret = 1;
+ }
+ break;
+ default:
+ shprintf("%s is *GOK*", id);
+ break;
+ }
+ if (vflag || !ret)
+ shprintf(newline);
+ }
+ return ret;
+}
+
+/* Deal with command -vV - command -p dealt with in comexec() */
+int
+c_command(wp)
+ char **wp;
+{
+ /* Let c_whence do the work. Note that c_command() must be
+ * a distinct function from c_whence() (tested in comexec()).
+ */
+ return c_whence(wp);
+}
+
+/* typeset, export, and readonly */
+int
+c_typeset(wp)
+ char **wp;
+{
+ struct block *l = e->loc;
+ struct tbl *vp, **p;
+ Tflag fset = 0, fclr = 0;
+ int thing = 0, func = 0, local = 0;
+ const char *options = "L#R#UZ#fi#lprtux"; /* see comment below */
+ char *fieldstr, *basestr;
+ int field, base;
+ int optc;
+ Tflag flag;
+ int pflag = 0;
+
+ switch (**wp) {
+ case 'e': /* export */
+ fset |= EXPORT;
+ options = "p";
+ break;
+ case 'r': /* readonly */
+ fset |= RDONLY;
+ options = "p";
+ break;
+ case 's': /* set */
+ /* called with 'typeset -' */
+ break;
+ case 't': /* typeset */
+ local = 1;
+ break;
+ }
+
+ fieldstr = basestr = (char *) 0;
+ builtin_opt.flags |= GF_PLUSOPT;
+ /* at&t ksh seems to have 0-9 as options, which are multiplied
+ * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
+ * sets right justify in a field of 12). This allows options
+ * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
+ * does not allow the number to be specified as a separate argument
+ * Here, the number must follow the RLZi option, but is optional
+ * (see the # kludge in ksh_getopt()).
+ */
+ while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) {
+ flag = 0;
+ switch (optc) {
+ case 'L':
+ flag = LJUST;
+ fieldstr = builtin_opt.optarg;
+ break;
+ case 'R':
+ flag = RJUST;
+ fieldstr = builtin_opt.optarg;
+ break;
+ case 'U':
+ /* at&t ksh uses u, but this conflicts with
+ * upper/lower case. If this option is changed,
+ * need to change the -U below as well
+ */
+ flag = INT_U;
+ break;
+ case 'Z':
+ flag = ZEROFIL;
+ fieldstr = builtin_opt.optarg;
+ break;
+ case 'f':
+ func = 1;
+ break;
+ case 'i':
+ flag = INTEGER;
+ basestr = builtin_opt.optarg;
+ break;
+ case 'l':
+ flag = LCASEV;
+ break;
+ case 'p': /* posix export/readonly -p flag.
+ * typset -p is the same as typeset (in pdksh);
+ * here for compatability with ksh93.
+ */
+ pflag = 1;
+ break;
+ case 'r':
+ flag = RDONLY;
+ break;
+ case 't':
+ flag = TRACE;
+ break;
+ case 'u':
+ flag = UCASEV_AL; /* upper case / autoload */
+ break;
+ case 'x':
+ flag = EXPORT;
+ break;
+ case '?':
+ return 1;
+ }
+ if (builtin_opt.info & GI_PLUS) {
+ fclr |= flag;
+ fset &= ~flag;
+ thing = '+';
+ } else {
+ fset |= flag;
+ fclr &= ~flag;
+ thing = '-';
+ }
+ }
+
+ field = 0;
+ if (fieldstr && !bi_getn(fieldstr, &field))
+ return 1;
+ base = 0;
+ if (basestr && !bi_getn(basestr, &base))
+ return 1;
+
+ if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind]
+ && (wp[builtin_opt.optind][0] == '-'
+ || wp[builtin_opt.optind][0] == '+')
+ && wp[builtin_opt.optind][1] == '\0')
+ {
+ thing = wp[builtin_opt.optind][0];
+ builtin_opt.optind++;
+ }
+
+ if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) {
+ bi_errorf("only -t, -u and -x options may be used with -f");
+ return 1;
+ }
+ if (wp[builtin_opt.optind]) {
+ /* Take care of exclusions.
+ * At this point, flags in fset are cleared in fclr and vise
+ * versa. This property should be preserved.
+ */
+ if (fset & LCASEV) /* LCASEV has priority over UCASEV_AL */
+ fset &= ~UCASEV_AL;
+ if (fset & LJUST) /* LJUST has priority over RJUST */
+ fset &= ~RJUST;
+ if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */
+ fset |= RJUST;
+ fclr &= ~RJUST;
+ }
+ /* Setting these attributes clears the others, unless they
+ * are also set in this command
+ */
+ if (fset & (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER
+ |INT_U|INT_L))
+ fclr |= ~fset &
+ (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER
+ |INT_U|INT_L);
+ }
+
+ /* set variables and attributes */
+ if (wp[builtin_opt.optind]) {
+ int i;
+ int rval = 0;
+ struct tbl *f;
+
+ if (local && !func)
+ fset |= LOCAL;
+ for (i = builtin_opt.optind; wp[i]; i++) {
+ if (func) {
+ f = findfunc(wp[i], hash(wp[i]),
+ (fset&UCASEV_AL) ? TRUE : FALSE);
+ if (!f) {
+ /* at&t ksh does ++rval: bogus */
+ rval = 1;
+ continue;
+ }
+ if (fset | fclr) {
+ f->flag |= fset;
+ f->flag &= ~fclr;
+ } else
+ fptreef(shl_stdout, 0,
+ f->flag & FKSH ?
+ "function %s %T\n"
+ : "%s() %T\n"
+ ,
+ wp[i], f->val.t);
+ } else if (!typeset(wp[i], fset, fclr, field, base)) {
+ bi_errorf("%s: not identifier", wp[i]);
+ return 1;
+ }
+ }
+ return rval;
+ }
+
+ /* list variables and attributes */
+ flag = fset | fclr; /* no difference at this point.. */
+ if (func) {
+ for (l = e->loc; l; l = l->next) {
+ for (p = tsort(&l->funs); (vp = *p++); ) {
+ if (flag && (vp->flag & flag) == 0)
+ continue;
+ if (thing == '-')
+ fptreef(shl_stdout, 0, vp->flag & FKSH ?
+ "function %s %T\n"
+ : "%s() %T\n",
+ vp->name, vp->val.t);
+ else
+ shprintf("%s\n", vp->name);
+ }
+ }
+ } else {
+ for (l = e->loc; l; l = l->next) {
+ for (p = tsort(&l->vars); (vp = *p++); ) {
+ struct tbl *tvp;
+ int any_set = 0;
+ /*
+ * See if the parameter is set (for arrays, if any
+ * element is set).
+ */
+ for (tvp = vp; tvp; tvp = tvp->u.array)
+ if (tvp->flag & ISSET) {
+ any_set = 1;
+ break;
+ }
+ /*
+ * Check attributes - note that all array elements
+ * have (should have?) the same attributes, so checking
+ * the first is sufficient.
+ *
+ * Report an unset param only if the user has
+ * explicitly given it some attribute (like export);
+ * otherwise, after "echo $FOO", we would report FOO...
+ */
+ if (!any_set && !(vp->flag & USERATTRIB))
+ continue;
+ if (flag && (vp->flag & flag) == 0)
+ continue;
+ for (; vp; vp = vp->u.array) {
+ /* Ignore array elements that aren't set unless there
+ * are no set elements, in which case the first is
+ * reported on
+ */
+ if ((vp->flag&ARRAY) && any_set && !(vp->flag & ISSET))
+ continue;
+ /* no arguments */
+ if (thing == 0 && flag == 0) {
+ /* at&t ksh prints things like export, integer,
+ * leftadj, zerofill, etc., but POSIX says must
+ * be suitable for re-entry...
+ */
+ shprintf("typeset ");
+ if ((vp->flag&INTEGER))
+ shprintf("-i ");
+ if ((vp->flag&EXPORT))
+ shprintf("-x ");
+ if ((vp->flag&RDONLY))
+ shprintf("-r ");
+ if ((vp->flag&TRACE))
+ shprintf("-t ");
+ if ((vp->flag&LJUST))
+ shprintf("-L%d ", vp->u2.field);
+ if ((vp->flag&RJUST))
+ shprintf("-R%d ", vp->u2.field);
+ if ((vp->flag&ZEROFIL))
+ shprintf("-Z ");
+ if ((vp->flag&LCASEV))
+ shprintf("-l ");
+ if ((vp->flag&UCASEV_AL))
+ shprintf("-u ");
+ if ((vp->flag&INT_U))
+ shprintf("-U ");
+ shprintf("%s\n", vp->name);
+ if (vp->flag&ARRAY)
+ break;
+ } else {
+ if (pflag)
+ shprintf("%s ",
+ (flag & EXPORT) ? "export" : "readonly");
+ if ((vp->flag&ARRAY) && any_set)
+ shprintf("%s[%d]", vp->name, vp->index);
+ else
+ shprintf("%s", vp->name);
+ if (thing == '-' && (vp->flag&ISSET)) {
+ char *s = str_val(vp);
+
+ shprintf("=");
+ /* at&t ksh can't have justified integers.. */
+ if ((vp->flag & (INTEGER|LJUST|RJUST))
+ == INTEGER)
+ shprintf("%s", s);
+ else
+ print_value_quoted(s);
+ }
+ shprintf(newline);
+ }
+ /* Only report first `element' of an array with
+ * no set elements.
+ */
+ if (!any_set)
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int
+c_alias(wp)
+ char **wp;
+{
+ struct table *t = &aliases;
+ int rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0;
+ int prefix = 0;
+ Tflag xflag = 0;
+ int optc;
+
+ builtin_opt.flags |= GF_PLUSOPT;
+ while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != EOF) {
+ prefix = builtin_opt.info & GI_PLUS ? '+' : '-';
+ switch (optc) {
+ case 'd':
+ t = &homedirs;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 't':
+ t = &taliases;
+ break;
+ case 'U': /* kludge for tracked alias initialization
+ * (don't do a path search, just make an entry)
+ */
+ Uflag = 1;
+ break;
+ case 'x':
+ xflag = EXPORT;
+ break;
+ case '?':
+ return 1;
+ }
+ }
+ wp += builtin_opt.optind;
+
+ if (!(builtin_opt.info & GI_MINUSMINUS) && *wp
+ && (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0')
+ {
+ prefix = wp[0][0];
+ wp++;
+ }
+
+ tflag = t == &taliases;
+
+ /* "hash -r" means reset all the tracked aliases.. */
+ if (rflag) {
+ static const char *const args[] = {
+ "unalias", "-ta", (const char *) 0
+ };
+
+ if (!tflag || *wp) {
+ shprintf(
+ "alias: -r flag can only be used with -t and without arguments\n");
+ return 1;
+ }
+ ksh_getopt_reset(&builtin_opt, GF_ERROR);
+ return c_unalias((char **) args);
+ }
+
+
+ if (*wp == NULL) {
+ struct tbl *ap, **p;
+
+ for (p = tsort(t); (ap = *p++) != NULL; )
+ if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
+ if (pflag)
+ shf_puts("alias ", shl_stdout);
+ shf_puts(ap->name, shl_stdout);
+ if (prefix != '+') {
+ shf_putc('=', shl_stdout);
+ print_value_quoted(ap->val.s);
+ }
+ shprintf(newline);
+ }
+ }
+
+ for (; *wp != NULL; wp++) {
+ char *alias = *wp;
+ char *val = strchr(alias, '=');
+ char *newval;
+ struct tbl *ap;
+ int h;
+
+ if (val)
+ alias = str_nsave(alias, val++ - alias, ATEMP);
+ h = hash(alias);
+ if (val == NULL && !tflag && !xflag) {
+ ap = tsearch(t, alias, h);
+ if (ap != NULL && (ap->flag&ISSET)) {
+ if (pflag)
+ shf_puts("alias ", shl_stdout);
+ shf_puts(ap->name, shl_stdout);
+ if (prefix != '+') {
+ shf_putc('=', shl_stdout);
+ print_value_quoted(ap->val.s);
+ }
+ shprintf(newline);
+ } else {
+ shprintf("%s alias not found\n", alias);
+ rv = 1;
+ }
+ continue;
+ }
+ ap = tenter(t, alias, h);
+ ap->type = tflag ? CTALIAS : CALIAS;
+ /* Are we setting the value or just some flags? */
+ if ((val && !tflag) || (!val && tflag && !Uflag)) {
+ if (ap->flag&ALLOC) {
+ ap->flag &= ~(ALLOC|ISSET);
+ afree((void*)ap->val.s, APERM);
+ }
+ /* ignore values for -t (at&t ksh does this) */
+ newval = tflag ? search(alias, path, X_OK, (int *) 0)
+ : val;
+ if (newval) {
+ ap->val.s = str_save(newval, APERM);
+ ap->flag |= ALLOC|ISSET;
+ } else
+ ap->flag &= ~ISSET;
+ }
+ ap->flag |= DEFINED;
+ if (prefix == '+')
+ ap->flag &= ~xflag;
+ else
+ ap->flag |= xflag;
+ if (val)
+ afree(alias, ATEMP);
+ }
+
+ return rv;
+}
+
+int
+c_unalias(wp)
+ char **wp;
+{
+ register struct table *t = &aliases;
+ register struct tbl *ap;
+ int rv = 0, all = 0;
+ int optc;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != EOF)
+ switch (optc) {
+ case 'a':
+ all = 1;
+ break;
+ case 'd':
+ t = &homedirs;
+ break;
+ case 't':
+ t = &taliases;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+ for (; *wp != NULL; wp++) {
+ ap = tsearch(t, *wp, hash(*wp));
+ if (ap == NULL) {
+ rv = 1; /* POSIX */
+ continue;
+ }
+ if (ap->flag&ALLOC) {
+ ap->flag &= ~(ALLOC|ISSET);
+ afree((void*)ap->val.s, APERM);
+ }
+ ap->flag &= ~(DEFINED|ISSET|EXPORT);
+ }
+
+ if (all) {
+ struct tstate ts;
+
+ for (twalk(&ts, t); (ap = tnext(&ts)); ) {
+ if (ap->flag&ALLOC) {
+ ap->flag &= ~(ALLOC|ISSET);
+ afree((void*)ap->val.s, APERM);
+ }
+ ap->flag &= ~(DEFINED|ISSET|EXPORT);
+ }
+ }
+
+ return rv;
+}
+
+#ifdef KSH
+int
+c_let(wp)
+ char **wp;
+{
+ int rv = 1;
+ long val;
+
+ if (wp[1] == (char *) 0) /* at&t ksh does this */
+ bi_errorf("no arguments");
+ else
+ for (wp++; *wp; wp++)
+ if (!evaluate(*wp, &val, KSH_RETURN_ERROR)) {
+ rv = 2; /* distinguish error from zero result */
+ break;
+ } else
+ rv = val == 0;
+ return rv;
+}
+#endif /* KSH */
+
+int
+c_jobs(wp)
+ char **wp;
+{
+ int optc;
+ int flag = 0;
+ int nflag = 0;
+ int rv = 0;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != EOF)
+ switch (optc) {
+ case 'l':
+ flag = 1;
+ break;
+ case 'p':
+ flag = 2;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'z': /* debugging: print zombies */
+ nflag = -1;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+ if (!*wp)
+ if (j_jobs((char *) 0, flag, nflag))
+ rv = 1;
+ else
+ for (; *wp; wp++)
+ if (j_jobs(*wp, flag, nflag))
+ rv = 1;
+ return rv;
+}
+
+#ifdef JOBS
+int
+c_fgbg(wp)
+ char **wp;
+{
+ int bg = strcmp(*wp, "bg") == 0;
+ int UNINITIALIZED(rv);
+
+ if (!Flag(FMONITOR)) {
+ bi_errorf("job control not enabled");
+ return 1;
+ }
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ wp += builtin_opt.optind;
+ if (*wp)
+ for (; *wp; wp++)
+ rv = j_resume(*wp, bg);
+ else
+ rv = j_resume("%%", bg);
+ /* POSIX says fg shall return 0 (unless an error occurs).
+ * at&t ksh returns the exit value of the job...
+ */
+ return (bg || Flag(FPOSIX)) ? 0 : rv;
+}
+#endif
+
+struct kill_info {
+ int num_width;
+ int name_width;
+};
+static char *kill_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
+
+/* format a single kill item */
+static char *
+kill_fmt_entry(arg, i, buf, buflen)
+ void *arg;
+ int i;
+ char *buf;
+ int buflen;
+{
+ struct kill_info *ki = (struct kill_info *) arg;
+
+ i++;
+ if (sigtraps[i].name)
+ shf_snprintf(buf, buflen, "%*d %*s %s",
+ ki->num_width, i,
+ ki->name_width, sigtraps[i].name,
+ sigtraps[i].mess);
+ else
+ shf_snprintf(buf, buflen, "%*d %*d %s",
+ ki->num_width, i,
+ ki->name_width, sigtraps[i].signal,
+ sigtraps[i].mess);
+ return buf;
+}
+
+
+int
+c_kill(wp)
+ char **wp;
+{
+ Trap *t = (Trap *) 0;
+ char *p;
+ int lflag = 0;
+ int i, n, rv, sig;
+
+ /* assume old style options if -digits or -UPPERCASE */
+ if ((p = wp[1]) && *p == '-' && (digit(p[1]) || isupper(p[1]))) {
+ if (!(t = gettrap(p + 1, TRUE))) {
+ bi_errorf("bad signal `%s'", p + 1);
+ return 1;
+ }
+ i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
+ } else {
+ int optc;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != EOF)
+ switch (optc) {
+ case 'l':
+ lflag = 1;
+ break;
+ case 's':
+ if (!(t = gettrap(builtin_opt.optarg, TRUE))) {
+ bi_errorf("bad signal `%s'",
+ builtin_opt.optarg);
+ return 1;
+ }
+ case '?':
+ return 1;
+ }
+ i = builtin_opt.optind;
+ }
+ if ((lflag && t) || (!wp[i] && !lflag)) {
+ shf_fprintf(shl_out,
+"Usage: kill [ -s signame | -signum | -signame ] {pid|job}...\n\
+ kill -l [exit_status]\n"
+ );
+ bi_errorf(null);
+ return 1;
+ }
+
+ if (lflag) {
+ if (wp[i]) {
+ for (; wp[i]; i++) {
+ if (!bi_getn(wp[i], &n))
+ return 1;
+ if (n > 128 && n < 128 + SIGNALS)
+ n -= 128;
+ if (n > 0 && n < SIGNALS && sigtraps[n].name)
+ shprintf("%s\n", sigtraps[n].name);
+ else
+ shprintf("%d\n", n);
+ }
+ } else if (Flag(FPOSIX)) {
+ p = null;
+ for (i = 1; i < SIGNALS; i++, p = space)
+ if (sigtraps[i].name)
+ shprintf("%s%s", p, sigtraps[i].name);
+ shprintf(newline);
+ } else {
+ int w, i;
+ int mess_width;
+ struct kill_info ki;
+
+ for (i = SIGNALS, ki.num_width = 1; i >= 10; i /= 10)
+ ki.num_width++;
+ ki.name_width = mess_width = 0;
+ for (i = 0; i < SIGNALS; i++) {
+ w = sigtraps[i].name ? strlen(sigtraps[i].name)
+ : ki.num_width;
+ if (w > ki.name_width)
+ ki.name_width = w;
+ w = strlen(sigtraps[i].mess);
+ if (w > mess_width)
+ mess_width = w;
+ }
+
+ print_columns(shl_stdout, SIGNALS - 1,
+ kill_fmt_entry, (void *) &ki,
+ ki.num_width + ki.name_width + mess_width + 3);
+ }
+ return 0;
+ }
+ rv = 0;
+ sig = t ? t->signal : SIGTERM;
+ for (; (p = wp[i]); i++) {
+ if (*p == '%') {
+ if (j_kill(p, sig))
+ rv = 1;
+ } else if (!getn(p, &n)) {
+ bi_errorf("%s: arguments must be jobs or process ids",
+ p);
+ rv = 1;
+ } else {
+ /* use killpg if < -1 since -1 does special things for
+ * some non-killpg-endowed kills
+ */
+ if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) < 0) {
+ bi_errorf("%s: %s", p, strerror(errno));
+ rv = 1;
+ }
+ }
+ }
+ return rv;
+}
+
+void
+getopts_reset(val)
+ int val;
+{
+ if (val >= 1) {
+ ksh_getopt_reset(&user_opt,
+ GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
+ user_opt.optind = user_opt.uoptind = val;
+ }
+}
+
+int
+c_getopts(wp)
+ char **wp;
+{
+ int argc;
+ const char *options;
+ const char *var;
+ int optc;
+ int ret;
+ char buf[3];
+ struct tbl *vq, *voptarg;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ wp += builtin_opt.optind;
+
+ options = *wp++;
+ if (!options) {
+ bi_errorf("missing options argument");
+ return 1;
+ }
+
+ var = *wp++;
+ if (!var) {
+ bi_errorf("missing name argument");
+ return 1;
+ }
+ if (!*var || *skip_varname(var, TRUE)) {
+ bi_errorf("%s: is not an identifier", var);
+ return 1;
+ }
+
+ if (e->loc->next == (struct block *) 0) {
+ internal_errorf(0, "c_getopts: no argv");
+ return 1;
+ }
+ /* Which arguments are we parsing... */
+ if (*wp == (char *) 0)
+ wp = e->loc->next->argv;
+ else
+ *--wp = e->loc->next->argv[0];
+
+ /* Check that our saved state won't cause a core dump... */
+ for (argc = 0; wp[argc]; argc++)
+ ;
+ if (user_opt.optind > argc
+ || (user_opt.p != 0
+ && user_opt.p > strlen(wp[user_opt.optind - 1])))
+ {
+ bi_errorf("arguments changed since last call");
+ return 1;
+ }
+
+ user_opt.optarg = (char *) 0;
+ optc = ksh_getopt(wp, &user_opt, options);
+
+ if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) {
+ buf[0] = '+';
+ buf[1] = optc;
+ buf[2] = '\0';
+ } else {
+ /* POSIX says var is set to ? at end-of-options, at&t ksh
+ * sets it to null - we go with POSIX...
+ */
+ buf[0] = optc < 0 ? '?' : optc;
+ buf[1] = '\0';
+ }
+
+ /* at&t ksh does not change OPTIND if it was an unknown option.
+ * Scripts counting on this are prone to break... (ie, don't count
+ * on this staying).
+ */
+ if (optc != '?') {
+ user_opt.uoptind = user_opt.optind;
+ }
+
+ voptarg = global("OPTARG");
+ voptarg->flag &= ~RDONLY; /* at&t ksh clears ro and int */
+ /* Paranoia: ensure no bizarre results. */
+ if (voptarg->flag & INTEGER)
+ typeset("OPTARG", 0, INTEGER, 0, 0);
+ if (user_opt.optarg == (char *) 0)
+ unset(voptarg, 0);
+ else
+ /* This can't fail (have cleared readonly/integer) */
+ setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
+
+ ret = 0;
+
+ vq = global(var);
+ /* Error message already printed (integer, readonly) */
+ if (!setstr(vq, buf, KSH_RETURN_ERROR))
+ ret = 1;
+ if (Flag(FEXPORT))
+ typeset(var, EXPORT, 0, 0, 0);
+
+ return optc < 0 ? 1 : ret;
+}
+
+#ifdef EMACS
+int
+c_bind(wp)
+ char **wp;
+{
+ int rv = 0, macro = 0, list = 0;
+ register char *cp;
+ int optc;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != EOF)
+ switch (optc) {
+ case 'l':
+ list = 1;
+ break;
+ case 'm':
+ macro = 1;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+ if (*wp == NULL) /* list all */
+ rv = x_bind((char*)NULL, (char*)NULL, 0, list);
+
+ for (; *wp != NULL; wp++) {
+ cp = strchr(*wp, '=');
+ if (cp != NULL)
+ *cp++ = '\0';
+ if (x_bind(*wp, cp, macro, 0))
+ rv = 1;
+ }
+
+ return rv;
+}
+#endif
+
+/* A leading = means assignments before command are kept;
+ * a leading * means a POSIX special builtin;
+ * a leading + means a POSIX regular builtin
+ * (* and + should not be combined).
+ */
+const struct builtin kshbuiltins [] = {
+ {"+alias", c_alias}, /* no =: at&t manual wrong */
+ {"+cd", c_cd},
+ {"+command", c_command},
+ {"echo", c_print},
+ {"*=export", c_typeset},
+#ifdef HISTORY
+ {"+fc", c_fc},
+#endif /* HISTORY */
+ {"+getopts", c_getopts},
+ {"+jobs", c_jobs},
+ {"+kill", c_kill},
+#ifdef KSH
+ {"let", c_let},
+#endif /* KSH */
+ {"print", c_print},
+ {"pwd", c_pwd},
+ {"*=readonly", c_typeset},
+ {"=typeset", c_typeset},
+ {"+unalias", c_unalias},
+ {"whence", c_whence},
+#ifdef JOBS
+ {"+bg", c_fgbg},
+ {"+fg", c_fgbg},
+#endif
+#ifdef EMACS
+ {"bind", c_bind},
+#endif
+ {NULL, NULL}
+};
diff --git a/shells/pdksh/files/c_sh.c b/shells/pdksh/files/c_sh.c
new file mode 100644
index 00000000000..534e8232e38
--- /dev/null
+++ b/shells/pdksh/files/c_sh.c
@@ -0,0 +1,904 @@
+/*
+ * built-in Bourne commands
+ */
+
+#include "sh.h"
+#include "ksh_stat.h" /* umask() */
+#include "ksh_time.h"
+#include "ksh_times.h"
+
+static char *clocktos ARGS((clock_t t));
+
+
+/* :, false and true */
+int
+c_label(wp)
+ char **wp;
+{
+ return wp[0][0] == 'f' ? 1 : 0;
+}
+
+int
+c_shift(wp)
+ char **wp;
+{
+ register struct block *l = e->loc;
+ register int n;
+ long val;
+ char *arg;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ arg = wp[builtin_opt.optind];
+
+ if (arg) {
+ evaluate(arg, &val, KSH_UNWIND_ERROR);
+ n = val;
+ } else
+ n = 1;
+ if (n < 0) {
+ bi_errorf("%s: bad number", arg);
+ return (1);
+ }
+ if (l->argc < n) {
+ bi_errorf("nothing to shift");
+ return (1);
+ }
+ l->argv[n] = l->argv[0];
+ l->argv += n;
+ l->argc -= n;
+ return 0;
+}
+
+int
+c_umask(wp)
+ char **wp;
+{
+ register int i;
+ register char *cp;
+ int symbolic = 0;
+ int old_umask;
+ int optc;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF)
+ switch (optc) {
+ case 'S':
+ symbolic = 1;
+ break;
+ case '?':
+ return 1;
+ }
+ cp = wp[builtin_opt.optind];
+ if (cp == NULL) {
+ old_umask = umask(0);
+ umask(old_umask);
+ if (symbolic) {
+ char buf[18];
+ int j;
+
+ old_umask = ~old_umask;
+ cp = buf;
+ for (i = 0; i < 3; i++) {
+ *cp++ = "ugo"[i];
+ *cp++ = '=';
+ for (j = 0; j < 3; j++)
+ if (old_umask & (1 << (8 - (3*i + j))))
+ *cp++ = "rwx"[j];
+ *cp++ = ',';
+ }
+ cp[-1] = '\0';
+ shprintf("%s\n", buf);
+ } else
+ shprintf("%#3.3o\n", old_umask);
+ } else {
+ int new_umask;
+
+ if (digit(*cp)) {
+ for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
+ new_umask = new_umask * 8 + (*cp - '0');
+ if (*cp) {
+ bi_errorf("bad number");
+ return 1;
+ }
+ } else {
+ /* symbolic format */
+ int positions, new_val;
+ char op;
+
+ old_umask = umask(0);
+ umask(old_umask); /* in case of error */
+ old_umask = ~old_umask;
+ new_umask = old_umask;
+ positions = 0;
+ while (*cp) {
+ while (*cp && strchr("augo", *cp))
+ switch (*cp++) {
+ case 'a': positions |= 0111; break;
+ case 'u': positions |= 0100; break;
+ case 'g': positions |= 0010; break;
+ case 'o': positions |= 0001; break;
+ }
+ if (!positions)
+ positions = 0111; /* default is a */
+ if (!strchr("=+-", op = *cp))
+ break;
+ cp++;
+ new_val = 0;
+ while (*cp && strchr("rwxugoXs", *cp))
+ switch (*cp++) {
+ case 'r': new_val |= 04; break;
+ case 'w': new_val |= 02; break;
+ case 'x': new_val |= 01; break;
+ case 'u': new_val |= old_umask >> 6;
+ break;
+ case 'g': new_val |= old_umask >> 3;
+ break;
+ case 'o': new_val |= old_umask >> 0;
+ break;
+ case 'X': if (old_umask & 0111)
+ new_val |= 01;
+ break;
+ case 's': /* ignored */
+ break;
+ }
+ new_val = (new_val & 07) * positions;
+ switch (op) {
+ case '-':
+ new_umask &= ~new_val;
+ break;
+ case '=':
+ new_umask = new_val
+ | (new_umask & ~(positions * 07));
+ break;
+ case '+':
+ new_umask |= new_val;
+ }
+ if (*cp == ',') {
+ positions = 0;
+ cp++;
+ } else if (!strchr("=+-", *cp))
+ break;
+ }
+ if (*cp) {
+ bi_errorf("bad mask");
+ return 1;
+ }
+ new_umask = ~new_umask;
+ }
+ umask(new_umask);
+ }
+ return 0;
+}
+
+int
+c_dot(wp)
+ char **wp;
+{
+ char *file, *cp;
+ char **argv;
+ int argc;
+ int i;
+ int err;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+
+ if ((cp = wp[builtin_opt.optind]) == NULL)
+ return 0;
+ file = search(cp, path, R_OK, &err);
+ if (file == NULL) {
+ bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
+ return 1;
+ }
+
+ /* Set positional parameters? */
+ if (wp[builtin_opt.optind + 1]) {
+ argv = wp + builtin_opt.optind;
+ argv[0] = e->loc->argv[0]; /* preserve $0 */
+ for (argc = 0; argv[argc + 1]; argc++)
+ ;
+ } else {
+ argc = 0;
+ argv = (char **) 0;
+ }
+ i = include(file, argc, argv, 0);
+ if (i < 0) { /* should not happen */
+ bi_errorf("%s: %s", cp, strerror(errno));
+ return 1;
+ }
+ return i;
+}
+
+int
+c_wait(wp)
+ char **wp;
+{
+ int UNINITIALIZED(rv);
+ int sig;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ wp += builtin_opt.optind;
+ if (*wp == (char *) 0) {
+ while (waitfor((char *) 0, &sig) >= 0)
+ ;
+ rv = sig;
+ } else {
+ for (; *wp; wp++)
+ rv = waitfor(*wp, &sig);
+ if (rv < 0)
+ rv = sig ? sig : 127; /* magic exit code: bad job-id */
+ }
+ return rv;
+}
+
+int
+c_read(wp)
+ char **wp;
+{
+ register int c = 0;
+ int expand = 1, history = 0;
+ int expanding;
+ int ecode = 0;
+ register char *cp;
+ int fd = 0;
+ struct shf *shf;
+ int optc;
+ const char *emsg;
+ XString cs, xs;
+ struct tbl *vp;
+ char UNINITIALIZED(*xp);
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF)
+ switch (optc) {
+#ifdef KSH
+ case 'p':
+ if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
+ bi_errorf("-p: %s", emsg);
+ return 1;
+ }
+ break;
+#endif /* KSH */
+ case 'r':
+ expand = 0;
+ break;
+ case 's':
+ history = 1;
+ break;
+ case 'u':
+ if (!*(cp = builtin_opt.optarg))
+ fd = 0;
+ else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
+ bi_errorf("-u: %s: %s", cp, emsg);
+ return 1;
+ }
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+ if (*wp == NULL)
+ *--wp = "REPLY";
+
+ /* Since we can't necessarily seek backwards on non-regular files,
+ * don't buffer them so we can't read too much.
+ */
+ shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
+
+ if ((cp = strchr(*wp, '?')) != NULL) {
+ *cp = 0;
+ if (isatty(fd)) {
+ /* at&t ksh says it prints prompt on fd if it's open
+ * for writing and is a tty, but it doesn't do it
+ * (it also doesn't check the interactive flag,
+ * as is indicated in the Kornshell book).
+ */
+ shellf("%s", cp+1);
+ }
+ }
+
+#ifdef KSH
+ /* If we are reading from the co-process for the first time,
+ * make sure the other side of the pipe is closed first. This allows
+ * the detection of eof.
+ *
+ * This is not compatiable with at&t ksh... the fd is kept so another
+ * coproc can be started with same ouput, however, this means eof
+ * can't be detected... This is why it is closed here.
+ * If this call is removed, remove the eof check below, too.
+ * coproc_readw_close(fd);
+ */
+#endif /* KSH */
+
+ if (history)
+ Xinit(xs, xp, 128, ATEMP);
+ expanding = 0;
+ Xinit(cs, cp, 128, ATEMP);
+ for (; *wp != NULL; wp++) {
+ for (cp = Xstring(cs, cp); ; ) {
+ if (c == '\n' || c == EOF)
+ break;
+ while (1) {
+ c = shf_getc(shf);
+ if (c == '\0'
+#ifdef OS2
+ || c == '\r'
+#endif /* OS2 */
+ )
+ continue;
+ if (c == EOF && shf_error(shf)
+ && shf_errno(shf) == EINTR)
+ {
+ /* Was the offending signal one that
+ * would normally kill a process?
+ * If so, pretend the read was killed.
+ */
+ ecode = fatal_trap_check();
+
+ /* non fatal (eg, CHLD), carry on */
+ if (!ecode) {
+ shf_clearerr(shf);
+ continue;
+ }
+ }
+ break;
+ }
+ if (history) {
+ Xcheck(xs, xp);
+ Xput(xs, xp, c);
+ }
+ Xcheck(cs, cp);
+ if (expanding) {
+ expanding = 0;
+ if (c == '\n') {
+ c = 0;
+ if (Flag(FTALKING_I) && isatty(fd)) {
+ /* set prompt in case this is
+ * called from .profile or $ENV
+ */
+ set_prompt(PS2, (Source *) 0);
+ pprompt(prompt, 0);
+ }
+ } else if (c != EOF)
+ Xput(cs, cp, c);
+ continue;
+ }
+ if (expand && c == '\\') {
+ expanding = 1;
+ continue;
+ }
+ if (c == '\n' || c == EOF)
+ break;
+ if (ctype(c, C_IFS)) {
+ if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
+ continue;
+ if (wp[1])
+ break;
+ }
+ Xput(cs, cp, c);
+ }
+ /* strip trailing IFS white space from last variable */
+ if (!wp[1])
+ while (Xlength(cs, cp) && ctype(cp[-1], C_IFS)
+ && ctype(cp[-1], C_IFSWS))
+ cp--;
+ Xput(cs, cp, '\0');
+ vp = global(*wp);
+ /* Must be done before setting export. */
+ if (vp->flag & RDONLY) {
+ shf_flush(shf);
+ bi_errorf("%s is read only", *wp);
+ return 1;
+ }
+ if (Flag(FEXPORT))
+ typeset(*wp, EXPORT, 0, 0, 0);
+ if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
+ shf_flush(shf);
+ return 1;
+ }
+ }
+
+ shf_flush(shf);
+ if (history) {
+ Xput(xs, xp, '\0');
+ source->line++;
+ histsave(source->line, Xstring(xs, xp), 1);
+ Xfree(xs, xp);
+ }
+#ifdef KSH
+ /* if this is the co-process fd, close the file descriptor
+ * (can get eof if and only if all processes are have died, ie,
+ * coproc.njobs is 0 and the pipe is closed).
+ */
+ if (c == EOF && !ecode)
+ coproc_read_close(fd);
+#endif /* KSH */
+
+ return ecode ? ecode : c == EOF;
+}
+
+int
+c_eval(wp)
+ char **wp;
+{
+ register struct source *s;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ s = pushs(SWORDS, ATEMP);
+ s->u.strv = wp + builtin_opt.optind;
+ if (!Flag(FPOSIX)) {
+ /*
+ * Handle case where the command is empty due to failed
+ * command substitution, eg, eval "$(false)".
+ * In this case, shell() will not set/change exstat (because
+ * compiled tree is empty), so will use this value.
+ * subst_exstat is cleared in execute(), so should be 0 if
+ * there were no substitutions.
+ *
+ * A strict reading of POSIX says we don't do this (though
+ * it is traditionally done). [from 1003.2-1992]
+ * 3.9.1: Simple Commands
+ * ... If there is a command name, execution shall
+ * continue as described in 3.9.1.1. If there
+ * is no command name, but the command contained a command
+ * substitution, the command shall complete with the exit
+ * status of the last command substitution
+ * 3.9.1.1: Command Search and Execution
+ * ...(1)...(a) If the command name matches the name of
+ * a special built-in utility, that special built-in
+ * utility shall be invoked.
+ * 3.14.5: Eval
+ * ... If there are no arguments, or only null arguments,
+ * eval shall return an exit status of zero.
+ */
+ exstat = subst_exstat;
+ }
+
+ return shell(s, FALSE);
+}
+
+int
+c_trap(wp)
+ char **wp;
+{
+ int i;
+ char *s;
+ register Trap *p;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ wp += builtin_opt.optind;
+
+ if (*wp == NULL) {
+ int anydfl = 0;
+
+ for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
+ if (p->trap == NULL)
+ anydfl = 1;
+ else {
+ shprintf("trap -- ");
+ print_value_quoted(p->trap);
+ shprintf(" %s\n", p->name);
+ }
+ }
+#if 0 /* this is ugly and not clear POSIX needs it */
+ /* POSIX may need this so output of trap can be saved and
+ * used to restore trap conditions
+ */
+ if (anydfl) {
+ shprintf("trap -- -");
+ for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
+ if (p->trap == NULL && p->name)
+ shprintf(" %s", p->name);
+ shprintf(newline);
+ }
+#endif
+ return 0;
+ }
+
+ /*
+ * Use case sensitive lookup for first arg so the
+ * command 'exit' isn't confused with the pseudo-signal
+ * 'EXIT'.
+ */
+ s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */
+ if (s != NULL && s[0] == '-' && s[1] == '\0')
+ s = NULL;
+
+ /* set/clear traps */
+ while (*wp != NULL) {
+ p = gettrap(*wp++, TRUE);
+ if (p == NULL) {
+ bi_errorf("bad signal %s", wp[-1]);
+ return 1;
+ }
+ settrap(p, s);
+ }
+ return 0;
+}
+
+int
+c_exitreturn(wp)
+ char **wp;
+{
+ int how = LEXIT;
+ int n;
+ char *arg;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ arg = wp[builtin_opt.optind];
+
+ if (arg) {
+ if (!getn(arg, &n)) {
+ exstat = 1;
+ warningf(TRUE, "%s: bad number", arg);
+ } else
+ exstat = n;
+ }
+ if (wp[0][0] == 'r') { /* return */
+ struct env *ep;
+
+ /* need to tell if this is exit or return so trap exit will
+ * work right (POSIX)
+ */
+ for (ep = e; ep; ep = ep->oenv)
+ if (STOP_RETURN(ep->type)) {
+ how = LRETURN;
+ break;
+ }
+ }
+
+ if (how == LEXIT && !really_exit && j_stopped_running()) {
+ really_exit = 1;
+ how = LSHELL;
+ }
+
+ quitenv(); /* get rid of any i/o redirections */
+ unwind(how);
+ /*NOTREACHED*/
+ return 0;
+}
+
+int
+c_brkcont(wp)
+ char **wp;
+{
+ int n, quit;
+ struct env *ep, *last_ep = (struct env *) 0;
+ char *arg;
+
+ if (ksh_getopt(wp, &builtin_opt, null) == '?')
+ return 1;
+ arg = wp[builtin_opt.optind];
+
+ if (!arg)
+ n = 1;
+ else if (!bi_getn(arg, &n))
+ return 1;
+ quit = n;
+ if (quit <= 0) {
+ /* at&t ksh does this for non-interactive shells only - weird */
+ bi_errorf("%s: bad value", arg);
+ return 1;
+ }
+
+ /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
+ for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
+ if (ep->type == E_LOOP) {
+ if (--quit == 0)
+ break;
+ ep->flags |= EF_BRKCONT_PASS;
+ last_ep = ep;
+ }
+
+ if (quit) {
+ /* at&t ksh doesn't print a message - just does what it
+ * can. We print a message 'cause it helps in debugging
+ * scripts, but don't generate an error (ie, keep going).
+ */
+ if (n == quit) {
+ warningf(TRUE, "%s: cannot %s", wp[0], wp[0]);
+ return 0;
+ }
+ /* POSIX says if n is too big, the last enclosing loop
+ * shall be used. Doesn't say to print an error but we
+ * do anyway 'cause the user messed up.
+ */
+ last_ep->flags &= ~EF_BRKCONT_PASS;
+ warningf(TRUE, "%s: can only %s %d level(s)",
+ wp[0], wp[0], n - quit);
+ }
+
+ unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
+ /*NOTREACHED*/
+}
+
+int
+c_set(wp)
+ char **wp;
+{
+ int argi, setargs;
+ struct block *l = e->loc;
+ register char **owp = wp;
+
+ if (wp[1] == NULL) {
+ static const char *const args [] = { "set", "-", NULL };
+ return c_typeset((char **) args);
+ }
+
+ argi = parse_args(wp, OF_SET, &setargs);
+ if (argi < 0)
+ return 1;
+ /* set $# and $* */
+ if (setargs) {
+ owp = wp += argi - 1;
+ wp[0] = l->argv[0]; /* save $0 */
+ while (*++wp != NULL)
+ *wp = str_save(*wp, &l->area);
+ l->argc = wp - owp - 1;
+ l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
+ for (wp = l->argv; (*wp++ = *owp++) != NULL; )
+ ;
+ }
+ /* POSIX says set exit status is 0, but old scripts that use
+ * getopt(1), use the construct: set -- `getopt ab:c "$@"`
+ * which assumes the exit value set will be that of the ``
+ * (subst_exstat is cleared in execute() so that it will be 0
+ * if there are no command substitutions).
+ */
+ return Flag(FPOSIX) ? 0 : subst_exstat;
+}
+
+int
+c_unset(wp)
+ char **wp;
+{
+ register char *id;
+ int optc, unset_var = 1;
+ int ret = 0;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
+ switch (optc) {
+ case 'f':
+ unset_var = 0;
+ break;
+ case 'v':
+ unset_var = 1;
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+ for (; (id = *wp) != NULL; wp++)
+ if (unset_var) { /* unset variable */
+ struct tbl *vp = global(id);
+
+ if (!(vp->flag & ISSET))
+ ret = 1;
+ if ((vp->flag&RDONLY)) {
+ bi_errorf("%s is read only", vp->name);
+ return 1;
+ }
+ unset(vp, strchr(id, '[') ? 1 : 0);
+ } else { /* unset function */
+ if (define(id, (struct op *) NULL))
+ ret = 1;
+ }
+ return ret;
+}
+
+int
+c_times(wp)
+ char **wp;
+{
+ struct tms all;
+
+ (void) ksh_times(&all);
+ shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
+ shprintf("%8ss system\n", clocktos(all.tms_stime));
+ shprintf("Kids: %8ss user ", clocktos(all.tms_cutime));
+ shprintf("%8ss system\n", clocktos(all.tms_cstime));
+
+ return 0;
+}
+
+/*
+ * time pipeline (really a statement, not a built-in command)
+ */
+int
+timex(t, f)
+ struct op *t;
+ int f;
+{
+#define TF_NOARGS BIT(0)
+#define TF_NOREAL BIT(1) /* don't report real time */
+#define TF_POSIX BIT(2) /* report in posix format */
+ int rv = 0;
+ struct tms t0, t1, tms;
+ clock_t t0t, t1t = 0;
+ int tf = 0;
+ extern clock_t j_usrtime, j_systime; /* computed by j_wait */
+ char opts[1];
+
+ t0t = ksh_times(&t0);
+ if (t->left) {
+ /*
+ * Two ways of getting cpu usage of a command: just use t0
+ * and t1 (which will get cpu usage from other jobs that
+ * finish while we are executing t->left), or get the
+ * cpu usage of t->left. at&t ksh does the former, while
+ * pdksh tries to do the later (the j_usrtime hack doesn't
+ * really work as it only counts the last job).
+ */
+ j_usrtime = j_systime = 0;
+ if (t->left->type == TCOM)
+ t->left->str = opts;
+ opts[0] = 0;
+ rv = execute(t->left, f | XTIME);
+ tf |= opts[0];
+ t1t = ksh_times(&t1);
+ } else
+ tf = TF_NOARGS;
+
+ if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
+ tf |= TF_NOREAL;
+ tms.tms_utime = t0.tms_utime + t0.tms_cutime;
+ tms.tms_stime = t0.tms_stime + t0.tms_cstime;
+ } else {
+ tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime;
+ tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime;
+ }
+
+ if (!(tf & TF_NOREAL))
+ shf_fprintf(shl_out,
+ tf & TF_POSIX ? "real %8s\n" : "%8ss real ",
+ clocktos(t1t - t0t));
+ shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ",
+ clocktos(tms.tms_utime));
+ shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n",
+ clocktos(tms.tms_stime));
+ shf_flush(shl_out);
+
+ return rv;
+}
+
+void
+timex_hook(t, app)
+ struct op *t;
+ char ** volatile *app;
+{
+ char **wp = *app;
+ int optc;
+ int i, j;
+ Getopt opt;
+
+ ksh_getopt_reset(&opt, 0);
+ opt.optind = 0; /* start at the start */
+ while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF)
+ switch (optc) {
+ case 'p':
+ t->str[0] |= TF_POSIX;
+ break;
+ case '?':
+ errorf("time: -%s unknown option", opt.optarg);
+ case ':':
+ errorf("time: -%s requires an argument",
+ opt.optarg);
+ }
+ /* Copy command words down over options. */
+ if (opt.optind != 0) {
+ for (i = 0; i < opt.optind; i++)
+ afree(wp[i], ATEMP);
+ for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
+ ;
+ }
+ if (!wp[0])
+ t->str[0] |= TF_NOARGS;
+ *app = wp;
+}
+
+static char *
+clocktos(t)
+ clock_t t;
+{
+ static char temp[22]; /* enough for 64 bit clock_t */
+ register int i;
+ register char *cp = temp + sizeof(temp);
+
+ /* note: posix says must use max precision, ie, if clk_tck is
+ * 1000, must print 3 places after decimal (if non-zero, else 1).
+ */
+ if (CLK_TCK != 100) /* convert to 1/100'ths */
+ t = (t < 1000000000/CLK_TCK) ?
+ (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
+
+ *--cp = '\0';
+ for (i = -2; i <= 0 || t > 0; i++) {
+ if (i == 0)
+ *--cp = '.';
+ *--cp = '0' + (char)(t%10);
+ t /= 10;
+ }
+ return cp;
+}
+
+/* exec with no args - args case is taken care of in comexec() */
+int
+c_exec(wp)
+ char ** wp;
+{
+ int i;
+
+ /* make sure redirects stay in place */
+ if (e->savefd != NULL) {
+ for (i = 0; i < NUFILE; i++) {
+ if (e->savefd[i] > 0)
+ close(e->savefd[i]);
+ /*
+ * For ksh keep anything > 2 private,
+ * for sh, let them be (POSIX says what
+ * happens is unspecified and the bourne shell
+ * keeps them open).
+ */
+#ifdef KSH
+ if (i > 2 && e->savefd[i])
+ fd_clexec(i);
+#endif /* KSH */
+ }
+ e->savefd = NULL;
+ }
+ return 0;
+}
+
+/* dummy function, special case in comexec() */
+int
+c_builtin(wp)
+ char ** wp;
+{
+ return 0;
+}
+
+extern int c_test ARGS((char **wp)); /* in c_test.c */
+extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */
+
+/* A leading = means assignments before command are kept;
+ * a leading * means a POSIX special builtin;
+ * a leading + means a POSIX regular builtin
+ * (* and + should not be combined).
+ */
+const struct builtin shbuiltins [] = {
+ {"*=.", c_dot},
+ {"*=:", c_label},
+ {"[", c_test},
+ {"*=break", c_brkcont},
+ {"=builtin", c_builtin},
+ {"*=continue", c_brkcont},
+ {"*=eval", c_eval},
+ {"*=exec", c_exec},
+ {"*=exit", c_exitreturn},
+ {"+false", c_label},
+ {"*=return", c_exitreturn},
+ {"*=set", c_set},
+ {"*=shift", c_shift},
+ {"=times", c_times},
+ {"*=trap", c_trap},
+ {"+=wait", c_wait},
+ {"+read", c_read},
+ {"test", c_test},
+ {"+true", c_label},
+ {"ulimit", c_ulimit},
+ {"+umask", c_umask},
+ {"*=unset", c_unset},
+#ifdef OS2
+ /* In OS2, the first line of a file can be "extproc name", which
+ * tells the command interpreter (cmd.exe) to use name to execute
+ * the file. For this to be useful, ksh must ignore commands
+ * starting with extproc and this does the trick...
+ */
+ {"extproc", c_label},
+#endif /* OS2 */
+ {NULL, NULL}
+};
diff --git a/shells/pdksh/files/c_test.c b/shells/pdksh/files/c_test.c
new file mode 100644
index 00000000000..63cfaf57ee2
--- /dev/null
+++ b/shells/pdksh/files/c_test.c
@@ -0,0 +1,662 @@
+/*
+ * test(1); version 7-like -- author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by Michael Rendell to add Korn's [[ .. ]] expressions.
+ * modified by J.T. Conklin to add POSIX compatibility.
+ */
+
+#include "sh.h"
+#include "ksh_stat.h"
+#include "c_test.h"
+
+/* test(1) accepts the following grammar:
+ oexpr ::= aexpr | aexpr "-o" oexpr ;
+ aexpr ::= nexpr | nexpr "-a" aexpr ;
+ nexpr ::= primary | "!" nexpr ;
+ primary ::= unary-operator operand
+ | operand binary-operator operand
+ | operand
+ | "(" oexpr ")"
+ ;
+
+ unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
+ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
+ "-L"|"-h"|"-S"|"-H";
+
+ binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ "-nt"|"-ot"|"-ef"|
+ "<"|">" # rules used for [[ .. ]] expressions
+ ;
+ operand ::= <any thing>
+*/
+
+#define T_ERR_EXIT 2 /* POSIX says > 1 for errors */
+
+struct t_op {
+ char op_text[4];
+ Test_op op_num;
+};
+static const struct t_op u_ops [] = {
+ {"-a", TO_FILAXST },
+ {"-b", TO_FILBDEV },
+ {"-c", TO_FILCDEV },
+ {"-d", TO_FILID },
+ {"-e", TO_FILEXST },
+ {"-f", TO_FILREG },
+ {"-G", TO_FILGID },
+ {"-g", TO_FILSETG },
+ {"-h", TO_FILSYM },
+ {"-H", TO_FILCDF },
+ {"-k", TO_FILSTCK },
+ {"-L", TO_FILSYM },
+ {"-n", TO_STNZE },
+ {"-O", TO_FILUID },
+ {"-o", TO_OPTION },
+ {"-p", TO_FILFIFO },
+ {"-r", TO_FILRD },
+ {"-s", TO_FILGZ },
+ {"-S", TO_FILSOCK },
+ {"-t", TO_FILTT },
+ {"-u", TO_FILSETU },
+ {"-w", TO_FILWR },
+ {"-x", TO_FILEX },
+ {"-z", TO_STZER },
+ {"", TO_NONOP }
+ };
+static const struct t_op b_ops [] = {
+ {"=", TO_STEQL },
+#ifdef KSH
+ {"==", TO_STEQL },
+#endif /* KSH */
+ {"!=", TO_STNEQ },
+ {"<", TO_STLT },
+ {">", TO_STGT },
+ {"-eq", TO_INTEQ },
+ {"-ne", TO_INTNE },
+ {"-gt", TO_INTGT },
+ {"-ge", TO_INTGE },
+ {"-lt", TO_INTLT },
+ {"-le", TO_INTLE },
+ {"-ef", TO_FILEQ },
+ {"-nt", TO_FILNT },
+ {"-ot", TO_FILOT },
+ {"", TO_NONOP }
+ };
+
+static int test_stat ARGS((const char *path, struct stat *statb));
+static int test_eaccess ARGS((const char *path, int mode));
+static int test_oexpr ARGS((Test_env *te, int do_eval));
+static int test_aexpr ARGS((Test_env *te, int do_eval));
+static int test_nexpr ARGS((Test_env *te, int do_eval));
+static int test_primary ARGS((Test_env *te, int do_eval));
+static int ptest_isa ARGS((Test_env *te, Test_meta meta));
+static const char *ptest_getopnd ARGS((Test_env *te, Test_op op, int do_eval));
+static int ptest_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
+ const char *opnd2, int do_eval));
+static void ptest_error ARGS((Test_env *te, int offset, const char *msg));
+
+int
+c_test(wp)
+ char **wp;
+{
+ int argc;
+ int res;
+ Test_env te;
+
+ te.flags = 0;
+ te.isa = ptest_isa;
+ te.getopnd = ptest_getopnd;
+ te.eval = ptest_eval;
+ te.error = ptest_error;
+
+ for (argc = 0; wp[argc]; argc++)
+ ;
+
+ if (strcmp(wp[0], "[") == 0) {
+ if (strcmp(wp[--argc], "]") != 0) {
+ bi_errorf("missing ]");
+ return T_ERR_EXIT;
+ }
+ }
+
+ te.pos.wp = wp + 1;
+ te.wp_end = wp + argc;
+
+ /*
+ * Handle the special cases from POSIX.2, section 4.62.4.
+ * Implementation of all the rules isn't necessary since
+ * our parser does the right thing for the ommited steps.
+ */
+ if (argc <= 5) {
+ char **owp = wp;
+ int invert = 0;
+ Test_op op;
+ const char *opnd1, *opnd2;
+
+ while (--argc >= 0) {
+ if ((*te.isa)(&te, TM_END))
+ return !0;
+ if (argc == 3) {
+ opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
+ if ((op = (Test_op) (*te.isa)(&te, TM_BINOP))) {
+ opnd2 = (*te.getopnd)(&te, op, 1);
+ res = (*te.eval)(&te, op, opnd1, opnd2,
+ 1);
+ if (te.flags & TEF_ERROR)
+ return T_ERR_EXIT;
+ if (invert & 1)
+ res = !res;
+ return !res;
+ }
+ /* back up to opnd1 */
+ te.pos.wp--;
+ }
+ if (argc == 1) {
+ opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
+ /* Historically, -t by itself test if fd 1
+ * is a file descriptor, but POSIX says its
+ * a string test...
+ */
+ if (!Flag(FPOSIX) && strcmp(opnd1, "-t") == 0)
+ break;
+ res = (*te.eval)(&te, TO_STNZE, opnd1,
+ (char *) 0, 1);
+ if (invert & 1)
+ res = !res;
+ return !res;
+ }
+ if ((*te.isa)(&te, TM_NOT)) {
+ invert++;
+ } else
+ break;
+ }
+ te.pos.wp = owp + 1;
+ }
+
+ return test_parse(&te);
+}
+
+/*
+ * Generic test routines.
+ */
+
+Test_op
+test_isop(te, meta, s)
+ Test_env *te;
+ Test_meta meta;
+ const char *s;
+{
+ char sc1;
+ const struct t_op *otab;
+
+ otab = meta == TM_UNOP ? u_ops : b_ops;
+ if (*s) {
+ sc1 = s[1];
+ for (; otab->op_text[0]; otab++)
+ if (sc1 == otab->op_text[1]
+ && strcmp(s, otab->op_text) == 0
+ && ((te->flags & TEF_DBRACKET)
+ || (otab->op_num != TO_STLT
+ && otab->op_num != TO_STGT)))
+ return otab->op_num;
+ }
+ return TO_NONOP;
+}
+
+int
+test_eval(te, op, opnd1, opnd2, do_eval)
+ Test_env *te;
+ Test_op op;
+ const char *opnd1;
+ const char *opnd2;
+ int do_eval;
+{
+ int res;
+ int not;
+ struct stat b1, b2;
+
+ if (!do_eval)
+ return 0;
+
+ switch ((int) op) {
+ /*
+ * Unary Operators
+ */
+ case TO_STNZE: /* -n */
+ return *opnd1 != '\0';
+ case TO_STZER: /* -z */
+ return *opnd1 == '\0';
+ case TO_OPTION: /* -o */
+ if ((not = *opnd1 == '!'))
+ opnd1++;
+ if ((res = option(opnd1)) < 0)
+ res = 0;
+ else {
+ res = Flag(res);
+ if (not)
+ res = !res;
+ }
+ return res;
+ case TO_FILRD: /* -r */
+ return test_eaccess(opnd1, R_OK) == 0;
+ case TO_FILWR: /* -w */
+ return test_eaccess(opnd1, W_OK) == 0;
+ case TO_FILEX: /* -x */
+ return test_eaccess(opnd1, X_OK) == 0;
+ case TO_FILAXST: /* -a */
+ return test_stat(opnd1, &b1) == 0;
+ case TO_FILEXST: /* -e */
+ /* at&t ksh does not appear to do the /dev/fd/ thing for
+ * this (unless the os itself handles it)
+ */
+ return stat(opnd1, &b1) == 0;
+ case TO_FILREG: /* -r */
+ return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode);
+ case TO_FILID: /* -d */
+ return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode);
+ case TO_FILCDEV: /* -c */
+#ifdef S_ISCHR
+ return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode);
+#else
+ return 0;
+#endif
+ case TO_FILBDEV: /* -b */
+#ifdef S_ISBLK
+ return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode);
+#else
+ return 0;
+#endif
+ case TO_FILFIFO: /* -p */
+#ifdef S_ISFIFO
+ return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode);
+#else
+ return 0;
+#endif
+ case TO_FILSYM: /* -h -L */
+#ifdef S_ISLNK
+ return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode);
+#else
+ return 0;
+#endif
+ case TO_FILSOCK: /* -S */
+#ifdef S_ISSOCK
+ return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode);
+#else
+ return 0;
+#endif
+ case TO_FILCDF:/* -H HP context dependent files (directories) */
+#ifdef S_ISCDF
+ {
+ /* Append a + to filename and check to see if result is a
+ * setuid directory. CDF stuff in general is hookey, since
+ * it breaks for the following sequence: echo hi > foo+;
+ * mkdir foo; echo bye > foo/default; chmod u+s foo
+ * (foo+ refers to the file with hi in it, there is no way
+ * to get at the file with bye in it - please correct me if
+ * I'm wrong about this).
+ */
+ int len = strlen(opnd1);
+ char *p = str_nsave(opnd1, len + 1, ATEMP);
+
+ p[len++] = '+';
+ p[len] = '\0';
+ return stat(p, &b1) == 0 && S_ISCDF(b1.st_mode);
+ }
+#else
+ return 0;
+#endif
+ case TO_FILSETU: /* -u */
+#ifdef S_ISUID
+ return test_stat(opnd1, &b1) == 0
+ && (b1.st_mode & S_ISUID) == S_ISUID;
+#else
+ return 0;
+#endif
+ case TO_FILSETG: /* -g */
+#ifdef S_ISGID
+ return test_stat(opnd1, &b1) == 0
+ && (b1.st_mode & S_ISGID) == S_ISGID;
+#else
+ return 0;
+#endif
+ case TO_FILSTCK: /* -k */
+ return test_stat(opnd1, &b1) == 0
+ && (b1.st_mode & S_ISVTX) == S_ISVTX;
+ case TO_FILGZ: /* -s */
+ return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L;
+ case TO_FILTT: /* -t */
+ if (opnd1 && !bi_getn(opnd1, &res)) {
+ te->flags |= TEF_ERROR;
+ res = 0;
+ } else {
+ /* generate error if in FPOSIX mode? */
+ res = isatty(opnd1 ? res : 0);
+ }
+ return res;
+ case TO_FILUID: /* -O */
+ return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid;
+ case TO_FILGID: /* -G */
+ return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid();
+ /*
+ * Binary Operators
+ */
+ case TO_STEQL: /* = */
+ if (te->flags & TEF_DBRACKET)
+ return gmatch(opnd1, opnd2, FALSE);
+ return strcmp(opnd1, opnd2) == 0;
+ case TO_STNEQ: /* != */
+ if (te->flags & TEF_DBRACKET)
+ return !gmatch(opnd1, opnd2, FALSE);
+ return strcmp(opnd1, opnd2) != 0;
+ case TO_STLT: /* < */
+ return strcmp(opnd1, opnd2) < 0;
+ case TO_STGT: /* > */
+ return strcmp(opnd1, opnd2) > 0;
+ case TO_INTEQ: /* -eq */
+ case TO_INTNE: /* -ne */
+ case TO_INTGE: /* -ge */
+ case TO_INTGT: /* -gt */
+ case TO_INTLE: /* -le */
+ case TO_INTLT: /* -lt */
+ {
+ long v1, v2;
+
+ if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR)
+ || !evaluate(opnd2, &v2, KSH_RETURN_ERROR))
+ {
+ /* error already printed.. */
+ te->flags |= TEF_ERROR;
+ return 1;
+ }
+ switch ((int) op) {
+ case TO_INTEQ:
+ return v1 == v2;
+ case TO_INTNE:
+ return v1 != v2;
+ case TO_INTGE:
+ return v1 >= v2;
+ case TO_INTGT:
+ return v1 > v2;
+ case TO_INTLE:
+ return v1 <= v2;
+ case TO_INTLT:
+ return v1 < v2;
+ }
+ }
+ case TO_FILNT: /* -nt */
+ {
+ int s2;
+ /* ksh88/ksh93 succeed if file2 can't be stated
+ * (subtly different from `does not exist').
+ */
+ return stat(opnd1, &b1) == 0
+ && (((s2 = stat(opnd2, &b2)) == 0
+ && b1.st_mtime > b2.st_mtime) || s2 < 0);
+ }
+ case TO_FILOT: /* -ot */
+ {
+ int s1;
+ /* ksh88/ksh93 succeed if file1 can't be stated
+ * (subtly different from `does not exist').
+ */
+ return stat(opnd2, &b2) == 0
+ && (((s1 = stat(opnd1, &b1)) == 0
+ && b1.st_mtime < b2.st_mtime) || s1 < 0);
+ }
+ case TO_FILEQ: /* -ef */
+ return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0
+ && b1.st_dev == b2.st_dev
+ && b1.st_ino == b2.st_ino;
+ }
+ (*te->error)(te, 0, "internal error: unknown op");
+ return 1;
+}
+
+/* Nasty kludge to handle Korn's bizarre /dev/fd hack */
+static int
+test_stat(path, statb)
+ const char *path;
+ struct stat *statb;
+{
+#if !defined(HAVE_DEV_FD)
+ int fd;
+
+ if (strncmp(path, "/dev/fd/", 8) == 0 && getn(path + 8, &fd))
+ return fstat(fd, statb);
+#endif /* !HAVE_DEV_FD */
+
+ return stat(path, statb);
+}
+
+/* Routine to handle Korn's /dev/fd hack, and to deal with X_OK on
+ * non-directories when running as root.
+ */
+static int
+test_eaccess(path, mode)
+ const char *path;
+ int mode;
+{
+ int res;
+
+#if !defined(HAVE_DEV_FD)
+ int fd;
+
+ /* Note: doesn't handle //dev/fd, etc.. (this is ok) */
+ if (strncmp(path, "/dev/fd/", 8) == 0 && getn(path + 8, &fd)) {
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL, 0)) < 0
+ || (mode & X_OK)
+ || ((mode & W_OK) && (flags & O_ACCMODE) == O_RDONLY)
+ || ((mode & R_OK) && (flags & O_ACCMODE) == O_WRONLY))
+ return -1;
+ return 0;
+ }
+#endif /* !HAVE_DEV_FD */
+
+ /* On most (all?) unixes, access() says everything is executable for
+ * root - avoid this on files by using stat().
+ */
+ if ((mode & X_OK) && ksheuid == 0) {
+ struct stat statb;
+
+ if (stat(path, &statb) < 0)
+ res = -1;
+ else if (S_ISDIR(statb.st_mode))
+ res = 0;
+ else
+ res = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+ ? 0 : -1;
+ /* Need to check other permissions? If so, use access() as
+ * this will deal with root on NFS.
+ */
+ if (res == 0 && (mode & (R_OK|W_OK)))
+ res = eaccess(path, mode);
+ } else
+ res = eaccess(path, mode);
+
+ return res;
+}
+
+int
+test_parse(te)
+ Test_env *te;
+{
+ int res;
+
+ res = test_oexpr(te, 1);
+
+ if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
+ (*te->error)(te, 0, "unexpected operator/operand");
+
+ return (te->flags & TEF_ERROR) ? T_ERR_EXIT : !res;
+}
+
+static int
+test_oexpr(te, do_eval)
+ Test_env *te;
+ int do_eval;
+{
+ int res;
+
+ res = test_aexpr(te, do_eval);
+ if (res)
+ do_eval = 0;
+ if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
+ return test_oexpr(te, do_eval) || res;
+ return res;
+}
+
+static int
+test_aexpr(te, do_eval)
+ Test_env *te;
+ int do_eval;
+{
+ int res;
+
+ res = test_nexpr(te, do_eval);
+ if (!res)
+ do_eval = 0;
+ if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
+ return test_aexpr(te, do_eval) && res;
+ return res;
+}
+
+static int
+test_nexpr(te, do_eval)
+ Test_env *te;
+ int do_eval;
+{
+ if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
+ return !test_nexpr(te, do_eval);
+ return test_primary(te, do_eval);
+}
+
+static int
+test_primary(te, do_eval)
+ Test_env *te;
+ int do_eval;
+{
+ const char *opnd1, *opnd2;
+ int res;
+ Test_op op;
+
+ if (te->flags & TEF_ERROR)
+ return 0;
+ if ((*te->isa)(te, TM_OPAREN)) {
+ res = test_oexpr(te, do_eval);
+ if (te->flags & TEF_ERROR)
+ return 0;
+ if (!(*te->isa)(te, TM_CPAREN)) {
+ (*te->error)(te, 0, "missing closing paren");
+ return 0;
+ }
+ return res;
+ }
+ if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) {
+ /* unary expression */
+ opnd1 = (*te->getopnd)(te, op, do_eval);
+ if (!opnd1) {
+ (*te->error)(te, -1, "missing argument");
+ return 0;
+ }
+
+ return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval);
+ }
+ opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
+ if (!opnd1) {
+ (*te->error)(te, 0, "expression expected");
+ return 0;
+ }
+ if ((op = (Test_op) (*te->isa)(te, TM_BINOP))) {
+ /* binary expression */
+ opnd2 = (*te->getopnd)(te, op, do_eval);
+ if (!opnd2) {
+ (*te->error)(te, -1, "missing second argument");
+ return 0;
+ }
+
+ return (*te->eval)(te, op, opnd1, opnd2, do_eval);
+ }
+ if (te->flags & TEF_DBRACKET) {
+ (*te->error)(te, -1, "missing expression operator");
+ return 0;
+ }
+ return (*te->eval)(te, TO_STNZE, opnd1, (const char *) 0, do_eval);
+}
+
+/*
+ * Plain test (test and [ .. ]) specific routines.
+ */
+
+/* Test if the current token is a whatever. Accepts the current token if
+ * it is. Returns 0 if it is not, non-zero if it is (in the case of
+ * TM_UNOP and TM_BINOP, the returned value is a Test_op).
+ */
+static int
+ptest_isa(te, meta)
+ Test_env *te;
+ Test_meta meta;
+{
+ /* Order important - indexed by Test_meta values */
+ static const char *const tokens[] = {
+ "-o", "-a", "!", "(", ")"
+ };
+ int ret;
+
+ if (te->pos.wp >= te->wp_end)
+ return meta == TM_END;
+
+ if (meta == TM_UNOP || meta == TM_BINOP)
+ ret = (int) test_isop(te, meta, *te->pos.wp);
+ else if (meta == TM_END)
+ ret = 0;
+ else
+ ret = strcmp(*te->pos.wp, tokens[(int) meta]) == 0;
+
+ /* Accept the token? */
+ if (ret)
+ te->pos.wp++;
+
+ return ret;
+}
+
+static const char *
+ptest_getopnd(te, op, do_eval)
+ Test_env *te;
+ Test_op op;
+ int do_eval;
+{
+ if (te->pos.wp >= te->wp_end)
+ return op == TO_FILTT ? "1" : (const char *) 0;
+ return *te->pos.wp++;
+}
+
+static int
+ptest_eval(te, op, opnd1, opnd2, do_eval)
+ Test_env *te;
+ Test_op op;
+ const char *opnd1;
+ const char *opnd2;
+ int do_eval;
+{
+ return test_eval(te, op, opnd1, opnd2, do_eval);
+}
+
+static void
+ptest_error(te, offset, msg)
+ Test_env *te;
+ int offset;
+ const char *msg;
+{
+ const char *op = te->pos.wp + offset >= te->wp_end ?
+ (const char *) 0 : te->pos.wp[offset];
+
+ te->flags |= TEF_ERROR;
+ if (op)
+ bi_errorf("%s: %s", op, msg);
+ else
+ bi_errorf("%s", msg);
+}
diff --git a/shells/pdksh/files/c_test.h b/shells/pdksh/files/c_test.h
new file mode 100644
index 00000000000..951dd9abd43
--- /dev/null
+++ b/shells/pdksh/files/c_test.h
@@ -0,0 +1,53 @@
+/* Various types of operations. Keeping things grouped nicely
+ * (unary,binary) makes switch() statements more efficeint.
+ */
+enum Test_op {
+ TO_NONOP = 0, /* non-operator */
+ /* unary operators */
+ TO_STNZE, TO_STZER, TO_OPTION,
+ TO_FILAXST,
+ TO_FILEXST,
+ TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK,
+ TO_FILCDF, TO_FILID, TO_FILGID, TO_FILSETG, TO_FILSTCK, TO_FILUID,
+ TO_FILRD, TO_FILGZ, TO_FILTT, TO_FILSETU, TO_FILWR, TO_FILEX,
+ /* binary operators */
+ TO_STEQL, TO_STNEQ, TO_STLT, TO_STGT, TO_INTEQ, TO_INTNE, TO_INTGT,
+ TO_INTGE, TO_INTLT, TO_INTLE, TO_FILEQ, TO_FILNT, TO_FILOT
+};
+typedef enum Test_op Test_op;
+
+/* Used by Test_env.isa() (order important - used to index *_tokens[] arrays) */
+enum Test_meta {
+ TM_OR, /* -o or || */
+ TM_AND, /* -a or && */
+ TM_NOT, /* ! */
+ TM_OPAREN, /* ( */
+ TM_CPAREN, /* ) */
+ TM_UNOP, /* unary operator */
+ TM_BINOP, /* binary operator */
+ TM_END /* end of input */
+};
+typedef enum Test_meta Test_meta;
+
+#define TEF_ERROR BIT(0) /* set if we've hit an error */
+#define TEF_DBRACKET BIT(1) /* set if [[ .. ]] test */
+
+typedef struct test_env Test_env;
+struct test_env {
+ int flags; /* TEF_* */
+ union {
+ char **wp; /* used by ptest_* */
+ XPtrV *av; /* used by dbtestp_* */
+ } pos;
+ char **wp_end; /* used by ptest_* */
+ int (*isa) ARGS((Test_env *te, Test_meta meta));
+ const char *(*getopnd) ARGS((Test_env *te, Test_op op, int do_eval));
+ int (*eval) ARGS((Test_env *te, Test_op op, const char *opnd1,
+ const char *opnd2, int do_eval));
+ void (*error) ARGS((Test_env *te, int offset, const char *msg));
+};
+
+Test_op test_isop ARGS((Test_env *te, Test_meta meta, const char *s));
+int test_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
+ const char *opnd2, int do_eval));
+int test_parse ARGS((Test_env *te));
diff --git a/shells/pdksh/files/c_ulimit.c b/shells/pdksh/files/c_ulimit.c
new file mode 100644
index 00000000000..5cd1ee06888
--- /dev/null
+++ b/shells/pdksh/files/c_ulimit.c
@@ -0,0 +1,271 @@
+/*
+ ulimit -- handle "ulimit" builtin
+
+ Reworked to use getrusage() and ulimit() at once (as needed on
+ some schizophenic systems, eg, HP-UX 9.01), made argument parsing
+ conform to at&t ksh, added autoconf support. Michael Rendell, May, '94
+
+ Eric Gisin, September 1988
+ Adapted to PD KornShell. Removed AT&T code.
+
+ last edit: 06-Jun-1987 D A Gwyn
+
+ This started out as the BRL UNIX System V system call emulation
+ for 4.nBSD, and was later extended by Doug Kingston to handle
+ the extended 4.nBSD resource limits. It now includes the code
+ that was originally under case SYSULIMIT in source file "xec.c".
+*/
+
+#include "sh.h"
+#include "ksh_time.h"
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+#ifdef HAVE_ULIMIT_H
+# include <ulimit.h>
+#else /* HAVE_ULIMIT_H */
+# ifdef HAVE_ULIMIT
+extern long ulimit();
+# endif /* HAVE_ULIMIT */
+#endif /* HAVE_ULIMIT_H */
+
+#define SOFT 0x1
+#define HARD 0x2
+
+#ifdef RLIM_INFINITY
+# define KSH_RLIM_INFINITY RLIM_INFINITY
+#else
+# define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
+#endif /* RLIM_INFINITY */
+
+int
+c_ulimit(wp)
+ char **wp;
+{
+ static const struct limits {
+ const char *name;
+ enum { RLIMIT, ULIMIT } which;
+ int gcmd; /* get command */
+ int scmd; /* set command (or -1, if no set command) */
+ int factor; /* multiply by to get rlim_{cur,max} values */
+ char option;
+ } limits[] = {
+ /* Do not use options -H, -S or -a */
+#ifdef RLIMIT_CPU
+ { "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+ { "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
+#else /* RLIMIT_FSIZE */
+# ifdef UL_GETFSIZE /* x/open */
+ { "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
+# else /* UL_GETFSIZE */
+# ifdef UL_GFILLIM /* svr4/xenix */
+ { "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
+# else /* UL_GFILLIM */
+ { "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
+# endif /* UL_GFILLIM */
+# endif /* UL_GETFSIZE */
+#endif /* RLIMIT_FSIZE */
+#ifdef RLIMIT_CORE
+ { "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
+#endif
+#ifdef RLIMIT_DATA
+ { "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+ { "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+ { "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_RSS
+ { "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
+#endif
+#ifdef RLIMIT_NOFILE
+ { "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
+#else /* RLIMIT_NOFILE */
+# ifdef UL_GDESLIM /* svr4/xenix */
+ { "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
+# endif /* UL_GDESLIM */
+#endif /* RLIMIT_NOFILE */
+#ifdef RLIMIT_NPROC
+ { "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
+#endif
+#ifdef RLIMIT_VMEM
+ { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
+#else /* RLIMIT_VMEM */
+ /* These are not quite right - really should subtract etext or something */
+# ifdef UL_GMEMLIM /* svr4/xenix */
+ { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
+# else /* UL_GMEMLIM */
+# ifdef UL_GETBREAK /* osf/1 */
+ { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
+# else /* UL_GETBREAK */
+# ifdef UL_GETMAXBRK /* hpux */
+ { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
+# endif /* UL_GETMAXBRK */
+# endif /* UL_GETBREAK */
+# endif /* UL_GMEMLIM */
+#endif /* RLIMIT_VMEM */
+#ifdef RLIMIT_SWAP
+ { "swap(kbytes)", RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
+#endif
+ { (char *) 0 }
+ };
+ static char options[3 + NELEM(limits)];
+ rlim_t UNINITIALIZED(val);
+ int how = SOFT | HARD;
+ const struct limits *l;
+ int set, all = 0;
+ int optc, what;
+#ifdef HAVE_SETRLIMIT
+ struct rlimit limit;
+#endif /* HAVE_SETRLIMIT */
+
+ if (!options[0]) {
+ /* build options string on first call - yuck */
+ char *p = options;
+
+ *p++ = 'H'; *p++ = 'S'; *p++ = 'a';
+ for (l = limits; l->name; l++)
+ *p++ = l->option;
+ *p = '\0';
+ }
+ what = 'f';
+ while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
+ switch (optc) {
+ case 'H':
+ how = HARD;
+ break;
+ case 'S':
+ how = SOFT;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ case '?':
+ return 1;
+ default:
+ what = optc;
+ }
+
+ for (l = limits; l->name && l->option != what; l++)
+ ;
+ if (!l->name) {
+ internal_errorf(0, "ulimit: %c", what);
+ return 1;
+ }
+
+ wp += builtin_opt.optind;
+ set = *wp ? 1 : 0;
+ if (set) {
+ if (all || wp[1]) {
+ bi_errorf("too many arguments");
+ return 1;
+ }
+ if (strcmp(wp[0], "unlimited") == 0)
+ val = KSH_RLIM_INFINITY;
+ else {
+ long rval;
+
+ if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
+ return 1;
+ /* Avoid problems caused by typos that
+ * evaluate misses due to evaluating unset
+ * parameters to 0...
+ * If this causes problems, will have to
+ * add parameter to evaluate() to control
+ * if unset params are 0 or an error.
+ */
+ if (!rval && !digit(wp[0][0])) {
+ bi_errorf("invalid limit: %s", wp[0]);
+ return 1;
+ }
+ val = rval * l->factor;
+ }
+ }
+ if (all) {
+ for (l = limits; l->name; l++) {
+#ifdef HAVE_SETRLIMIT
+ if (l->which == RLIMIT) {
+ getrlimit(l->gcmd, &limit);
+ if (how & SOFT)
+ val = limit.rlim_cur;
+ else if (how & HARD)
+ val = limit.rlim_max;
+ } else
+#endif /* HAVE_SETRLIMIT */
+#ifdef HAVE_ULIMIT
+ {
+ val = ulimit(l->gcmd, (rlim_t) 0);
+ }
+#else /* HAVE_ULIMIT */
+ ;
+#endif /* HAVE_ULIMIT */
+ shprintf("%-20s ", l->name);
+#ifdef RLIM_INFINITY
+ if (val == RLIM_INFINITY)
+ shprintf("unlimited\n");
+ else
+#endif /* RLIM_INFINITY */
+ {
+ val /= l->factor;
+ shprintf("%ld\n", (long) val);
+ }
+ }
+ return 0;
+ }
+#ifdef HAVE_SETRLIMIT
+ if (l->which == RLIMIT) {
+ getrlimit(l->gcmd, &limit);
+ if (set) {
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (setrlimit(l->scmd, &limit) < 0) {
+ if (errno == EPERM)
+ bi_errorf("exceeds allowable limit");
+ else
+ bi_errorf("bad limit: %s",
+ strerror(errno));
+ return 1;
+ }
+ } else {
+ if (how & SOFT)
+ val = limit.rlim_cur;
+ else if (how & HARD)
+ val = limit.rlim_max;
+ }
+ } else
+#endif /* HAVE_SETRLIMIT */
+#ifdef HAVE_ULIMIT
+ {
+ if (set) {
+ if (l->scmd == -1) {
+ bi_errorf("can't change limit");
+ return 1;
+ } else if (ulimit(l->scmd, val) < 0) {
+ bi_errorf("bad limit: %s", strerror(errno));
+ return 1;
+ }
+ } else
+ val = ulimit(l->gcmd, (rlim_t) 0);
+ }
+#else /* HAVE_ULIMIT */
+ ;
+#endif /* HAVE_ULIMIT */
+ if (!set) {
+#ifdef RLIM_INFINITY
+ if (val == RLIM_INFINITY)
+ shprintf("unlimited\n");
+ else
+#endif /* RLIM_INFINITY */
+ {
+ val /= l->factor;
+ shprintf("%ld\n", (long) val);
+ }
+ }
+ return 0;
+}
diff --git a/shells/pdksh/files/check-fd.c b/shells/pdksh/files/check-fd.c
new file mode 100644
index 00000000000..5055e62d809
--- /dev/null
+++ b/shells/pdksh/files/check-fd.c
@@ -0,0 +1,89 @@
+/* A simple program to check which file descriptors are open and
+ * print some info about them.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else /* HAVE_FCNTL_H */
+# include <sys/file.h>
+#endif /* HAVE_FCNTL_H */
+#include "ksh_stat.h"
+
+int usage();
+
+char *progname = "check-fd";
+
+#define MAXFD 256 /* a somewhat arbitrary number */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern int optind;
+
+ int opt;
+ int do_close = 0;
+ struct stat statb;
+ int i;
+
+ if (argc > 0 && argv[0] && *argv[0])
+ progname = argv[0];
+
+ while ((opt = getopt(argc, argv, "c")) != EOF) {
+ switch (opt) {
+ case 'c':
+ do_close = 1;
+ break;
+
+ default:
+ usage(1);
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "%s: too many arguments\n", progname);
+ usage(0);
+ }
+
+ if (do_close) {
+ for (i = 0; i < MAXFD; i++)
+ if (i == 1)
+ printf("(can't check 1)\n");
+ else if (close(i) >= 0)
+ printf("%d was open\n", i);
+ } else {
+ for (i = 0; i < MAXFD; i++)
+ if (fstat(i, &statb) == 0)
+ printf(
+ "%d is open (dev/inode %hd/%ld, flags 0x%x)\n",
+ i, statb.st_dev, statb.st_ino,
+ fcntl(i, F_GETFL, 0));
+ }
+
+ return 0;
+}
+
+int
+usage(verbose)
+ int verbose;
+{
+ fprintf(stderr, "Usage: %s [-?c]\n", progname);
+ if (verbose)
+ fprintf(stderr, "\
+ -c use close(2) instead of fstat(2) to check for open fds\n\
+ (prints dev, inode and fcntl(F_GETFL) flags)\n\
+");
+
+ exit(1);
+ return 0;
+}
diff --git a/shells/pdksh/files/check-pgrp.c b/shells/pdksh/files/check-pgrp.c
new file mode 100644
index 00000000000..f4d8d0932b8
--- /dev/null
+++ b/shells/pdksh/files/check-pgrp.c
@@ -0,0 +1,101 @@
+/* A simple program to print information about process groups */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else /* HAVE_FCNTL_H */
+# include <sys/file.h>
+#endif /* HAVE_FCNTL_H */
+
+#ifdef BSD_PGRP
+# include <sys/ioctl.h>
+int
+tcgetpgrp(fd)
+ int fd;
+{
+ int r, grp;
+
+ if ((r = ioctl(fd, TIOCGPGRP, &grp)) < 0)
+ return r;
+ return grp;
+}
+# define getPGRP() getpgrp(0)
+#else /* BSD_PGRP */
+# define getPGRP() getpgrp()
+#endif /* BSD_PGRP */
+
+int usage();
+
+char *progname = "check-pgrp";
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern int optind;
+ extern char *optarg;
+
+ int opt;
+ int ttyfd = 0;
+ int my_pgrp, my_pid, my_ppid, tty_pgrp;
+ char *tty_name;
+ char *e;
+
+ if (argc > 0 && argv[0] && *argv[0])
+ progname = argv[0];
+
+ while ((opt = getopt(argc, argv, "u:")) != EOF) {
+ switch (opt) {
+ case 'u':
+ ttyfd = atoi(optarg);
+ break;
+
+ default:
+ usage(1);
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "%s: too many arguments\n", progname);
+ usage(0);
+ }
+
+ my_pid = getpid();
+ my_ppid = getppid();
+ my_pgrp = getPGRP();
+ tty_pgrp = tcgetpgrp(ttyfd);
+ tty_name = ttyname(ttyfd);
+
+ printf("in %s pgrp\ntty %s (%s)\npid %d, ppid %d, pgrp %d, tty_pgrp %d\n",
+ my_pgrp == my_pid ? "my own"
+ : (my_pgrp == my_ppid ? "parent's" : "unknown"),
+ tty_name ? tty_name : "(none)",
+ tty_pgrp == my_pgrp ? "mine"
+ : (tty_pgrp == my_ppid ? "parent's" : "unknown"),
+ my_pid, my_ppid, my_pgrp, tty_pgrp);
+
+ return 0;
+}
+
+int
+usage(verbose)
+ int verbose;
+{
+ fprintf(stderr, "Usage: %s [-?] [-u fd]\n", progname);
+ if (verbose)
+ fprintf(stderr, "\
+ -u fd use fd as tty fd (default is 0)\n\
+");
+
+ exit(1);
+ return 0;
+}
diff --git a/shells/pdksh/files/check-sigs.c b/shells/pdksh/files/check-sigs.c
new file mode 100644
index 00000000000..91f288badb4
--- /dev/null
+++ b/shells/pdksh/files/check-sigs.c
@@ -0,0 +1,255 @@
+/* A simple program to print information about signal handlers */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+# define strchr index
+# define strrchr rindex
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#ifndef SIG_ERR
+# define SIG_ERR ((RETSIGTYPE (*)()) -1)
+#endif /* SIG_ERR */
+
+/* must be similar to struct Trap in sh.h */
+struct signal_info {
+ int signal;
+ char *name;
+ char *mess;
+};
+struct signal_info siginfo[] = {
+ { 0, "0", "Signal 0" },
+#include "siglist.out"
+ { 0, (char *) 0, (char *)0 },
+};
+
+int usage();
+#if 0
+RETSIGTYPE sig_catcher();
+#endif /* 0 */
+char *signal_name();
+#ifndef HAVE_STRERROR
+char *strerror(int);
+#endif /* !HAVE_STRERROR */
+
+char *progname = "check-sigs";
+int caught_sigs;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern int optind;
+ extern char *optarg;
+ extern int errno;
+
+ int opt;
+ int i;
+ int eno;
+ int report_all = 0;
+ RETSIGTYPE (*f)();
+ char *ofile = (char *) 0;
+ char *s;
+ int wait_forever = 0;
+
+ if (argc > 0 && argv[0] && *argv[0])
+ progname = argv[0];
+
+ while ((opt = getopt(argc, argv, "ao:w")) != EOF) {
+ switch (opt) {
+ case 'a':
+ report_all = 1;
+ break;
+
+ case 'o':
+ ofile = optarg;
+ break;
+
+ case 'w':
+ wait_forever = 1;
+ break;
+
+ default:
+ usage(1);
+ }
+ }
+
+ if (argc != optind)
+ usage(0);
+
+ if (ofile && freopen(ofile, "w", stdout) == (FILE *) 0) {
+ fprintf(stderr, "%s: Couldn't open output file `%s' - %s\n",
+ progname, ofile, strerror(errno));
+ exit(1);
+ }
+
+ if (!wait_forever) {
+ char *blocked = "";
+#ifdef POSIX_SIGNALS
+ sigset_t mask;
+
+ sigprocmask(SIG_BLOCK, (sigset_t *) 0, &mask);
+#endif /* POSIX_SIGNALS */
+#ifdef BSD42_SIGNALS
+ int mask;
+
+ mask = sigblock(0);
+#endif /* BSD42_SIGNALS */
+ for (i = 1; i < NSIG; i++) {
+ f = signal(i, SIG_DFL);
+ eno = errno;
+#ifdef BSD42_SIGNALS
+ blocked = (mask & sigmask(i)) ? "blocked" : "";
+#endif /* BSD42_SIGNALS */
+#ifdef POSIX_SIGNALS
+ blocked = sigismember(&mask, i) ? "blocked" : "";
+#endif /* POSIX_SIGNALS */
+ if (f == SIG_DFL && !report_all && !*blocked)
+ continue;
+ printf("%3d: %7s %30s: ",
+ i, blocked, (s = signal_name(i)) ? s : "");
+ if (f == SIG_IGN)
+ printf("ignored\n");
+ else if (f == SIG_ERR)
+ printf("error - %s\n", strerror(eno));
+ else if (f != SIG_DFL)
+ printf("caught - function address %lx\n",
+ (long) f);
+ else if (report_all)
+ printf("default\n");
+ }
+ }
+
+#if 0 /* code assumes BSD signals - not worth posixizing */
+ if (wait_forever) {
+ printf("pid is %d\n", getpid());
+ sigsetmask(-1L);
+ for (i = 0; i < NSIG; i++)
+ (void) signal(i, sig_catcher);
+ while (1) {
+ sigpause(0L);
+ for (i = 1; i < NSIG; i++)
+ if (caught_sigs & sigmask(i))
+ printf("received signal %d - %s\n",
+ i,
+ (s = signal_name(i)) ? s
+ : "");
+ caught_sigs = 0L;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+int
+usage(verbose)
+ int verbose;
+{
+ fprintf(stderr, "Usage: %s [-?aw] [-o file]\n", progname);
+ if (verbose)
+ fprintf(stderr, "\
+ -a report on all signals - instead of just non-default signals\n\
+ -o f redirect standard output to file f\n\
+ -w wait forever, reporting all signals sent\n\
+");
+
+ exit(1);
+ return 0;
+}
+
+#if 0
+RETSIGTYPE
+sig_catcher(sig)
+ int sig;
+{
+ caught_sigs |= sigmask(sig);
+ return RETSIGVAL;
+}
+#endif /* 0 */
+
+
+
+char *
+signal_name(sig)
+ int sig;
+{
+ static char buf[1024];
+
+#ifdef HAVE_SYS_SIGLIST
+# ifndef SYS_SIGLIST_DECLARED
+ extern char *sys_siglist[];
+# endif
+ /* Use system description, if available... */
+ if (sys_siglist[sig] && sys_siglist[sig][0])
+ return sys_siglist[sig];
+#endif /* HAVE_SYS_SIGLIST */
+
+
+ if (sig > 0 && sig < sizeof(siginfo) / sizeof(siginfo[0]) - 1) {
+ sprintf(buf, "SIG%s (%s)",
+ siginfo[sig].name, siginfo[sig].mess);
+ return buf;
+ }
+
+ return (char *) 0;
+}
+
+#ifndef HAVE_STRERROR
+char *
+strerror(err)
+ int err;
+{
+ static char buf[64];
+# ifdef HAVE_SYS_ERRLIST
+# ifndef SYS_ERRLIST_DECLARED
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+# endif
+ char *p;
+
+ if (err < 0 || err >= sys_nerr)
+ sprintf(p = buf, "Unknown system error %d", err);
+ else
+ p = sys_errlist[err];
+ return p;
+# else /* HAVE_SYS_ERRLIST */
+ switch (err) {
+ case EINVAL:
+ return "Invalid argument";
+ case EACCES:
+ return "Permission denied";
+ case ESRCH:
+ return "No such process";
+ case EPERM:
+ return "Not owner";
+ case ENOENT:
+ return "No such file or directory";
+ case ENOTDIR:
+ return "Not a directory";
+ case ENOEXEC:
+ return "Exec format error";
+ case ENOMEM:
+ return "Not enough memory";
+ case E2BIG:
+ return "Argument list too long";
+ default:
+ sprintf(buf, "Unknown system error %d", err);
+ return buf;
+ }
+# endif /* HAVE_SYS_ERRLIST */
+}
+#endif /* !HAVE_STRERROR */
diff --git a/shells/pdksh/files/conf-end.h b/shells/pdksh/files/conf-end.h
new file mode 100644
index 00000000000..c23cc07a2cb
--- /dev/null
+++ b/shells/pdksh/files/conf-end.h
@@ -0,0 +1,55 @@
+/*
+ * End of configuration stuff for PD ksh.
+ *
+ * RCSid: $Id: conf-end.h,v 1.1.1.1 2008/05/23 17:15:16 tnn Exp $
+ */
+
+#if defined(EMACS) || defined(VI)
+# define EDIT
+#else
+# undef EDIT
+#endif
+
+/* Editing implies history */
+#if defined(EDIT) && !defined(HISTORY)
+# define HISTORY
+#endif /* EDIT */
+
+/*
+ * if you don't have mmap() you can't use Peter Collinson's history
+ * mechanism. If that is the case, then define EASY_HISTORY
+ */
+#if defined(HISTORY) && (!defined(COMPLEX_HISTORY) || !defined(HAVE_MMAP) || !defined(HAVE_FLOCK))
+# undef COMPLEX_HISTORY
+# define EASY_HISTORY /* sjg's trivial history file */
+#endif
+
+/* Can we safely catch sigchld and wait for processes? */
+#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT3)) \
+ && (defined(POSIX_SIGNALS) || defined(BSD42_SIGNALS))
+# define JOB_SIGS
+#endif
+
+#if !defined(JOB_SIGS) || !(defined(POSIX_PGRP) || defined(BSD_PGRP))
+# undef JOBS /* if no JOB_SIGS, no job control support */
+#endif
+
+/* pdksh assumes system calls return EINTR if a signal happened (this so
+ * the signal handler doesn't have to longjmp()). I don't know if this
+ * happens (or can be made to happen) with sigset() et. al. (the bsd41 signal
+ * routines), so, the autoconf stuff checks what they do and defines
+ * SIGNALS_DONT_INTERRUPT if signals don't interrupt read().
+ * If SIGNALS_DONT_INTERRUPT isn't defined and your compiler chokes on this,
+ * delete the hash in front of the error (and file a bug report).
+ */
+#ifdef SIGNALS_DONT_INTERRUPT
+ # error pdksh needs interruptable system calls.
+#endif /* SIGNALS_DONT_INTERRUPT */
+
+#ifdef HAVE_GCC_FUNC_ATTR
+# define GCC_FUNC_ATTR(x) __attribute__((x))
+# define GCC_FUNC_ATTR2(x,y) __attribute__((x,y))
+#else
+# define GCC_FUNC_ATTR(x)
+# define GCC_FUNC_ATTR2(x,y)
+#endif /* HAVE_GCC_FUNC_ATTR */
diff --git a/shells/pdksh/files/config.h.in b/shells/pdksh/files/config.h.in
new file mode 100644
index 00000000000..bf16ac9dbca
--- /dev/null
+++ b/shells/pdksh/files/config.h.in
@@ -0,0 +1,360 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/*
+ * This file, acconfig.h, which is a part of pdksh (the public domain ksh),
+ * is placed in the public domain. It comes with no licence, warranty
+ * or guarantee of any kind (i.e., at your own risk).
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if the closedir function returns void instead of int. */
+#undef CLOSEDIR_VOID
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define if your struct stat has st_rdev. */
+#undef HAVE_ST_RDEV
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <unistd.h>. */
+#undef HAVE_UNISTD_H
+
+/* Define if on MINIX. */
+#undef _MINIX
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef mode_t
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define if `sys_siglist' is declared by <signal.h>. */
+#undef SYS_SIGLIST_DECLARED
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define if the closedir function returns void instead of int. */
+#undef VOID_CLOSEDIR
+
+/* Define if your kernal doesn't handle scripts starting with #! */
+#undef SHARPBANG
+
+/* Define if dup2() preserves the close-on-exec flag (ultrix does this) */
+#undef DUP2_BROKEN
+
+/* Define as the return value of signal handlers (0 or ). */
+#undef RETSIGVAL
+
+/* Define if you have posix signal routines (sigaction(), et. al.) */
+#undef POSIX_SIGNALS
+
+/* Define if you have BSD4.2 signal routines (sigsetmask(), et. al.) */
+#undef BSD42_SIGNALS
+
+/* Define if you have BSD4.1 signal routines (sigset(), et. al.) */
+#undef BSD41_SIGNALS
+
+/* Define if you have v7 signal routines (signal(), signal reset on delivery) */
+#undef V7_SIGNALS
+
+/* Define to use the fake posix signal routines (sigact.[ch]) */
+#undef USE_FAKE_SIGACT
+
+/* Define if signals don't interrupt read() */
+#undef SIGNALS_DONT_INTERRUPT
+
+/* Define if you have bsd versions of the setpgrp() and getpgrp() routines */
+#undef BSD_PGRP
+
+/* Define if you have POSIX versions of the setpgid() and getpgrp() routines */
+#undef POSIX_PGRP
+
+/* Define if you have sysV versions of the setpgrp() and getpgrp() routines */
+#undef SYSV_PGRP
+
+/* Define if you don't have setpgrp(), setpgid() or getpgrp() routines */
+#undef NO_PGRP
+
+/* Define to char if your compiler doesn't like the void keyword */
+#undef void
+
+/* Define to nothing if compiler doesn't like the volatile keyword */
+#undef volatile
+
+/* Define if C compiler groks function prototypes */
+#undef HAVE_PROTOTYPES
+
+/* Define if C compiler groks __attribute__((...)) (const, noreturn, format) */
+#undef HAVE_GCC_FUNC_ATTR
+
+/* Define to 32-bit signed integer type if <sys/types.h> doesn't define */
+#undef clock_t
+
+/* Define to the type of struct rlimit fields if the rlim_t type is missing */
+#undef rlim_t
+
+/* Define if time() is declared in <time.h> */
+#undef TIME_DECLARED
+
+/* Define to `unsigned' if <signal.h> doesn't define */
+#undef sigset_t
+
+/* Define if sys_errlist[] and sys_nerr are in the C library */
+#undef HAVE_SYS_ERRLIST
+
+/* Define if sys_errlist[] and sys_nerr are defined in <errno.h> */
+#undef SYS_ERRLIST_DECLARED
+
+/* Define if sys_siglist[] is in the C library */
+#undef HAVE_SYS_SIGLIST
+
+/* Define if you have a sane <termios.h> header file */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have a memset() function in your C library */
+#undef HAVE_MEMSET
+
+/* Define if you have a memmove() function in your C library */
+#undef HAVE_MEMMOVE
+
+/* Define if you have a bcopy() function in your C library */
+#undef HAVE_BCOPY
+
+/* Define if you have a lstat() function in your C library */
+#undef HAVE_LSTAT
+
+/* Define if you have a sane <termio.h> header file */
+#undef HAVE_TERMIO_H
+
+/* Define if you don't have times() or if it always returns 0 */
+#undef TIMES_BROKEN
+
+/* Define if opendir() will open non-directory files */
+#undef OPENDIR_DOES_NONDIR
+
+/* Define if the pgrp of setpgrp() can't be the pid of a zombie process */
+#undef NEED_PGRP_SYNC
+
+/* Define if you arg running SCO unix */
+#undef OS_SCO
+
+/* Define if you arg running ISC unix */
+#undef OS_ISC
+
+/* Define if you arg running OS2 with the EMX library */
+#undef OS2
+
+/* Define if you have a POSIX.1 compatiable <sys/wait.h> */
+#undef POSIX_SYS_WAIT
+
+/* Define if your OS maps references to /dev/fd/n to file descriptor n */
+#undef HAVE_DEV_FD
+
+/* Define if your C library's getwd/getcwd function dumps core in unreadable
+ * directories. */
+#undef HPUX_GETWD_BUG
+
+/* Default PATH (see comments in configure.in for more details) */
+#undef DEFAULT_PATH
+
+/* Include ksh features? (see comments in configure.in for more details) */
+#undef KSH
+
+/* Include emacs editing? (see comments in configure.in for more details) */
+#undef EMACS
+
+/* Include vi editing? (see comments in configure.in for more details) */
+#undef VI
+
+/* Include job control? (see comments in configure.in for more details) */
+#undef JOBS
+
+/* Include brace-expansion? (see comments in configure.in for more details) */
+#undef BRACE_EXPAND
+
+/* Include any history? (see comments in configure.in for more details) */
+#undef HISTORY
+
+/* Include complex history? (see comments in configure.in for more details) */
+#undef COMPLEX_HISTORY
+
+/* Strict POSIX behaviour? (see comments in configure.in for more details) */
+#undef POSIXLY_CORRECT
+
+/* Specify default $ENV? (see comments in configure.in for more details) */
+#undef DEFAULT_ENV
+
+/* Include shl(1) support? (see comments in configure.in for more details) */
+#undef SWTCH
+
+/* Include game-of-life? (see comments in configure.in for more details) */
+#undef SILLY
+
+/* The number of bytes in a int. */
+#undef SIZEOF_INT
+
+/* The number of bytes in a long. */
+#undef SIZEOF_LONG
+
+/* Define if you have the _setjmp function. */
+#undef HAVE__SETJMP
+
+/* Define if you have the confstr function. */
+#undef HAVE_CONFSTR
+
+/* Define if you have the dup2 function. */
+#undef HAVE_DUP2
+
+/* Define if you have the flock function. */
+#undef HAVE_FLOCK
+
+/* Define if you have the getcwd function. */
+#undef HAVE_GETCWD
+
+/* Define if you have the getgroups function. */
+#undef HAVE_GETGROUPS
+
+/* Define if you have the getpagesize function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function. */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the getwd function. */
+#undef HAVE_GETWD
+
+/* Define if you have the killpg function. */
+#undef HAVE_KILLPG
+
+/* Define if you have the nice function. */
+#undef HAVE_NICE
+
+/* Define if you have the setrlimit function. */
+#undef HAVE_SETRLIMIT
+
+/* Define if you have the sigsetjmp function. */
+#undef HAVE_SIGSETJMP
+
+/* Define if you have the strcasecmp function. */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strstr function. */
+#undef HAVE_STRSTR
+
+/* Define if you have the sysconf function. */
+#undef HAVE_SYSCONF
+
+/* Define if you have the tcsetpgrp function. */
+#undef HAVE_TCSETPGRP
+
+/* Define if you have the ulimit function. */
+#undef HAVE_ULIMIT
+
+/* Define if you have the valloc function. */
+#undef HAVE_VALLOC
+
+/* Define if you have the wait3 function. */
+#undef HAVE_WAIT3
+
+/* Define if you have the waitpid function. */
+#undef HAVE_WAITPID
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <paths.h> header file. */
+#undef HAVE_PATHS_H
+
+/* Define if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have the <ulimit.h> header file. */
+#undef HAVE_ULIMIT_H
+
+/* Define if you have the <values.h> header file. */
+#undef HAVE_VALUES_H
+
+/* Need to use a separate file to keep the configure script from commenting
+ * out the undefs....
+ */
+#include "conf-end.h"
+
+#endif /* CONFIG_H */
diff --git a/shells/pdksh/files/configure b/shells/pdksh/files/configure
new file mode 100755
index 00000000000..ee34802a195
--- /dev/null
+++ b/shells/pdksh/files/configure
@@ -0,0 +1,4447 @@
+#! /bin/sh
+
+
+
+
+
+
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-path=PaTh (NOTE: this value isn't used if confstr() and _CS_PATH
+ are available, or if <paths.h> defines _PATH_DEFPATH)
+ Use PaTh if PATH isn't specified in the environment
+ when the shell starts. A value without . in it is
+ safest.
+ The default value is \"/bin:/usr/bin:/usr/ucb\"."
+ac_help="$ac_help
+ --enable-shell={sh,ksh} Specify the kind of shell that is to be built (the
+ default is ksh). Specifiying sh compiles out:
+ command line editing (emacs/vi), history,
+ a bunch of aliases, [[ .. ]], select, let,
+ brace-expansion, extended globing (*(..|..), etc.),
+ co-processes, some special environment variables
+ (ie, MAIL, MAILCHECK, MAILPATH, RANDOM, SECONDS,
+ TMOUT)."
+ac_help="$ac_help
+ --disable-emacs Compile out emacs command line editing (by default,
+ this is compiled in for ksh, compiled out for sh)."
+ac_help="$ac_help
+ --disable-vi Compile out vi command line editing (by default,
+ this is compiled in for ksh, compiled out for sh)."
+ac_help="$ac_help
+ --disable-jobs Compile out job control support. If your system
+ doesn't support job control, this will automatically
+ be compiled out."
+ac_help="$ac_help
+ --disable-brace-expand Compile out brace expansion code (a{b,c} -> ab ac)
+ (by default, this is compiled in for ksh, compiled
+ out for sh). Brace expansion can also be disabled
+ at run time (see set +o braceexpand)."
+ac_help="$ac_help
+ --enable-history={no,simple,complex} By default, simple history is used for
+ ksh, no history is used for sh. \`simple' means
+ history file is read on start-up, written when shell
+ exists. \`complex' means history files are updated
+ after each command so concurrent shells read each
+ other's commands. Note: \`complex' history doesn't
+ work well across NFS; also, it requires the mmap()
+ and flock() functions - if these aren't available,
+ \`simple' history is automatically used."
+ac_help="$ac_help
+ --enable-posixly-correct Enable if you want POSIX behavior by default
+ (otherwise, posix behavior is only turned on if the
+ environment variable POSIXLY_CORRECT is present or by
+ using \"set -o posix\"; it can be turned off with
+ \"set +o posix\"). See the POSIX Mode section in the
+ man page for details on what this option affects.
+ NOTE: posix mode is not compatable with some bourne
+ sh/at&t ksh scripts."
+ac_help="$ac_help
+ --enable-default-env=FILE Include FILE if ENV parameter is not set when
+ the shell starts. This can be useful when used with
+ rsh(1), which creates a non-login shell (ie, profile
+ isn't read, so there is no opertunity to set ENV).
+ Setting ENV to null disables the inclusion of
+ DEFAULT_ENV. NOTE: This is a non-standard feature
+ (ie, at&t ksh has no default environment)."
+ac_help="$ac_help
+ --enable-silly [A silly option]"
+ac_help="$ac_help
+ --enable-swtch For use with shell layers (shl(1)). This has not
+ been tested for some time."
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.12"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=c_ksh.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='echo $CPP $CPPFLAGS 1>&5;
+$CPP $CPPFLAGS'
+ac_compile='echo ${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5;
+${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5'
+ac_link='echo ${CC-cc} -o conftest$ac_exe_suffix $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5;
+${CC-cc} -o conftest$ac_exe_suffix $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+def_path_unix="/bin:/usr/bin:/usr/ucb"
+def_path_os2="c:/usr/bin;c:/os2;/os2"
+# Check whether --enable-path or --disable-path was given.
+if test "${enable_path+set}" = set; then
+ enableval="$enable_path"
+ :
+else
+ enable_path=default
+fi
+
+case $enable_path:$ksh_cv_os_type in
+ default:OS2_EMX) enable_path="$def_path_os2" ;;
+ default:*) enable_path="$def_path_unix" ;;
+esac
+case $enable_path in
+ \"*\") ;;
+ *)
+ enable_path="\"$enable_path\""
+ ;;
+esac
+cat >> confdefs.h <<EOF
+#define DEFAULT_PATH $enable_path
+EOF
+
+# Check whether --enable-shell or --disable-shell was given.
+if test "${enable_shell+set}" = set; then
+ enableval="$enable_shell"
+ :
+else
+ enable_shell=ksh
+fi
+
+case $enable_shell in
+ ksh) cat >> confdefs.h <<\EOF
+#define KSH 1
+EOF
+ ;;
+ sh) ;;
+ *)
+ { echo "configure: error: bad --enable-shell: must be one of sh or ksh" 1>&2; exit 1; }
+esac
+SHELL_PROG=$enable_shell
+
+# Check whether --enable-emacs or --disable-emacs was given.
+if test "${enable_emacs+set}" = set; then
+ enableval="$enable_emacs"
+ :
+fi
+
+case $enable_emacs:$enable_shell in
+ yes:*|:ksh) enable_emacs=yes; cat >> confdefs.h <<\EOF
+#define EMACS 1
+EOF
+ ;;
+ no:*|:sh) enable_emacs=no;;
+ *) { echo "configure: error: bad --enable-emacs argument" 1>&2; exit 1; }
+esac
+# Check whether --enable-vi or --disable-vi was given.
+if test "${enable_vi+set}" = set; then
+ enableval="$enable_vi"
+ :
+fi
+
+case $enable_vi:$enable_shell in
+ yes:*|:ksh) enable_vi=yes; cat >> confdefs.h <<\EOF
+#define VI 1
+EOF
+ ;;
+ no:*|:sh) enable_vi=no;;
+ *) { echo "configure: error: bad --enable-vi argument" 1>&2; exit 1; }
+esac
+# Check whether --enable-jobs or --disable-jobs was given.
+if test "${enable_jobs+set}" = set; then
+ enableval="$enable_jobs"
+ :
+fi
+
+case $enable_jobs in
+ yes|'') enable_jobs=yes; cat >> confdefs.h <<\EOF
+#define JOBS 1
+EOF
+ ;;
+ no) enable_jobs=no;;
+ *) { echo "configure: error: bad --enable-jobs argument" 1>&2; exit 1; }
+esac
+# Check whether --enable-brace-expand or --disable-brace-expand was given.
+if test "${enable_brace_expand+set}" = set; then
+ enableval="$enable_brace_expand"
+ :
+fi
+
+case $enable_brace_expand:$enable_shell in
+ yes:*|:ksh) enable_brace_expand=yes; cat >> confdefs.h <<\EOF
+#define BRACE_EXPAND 1
+EOF
+ ;;
+ no:*|:sh) enable_brace_expand=no;;
+ *) { echo "configure: error: bad --enable-brace-expand argument" 1>&2; exit 1; }
+esac
+# Check whether --enable-history or --disable-history was given.
+if test "${enable_history+set}" = set; then
+ enableval="$enable_history"
+ :
+fi
+
+case $enable_history:$enable_shell in
+ simple:*|:ksh) enable_history=simple; ;;
+ complex:*) enable_history=complex; cat >> confdefs.h <<\EOF
+#define COMPLEX_HISTORY 1
+EOF
+ ;;
+ no:*|:sh)
+ case $enable_history:$enable_vi:$enable_emacs in
+ no:yes:*|no:*:yes)
+ { echo "configure: error: can't disable history when vi or emacs is enabled" 1>&2; exit 1; } ;;
+ :yes:*|:*:yes)
+ enable_history=yes;;
+ *)
+ enable_history=no;;
+ esac
+ ;;
+ *) { echo "configure: error: bad --enable-history argument" 1>&2; exit 1; }
+esac
+test X"$enable_history" != Xno && cat >> confdefs.h <<\EOF
+#define HISTORY 1
+EOF
+
+# Check whether --enable-posixly_correct or --disable-posixly_correct was given.
+if test "${enable_posixly_correct+set}" = set; then
+ enableval="$enable_posixly_correct"
+ :
+fi
+
+case $enable_posixly_correct:$enable_shell in
+ yes:*) enable_posixly_correct=yes; cat >> confdefs.h <<\EOF
+#define POSIXLY_CORRECT 1
+EOF
+ ;;
+ no:*|:*) enable_posixly_correct=no;;
+ *) { echo "configure: error: bad --enable-posixly_correct argument" 1>&2; exit 1; }
+esac
+# Check whether --enable-default-env or --disable-default-env was given.
+if test "${enable_default_env+set}" = set; then
+ enableval="$enable_default_env"
+ :
+else
+ enable_default_env=no
+fi
+
+if test X"$enable_default_env" != Xno; then
+ # The [a-zA-Z]:/ is for os2 types...
+ case $enable_default_env in
+ /*|[a-zA-Z]:/*)
+ enable_default_env="\"$enable_default_env\""
+ ;;
+ \"/*\"|\"[a-zA-Z]:/*\")
+ ;;
+ *)
+ { echo "configure: error: --enable-default-env argument must be an absolute path (was $enable_default_env)" 1>&2; exit 1; }
+ ;;
+ esac
+ cat >> confdefs.h <<EOF
+#define DEFAULT_ENV $enable_default_env
+EOF
+
+fi
+# Check whether --enable-silly or --disable-silly was given.
+if test "${enable_silly+set}" = set; then
+ enableval="$enable_silly"
+ :
+fi
+
+case $enable_silly:$enable_shell in
+ yes:*) enable_silly=yes; cat >> confdefs.h <<\EOF
+#define SILLY 1
+EOF
+ ;;
+ no:*|:*) enable_silly=no;;
+ *) { echo "configure: error: bad --enable-silly argument" 1>&2; exit 1; }
+esac
+# Check whether --enable-swtch or --disable-swtch was given.
+if test "${enable_swtch+set}" = set; then
+ enableval="$enable_swtch"
+ :
+fi
+
+case $enable_swtch:$enable_shell in
+ yes:*) enable_swtch=yes; cat >> confdefs.h <<\EOF
+#define SWTCH 1
+EOF
+ ;;
+ no:*|:*) enable_swtch=no;;
+ *) { echo "configure: error: bad --enable-swtch argument" 1>&2; exit 1; }
+esac
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:791: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:819: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ if test "${CFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:840: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'int main(){ return 0; }' > conftest.c
+if test -z "`${CC-cc} -g conftest.c 2>&1`"; then
+ ac_cv_prog_gcc_g=yes
+else
+ ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6
+ if test $ac_cv_prog_gcc_g = yes; then
+ CFLAGS="-g -O"
+ else
+ CFLAGS="-O"
+ fi
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:867: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 882 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:888: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 899 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:905: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:929: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat > conftest.$ac_ext <<EOF
+#line 935 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+else
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat > conftest.$ac_ext <<EOF
+#line 953 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+if test X"$GCC" = Xyes && test -f $srcdir/Warn-flags; then
+ CFLAGS="${CFLAGS+$CFLAGS }`cat $srcdir/Warn-flags`"
+fi
+
+LDSTATIC=${LDSTATIC-}
+test X"$LDSTATIC" != X && LDFLAGS="${LDFLAGS+$LDFLAGS }$LDSTATIC"
+
+ echo $ac_n "checking if this is a problematic os""... $ac_c" 1>&6
+echo "configure:982: checking if this is a problematic os" >&5
+if eval "test \"`echo '$''{'ksh_cv_os_type'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ksh_cv_os_type=no
+ # Some tests below add -C to CPPFLAGS
+ saveCPPFLAGS="$CPPFLAGS"
+ for i in AIX ISC MINIX SCO OS2_EMX TITANOS NEXT HPUX; do
+ case $i in #((
+ AIX)
+ cat > conftest.$ac_ext <<EOF
+#line 993 "configure"
+#include "confdefs.h"
+
+#ifdef _AIX
+yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ksh_cv_os_type=$i
+fi
+rm -f conftest*
+
+ ;; #(
+ ISC)
+ # Both native ISC cpp and gcc understand this (leave comments in)
+ CPPFLAGS="$CPPFLAGS -C"
+ #XXX grep part won't work if cross-compiling...
+ cat > conftest.$ac_ext <<EOF
+#line 1014 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "INTERACTIVE Systems Corporation" >/dev/null 2>&1; then
+ rm -rf conftest*
+ if grep _POSIX_VERSION /usr/include/sys/unistd.h > /dev/null 2>&1; then
+ ksh_cv_os_type="$i-posix"
+ else
+ ksh_cv_os_type=$i
+ fi
+fi
+rm -f conftest*
+ CPPFLAGS="$saveCPPFLAGS"
+ ;; #(
+ MINIX)
+ ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1033: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1038 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1043: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ksh_cv_os_type=$i
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;; #(
+ SCO)
+ # Both native SCO cpp and gcc understand this (leave comments in)
+ CPPFLAGS="$CPPFLAGS -C"
+ cat > conftest.$ac_ext <<EOF
+#line 1068 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "The Santa Cruz Operation" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ksh_cv_os_type=$i
+fi
+rm -f conftest*
+ CPPFLAGS="$saveCPPFLAGS"
+ ;; #(
+ OS2_EMX)
+ cat > conftest.$ac_ext <<EOF
+#line 1082 "configure"
+#include "confdefs.h"
+
+#ifdef __EMX__
+yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ksh_cv_os_type=$i
+fi
+rm -f conftest*
+ ;; #(
+ TITANOS)
+ cat > conftest.$ac_ext <<EOF
+#line 1099 "configure"
+#include "confdefs.h"
+
+#if defined(titan) || defined(_titan) || defined(__titan)
+YesTitan
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "YesTitan" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ksh_cv_os_type=$i
+fi
+rm -f conftest*
+ ;; #(
+ NEXT)
+ #
+ # NeXT 3.2 (other versions?) - cc -E doesn't work and /lib/cpp
+ # doesn't define things that need defining, so tests that rely
+ # on $CPP will break.
+ #
+ # Hmmm - can't safely use CPP to test for NeXT defines, so have
+ # to use a program that won't compile on a NeXT and one that will
+ # only compile on a NeXT...
+ cat > conftest.$ac_ext <<EOF
+#line 1124 "configure"
+#include "confdefs.h"
+
+int main() {
+
+ #if defined(__NeXT) || defined(NeXT)
+ this is a NeXT box and the compile should fail
+ #endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1135: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 1142 "configure"
+#include "confdefs.h"
+
+int main() {
+
+ #if !defined(__NeXT) && !defined(NeXT)
+ this is NOT a NeXT box and the compile should fail
+ #endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1153: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_os_type=$i
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+fi
+rm -f conftest* ;; #(
+ HPUX)
+ cat > conftest.$ac_ext <<EOF
+#line 1165 "configure"
+#include "confdefs.h"
+
+#ifdef __hpux
+yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ksh_cv_os_type=$i
+fi
+rm -f conftest*
+
+ ;; #(
+ esac #))
+ test $ksh_cv_os_type != no && break
+ done
+
+fi
+
+echo "$ac_t""$ksh_cv_os_type" 1>&6
+ case $ksh_cv_os_type in #((
+ AIX)
+ cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+ ;; #(
+ ISC)
+ cat >> confdefs.h <<\EOF
+#define OS_ISC 1
+EOF
+ ;; #(
+ ISC-posix)
+ cat >> confdefs.h <<\EOF
+#define OS_ISC 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+ if test "$GCC" = yes; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+ ;; #(
+ MINIX)
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+ cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+ ;; #(
+ SCO)
+ cat >> confdefs.h <<\EOF
+#define OS_SCO 1
+EOF
+ ;; #(
+ OS2_EMX)
+ # XXX change this to OS_OS2 or OS_OS2_EMX?
+ cat >> confdefs.h <<\EOF
+#define OS2 1
+EOF
+ ac_exe_suffix=.exe
+ ;; #(
+ TITANOS)
+ # Need to use cc -43 to get a shell with job control
+ case "$CC" in #((
+ *-43*) # Already have -43 option?
+ ;; #(
+ */cc|*/cc' '|*/cc' '|cc|cc' '|cc' ') # Using stock compiler?
+ CC="$CC -43"
+ ;; #(
+ esac #))
+ #
+ # Force dirent check to find the right thing. There is a dirent.h
+ # (and a sys/dirent.h) file which compiles, but generates garbage...
+ #
+ ac_cv_header_dirent_dirent_h=no
+ ac_cv_header_dirent_sys_ndir_h=no
+ ac_cv_header_dirent_sys_dir_h=yes
+ ;; #(
+ NEXT)
+ #
+ # NeXT 3.2 (other versions?) - cc -E doesn't work and /lib/cpp
+ # doesn't define things that need defining, so tests that rely
+ # on $CPP will break.
+ #
+ cat > conftest.$ac_ext <<EOF
+#line 1259 "configure"
+#include "confdefs.h"
+#include <signal.h>
+ #if !defined(SIGINT) || !defined(SIGQUIT)
+ Bad NeXT
+ #endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "Bad NeXT" >/dev/null 2>&1; then
+ rm -rf conftest*
+ { echo "configure: error:
+There is a problem on NeXT boxes resulting in a bad siglist.out file being
+generated (which breaks the trap and kill commands) and probably resulting
+in many configuration tests not working correctly.
+
+You appear to have this problem - see the comments on NeXT in the pdksh
+README file for work arounds." 1>&2; exit 1; }
+fi
+rm -f conftest*
+ ;; #(
+ HPUX)
+ #
+ # In some versions of hpux (eg, 10.2), getwd & getcwd will dump core
+ # if directory is not readble.
+ #
+ # name is used in test program
+ echo $ac_n "checking for bug in getwd""... $ac_c" 1>&6
+echo "configure:1287: checking for bug in getwd" >&5
+if eval "test \"`echo '$''{'ksh_cv_hpux_getwd_bug'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ tmpdir=conftest.dir
+ if mkdir $tmpdir ; then
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: assuming getwd broken" 1>&2; ksh_cv_hpux_getwd_bug=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 1297 "configure"
+#include "confdefs.h"
+
+ int
+ main()
+ {
+ char buf[8 * 1024];
+ char *dirname = "conftest.dir";
+ int ok = 0;
+ if (chdir(dirname) < 0)
+ exit(2);
+ if (chmod(".", 0) < 0)
+ exit(3);
+ /* Test won't work if run as root - so don't be root */
+ if (getuid() == 0 || geteuid() == 0)
+ setresuid(1, 1, 1); /* hpux has this */
+#ifdef HAVE_GETWD /* silly since HAVE_* tests haven't been done yet */
+ {
+ extern char *getwd();
+ ok = getwd(buf) == 0;
+ }
+#else
+ {
+ extern char *getcwd();
+ ok = getcwd(buf, sizeof(buf)) == 0;
+ }
+#endif
+ exit(ok ? 0 : 10);
+ return ok ? 0 : 10;
+ }
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_hpux_getwd_bug=no
+else
+ ksh_cv_hpux_getwd_bug=yes
+fi
+fi
+rm -fr conftest*
+ test -d $tmpdir && rmdir $tmpdir
+ else
+ { echo "configure: error: could not make temp directory for test" 1>&2; exit 1; }; ksh_cv_hpux_getwd_bug=yes
+ fi
+fi
+
+echo "$ac_t""$ksh_cv_hpux_getwd_bug" 1>&6
+ if test $ksh_cv_hpux_getwd_bug = yes; then
+ cat >> confdefs.h <<\EOF
+#define HPUX_GETWD_BUG 1
+EOF
+
+ fi
+ ;; #(
+ esac #))
+
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1376: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1381 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1389: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1414: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1422 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1433: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for opendir in -lndir""... $ac_c" 1>&6
+echo "configure:1452: checking for opendir in -lndir" >&5
+ac_lib_var=`echo ndir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lndir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1460 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1471: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lndir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1495: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1503 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1514: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for sane unistd.h""... $ac_c" 1>&6
+echo "configure:1537: checking for sane unistd.h" >&5
+if eval "test \"`echo '$''{'ksh_cv_header_unistd'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1542 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+#if defined(_POSIX_VERSION)
+# include <sys/types.h>
+# include <dirent.h> /* _POSIX_VERSION => HAVE_DIRENT_H test not needed */
+#endif
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:1555: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_header_unistd=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_header_unistd=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_header_unistd" 1>&6
+ if test $ksh_cv_header_unistd = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UNISTD_H 1
+EOF
+
+ fi
+
+echo $ac_n "checking terminal interface""... $ac_c" 1>&6
+echo "configure:1576: checking terminal interface" >&5
+if eval "test \"`echo '$''{'ksh_cv_term_check'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1581 "configure"
+#include "confdefs.h"
+#include <termios.h>
+int main() {
+
+ struct termios t;
+#if defined(ultrix) || defined(__ultrix__)
+ Termios in ultrix 4.2 botches type-ahead when going from cooked to
+ cbreak mode. The BSD tty interface works fine though, so use it
+ (would be good to know if alter versions of ultrix work).
+#endif /* ultrix */
+ tcgetattr(0, &t); tcsetattr(0, TCSADRAIN, &t);
+
+; return 0; }
+EOF
+if { (eval echo configure:1596: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_term_check=termios
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 1604 "configure"
+#include "confdefs.h"
+#include <sys/ioctl.h>
+int main() {
+
+ struct sgttyb sb; ioctl(0, TIOCGETP, &sb);
+#ifdef TIOCGATC
+ { struct ttychars lc; ioctl(0, TIOCGATC, &lc); }
+#else /* TIOCGATC */
+ { struct tchars tc; ioctl(0, TIOCGETC, &tc); }
+# ifdef TIOCGLTC
+ { struct ltchars ltc; ioctl(0, TIOCGLTC, &ltc); }
+# endif /* TIOCGLTC */
+#endif /* TIOCGATC */
+
+; return 0; }
+EOF
+if { (eval echo configure:1621: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_term_check=bsd
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_safe=`echo "termio.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for termio.h""... $ac_c" 1>&6
+echo "configure:1630: checking for termio.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1635 "configure"
+#include "confdefs.h"
+#include <termio.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1640: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ksh_cv_term_check=termio
+else
+ echo "$ac_t""no" 1>&6
+ksh_cv_term_check=sgtty
+fi
+
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_term_check" 1>&6
+ if test $ksh_cv_term_check = termios; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_TERMIOS_H 1
+EOF
+
+ elif test $ksh_cv_term_check = termio; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_TERMIO_H 1
+EOF
+
+ fi
+
+for ac_hdr in stddef.h stdlib.h string.h memory.h fcntl.h limits.h paths.h \
+ sys/param.h sys/resource.h values.h ulimit.h sys/time.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1686: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1691 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1696: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1723: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1728 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1737: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:1758: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ksh_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1763 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:1779: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_header_sys_wait_h" 1>&6
+if test $ksh_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define POSIX_SYS_WAIT 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+else
+ for ac_hdr in sys/wait.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1804: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1809 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1814: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+fi
+
+echo $ac_n "checking for off_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:1842: checking for off_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1847 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])off_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+ if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+ fi
+
+echo $ac_n "checking for mode_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:1877: checking for mode_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1882 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])mode_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_mode_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+ if test $ac_cv_type_mode_t = no; then
+ cat >> confdefs.h <<\EOF
+#define mode_t short
+EOF
+
+ fi
+
+echo $ac_n "checking for pid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:1912: checking for pid_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1917 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])pid_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+ if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+ fi
+
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:1947: checking for uid_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1952 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])uid_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_uid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_uid_t" 1>&6
+ if test $ac_cv_type_uid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+ fi
+
+if test $ac_cv_type_uid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2057: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2062 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+case $ac_cv_type_signal in
+int) ksh_cv_signal_retval=0 ;;
+void) ksh_cv_signal_retval= ;;
+*)
+ { echo "configure: error: Internal erorr: unknown signal return type: $ac_cv_type_signal" 1>&2; exit 1; }
+esac
+cat >> confdefs.h <<EOF
+#define RETSIGVAL $ksh_cv_signal_retval
+EOF
+
+echo $ac_n "checking size of int""... $ac_c" 1>&6
+echo "configure:2108: checking size of int" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 2116 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(int));
+ exit(0);
+}
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ac_cv_sizeof_int=`cat conftestval`
+else
+ ac_cv_sizeof_int=0
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_sizeof_int" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+EOF
+
+
+echo $ac_n "checking size of long""... $ac_c" 1>&6
+echo "configure:2143: checking size of long" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 2151 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(long));
+ exit(0);
+}
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ac_cv_sizeof_long=`cat conftestval`
+else
+ ac_cv_sizeof_long=0
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_sizeof_long" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+EOF
+
+
+echo $ac_n "checking for clock_t in any of <sys/types.h>, <sys/times.h> and <sys/time.h>""... $ac_c" 1>&6
+echo "configure:2178: checking for clock_t in any of <sys/types.h>, <sys/times.h> and <sys/time.h>" >&5
+if eval "test \"`echo '$''{'ac_cv_type_clock_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2183 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#include <sys/times.h>
+
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])clock_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_clock_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_clock_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_clock_t" 1>&6
+ if test $ac_cv_type_clock_t = no; then
+ cat >> confdefs.h <<\EOF
+#define clock_t INT32
+EOF
+
+ fi
+
+echo $ac_n "checking for sigset_t in <sys/types.h> and <signal.h>""... $ac_c" 1>&6
+echo "configure:2218: checking for sigset_t in <sys/types.h> and <signal.h>" >&5
+if eval "test \"`echo '$''{'ac_cv_type_sigset_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2223 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+#include <signal.h>
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])sigset_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_sigset_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_sigset_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_sigset_t" 1>&6
+ if test $ac_cv_type_sigset_t = no; then
+ cat >> confdefs.h <<\EOF
+#define sigset_t unsigned
+EOF
+
+ fi
+
+echo $ac_n "checking for rlim_t in <sys/types.h> and <sys/resource.h>""... $ac_c" 1>&6
+echo "configure:2253: checking for rlim_t in <sys/types.h> and <sys/resource.h>" >&5
+if eval "test \"`echo '$''{'ac_cv_type_rlim_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2258 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z0-9_])rlim_t([^a-zA-Z0-9_]|\$)" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_rlim_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_rlim_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_rlim_t" 1>&6
+ if test $ac_cv_type_rlim_t = no; then
+ echo $ac_n "checking what to set rlim_t to""... $ac_c" 1>&6
+echo "configure:2284: checking what to set rlim_t to" >&5
+ if test $ac_cv_header_sys_resource_h = yes; then
+ if eval "test \"`echo '$''{'ksh_cv_rlim_check'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot determine type for rlimt_t when cross compiling" 1>&2; exit 1; }
+
+else
+cat > conftest.$ac_ext <<EOF
+#line 2294 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+ main()
+ {
+ struct rlimit rl;
+ if (sizeof(rl.rlim_cur) == sizeof(quad_t))
+ exit(0);
+ exit(1);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_rlim_check=quad_t
+else
+ ksh_cv_rlim_check=long
+fi
+fi
+rm -fr conftest*
+fi
+ else
+ ksh_cv_rlim_check=long
+ fi
+ echo "$ac_t""$ksh_cv_rlim_check" 1>&6
+ cat >> confdefs.h <<EOF
+#define rlim_t $ksh_cv_rlim_check
+EOF
+
+ fi
+
+echo $ac_n "checking for working memmove""... $ac_c" 1>&6
+echo "configure:2329: checking for working memmove" >&5
+if eval "test \"`echo '$''{'ksh_cv_func_memmove'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: assuming memmove broken" 1>&2; ksh_cv_func_memmove=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 2337 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+ int
+ main()
+ {
+ char buf[16];
+ strcpy(buf, "abcdefABCDEF");
+ memmove(buf + 4, buf, 6);
+ if (strcmp(buf, "abcdabcdefEF"))
+ exit(1);
+ memmove(buf, buf + 4, 6);
+ if (strcmp(buf, "abcdefcdefEF"))
+ exit(2);
+ exit(0);
+ return 0;
+ }
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_func_memmove=yes
+else
+ ksh_cv_func_memmove=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_func_memmove" 1>&6
+ if test $ksh_cv_func_memmove = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MEMMOVE 1
+EOF
+
+ else
+ echo $ac_n "checking for working bcopy""... $ac_c" 1>&6
+echo "configure:2381: checking for working bcopy" >&5
+if eval "test \"`echo '$''{'ksh_cv_func_bcopy'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: assuming bcopy broken" 1>&2; ksh_cv_func_bcopy=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 2389 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+ int
+ main()
+ {
+ char buf[16];
+ strcpy(buf, "abcdefABCDEF");
+ bcopy(buf, buf + 4, 6);
+ if (strcmp(buf, "abcdabcdefEF"))
+ exit(1);
+ bcopy(buf + 4, buf, 6);
+ if (strcmp(buf, "abcdefcdefEF"))
+ exit(2);
+ exit(0);
+ }
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_func_bcopy=yes
+else
+ ksh_cv_func_bcopy=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_func_bcopy" 1>&6
+ if test $ksh_cv_func_bcopy = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_BCOPY 1
+EOF
+
+ fi
+ fi
+
+echo $ac_n "checking for memset""... $ac_c" 1>&6
+echo "configure:2434: checking for memset" >&5
+if eval "test \"`echo '$''{'ksh_cv_func_memset'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2439 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+int main() {
+
+ char buf[16]; memset(buf, 'x', 7); printf("%7s", buf);
+; return 0; }
+EOF
+if { (eval echo configure:2456: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_func_memset=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_func_memset=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_func_memset" 1>&6
+ if test $ksh_cv_func_memset = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MEMSET 1
+EOF
+
+ fi
+
+for ac_func in confstr dup2 flock getcwd getwd killpg nice \
+ setrlimit strerror strcasecmp strstr sysconf tcsetpgrp \
+ ulimit waitpid wait3
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2481: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2486 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2509: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in sigsetjmp _setjmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2536: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2541 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in valloc getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2591: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2596 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2619: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for working mmap""... $ac_c" 1>&6
+echo "configure:2644: checking for working mmap" >&5
+if eval "test \"`echo '$''{'ac_cv_func_mmap'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_mmap=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 2652 "configure"
+#include "confdefs.h"
+
+/* Thanks to Mike Haertel and Jim Avera for this test. */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifndef HAVE_GETPAGESIZE
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define getpagesize() EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# define getpagesize() NBPG * CLSIZE
+# ifndef CLSIZE
+# define CLSIZE 1
+# endif
+# else
+# ifdef NBPC
+# define getpagesize() NBPC
+# else
+# define getpagesize() PAGESIZE /* SVR4 */
+# endif
+# endif
+# endif
+#endif
+
+#ifndef HAVE_VALLOC
+# define valloc malloc
+#endif
+
+#ifdef __cplusplus
+extern "C" { void *valloc(unsigned), *malloc(unsigned); }
+#else
+char *valloc(), *malloc();
+#endif
+
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif /* MAP_FILE */
+
+int
+main()
+{
+ char *buf1, *buf2, *buf3;
+ int i = getpagesize(), j;
+ int i2 = i * 2;
+ int fd;
+
+ buf1 = (char *)valloc(i2);
+ buf2 = (char *)valloc(i);
+ buf3 = (char *)malloc(i2);
+ for (j = 0; j < i2; ++j)
+ *(buf1 + j) = rand();
+ fd = open("conftestmmap", O_CREAT | O_RDWR, 0666);
+ write(fd, buf1, i2);
+ mmap(buf2, i, PROT_READ | PROT_WRITE, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd, 0);
+ for (j = 0; j < i; ++j)
+ if (*(buf1 + j) != *(buf2 + j))
+ exit(1);
+ lseek(fd, (long)i, 0);
+ read(fd, buf2, i); /* read into mapped memory -- file should not change */
+ /* (it does in i386 SVR4.0 - Jim Avera, jima@netcom.com) */
+ lseek(fd, (long)0, 0);
+ read(fd, buf3, i2);
+ for (j = 0; j < i2; ++j)
+ if (*(buf1 + j) != *(buf3 + j))
+ exit(1);
+ exit(0);
+}
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ac_cv_func_mmap=yes
+else
+ ac_cv_func_mmap=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_mmap" 1>&6
+if test $ac_cv_func_mmap = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MMAP 1
+EOF
+
+fi
+
+echo $ac_n "checking for lstat""... $ac_c" 1>&6
+echo "configure:2744: checking for lstat" >&5
+if eval "test \"`echo '$''{'ksh_cv_func_lstat'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2749 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int main() {
+
+ struct stat statb;
+ lstat("/", &statb);
+
+; return 0; }
+EOF
+if { (eval echo configure:2762: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_func_lstat=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_func_lstat=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_func_lstat" 1>&6
+if test $ksh_cv_func_lstat = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_LSTAT 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys_errlist declaration in errno.h""... $ac_c" 1>&6
+echo "configure:2783: checking for sys_errlist declaration in errno.h" >&5
+if eval "test \"`echo '$''{'ksh_cv_decl_sys_errlist'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2788 "configure"
+#include "confdefs.h"
+#include <errno.h>
+int main() {
+char *msg = *(sys_errlist + 1); if (msg && *msg) return 12;
+; return 0; }
+EOF
+if { (eval echo configure:2795: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_decl_sys_errlist=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_decl_sys_errlist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_decl_sys_errlist" 1>&6
+ if test $ksh_cv_decl_sys_errlist = yes; then
+ cat >> confdefs.h <<\EOF
+#define SYS_ERRLIST_DECLARED 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_ERRLIST 1
+EOF
+
+ else
+ echo $ac_n "checking for sys_errlist in library""... $ac_c" 1>&6
+echo "configure:2819: checking for sys_errlist in library" >&5
+if eval "test \"`echo '$''{'ksh_cv_var_sys_errlist'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2824 "configure"
+#include "confdefs.h"
+
+int main() {
+
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ char *p;
+ p = sys_errlist[sys_nerr - 1];
+ if (p) return 12;
+
+; return 0; }
+EOF
+if { (eval echo configure:2837: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_var_sys_errlist=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_var_sys_errlist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_var_sys_errlist" 1>&6
+ if test $ksh_cv_var_sys_errlist = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_ERRLIST 1
+EOF
+
+ fi
+ fi
+
+echo $ac_n "checking for sys_siglist declaration in signal.h or unistd.h""... $ac_c" 1>&6
+echo "configure:2859: checking for sys_siglist declaration in signal.h or unistd.h" >&5
+if eval "test \"`echo '$''{'ac_cv_decl_sys_siglist'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2864 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+/* NetBSD declares sys_siglist in unistd.h. */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+int main() {
+char *msg = *(sys_siglist + 1);
+; return 0; }
+EOF
+if { (eval echo configure:2876: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_decl_sys_siglist=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_decl_sys_siglist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_decl_sys_siglist" 1>&6
+if test $ac_cv_decl_sys_siglist = yes; then
+ cat >> confdefs.h <<\EOF
+#define SYS_SIGLIST_DECLARED 1
+EOF
+
+fi
+
+ if test ac_cv_decl_sys_siglist = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_SIGLIST 1
+EOF
+
+ else
+ echo $ac_n "checking for sys_siglist in library""... $ac_c" 1>&6
+echo "configure:2903: checking for sys_siglist in library" >&5
+if eval "test \"`echo '$''{'ksh_cv_var_sys_siglist'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2908 "configure"
+#include "confdefs.h"
+
+int main() {
+
+ extern char *sys_siglist[];
+ char *p = sys_siglist[2];
+ if (p)
+ return 12;
+
+; return 0; }
+EOF
+if { (eval echo configure:2920: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_var_sys_siglist=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_var_sys_siglist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_var_sys_siglist" 1>&6
+ if test $ksh_cv_var_sys_siglist = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_SIGLIST 1
+EOF
+
+ fi
+ fi
+
+echo $ac_n "checking time() declaration in time.h""... $ac_c" 1>&6
+echo "configure:2942: checking time() declaration in time.h" >&5
+if eval "test \"`echo '$''{'ksh_cv_time_delcared'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2947 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+time_t (*f)() = time; if (f) return 12;
+; return 0; }
+EOF
+if { (eval echo configure:2955: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_time_delcared=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_time_delcared=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_time_delcared" 1>&6
+ if test $ksh_cv_time_delcared = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_DECLARED 1
+EOF
+
+ fi
+
+echo $ac_n "checking if times() is present/working""... $ac_c" 1>&6
+echo "configure:2976: checking if times() is present/working" >&5
+if eval "test \"`echo '$''{'ksh_cv_func_times_ok'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot determine if times works when cross compiling" 1>&2; exit 1; }
+
+else
+cat > conftest.$ac_ext <<EOF
+#line 2985 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/times.h>
+/* if missing, clock_t is defined to be INT32 */
+#if SIZEOF_INT == 4
+# define INT32 int
+#else /* SIZEOF_INT */
+# if SIZEOF_LONG == 4
+# define INT32 long
+# else /* SIZEOF_LONG */
+ #error cannot find 32 bit type...
+# endif /* SIZEOF_LONG */
+#endif /* SIZEOF_INT */
+ main()
+ {
+ extern clock_t times();
+ struct tms tms;
+ times(&tms);
+ sleep(1);
+ if (times(&tms) == 0)
+ exit(1);
+ exit(0);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_func_times_ok=yes
+else
+ ksh_cv_func_times_ok=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_func_times_ok" 1>&6
+ if test $ksh_cv_func_times_ok = no; then
+ cat >> confdefs.h <<\EOF
+#define TIMES_BROKEN 1
+EOF
+
+ for ac_func in getrusage
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3031: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3036 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3059: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ fi
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
+echo "configure:3086: checking whether stat file-mode macros are broken" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3091 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFIFO)
+# if S_ISSOCK (S_IFIFO)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "You lose" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_header_stat_broken=yes
+else
+ rm -rf conftest*
+ ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&6
+if test $ac_cv_header_stat_broken = yes; then
+ cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
+echo "configure:3148: checking for st_rdev in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3153 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_rdev;
+; return 0; }
+EOF
+if { (eval echo configure:3161: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_st_rdev=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_st_rdev=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6
+if test $ac_cv_struct_st_rdev = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ST_RDEV 1
+EOF
+
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:3182: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3187 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:3236: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking if compiler understands void""... $ac_c" 1>&6
+echo "configure:3257: checking if compiler understands void" >&5
+if eval "test \"`echo '$''{'ksh_cv_c_void'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3262 "configure"
+#include "confdefs.h"
+
+ void foo() { }
+ /* Some compilers (old pcc ones) like "void *a;", but a can't be used */
+ void *bar(a) void *a; { int *b = (int *) a; *b = 1; return a; }
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3273: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_c_void=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_c_void=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_c_void" 1>&6
+ if test $ksh_cv_c_void = yes; then
+ :
+ else
+ cat >> confdefs.h <<\EOF
+#define void char
+EOF
+
+ fi
+
+echo $ac_n "checking if compiler understands volatile""... $ac_c" 1>&6
+echo "configure:3296: checking if compiler understands volatile" >&5
+if eval "test \"`echo '$''{'ksh_cv_c_volatile'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3301 "configure"
+#include "confdefs.h"
+int x, y, z;
+int main() {
+volatile int a; int * volatile b = x ? &y : &z;
+ /* Older MIPS compilers (eg., in Ultrix 4.2) don't like *b = 0 */
+ *b = 0;
+; return 0; }
+EOF
+if { (eval echo configure:3310: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_c_volatile=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_c_volatile=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_c_volatile" 1>&6
+ if test $ksh_cv_c_volatile = yes; then
+ :
+ else
+ cat >> confdefs.h <<\EOF
+#define volatile
+EOF
+
+ fi
+
+echo $ac_n "checking if compiler understands prototypes""... $ac_c" 1>&6
+echo "configure:3333: checking if compiler understands prototypes" >&5
+if eval "test \"`echo '$''{'ksh_cv_c_prototypes'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3338 "configure"
+#include "confdefs.h"
+
+#include <stdarg.h>
+void foo(char *fmt, ...);
+int bar(int a, char b, char *c);
+int bar(a, b, c) int a; char b; char *c;
+{ foo("%d%c%s\n", a, b, c); return a + b + *c; }
+void foo(char *fmt, ...) { va_list a; va_start(a, fmt); va_end(a); }
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3352: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_c_prototypes=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_c_prototypes=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_c_prototypes" 1>&6
+ if test $ksh_cv_c_prototypes = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_PROTOTYPES 1
+EOF
+
+ fi
+
+echo $ac_n "checking if C compiler groks __attribute__(( .. ))""... $ac_c" 1>&6
+echo "configure:3373: checking if C compiler groks __attribute__(( .. ))" >&5
+if eval "test \"`echo '$''{'ksh_cv_c_func_attr'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3378 "configure"
+#include "confdefs.h"
+
+#include <stdarg.h>
+void test_fmt(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void test_fmt(char *fmt, ...) { return; }
+int test_cnst(int) __attribute__((const));
+int test_cnst(int x) { return x + 1; }
+void test_nr() __attribute__((noreturn));
+void test_nr() { exit(1); }
+void test_uk() __attribute__((blah));
+void test_uk() { return; }
+
+int main() {
+test_nr("%d", 10); test_cnst(2); test_uk(); test_nr();
+; return 0; }
+EOF
+if { (eval echo configure:3395: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ksh_cv_c_func_attr=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_c_func_attr=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_c_func_attr" 1>&6
+ if test $ksh_cv_c_func_attr = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GCC_FUNC_ATTR 1
+EOF
+
+ fi
+
+# Pull the hash mark out of the macro call to avoid m4 problems.
+ac_msg="whether #! works in shell scripts"
+echo $ac_n "checking $ac_msg""... $ac_c" 1>&6
+echo "configure:3418: checking $ac_msg" >&5
+if eval "test \"`echo '$''{'ac_cv_sys_interpreter'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo '#! /bin/cat
+exit 69
+' > conftest
+chmod u+x conftest
+(SHELL=/bin/sh; export SHELL; ./conftest >/dev/null)
+if test $? -ne 69; then
+ ac_cv_sys_interpreter=yes
+else
+ ac_cv_sys_interpreter=no
+fi
+rm -f conftest
+fi
+
+echo "$ac_t""$ac_cv_sys_interpreter" 1>&6
+
+if test $ac_cv_sys_interpreter = no;
+ then cat >> confdefs.h <<\EOF
+#define SHARPBANG 1
+EOF
+
+fi
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:3473: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking if dup2() works (ie, resets the close-on-exec flag)""... $ac_c" 1>&6
+echo "configure:3523: checking if dup2() works (ie, resets the close-on-exec flag)" >&5
+if eval "test \"`echo '$''{'ksh_cv_dup2_clexec_ok'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot test if dup2 is broken when cross compiling - assuming it is" 1>&2
+ ksh_cv_dup2_clexec_ok=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 3532 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#ifndef F_GETFD
+# define F_GETFD 1
+#endif
+#ifndef F_SETFD
+# define F_SETFD 2
+#endif
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+/* On some systems (Ultrix 2.1..4.2 (and more?)), dup2() does not clear
+ the close on exec flag */
+main()
+{
+ int fd1, fd2;
+ fd1 = open("/dev/null", O_RDONLY);
+ if (fcntl(fd1, F_SETFD, 1) < 0)
+ exit(1);
+ fd2 = dup2(fd1, fd1 + 1);
+ if (fd2 < 0)
+ exit(2);
+ exit(fcntl(fd2, F_GETFD, 0) == 0 ? 0 : 3);
+}
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_dup2_clexec_ok=yes
+else
+ ksh_cv_dup2_clexec_ok=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_dup2_clexec_ok" 1>&6
+ if test $ksh_cv_dup2_clexec_ok = no; then
+ cat >> confdefs.h <<\EOF
+#define DUP2_BROKEN 1
+EOF
+
+ fi
+
+echo $ac_n "checking flavour of signal routines""... $ac_c" 1>&6
+echo "configure:3582: checking flavour of signal routines" >&5
+if eval "test \"`echo '$''{'ksh_cv_signal_check'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3587 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+
+ sigset_t ss;
+ struct sigaction sa;
+ sigemptyset(&ss); sigsuspend(&ss);
+ sigaction(SIGINT, &sa, (struct sigaction *) 0);
+ sigprocmask(SIG_BLOCK, &ss, (sigset_t *) 0);
+
+; return 0; }
+EOF
+if { (eval echo configure:3600: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_signal_check=posix
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 3608 "configure"
+#include "confdefs.h"
+#include <signal.h>
+int main() {
+
+ int mask = sigmask(SIGINT);
+ sigsetmask(mask); sigblock(mask); sigpause(mask);
+
+; return 0; }
+EOF
+if { (eval echo configure:3618: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_signal_check=bsd42
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 3626 "configure"
+#include "confdefs.h"
+#include <signal.h>
+ RETSIGTYPE foo() { }
+int main() {
+
+ int mask = sigmask(SIGINT);
+ sigset(SIGINT, foo); sigrelse(SIGINT);
+ sighold(SIGINT); sigpause(SIGINT);
+
+; return 0; }
+EOF
+if { (eval echo configure:3638: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ ksh_cv_signal_check=bsd41
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ksh_cv_signal_check=v7
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ksh_cv_signal_check" 1>&6
+ if test $ksh_cv_signal_check = posix; then
+ cat >> confdefs.h <<\EOF
+#define POSIX_SIGNALS 1
+EOF
+
+ else
+ cat >> confdefs.h <<\EOF
+#define USE_FAKE_SIGACT 1
+EOF
+
+ if test $ksh_cv_signal_check = bsd42; then
+ cat >> confdefs.h <<\EOF
+#define BSD42_SIGNALS 1
+EOF
+
+ elif test $ksh_cv_signal_check = bsd41; then
+ cat >> confdefs.h <<\EOF
+#define BSD41_SIGNALS 1
+EOF
+
+ echo $ac_n "checking if signals interrupt read()""... $ac_c" 1>&6
+echo "configure:3676: checking if signals interrupt read()" >&5
+if eval "test \"`echo '$''{'ksh_cv_signals_interrupt'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot determine if signals interrupt read() when cross compiling" 1>&2; exit 1; }
+
+else
+cat > conftest.$ac_ext <<EOF
+#line 3685 "configure"
+#include "confdefs.h"
+
+#include <errno.h>
+#include <signal.h>
+
+ extern int errno;
+ int flag = 0;
+
+ RETSIGTYPE
+ catcher(int sig)
+ {
+ flag = 1;
+ return RETSIGVAL;
+ }
+
+ int
+ main()
+ {
+ int pid;
+ int fdc[2]; /* child writes to parent */
+ int fdp[2]; /* parent writes to child */
+ char buf;
+ int nread;
+
+ if (pipe(fdc) < 0)
+ exit(1);
+ if (pipe(fdp) < 0)
+ exit(2);
+ if ((pid = fork()) < 0)
+ exit(3);
+ if (pid == 0) {
+ close(fdc[0]);
+ close(fdp[1]);
+ if (read(fdp[0], &buf, 1) != 0)
+ exit(10);
+ sleep(1); /* let parent into read */
+ if (kill(getppid(), SIGALRM) < 0)
+ exit(11);
+ sleep(1); /* ensure parent gets to run */
+ write(fdc[1], "1", 1);
+ close(fdc[1]);
+ exit(0);
+ }
+ close(fdc[1]);
+ close(fdp[0]);
+
+ /* Use native routines for test as this is what the shell
+ * will be using...
+ */
+#ifdef POSIX_SIGNALS
+ {
+ struct sigaction sa, osa;
+ sa.sa_handler = catcher;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGALRM, &sa, &osa);
+ }
+#else /* POSIX_SIGNALS */
+# ifdef BSD42_SIGNALS
+ {
+ struct sigvec vec, ovec;
+ vec.sv_handler = catcher;
+ vec.sv_mask = 0;
+ vec.sv_flags = 0;
+# ifdef SV_INTERRUPT
+ vec.sv_flags |= SV_INTERRUPT;
+# endif /* SV_INTERRUPT */
+ sigvec(SIGALRM, &vec, &ovec);
+ }
+# else /* BSD42_SIGNALS */
+# ifdef BSD41_SIGNALS
+ sigset(SIGALRM, catcher);
+# else /* BSD41_SIGNALS */
+# ifdef V7_SIGNALS
+ signal(SIGALRM, catcher);
+# else /* V7_SIGNALS */
+ what kind of signals do you have?
+# endif /* V7_SIGNALS */
+# endif /* BSD41_SIGNALS */
+# endif /* BSD42_SIGNALS */
+#endif /* POSIX_SIGNALS */
+ close(fdp[1]); /* start child */
+ nread = read(fdc[0], &buf, 1);
+ if (nread == 0)
+ exit(4);
+ if (nread > 0)
+ exit(5);
+ if (errno != EINTR)
+ exit(6);
+ if (!flag)
+ exit(7);
+ exit(0);
+ return 0;
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_signals_interrupt=yes
+else
+ ksh_cv_signals_interrupt=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_signals_interrupt" 1>&6
+ if test $ksh_cv_signals_interrupt = no ; then
+ cat >> confdefs.h <<\EOF
+#define SIGNALS_DONT_INTERRUPT 1
+EOF
+
+ fi
+ else
+ cat >> confdefs.h <<\EOF
+#define V7_SIGNALS 1
+EOF
+
+ fi
+ fi
+
+echo $ac_n "checking flavour of pgrp routines""... $ac_c" 1>&6
+echo "configure:3808: checking flavour of pgrp routines" >&5
+if eval "test \"`echo '$''{'ksh_cv_pgrp_check'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot taste pgrp routines when cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 3816 "configure"
+#include "confdefs.h"
+
+/* Check for BSD process groups */
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+ main()
+ {
+ int ecode = 0, child = fork();
+ if (child < 0)
+ exit(1);
+ if (child == 0) {
+ signal(SIGTERM, SIG_DFL); /* just to make sure */
+ sleep(10);
+ exit(9);
+ }
+ if (setpgrp(child, child) < 0)
+ ecode = 2;
+ else if (getpgrp(child) != child)
+ ecode = 3;
+ kill(child, SIGTERM);
+ exit(ecode);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_pgrp_check=bsd
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot taste pgrp routines when cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 3851 "configure"
+#include "confdefs.h"
+
+/* Check for POSIX process groups */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+ main()
+ {
+ int child;
+ int n, p1[2], p2[2];
+ char buf[1];
+ if (pipe(p1) < 0 || pipe(p2) < 0)
+ exit(1);
+ if ((child = fork()) < 0)
+ exit(2);
+ if (child == 0) {
+ n = read(p1[0], buf, sizeof(buf)); /* wait for parent to setpgid */
+ buf[0] = (n != 1 ? 10 : (getpgrp() != getpid() ? 11 : 0));
+ if (write(p2[1], buf, sizeof(buf)) != 1)
+ exit(12);
+ exit(0);
+ }
+ if (setpgid(child, child) < 0)
+ exit(3);
+ if (write(p1[1], buf, 1) != 1)
+ exit(4);
+ if (read(p2[0], buf, 1) != 1)
+ exit(5);
+ exit((int) buf[0]);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_pgrp_check=posix
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot taste pgrp routines when cross compiling" 1>&2; exit 1; }
+else
+cat > conftest.$ac_ext <<EOF
+#line 3892 "configure"
+#include "confdefs.h"
+
+/* Check for SYSV process groups */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+ main()
+ {
+ int child;
+ int n, p[2];
+ char buf[1];
+ if (pipe(p) < 0)
+ exit(1);
+ if ((child = fork()) < 0)
+ exit(2);
+ if (child == 0) {
+ buf[0] = (setpgrp() < 0 ? 10 : (getpgrp() != getpid() ? 11 : 0));
+ if (write(p[1], buf, sizeof(buf)) != 1)
+ exit(11);
+ exit(0);
+ }
+ if (read(p[0], buf, 1) != 1)
+ exit(3);
+ exit((int) buf[0]);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_pgrp_check=sysv
+else
+ ksh_cv_pgrp_check=none
+fi
+fi
+rm -fr conftest*
+fi
+fi
+rm -fr conftest*
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_pgrp_check" 1>&6
+ if test $ksh_cv_pgrp_check = bsd; then
+ cat >> confdefs.h <<\EOF
+#define BSD_PGRP 1
+EOF
+
+ elif test $ksh_cv_pgrp_check = posix; then
+ cat >> confdefs.h <<\EOF
+#define POSIX_PGRP 1
+EOF
+
+ elif test $ksh_cv_pgrp_check = sysv; then
+ cat >> confdefs.h <<\EOF
+#define SYSV_PGRP 1
+EOF
+
+ else
+ cat >> confdefs.h <<\EOF
+#define NO_PGRP 1
+EOF
+
+ fi
+
+ if test $ksh_cv_pgrp_check = bsd || test $ksh_cv_pgrp_check = posix ; then
+ echo $ac_n "checking if process group synchronization is required""... $ac_c" 1>&6
+echo "configure:3961: checking if process group synchronization is required" >&5
+if eval "test \"`echo '$''{'ksh_cv_need_pgrp_sync'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot test if pgrp synchronization needed when cross compiling - assuming it is" 1>&2
+ ksh_cv_need_pgrp_sync=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 3970 "configure"
+#include "confdefs.h"
+
+ main()
+ {
+#ifdef POSIX_PGRP
+# define getpgID() getpgrp()
+#else
+# define getpgID() getpgrp(0)
+# define setpgid(x,y) setpgrp(x,y)
+#endif
+ int pid1, pid2, fds[2];
+ int status;
+ char ok;
+ switch (pid1 = fork()) {
+ case -1:
+ exit(1);
+ case 0:
+ setpgid(0, getpid());
+ exit(0);
+ }
+ setpgid(pid1, pid1);
+ sleep(2); /* let first child die */
+ if (pipe(fds) < 0)
+ exit(2);
+ switch (pid2 = fork()) {
+ case -1:
+ exit(3);
+ case 0:
+ setpgid(0, pid1);
+ ok = getpgID() == pid1;
+ write(fds[1], &ok, 1);
+ exit(0);
+ }
+ setpgid(pid2, pid1);
+ close(fds[1]);
+ if (read(fds[0], &ok, 1) != 1)
+ exit(4);
+ wait(&status);
+ wait(&status);
+ exit(ok ? 0 : 5);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_need_pgrp_sync=no
+else
+ ksh_cv_need_pgrp_sync=yes
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_need_pgrp_sync" 1>&6
+ if test $ksh_cv_need_pgrp_sync = yes; then
+ cat >> confdefs.h <<\EOF
+#define NEED_PGRP_SYNC 1
+EOF
+
+ fi
+ fi
+
+echo $ac_n "checking if opendir() fails to open non-directories""... $ac_c" 1>&6
+echo "configure:4034: checking if opendir() fails to open non-directories" >&5
+if eval "test \"`echo '$''{'ksh_cv_opendir_ok'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot test if opendir opens non-directories when cross compiling - assuming it does" 1>&2
+ ksh_cv_opendir_ok=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 4043 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef SYSNDIR
+# include <sys/ndir.h>
+# endif /* SYSNDIR */
+# ifdef SYSDIR
+# include <sys/dir.h>
+# endif /* SYSDIR */
+# ifdef NDIR
+# include <ndir.h>
+# endif /* NDIR */
+#endif /* DIRENT */
+ main()
+ {
+ int i, ret = 0;
+ FILE *fp;
+ char *fname = "conftestod", buf[256];
+ for (i = 0; i < sizeof(buf); i++) /* memset(buf, 0, sizeof(buf)) */
+ buf[i] = 0;
+ unlink(fname); /* paranoia */
+ i = ((fp = fopen(fname, "w")) == (FILE *) 0 && (ret = 1))
+ || (fwrite(buf, sizeof(buf), 1, fp) != 1 && (ret = 2))
+ || (fclose(fp) == EOF && (ret = 3))
+ || (opendir(fname) && (ret = 4))
+ || (opendir("/dev/null") && (ret = 5));
+ unlink(fname);
+ exit(ret);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_opendir_ok=yes
+else
+ ksh_cv_opendir_ok=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_opendir_ok" 1>&6
+ if test $ksh_cv_opendir_ok = no; then
+ cat >> confdefs.h <<\EOF
+#define OPENDIR_DOES_NONDIR 1
+EOF
+
+ fi
+
+echo $ac_n "checking if you have /dev/fd/n""... $ac_c" 1>&6
+echo "configure:4102: checking if you have /dev/fd/n" >&5
+if eval "test \"`echo '$''{'ksh_cv_dev_fd'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo "configure: warning: cannot determine if you have /dev/fd support" 1>&2
+ ksh_cv_dev_fd=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 4111 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+ main()
+ {
+ struct stat s1, s2;
+ FILE *fp1, *fp2;
+ char *file = "conftest.file";
+ char devfd[32];
+
+ if (!(fp1 = fopen(file, "w")))
+ exit(1);
+ if (fstat(fileno(fp1), &s1) < 0)
+ exit(2);
+ sprintf(devfd, "/dev/fd/%d", fileno(fp1));
+ if (!(fp2 = fopen(devfd, "w")))
+ exit(3);
+ if (fstat(fileno(fp2), &s2) < 0)
+ exit(4);
+ if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
+ exit(5);
+ exit(0);
+ }
+
+EOF
+eval $ac_link
+if test -s conftest$ac_exe_suffix && (./conftest; exit) 2>/dev/null; then
+ ksh_cv_dev_fd=yes
+else
+ ksh_cv_dev_fd=no
+fi
+fi
+rm -fr conftest*
+fi
+
+echo "$ac_t""$ksh_cv_dev_fd" 1>&6
+ if test $ksh_cv_dev_fd = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_DEV_FD 1
+EOF
+
+ fi
+
+if test X"$LDSTATIC" != X; then
+ LDFLAGS=`echo -- "$LDFLAGS" | sed -e 's/^-- //' -e 's?$LDSTATIC?\$(LDSTATIC)?'`
+fi
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.12"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@SHELL_PROG@%$SHELL_PROG%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@LDSTATIC@%$LDSTATIC%g
+s%@ac_exe_suffix@%$ac_exe_suffix%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/shells/pdksh/files/configure.in b/shells/pdksh/files/configure.in
new file mode 100644
index 00000000000..4cf1c710d98
--- /dev/null
+++ b/shells/pdksh/files/configure.in
@@ -0,0 +1,328 @@
+dnl
+dnl This file, configure.in, which is a part of pdksh (the public domain ksh),
+dnl is placed in the public domain. It comes with no licence, warranty
+dnl or guarantee of any kind (i.e., at your own risk).
+dnl
+dnl
+dnl
+dnl Process this file with autoconf to produce a configure script
+dnl
+AC_INIT(c_ksh.c)
+AC_CONFIG_HEADER(config.h)
+dnl
+dnl
+dnl
+dnl Set up command line options (--enable/--disable)
+dnl
+def_path_unix="/bin:/usr/bin:/usr/ucb"
+def_path_os2="c:/usr/bin;c:/os2;/os2"
+AC_ARG_ENABLE(path,
+[ --enable-path=PaTh (NOTE: this value isn't used if confstr() and _CS_PATH
+ are available, or if <paths.h> defines _PATH_DEFPATH)
+ Use PaTh if PATH isn't specified in the environment
+ when the shell starts. A value without . in it is
+ safest.
+ The default value is \"/bin:/usr/bin:/usr/ucb\".],,
+ enable_path=default)
+case $enable_path:$ksh_cv_os_type in
+ default:OS2_EMX) enable_path="$def_path_os2" ;;
+ default:*) enable_path="$def_path_unix" ;;
+esac
+case $enable_path in
+ \"*\") ;;
+ *)
+ enable_path="\"$enable_path\""
+ ;;
+esac
+AC_DEFINE_UNQUOTED(DEFAULT_PATH, $enable_path)
+dnl
+dnl
+dnl
+dnl Specify what kind of shell we are to build. Options are ksh and sh.
+dnl This must be before most other options, as it controls their default
+dnl behaviour.
+dnl
+AC_ARG_ENABLE(shell,
+[ --enable-shell={sh,ksh} Specify the kind of shell that is to be built (the
+ default is ksh). Specifiying sh compiles out:
+ command line editing (emacs/vi), history,
+ a bunch of aliases, [[ .. ]], select, let,
+ brace-expansion, extended globing (*(..|..), etc.),
+ co-processes, some special environment variables
+ (ie, MAIL, MAILCHECK, MAILPATH, RANDOM, SECONDS,
+ TMOUT).],,
+ enable_shell=ksh)
+case $enable_shell in
+ ksh) AC_DEFINE(KSH) ;;
+ sh) ;;
+ *)
+ AC_MSG_ERROR(bad --enable-shell: must be one of sh or ksh)
+esac
+SHELL_PROG=$enable_shell
+AC_SUBST(SHELL_PROG)
+dnl
+dnl
+dnl
+AC_ARG_ENABLE(emacs,
+[ --disable-emacs Compile out emacs command line editing (by default,
+ this is compiled in for ksh, compiled out for sh).])
+case $enable_emacs:$enable_shell in
+ yes:*|:ksh) enable_emacs=yes; AC_DEFINE(EMACS) ;;
+ no:*|:sh) enable_emacs=no;;
+ *) AC_MSG_ERROR(bad --enable-emacs argument)
+esac
+dnl
+dnl
+AC_ARG_ENABLE(vi,
+[ --disable-vi Compile out vi command line editing (by default,
+ this is compiled in for ksh, compiled out for sh).])
+case $enable_vi:$enable_shell in
+ yes:*|:ksh) enable_vi=yes; AC_DEFINE(VI) ;;
+ no:*|:sh) enable_vi=no;;
+ *) AC_MSG_ERROR(bad --enable-vi argument)
+esac
+dnl
+dnl
+AC_ARG_ENABLE(jobs,
+[ --disable-jobs Compile out job control support. If your system
+ doesn't support job control, this will automatically
+ be compiled out.])
+case $enable_jobs in
+ yes|'') enable_jobs=yes; AC_DEFINE(JOBS) ;;
+ no) enable_jobs=no;;
+ *) AC_MSG_ERROR(bad --enable-jobs argument)
+esac
+dnl
+dnl
+AC_ARG_ENABLE(brace-expand,
+[ --disable-brace-expand Compile out brace expansion code (a{b,c} -> ab ac)
+ (by default, this is compiled in for ksh, compiled
+ out for sh). Brace expansion can also be disabled
+ at run time (see set +o braceexpand).])
+case $enable_brace_expand:$enable_shell in
+ yes:*|:ksh) enable_brace_expand=yes; AC_DEFINE(BRACE_EXPAND) ;;
+ no:*|:sh) enable_brace_expand=no;;
+ *) AC_MSG_ERROR(bad --enable-brace-expand argument)
+esac
+dnl
+dnl
+AC_ARG_ENABLE(history,
+[ --enable-history={no,simple,complex} By default, simple history is used for
+ ksh, no history is used for sh. \`simple' means
+ history file is read on start-up, written when shell
+ exists. \`complex' means history files are updated
+ after each command so concurrent shells read each
+ other's commands. Note: \`complex' history doesn't
+ work well across NFS; also, it requires the mmap()
+ and flock() functions - if these aren't available,
+ \`simple' history is automatically used.])
+case $enable_history:$enable_shell in
+ simple:*|:ksh) enable_history=simple; ;;
+ complex:*) enable_history=complex; AC_DEFINE(COMPLEX_HISTORY) ;;
+ no:*|:sh)
+ case $enable_history:$enable_vi:$enable_emacs in
+ no:yes:*|no:*:yes)
+ AC_MSG_ERROR(can't disable history when vi or emacs is enabled) ;;
+ :yes:*|:*:yes)
+ enable_history=yes;;
+ *)
+ enable_history=no;;
+ esac
+ ;;
+ *) AC_MSG_ERROR(bad --enable-history argument)
+esac
+test X"$enable_history" != Xno && AC_DEFINE(HISTORY)
+dnl
+dnl
+AC_ARG_ENABLE(posixly_correct,
+[ --enable-posixly-correct Enable if you want POSIX behavior by default
+ (otherwise, posix behavior is only turned on if the
+ environment variable POSIXLY_CORRECT is present or by
+ using \"set -o posix\"; it can be turned off with
+ \"set +o posix\"). See the POSIX Mode section in the
+ man page for details on what this option affects.
+ NOTE: posix mode is not compatable with some bourne
+ sh/at&t ksh scripts.])
+case $enable_posixly_correct:$enable_shell in
+ yes:*) enable_posixly_correct=yes; AC_DEFINE(POSIXLY_CORRECT) ;;
+ no:*|:*) enable_posixly_correct=no;;
+ *) AC_MSG_ERROR(bad --enable-posixly_correct argument)
+esac
+dnl
+dnl
+AC_ARG_ENABLE(default-env,
+[ --enable-default-env=FILE Include FILE if ENV parameter is not set when
+ the shell starts. This can be useful when used with
+ rsh(1), which creates a non-login shell (ie, profile
+ isn't read, so there is no opertunity to set ENV).
+ Setting ENV to null disables the inclusion of
+ DEFAULT_ENV. NOTE: This is a non-standard feature
+ (ie, at&t ksh has no default environment).],,
+ enable_default_env=no)
+if test X"$enable_default_env" != Xno; then
+ # The [a-zA-Z]:/ is for os2 types...
+ case $enable_default_env in
+ /*|[[a-zA-Z]]:/*)
+ enable_default_env="\"$enable_default_env\""
+ ;;
+ \"/*\"|\"[[a-zA-Z]]:/*\")
+ ;;
+ *)
+ AC_MSG_ERROR(--enable-default-env argument must be an absolute path (was $enable_default_env))
+ ;;
+ esac
+ AC_DEFINE_UNQUOTED(DEFAULT_ENV, $enable_default_env)
+fi
+dnl
+dnl
+dnl Don't want silly documented - its silly
+AC_ARG_ENABLE(silly,[ --enable-silly [A silly option]])
+case $enable_silly:$enable_shell in
+ yes:*) enable_silly=yes; AC_DEFINE(SILLY) ;;
+ no:*|:*) enable_silly=no;;
+ *) AC_MSG_ERROR(bad --enable-silly argument)
+esac
+dnl
+dnl
+dnl don't want swtch documented - its ancient and probably doesn't work
+AC_ARG_ENABLE(swtch,
+[ --enable-swtch For use with shell layers (shl(1)). This has not
+ been tested for some time.])
+case $enable_swtch:$enable_shell in
+ yes:*) enable_swtch=yes; AC_DEFINE(SWTCH) ;;
+ no:*|:*) enable_swtch=no;;
+ *) AC_MSG_ERROR(bad --enable-swtch argument)
+esac
+dnl
+dnl
+dnl Start of auto-configuration stuff...
+dnl
+dnl
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_GCC_TRADITIONAL
+dnl A hack to turn on warning messages for gcc - Warn-flags is not in
+dnl the distribution since not everyone wants to see this stuff.
+dnl (Warn-flags contains: -Wall)
+if test X"$GCC" = Xyes && test -f $srcdir/Warn-flags; then
+ CFLAGS="${CFLAGS+$CFLAGS }`cat $srcdir/Warn-flags`"
+fi
+
+dnl
+dnl If LDSTATIC set in environment, pass it on to the Makefile and use it when
+dnl doing compile checks to ensure we are checking the right thing.
+AC_SUBST(LDSTATIC)LDSTATIC=${LDSTATIC-}
+test X"$LDSTATIC" != X && LDFLAGS="${LDFLAGS+$LDFLAGS }$LDSTATIC"
+dnl
+dnl Executable suffix - normally empty; .exe on os2.
+AC_SUBST(ac_exe_suffix)dnl
+
+dnl this incorperates AC_AIX, AC_ISC_POSIX and AC_MINIX tests and does others
+KSH_OS_TYPE
+dnl
+dnl Program name munging stuff (prefix, suffix, transform)
+AC_ARG_PROGRAM
+dnl
+dnl
+dnl Headers
+dnl
+AC_HEADER_DIRENT
+KSH_UNISTD_H
+KSH_TERM_CHECK
+AC_CHECK_HEADERS(stddef.h stdlib.h string.h memory.h fcntl.h limits.h paths.h \
+ sys/param.h sys/resource.h values.h ulimit.h sys/time.h)
+AC_HEADER_TIME
+KSH_HEADER_SYS_WAIT
+dnl
+dnl
+dnl Typedefs
+dnl
+dnl (don't use AC_TYPE_XXX() 'cause it doesn't check word boundaries)
+KSH_CHECK_H_TYPE(off_t, for off_t in sys/types.h, , long)
+KSH_CHECK_H_TYPE(mode_t, for mode_t in sys/types.h, , short)
+KSH_CHECK_H_TYPE(pid_t, for pid_t in sys/types.h, , int)
+KSH_CHECK_H_TYPE(uid_t, for uid_t in sys/types.h, , int)
+if test $ac_cv_type_uid_t = no; then
+ AC_DEFINE(gid_t, int)
+fi
+define([AC_PROVIDE_AC_TYPE_UID_T],)
+AC_TYPE_SIGNAL
+case $ac_cv_type_signal in
+int) ksh_cv_signal_retval=0 ;;
+void) ksh_cv_signal_retval= ;;
+*)
+ AC_MSG_ERROR(Internal erorr: unknown signal return type: $ac_cv_type_signal)
+esac
+AC_DEFINE_UNQUOTED(RETSIGVAL, $ksh_cv_signal_retval)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+dnl sh.h sets INT32 to int or long as appropriate. Some burnt systems, such
+dnl as NeXT's, clock_t is in sys/time.h (in non-posix mode).
+KSH_CHECK_H_TYPE(clock_t, [[for clock_t in any of <sys/types.h>, <sys/times.h> and <sys/time.h>]],
+ [
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+#include <sys/times.h>
+ ], INT32)
+KSH_CHECK_H_TYPE(sigset_t, for sigset_t in <sys/types.h> and <signal.h>,
+ [#include <signal.h>], unsigned)
+KSH_RLIM_CHECK
+dnl
+dnl
+dnl Library functions
+dnl
+KSH_MEMMOVE
+KSH_MEMSET
+AC_CHECK_FUNCS(confstr dup2 flock getcwd getwd killpg nice \
+ setrlimit strerror strcasecmp strstr sysconf tcsetpgrp \
+ ulimit waitpid wait3)
+AC_CHECK_FUNCS(sigsetjmp _setjmp, break)
+AC_FUNC_MMAP
+KSH_FUNC_LSTAT
+KSH_SYS_ERRLIST
+KSH_SYS_SIGLIST
+KSH_TIME_DECLARED
+KSH_TIMES_CHECK
+dnl
+dnl
+dnl Structures
+dnl
+AC_HEADER_STAT
+AC_STRUCT_ST_RDEV
+dnl
+dnl
+dnl Compiler characteristics
+dnl
+AC_C_CONST
+KSH_C_VOID
+KSH_C_VOLATILE
+KSH_C_PROTOTYPES
+KSH_C_FUNC_ATTR
+dnl
+dnl
+dnl System services
+dnl
+AC_SYS_INTERPRETER
+if test $ac_cv_sys_interpreter = no;
+ then AC_DEFINE(SHARPBANG)
+fi
+AC_PROG_INSTALL
+dnl
+dnl
+dnl Misc ksh tests
+dnl
+KSH_DUP2_CLEXEC_CHECK
+KSH_SIGNAL_CHECK
+KSH_PGRP_CHECK
+KSH_PGRP_SYNC
+KSH_OPENDIR_CHECK
+KSH_DEV_FD
+dnl
+dnl
+dnl Take replace value of LDSTATIC in LDFLAGS with reference to make variable
+if test X"$LDSTATIC" != X; then
+ LDFLAGS=`echo -- "$LDFLAGS" | sed -e 's/^-- //' -e 's?$LDSTATIC?\$(LDSTATIC)?'`
+fi
+dnl
+AC_OUTPUT(Makefile)
diff --git a/shells/pdksh/files/edit.c b/shells/pdksh/files/edit.c
new file mode 100644
index 00000000000..45446ef825f
--- /dev/null
+++ b/shells/pdksh/files/edit.c
@@ -0,0 +1,1021 @@
+/*
+ * Command line editing - common code
+ *
+ */
+
+#include "config.h"
+#ifdef EDIT
+
+#include "sh.h"
+#include "tty.h"
+#define EXTERN
+#include "edit.h"
+#undef EXTERN
+#ifdef OS_SCO /* SCO Unix 3.2v4.1 */
+# include <sys/stream.h> /* needed for <sys/ptem.h> */
+# include <sys/ptem.h> /* needed for struct winsize */
+#endif /* OS_SCO */
+#include <ctype.h>
+#include "ksh_stat.h"
+
+
+#if defined(TIOCGWINSZ)
+static RETSIGTYPE x_sigwinch ARGS((int sig));
+static int got_sigwinch;
+static void check_sigwinch ARGS((void));
+#endif /* TIOCGWINSZ */
+
+static int x_file_glob ARGS((int flags, const char *str, int slen,
+ char ***wordsp));
+static int x_command_glob ARGS((int flags, const char *str, int slen,
+ char ***wordsp));
+static int x_locate_word ARGS((const char *buf, int buflen, int pos,
+ int *startp, int *is_command));
+
+static char vdisable_c;
+
+
+/* Called from main */
+void
+x_init()
+{
+ /* set to -2 to force initial binding */
+ edchars.erase = edchars.kill = edchars.intr = edchars.quit
+ = edchars.eof = -2;
+ /* default value for deficient systems */
+ edchars.werase = 027; /* ^W */
+
+#ifdef TIOCGWINSZ
+# ifdef SIGWINCH
+ if (setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_SHTRAP))
+ sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
+# endif /* SIGWINCH */
+ got_sigwinch = 1; /* force initial check */
+ check_sigwinch();
+#endif /* TIOCGWINSZ */
+
+#ifdef EMACS
+ x_init_emacs();
+#endif /* EMACS */
+
+ /* Bizarreness to figure out how to disable
+ * a struct termios.c_cc[] char
+ */
+#ifdef _POSIX_VDISABLE
+ if (_POSIX_VDISABLE >= 0)
+ vdisable_c = (char) _POSIX_VDISABLE;
+ else
+ /* `feature not available' */
+ vdisable_c = (char) 0377;
+#else
+# if defined(HAVE_PATHCONF) && defined(_PC_VDISABLE)
+ vdisable_c = fpathconf(tty_fd, _PC_VDISABLE);
+# else
+ vdisable_c = (char) 0377; /* default to old BSD value */
+# endif
+#endif /* _POSIX_VDISABLE */
+}
+
+#if defined(TIOCGWINSZ)
+static RETSIGTYPE
+x_sigwinch(sig)
+ int sig;
+{
+ got_sigwinch = 1;
+ return RETSIGVAL;
+}
+
+static void
+check_sigwinch ARGS((void))
+{
+ if (got_sigwinch) {
+ struct winsize ws;
+
+ got_sigwinch = 0;
+ if (procpid == kshpid && ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) {
+ struct tbl *vp;
+
+ /* Do NOT export COLUMNS/LINES. Many applications
+ * check COLUMNS/LINES before checking ws.ws_col/row,
+ * so if the app is started with C/L in the environ
+ * and the window is then resized, the app won't
+ * see the change cause the environ doesn't change.
+ */
+ if (ws.ws_col) {
+ x_cols = ws.ws_col < MIN_COLS ? MIN_COLS
+ : ws.ws_col;
+
+ if ((vp = typeset("COLUMNS", 0, 0, 0, 0)))
+ setint(vp, (long) ws.ws_col);
+ }
+ if (ws.ws_row
+ && (vp = typeset("LINES", 0, 0, 0, 0)))
+ setint(vp, (long) ws.ws_row);
+ }
+ }
+}
+#endif /* TIOCGWINSZ */
+
+/*
+ * read an edited command line
+ */
+int
+x_read(buf, len)
+ char *buf;
+ size_t len;
+{
+ int i;
+
+#if defined(TIOCGWINSZ)
+ if (got_sigwinch)
+ check_sigwinch();
+#endif /* TIOCGWINSZ */
+
+ x_mode(TRUE);
+#ifdef EMACS
+ if (Flag(FEMACS) || Flag(FGMACS))
+ i = x_emacs(buf, len);
+ else
+#endif
+#ifdef VI
+ if (Flag(FVI))
+ i = x_vi(buf, len);
+ else
+#endif
+ i = -1; /* internal error */
+ x_mode(FALSE);
+ return i;
+}
+
+/* tty I/O */
+
+int
+x_getc()
+{
+#ifdef OS2
+ unsigned char c = _read_kbd(0, 1, 0);
+ return c == 0 ? 0xE0 : c;
+#else /* OS2 */
+ char c;
+ int n;
+
+ while ((n = blocking_read(0, &c, 1)) < 0 && errno == EINTR)
+ if (trap) {
+ x_mode(FALSE);
+ runtraps(0);
+ x_mode(TRUE);
+ }
+ if (n != 1)
+ return -1;
+ return (int) (unsigned char) c;
+#endif /* OS2 */
+}
+
+void
+x_flush()
+{
+ shf_flush(shl_out);
+}
+
+void
+x_putc(c)
+ int c;
+{
+ shf_putc(c, shl_out);
+}
+
+void
+x_puts(s)
+ const char *s;
+{
+ while (*s != 0)
+ shf_putc(*s++, shl_out);
+}
+
+bool_t
+x_mode(onoff)
+ bool_t onoff;
+{
+ static bool_t x_cur_mode;
+ bool_t prev;
+
+ if (x_cur_mode == onoff)
+ return x_cur_mode;
+ prev = x_cur_mode;
+ x_cur_mode = onoff;
+
+ if (onoff) {
+ TTY_state cb;
+ X_chars oldchars;
+
+ oldchars = edchars;
+ cb = tty_state;
+
+#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
+ edchars.erase = cb.c_cc[VERASE];
+ edchars.kill = cb.c_cc[VKILL];
+ edchars.intr = cb.c_cc[VINTR];
+ edchars.quit = cb.c_cc[VQUIT];
+ edchars.eof = cb.c_cc[VEOF];
+# ifdef VWERASE
+ edchars.werase = cb.c_cc[VWERASE];
+# endif
+# ifdef _CRAY2 /* brain-damaged terminal handler */
+ cb.c_lflag &= ~(ICANON|ECHO);
+ /* rely on print routine to map '\n' to CR,LF */
+# else
+ cb.c_iflag &= ~(INLCR|ICRNL);
+# ifdef _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */
+ cb.c_lflag &= ~(ICANON|ECHO);
+# else
+# ifdef SWTCH /* need CBREAK to handle swtch char */
+ cb.c_lflag &= ~(ICANON|ECHO);
+ cb.c_lflag |= ISIG;
+ cb.c_cc[VINTR] = vdisable_c;
+ cb.c_cc[VQUIT] = vdisable_c;
+# else
+ cb.c_lflag &= ~(ISIG|ICANON|ECHO);
+# endif
+# endif
+# ifdef VLNEXT
+ /* osf/1 processes lnext when ~icanon */
+ cb.c_cc[VLNEXT] = vdisable_c;
+# endif /* VLNEXT */
+# ifdef VDISCARD
+ /* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */
+ cb.c_cc[VDISCARD] = vdisable_c;
+# endif /* VDISCARD */
+ cb.c_cc[VTIME] = 0;
+ cb.c_cc[VMIN] = 1;
+# endif /* _CRAY2 */
+#else
+ /* Assume BSD tty stuff. */
+ edchars.erase = cb.sgttyb.sg_erase;
+ edchars.kill = cb.sgttyb.sg_kill;
+ cb.sgttyb.sg_flags &= ~ECHO;
+ cb.sgttyb.sg_flags |= CBREAK;
+# ifdef TIOCGATC
+ edchars.intr = cb.lchars.tc_intrc;
+ edchars.quit = cb.lchars.tc_quitc;
+ edchars.eof = cb.lchars.tc_eofc;
+ edchars.werase = cb.lchars.tc_werasc;
+ cb.lchars.tc_suspc = -1;
+ cb.lchars.tc_dsuspc = -1;
+ cb.lchars.tc_lnextc = -1;
+ cb.lchars.tc_statc = -1;
+ cb.lchars.tc_intrc = -1;
+ cb.lchars.tc_quitc = -1;
+ cb.lchars.tc_rprntc = -1;
+# else
+ edchars.intr = cb.tchars.t_intrc;
+ edchars.quit = cb.tchars.t_quitc;
+ edchars.eof = cb.tchars.t_eofc;
+ cb.tchars.t_intrc = -1;
+ cb.tchars.t_quitc = -1;
+# ifdef TIOCGLTC
+ edchars.werase = cb.ltchars.t_werasc;
+ cb.ltchars.t_suspc = -1;
+ cb.ltchars.t_dsuspc = -1;
+ cb.ltchars.t_lnextc = -1;
+ cb.ltchars.t_rprntc = -1;
+# endif
+# endif /* TIOCGATC */
+#endif /* HAVE_TERMIOS_H || HAVE_TERMIO_H */
+
+ set_tty(tty_fd, &cb, TF_WAIT);
+
+#ifdef __CYGWIN__
+ if (edchars.eof == '\0')
+ edchars.eof = '\4';
+#endif /* __CYGWIN__ */
+
+ /* Convert unset values to internal `unset' value */
+ if (edchars.erase == vdisable_c)
+ edchars.erase = -1;
+ if (edchars.kill == vdisable_c)
+ edchars.kill = -1;
+ if (edchars.intr == vdisable_c)
+ edchars.intr = -1;
+ if (edchars.quit == vdisable_c)
+ edchars.quit = -1;
+ if (edchars.eof == vdisable_c)
+ edchars.eof = -1;
+ if (edchars.werase == vdisable_c)
+ edchars.werase = -1;
+ if (memcmp(&edchars, &oldchars, sizeof(edchars)) != 0) {
+#ifdef EMACS
+ x_emacs_keys(&edchars);
+#endif
+ }
+ } else {
+ /* TF_WAIT doesn't seem to be necessary when leaving xmode */
+ set_tty(tty_fd, &tty_state, TF_NONE);
+ }
+
+ return prev;
+}
+
+/* NAME:
+ * promptlen - calculate the length of PS1 etc.
+ *
+ * DESCRIPTION:
+ * This function is based on a fix from guy@demon.co.uk
+ * It fixes a bug in that if PS1 contains '!', the length
+ * given by strlen() is probably wrong.
+ *
+ * RETURN VALUE:
+ * length
+ */
+int
+promptlen(cp, spp)
+ const char *cp;
+ const char **spp;
+{
+ int count = 0;
+ const char *sp = cp;
+ char delimiter = 0;
+ int indelimit = 0;
+
+ /* Undocumented AT&T ksh feature:
+ * If the second char in the prompt string is \r then the first char
+ * is taken to be a non-printing delimiter and any chars between two
+ * instances of the delimiter are not considered to be part of the
+ * prompt length
+ */
+ if (*cp && cp[1] == '\r') {
+ delimiter = *cp;
+ cp += 2;
+ }
+
+ for (; *cp; cp++) {
+ if (indelimit && *cp != delimiter)
+ ;
+ else if (*cp == '\n' || *cp == '\r') {
+ count = 0;
+ sp = cp + 1;
+ } else if (*cp == '\t') {
+ count = (count | 7) + 1;
+ } else if (*cp == '\b') {
+ if (count > 0)
+ count--;
+ } else if (*cp == delimiter)
+ indelimit = !indelimit;
+ else
+ count++;
+ }
+ if (spp)
+ *spp = sp;
+ return count;
+}
+
+void
+set_editmode(ed)
+ const char *ed;
+{
+ static const enum sh_flag edit_flags[] = {
+#ifdef EMACS
+ FEMACS, FGMACS,
+#endif
+#ifdef VI
+ FVI,
+#endif
+ };
+ char *rcp;
+ int i;
+
+ if ((rcp = ksh_strrchr_dirsep(ed)))
+ ed = ++rcp;
+ for (i = 0; i < NELEM(edit_flags); i++)
+ if (strstr(ed, options[(int) edit_flags[i]].name)) {
+ change_flag(edit_flags[i], OF_SPECIAL, 1);
+ return;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Misc common code for vi/emacs */
+
+/* Handle the commenting/uncommenting of a line.
+ * Returns:
+ * 1 if a carriage return is indicated (comment added)
+ * 0 if no return (comment removed)
+ * -1 if there is an error (not enough room for comment chars)
+ * If successful, *lenp contains the new length. Note: cursor should be
+ * moved to the start of the line after (un)commenting.
+ */
+int
+x_do_comment(buf, bsize, lenp)
+ char *buf;
+ int bsize;
+ int *lenp;
+{
+ int i, j;
+ int len = *lenp;
+
+ if (len == 0)
+ return 1; /* somewhat arbitrary - it's what at&t ksh does */
+
+ /* Already commented? */
+ if (buf[0] == '#') {
+ int saw_nl = 0;
+
+ for (j = 0, i = 1; i < len; i++) {
+ if (!saw_nl || buf[i] != '#')
+ buf[j++] = buf[i];
+ saw_nl = buf[i] == '\n';
+ }
+ *lenp = j;
+ return 0;
+ } else {
+ int n = 1;
+
+ /* See if there's room for the #'s - 1 per \n */
+ for (i = 0; i < len; i++)
+ if (buf[i] == '\n')
+ n++;
+ if (len + n >= bsize)
+ return -1;
+ /* Now add them... */
+ for (i = len, j = len + n; --i >= 0; ) {
+ if (buf[i] == '\n')
+ buf[--j] = '#';
+ buf[--j] = buf[i];
+ }
+ buf[0] = '#';
+ *lenp += n;
+ return 1;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Common file/command completion code for vi/emacs */
+
+
+static char *add_glob ARGS((const char *str, int slen));
+static void glob_table ARGS((const char *pat, XPtrV *wp, struct table *tp));
+static void glob_path ARGS((int flags, const char *pat, XPtrV *wp,
+ const char *path));
+
+#if 0 /* not used... */
+int x_complete_word ARGS((const char *str, int slen, int is_command,
+ int *multiple, char **ret));
+int
+x_complete_word(str, slen, is_command, nwordsp, ret)
+ const char *str;
+ int slen;
+ int is_command;
+ int *nwordsp;
+ char **ret;
+{
+ int nwords;
+ int prefix_len;
+ char **words;
+
+ nwords = (is_command ? x_command_glob : x_file_glob)(XCF_FULLPATH,
+ str, slen, &words);
+ *nwordsp = nwords;
+ if (nwords == 0) {
+ *ret = (char *) 0;
+ return -1;
+ }
+
+ prefix_len = x_longest_prefix(nwords, words);
+ *ret = str_nsave(words[0], prefix_len, ATEMP);
+ x_free_words(nwords, words);
+ return prefix_len;
+}
+#endif /* 0 */
+
+void
+x_print_expansions(nwords, words, is_command)
+ int nwords;
+ char *const *words;
+ int is_command;
+{
+ int use_copy = 0;
+ int prefix_len;
+ XPtrV l;
+
+ /* Check if all matches are in the same directory (in this
+ * case, we want to omitt the directory name)
+ */
+ if (!is_command
+ && (prefix_len = x_longest_prefix(nwords, words)) > 0)
+ {
+ int i;
+
+ /* Special case for 1 match (prefix is whole word) */
+ if (nwords == 1)
+ prefix_len = x_basename(words[0], (char *) 0);
+ /* Any (non-trailing) slashes in non-common word suffixes? */
+ for (i = 0; i < nwords; i++)
+ if (x_basename(words[i] + prefix_len, (char *) 0)
+ > prefix_len)
+ break;
+ /* All in same directory? */
+ if (i == nwords) {
+ while (prefix_len > 0
+ && !ISDIRSEP(words[0][prefix_len - 1]))
+ prefix_len--;
+ use_copy = 1;
+ XPinit(l, nwords + 1);
+ for (i = 0; i < nwords; i++)
+ XPput(l, words[i] + prefix_len);
+ XPput(l, (char *) 0);
+ }
+ }
+
+ /*
+ * Enumerate expansions
+ */
+ x_putc('\r');
+ x_putc('\n');
+ pr_menu(use_copy ? (char **) XPptrv(l) : words);
+
+ if (use_copy)
+ XPfree(l); /* not x_free_words() */
+}
+
+/*
+ * Do file globbing:
+ * - appends * to (copy of) str if no globbing chars found
+ * - does expansion, checks for no match, etc.
+ * - sets *wordsp to array of matching strings
+ * - returns number of matching strings
+ */
+static int
+x_file_glob(flags, str, slen, wordsp)
+ int flags;
+ const char *str;
+ int slen;
+ char ***wordsp;
+{
+ char *toglob;
+ char **words;
+ int nwords;
+ XPtrV w;
+ struct source *s, *sold;
+
+ if (slen < 0)
+ return 0;
+
+ toglob = add_glob(str, slen);
+
+ /*
+ * Convert "foo*" (toglob) to an array of strings (words)
+ */
+ sold = source;
+ s = pushs(SWSTR, ATEMP);
+ s->start = s->str = toglob;
+ source = s;
+ if (yylex(ONEWORD) != LWORD) {
+ source = sold;
+ internal_errorf(0, "fileglob: substitute error");
+ return 0;
+ }
+ source = sold;
+ XPinit(w, 32);
+ expand(yylval.cp, &w, DOGLOB|DOTILDE|DOMARKDIRS);
+ XPput(w, NULL);
+ words = (char **) XPclose(w);
+
+ for (nwords = 0; words[nwords]; nwords++)
+ ;
+ if (nwords == 1) {
+ struct stat statb;
+
+ /* Check if globbing failed (returned glob pattern),
+ * but be careful (E.g. toglob == "ab*" when the file
+ * "ab*" exists is not an error).
+ * Also, check for empty result - happens if we tried
+ * to glob something which evaluated to an empty
+ * string (e.g., "$FOO" when there is no FOO, etc).
+ */
+ if ((strcmp(words[0], toglob) == 0
+ && stat(words[0], &statb) < 0)
+ || words[0][0] == '\0')
+ {
+ x_free_words(nwords, words);
+ nwords = 0;
+ }
+ }
+ afree(toglob, ATEMP);
+
+ *wordsp = nwords ? words : (char **) 0;
+
+ return nwords;
+}
+
+/* Data structure used in x_command_glob() */
+struct path_order_info {
+ char *word;
+ int base;
+ int path_order;
+};
+
+/* Compare routine used in x_command_glob() */
+static int
+path_order_cmp(aa, bb)
+ const void *aa;
+ const void *bb;
+{
+ const struct path_order_info *a = (const struct path_order_info *) aa;
+ const struct path_order_info *b = (const struct path_order_info *) bb;
+ int t;
+
+ t = FILECMP(a->word + a->base, b->word + b->base);
+ return t ? t : a->path_order - b->path_order;
+}
+
+static int
+x_command_glob(flags, str, slen, wordsp)
+ int flags;
+ const char *str;
+ int slen;
+ char ***wordsp;
+{
+ char *toglob;
+ char *pat;
+ char *fpath;
+ int nwords;
+ XPtrV w;
+ struct block *l;
+
+ if (slen < 0)
+ return 0;
+
+ toglob = add_glob(str, slen);
+
+ /* Convert "foo*" (toglob) to a pattern for future use */
+ pat = evalstr(toglob, DOPAT|DOTILDE);
+ afree(toglob, ATEMP);
+
+ XPinit(w, 32);
+
+ glob_table(pat, &w, &keywords);
+ glob_table(pat, &w, &aliases);
+ glob_table(pat, &w, &builtins);
+ for (l = e->loc; l; l = l->next)
+ glob_table(pat, &w, &l->funs);
+
+ glob_path(flags, pat, &w, path);
+ if ((fpath = str_val(global("FPATH"))) != null)
+ glob_path(flags, pat, &w, fpath);
+
+ nwords = XPsize(w);
+
+ if (!nwords) {
+ *wordsp = (char **) 0;
+ XPfree(w);
+ return 0;
+ }
+
+ /* Sort entries */
+ if (flags & XCF_FULLPATH) {
+ /* Sort by basename, then path order */
+ struct path_order_info *info;
+ struct path_order_info *last_info = 0;
+ char **words = (char **) XPptrv(w);
+ int path_order = 0;
+ int i;
+
+ info = (struct path_order_info *)
+ alloc(sizeof(struct path_order_info) * nwords, ATEMP);
+ for (i = 0; i < nwords; i++) {
+ info[i].word = words[i];
+ info[i].base = x_basename(words[i], (char *) 0);
+ if (!last_info || info[i].base != last_info->base
+ || FILENCMP(words[i],
+ last_info->word, info[i].base) != 0)
+ {
+ last_info = &info[i];
+ path_order++;
+ }
+ info[i].path_order = path_order;
+ }
+ qsort(info, nwords, sizeof(struct path_order_info),
+ path_order_cmp);
+ for (i = 0; i < nwords; i++)
+ words[i] = info[i].word;
+ afree((void *) info, ATEMP);
+ } else {
+ /* Sort and remove duplicate entries */
+ char **words = (char **) XPptrv(w);
+ int i, j;
+
+ qsortp(XPptrv(w), (size_t) nwords, xstrcmp);
+
+ for (i = j = 0; i < nwords - 1; i++) {
+ if (strcmp(words[i], words[i + 1]))
+ words[j++] = words[i];
+ else
+ afree(words[i], ATEMP);
+ }
+ words[j++] = words[i];
+ nwords = j;
+ w.cur = (void **) &words[j];
+ }
+
+ XPput(w, NULL);
+ *wordsp = (char **) XPclose(w);
+
+ return nwords;
+}
+
+#define IS_WORDC(c) !(ctype(c, C_LEX1) || (c) == '\'' || (c) == '"')
+
+static int
+x_locate_word(buf, buflen, pos, startp, is_commandp)
+ const char *buf;
+ int buflen;
+ int pos;
+ int *startp;
+ int *is_commandp;
+{
+ int p;
+ int start, end;
+
+ /* Bad call? Probably should report error */
+ if (pos < 0 || pos > buflen) {
+ *startp = pos;
+ *is_commandp = 0;
+ return 0;
+ }
+ /* The case where pos == buflen happens to take care of itself... */
+
+ start = pos;
+ /* Keep going backwards to start of word (has effect of allowing
+ * one blank after the end of a word)
+ */
+ for (; start > 0 && IS_WORDC(buf[start - 1]); start--)
+ ;
+ /* Go forwards to end of word */
+ for (end = start; end < buflen && IS_WORDC(buf[end]); end++)
+ ;
+
+ if (is_commandp) {
+ int iscmd;
+
+ /* Figure out if this is a command */
+ for (p = start - 1; p >= 0 && isspace(buf[p]); p--)
+ ;
+ iscmd = p < 0 || strchr(";|&()", buf[p]);
+ if (iscmd) {
+ /* If command has a /, path, etc. is not searched;
+ * only current directory is searched, which is just
+ * like file globbing.
+ */
+ for (p = start; p < end; p++)
+ if (ISDIRSEP(buf[p]))
+ break;
+ iscmd = p == end;
+ }
+ *is_commandp = iscmd;
+ }
+
+ *startp = start;
+
+ return end - start;
+}
+
+int
+x_cf_glob(flags, buf, buflen, pos, startp, endp, wordsp, is_commandp)
+ int flags;
+ const char *buf;
+ int buflen;
+ int pos;
+ int *startp;
+ int *endp;
+ char ***wordsp;
+ int *is_commandp;
+{
+ int len;
+ int nwords;
+ char **words;
+ int is_command;
+
+ len = x_locate_word(buf, buflen, pos, startp, &is_command);
+ if (!(flags & XCF_COMMAND))
+ is_command = 0;
+ /* Don't do command globing on zero length strings - it takes too
+ * long and isn't very useful. File globs are more likely to be
+ * useful, so allow these.
+ */
+ if (len == 0 && is_command)
+ return 0;
+
+ nwords = (is_command ? x_command_glob : x_file_glob)(flags,
+ buf + *startp, len, &words);
+ if (nwords == 0) {
+ *wordsp = (char **) 0;
+ return 0;
+ }
+
+ if (is_commandp)
+ *is_commandp = is_command;
+ *wordsp = words;
+ *endp = *startp + len;
+
+ return nwords;
+}
+
+/* Given a string, copy it and possibly add a '*' to the end. The
+ * new string is returned.
+ */
+static char *
+add_glob(str, slen)
+ const char *str;
+ int slen;
+{
+ char *toglob;
+ char *s;
+ bool_t saw_slash = FALSE;
+
+ if (slen < 0)
+ return (char *) 0;
+
+ toglob = str_nsave(str, slen + 1, ATEMP); /* + 1 for "*" */
+ toglob[slen] = '\0';
+
+ /*
+ * If the pathname contains a wildcard (an unquoted '*',
+ * '?', or '[') or parameter expansion ('$'), or a ~username
+ * with no trailing slash, then it is globbed based on that
+ * value (i.e., without the appended '*').
+ */
+ for (s = toglob; *s; s++) {
+ if (*s == '\\' && s[1])
+ s++;
+ else if (*s == '*' || *s == '[' || *s == '?' || *s == '$'
+ || (s[1] == '(' /*)*/ && strchr("*+?@!", *s)))
+ break;
+ else if (ISDIRSEP(*s))
+ saw_slash = TRUE;
+ }
+ if (!*s && (*toglob != '~' || saw_slash)) {
+ toglob[slen] = '*';
+ toglob[slen + 1] = '\0';
+ }
+
+ return toglob;
+}
+
+/*
+ * Find longest common prefix
+ */
+int
+x_longest_prefix(nwords, words)
+ int nwords;
+ char *const *words;
+{
+ int i, j;
+ int prefix_len;
+ char *p;
+
+ if (nwords <= 0)
+ return 0;
+
+ prefix_len = strlen(words[0]);
+ for (i = 1; i < nwords; i++)
+ for (j = 0, p = words[i]; j < prefix_len; j++)
+ if (FILECHCONV(p[j]) != FILECHCONV(words[0][j])) {
+ prefix_len = j;
+ break;
+ }
+ return prefix_len;
+}
+
+void
+x_free_words(nwords, words)
+ int nwords;
+ char **words;
+{
+ int i;
+
+ for (i = 0; i < nwords; i++)
+ if (words[i])
+ afree(words[i], ATEMP);
+ afree(words, ATEMP);
+}
+
+/* Return the offset of the basename of string s (which ends at se - need not
+ * be null terminated). Trailing slashes are ignored. If s is just a slash,
+ * then the offset is 0 (actually, length - 1).
+ * s Return
+ * /etc 1
+ * /etc/ 1
+ * /etc// 1
+ * /etc/fo 5
+ * foo 0
+ * /// 2
+ * 0
+ */
+int
+x_basename(s, se)
+ const char *s;
+ const char *se;
+{
+ const char *p;
+
+ if (se == (char *) 0)
+ se = s + strlen(s);
+ if (s == se)
+ return 0;
+
+ /* Skip trailing slashes */
+ for (p = se - 1; p > s && ISDIRSEP(*p); p--)
+ ;
+ for (; p > s && !ISDIRSEP(*p); p--)
+ ;
+ if (ISDIRSEP(*p) && p + 1 < se)
+ p++;
+
+ return p - s;
+}
+
+/*
+ * Apply pattern matching to a table: all table entries that match a pattern
+ * are added to wp.
+ */
+static void
+glob_table(pat, wp, tp)
+ const char *pat;
+ XPtrV *wp;
+ struct table *tp;
+{
+ struct tstate ts;
+ struct tbl *te;
+
+ for (twalk(&ts, tp); (te = tnext(&ts)); ) {
+ if (gmatch(te->name, pat, FALSE))
+ XPput(*wp, str_save(te->name, ATEMP));
+ }
+}
+
+static void
+glob_path(flags, pat, wp, path)
+ int flags;
+ const char *pat;
+ XPtrV *wp;
+ const char *path;
+{
+ const char *sp, *p;
+ char *xp;
+ int pathlen;
+ int patlen;
+ int oldsize, newsize, i, j;
+ char **words;
+ XString xs;
+
+ patlen = strlen(pat) + 1;
+ sp = path;
+ Xinit(xs, xp, patlen + 128, ATEMP);
+ while (sp) {
+ xp = Xstring(xs, xp);
+ if (!(p = strchr(sp, PATHSEP)))
+ p = sp + strlen(sp);
+ pathlen = p - sp;
+ if (pathlen) {
+ /* Copy sp into xp, stuffing any MAGIC characters
+ * on the way
+ */
+ const char *s = sp;
+
+ XcheckN(xs, xp, pathlen * 2);
+ while (s < p) {
+ if (ISMAGIC(*s))
+ *xp++ = MAGIC;
+ *xp++ = *s++;
+ }
+ *xp++ = DIRSEP;
+ pathlen++;
+ }
+ sp = p;
+ XcheckN(xs, xp, patlen);
+ memcpy(xp, pat, patlen);
+
+ oldsize = XPsize(*wp);
+ glob_str(Xstring(xs, xp), wp, 0);
+ newsize = XPsize(*wp);
+
+ /* Check that each match is executable... */
+ words = (char **) XPptrv(*wp);
+ for (i = j = oldsize; i < newsize; i++) {
+ if (search_access(words[i], X_OK, (int *) 0) >= 0) {
+ words[j] = words[i];
+ if (!(flags & XCF_FULLPATH))
+ memmove(words[j], words[j] + pathlen,
+ strlen(words[j] + pathlen) + 1);
+ j++;
+ } else
+ afree(words[i], ATEMP);
+ }
+ wp->cur = (void **) &words[j];
+
+ if (!*sp++)
+ break;
+ }
+ Xfree(xs, xp);
+}
+
+#endif /* EDIT */
diff --git a/shells/pdksh/files/edit.h b/shells/pdksh/files/edit.h
new file mode 100644
index 00000000000..a55ac5e0749
--- /dev/null
+++ b/shells/pdksh/files/edit.h
@@ -0,0 +1,84 @@
+/* NAME:
+ * edit.h - globals for edit modes
+ *
+ * DESCRIPTION:
+ * This header defines various global edit objects.
+ *
+ * SEE ALSO:
+ *
+ *
+ * RCSid:
+ * $Id: edit.h,v 1.1.1.1 2008/05/23 17:15:17 tnn Exp $
+ *
+ */
+
+/* some useful #defines */
+#ifdef EXTERN
+# define I__(i) = i
+#else
+# define I__(i)
+# define EXTERN extern
+# define EXTERN_DEFINED
+#endif
+
+#define BEL 0x07
+
+/* tty driver characters we are interested in */
+typedef struct {
+ int erase;
+ int kill;
+ int werase;
+ int intr;
+ int quit;
+ int eof;
+} X_chars;
+
+EXTERN X_chars edchars;
+
+/* x_fc_glob() flags */
+#define XCF_COMMAND BIT(0) /* Do command completion */
+#define XCF_FILE BIT(1) /* Do file completion */
+#define XCF_FULLPATH BIT(2) /* command completion: store full path */
+#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
+
+/* edit.c */
+int x_getc ARGS((void));
+void x_flush ARGS((void));
+void x_putc ARGS((int c));
+void x_puts ARGS((const char *s));
+bool_t x_mode ARGS((bool_t onoff));
+int promptlen ARGS((const char *cp, const char **spp));
+int x_do_comment ARGS((char *buf, int bsize, int *lenp));
+void x_print_expansions ARGS((int nwords, char *const *words, int is_command));
+int x_cf_glob ARGS((int flags, const char *buf, int buflen, int pos, int *startp,
+ int *endp, char ***wordsp, int *is_commandp));
+int x_longest_prefix ARGS((int nwords, char *const *words));
+int x_basename ARGS((const char *s, const char *se));
+void x_free_words ARGS((int nwords, char **words));
+/* emacs.c */
+int x_emacs ARGS((char *buf, size_t len));
+void x_init_emacs ARGS((void));
+void x_emacs_keys ARGS((X_chars *ec));
+/* vi.c */
+int x_vi ARGS((char *buf, size_t len));
+
+
+#ifdef DEBUG
+# define D__(x) x
+#else
+# define D__(x)
+#endif
+
+/* This lot goes at the END */
+/* be sure not to interfere with anyone else's idea about EXTERN */
+#ifdef EXTERN_DEFINED
+# undef EXTERN_DEFINED
+# undef EXTERN
+#endif
+#undef I__
+/*
+ * Local Variables:
+ * version-control:t
+ * comment-column:40
+ * End:
+ */
diff --git a/shells/pdksh/files/emacs-gen.sh b/shells/pdksh/files/emacs-gen.sh
new file mode 100755
index 00000000000..c4a148e155e
--- /dev/null
+++ b/shells/pdksh/files/emacs-gen.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+case $# in
+1) file=$1;;
+*)
+ echo "$0: Usage: $0 path-to-emacs.c" 1>&2
+ exit 1
+esac;
+
+if [ ! -r "$file" ] ;then
+ echo "$0: can't read $file" 1>&2
+ exit 1
+fi
+
+cat << E_O_F || exit 1
+/*
+ * NOTE: THIS FILE WAS GENERATED AUTOMATICALLY FROM $file
+ *
+ * DO NOT BOTHER EDITING THIS FILE
+ */
+E_O_F
+
+# Pass 1: print out lines before @START-FUNC-TAB@
+# and generate defines and function declarations,
+sed -e '1,/@START-FUNC-TAB@/d' -e '/@END-FUNC-TAB@/,$d' < $file |
+ awk 'BEGIN { nfunc = 0; }
+ /^[ ]*#/ {
+ print $0;
+ next;
+ }
+ {
+ fname = $2;
+ c = substr(fname, length(fname), 1);
+ if (c == ",")
+ fname = substr(fname, 1, length(fname) - 1);
+ if (fname != "0") {
+ printf "#define XFUNC_%s %d\n", substr(fname, 3, length(fname) - 2), nfunc;
+ printf "static int %s ARGS((int c));\n", fname;
+ nfunc++;
+ }
+ }' || exit 1
+
+exit 0
diff --git a/shells/pdksh/files/emacs.c b/shells/pdksh/files/emacs.c
new file mode 100644
index 00000000000..68faf1a2e6c
--- /dev/null
+++ b/shells/pdksh/files/emacs.c
@@ -0,0 +1,2201 @@
+/*
+ * Emacs-like command line editing and history
+ *
+ * created by Ron Natalie at BRL
+ * modified by Doug Kingston, Doug Gwyn, and Lou Salkind
+ * adapted to PD ksh by Eric Gisin
+ */
+
+#include "config.h"
+#ifdef EMACS
+
+#include "sh.h"
+#include "ksh_stat.h"
+#include "ksh_dir.h"
+#include <ctype.h>
+#include "edit.h"
+
+static Area aedit;
+#define AEDIT &aedit /* area for kill ring and macro defns */
+
+#undef CTRL /* _BSD brain damage */
+#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
+#define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */
+
+
+/* values returned by keyboard functions */
+#define KSTD 0
+#define KEOL 1 /* ^M, ^J */
+#define KINTR 2 /* ^G, ^C */
+
+struct x_ftab {
+ int (*xf_func) ARGS((int c));
+ const char *xf_name;
+ short xf_flags;
+};
+
+/* index into struct x_ftab x_ftab[] - small is good */
+typedef unsigned char Findex;
+
+struct x_defbindings {
+ Findex xdb_func; /* XFUNC_* */
+ unsigned char xdb_tab;
+ unsigned char xdb_char;
+};
+
+#define XF_ARG 1 /* command takes number prefix */
+#define XF_NOBIND 2 /* not allowed to bind to function */
+#define XF_PREFIX 4 /* function sets prefix */
+
+/* Separator for completion */
+#define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'')
+#define is_mfs(c) (!(isalnum(c) || c == '_' || c == '$')) /* Separator for motion */
+
+#ifdef OS2
+ /* Deal with 8 bit chars & an extra prefix for function key (these two
+ * changes increase memory usage from 9,216 bytes to 24,416 bytes...)
+ */
+# define CHARMASK 0xFF /* 8-bit ASCII character mask */
+# define X_NTABS 4 /* normal, meta1, meta2, meta3 */
+static int x_prefix3 = 0xE0;
+#else /* OS2 */
+# define CHARMASK 0xFF /* 8-bit character mask */
+# define X_NTABS 3 /* normal, meta1, meta2 */
+#endif /* OS2 */
+#define X_TABSZ (CHARMASK+1) /* size of keydef tables etc */
+
+/* Arguments for do_complete()
+ * 0 = enumerate M-= complete as much as possible and then list
+ * 1 = complete M-Esc
+ * 2 = list M-?
+ */
+typedef enum { CT_LIST, /* list the possible completions */
+ CT_COMPLETE, /* complete to longest prefix */
+ CT_COMPLIST /* complete and then list (if non-exact) */
+ } Comp_type;
+
+/* { from 4.9 edit.h */
+/*
+ * The following are used for my horizontal scrolling stuff
+ */
+static char *xbuf; /* beg input buffer */
+static char *xend; /* end input buffer */
+static char *xcp; /* current position */
+static char *xep; /* current end */
+static char *xbp; /* start of visible portion of input buffer */
+static char *xlp; /* last char visible on screen */
+static int x_adj_ok;
+/*
+ * we use x_adj_done so that functions can tell
+ * whether x_adjust() has been called while they are active.
+ */
+static int x_adj_done;
+
+static int xx_cols;
+static int x_col;
+static int x_displen;
+static int x_arg; /* general purpose arg */
+static int x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */
+
+static int xlp_valid;
+/* end from 4.9 edit.h } */
+
+static int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
+static char **x_histp; /* history position */
+static int x_nextcmd; /* for newline-and-next */
+static char *xmp; /* mark pointer */
+static Findex x_last_command;
+static Findex (*x_tab)[X_TABSZ]; /* key definition */
+static char *(*x_atab)[X_TABSZ]; /* macro definitions */
+static unsigned char x_bound[(X_TABSZ * X_NTABS + 7) / 8];
+#define KILLSIZE 20
+static char *killstack[KILLSIZE];
+static int killsp, killtp;
+static int x_curprefix;
+static char *macroptr;
+static int prompt_skip;
+
+static int x_ins ARGS((char *cp));
+static void x_delete ARGS((int nc, int force_push));
+static int x_bword ARGS((void));
+static int x_fword ARGS((void));
+static void x_goto ARGS((char *cp));
+static void x_bs ARGS((int c));
+static int x_size_str ARGS((char *cp));
+static int x_size ARGS((int c));
+static void x_zots ARGS((char *str));
+static void x_zotc ARGS((int c));
+static void x_load_hist ARGS((char **hp));
+static int x_search ARGS((char *pat, int sameline, int offset));
+static int x_match ARGS((char *str, char *pat));
+static void x_redraw ARGS((int limit));
+static void x_push ARGS((int nchars));
+static char * x_mapin ARGS((const char *cp));
+static char * x_mapout ARGS((int c));
+static void x_print ARGS((int prefix, int key));
+static void x_adjust ARGS((void));
+static void x_e_ungetc ARGS((int c));
+static int x_e_getc ARGS((void));
+static void x_e_putc ARGS((int c));
+static void x_e_puts ARGS((const char *s));
+static int x_fold_case ARGS((int c));
+static char *x_lastcp ARGS((void));
+static void do_complete ARGS((int flags, Comp_type type));
+
+
+/* The lines between START-FUNC-TAB .. END-FUNC-TAB are run through a
+ * script (emacs-gen.sh) that generates emacs.out which contains:
+ * - function declarations for x_* functions
+ * - defines of the form XFUNC_<name> where <name> is function
+ * name, sans leading x_.
+ * Note that the script treats #ifdef and { 0, 0, 0} specially - use with
+ * caution.
+ */
+#include "emacs.out"
+static const struct x_ftab x_ftab[] = {
+/* @START-FUNC-TAB@ */
+ { x_abort, "abort", 0 },
+ { x_beg_hist, "beginning-of-history", 0 },
+ { x_comp_comm, "complete-command", 0 },
+ { x_comp_file, "complete-file", 0 },
+ { x_complete, "complete", 0 },
+ { x_del_back, "delete-char-backward", XF_ARG },
+ { x_del_bword, "delete-word-backward", XF_ARG },
+ { x_del_char, "delete-char-forward", XF_ARG },
+ { x_del_fword, "delete-word-forward", XF_ARG },
+ { x_del_line, "kill-line", 0 },
+ { x_draw_line, "redraw", 0 },
+ { x_end_hist, "end-of-history", 0 },
+ { x_end_of_text, "eot", 0 },
+ { x_enumerate, "list", 0 },
+ { x_eot_del, "eot-or-delete", XF_ARG },
+ { x_error, "error", 0 },
+ { x_goto_hist, "goto-history", XF_ARG },
+ { x_ins_string, "macro-string", XF_NOBIND },
+ { x_insert, "auto-insert", XF_ARG },
+ { x_kill, "kill-to-eol", XF_ARG },
+ { x_kill_region, "kill-region", 0 },
+ { x_list_comm, "list-command", 0 },
+ { x_list_file, "list-file", 0 },
+ { x_literal, "quote", 0 },
+ { x_meta1, "prefix-1", XF_PREFIX },
+ { x_meta2, "prefix-2", XF_PREFIX },
+ { x_meta_yank, "yank-pop", 0 },
+ { x_mv_back, "backward-char", XF_ARG },
+ { x_mv_begin, "beginning-of-line", 0 },
+ { x_mv_bword, "backward-word", XF_ARG },
+ { x_mv_end, "end-of-line", 0 },
+ { x_mv_forw, "forward-char", XF_ARG },
+ { x_mv_fword, "forward-word", XF_ARG },
+ { x_newline, "newline", 0 },
+ { x_next_com, "down-history", XF_ARG },
+ { x_nl_next_com, "newline-and-next", 0 },
+ { x_noop, "no-op", 0 },
+ { x_prev_com, "up-history", XF_ARG },
+ { x_prev_histword, "prev-hist-word", XF_ARG },
+ { x_search_char_forw, "search-character-forward", XF_ARG },
+ { x_search_char_back, "search-character-backward", XF_ARG },
+ { x_search_hist, "search-history", 0 },
+ { x_set_mark, "set-mark-command", 0 },
+ { x_stuff, "stuff", 0 },
+ { x_stuffreset, "stuff-reset", 0 },
+ { x_transpose, "transpose-chars", 0 },
+ { x_version, "version", 0 },
+ { x_xchg_point_mark, "exchange-point-and-mark", 0 },
+ { x_yank, "yank", 0 },
+ { x_comp_list, "complete-list", 0 },
+ { x_expand, "expand-file", 0 },
+ { x_fold_capitialize, "capitalize-word", XF_ARG },
+ { x_fold_lower, "downcase-word", XF_ARG },
+ { x_fold_upper, "upcase-word", XF_ARG },
+ { x_set_arg, "set-arg", XF_NOBIND },
+ { x_comment, "comment", 0 },
+#ifdef SILLY
+ { x_game_of_life, "play-game-of-life", 0 },
+#else
+ { 0, 0, 0 },
+#endif
+#ifdef DEBUG
+ { x_debug_info, "debug-info", 0 },
+#else
+ { 0, 0, 0 },
+#endif
+#ifdef OS2
+ { x_meta3, "prefix-3", XF_PREFIX },
+#else
+ { 0, 0, 0 },
+#endif
+/* @END-FUNC-TAB@ */
+ };
+
+static struct x_defbindings const x_defbindings[] = {
+ { XFUNC_del_back, 0, CTRL('?') },
+ { XFUNC_del_bword, 1, CTRL('?') },
+ { XFUNC_eot_del, 0, CTRL('D') },
+ { XFUNC_del_back, 0, CTRL('H') },
+ { XFUNC_del_bword, 1, CTRL('H') },
+ { XFUNC_del_bword, 1, 'h' },
+ { XFUNC_mv_bword, 1, 'b' },
+ { XFUNC_mv_fword, 1, 'f' },
+ { XFUNC_del_fword, 1, 'd' },
+ { XFUNC_mv_back, 0, CTRL('B') },
+ { XFUNC_mv_forw, 0, CTRL('F') },
+ { XFUNC_search_char_forw, 0, CTRL(']') },
+ { XFUNC_search_char_back, 1, CTRL(']') },
+ { XFUNC_newline, 0, CTRL('M') },
+ { XFUNC_newline, 0, CTRL('J') },
+ { XFUNC_end_of_text, 0, CTRL('_') },
+ { XFUNC_abort, 0, CTRL('G') },
+ { XFUNC_prev_com, 0, CTRL('P') },
+ { XFUNC_next_com, 0, CTRL('N') },
+ { XFUNC_nl_next_com, 0, CTRL('O') },
+ { XFUNC_search_hist, 0, CTRL('R') },
+ { XFUNC_beg_hist, 1, '<' },
+ { XFUNC_end_hist, 1, '>' },
+ { XFUNC_goto_hist, 1, 'g' },
+ { XFUNC_mv_end, 0, CTRL('E') },
+ { XFUNC_mv_begin, 0, CTRL('A') },
+ { XFUNC_draw_line, 0, CTRL('L') },
+ { XFUNC_meta1, 0, CTRL('[') },
+ { XFUNC_meta2, 0, CTRL('X') },
+ { XFUNC_kill, 0, CTRL('K') },
+ { XFUNC_yank, 0, CTRL('Y') },
+ { XFUNC_meta_yank, 1, 'y' },
+ { XFUNC_literal, 0, CTRL('^') },
+ { XFUNC_comment, 1, '#' },
+#if defined(BRL) && defined(TIOCSTI)
+ { XFUNC_stuff, 0, CTRL('T') },
+#else
+ { XFUNC_transpose, 0, CTRL('T') },
+#endif
+ { XFUNC_complete, 1, CTRL('[') },
+ { XFUNC_comp_list, 1, '=' },
+ { XFUNC_enumerate, 1, '?' },
+ { XFUNC_expand, 1, '*' },
+ { XFUNC_comp_file, 1, CTRL('X') },
+ { XFUNC_comp_comm, 2, CTRL('[') },
+ { XFUNC_list_comm, 2, '?' },
+ { XFUNC_list_file, 2, CTRL('Y') },
+ { XFUNC_set_mark, 1, ' ' },
+ { XFUNC_kill_region, 0, CTRL('W') },
+ { XFUNC_xchg_point_mark, 2, CTRL('X') },
+ { XFUNC_version, 0, CTRL('V') },
+#ifdef DEBUG
+ { XFUNC_debug_info, 1, CTRL('H') },
+#endif
+ { XFUNC_prev_histword, 1, '.' },
+ { XFUNC_prev_histword, 1, '_' },
+ { XFUNC_set_arg, 1, '0' },
+ { XFUNC_set_arg, 1, '1' },
+ { XFUNC_set_arg, 1, '2' },
+ { XFUNC_set_arg, 1, '3' },
+ { XFUNC_set_arg, 1, '4' },
+ { XFUNC_set_arg, 1, '5' },
+ { XFUNC_set_arg, 1, '6' },
+ { XFUNC_set_arg, 1, '7' },
+ { XFUNC_set_arg, 1, '8' },
+ { XFUNC_set_arg, 1, '9' },
+ { XFUNC_fold_upper, 1, 'U' },
+ { XFUNC_fold_upper, 1, 'u' },
+ { XFUNC_fold_lower, 1, 'L' },
+ { XFUNC_fold_lower, 1, 'l' },
+ { XFUNC_fold_capitialize, 1, 'C' },
+ { XFUNC_fold_capitialize, 1, 'c' },
+#ifdef OS2
+ { XFUNC_meta3, 0, 0xE0 },
+ { XFUNC_mv_back, 3, 'K' },
+ { XFUNC_mv_forw, 3, 'M' },
+ { XFUNC_next_com, 3, 'P' },
+ { XFUNC_prev_com, 3, 'H' },
+#endif /* OS2 */
+ /* These for ansi arrow keys: arguablely shouldn't be here by
+ * default, but its simpler/faster/smaller than using termcap
+ * entries.
+ */
+ { XFUNC_meta2, 1, '[' },
+ { XFUNC_prev_com, 2, 'A' },
+ { XFUNC_next_com, 2, 'B' },
+ { XFUNC_mv_forw, 2, 'C' },
+ { XFUNC_mv_back, 2, 'D' },
+};
+
+int
+x_emacs(buf, len)
+ char *buf;
+ size_t len;
+{
+ int c;
+ const char *p;
+ int i;
+ Findex f;
+
+ xbp = xbuf = buf; xend = buf + len;
+ xlp = xcp = xep = buf;
+ *xcp = 0;
+ xlp_valid = TRUE;
+ xmp = NULL;
+ x_curprefix = 0;
+ macroptr = (char *) 0;
+ x_histp = histptr + 1;
+ x_last_command = XFUNC_error;
+
+ xx_cols = x_cols;
+ x_col = promptlen(prompt, &p);
+ prompt_skip = p - prompt;
+ x_adj_ok = 1;
+ x_displen = xx_cols - 2 - x_col;
+ x_adj_done = 0;
+
+ pprompt(prompt, 0);
+
+ if (x_nextcmd >= 0) {
+ int off = source->line - x_nextcmd;
+ if (histptr - history >= off)
+ x_load_hist(histptr - off);
+ x_nextcmd = -1;
+ }
+
+ while (1) {
+ x_flush();
+ if ((c = x_e_getc()) < 0)
+ return 0;
+
+ f = x_curprefix == -1 ? XFUNC_insert
+ : x_tab[x_curprefix][c&CHARMASK];
+
+ if (!(x_ftab[f].xf_flags & XF_PREFIX)
+ && x_last_command != XFUNC_set_arg)
+ {
+ x_arg = 1;
+ x_arg_defaulted = 1;
+ }
+ i = c | (x_curprefix << 8);
+ x_curprefix = 0;
+ switch (i = (*x_ftab[f].xf_func)(i)) {
+ case KSTD:
+ if (!(x_ftab[f].xf_flags & XF_PREFIX))
+ x_last_command = f;
+ break;
+ case KEOL:
+ i = xep - xbuf;
+ return i;
+ case KINTR: /* special case for interrupt */
+ trapsig(SIGINT);
+ x_mode(FALSE);
+ unwind(LSHELL);
+ }
+ }
+}
+
+static int
+x_insert(c)
+ int c;
+{
+ char str[2];
+
+ /*
+ * Should allow tab and control chars.
+ */
+ if (c == 0) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ str[0] = c;
+ str[1] = '\0';
+ while (x_arg--)
+ x_ins(str);
+ return KSTD;
+}
+
+static int
+x_ins_string(c)
+ int c;
+{
+ if (macroptr) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ macroptr = x_atab[c>>8][c & CHARMASK];
+ if (macroptr && !*macroptr) {
+ /* XXX bell? */
+ macroptr = (char *) 0;
+ }
+ return KSTD;
+}
+
+static int
+x_do_ins(cp, len)
+ const char *cp;
+ int len;
+{
+ if (xep+len >= xend) {
+ x_e_putc(BEL);
+ return -1;
+ }
+
+ memmove(xcp+len, xcp, xep - xcp + 1);
+ memmove(xcp, cp, len);
+ xcp += len;
+ xep += len;
+ return 0;
+}
+
+static int
+x_ins(s)
+ char *s;
+{
+ char *cp = xcp;
+ register int adj = x_adj_done;
+
+ if (x_do_ins(s, strlen(s)) < 0)
+ return -1;
+ /*
+ * x_zots() may result in a call to x_adjust()
+ * we want xcp to reflect the new position.
+ */
+ xlp_valid = FALSE;
+ x_lastcp();
+ x_adj_ok = (xcp >= xlp);
+ x_zots(cp);
+ if (adj == x_adj_done) /* has x_adjust() been called? */
+ {
+ /* no */
+ for (cp = xlp; cp > xcp; )
+ x_bs(*--cp);
+ }
+
+ x_adj_ok = 1;
+ return 0;
+}
+
+static int
+x_del_back(c)
+ int c;
+{
+ int col = xcp - xbuf;
+
+ if (col == 0) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ if (x_arg > col)
+ x_arg = col;
+ x_goto(xcp - x_arg);
+ x_delete(x_arg, FALSE);
+ return KSTD;
+}
+
+static int
+x_del_char(c)
+ int c;
+{
+ int nleft = xep - xcp;
+
+ if (!nleft) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ if (x_arg > nleft)
+ x_arg = nleft;
+ x_delete(x_arg, FALSE);
+ return KSTD;
+}
+
+/* Delete nc chars to the right of the cursor (including cursor position) */
+static void
+x_delete(nc, force_push)
+ int nc;
+ int force_push;
+{
+ int i,j;
+ char *cp;
+
+ if (nc == 0)
+ return;
+ if (xmp != NULL && xmp > xcp) {
+ if (xcp + nc > xmp)
+ xmp = xcp;
+ else
+ xmp -= nc;
+ }
+
+ /*
+ * This lets us yank a word we have deleted.
+ */
+ if (nc > 1 || force_push)
+ x_push(nc);
+
+ xep -= nc;
+ cp = xcp;
+ j = 0;
+ i = nc;
+ while (i--) {
+ j += x_size(*cp++);
+ }
+ memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */
+ x_adj_ok = 0; /* don't redraw */
+ x_zots(xcp);
+ /*
+ * if we are already filling the line,
+ * there is no need to ' ','\b'.
+ * But if we must, make sure we do the minimum.
+ */
+ if ((i = xx_cols - 2 - x_col) > 0)
+ {
+ j = (j < i) ? j : i;
+ i = j;
+ while (i--)
+ x_e_putc(' ');
+ i = j;
+ while (i--)
+ x_e_putc('\b');
+ }
+ /*x_goto(xcp);*/
+ x_adj_ok = 1;
+ xlp_valid = FALSE;
+ for (cp = x_lastcp(); cp > xcp; )
+ x_bs(*--cp);
+
+ return;
+}
+
+static int
+x_del_bword(c)
+ int c;
+{
+ x_delete(x_bword(), FALSE);
+ return KSTD;
+}
+
+static int
+x_mv_bword(c)
+ int c;
+{
+ (void)x_bword();
+ return KSTD;
+}
+
+static int
+x_mv_fword(c)
+ int c;
+{
+ x_goto(xcp + x_fword());
+ return KSTD;
+}
+
+static int
+x_del_fword(c)
+ int c;
+{
+ x_delete(x_fword(), FALSE);
+ return KSTD;
+}
+
+static int
+x_bword()
+{
+ int nc = 0;
+ register char *cp = xcp;
+
+ if (cp == xbuf) {
+ x_e_putc(BEL);
+ return 0;
+ }
+ while (x_arg--)
+ {
+ while (cp != xbuf && is_mfs(cp[-1]))
+ {
+ cp--;
+ nc++;
+ }
+ while (cp != xbuf && !is_mfs(cp[-1]))
+ {
+ cp--;
+ nc++;
+ }
+ }
+ x_goto(cp);
+ return nc;
+}
+
+static int
+x_fword()
+{
+ int nc = 0;
+ register char *cp = xcp;
+
+ if (cp == xep) {
+ x_e_putc(BEL);
+ return 0;
+ }
+ while (x_arg--)
+ {
+ while (cp != xep && is_mfs(*cp))
+ {
+ cp++;
+ nc++;
+ }
+ while (cp != xep && !is_mfs(*cp))
+ {
+ cp++;
+ nc++;
+ }
+ }
+ return nc;
+}
+
+static void
+x_goto(cp)
+ register char *cp;
+{
+ if (cp < xbp || cp >= (xbp + x_displen))
+ {
+ /* we are heading off screen */
+ xcp = cp;
+ x_adjust();
+ }
+ else
+ {
+ if (cp < xcp) /* move back */
+ {
+ while (cp < xcp)
+ x_bs(*--xcp);
+ }
+ else
+ {
+ if (cp > xcp) /* move forward */
+ {
+ while (cp > xcp)
+ x_zotc(*xcp++);
+ }
+ }
+ }
+}
+
+static void
+x_bs(c)
+ int c;
+{
+ register int i;
+ i = x_size(c);
+ while (i--)
+ x_e_putc('\b');
+}
+
+static int
+x_size_str(cp)
+ register char *cp;
+{
+ register int size = 0;
+ while (*cp)
+ size += x_size(*cp++);
+ return size;
+}
+
+static int
+x_size(c)
+ int c;
+{
+ if (c=='\t')
+ return 4; /* Kludge, tabs are always four spaces. */
+ if (iscntrl(c)) /* control char */
+ return 2;
+ return 1;
+}
+
+static void
+x_zots(str)
+ register char *str;
+{
+ register int adj = x_adj_done;
+
+ x_lastcp();
+ while (*str && str < xlp && adj == x_adj_done)
+ x_zotc(*str++);
+}
+
+static void
+x_zotc(c)
+ int c;
+{
+ if (c == '\t') {
+ /* Kludge, tabs are always four spaces. */
+ x_e_puts(" ");
+ } else if (iscntrl(c)) {
+ x_e_putc('^');
+ x_e_putc(UNCTRL(c));
+ } else
+ x_e_putc(c);
+}
+
+static int
+x_mv_back(c)
+ int c;
+{
+ int col = xcp - xbuf;
+
+ if (col == 0) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ if (x_arg > col)
+ x_arg = col;
+ x_goto(xcp - x_arg);
+ return KSTD;
+}
+
+static int
+x_mv_forw(c)
+ int c;
+{
+ int nleft = xep - xcp;
+
+ if (!nleft) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ if (x_arg > nleft)
+ x_arg = nleft;
+ x_goto(xcp + x_arg);
+ return KSTD;
+}
+
+static int
+x_search_char_forw(c)
+ int c;
+{
+ char *cp = xcp;
+
+ *xep = '\0';
+ c = x_e_getc();
+ while (x_arg--) {
+ if (c < 0
+ || ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL
+ && (cp = strchr(xbuf, c)) == NULL))
+ {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ }
+ x_goto(cp);
+ return KSTD;
+}
+
+static int
+x_search_char_back(c)
+ int c;
+{
+ char *cp = xcp, *p;
+
+ c = x_e_getc();
+ for (; x_arg--; cp = p)
+ for (p = cp; ; ) {
+ if (p-- == xbuf)
+ p = xep;
+ if (c < 0 || p == cp) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ if (*p == c)
+ break;
+ }
+ x_goto(cp);
+ return KSTD;
+}
+
+static int
+x_newline(c)
+ int c;
+{
+ x_e_putc('\r');
+ x_e_putc('\n');
+ x_flush();
+ *xep++ = '\n';
+ return KEOL;
+}
+
+static int
+x_end_of_text(c)
+ int c;
+{
+ return KEOL;
+}
+
+static int x_beg_hist(c) int c; { x_load_hist(history); return KSTD;}
+
+static int x_end_hist(c) int c; { x_load_hist(histptr); return KSTD;}
+
+static int x_prev_com(c) int c; { x_load_hist(x_histp - x_arg); return KSTD;}
+
+static int x_next_com(c) int c; { x_load_hist(x_histp + x_arg); return KSTD;}
+
+/* Goto a particular history number obtained from argument.
+ * If no argument is given history 1 is probably not what you
+ * want so we'll simply go to the oldest one.
+ */
+static int
+x_goto_hist(c)
+ int c;
+{
+ if (x_arg_defaulted)
+ x_load_hist(history);
+ else
+ x_load_hist(histptr + x_arg - source->line);
+ return KSTD;
+}
+
+static void
+x_load_hist(hp)
+ register char **hp;
+{
+ int oldsize;
+
+ if (hp < history || hp > histptr) {
+ x_e_putc(BEL);
+ return;
+ }
+ x_histp = hp;
+ oldsize = x_size_str(xbuf);
+ (void)strcpy(xbuf, *hp);
+ xbp = xbuf;
+ xep = xcp = xbuf + strlen(*hp);
+ xlp_valid = FALSE;
+ if (xep > x_lastcp())
+ x_goto(xep);
+ else
+ x_redraw(oldsize);
+}
+
+static int
+x_nl_next_com(c)
+ int c;
+{
+ x_nextcmd = source->line - (histptr - x_histp) + 1;
+ return (x_newline(c));
+}
+
+static int
+x_eot_del(c)
+ int c;
+{
+ if (xep == xbuf && x_arg_defaulted)
+ return (x_end_of_text(c));
+ else
+ return (x_del_char(c));
+}
+
+/* reverse incremental history search */
+static int
+x_search_hist(c)
+ int c;
+{
+ int offset = -1; /* offset of match in xbuf, else -1 */
+ char pat [256+1]; /* pattern buffer */
+ register char *p = pat;
+ Findex f;
+
+ *p = '\0';
+ while (1) {
+ if (offset < 0) {
+ x_e_puts("\nI-search: ");
+ x_e_puts(pat);
+ }
+ x_flush();
+ if ((c = x_e_getc()) < 0)
+ return KSTD;
+ f = x_tab[0][c&CHARMASK];
+ if (c == CTRL('['))
+ break;
+ else if (f == XFUNC_search_hist)
+ offset = x_search(pat, 0, offset);
+ else if (f == XFUNC_del_back) {
+ if (p == pat) {
+ offset = -1;
+ break;
+ }
+ if (p > pat)
+ *--p = '\0';
+ if (p == pat)
+ offset = -1;
+ else
+ offset = x_search(pat, 1, offset);
+ continue;
+ } else if (f == XFUNC_insert) {
+ /* add char to pattern */
+ /* overflow check... */
+ if (p >= &pat[sizeof(pat) - 1]) {
+ x_e_putc(BEL);
+ continue;
+ }
+ *p++ = c, *p = '\0';
+ if (offset >= 0) {
+ /* already have partial match */
+ offset = x_match(xbuf, pat);
+ if (offset >= 0) {
+ x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
+ continue;
+ }
+ }
+ offset = x_search(pat, 0, offset);
+ } else { /* other command */
+ x_e_ungetc(c);
+ break;
+ }
+ }
+ if (offset < 0)
+ x_redraw(-1);
+ return KSTD;
+}
+
+/* search backward from current line */
+static int
+x_search(pat, sameline, offset)
+ char *pat;
+ int sameline;
+ int offset;
+{
+ register char **hp;
+ int i;
+
+ for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
+ i = x_match(*hp, pat);
+ if (i >= 0) {
+ if (offset < 0)
+ x_e_putc('\n');
+ x_load_hist(hp);
+ x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
+ return i;
+ }
+ }
+ x_e_putc(BEL);
+ x_histp = histptr;
+ return -1;
+}
+
+/* return position of first match of pattern in string, else -1 */
+static int
+x_match(str, pat)
+ char *str, *pat;
+{
+ if (*pat == '^') {
+ return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
+ } else {
+ char *q = strstr(str, pat);
+ return (q == NULL) ? -1 : q - str;
+ }
+}
+
+static int
+x_del_line(c)
+ int c;
+{
+ int i, j;
+
+ *xep = 0;
+ i = xep- xbuf;
+ j = x_size_str(xbuf);
+ xcp = xbuf;
+ x_push(i);
+ xlp = xbp = xep = xbuf;
+ xlp_valid = TRUE;
+ *xcp = 0;
+ xmp = NULL;
+ x_redraw(j);
+ return KSTD;
+}
+
+static int
+x_mv_end(c)
+ int c;
+{
+ x_goto(xep);
+ return KSTD;
+}
+
+static int
+x_mv_begin(c)
+ int c;
+{
+ x_goto(xbuf);
+ return KSTD;
+}
+
+static int
+x_draw_line(c)
+ int c;
+{
+ x_redraw(-1);
+ return KSTD;
+
+}
+
+/* Redraw (part of) the line. If limit is < 0, the everything is redrawn
+ * on a NEW line, otherwise limit is the screen column up to which needs
+ * redrawing.
+ */
+static void
+x_redraw(limit)
+ int limit;
+{
+ int i, j;
+ char *cp;
+
+ x_adj_ok = 0;
+ if (limit == -1)
+ x_e_putc('\n');
+ else
+ x_e_putc('\r');
+ x_flush();
+ if (xbp == xbuf)
+ {
+ pprompt(prompt + prompt_skip, 0);
+ x_col = promptlen(prompt, (const char **) 0);
+ }
+ x_displen = xx_cols - 2 - x_col;
+ xlp_valid = FALSE;
+ cp = x_lastcp();
+ x_zots(xbp);
+ if (xbp != xbuf || xep > xlp)
+ limit = xx_cols;
+ if (limit >= 0)
+ {
+ if (xep > xlp)
+ i = 0; /* we fill the line */
+ else
+ i = limit - (xlp - xbp);
+
+ for (j = 0; j < i && x_col < (xx_cols - 2); j++)
+ x_e_putc(' ');
+ i = ' ';
+ if (xep > xlp) /* more off screen */
+ {
+ if (xbp > xbuf)
+ i = '*';
+ else
+ i = '>';
+ }
+ else
+ if (xbp > xbuf)
+ i = '<';
+ x_e_putc(i);
+ j++;
+ while (j--)
+ x_e_putc('\b');
+ }
+ for (cp = xlp; cp > xcp; )
+ x_bs(*--cp);
+ x_adj_ok = 1;
+ D__(x_flush();)
+ return;
+}
+
+static int
+x_transpose(c)
+ int c;
+{
+ char tmp;
+
+ /* What transpose is meant to do seems to be up for debate. This
+ * is a general summary of the options; the text is abcd with the
+ * upper case character or underscore indicating the cursor positiion:
+ * Who Before After Before After
+ * at&t ksh in emacs mode: abCd abdC abcd_ (bell)
+ * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_
+ * gnu emacs: abCd acbD abcd_ abdc_
+ * Pdksh currently goes with GNU behavior since I believe this is the
+ * most common version of emacs, unless in gmacs mode, in which case
+ * it does the at&t ksh gmacs mdoe.
+ * This should really be broken up into 3 functions so users can bind
+ * to the one they want.
+ */
+ if (xcp == xbuf) {
+ x_e_putc(BEL);
+ return KSTD;
+ } else if (xcp == xep || Flag(FGMACS)) {
+ if (xcp - xbuf == 1) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ /* Gosling/Unipress emacs style: Swap two characters before the
+ * cursor, do not change cursor position
+ */
+ x_bs(xcp[-1]);
+ x_bs(xcp[-2]);
+ x_zotc(xcp[-1]);
+ x_zotc(xcp[-2]);
+ tmp = xcp[-1];
+ xcp[-1] = xcp[-2];
+ xcp[-2] = tmp;
+ } else {
+ /* GNU emacs style: Swap the characters before and under the
+ * cursor, move cursor position along one.
+ */
+ x_bs(xcp[-1]);
+ x_zotc(xcp[0]);
+ x_zotc(xcp[-1]);
+ tmp = xcp[-1];
+ xcp[-1] = xcp[0];
+ xcp[0] = tmp;
+ x_bs(xcp[0]);
+ x_goto(xcp + 1);
+ }
+ return KSTD;
+}
+
+static int
+x_literal(c)
+ int c;
+{
+ x_curprefix = -1;
+ return KSTD;
+}
+
+static int
+x_meta1(c)
+ int c;
+{
+ x_curprefix = 1;
+ return KSTD;
+}
+
+static int
+x_meta2(c)
+ int c;
+{
+ x_curprefix = 2;
+ return KSTD;
+}
+
+#ifdef OS2
+static int
+x_meta3(c)
+ int c;
+{
+ x_curprefix = 3;
+ return KSTD;
+}
+#endif /* OS2 */
+
+static int
+x_kill(c)
+ int c;
+{
+ int col = xcp - xbuf;
+ int lastcol = xep - xbuf;
+ int ndel;
+
+ if (x_arg_defaulted)
+ x_arg = lastcol;
+ else if (x_arg > lastcol)
+ x_arg = lastcol;
+ ndel = x_arg - col;
+ if (ndel < 0) {
+ x_goto(xbuf + x_arg);
+ ndel = -ndel;
+ }
+ x_delete(ndel, TRUE);
+ return KSTD;
+}
+
+static void
+x_push(nchars)
+ int nchars;
+{
+ char *cp = str_nsave(xcp, nchars, AEDIT);
+ if (killstack[killsp])
+ afree((void *)killstack[killsp], AEDIT);
+ killstack[killsp] = cp;
+ killsp = (killsp + 1) % KILLSIZE;
+}
+
+static int
+x_yank(c)
+ int c;
+{
+ if (killsp == 0)
+ killtp = KILLSIZE;
+ else
+ killtp = killsp;
+ killtp --;
+ if (killstack[killtp] == 0) {
+ x_e_puts("\nnothing to yank");
+ x_redraw(-1);
+ return KSTD;
+ }
+ xmp = xcp;
+ x_ins(killstack[killtp]);
+ return KSTD;
+}
+
+static int
+x_meta_yank(c)
+ int c;
+{
+ int len;
+ if (x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) {
+ x_e_puts("\nyank something first");
+ x_redraw(-1);
+ return KSTD;
+ }
+ len = strlen(killstack[killtp]);
+ x_goto(xcp - len);
+ x_delete(len, FALSE);
+ do {
+ if (killtp == 0)
+ killtp = KILLSIZE - 1;
+ else
+ killtp--;
+ } while (killstack[killtp] == 0);
+ x_ins(killstack[killtp]);
+ return KSTD;
+}
+
+static int
+x_abort(c)
+ int c;
+{
+ /* x_zotc(c); */
+ xlp = xep = xcp = xbp = xbuf;
+ xlp_valid = TRUE;
+ *xcp = 0;
+ return KINTR;
+}
+
+static int
+x_error(c)
+ int c;
+{
+ x_e_putc(BEL);
+ return KSTD;
+}
+
+static int
+x_stuffreset(c)
+ int c;
+{
+#ifdef TIOCSTI
+ (void)x_stuff(c);
+ return KINTR;
+#else
+ x_zotc(c);
+ xlp = xcp = xep = xbp = xbuf;
+ xlp_valid = TRUE;
+ *xcp = 0;
+ x_redraw(-1);
+ return KSTD;
+#endif
+}
+
+static int
+x_stuff(c)
+ int c;
+{
+#if 0 || defined TIOCSTI
+ char ch = c;
+ bool_t savmode = x_mode(FALSE);
+
+ (void)ioctl(TTY, TIOCSTI, &ch);
+ (void)x_mode(savmode);
+ x_redraw(-1);
+#endif
+ return KSTD;
+}
+
+static char *
+x_mapin(cp)
+ const char *cp;
+{
+ char *new, *op;
+
+ op = new = str_save(cp, ATEMP);
+ while (*cp) {
+ /* XXX -- should handle \^ escape? */
+ if (*cp == '^') {
+ cp++;
+#ifdef OS2
+ if (*cp == '0') /* To define function keys */
+ *op++ = 0xE0;
+ else
+#endif /* OS2 */
+ if (*cp >= '?') /* includes '?'; ASCII */
+ *op++ = CTRL(*cp);
+ else {
+ *op++ = '^';
+ cp--;
+ }
+ } else
+ *op++ = *cp;
+ cp++;
+ }
+ *op = '\0';
+
+ return new;
+}
+
+static char *
+x_mapout(c)
+ int c;
+{
+ static char buf[8];
+ register char *p = buf;
+
+#ifdef OS2
+ if (c == 0xE0) {
+ *p++ = '^';
+ *p++ = '0';
+ } else
+#endif /* OS2 */
+ if (iscntrl(c)) {
+ *p++ = '^';
+ *p++ = UNCTRL(c);
+ } else
+ *p++ = c;
+ *p = 0;
+ return buf;
+}
+
+static void
+x_print(prefix, key)
+ int prefix, key;
+{
+ if (prefix == 1)
+ shprintf("%s", x_mapout(x_prefix1));
+ if (prefix == 2)
+ shprintf("%s", x_mapout(x_prefix2));
+#ifdef OS2
+ if (prefix == 3)
+ shprintf("%s", x_mapout(x_prefix3));
+#endif /* OS2 */
+ shprintf("%s = ", x_mapout(key));
+ if (x_tab[prefix][key] != XFUNC_ins_string)
+ shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name);
+ else
+ shprintf("'%s'\n", x_atab[prefix][key]);
+}
+
+int
+x_bind(a1, a2, macro, list)
+ const char *a1, *a2;
+ int macro; /* bind -m */
+ int list; /* bind -l */
+{
+ Findex f;
+ int prefix, key;
+ char *sp = NULL;
+ char *m1, *m2;
+
+ if (x_tab == NULL) {
+ bi_errorf("cannot bind, not a tty");
+ return 1;
+ }
+
+ /* List function names */
+ if (list) {
+ for (f = 0; f < NELEM(x_ftab); f++)
+ if (x_ftab[f].xf_name
+ && !(x_ftab[f].xf_flags & XF_NOBIND))
+ shprintf("%s\n", x_ftab[f].xf_name);
+ return 0;
+ }
+
+ if (a1 == NULL) {
+ for (prefix = 0; prefix < X_NTABS; prefix++)
+ for (key = 0; key < X_TABSZ; key++) {
+ f = x_tab[prefix][key];
+ if (f == XFUNC_insert || f == XFUNC_error
+ || (macro && f != XFUNC_ins_string))
+ continue;
+ x_print(prefix, key);
+ }
+ return 0;
+ }
+
+ m1 = x_mapin(a1);
+ prefix = key = 0;
+ for (;; m1++) {
+ key = *m1 & CHARMASK;
+ if (x_tab[prefix][key] == XFUNC_meta1)
+ prefix = 1;
+ else if (x_tab[prefix][key] == XFUNC_meta2)
+ prefix = 2;
+#ifdef OS2
+ else if (x_tab[prefix][key] == XFUNC_meta3)
+ prefix = 3;
+#endif /* OS2 */
+ else
+ break;
+ }
+
+ if (a2 == NULL) {
+ x_print(prefix, key);
+ return 0;
+ }
+
+ if (*a2 == 0)
+ f = XFUNC_insert;
+ else if (!macro) {
+ for (f = 0; f < NELEM(x_ftab); f++)
+ if (x_ftab[f].xf_name
+ && strcmp(x_ftab[f].xf_name, a2) == 0)
+ break;
+ if (f == NELEM(x_ftab) || x_ftab[f].xf_flags & XF_NOBIND) {
+ bi_errorf("%s: no such function", a2);
+ return 1;
+ }
+#if 0 /* This breaks the bind commands that map arrow keys */
+ if (f == XFUNC_meta1)
+ x_prefix1 = key;
+ if (f == XFUNC_meta2)
+ x_prefix2 = key;
+#endif /* 0 */
+ } else {
+ f = XFUNC_ins_string;
+ m2 = x_mapin(a2);
+ sp = str_save(m2, AEDIT);
+ }
+
+ if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key])
+ afree((void *)x_atab[prefix][key], AEDIT);
+ x_tab[prefix][key] = f;
+ x_atab[prefix][key] = sp;
+
+ /* Track what the user has bound so x_emacs_keys() won't toast things */
+ if (f == XFUNC_insert)
+ x_bound[(prefix * X_TABSZ + key) / 8] &=
+ ~(1 << ((prefix * X_TABSZ + key) % 8));
+ else
+ x_bound[(prefix * X_TABSZ + key) / 8] |=
+ (1 << ((prefix * X_TABSZ + key) % 8));
+
+ return 0;
+}
+
+void
+x_init_emacs()
+{
+ register int i, j;
+
+ ainit(AEDIT);
+ x_nextcmd = -1;
+
+ x_tab = (Findex (*)[X_TABSZ]) alloc(sizeofN(*x_tab, X_NTABS), AEDIT);
+ for (j = 0; j < X_TABSZ; j++)
+ x_tab[0][j] = XFUNC_insert;
+ for (i = 1; i < X_NTABS; i++)
+ for (j = 0; j < X_TABSZ; j++)
+ x_tab[i][j] = XFUNC_error;
+ for (i = 0; i < NELEM(x_defbindings); i++)
+ x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
+ = x_defbindings[i].xdb_func;
+
+ x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT);
+ for (i = 1; i < X_NTABS; i++)
+ for (j = 0; j < X_TABSZ; j++)
+ x_atab[i][j] = NULL;
+}
+
+static void
+bind_if_not_bound(p, k, func)
+ int p, k;
+ int func;
+{
+ /* Has user already bound this key? If so, don't override it */
+ if (x_bound[((p) * X_TABSZ + (k)) / 8]
+ & (1 << (((p) * X_TABSZ + (k)) % 8)))
+ return;
+
+ x_tab[p][k] = func;
+}
+
+void
+x_emacs_keys(ec)
+ X_chars *ec;
+{
+ if (ec->erase >= 0) {
+ bind_if_not_bound(0, ec->erase, XFUNC_del_back);
+ bind_if_not_bound(1, ec->erase, XFUNC_del_bword);
+ }
+ if (ec->kill >= 0)
+ bind_if_not_bound(0, ec->kill, XFUNC_del_line);
+ if (ec->werase >= 0)
+ bind_if_not_bound(0, ec->werase, XFUNC_del_bword);
+ if (ec->intr >= 0)
+ bind_if_not_bound(0, ec->intr, XFUNC_abort);
+ if (ec->quit >= 0)
+ bind_if_not_bound(0, ec->quit, XFUNC_noop);
+}
+
+static int
+x_set_mark(c)
+ int c;
+{
+ xmp = xcp;
+ return KSTD;
+}
+
+static int
+x_kill_region(c)
+ int c;
+{
+ int rsize;
+ char *xr;
+
+ if (xmp == NULL) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ if (xmp > xcp) {
+ rsize = xmp - xcp;
+ xr = xcp;
+ } else {
+ rsize = xcp - xmp;
+ xr = xmp;
+ }
+ x_goto(xr);
+ x_delete(rsize, TRUE);
+ xmp = xr;
+ return KSTD;
+}
+
+static int
+x_xchg_point_mark(c)
+ int c;
+{
+ char *tmp;
+
+ if (xmp == NULL) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ tmp = xmp;
+ xmp = xcp;
+ x_goto( tmp );
+ return KSTD;
+}
+
+static int
+x_version(c)
+ int c;
+{
+ char *o_xbuf = xbuf, *o_xend = xend;
+ char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
+ int lim = x_lastcp() - xbp;
+
+ xbuf = xbp = xcp = (char *) ksh_version + 4;
+ xend = xep = (char *) ksh_version + 4 + strlen(ksh_version + 4);
+ x_redraw(lim);
+ x_flush();
+
+ c = x_e_getc();
+ xbuf = o_xbuf;
+ xend = o_xend;
+ xbp = o_xbp;
+ xep = o_xep;
+ xcp = o_xcp;
+ x_redraw(strlen(ksh_version));
+
+ if (c < 0)
+ return KSTD;
+ /* This is what at&t ksh seems to do... Very bizarre */
+ if (c != ' ')
+ x_e_ungetc(c);
+
+ return KSTD;
+}
+
+static int
+x_noop(c)
+ int c;
+{
+ return KSTD;
+}
+
+#ifdef SILLY
+static int
+x_game_of_life(c)
+ int c;
+{
+ char newbuf [256+1];
+ register char *ip, *op;
+ int i, len;
+
+ i = xep - xbuf;
+ *xep = 0;
+ len = x_size_str(xbuf);
+ xcp = xbp = xbuf;
+ memmove(newbuf+1, xbuf, i);
+ newbuf[0] = 'A';
+ newbuf[i] = 'A';
+ for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) {
+ /* Empty space */
+ if (*ip < '@' || *ip == '_' || *ip == 0x7F) {
+ /* Two adults, make whoopee */
+ if (ip[-1] < '_' && ip[1] < '_') {
+ /* Make kid look like parents. */
+ *op = '`' + ((ip[-1] + ip[1])/2)%32;
+ if (*op == 0x7F) /* Birth defect */
+ *op = '`';
+ }
+ else
+ *op = ' '; /* nothing happens */
+ continue;
+ }
+ /* Child */
+ if (*ip > '`') {
+ /* All alone, dies */
+ if (ip[-1] == ' ' && ip[1] == ' ')
+ *op = ' ';
+ else /* Gets older */
+ *op = *ip-'`'+'@';
+ continue;
+ }
+ /* Adult */
+ /* Overcrowded, dies */
+ if (ip[-1] >= '@' && ip[1] >= '@') {
+ *op = ' ';
+ continue;
+ }
+ *op = *ip;
+ }
+ *op = 0;
+ x_redraw(len);
+ return KSTD;
+}
+#endif
+
+/*
+ * File/command name completion routines
+ */
+
+
+static int
+x_comp_comm(c)
+ int c;
+{
+ do_complete(XCF_COMMAND, CT_COMPLETE);
+ return KSTD;
+}
+static int
+x_list_comm(c)
+ int c;
+{
+ do_complete(XCF_COMMAND, CT_LIST);
+ return KSTD;
+}
+static int
+x_complete(c)
+ int c;
+{
+ do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
+ return KSTD;
+}
+static int
+x_enumerate(c)
+ int c;
+{
+ do_complete(XCF_COMMAND_FILE, CT_LIST);
+ return KSTD;
+}
+static int
+x_comp_file(c)
+ int c;
+{
+ do_complete(XCF_FILE, CT_COMPLETE);
+ return KSTD;
+}
+static int
+x_list_file(c)
+ int c;
+{
+ do_complete(XCF_FILE, CT_LIST);
+ return KSTD;
+}
+static int
+x_comp_list(c)
+ int c;
+{
+ do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
+ return KSTD;
+}
+static int
+x_expand(c)
+ int c;
+{
+ char **words;
+ int nwords = 0;
+ int start, end;
+ int is_command;
+ int i;
+
+ nwords = x_cf_glob(XCF_FILE,
+ xbuf, xep - xbuf, xcp - xbuf,
+ &start, &end, &words, &is_command);
+
+ if (nwords == 0) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+
+ x_goto(xbuf + start);
+ x_delete(end - start, FALSE);
+ for (i = 0; i < nwords; i++)
+ if (x_ins(words[i]) < 0 || (i < nwords - 1 && x_ins(space) < 0))
+ {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+
+ return KSTD;
+}
+
+/* type == 0 for list, 1 for complete and 2 for complete-list */
+static void
+do_complete(flags, type)
+ int flags; /* XCF_{COMMAND,FILE,COMMAND_FILE} */
+ Comp_type type;
+{
+ char **words;
+ int nwords = 0;
+ int start, end;
+ int is_command;
+ int do_glob = 1;
+ Comp_type t = type;
+ char *comp_word = (char *) 0;
+
+ if (type == CT_COMPLIST) {
+ do_glob = 0;
+ /* decide what we will do */
+ nwords = x_cf_glob(flags,
+ xbuf, xep - xbuf, xcp - xbuf,
+ &start, &end, &words, &is_command);
+ if (nwords > 0) {
+ if (nwords > 1) {
+ int len = x_longest_prefix(nwords, words);
+
+ t = CT_LIST;
+ /* Do completion if prefix matches original
+ * prefix (ie, no globbing chars), otherwise
+ * don't bother
+ */
+ if (strncmp(words[0], xbuf + start, end - start)
+ == 0)
+ comp_word = str_nsave(words[0], len,
+ ATEMP);
+ else
+ type = CT_LIST;
+ /* Redo globing to show full paths if this
+ * is a command.
+ */
+ if (is_command) {
+ do_glob = 1;
+ x_free_words(nwords, words);
+ }
+ } else
+ type = t = CT_COMPLETE;
+ }
+ }
+ if (do_glob)
+ nwords = x_cf_glob(flags | (t == CT_LIST ? XCF_FULLPATH : 0),
+ xbuf, xep - xbuf, xcp - xbuf,
+ &start, &end, &words, &is_command);
+ if (nwords == 0) {
+ x_e_putc(BEL);
+ return;
+ }
+ switch (type) {
+ case CT_LIST:
+ x_print_expansions(nwords, words, is_command);
+ x_redraw(0);
+ break;
+
+ case CT_COMPLIST:
+ /* Only get here if nwords > 1 && comp_word is set */
+ {
+ int olen = end - start;
+ int nlen = strlen(comp_word);
+
+ x_print_expansions(nwords, words, is_command);
+ xcp = xbuf + end;
+ x_do_ins(comp_word + olen, nlen - olen);
+ x_redraw(0);
+ }
+ break;
+
+ case CT_COMPLETE:
+ {
+ int nlen = x_longest_prefix(nwords, words);
+
+ if (nlen > 0) {
+ x_goto(xbuf + start);
+ x_delete(end - start, FALSE);
+ words[0][nlen] = '\0';
+ x_ins(words[0]);
+ /* If single match is not a directory, add a
+ * space to the end...
+ */
+ if (nwords == 1
+ && !ISDIRSEP(words[0][nlen - 1]))
+ x_ins(space);
+ } else
+ x_e_putc(BEL);
+ }
+ break;
+ }
+}
+
+/* NAME:
+ * x_adjust - redraw the line adjusting starting point etc.
+ *
+ * DESCRIPTION:
+ * This function is called when we have exceeded the bounds
+ * of the edit window. It increments x_adj_done so that
+ * functions like x_ins and x_delete know that we have been
+ * called and can skip the x_bs() stuff which has already
+ * been done by x_redraw.
+ *
+ * RETURN VALUE:
+ * None
+ */
+
+static void
+x_adjust()
+{
+ x_adj_done++; /* flag the fact that we were called. */
+ /*
+ * we had a problem if the prompt length > xx_cols / 2
+ */
+ if ((xbp = xcp - (x_displen / 2)) < xbuf)
+ xbp = xbuf;
+ xlp_valid = FALSE;
+ x_redraw(xx_cols);
+ x_flush();
+}
+
+static int unget_char = -1;
+
+static void
+x_e_ungetc(c)
+ int c;
+{
+ unget_char = c;
+}
+
+static int
+x_e_getc()
+{
+ int c;
+
+ if (unget_char >= 0) {
+ c = unget_char;
+ unget_char = -1;
+ } else {
+ if (macroptr) {
+ c = *macroptr++;
+ if (!*macroptr)
+ macroptr = (char *) 0;
+ } else
+ c = x_getc();
+ }
+
+ return c <= CHARMASK ? c : (c & CHARMASK);
+}
+
+static void
+x_e_putc(c)
+ int c;
+{
+ if (c == '\r' || c == '\n')
+ x_col = 0;
+ if (x_col < xx_cols)
+ {
+ x_putc(c);
+ switch(c)
+ {
+ case BEL:
+ break;
+ case '\r':
+ case '\n':
+ break;
+ case '\b':
+ x_col--;
+ break;
+ default:
+ x_col++;
+ break;
+ }
+ }
+ if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
+ {
+ x_adjust();
+ }
+}
+
+#ifdef DEBUG
+static int
+x_debug_info(c)
+ int c;
+{
+ x_flush();
+ shellf("\nksh debug:\n");
+ shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
+ x_col, xx_cols, x_displen);
+ shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
+ shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
+ shellf("\txlp == 0x%lx\n", (long) xlp);
+ shellf("\txlp == 0x%lx\n", (long) x_lastcp());
+ shellf(newline);
+ x_redraw(-1);
+ return 0;
+}
+#endif
+
+static void
+x_e_puts(s)
+ const char *s;
+{
+ register int adj = x_adj_done;
+
+ while (*s && adj == x_adj_done)
+ x_e_putc(*s++);
+}
+
+/* NAME:
+ * x_set_arg - set an arg value for next function
+ *
+ * DESCRIPTION:
+ * This is a simple implementation of M-[0-9].
+ *
+ * RETURN VALUE:
+ * KSTD
+ */
+
+static int
+x_set_arg(c)
+ int c;
+{
+ int n = 0;
+ int first = 1;
+
+ c &= CHARMASK; /* strip command prefix */
+ for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0)
+ n = n * 10 + (c - '0');
+ if (c < 0 || first) {
+ x_e_putc(BEL);
+ x_arg = 1;
+ x_arg_defaulted = 1;
+ } else {
+ x_e_ungetc(c);
+ x_arg = n;
+ x_arg_defaulted = 0;
+ }
+ return KSTD;
+}
+
+
+/* Comment or uncomment the current line. */
+static int
+x_comment(c)
+ int c;
+{
+ int oldsize = x_size_str(xbuf);
+ int len = xep - xbuf;
+ int ret = x_do_comment(xbuf, xend - xbuf, &len);
+
+ if (ret < 0)
+ x_e_putc(BEL);
+ else {
+ xep = xbuf + len;
+ *xep = '\0';
+ xcp = xbp = xbuf;
+ x_redraw(oldsize);
+ if (ret > 0)
+ return x_newline('\n');
+ }
+ return KSTD;
+}
+
+
+/* NAME:
+ * x_prev_histword - recover word from prev command
+ *
+ * DESCRIPTION:
+ * This function recovers the last word from the previous
+ * command and inserts it into the current edit line. If a
+ * numeric arg is supplied then the n'th word from the
+ * start of the previous command is used.
+ *
+ * Bound to M-.
+ *
+ * RETURN VALUE:
+ * KSTD
+ */
+
+static int
+x_prev_histword(c)
+ int c;
+{
+ register char *rcp;
+ char *cp;
+
+ cp = *histptr;
+ if (!cp)
+ x_e_putc(BEL);
+ else if (x_arg_defaulted) {
+ rcp = &cp[strlen(cp) - 1];
+ /*
+ * ignore white-space after the last word
+ */
+ while (rcp > cp && is_cfs(*rcp))
+ rcp--;
+ while (rcp > cp && !is_cfs(*rcp))
+ rcp--;
+ if (is_cfs(*rcp))
+ rcp++;
+ x_ins(rcp);
+ } else {
+ int c;
+
+ rcp = cp;
+ /*
+ * ignore white-space at start of line
+ */
+ while (*rcp && is_cfs(*rcp))
+ rcp++;
+ while (x_arg-- > 1)
+ {
+ while (*rcp && !is_cfs(*rcp))
+ rcp++;
+ while (*rcp && is_cfs(*rcp))
+ rcp++;
+ }
+ cp = rcp;
+ while (*rcp && !is_cfs(*rcp))
+ rcp++;
+ c = *rcp;
+ *rcp = '\0';
+ x_ins(cp);
+ *rcp = c;
+ }
+ return KSTD;
+}
+
+/* Uppercase N(1) words */
+static int
+x_fold_upper(c)
+ int c;
+{
+ return x_fold_case('U');
+}
+
+/* Lowercase N(1) words */
+static int
+x_fold_lower(c)
+ int c;
+{
+ return x_fold_case('L');
+}
+
+/* Lowercase N(1) words */
+static int
+x_fold_capitialize(c)
+ int c;
+{
+ return x_fold_case('C');
+}
+
+/* NAME:
+ * x_fold_case - convert word to UPPER/lower/Capitial case
+ *
+ * DESCRIPTION:
+ * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c
+ * to UPPER case, lower case or Capitalize words.
+ *
+ * RETURN VALUE:
+ * None
+ */
+
+static int
+x_fold_case(c)
+ int c;
+{
+ char *cp = xcp;
+
+ if (cp == xep) {
+ x_e_putc(BEL);
+ return KSTD;
+ }
+ while (x_arg--) {
+ /*
+ * fisrt skip over any white-space
+ */
+ while (cp != xep && is_mfs(*cp))
+ cp++;
+ /*
+ * do the first char on its own since it may be
+ * a different action than for the rest.
+ */
+ if (cp != xep) {
+ if (c == 'L') { /* lowercase */
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ } else { /* uppercase, capitialize */
+ if (islower(*cp))
+ *cp = toupper(*cp);
+ }
+ cp++;
+ }
+ /*
+ * now for the rest of the word
+ */
+ while (cp != xep && !is_mfs(*cp)) {
+ if (c == 'U') { /* uppercase */
+ if (islower(*cp))
+ *cp = toupper(*cp);
+ } else { /* lowercase, capitialize */
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ }
+ cp++;
+ }
+ }
+ x_goto(cp);
+ return KSTD;
+}
+
+/* NAME:
+ * x_lastcp - last visible char
+ *
+ * SYNOPSIS:
+ * x_lastcp()
+ *
+ * DESCRIPTION:
+ * This function returns a pointer to that char in the
+ * edit buffer that will be the last displayed on the
+ * screen. The sequence:
+ *
+ * for (cp = x_lastcp(); cp > xcp; cp)
+ * x_bs(*--cp);
+ *
+ * Will position the cursor correctly on the screen.
+ *
+ * RETURN VALUE:
+ * cp or NULL
+ */
+
+static char *
+x_lastcp()
+{
+ register char *rcp;
+ register int i;
+
+ if (!xlp_valid)
+ {
+ for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
+ i += x_size(*rcp);
+ xlp = rcp;
+ }
+ xlp_valid = TRUE;
+ return (xlp);
+}
+
+#endif /* EDIT */
diff --git a/shells/pdksh/files/eval.c b/shells/pdksh/files/eval.c
new file mode 100644
index 00000000000..6415b028db0
--- /dev/null
+++ b/shells/pdksh/files/eval.c
@@ -0,0 +1,1376 @@
+/*
+ * Expansion - quoting, separation, substitution, globbing
+ */
+
+#include "sh.h"
+#include <pwd.h>
+#include "ksh_dir.h"
+#include "ksh_stat.h"
+
+/*
+ * string expansion
+ *
+ * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
+ * second pass: alternation ({,}), filename expansion (*?[]).
+ */
+
+/* expansion generator state */
+typedef struct Expand {
+ /* int type; */ /* see expand() */
+ const char *str; /* string */
+ union {
+ const char **strv;/* string[] */
+ struct shf *shf;/* file */
+ } u; /* source */
+ struct tbl *var; /* variable in ${var..} */
+ short split; /* split "$@" / call waitlast $() */
+} Expand;
+
+#define XBASE 0 /* scanning original */
+#define XSUB 1 /* expanding ${} string */
+#define XARGSEP 2 /* ifs0 between "$*" */
+#define XARG 3 /* expanding $*, $@ */
+#define XCOM 4 /* expanding $() */
+#define XNULLSUB 5 /* "$@" when $# is 0 (don't generate word) */
+
+/* States used for field splitting */
+#define IFS_WORD 0 /* word has chars (or quotes) */
+#define IFS_WS 1 /* have seen IFS white-space */
+#define IFS_NWS 2 /* have seen IFS non-white-space */
+
+static int varsub ARGS((Expand *xp, char *sp, char *word, int *stypep, int *slenp));
+static int comsub ARGS((Expand *xp, char *cp));
+static char *trimsub ARGS((char *str, char *pat, int how));
+static void glob ARGS((char *cp, XPtrV *wp, int markdirs));
+static void globit ARGS((XString *xs, char **xpp, char *sp, XPtrV *wp,
+ int check));
+static char *maybe_expand_tilde ARGS((char *p, XString *dsp, char **dpp,
+ int isassign));
+static char *tilde ARGS((char *acp));
+static char *homedir ARGS((char *name));
+#ifdef BRACE_EXPAND
+static void alt_expand ARGS((XPtrV *wp, char *start, char *exp_start,
+ char *end, int fdo));
+#endif
+
+/* compile and expand word */
+char *
+substitute(cp, f)
+ const char *cp;
+ int f;
+{
+ struct source *s, *sold;
+
+ sold = source;
+ s = pushs(SWSTR, ATEMP);
+ s->start = s->str = cp;
+ source = s;
+ if (yylex(ONEWORD) != LWORD)
+ internal_errorf(1, "substitute");
+ source = sold;
+ afree(s, ATEMP);
+ return evalstr(yylval.cp, f);
+}
+
+/*
+ * expand arg-list
+ */
+char **
+eval(ap, f)
+ register char **ap;
+ int f;
+{
+ XPtrV w;
+
+ if (*ap == NULL)
+ return ap;
+ XPinit(w, 32);
+ XPput(w, NULL); /* space for shell name */
+#ifdef SHARPBANG
+ XPput(w, NULL); /* and space for one arg */
+#endif
+ while (*ap != NULL)
+ expand(*ap++, &w, f);
+ XPput(w, NULL);
+#ifdef SHARPBANG
+ return (char **) XPclose(w) + 2;
+#else
+ return (char **) XPclose(w) + 1;
+#endif
+}
+
+/*
+ * expand string
+ */
+char *
+evalstr(cp, f)
+ char *cp;
+ int f;
+{
+ XPtrV w;
+
+ XPinit(w, 1);
+ expand(cp, &w, f);
+ cp = (XPsize(w) == 0) ? null : (char*) *XPptrv(w);
+ XPfree(w);
+ return cp;
+}
+
+/*
+ * expand string - return only one component
+ * used from iosetup to expand redirection files
+ */
+char *
+evalonestr(cp, f)
+ register char *cp;
+ int f;
+{
+ XPtrV w;
+
+ XPinit(w, 1);
+ expand(cp, &w, f);
+ switch (XPsize(w)) {
+ case 0:
+ cp = null;
+ break;
+ case 1:
+ cp = (char*) *XPptrv(w);
+ break;
+ default:
+ cp = evalstr(cp, f&~DOGLOB);
+ break;
+ }
+ XPfree(w);
+ return cp;
+}
+
+/* for nested substitution: ${var:=$var2} */
+typedef struct SubType {
+ short stype; /* [=+-?%#] action after expanded word */
+ short base; /* begin position of expanded word */
+ short f; /* saved value of f (DOPAT, etc) */
+ struct tbl *var; /* variable for ${var..} */
+ short quote; /* saved value of quote (for ${..[%#]..}) */
+ struct SubType *prev; /* old type */
+ struct SubType *next; /* poped type (to avoid re-allocating) */
+} SubType;
+
+void
+expand(cp, wp, f)
+ char *cp; /* input word */
+ register XPtrV *wp; /* output words */
+ int f; /* DO* flags */
+{
+ register int UNINITIALIZED(c);
+ register int type; /* expansion type */
+ register int quote = 0; /* quoted */
+ XString ds; /* destination string */
+ register char *dp, *sp; /* dest., source */
+ int fdo, word; /* second pass flags; have word */
+ int doblank; /* field spliting of parameter/command subst */
+ Expand x; /* expansion variables */
+ SubType st_head, *st;
+ int UNINITIALIZED(newlines); /* For trailing newlines in COMSUB */
+ int saw_eq, tilde_ok;
+ int make_magic;
+
+ if (cp == NULL)
+ internal_errorf(1, "expand(NULL)");
+ /* for alias, readonly, set, typeset commands */
+ if ((f & DOVACHECK) && is_wdvarassign(cp)) {
+ f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
+ f |= DOASNTILDE;
+ }
+ if (Flag(FNOGLOB))
+ f &= ~DOGLOB;
+ if (Flag(FMARKDIRS))
+ f |= DOMARKDIRS;
+#ifdef BRACE_EXPAND
+ if (Flag(FBRACEEXPAND) && (f & DOGLOB))
+ f |= DOBRACE_;
+#endif /* BRACE_EXPAND */
+
+ Xinit(ds, dp, 128, ATEMP); /* init dest. string */
+ type = XBASE;
+ sp = cp;
+ fdo = 0;
+ saw_eq = 0;
+ tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; /* must be 1/0 */
+ doblank = 0;
+ make_magic = 0;
+ word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
+ st_head.next = (SubType *) 0;
+ st = &st_head;
+
+ while (1) {
+ Xcheck(ds, dp);
+
+ switch (type) {
+ case XBASE: /* original prefixed string */
+ c = *sp++;
+ switch (c) {
+ case EOS:
+ c = 0;
+ break;
+ case CHAR:
+ c = *sp++;
+ break;
+ case QCHAR:
+ quote |= 2; /* temporary quote */
+ c = *sp++;
+ break;
+ case OQUOTE:
+ word = IFS_WORD;
+ tilde_ok = 0;
+ quote = 1;
+ continue;
+ case CQUOTE:
+ quote = 0;
+ continue;
+ case COMSUB:
+ tilde_ok = 0;
+ if (f & DONTRUNCOMMAND) {
+ word = IFS_WORD;
+ *dp++ = '$'; *dp++ = '(';
+ while (*sp != '\0') {
+ Xcheck(ds, dp);
+ *dp++ = *sp++;
+ }
+ *dp++ = ')';
+ } else {
+ type = comsub(&x, sp);
+ if (type == XCOM && (f&DOBLANK))
+ doblank++;
+ sp = strchr(sp, 0) + 1;
+ newlines = 0;
+ }
+ continue;
+ case EXPRSUB:
+ word = IFS_WORD;
+ tilde_ok = 0;
+ if (f & DONTRUNCOMMAND) {
+ *dp++ = '$'; *dp++ = '('; *dp++ = '(';
+ while (*sp != '\0') {
+ Xcheck(ds, dp);
+ *dp++ = *sp++;
+ }
+ *dp++ = ')'; *dp++ = ')';
+ } else {
+ struct tbl v;
+ char *p;
+
+ v.flag = DEFINED|ISSET|INTEGER;
+ v.type = 10; /* not default */
+ v.name[0] = '\0';
+ v_evaluate(&v, substitute(sp, 0),
+ KSH_UNWIND_ERROR);
+ sp = strchr(sp, 0) + 1;
+ for (p = str_val(&v); *p; ) {
+ Xcheck(ds, dp);
+ *dp++ = *p++;
+ }
+ }
+ continue;
+ case OSUBST: /* ${{#}var{:}[=+-?#%]word} */
+ /* format is:
+ * OSUBST [{x] plain-variable-part \0
+ * compiled-word-part CSUBST [}x]
+ * This is were all syntax checking gets done...
+ */
+ {
+ char *varname = ++sp; /* skip the { or x (}) */
+ int stype;
+ int slen;
+
+ sp = strchr(sp, '\0') + 1; /* skip variable */
+ type = varsub(&x, varname, sp, &stype, &slen);
+ if (type < 0) {
+ char endc;
+ char *str, *end;
+
+ end = (char *) wdscan(sp, CSUBST);
+ /* ({) the } or x is already skipped */
+ endc = *end;
+ *end = EOS;
+ str = snptreef((char *) 0, 64, "%S",
+ varname - 1);
+ *end = endc;
+ errorf("%s: bad substitution", str);
+ }
+ if (f&DOBLANK)
+ doblank++;
+ tilde_ok = 0;
+ if (type == XBASE) { /* expand? */
+ if (!st->next) {
+ SubType *newst;
+
+ newst = (SubType *) alloc(
+ sizeof(SubType), ATEMP);
+ newst->next = (SubType *) 0;
+ newst->prev = st;
+ st->next = newst;
+ }
+ st = st->next;
+ st->stype = stype;
+ st->base = Xsavepos(ds, dp);
+ st->f = f;
+ st->var = x.var;
+ st->quote = quote;
+ /* skip qualifier(s) */
+ if (stype)
+ sp += slen;
+ switch (stype & 0x7f) {
+ case '#':
+ case '%':
+ /* ! DOBLANK,DOBRACE_,DOTILDE */
+ f = DOPAT | (f&DONTRUNCOMMAND)
+ | DOTEMP_;
+ quote = 0;
+ /* Prepend open pattern (so |
+ * in a trim will work as
+ * expected)
+ */
+ *dp++ = MAGIC;
+ *dp++ = '@' + 0x80;
+ break;
+ case '=':
+ /* Enabling tilde expansion
+ * after :'s here is
+ * non-standard ksh, but is
+ * consistent with rules for
+ * other assignments. Not
+ * sure what POSIX thinks of
+ * this.
+ * Not doing tilde expansion
+ * for integer variables is a
+ * non-POSIX thing - makes
+ * sense though, since ~ is
+ * a arithmetic operator.
+ */
+ if (!(x.var->flag & INTEGER))
+ f |= DOASNTILDE|DOTILDE;
+ f |= DOTEMP_;
+ /* These will be done after the
+ * value has been assigned.
+ */
+ f &= ~(DOBLANK|DOGLOB|DOBRACE_);
+ tilde_ok = 1;
+ break;
+ case '?':
+ f &= ~DOBLANK;
+ f |= DOTEMP_;
+ /* fall through */
+ default:
+ /* Enable tilde expansion */
+ tilde_ok = 1;
+ f |= DOTILDE;
+ }
+ } else
+ /* skip word */
+ sp = (char *) wdscan(sp, CSUBST);
+ continue;
+ }
+ case CSUBST: /* only get here if expanding word */
+ sp++; /* ({) skip the } or x */
+ tilde_ok = 0; /* in case of ${unset:-} */
+ *dp = '\0';
+ quote = st->quote;
+ f = st->f;
+ if (f&DOBLANK)
+ doblank--;
+ switch (st->stype&0x7f) {
+ case '#':
+ case '%':
+ /* Append end-pattern */
+ *dp++ = MAGIC; *dp++ = ')'; *dp = '\0';
+ dp = Xrestpos(ds, dp, st->base);
+ /* Must use st->var since calling
+ * global would break things
+ * like x[i+=1].
+ */
+ x.str = trimsub(str_val(st->var),
+ dp, st->stype);
+ type = XSUB;
+ if (f&DOBLANK)
+ doblank++;
+ st = st->prev;
+ continue;
+ case '=':
+ /* Restore our position and substitute
+ * the value of st->var (may not be
+ * the assigned value in the presence
+ * of integer/right-adj/etc attributes).
+ */
+ dp = Xrestpos(ds, dp, st->base);
+ /* Must use st->var since calling
+ * global would cause with things
+ * like x[i+=1] to be evaluated twice.
+ */
+ /* Note: not exported by FEXPORT
+ * in at&t ksh.
+ */
+ /* XXX POSIX says readonly is only
+ * fatal for special builtins (setstr
+ * does readonly check).
+ */
+ setstr(st->var, debunk(
+ (char *) alloc(strlen(dp) + 1,
+ ATEMP), dp),
+ KSH_UNWIND_ERROR);
+ x.str = str_val(st->var);
+ type = XSUB;
+ if (f&DOBLANK)
+ doblank++;
+ st = st->prev;
+ continue;
+ case '?':
+ {
+ char *s = Xrestpos(ds, dp, st->base);
+
+ errorf("%s: %s", st->var->name,
+ dp == s ?
+ "parameter null or not set"
+ : (debunk(s, s), s));
+ }
+ }
+ st = st->prev;
+ type = XBASE;
+ continue;
+
+ case OPAT: /* open pattern: *(foo|bar) */
+ /* Next char is the type of pattern */
+ make_magic = 1;
+ c = *sp++ + 0x80;
+ break;
+
+ case SPAT: /* pattern seperator (|) */
+ make_magic = 1;
+ c = '|';
+ break;
+
+ case CPAT: /* close pattern */
+ make_magic = 1;
+ c = /*(*/ ')';
+ break;
+ }
+ break;
+
+ case XNULLSUB:
+ /* Special case for "$@" (and "${foo[@]}") - no
+ * word is generated if $# is 0 (unless there is
+ * other stuff inside the quotes).
+ */
+ type = XBASE;
+ if (f&DOBLANK) {
+ doblank--;
+ /* not really correct: x=; "$x$@" should
+ * generate a null argument and
+ * set A; "${@:+}" shouldn't.
+ */
+ if (dp == Xstring(ds, dp))
+ word = IFS_WS;
+ }
+ continue;
+
+ case XSUB:
+ if ((c = *x.str++) == 0) {
+ type = XBASE;
+ if (f&DOBLANK)
+ doblank--;
+ continue;
+ }
+ break;
+
+ case XARGSEP:
+ type = XARG;
+ quote = 1;
+ case XARG:
+ if ((c = *x.str++) == '\0') {
+ /* force null words to be created so
+ * set -- '' 2 ''; foo "$@" will do
+ * the right thing
+ */
+ if (quote && x.split)
+ word = IFS_WORD;
+ if ((x.str = *x.u.strv++) == NULL) {
+ type = XBASE;
+ if (f&DOBLANK)
+ doblank--;
+ continue;
+ }
+ c = ifs0;
+ if (c == 0) {
+ if (quote && !x.split)
+ continue;
+ c = ' ';
+ }
+ if (quote && x.split) {
+ /* terminate word for "$@" */
+ type = XARGSEP;
+ quote = 0;
+ }
+ }
+ break;
+
+ case XCOM:
+ if (newlines) { /* Spit out saved nl's */
+ c = '\n';
+ --newlines;
+ } else {
+ while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
+ if (c == '\n')
+ newlines++; /* Save newlines */
+ if (newlines && c != EOF) {
+ shf_ungetc(c, x.u.shf);
+ c = '\n';
+ --newlines;
+ }
+ }
+ if (c == EOF) {
+ newlines = 0;
+ shf_close(x.u.shf);
+ if (x.split)
+ subst_exstat = waitlast();
+ type = XBASE;
+ if (f&DOBLANK)
+ doblank--;
+ continue;
+ }
+ break;
+ }
+
+ /* check for end of word or IFS separation */
+ if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic
+ && ctype(c, C_IFS)))
+ {
+ /* How words are broken up:
+ * | value of c
+ * word | ws nws 0
+ * -----------------------------------
+ * IFS_WORD w/WS w/NWS w
+ * IFS_WS -/WS w/NWS -
+ * IFS_NWS -/NWS w/NWS w
+ * (w means generate a word)
+ * Note that IFS_NWS/0 generates a word (at&t ksh
+ * doesn't do this, but POSIX does).
+ */
+ if (word == IFS_WORD
+ || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS)))
+ {
+ char *p;
+
+ *dp++ = '\0';
+ p = Xclose(ds, dp);
+#ifdef BRACE_EXPAND
+ if (fdo & DOBRACE_)
+ /* also does globbing */
+ alt_expand(wp, p, p,
+ p + Xlength(ds, (dp - 1)),
+ fdo | (f & DOMARKDIRS));
+ else
+#endif /* BRACE_EXPAND */
+ if (fdo & DOGLOB)
+ glob(p, wp, f & DOMARKDIRS);
+ else if ((f & DOPAT) || !(fdo & DOMAGIC_))
+ XPput(*wp, p);
+ else
+ XPput(*wp, debunk(p, p));
+ fdo = 0;
+ saw_eq = 0;
+ tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
+ if (c != 0)
+ Xinit(ds, dp, 128, ATEMP);
+ }
+ if (c == 0)
+ return;
+ if (word != IFS_NWS)
+ word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
+ } else {
+ /* age tilde_ok info - ~ code tests second bit */
+ tilde_ok <<= 1;
+ /* mark any special second pass chars */
+ if (!quote)
+ switch (c) {
+ case '[':
+ case NOT:
+ case '-':
+ case ']':
+ /* For character classes - doesn't hurt
+ * to have magic !,-,]'s outside of
+ * [...] expressions.
+ */
+ if (f & (DOPAT | DOGLOB)) {
+ fdo |= DOMAGIC_;
+ if (c == '[')
+ fdo |= f & DOGLOB;
+ *dp++ = MAGIC;
+ }
+ break;
+ case '*':
+ case '?':
+ if (f & (DOPAT | DOGLOB)) {
+ fdo |= DOMAGIC_ | (f & DOGLOB);
+ *dp++ = MAGIC;
+ }
+ break;
+#ifdef BRACE_EXPAND
+ case OBRACE:
+ case ',':
+ case CBRACE:
+ if ((f & DOBRACE_) && (c == OBRACE
+ || (fdo & DOBRACE_)))
+ {
+ fdo |= DOBRACE_|DOMAGIC_;
+ *dp++ = MAGIC;
+ }
+ break;
+#endif /* BRACE_EXPAND */
+ case '=':
+ /* Note first unquoted = for ~ */
+ if (!(f & DOTEMP_) && !saw_eq) {
+ saw_eq = 1;
+ tilde_ok = 1;
+ }
+ break;
+ case PATHSEP: /* : */
+ /* Note unquoted : for ~ */
+ if (!(f & DOTEMP_) && (f & DOASNTILDE))
+ tilde_ok = 1;
+ break;
+ case '~':
+ /* tilde_ok is reset whenever
+ * any of ' " $( $(( ${ } are seen.
+ * Note that tilde_ok must be preserved
+ * through the sequence ${A=a=}~
+ */
+ if (type == XBASE
+ && (f & (DOTILDE|DOASNTILDE))
+ && (tilde_ok & 2))
+ {
+ char *p, *dp_x;
+
+ dp_x = dp;
+ p = maybe_expand_tilde(sp,
+ &ds, &dp_x,
+ f & DOASNTILDE);
+ if (p) {
+ if (dp != dp_x)
+ word = IFS_WORD;
+ dp = dp_x;
+ sp = p;
+ continue;
+ }
+ }
+ break;
+ }
+ else
+ quote &= ~2; /* undo temporary */
+
+ if (make_magic) {
+ make_magic = 0;
+ fdo |= DOMAGIC_ | (f & DOGLOB);
+ *dp++ = MAGIC;
+ } else if (ISMAGIC(c)) {
+ fdo |= DOMAGIC_;
+ *dp++ = MAGIC;
+ }
+ *dp++ = c; /* save output char */
+ word = IFS_WORD;
+ }
+ }
+}
+
+/*
+ * Prepare to generate the string returned by ${} substitution.
+ */
+static int
+varsub(xp, sp, word, stypep, slenp)
+ Expand *xp;
+ char *sp;
+ char *word;
+ int *stypep; /* becomes qualifier type */
+ int *slenp; /* " " len (=, :=, etc.) valid iff *stypep != 0 */
+{
+ int c;
+ int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */
+ int stype; /* substitution type */
+ int slen;
+ char *p;
+ struct tbl *vp;
+
+ if (sp[0] == '\0') /* Bad variable name */
+ return -1;
+
+ xp->var = (struct tbl *) 0;
+
+ /* ${#var}, string length or array size */
+ if (sp[0] == '#' && (c = sp[1]) != '\0') {
+ int zero_ok = 0;
+
+ /* Can't have any modifiers for ${#...} */
+ if (*word != CSUBST)
+ return -1;
+ sp++;
+ /* Check for size of array */
+ if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
+ int n = 0;
+ int max = 0;
+ vp = global(arrayname(sp));
+ if (vp->flag & (ISSET|ARRAY))
+ zero_ok = 1;
+ for (; vp; vp = vp->u.array)
+ if (vp->flag & ISSET) {
+ max = vp->index + 1;
+ n++;
+ }
+ c = n; /* ksh88/ksh93 go for number, not max index */
+ } else if (c == '*' || c == '@')
+ c = e->loc->argc;
+ else {
+ p = str_val(global(sp));
+ zero_ok = p != null;
+ c = strlen(p);
+ }
+ if (Flag(FNOUNSET) && c == 0 && !zero_ok)
+ errorf("%s: parameter not set", sp);
+ *stypep = 0; /* unqualified variable/string substitution */
+ xp->str = str_save(ulton((unsigned long)c, 10), ATEMP);
+ return XSUB;
+ }
+
+ /* Check for qualifiers in word part */
+ stype = 0;
+ c = word[slen = 0] == CHAR ? word[1] : 0;
+ if (c == ':') {
+ slen += 2;
+ stype = 0x80;
+ c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
+ }
+ if (ctype(c, C_SUBOP1)) {
+ slen += 2;
+ stype |= c;
+ } else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */
+ slen += 2;
+ stype = c;
+ if (word[slen + 0] == CHAR && c == word[slen + 1]) {
+ stype |= 0x80;
+ slen += 2;
+ }
+ } else if (stype) /* : is not ok */
+ return -1;
+ if (!stype && *word != CSUBST)
+ return -1;
+ *stypep = stype;
+ *slenp = slen;
+
+ c = sp[0];
+ if (c == '*' || c == '@') {
+ switch (stype & 0x7f) {
+ case '=': /* can't assign to a vector */
+ case '%': /* can't trim a vector (yet) */
+ case '#':
+ return -1;
+ }
+ if (e->loc->argc == 0) {
+ xp->str = null;
+ state = c == '@' ? XNULLSUB : XSUB;
+ } else {
+ xp->u.strv = (const char **) e->loc->argv + 1;
+ xp->str = *xp->u.strv++;
+ xp->split = c == '@'; /* $@ */
+ state = XARG;
+ }
+ } else {
+ if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
+ XPtrV wv;
+
+ switch (stype & 0x7f) {
+ case '=': /* can't assign to a vector */
+ case '%': /* can't trim a vector (yet) */
+ case '#':
+ return -1;
+ }
+ XPinit(wv, 32);
+ vp = global(arrayname(sp));
+ for (; vp; vp = vp->u.array) {
+ if (!(vp->flag&ISSET))
+ continue;
+ XPput(wv, str_val(vp));
+ }
+ if (XPsize(wv) == 0) {
+ xp->str = null;
+ state = p[1] == '@' ? XNULLSUB : XSUB;
+ XPfree(wv);
+ } else {
+ XPput(wv, 0);
+ xp->u.strv = (const char **) XPptrv(wv);
+ xp->str = *xp->u.strv++;
+ xp->split = p[1] == '@'; /* ${foo[@]} */
+ state = XARG;
+ }
+ } else {
+ /* Can't assign things like $! or $1 */
+ if ((stype & 0x7f) == '='
+ && (ctype(*sp, C_VAR1) || digit(*sp)))
+ return -1;
+ xp->var = global(sp);
+ xp->str = str_val(xp->var);
+ state = XSUB;
+ }
+ }
+
+ c = stype&0x7f;
+ /* test the compiler's code generator */
+ if (ctype(c, C_SUBOP2) ||
+ (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
+ c == '=' || c == '-' || c == '?' : c == '+'))
+ state = XBASE; /* expand word instead of variable value */
+ if (Flag(FNOUNSET) && xp->str == null
+ && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
+ errorf("%s: parameter not set", sp);
+ return state;
+}
+
+/*
+ * Run the command in $(...) and read its output.
+ */
+static int
+comsub(xp, cp)
+ register Expand *xp;
+ char *cp;
+{
+ Source *s, *sold;
+ register struct op *t;
+ struct shf *shf;
+
+ s = pushs(SSTRING, ATEMP);
+ s->start = s->str = cp;
+ sold = source;
+ t = compile(s);
+ source = sold;
+
+ if (t == NULL)
+ return XBASE;
+
+ if (t != NULL && t->type == TCOM && /* $(<file) */
+ *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
+ register struct ioword *io = *t->ioact;
+ char *name;
+
+ if ((io->flag&IOTYPE) != IOREAD)
+ errorf("funny $() command: %s",
+ snptreef((char *) 0, 32, "%R", io));
+ shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
+ SHF_MAPHI|SHF_CLEXEC);
+ if (shf == NULL)
+ errorf("%s: cannot open $() input", name);
+ xp->split = 0; /* no waitlast() */
+ } else {
+ int ofd1, pv[2];
+ openpipe(pv);
+ shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
+ ofd1 = savefd(1, 0); /* fd 1 may be closed... */
+ ksh_dup2(pv[1], 1, FALSE);
+ close(pv[1]);
+ execute(t, XFORK|XXCOM|XPIPEO);
+ restfd(1, ofd1);
+ startlast();
+ xp->split = 1; /* waitlast() */
+ }
+
+ xp->u.shf = shf;
+ return XCOM;
+}
+
+/*
+ * perform #pattern and %pattern substitution in ${}
+ */
+
+static char *
+trimsub(str, pat, how)
+ register char *str;
+ char *pat;
+ int how;
+{
+ register char *end = strchr(str, 0);
+ register char *p, c;
+
+ switch (how&0xff) { /* UCHAR_MAX maybe? */
+ case '#': /* shortest at begining */
+ for (p = str; p <= end; p++) {
+ c = *p; *p = '\0';
+ if (gmatch(str, pat, FALSE)) {
+ *p = c;
+ return p;
+ }
+ *p = c;
+ }
+ break;
+ case '#'|0x80: /* longest match at begining */
+ for (p = end; p >= str; p--) {
+ c = *p; *p = '\0';
+ if (gmatch(str, pat, FALSE)) {
+ *p = c;
+ return p;
+ }
+ *p = c;
+ }
+ break;
+ case '%': /* shortest match at end */
+ for (p = end; p >= str; p--) {
+ if (gmatch(p, pat, FALSE))
+ return str_nsave(str, p - str, ATEMP);
+ }
+ break;
+ case '%'|0x80: /* longest match at end */
+ for (p = str; p <= end; p++) {
+ if (gmatch(p, pat, FALSE))
+ return str_nsave(str, p - str, ATEMP);
+ }
+ break;
+ }
+
+ return str; /* no match, return string */
+}
+
+/*
+ * glob
+ * Name derived from V6's /etc/glob, the program that expanded filenames.
+ */
+
+/* XXX cp not const 'cause slashes are temporarily replaced with nulls... */
+static void
+glob(cp, wp, markdirs)
+ char *cp;
+ register XPtrV *wp;
+ int markdirs;
+{
+ int oldsize = XPsize(*wp);
+
+ if (glob_str(cp, wp, markdirs) == 0)
+ XPput(*wp, debunk(cp, cp));
+ else
+ qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize),
+ xstrcmp);
+}
+
+#define GF_NONE 0
+#define GF_EXCHECK BIT(0) /* do existance check on file */
+#define GF_GLOBBED BIT(1) /* some globbing has been done */
+#define GF_MARKDIR BIT(2) /* add trailing / to directories */
+
+/* Apply file globbing to cp and store the matching files in wp. Returns
+ * the number of matches found.
+ */
+int
+glob_str(cp, wp, markdirs)
+ char *cp;
+ XPtrV *wp;
+ int markdirs;
+{
+ int oldsize = XPsize(*wp);
+ XString xs;
+ char *xp;
+
+ Xinit(xs, xp, 256, ATEMP);
+ globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
+ Xfree(xs, xp);
+
+ return XPsize(*wp) - oldsize;
+}
+
+static void
+globit(xs, xpp, sp, wp, check)
+ XString *xs; /* dest string */
+ char **xpp; /* ptr to dest end */
+ char *sp; /* source path */
+ register XPtrV *wp; /* output list */
+ int check; /* GF_* flags */
+{
+ register char *np; /* next source component */
+ char *xp = *xpp;
+ char *se;
+ char odirsep;
+
+ /* This to allow long expansions to be interrupted */
+ intrcheck();
+
+ if (sp == NULL) { /* end of source path */
+ /* We only need to check if the file exists if a pattern
+ * is followed by a non-pattern (eg, foo*x/bar; no check
+ * is needed for foo* since the match must exist) or if
+ * any patterns were expanded and the markdirs option is set.
+ * Symlinks make things a bit tricky...
+ */
+ if ((check & GF_EXCHECK)
+ || ((check & GF_MARKDIR) && (check & GF_GLOBBED)))
+ {
+#define stat_check() (stat_done ? stat_done : \
+ (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
+ ? -1 : 1))
+ struct stat lstatb, statb;
+ int stat_done = 0; /* -1: failed, 1 ok */
+
+ if (lstat(Xstring(*xs, xp), &lstatb) < 0)
+ return;
+ /* special case for systems which strip trailing
+ * slashes from regular files (eg, /etc/passwd/).
+ * SunOS 4.1.3 does this...
+ */
+ if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp)
+ && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode)
+#ifdef S_ISLNK
+ && (!S_ISLNK(lstatb.st_mode)
+ || stat_check() < 0
+ || !S_ISDIR(statb.st_mode))
+#endif /* S_ISLNK */
+ )
+ return;
+ /* Possibly tack on a trailing / if there isn't already
+ * one and if the file is a directory or a symlink to a
+ * directory
+ */
+ if (((check & GF_MARKDIR) && (check & GF_GLOBBED))
+ && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1])
+ && (S_ISDIR(lstatb.st_mode)
+#ifdef S_ISLNK
+ || (S_ISLNK(lstatb.st_mode)
+ && stat_check() > 0
+ && S_ISDIR(statb.st_mode))
+#endif /* S_ISLNK */
+ ))
+ {
+ *xp++ = DIRSEP;
+ *xp = '\0';
+ }
+ }
+#ifdef OS2 /* Done this way to avoid bug in gcc 2.7.2... */
+ /* Ugly kludge required for command
+ * completion - see how search_access()
+ * is implemented for OS/2...
+ */
+# define KLUDGE_VAL 4
+#else /* OS2 */
+# define KLUDGE_VAL 0
+#endif /* OS2 */
+ XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp)
+ + KLUDGE_VAL, ATEMP));
+ return;
+ }
+
+ if (xp > Xstring(*xs, xp))
+ *xp++ = DIRSEP;
+ while (ISDIRSEP(*sp)) {
+ Xcheck(*xs, xp);
+ *xp++ = *sp++;
+ }
+ np = ksh_strchr_dirsep(sp);
+ if (np != NULL) {
+ se = np;
+ odirsep = *np; /* don't assume DIRSEP, can be multiple kinds */
+ *np++ = '\0';
+ } else {
+ odirsep = '\0'; /* keep gcc quiet */
+ se = sp + strlen(sp);
+ }
+
+
+ /* Check if sp needs globbing - done to avoid pattern checks for strings
+ * containing MAGIC characters, open ['s without the matching close ],
+ * etc. (otherwise opendir() will be called which may fail because the
+ * directory isn't readable - if no globbing is needed, only execute
+ * permission should be required (as per POSIX)).
+ */
+ if (!has_globbing(sp, se)) {
+ XcheckN(*xs, xp, se - sp + 1);
+ debunk(xp, sp);
+ xp += strlen(xp);
+ *xpp = xp;
+ globit(xs, xpp, np, wp, check);
+ } else {
+ DIR *dirp;
+ struct dirent *d;
+ char *name;
+ int len;
+ int prefix_len;
+
+ /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */
+ *xp = '\0';
+ prefix_len = Xlength(*xs, xp);
+ dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : ".");
+ if (dirp == NULL)
+ goto Nodir;
+ while ((d = readdir(dirp)) != NULL) {
+ name = d->d_name;
+ if (name[0] == '.' &&
+ (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
+ continue; /* always ignore . and .. */
+ if ((*name == '.' && *sp != '.')
+ || !gmatch(name, sp, TRUE))
+ continue;
+
+ len = NLENGTH(d) + 1;
+ XcheckN(*xs, xp, len);
+ memcpy(xp, name, len);
+ *xpp = xp + len - 1;
+ globit(xs, xpp, np, wp,
+ (check & GF_MARKDIR) | GF_GLOBBED
+ | (np ? GF_EXCHECK : GF_NONE));
+ xp = Xstring(*xs, xp) + prefix_len;
+ }
+ closedir(dirp);
+ Nodir:;
+ }
+
+ if (np != NULL)
+ *--np = odirsep;
+}
+
+#if 0
+/* Check if p contains something that needs globbing; if it does, 0 is
+ * returned; if not, p is copied into xs/xp after stripping any MAGICs
+ */
+static int copy_non_glob ARGS((XString *xs, char **xpp, char *p));
+static int
+copy_non_glob(xs, xpp, p)
+ XString *xs;
+ char **xpp;
+ char *p;
+{
+ char *xp;
+ int len = strlen(p);
+
+ XcheckN(*xs, *xpp, len);
+ xp = *xpp;
+ for (; *p; p++) {
+ if (ISMAGIC(*p)) {
+ int c = *++p;
+
+ if (c == '*' || c == '?')
+ return 0;
+ if (*p == '[') {
+ char *q = p + 1;
+
+ if (ISMAGIC(*q) && q[1] == NOT)
+ q += 2;
+ if (ISMAGIC(*q) && q[1] == ']')
+ q += 2;
+ for (; *q; q++)
+ if (ISMAGIC(*q) && *++q == ']')
+ return 0;
+ /* pass a literal [ through */
+ }
+ /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */
+ }
+ *xp++ = *p;
+ }
+ *xp = '\0';
+ *xpp = xp;
+ return 1;
+}
+#endif /* 0 */
+
+/* remove MAGIC from string */
+char *
+debunk(dp, sp)
+ char *dp;
+ const char *sp;
+{
+ char *d, *s;
+
+ if ((s = strchr(sp, MAGIC))) {
+ memcpy(dp, sp, s - sp);
+ for (d = dp + (s - sp); *s; s++)
+ if (!ISMAGIC(*s) || !(*++s & 0x80)
+ || !strchr("*+?@! ", *s & 0x7f))
+ *d++ = *s;
+ else {
+ /* extended pattern operators: *+?@! */
+ if ((*s & 0x7f) != ' ')
+ *d++ = *s & 0x7f;
+ *d++ = '(';
+ }
+ *d = '\0';
+ } else if (dp != sp)
+ strcpy(dp, sp);
+ return dp;
+}
+
+/* Check if p is an unquoted name, possibly followed by a / or :. If so
+ * puts the expanded version in *dcp,dp and returns a pointer in p just
+ * past the name, otherwise returns 0.
+ */
+static char *
+maybe_expand_tilde(p, dsp, dpp, isassign)
+ char *p;
+ XString *dsp;
+ char **dpp;
+ int isassign;
+{
+ XString ts;
+ char *dp = *dpp;
+ char *tp, *r;
+
+ Xinit(ts, tp, 16, ATEMP);
+ /* : only for DOASNTILDE form */
+ while (p[0] == CHAR && !ISDIRSEP(p[1])
+ && (!isassign || p[1] != PATHSEP))
+ {
+ Xcheck(ts, tp);
+ *tp++ = p[1];
+ p += 2;
+ }
+ *tp = '\0';
+ r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0;
+ Xfree(ts, tp);
+ if (r) {
+ while (*r) {
+ Xcheck(*dsp, dp);
+ if (ISMAGIC(*r))
+ *dp++ = MAGIC;
+ *dp++ = *r++;
+ }
+ *dpp = dp;
+ r = p;
+ }
+ return r;
+}
+
+/*
+ * tilde expansion
+ *
+ * based on a version by Arnold Robbins
+ */
+
+static char *
+tilde(cp)
+ char *cp;
+{
+ char *dp;
+
+ if (cp[0] == '\0')
+ dp = str_val(global("HOME"));
+ else if (cp[0] == '+' && cp[1] == '\0')
+ dp = str_val(global("PWD"));
+ else if (cp[0] == '-' && cp[1] == '\0')
+ dp = str_val(global("OLDPWD"));
+ else
+ dp = homedir(cp);
+ /* If HOME, PWD or OLDPWD are not set, don't expand ~ */
+ if (dp == null)
+ dp = (char *) 0;
+ return dp;
+}
+
+/*
+ * map userid to user's home directory.
+ * note that 4.3's getpw adds more than 6K to the shell,
+ * and the YP version probably adds much more.
+ * we might consider our own version of getpwnam() to keep the size down.
+ */
+
+static char *
+homedir(name)
+ char *name;
+{
+ register struct tbl *ap;
+
+ ap = tenter(&homedirs, name, hash(name));
+ if (!(ap->flag & ISSET)) {
+#ifdef OS2
+ /* No usernames in OS2 - punt */
+ return NULL;
+#else /* OS2 */
+ struct passwd *pw;
+
+ pw = getpwnam(name);
+ if (pw == NULL)
+ return NULL;
+ ap->val.s = str_save(pw->pw_dir, APERM);
+ ap->flag |= DEFINED|ISSET|ALLOC;
+#endif /* OS2 */
+ }
+ return ap->val.s;
+}
+
+#ifdef BRACE_EXPAND
+static void
+alt_expand(wp, start, exp_start, end, fdo)
+ XPtrV *wp;
+ char *start, *exp_start;
+ char *end;
+ int fdo;
+{
+ int UNINITIALIZED(count);
+ char *brace_start, *brace_end, *UNINITIALIZED(comma);
+ char *field_start;
+ char *p;
+
+ /* search for open brace */
+ for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2)
+ ;
+ brace_start = p;
+
+ /* find matching close brace, if any */
+ if (p) {
+ comma = (char *) 0;
+ count = 1;
+ for (p += 2; *p && count; p++) {
+ if (ISMAGIC(*p)) {
+ if (*++p == OBRACE)
+ count++;
+ else if (*p == CBRACE)
+ --count;
+ else if (*p == ',' && count == 1)
+ comma = p;
+ }
+ }
+ }
+ /* no valid expansions... */
+ if (!p || count != 0) {
+ /* Note that given a{{b,c} we do not expand anything (this is
+ * what at&t ksh does. This may be changed to do the {b,c}
+ * expansion. }
+ */
+ if (fdo & DOGLOB)
+ glob(start, wp, fdo & DOMARKDIRS);
+ else
+ XPput(*wp, debunk(start, start));
+ return;
+ }
+ brace_end = p;
+ if (!comma) {
+ alt_expand(wp, start, brace_end, end, fdo);
+ return;
+ }
+
+ /* expand expression */
+ field_start = brace_start + 2;
+ count = 1;
+ for (p = brace_start + 2; p != brace_end; p++) {
+ if (ISMAGIC(*p)) {
+ if (*++p == OBRACE)
+ count++;
+ else if ((*p == CBRACE && --count == 0)
+ || (*p == ',' && count == 1))
+ {
+ char *new;
+ int l1, l2, l3;
+
+ l1 = brace_start - start;
+ l2 = (p - 1) - field_start;
+ l3 = end - brace_end;
+ new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP);
+ memcpy(new, start, l1);
+ memcpy(new + l1, field_start, l2);
+ memcpy(new + l1 + l2, brace_end, l3);
+ new[l1 + l2 + l3] = '\0';
+ alt_expand(wp, new, new + l1,
+ new + l1 + l2 + l3, fdo);
+ field_start = p + 1;
+ }
+ }
+ }
+ return;
+}
+#endif /* BRACE_EXPAND */
diff --git a/shells/pdksh/files/exec.c b/shells/pdksh/files/exec.c
new file mode 100644
index 00000000000..f71404c50de
--- /dev/null
+++ b/shells/pdksh/files/exec.c
@@ -0,0 +1,1687 @@
+/*
+ * execute command tree
+ */
+
+#include "sh.h"
+#include "c_test.h"
+#include <ctype.h>
+#include "ksh_stat.h"
+
+/* Does ps4 get parameter substitutions done? */
+#ifdef KSH
+# define PS4_SUBSTITUTE(s) substitute((s), 0)
+#else
+# define PS4_SUBSTITUTE(s) (s)
+#endif /* KSH */
+
+static int comexec ARGS((struct op *t, struct tbl *volatile tp, char **ap,
+ int volatile flags));
+static void scriptexec ARGS((struct op *tp, char **ap));
+static int call_builtin ARGS((struct tbl *tp, char **wp));
+static int iosetup ARGS((struct ioword *iop, struct tbl *tp));
+static int herein ARGS((const char *content, int sub));
+#ifdef KSH
+static char *do_selectargs ARGS((char **ap, bool_t print_menu));
+#endif /* KSH */
+#ifdef KSH
+static int dbteste_isa ARGS((Test_env *te, Test_meta meta));
+static const char *dbteste_getopnd ARGS((Test_env *te, Test_op op,
+ int do_eval));
+static int dbteste_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
+ const char *opnd2, int do_eval));
+static void dbteste_error ARGS((Test_env *te, int offset, const char *msg));
+#endif /* KSH */
+#ifdef OS2
+static int search_access1 ARGS((const char *path, int mode, int *errnop));
+#endif /* OS2 */
+
+
+/*
+ * handle systems that don't have F_SETFD
+ */
+#ifndef F_SETFD
+# ifndef MAXFD
+# define MAXFD 64
+# endif
+/* a bit field would be smaller, but this will work */
+static char clexec_tab[MAXFD+1];
+#endif
+
+/*
+ * we now use this function always.
+ */
+int
+fd_clexec(fd)
+ int fd;
+{
+#ifndef F_SETFD
+ if (fd >= 0 && fd < sizeof(clexec_tab)) {
+ clexec_tab[fd] = 1;
+ return 0;
+ }
+ return -1;
+#else
+ return fcntl(fd, F_SETFD, 1);
+#endif
+}
+
+
+/*
+ * execute command tree
+ */
+int
+execute(t, flags)
+ struct op * volatile t;
+ volatile int flags; /* if XEXEC don't fork */
+{
+ int i;
+ volatile int rv = 0;
+ int pv[2];
+ char ** volatile ap;
+ char *s, *cp;
+ struct ioword **iowp;
+ struct tbl *tp = NULL;
+
+ if (t == NULL)
+ return 0;
+
+ /* Is this the end of a pipeline? If so, we want to evaluate the
+ * command arguments
+ bool_t eval_done = FALSE;
+ if ((flags&XFORK) && !(flags&XEXEC) && (flags&XPCLOSE)) {
+ eval_done = TRUE;
+ tp = eval_execute_args(t, &ap);
+ }
+ */
+ if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
+ return exchild(t, flags & ~XTIME, -1); /* run in sub-process */
+
+ newenv(E_EXEC);
+ if (trap)
+ runtraps(0);
+
+ if (t->type == TCOM) {
+ /* Clear subst_exstat before argument expansion. Used by
+ * null commands (see comexec() and c_eval()) and by c_set().
+ */
+ subst_exstat = 0;
+
+ current_lineno = t->lineno; /* for $LINENO */
+
+ /* POSIX says expand command words first, then redirections,
+ * and assignments last..
+ */
+ ap = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
+ if (flags & XTIME)
+ /* Allow option parsing (bizarre, but POSIX) */
+ timex_hook(t, &ap);
+ if (Flag(FXTRACE) && ap[0]) {
+ shf_fprintf(shl_out, "%s",
+ PS4_SUBSTITUTE(str_val(global("PS4"))));
+ for (i = 0; ap[i]; i++)
+ shf_fprintf(shl_out, "%s%s", ap[i],
+ ap[i + 1] ? space : newline);
+ shf_flush(shl_out);
+ }
+ if (ap[0])
+ tp = findcom(ap[0], FC_BI|FC_FUNC);
+ }
+ flags &= ~XTIME;
+
+ if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
+ e->savefd = (short *) alloc(sizeofN(short, NUFILE), ATEMP);
+ /* initialize to not redirected */
+ memset(e->savefd, 0, sizeofN(short, NUFILE));
+ }
+
+ /* do redirection, to be restored in quitenv() */
+ if (t->ioact != NULL)
+ for (iowp = t->ioact; *iowp != NULL; iowp++) {
+ if (iosetup(*iowp, tp) < 0) {
+ exstat = rv = 1;
+ /* Redirection failures for special commands
+ * cause (non-interactive) shell to exit.
+ */
+ if (tp && tp->type == CSHELL
+ && (tp->flag & SPEC_BI))
+ errorf(null);
+ /* Deal with FERREXIT, quitenv(), etc. */
+ goto Break;
+ }
+ }
+
+ switch(t->type) {
+ case TCOM:
+ rv = comexec(t, tp, ap, flags);
+ break;
+
+ case TPAREN:
+ rv = execute(t->left, flags|XFORK);
+ break;
+
+ case TPIPE:
+ flags |= XFORK;
+ flags &= ~XEXEC;
+ e->savefd[0] = savefd(0, 0);
+ (void) ksh_dup2(e->savefd[0], 0, FALSE); /* stdin of first */
+ e->savefd[1] = savefd(1, 0);
+ while (t->type == TPIPE) {
+ openpipe(pv);
+ (void) ksh_dup2(pv[1], 1, FALSE); /* stdout of curr */
+ /* Let exchild() close pv[0] in child
+ * (if this isn't done, commands like
+ * (: ; cat /etc/termcap) | sleep 1
+ * will hang forever).
+ */
+ exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]);
+ (void) ksh_dup2(pv[0], 0, FALSE); /* stdin of next */
+ closepipe(pv);
+ flags |= XPIPEI;
+ t = t->right;
+ }
+ restfd(1, e->savefd[1]); /* stdout of last */
+ e->savefd[1] = 0; /* no need to re-restore this */
+ /* Let exchild() close 0 in parent, after fork, before wait */
+ i = exchild(t, flags|XPCLOSE, 0);
+ if (!(flags&XBGND) && !(flags&XXCOM))
+ rv = i;
+ break;
+
+ case TLIST:
+ while (t->type == TLIST) {
+ execute(t->left, flags & XERROK);
+ t = t->right;
+ }
+ rv = execute(t, flags & XERROK);
+ break;
+
+#ifdef KSH
+ case TCOPROC:
+ {
+# ifdef JOB_SIGS
+ sigset_t omask;
+# endif /* JOB_SIGS */
+
+# ifdef JOB_SIGS
+ /* Block sigchild as we are using things changed in the
+ * signal handler
+ */
+ sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
+ e->type = E_ERRH;
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (i) {
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+ quitenv();
+ unwind(i);
+ /*NOTREACHED*/
+ }
+# endif /* JOB_SIGS */
+ /* Already have a (live) co-process? */
+ if (coproc.job && coproc.write >= 0)
+ errorf("coprocess already exists");
+
+ /* Can we re-use the existing co-process pipe? */
+ coproc_cleanup(TRUE);
+
+ /* do this before opening pipes, in case these fail */
+ e->savefd[0] = savefd(0, 0);
+ e->savefd[1] = savefd(1, 0);
+
+ openpipe(pv);
+ ksh_dup2(pv[0], 0, FALSE);
+ close(pv[0]);
+ coproc.write = pv[1];
+ coproc.job = (void *) 0;
+
+ if (coproc.readw >= 0)
+ ksh_dup2(coproc.readw, 1, FALSE);
+ else {
+ openpipe(pv);
+ coproc.read = pv[0];
+ ksh_dup2(pv[1], 1, FALSE);
+ coproc.readw = pv[1]; /* closed before first read */
+ coproc.njobs = 0;
+ /* create new coprocess id */
+ ++coproc.id;
+ }
+# ifdef JOB_SIGS
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+ e->type = E_EXEC; /* no more need for error handler */
+# endif /* JOB_SIGS */
+
+ /* exchild() closes coproc.* in child after fork,
+ * will also increment coproc.njobs when the
+ * job is actually created.
+ */
+ flags &= ~XEXEC;
+ exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
+ coproc.readw);
+ break;
+ }
+#endif /* KSH */
+
+ case TASYNC:
+ /* XXX non-optimal, I think - "(foo &)", forks for (),
+ * forks again for async... parent should optimize
+ * this to "foo &"...
+ */
+ rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK);
+ break;
+
+ case TOR:
+ case TAND:
+ rv = execute(t->left, XERROK);
+ if (t->right != NULL && (rv == 0) == (t->type == TAND))
+ rv = execute(t->right, flags & XERROK);
+ else
+ flags |= XERROK;
+ break;
+
+ case TBANG:
+ rv = !execute(t->right, XERROK);
+ break;
+
+#ifdef KSH
+ case TDBRACKET:
+ {
+ Test_env te;
+
+ te.flags = TEF_DBRACKET;
+ te.pos.wp = t->args;
+ te.isa = dbteste_isa;
+ te.getopnd = dbteste_getopnd;
+ te.eval = dbteste_eval;
+ te.error = dbteste_error;
+
+ rv = test_parse(&te);
+ break;
+ }
+#endif /* KSH */
+
+ case TFOR:
+#ifdef KSH
+ case TSELECT:
+ {
+ volatile bool_t is_first = TRUE;
+#endif /* KSH */
+ ap = (t->vars != NULL) ?
+ eval(t->vars, DOBLANK|DOGLOB|DOTILDE)
+ : e->loc->argv + 1;
+ e->type = E_LOOP;
+ while (1) {
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (!i)
+ break;
+ if ((e->flags&EF_BRKCONT_PASS)
+ || (i != LBREAK && i != LCONTIN))
+ {
+ quitenv();
+ unwind(i);
+ } else if (i == LBREAK) {
+ rv = 0;
+ goto Break;
+ }
+ }
+ rv = 0; /* in case of a continue */
+ if (t->type == TFOR) {
+ while (*ap != NULL) {
+ setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
+ rv = execute(t->left, flags & XERROK);
+ }
+ }
+#ifdef KSH
+ else { /* TSELECT */
+ for (;;) {
+ if (!(cp = do_selectargs(ap, is_first))) {
+ rv = 1;
+ break;
+ }
+ is_first = FALSE;
+ setstr(global(t->str), cp, KSH_UNWIND_ERROR);
+ rv = execute(t->left, flags & XERROK);
+ }
+ }
+ }
+#endif /* KSH */
+ break;
+
+ case TWHILE:
+ case TUNTIL:
+ e->type = E_LOOP;
+ while (1) {
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (!i)
+ break;
+ if ((e->flags&EF_BRKCONT_PASS)
+ || (i != LBREAK && i != LCONTIN))
+ {
+ quitenv();
+ unwind(i);
+ } else if (i == LBREAK) {
+ rv = 0;
+ goto Break;
+ }
+ }
+ rv = 0; /* in case of a continue */
+ while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE))
+ rv = execute(t->right, flags & XERROK);
+ break;
+
+ case TIF:
+ case TELIF:
+ if (t->right == NULL)
+ break; /* should be error */
+ rv = execute(t->left, XERROK) == 0 ?
+ execute(t->right->left, flags & XERROK) :
+ execute(t->right->right, flags & XERROK);
+ break;
+
+ case TCASE:
+ cp = evalstr(t->str, DOTILDE);
+ for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
+ for (ap = t->vars; *ap; ap++)
+ if ((s = evalstr(*ap, DOTILDE|DOPAT))
+ && gmatch(cp, s, FALSE))
+ goto Found;
+ break;
+ Found:
+ rv = execute(t->left, flags & XERROK);
+ break;
+
+ case TBRACE:
+ rv = execute(t->left, flags & XERROK);
+ break;
+
+ case TFUNCT:
+ rv = define(t->str, t);
+ break;
+
+ case TTIME:
+ /* Clear XEXEC so nested execute() call doesn't exit
+ * (allows "ls -l | time grep foo").
+ */
+ rv = timex(t, flags & ~XEXEC);
+ break;
+
+ case TEXEC: /* an eval'd TCOM */
+ s = t->args[0];
+ ap = makenv();
+#ifndef F_SETFD
+ for (i = 0; i < sizeof(clexec_tab); i++)
+ if (clexec_tab[i]) {
+ close(i);
+ clexec_tab[i] = 0;
+ }
+#endif
+ restoresigs();
+ cleanup_proc_env();
+ /* XINTACT bit is for OS2 */
+ ksh_execve(t->str, t->args, ap, (flags & XINTACT) ? 1 : 0);
+ if (errno == ENOEXEC)
+ scriptexec(t, ap);
+ else
+ errorf("%s: %s", s, strerror(errno));
+ }
+ Break:
+ exstat = rv;
+
+ quitenv(); /* restores IO */
+ if ((flags&XEXEC))
+ unwind(LEXIT); /* exit child */
+ if (rv != 0 && !(flags & XERROK)) {
+ if (Flag(FERREXIT))
+ unwind(LERROR);
+ trapsig(SIGERR_);
+ }
+ return rv;
+}
+
+/*
+ * execute simple command
+ */
+
+static int
+comexec(t, tp, ap, flags)
+ struct op *t;
+ struct tbl *volatile tp;
+ register char **ap;
+ int volatile flags;
+{
+ int i;
+ int rv = 0;
+ register char *cp;
+ register char **lastp;
+ static struct op texec; /* Must be static (XXX but why?) */
+ int type_flags;
+ int keepasn_ok;
+ int fcflags = FC_BI|FC_FUNC|FC_PATH;
+
+#ifdef KSH
+ /* snag the last argument for $_ XXX not the same as at&t ksh,
+ * which only seems to set $_ after a newline (but not in
+ * functions/dot scripts, but in interactive and scipt) -
+ * perhaps save last arg here and set it in shell()?.
+ */
+ if (Flag(FTALKING) && *(lastp = ap)) {
+ while (*++lastp)
+ ;
+ /* setstr() can't fail here */
+ setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
+ KSH_RETURN_ERROR);
+ }
+#endif /* KSH */
+
+ /* Deal with the shell builtins builtin, exec and command since
+ * they can be followed by other commands. This must be done before
+ * we know if we should create a local block, which must be done
+ * before we can do a path search (in case the assignments change
+ * PATH).
+ * Odd cases:
+ * FOO=bar exec > /dev/null FOO is kept but not exported
+ * FOO=bar exec foobar FOO is exported
+ * FOO=bar command exec > /dev/null FOO is neither kept nor exported
+ * FOO=bar command FOO is neither kept nor exported
+ * PATH=... foobar use new PATH in foobar search
+ */
+ keepasn_ok = 1;
+ while (tp && tp->type == CSHELL) {
+ fcflags = FC_BI|FC_FUNC|FC_PATH;/* undo effects of command */
+ if (tp->val.f == c_builtin) {
+ if ((cp = *++ap) == NULL) {
+ tp = NULL;
+ break;
+ }
+ tp = findcom(cp, FC_BI);
+ if (tp == NULL)
+ errorf("builtin: %s: not a builtin", cp);
+ continue;
+ } else if (tp->val.f == c_exec) {
+ if (ap[1] == NULL)
+ break;
+ ap++;
+ flags |= XEXEC;
+ } else if (tp->val.f == c_command) {
+ int optc, saw_p = 0;
+
+ /* Ugly dealing with options in two places (here and
+ * in c_command(), but such is life)
+ */
+ ksh_getopt_reset(&builtin_opt, 0);
+ while ((optc = ksh_getopt(ap, &builtin_opt, ":p"))
+ == 'p')
+ saw_p = 1;
+ if (optc != EOF)
+ break; /* command -vV or something */
+ /* don't look for functions */
+ fcflags = FC_BI|FC_PATH;
+ if (saw_p) {
+ if (Flag(FRESTRICTED)) {
+ warningf(TRUE,
+ "command -p: restricted");
+ rv = 1;
+ goto Leave;
+ }
+ fcflags |= FC_DEFPATH;
+ }
+ ap += builtin_opt.optind;
+ /* POSIX says special builtins lose their status
+ * if accessed using command.
+ */
+ keepasn_ok = 0;
+ if (!ap[0]) {
+ /* ensure command with no args exits with 0 */
+ subst_exstat = 0;
+ break;
+ }
+ } else
+ break;
+ tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
+ }
+ if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
+ type_flags = 0;
+ else {
+ /* create new variable/function block */
+ newblock();
+ /* ksh functions don't keep assignments, POSIX functions do. */
+ if (keepasn_ok && tp && tp->type == CFUNC
+ && !(tp->flag & FKSH))
+ type_flags = 0;
+ else
+ type_flags = LOCAL|LOCAL_COPY|EXPORT;
+ }
+ if (Flag(FEXPORT))
+ type_flags |= EXPORT;
+ for (i = 0; t->vars[i]; i++) {
+ cp = evalstr(t->vars[i], DOASNTILDE);
+ if (Flag(FXTRACE)) {
+ if (i == 0)
+ shf_fprintf(shl_out, "%s",
+ PS4_SUBSTITUTE(str_val(global("PS4"))));
+ shf_fprintf(shl_out, "%s%s", cp,
+ t->vars[i + 1] ? space : newline);
+ if (!t->vars[i + 1])
+ shf_flush(shl_out);
+ }
+ typeset(cp, type_flags, 0, 0, 0);
+ }
+
+ if ((cp = *ap) == NULL) {
+ rv = subst_exstat;
+ goto Leave;
+ } else if (!tp) {
+ if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) {
+ warningf(TRUE, "%s: restricted", cp);
+ rv = 1;
+ goto Leave;
+ }
+ tp = findcom(cp, fcflags);
+ }
+
+ switch (tp->type) {
+ case CSHELL: /* shell built-in */
+ rv = call_builtin(tp, ap);
+ break;
+
+ case CFUNC: /* function call */
+ {
+ volatile int old_xflag;
+ volatile Tflag old_inuse;
+ const char *volatile old_kshname;
+
+ if (!(tp->flag & ISSET)) {
+ struct tbl *ftp;
+
+ if (!tp->u.fpath) {
+ if (tp->u2.errno_) {
+ warningf(TRUE,
+ "%s: can't find function definition file - %s",
+ cp, strerror(tp->u2.errno_));
+ rv = 126;
+ } else {
+ warningf(TRUE,
+ "%s: can't find function definition file", cp);
+ rv = 127;
+ }
+ break;
+ }
+ if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) {
+ warningf(TRUE,
+ "%s: can't open function definition file %s - %s",
+ cp, tp->u.fpath, strerror(errno));
+ rv = 127;
+ break;
+ }
+ if (!(ftp = findfunc(cp, hash(cp), FALSE))
+ || !(ftp->flag & ISSET))
+ {
+ warningf(TRUE,
+ "%s: function not defined by %s",
+ cp, tp->u.fpath);
+ rv = 127;
+ break;
+ }
+ tp = ftp;
+ }
+
+ /* ksh functions set $0 to function name, POSIX functions leave
+ * $0 unchanged.
+ */
+ old_kshname = kshname;
+ if (tp->flag & FKSH)
+ kshname = ap[0];
+ else
+ ap[0] = (char *) kshname;
+ e->loc->argv = ap;
+ for (i = 0; *ap++ != NULL; i++)
+ ;
+ e->loc->argc = i - 1;
+ /* ksh-style functions handle getopts sanely,
+ * bourne/posix functions are insane...
+ */
+ if (tp->flag & FKSH) {
+ e->loc->flags |= BF_DOGETOPTS;
+ e->loc->getopts_state = user_opt;
+ getopts_reset(1);
+ }
+
+ old_xflag = Flag(FXTRACE);
+ Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE;
+
+ old_inuse = tp->flag & FINUSE;
+ tp->flag |= FINUSE;
+
+ e->type = E_FUNC;
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (i == 0) {
+ /* seems odd to pass XERROK here, but at&t ksh does */
+ exstat = execute(tp->val.t, flags & XERROK);
+ i = LRETURN;
+ }
+ kshname = old_kshname;
+ Flag(FXTRACE) = old_xflag;
+ tp->flag = (tp->flag & ~FINUSE) | old_inuse;
+ /* Were we deleted while executing? If so, free the execution
+ * tree. todo: Unfortunately, the table entry is never re-used
+ * until the lookup table is expanded.
+ */
+ if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
+ if (tp->flag & ALLOC) {
+ tp->flag &= ~ALLOC;
+ tfree(tp->val.t, tp->areap);
+ }
+ tp->flag = 0;
+ }
+ switch (i) {
+ case LRETURN:
+ case LERROR:
+ rv = exstat;
+ break;
+ case LINTR:
+ case LEXIT:
+ case LLEAVE:
+ case LSHELL:
+ quitenv();
+ unwind(i);
+ /*NOTREACHED*/
+ default:
+ quitenv();
+ internal_errorf(1, "CFUNC %d", i);
+ }
+ break;
+ }
+
+ case CEXEC: /* executable command */
+ case CTALIAS: /* tracked alias */
+ if (!(tp->flag&ISSET)) {
+ /* errno_ will be set if the named command was found
+ * but could not be executed (permissions, no execute
+ * bit, directory, etc). Print out a (hopefully)
+ * useful error message and set the exit status to 126.
+ */
+ if (tp->u2.errno_) {
+ warningf(TRUE, "%s: cannot execute - %s", cp,
+ strerror(tp->u2.errno_));
+ rv = 126; /* POSIX */
+ } else {
+ warningf(TRUE, "%s: not found", cp);
+ rv = 127;
+ }
+ break;
+ }
+
+#ifdef KSH
+ /* set $_ to program's full path */
+ /* setstr() can't fail here */
+ setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s,
+ KSH_RETURN_ERROR);
+#endif /* KSH */
+
+ if (flags&XEXEC) {
+ j_exit();
+ if (!(flags&XBGND) || Flag(FMONITOR)) {
+ setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
+ setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
+ }
+ }
+
+ /* to fork we set up a TEXEC node and call execute */
+ texec.type = TEXEC;
+ texec.left = t; /* for tprint */
+ texec.str = tp->val.s;
+ texec.args = ap;
+ rv = exchild(&texec, flags, -1);
+ break;
+ }
+ Leave:
+ if (flags & XEXEC) {
+ exstat = rv;
+ unwind(LLEAVE);
+ }
+ return rv;
+}
+
+static void
+scriptexec(tp, ap)
+ register struct op *tp;
+ register char **ap;
+{
+ char *shell;
+
+ shell = str_val(global(EXECSHELL_STR));
+ if (shell && *shell)
+ shell = search(shell, path, X_OK, (int *) 0);
+ if (!shell || !*shell)
+ shell = EXECSHELL;
+
+ *tp->args-- = tp->str;
+#ifdef SHARPBANG
+ {
+ char buf[LINE];
+ register char *cp;
+ register int fd, n;
+
+ buf[0] = '\0';
+ if ((fd = open(tp->str, O_RDONLY)) >= 0) {
+ if ((n = read(fd, buf, LINE - 1)) > 0)
+ buf[n] = '\0';
+ (void) close(fd);
+ }
+ if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2]))
+# ifdef OS2
+ || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7])
+ && (cp = &buf[7]))
+# endif /* OS2 */
+ )
+ {
+ while (*cp && (*cp == ' ' || *cp == '\t'))
+ cp++;
+ if (*cp && *cp != '\n') {
+ char *a0 = cp, *a1 = (char *) 0;
+# ifdef OS2
+ char *a2 = cp;
+# endif /* OS2 */
+
+ while (*cp && *cp != '\n' && *cp != ' '
+ && *cp != '\t')
+ {
+# ifdef OS2
+ /* Allow shell search without prepended path
+ * if shell with / in pathname cannot be found.
+ * Use / explicitly so \ can be used if explicit
+ * needs to be forced.
+ */
+ if (*cp == '/')
+ a2 = cp + 1;
+# endif /* OS2 */
+ cp++;
+ }
+ if (*cp && *cp != '\n') {
+ *cp++ = '\0';
+ while (*cp
+ && (*cp == ' ' || *cp == '\t'))
+ cp++;
+ if (*cp && *cp != '\n') {
+ a1 = cp;
+ /* all one argument */
+ while (*cp && *cp != '\n')
+ cp++;
+ }
+ }
+ if (*cp == '\n') {
+ *cp = '\0';
+ if (a1)
+ *tp->args-- = a1;
+# ifdef OS2
+ if (a0 != a2) {
+ char *tmp_a0 = str_nsave(a0,
+ strlen(a0) + 5, ATEMP);
+ if (search_access(tmp_a0, X_OK,
+ (int *) 0))
+ a0 = a2;
+ afree(tmp_a0, ATEMP);
+ }
+# endif /* OS2 */
+ shell = a0;
+ }
+ }
+# ifdef OS2
+ } else {
+ /* Use ksh documented shell default if present
+ * else use OS2_SHELL which is assumed to need
+ * the /c option and '\' as dir separater.
+ */
+ char *p = shell;
+
+ shell = str_val(global("EXECSHELL"));
+ if (shell && *shell)
+ shell = search(shell, path, X_OK, (int *) 0);
+ if (!shell || !*shell) {
+ shell = p;
+ *tp->args-- = "/c";
+ for (p = tp->str; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+ }
+# endif /* OS2 */
+ }
+ }
+#endif /* SHARPBANG */
+ *tp->args = shell;
+
+ ksh_execve(tp->args[0], tp->args, ap, 0);
+
+ /* report both the program that was run and the bogus shell */
+ errorf("%s: %s: %s", tp->str, shell, strerror(errno));
+}
+
+int
+shcomexec(wp)
+ register char **wp;
+{
+ register struct tbl *tp;
+
+ tp = tsearch(&builtins, *wp, hash(*wp));
+ if (tp == NULL)
+ internal_errorf(1, "shcomexec: %s", *wp);
+ return call_builtin(tp, wp);
+}
+
+/*
+ * Search function tables for a function. If create set, a table entry
+ * is created if none is found.
+ */
+struct tbl *
+findfunc(name, h, create)
+ const char *name;
+ unsigned int h;
+ int create;
+{
+ struct block *l;
+ struct tbl *tp = (struct tbl *) 0;
+
+ for (l = e->loc; l; l = l->next) {
+ tp = tsearch(&l->funs, name, h);
+ if (tp)
+ break;
+ if (!l->next && create) {
+ tp = tenter(&l->funs, name, h);
+ tp->flag = DEFINED;
+ tp->type = CFUNC;
+ tp->val.t = (struct op *) 0;
+ break;
+ }
+ }
+ return tp;
+}
+
+/*
+ * define function. Returns 1 if function is being undefined (t == 0) and
+ * function did not exist, returns 0 otherwise.
+ */
+int
+define(name, t)
+ const char *name;
+ struct op *t;
+{
+ struct tbl *tp;
+ int was_set = 0;
+
+ while (1) {
+ tp = findfunc(name, hash(name), TRUE);
+
+ if (tp->flag & ISSET)
+ was_set = 1;
+ /* If this function is currently being executed, we zap this
+ * table entry so findfunc() won't see it
+ */
+ if (tp->flag & FINUSE) {
+ tp->name[0] = '\0';
+ tp->flag &= ~DEFINED; /* ensure it won't be found */
+ tp->flag |= FDELETE;
+ } else
+ break;
+ }
+
+ if (tp->flag & ALLOC) {
+ tp->flag &= ~(ISSET|ALLOC);
+ tfree(tp->val.t, tp->areap);
+ }
+
+ if (t == NULL) { /* undefine */
+ tdelete(tp);
+ return was_set ? 0 : 1;
+ }
+
+ tp->val.t = tcopy(t->left, tp->areap);
+ tp->flag |= (ISSET|ALLOC);
+ if (t->u.ksh_func)
+ tp->flag |= FKSH;
+
+ return 0;
+}
+
+/*
+ * add builtin
+ */
+void
+builtin(name, func)
+ const char *name;
+ int (*func) ARGS((char **));
+{
+ register struct tbl *tp;
+ Tflag flag;
+
+ /* see if any flags should be set for this builtin */
+ for (flag = 0; ; name++) {
+ if (*name == '=') /* command does variable assignment */
+ flag |= KEEPASN;
+ else if (*name == '*') /* POSIX special builtin */
+ flag |= SPEC_BI;
+ else if (*name == '+') /* POSIX regular builtin */
+ flag |= REG_BI;
+ else
+ break;
+ }
+
+ tp = tenter(&builtins, name, hash(name));
+ tp->flag = DEFINED | flag;
+ tp->type = CSHELL;
+ tp->val.f = func;
+}
+
+/*
+ * find command
+ * either function, hashed command, or built-in (in that order)
+ */
+struct tbl *
+findcom(name, flags)
+ const char *name;
+ int flags; /* FC_* */
+{
+ static struct tbl temp;
+ unsigned int h = hash(name);
+ struct tbl *tp = NULL, *tbi;
+ int insert = Flag(FTRACKALL); /* insert if not found */
+ char *fpath; /* for function autoloading */
+ char *npath;
+
+ if (ksh_strchr_dirsep(name) != NULL) {
+ insert = 0;
+ /* prevent FPATH search below */
+ flags &= ~FC_FUNC;
+ goto Search;
+ }
+ tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL;
+ /* POSIX says special builtins first, then functions, then
+ * POSIX regular builtins, then search path...
+ */
+ if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
+ tp = tbi;
+ if (!tp && (flags & FC_FUNC)) {
+ tp = findfunc(name, h, FALSE);
+ if (tp && !(tp->flag & ISSET)) {
+ if ((fpath = str_val(global("FPATH"))) == null) {
+ tp->u.fpath = (char *) 0;
+ tp->u2.errno_ = 0;
+ } else
+ tp->u.fpath = search(name, fpath, R_OK,
+ &tp->u2.errno_);
+ }
+ }
+ if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
+ tp = tbi;
+ /* todo: posix says non-special/non-regular builtins must
+ * be triggered by some user-controllable means like a
+ * special directory in PATH. Requires modifications to
+ * the search() function. Tracked aliases should be
+ * modified to allow tracking of builtin commands.
+ * This should be under control of the FPOSIX flag.
+ * If this is changed, also change c_whence...
+ */
+ if (!tp && (flags & FC_UNREGBI) && tbi)
+ tp = tbi;
+ if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
+ tp = tsearch(&taliases, name, h);
+ if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) {
+ if (tp->flag & ALLOC) {
+ tp->flag &= ~ALLOC;
+ afree(tp->val.s, APERM);
+ }
+ tp->flag &= ~ISSET;
+ }
+ }
+
+ Search:
+ if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET)))
+ && (flags & FC_PATH))
+ {
+ if (!tp) {
+ if (insert && !(flags & FC_DEFPATH)) {
+ tp = tenter(&taliases, name, h);
+ tp->type = CTALIAS;
+ } else {
+ tp = &temp;
+ tp->type = CEXEC;
+ }
+ tp->flag = DEFINED; /* make ~ISSET */
+ }
+ npath = search(name, flags & FC_DEFPATH ? def_path : path,
+ X_OK, &tp->u2.errno_);
+ if (npath) {
+ tp->val.s = tp == &temp ? npath : str_save(npath, APERM);
+ tp->flag |= ISSET|ALLOC;
+ } else if ((flags & FC_FUNC)
+ && (fpath = str_val(global("FPATH"))) != null
+ && (npath = search(name, fpath, R_OK,
+ &tp->u2.errno_)) != (char *) 0)
+ {
+ /* An undocumented feature of at&t ksh is that it
+ * searches FPATH if a command is not found, even
+ * if the command hasn't been set up as an autoloaded
+ * function (ie, no typeset -uf).
+ */
+ tp = &temp;
+ tp->type = CFUNC;
+ tp->flag = DEFINED; /* make ~ISSET */
+ tp->u.fpath = npath;
+ }
+ }
+ return tp;
+}
+
+/*
+ * flush executable commands with relative paths
+ */
+void
+flushcom(all)
+ int all; /* just relative or all */
+{
+ struct tbl *tp;
+ struct tstate ts;
+
+ for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; )
+ if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) {
+ if (tp->flag&ALLOC) {
+ tp->flag &= ~(ALLOC|ISSET);
+ afree(tp->val.s, APERM);
+ }
+ tp->flag &= ~ISSET;
+ }
+}
+
+/* Check if path is something we want to find. Returns -1 for failure. */
+int
+search_access(path, mode, errnop)
+ const char *path;
+ int mode;
+ int *errnop; /* set if candidate found, but not suitable */
+{
+#ifndef OS2
+ int ret, err = 0;
+ struct stat statb;
+
+ if (stat(path, &statb) < 0)
+ return -1;
+ ret = eaccess(path, mode);
+ if (ret < 0)
+ err = errno; /* File exists, but we can't access it */
+ else if (mode == X_OK
+ && (!S_ISREG(statb.st_mode)
+ /* This 'cause access() says root can execute everything */
+ || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
+ {
+ ret = -1;
+ err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
+ }
+ if (err && errnop && !*errnop)
+ *errnop = err;
+ return ret;
+#else /* !OS2 */
+ /*
+ * NOTE: ASSUMES path can be modified and has enough room at the
+ * end of the string for a suffix (ie, 4 extra characters).
+ * Certain code knows this (eg, eval.c(globit()),
+ * exec.c(search())).
+ */
+ static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd",
+ ".com", ".bat", (char *) 0
+ };
+ static char *rsuffixes[] = { ".ksh", ".", ".sh", ".cmd", ".bat",
+ (char *) 0
+ };
+ int i;
+ char *mpath = (char *) path;
+ char *tp = mpath + strlen(mpath);
+ char *p;
+ char **sfx;
+
+ /* If a suffix has been specified, check if it is one of the
+ * suffixes that indicate the file is executable - if so, change
+ * the access test to R_OK...
+ * This code assumes OS/2 files can have only one suffix...
+ */
+ if ((p = strrchr((p = ksh_strrchr_dirsep(mpath)) ? p : mpath, '.'))) {
+ if (mode == X_OK)
+ mode = R_OK;
+ return search_access1(mpath, mode, errnop);
+ }
+ /* Try appending the various suffixes. Different suffixes for
+ * read and execute 'cause we don't want to read an executable...
+ */
+ sfx = mode == R_OK ? rsuffixes : xsuffixes;
+ for (i = 0; sfx[i]; i++) {
+ strcpy(tp, p = sfx[i]);
+ if (search_access1(mpath, R_OK, errnop) == 0)
+ return 0;
+ *tp = '\0';
+ }
+ return -1;
+#endif /* !OS2 */
+}
+
+#ifdef OS2
+static int
+search_access1(path, mode, errnop)
+ const char *path;
+ int mode;
+ int *errnop; /* set if candidate found, but not suitable */
+{
+ int ret, err = 0;
+ struct stat statb;
+
+ if (stat(path, &statb) < 0)
+ return -1;
+ ret = eaccess(path, mode);
+ if (ret < 0)
+ err = errno; /* File exists, but we can't access it */
+ else if (!S_ISREG(statb.st_mode)) {
+ ret = -1;
+ err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
+ }
+ if (err && errnop && !*errnop)
+ *errnop = err;
+ return ret;
+}
+#endif /* OS2 */
+
+/*
+ * search for command with PATH
+ */
+char *
+search(name, path, mode, errnop)
+ const char *name;
+ const char *path;
+ int mode; /* R_OK or X_OK */
+ int *errnop; /* set if candidate found, but not suitable */
+{
+ const char *sp, *p;
+ char *xp;
+ XString xs;
+ int namelen;
+
+ if (errnop)
+ *errnop = 0;
+#ifdef OS2
+ /* Xinit() allocates 8 additional bytes, so appended suffixes won't
+ * overflow the memory.
+ */
+ namelen = strlen(name) + 1;
+ Xinit(xs, xp, namelen, ATEMP);
+ memcpy(Xstring(xs, xp), name, namelen);
+
+ if (ksh_strchr_dirsep(name)) {
+ if (search_access(Xstring(xs, xp), mode, errnop) >= 0)
+ return Xstring(xs, xp); /* not Xclose() - see above */
+ Xfree(xs, xp);
+ return NULL;
+ }
+
+ /* Look in current context always. (os2 style) */
+ if (search_access(Xstring(xs, xp), mode, errnop) == 0)
+ return Xstring(xs, xp); /* not Xclose() - xp may be wrong */
+#else /* OS2 */
+ if (ksh_strchr_dirsep(name)) {
+ if (search_access(name, mode, errnop) == 0)
+ return (char *) name;
+ return NULL;
+ }
+
+ namelen = strlen(name) + 1;
+ Xinit(xs, xp, 128, ATEMP);
+#endif /* OS2 */
+
+ sp = path;
+ while (sp != NULL) {
+ xp = Xstring(xs, xp);
+ if (!(p = strchr(sp, PATHSEP)))
+ p = sp + strlen(sp);
+ if (p != sp) {
+ XcheckN(xs, xp, p - sp);
+ memcpy(xp, sp, p - sp);
+ xp += p - sp;
+ *xp++ = DIRSEP;
+ }
+ sp = p;
+ XcheckN(xs, xp, namelen);
+ memcpy(xp, name, namelen);
+ if (search_access(Xstring(xs, xp), mode, errnop) == 0)
+#ifdef OS2
+ return Xstring(xs, xp); /* Not Xclose() - see above */
+#else /* OS2 */
+ return Xclose(xs, xp + namelen);
+#endif /* OS2 */
+ if (*sp++ == '\0')
+ sp = NULL;
+ }
+ Xfree(xs, xp);
+ return NULL;
+}
+
+static int
+call_builtin(tp, wp)
+ struct tbl *tp;
+ char **wp;
+{
+ int rv;
+
+ builtin_argv0 = wp[0];
+ builtin_flag = tp->flag;
+ shf_reopen(1, SHF_WR, shl_stdout);
+ shl_stdout_ok = 1;
+ ksh_getopt_reset(&builtin_opt, GF_ERROR);
+ rv = (*tp->val.f)(wp);
+ shf_flush(shl_stdout);
+ shl_stdout_ok = 0;
+ builtin_flag = 0;
+ builtin_argv0 = (char *) 0;
+ return rv;
+}
+
+/*
+ * set up redirection, saving old fd's in e->savefd
+ */
+static int
+iosetup(iop, tp)
+ register struct ioword *iop;
+ struct tbl *tp;
+{
+ register int u = -1;
+ char *cp = iop->name;
+ int iotype = iop->flag & IOTYPE;
+ int do_open = 1, do_close = 0, UNINITIALIZED(flags);
+ struct ioword iotmp;
+ struct stat statb;
+
+ if (iotype != IOHERE)
+ cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
+
+ /* Used for tracing and error messages to print expanded cp */
+ iotmp = *iop;
+ iotmp.name = (iotype == IOHERE) ? (char *) 0 : cp;
+ iotmp.flag |= IONAMEXP;
+
+ if (Flag(FXTRACE))
+ shellf("%s%s\n",
+ PS4_SUBSTITUTE(str_val(global("PS4"))),
+ snptreef((char *) 0, 32, "%R", &iotmp));
+
+ switch (iotype) {
+ case IOREAD:
+ flags = O_RDONLY;
+ break;
+
+ case IOCAT:
+ flags = O_WRONLY | O_APPEND | O_CREAT;
+ break;
+
+ case IOWRITE:
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ /* The stat() is here to allow redirections to
+ * things like /dev/null without error.
+ */
+ if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB)
+ && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
+ flags |= O_EXCL;
+ break;
+
+ case IORDWR:
+ flags = O_RDWR | O_CREAT;
+ break;
+
+ case IOHERE:
+ do_open = 0;
+ /* herein() returns -2 if error has been printed */
+ u = herein(iop->heredoc, iop->flag & IOEVAL);
+ /* cp may have wrong name */
+ break;
+
+ case IODUP:
+ {
+ const char *emsg;
+
+ do_open = 0;
+ if (*cp == '-' && !cp[1]) {
+ u = 1009; /* prevent error return below */
+ do_close = 1;
+ } else if ((u = check_fd(cp,
+ X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
+ &emsg)) < 0)
+ {
+ warningf(TRUE, "%s: %s",
+ snptreef((char *) 0, 32, "%R", &iotmp), emsg);
+ return -1;
+ }
+ break;
+ }
+ }
+ if (do_open) {
+ if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
+ warningf(TRUE, "%s: restricted", cp);
+ return -1;
+ }
+ u = open(cp, flags, 0666);
+#ifdef OS2
+ if (u < 0 && strcmp(cp, "/dev/null") == 0)
+ u = open("nul", flags, 0666);
+#endif /* OS2 */
+ }
+ if (u < 0) {
+ /* herein() may already have printed message */
+ if (u == -1)
+ warningf(TRUE, "cannot %s %s: %s",
+ iotype == IODUP ? "dup"
+ : (iotype == IOREAD || iotype == IOHERE) ?
+ "open" : "create", cp, strerror(errno));
+ return -1;
+ }
+ /* Do not save if it has already been redirected (i.e. "cat >x >y"). */
+ if (e->savefd[iop->unit] == 0)
+ /* c_exec() assumes e->savefd[fd] set for any redirections.
+ * Ask savefd() not to close iop->unit - allows error messages
+ * to be seen if iop->unit is 2; also means we can't lose
+ * the fd (eg, both dup2 below and dup2 in restfd() failing).
+ */
+ e->savefd[iop->unit] = savefd(iop->unit, 1);
+
+ if (do_close)
+ close(iop->unit);
+ else if (u != iop->unit) {
+ if (ksh_dup2(u, iop->unit, TRUE) < 0) {
+ warningf(TRUE,
+ "could not finish (dup) redirection %s: %s",
+ snptreef((char *) 0, 32, "%R", &iotmp),
+ strerror(errno));
+ if (iotype != IODUP)
+ close(u);
+ return -1;
+ }
+ if (iotype != IODUP)
+ close(u);
+#ifdef KSH
+ /* Touching any co-process fd in an empty exec
+ * causes the shell to close its copies
+ */
+ else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
+ if (iop->flag & IORDUP) /* possible exec <&p */
+ coproc_read_close(u);
+ else /* possible exec >&p */
+ coproc_write_close(u);
+ }
+#endif /* KSH */
+ }
+ if (u == 2) /* Clear any write errors */
+ shf_reopen(2, SHF_WR, shl_out);
+ return 0;
+}
+
+/*
+ * open here document temp file.
+ * if unquoted here, expand here temp file into second temp file.
+ */
+static int
+herein(content, sub)
+ const char *content;
+ int sub;
+{
+ volatile int fd = -1;
+ struct source *s, *volatile osource;
+ struct shf *volatile shf;
+ struct temp *h;
+ int i;
+
+ /* ksh -c 'cat << EOF' can cause this... */
+ if (content == (char *) 0) {
+ warningf(TRUE, "here document missing");
+ return -2; /* special to iosetup(): don't print error */
+ }
+
+ /* Create temp file to hold content (done before newenv so temp
+ * doesn't get removed too soon).
+ */
+ h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
+ if (!(shf = h->shf) || (fd = open(h->name, O_RDONLY, 0)) < 0) {
+ warningf(TRUE, "can't %s temporary file %s: %s",
+ !shf ? "create" : "open",
+ h->name, strerror(errno));
+ if (shf)
+ shf_close(shf);
+ return -2 /* special to iosetup(): don't print error */;
+ }
+
+ osource = source;
+ newenv(E_ERRH);
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (i) {
+ source = osource;
+ quitenv();
+ shf_close(shf); /* after quitenv */
+ close(fd);
+ return -2; /* special to iosetup(): don't print error */
+ }
+ if (sub) {
+ /* Do substitutions on the content of heredoc */
+ s = pushs(SSTRING, ATEMP);
+ s->start = s->str = content;
+ source = s;
+ if (yylex(ONEWORD) != LWORD)
+ internal_errorf(1, "herein: yylex");
+ source = osource;
+ shf_puts(evalstr(yylval.cp, 0), shf);
+ } else
+ shf_puts(content, shf);
+
+ quitenv();
+
+ if (shf_close(shf) == EOF) {
+ close(fd);
+ warningf(TRUE, "error writing %s: %s", h->name,
+ strerror(errno));
+ return -2; /* special to iosetup(): don't print error */
+ }
+
+ return fd;
+}
+
+#ifdef KSH
+/*
+ * ksh special - the select command processing section
+ * print the args in column form - assuming that we can
+ */
+static char *
+do_selectargs(ap, print_menu)
+ register char **ap;
+ bool_t print_menu;
+{
+ static const char *const read_args[] = {
+ "read", "-r", "REPLY", (char *) 0
+ };
+ char *s;
+ int i, argct;
+
+ for (argct = 0; ap[argct]; argct++)
+ ;
+ while (1) {
+ /* Menu is printed if
+ * - this is the first time around the select loop
+ * - the user enters a blank line
+ * - the REPLY parameter is empty
+ */
+ if (print_menu || !*str_val(global("REPLY")))
+ pr_menu(ap);
+ shellf("%s", str_val(global("PS3")));
+ if (call_builtin(findcom("read", FC_BI), (char **) read_args))
+ return (char *) 0;
+ s = str_val(global("REPLY"));
+ if (*s) {
+ i = atoi(s);
+ return (i >= 1 && i <= argct) ? ap[i - 1] : null;
+ }
+ print_menu = 1;
+ }
+}
+
+struct select_menu_info {
+ char *const *args;
+ int arg_width;
+ int num_width;
+} info;
+
+static char *select_fmt_entry ARGS((void *arg, int i, char *buf, int buflen));
+
+/* format a single select menu item */
+static char *
+select_fmt_entry(arg, i, buf, buflen)
+ void *arg;
+ int i;
+ char *buf;
+ int buflen;
+{
+ struct select_menu_info *smi = (struct select_menu_info *) arg;
+
+ shf_snprintf(buf, buflen, "%*d) %s",
+ smi->num_width, i + 1, smi->args[i]);
+ return buf;
+}
+
+/*
+ * print a select style menu
+ */
+int
+pr_menu(ap)
+ char *const *ap;
+{
+ struct select_menu_info smi;
+ char *const *pp;
+ int nwidth, dwidth;
+ int i, n;
+
+ /* Width/column calculations were done once and saved, but this
+ * means select can't be used recursively so we re-calculate each
+ * time (could save in a structure that is returned, but its probably
+ * not worth the bother).
+ */
+
+ /*
+ * get dimensions of the list
+ */
+ for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
+ i = strlen(*pp);
+ nwidth = (i > nwidth) ? i : nwidth;
+ }
+ /*
+ * we will print an index of the form
+ * %d)
+ * in front of each entry
+ * get the max width of this
+ */
+ for (i = n, dwidth = 1; i >= 10; i /= 10)
+ dwidth++;
+
+ smi.args = ap;
+ smi.arg_width = nwidth;
+ smi.num_width = dwidth;
+ print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
+ dwidth + nwidth + 2);
+
+ return n;
+}
+#endif /* KSH */
+#ifdef KSH
+
+/*
+ * [[ ... ]] evaluation routines
+ */
+
+extern const char *const dbtest_tokens[];
+extern const char db_close[];
+
+/* Test if the current token is a whatever. Accepts the current token if
+ * it is. Returns 0 if it is not, non-zero if it is (in the case of
+ * TM_UNOP and TM_BINOP, the returned value is a Test_op).
+ */
+static int
+dbteste_isa(te, meta)
+ Test_env *te;
+ Test_meta meta;
+{
+ int ret = 0;
+ int uqword;
+ char *p;
+
+ if (!*te->pos.wp)
+ return meta == TM_END;
+
+ /* unquoted word? */
+ for (p = *te->pos.wp; *p == CHAR; p += 2)
+ ;
+ uqword = *p == EOS;
+
+ if (meta == TM_UNOP || meta == TM_BINOP) {
+ if (uqword) {
+ char buf[8]; /* longer than the longest operator */
+ char *q = buf;
+ for (p = *te->pos.wp; *p == CHAR
+ && q < &buf[sizeof(buf) - 1];
+ p += 2)
+ *q++ = p[1];
+ *q = '\0';
+ ret = (int) test_isop(te, meta, buf);
+ }
+ } else if (meta == TM_END)
+ ret = 0;
+ else
+ ret = uqword
+ && strcmp(*te->pos.wp, dbtest_tokens[(int) meta]) == 0;
+
+ /* Accept the token? */
+ if (ret)
+ te->pos.wp++;
+
+ return ret;
+}
+
+static const char *
+dbteste_getopnd(te, op, do_eval)
+ Test_env *te;
+ Test_op op;
+ int do_eval;
+{
+ char *s = *te->pos.wp;
+
+ if (!s)
+ return (char *) 0;
+
+ te->pos.wp++;
+
+ if (!do_eval)
+ return null;
+
+ if (op == TO_STEQL || op == TO_STNEQ)
+ s = evalstr(s, DOTILDE | DOPAT);
+ else
+ s = evalstr(s, DOTILDE);
+
+ return s;
+}
+
+static int
+dbteste_eval(te, op, opnd1, opnd2, do_eval)
+ Test_env *te;
+ Test_op op;
+ const char *opnd1;
+ const char *opnd2;
+ int do_eval;
+{
+ return test_eval(te, op, opnd1, opnd2, do_eval);
+}
+
+static void
+dbteste_error(te, offset, msg)
+ Test_env *te;
+ int offset;
+ const char *msg;
+{
+ te->flags |= TEF_ERROR;
+ internal_errorf(0, "dbteste_error: %s (offset %d)", msg, offset);
+}
+#endif /* KSH */
diff --git a/shells/pdksh/files/expand.h b/shells/pdksh/files/expand.h
new file mode 100644
index 00000000000..73ac44c5777
--- /dev/null
+++ b/shells/pdksh/files/expand.h
@@ -0,0 +1,106 @@
+/*
+ * Expanding strings
+ */
+/* $Id: expand.h,v 1.1.1.1 2008/05/23 17:15:18 tnn Exp $ */
+
+#define X_EXTRA 8 /* this many extra bytes in X string */
+
+#if 0 /* Usage */
+ XString xs;
+ char *xp;
+
+ Xinit(xs, xp, 128, ATEMP); /* allocate initial string */
+ while ((c = generate()) {
+ Xcheck(xs, xp); /* expand string if neccessary */
+ Xput(xs, xp, c); /* add character */
+ }
+ return Xclose(xs, xp); /* resize string */
+/*
+ * NOTE:
+ * The Xcheck and Xinit macros have a magic + X_EXTRA in the lengths.
+ * This is so that you can put up to X_EXTRA characters in a XString
+ * before calling Xcheck. (See yylex in lex.c)
+ */
+#endif /* 0 */
+
+typedef struct XString {
+ char *end, *beg; /* end, begin of string */
+ size_t len; /* length */
+ Area *areap; /* area to allocate/free from */
+} XString;
+
+typedef char * XStringP;
+
+/* initialize expandable string */
+#define Xinit(xs, xp, length, area) do { \
+ (xs).len = length; \
+ (xs).areap = (area); \
+ (xs).beg = alloc((xs).len + X_EXTRA, (xs).areap); \
+ (xs).end = (xs).beg + (xs).len; \
+ xp = (xs).beg; \
+ } while (0)
+
+/* stuff char into string */
+#define Xput(xs, xp, c) (*xp++ = (c))
+
+/* check if there are at least n bytes left */
+#define XcheckN(xs, xp, n) do { \
+ int more = ((xp) + (n)) - (xs).end; \
+ if (more > 0) \
+ xp = Xcheck_grow_(&xs, xp, more); \
+ } while (0)
+
+/* check for overflow, expand string */
+#define Xcheck(xs, xp) XcheckN(xs, xp, 1)
+
+/* free string */
+#define Xfree(xs, xp) afree((void*) (xs).beg, (xs).areap)
+
+/* close, return string */
+#define Xclose(xs, xp) (char*) aresize((void*)(xs).beg, \
+ (size_t)((xp) - (xs).beg), (xs).areap)
+/* begin of string */
+#define Xstring(xs, xp) ((xs).beg)
+
+#define Xnleft(xs, xp) ((xs).end - (xp)) /* may be less than 0 */
+#define Xlength(xs, xp) ((xp) - (xs).beg)
+#define Xsize(xs, xp) ((xs).end - (xs).beg)
+#define Xsavepos(xs, xp) ((xp) - (xs).beg)
+#define Xrestpos(xs, xp, n) ((xs).beg + (n))
+
+char * Xcheck_grow_ ARGS((XString *xsp, char *xp, int more));
+
+/*
+ * expandable vector of generic pointers
+ */
+
+typedef struct XPtrV {
+ void **cur; /* next avail pointer */
+ void **beg, **end; /* begin, end of vector */
+} XPtrV;
+
+#define XPinit(x, n) do { \
+ register void **vp__; \
+ vp__ = (void**) alloc(sizeofN(void*, n), ATEMP); \
+ (x).cur = (x).beg = vp__; \
+ (x).end = vp__ + n; \
+ } while (0)
+
+#define XPput(x, p) do { \
+ if ((x).cur >= (x).end) { \
+ int n = XPsize(x); \
+ (x).beg = (void**) aresize((void*) (x).beg, \
+ sizeofN(void*, n*2), ATEMP); \
+ (x).cur = (x).beg + n; \
+ (x).end = (x).cur + n; \
+ } \
+ *(x).cur++ = (p); \
+ } while (0)
+
+#define XPptrv(x) ((x).beg)
+#define XPsize(x) ((x).cur - (x).beg)
+
+#define XPclose(x) (void**) aresize((void*)(x).beg, \
+ sizeofN(void*, XPsize(x)), ATEMP)
+
+#define XPfree(x) afree((void*) (x).beg, ATEMP)
diff --git a/shells/pdksh/files/expr.c b/shells/pdksh/files/expr.c
new file mode 100644
index 00000000000..48a1cc8f316
--- /dev/null
+++ b/shells/pdksh/files/expr.c
@@ -0,0 +1,605 @@
+/*
+ * Korn expression evaluation
+ */
+/*
+ * todo: better error handling: if in builtin, should be builtin error, etc.
+ */
+
+#include "sh.h"
+#include <ctype.h>
+
+
+/* The order of these enums is constrained by the order of opinfo[] */
+enum token {
+ /* some (long) unary operators */
+ O_PLUSPLUS = 0, O_MINUSMINUS,
+ /* binary operators */
+ O_EQ, O_NE,
+ /* assignments are assumed to be in range O_ASN .. O_BORASN */
+ O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
+ O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
+ O_LSHIFT, O_RSHIFT,
+ O_LE, O_GE, O_LT, O_GT,
+ O_LAND,
+ O_LOR,
+ O_TIMES, O_DIV, O_MOD,
+ O_PLUS, O_MINUS,
+ O_BAND,
+ O_BXOR,
+ O_BOR,
+ O_TERN,
+ O_COMMA,
+ /* things after this aren't used as binary operators */
+ /* unary that are not also binaries */
+ O_BNOT, O_LNOT,
+ /* misc */
+ OPEN_PAREN, CLOSE_PAREN, CTERN,
+ /* things that don't appear in the opinfo[] table */
+ VAR, LIT, END, BAD
+ };
+#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
+#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
+
+enum prec {
+ P_PRIMARY = 0, /* VAR, LIT, (), ~ ! - + */
+ P_MULT, /* * / % */
+ P_ADD, /* + - */
+ P_SHIFT, /* << >> */
+ P_RELATION, /* < <= > >= */
+ P_EQUALITY, /* == != */
+ P_BAND, /* & */
+ P_BXOR, /* ^ */
+ P_BOR, /* | */
+ P_LAND, /* && */
+ P_LOR, /* || */
+ P_TERN, /* ?: */
+ P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */
+ P_COMMA /* , */
+ };
+#define MAX_PREC P_COMMA
+
+struct opinfo {
+ char name[4];
+ int len; /* name length */
+ enum prec prec; /* precidence: lower is higher */
+};
+
+/* Tokens in this table must be ordered so the longest are first
+ * (eg, += before +). If you change something, change the order
+ * of enum token too.
+ */
+static const struct opinfo opinfo[] = {
+ { "++", 2, P_PRIMARY }, /* before + */
+ { "--", 2, P_PRIMARY }, /* before - */
+ { "==", 2, P_EQUALITY }, /* before = */
+ { "!=", 2, P_EQUALITY }, /* before ! */
+ { "=", 1, P_ASSIGN }, /* keep assigns in a block */
+ { "*=", 2, P_ASSIGN },
+ { "/=", 2, P_ASSIGN },
+ { "%=", 2, P_ASSIGN },
+ { "+=", 2, P_ASSIGN },
+ { "-=", 2, P_ASSIGN },
+ { "<<=", 3, P_ASSIGN },
+ { ">>=", 3, P_ASSIGN },
+ { "&=", 2, P_ASSIGN },
+ { "^=", 2, P_ASSIGN },
+ { "|=", 2, P_ASSIGN },
+ { "<<", 2, P_SHIFT },
+ { ">>", 2, P_SHIFT },
+ { "<=", 2, P_RELATION },
+ { ">=", 2, P_RELATION },
+ { "<", 1, P_RELATION },
+ { ">", 1, P_RELATION },
+ { "&&", 2, P_LAND },
+ { "||", 2, P_LOR },
+ { "*", 1, P_MULT },
+ { "/", 1, P_MULT },
+ { "%", 1, P_MULT },
+ { "+", 1, P_ADD },
+ { "-", 1, P_ADD },
+ { "&", 1, P_BAND },
+ { "^", 1, P_BXOR },
+ { "|", 1, P_BOR },
+ { "?", 1, P_TERN },
+ { ",", 1, P_COMMA },
+ { "~", 1, P_PRIMARY },
+ { "!", 1, P_PRIMARY },
+ { "(", 1, P_PRIMARY },
+ { ")", 1, P_PRIMARY },
+ { ":", 1, P_PRIMARY },
+ { "", 0, P_PRIMARY } /* end of table */
+ };
+
+
+typedef struct expr_state Expr_state;
+struct expr_state {
+ const char *expression; /* expression being evaluated */
+ const char *tokp; /* lexical position */
+ enum token tok; /* token from token() */
+ int noassign; /* don't do assigns (for ?:,&&,||) */
+ struct tbl *val; /* value from token() */
+ struct tbl *evaling; /* variable that is being recursively
+ * expanded (EXPRINEVAL flag set)
+ */
+};
+
+enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
+ ET_LVALUE, ET_RDONLY, ET_STR };
+
+static void evalerr ARGS((Expr_state *es, enum error_type type,
+ const char *str)) GCC_FUNC_ATTR(noreturn);
+static struct tbl *evalexpr ARGS((Expr_state *es, enum prec prec));
+static void token ARGS((Expr_state *es));
+static struct tbl *do_ppmm ARGS((Expr_state *es, enum token op,
+ struct tbl *vasn, bool_t is_prefix));
+static void assign_check ARGS((Expr_state *es, enum token op,
+ struct tbl *vasn));
+static struct tbl *tempvar ARGS((void));
+static struct tbl *intvar ARGS((Expr_state *es, struct tbl *vp));
+
+/*
+ * parse and evalute expression
+ */
+int
+evaluate(expr, rval, error_ok)
+ const char *expr;
+ long *rval;
+ int error_ok;
+{
+ struct tbl v;
+ int ret;
+
+ v.flag = DEFINED|INTEGER;
+ v.type = 0;
+ ret = v_evaluate(&v, expr, error_ok);
+ *rval = v.val.i;
+ return ret;
+}
+
+/*
+ * parse and evalute expression, storing result in vp.
+ */
+int
+v_evaluate(vp, expr, error_ok)
+ struct tbl *vp;
+ const char *expr;
+ volatile int error_ok;
+{
+ struct tbl *v;
+ Expr_state curstate;
+ Expr_state * const es = &curstate;
+ int i;
+
+ /* save state to allow recursive calls */
+ curstate.expression = curstate.tokp = expr;
+ curstate.noassign = 0;
+ curstate.evaling = (struct tbl *) 0;
+
+ newenv(E_ERRH);
+ i = ksh_sigsetjmp(e->jbuf, 0);
+ if (i) {
+ /* Clear EXPRINEVAL in of any variables we were playing with */
+ if (curstate.evaling)
+ curstate.evaling->flag &= ~EXPRINEVAL;
+ quitenv();
+ if (i == LAEXPR) {
+ if (error_ok == KSH_RETURN_ERROR)
+ return 0;
+ errorf(null);
+ }
+ unwind(i);
+ /*NOTREACHED*/
+ }
+
+ token(es);
+#if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */
+ if (es->tok == END) {
+ es->tok = LIT;
+ es->val = tempvar();
+ }
+#endif /* 0 */
+ v = intvar(es, evalexpr(es, MAX_PREC));
+
+ if (es->tok != END)
+ evalerr(es, ET_UNEXPECTED, (char *) 0);
+
+ if (vp->flag & INTEGER)
+ setint_v(vp, v);
+ else
+ /* can fail if readony */
+ setstr(vp, str_val(v), error_ok);
+
+ quitenv();
+
+ return 1;
+}
+
+static void
+evalerr(es, type, str)
+ Expr_state *es;
+ enum error_type type;
+ const char *str;
+{
+ char tbuf[2];
+ const char *s;
+
+ switch (type) {
+ case ET_UNEXPECTED:
+ switch (es->tok) {
+ case VAR:
+ s = es->val->name;
+ break;
+ case LIT:
+ s = str_val(es->val);
+ break;
+ case END:
+ s = "end of expression";
+ break;
+ case BAD:
+ tbuf[0] = *es->tokp;
+ tbuf[1] = '\0';
+ s = tbuf;
+ break;
+ default:
+ s = opinfo[(int)es->tok].name;
+ }
+ warningf(TRUE, "%s: unexpected `%s'", es->expression, s);
+ break;
+
+ case ET_BADLIT:
+ warningf(TRUE, "%s: bad number `%s'", es->expression, str);
+ break;
+
+ case ET_RECURSIVE:
+ warningf(TRUE, "%s: expression recurses on parameter `%s'",
+ es->expression, str);
+ break;
+
+ case ET_LVALUE:
+ warningf(TRUE, "%s: %s requires lvalue",
+ es->expression, str);
+ break;
+
+ case ET_RDONLY:
+ warningf(TRUE, "%s: %s applied to read only variable",
+ es->expression, str);
+ break;
+
+ default: /* keep gcc happy */
+ case ET_STR:
+ warningf(TRUE, "%s: %s", es->expression, str);
+ break;
+ }
+ unwind(LAEXPR);
+}
+
+static struct tbl *
+evalexpr(es, prec)
+ Expr_state *es;
+ enum prec prec;
+{
+ struct tbl *vl, UNINITIALIZED(*vr), *vasn;
+ enum token op;
+ long UNINITIALIZED(res);
+
+ if (prec == P_PRIMARY) {
+ op = es->tok;
+ if (op == O_BNOT || op == O_LNOT || op == O_MINUS
+ || op == O_PLUS)
+ {
+ token(es);
+ vl = intvar(es, evalexpr(es, P_PRIMARY));
+ if (op == O_BNOT)
+ vl->val.i = ~vl->val.i;
+ else if (op == O_LNOT)
+ vl->val.i = !vl->val.i;
+ else if (op == O_MINUS)
+ vl->val.i = -vl->val.i;
+ /* op == O_PLUS is a no-op */
+ } else if (op == OPEN_PAREN) {
+ token(es);
+ vl = evalexpr(es, MAX_PREC);
+ if (es->tok != CLOSE_PAREN)
+ evalerr(es, ET_STR, "missing )");
+ token(es);
+ } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
+ token(es);
+ vl = do_ppmm(es, op, es->val, TRUE);
+ token(es);
+ } else if (op == VAR || op == LIT) {
+ vl = es->val;
+ token(es);
+ } else {
+ evalerr(es, ET_UNEXPECTED, (char *) 0);
+ /*NOTREACHED*/
+ }
+ if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
+ vl = do_ppmm(es, es->tok, vl, FALSE);
+ token(es);
+ }
+ return vl;
+ }
+ vl = evalexpr(es, ((int) prec) - 1);
+ for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
+ op = es->tok)
+ {
+ token(es);
+ vasn = vl;
+ if (op != O_ASN) /* vl may not have a value yet */
+ vl = intvar(es, vl);
+ if (IS_ASSIGNOP(op)) {
+ assign_check(es, op, vasn);
+ vr = intvar(es, evalexpr(es, P_ASSIGN));
+ } else if (op != O_TERN && op != O_LAND && op != O_LOR)
+ vr = intvar(es, evalexpr(es, ((int) prec) - 1));
+ if ((op == O_DIV || op == O_MOD || op == O_DIVASN
+ || op == O_MODASN) && vr->val.i == 0)
+ {
+ if (es->noassign)
+ vr->val.i = 1;
+ else
+ evalerr(es, ET_STR, "zero divisor");
+ }
+ switch ((int) op) {
+ case O_TIMES:
+ case O_TIMESASN:
+ res = vl->val.i * vr->val.i;
+ break;
+ case O_DIV:
+ case O_DIVASN:
+ res = vl->val.i / vr->val.i;
+ break;
+ case O_MOD:
+ case O_MODASN:
+ res = vl->val.i % vr->val.i;
+ break;
+ case O_PLUS:
+ case O_PLUSASN:
+ res = vl->val.i + vr->val.i;
+ break;
+ case O_MINUS:
+ case O_MINUSASN:
+ res = vl->val.i - vr->val.i;
+ break;
+ case O_LSHIFT:
+ case O_LSHIFTASN:
+ res = vl->val.i << vr->val.i;
+ break;
+ case O_RSHIFT:
+ case O_RSHIFTASN:
+ res = vl->val.i >> vr->val.i;
+ break;
+ case O_LT:
+ res = vl->val.i < vr->val.i;
+ break;
+ case O_LE:
+ res = vl->val.i <= vr->val.i;
+ break;
+ case O_GT:
+ res = vl->val.i > vr->val.i;
+ break;
+ case O_GE:
+ res = vl->val.i >= vr->val.i;
+ break;
+ case O_EQ:
+ res = vl->val.i == vr->val.i;
+ break;
+ case O_NE:
+ res = vl->val.i != vr->val.i;
+ break;
+ case O_BAND:
+ case O_BANDASN:
+ res = vl->val.i & vr->val.i;
+ break;
+ case O_BXOR:
+ case O_BXORASN:
+ res = vl->val.i ^ vr->val.i;
+ break;
+ case O_BOR:
+ case O_BORASN:
+ res = vl->val.i | vr->val.i;
+ break;
+ case O_LAND:
+ if (!vl->val.i)
+ es->noassign++;
+ vr = intvar(es, evalexpr(es, ((int) prec) - 1));
+ res = vl->val.i && vr->val.i;
+ if (!vl->val.i)
+ es->noassign--;
+ break;
+ case O_LOR:
+ if (vl->val.i)
+ es->noassign++;
+ vr = intvar(es, evalexpr(es, ((int) prec) - 1));
+ res = vl->val.i || vr->val.i;
+ if (vl->val.i)
+ es->noassign--;
+ break;
+ case O_TERN:
+ {
+ int e = vl->val.i != 0;
+ if (!e)
+ es->noassign++;
+ vl = evalexpr(es, MAX_PREC);
+ if (!e)
+ es->noassign--;
+ if (es->tok != CTERN)
+ evalerr(es, ET_STR, "missing :");
+ token(es);
+ if (e)
+ es->noassign++;
+ vr = evalexpr(es, P_TERN);
+ if (e)
+ es->noassign--;
+ vl = e ? vl : vr;
+ }
+ break;
+ case O_ASN:
+ res = vr->val.i;
+ break;
+ case O_COMMA:
+ res = vr->val.i;
+ break;
+ }
+ if (IS_ASSIGNOP(op)) {
+ vr->val.i = res;
+ if (vasn->flag & INTEGER)
+ setint_v(vasn, vr);
+ else
+ setint(vasn, res);
+ vl = vr;
+ } else if (op != O_TERN)
+ vl->val.i = res;
+ }
+ return vl;
+}
+
+static void
+token(es)
+ Expr_state *es;
+{
+ const char *cp;
+ int c;
+ char *tvar;
+
+ /* skip white space */
+ for (cp = es->tokp; (c = *cp), isspace(c); cp++)
+ ;
+ es->tokp = cp;
+
+ if (c == '\0')
+ es->tok = END;
+ else if (letter(c)) {
+ for (; letnum(c); c = *cp)
+ cp++;
+ if (c == '[') {
+ int len;
+
+ len = array_ref_len(cp);
+ if (len == 0)
+ evalerr(es, ET_STR, "missing ]");
+ cp += len;
+ }
+#ifdef KSH
+ else if (c == '(' /*)*/ ) {
+ /* todo: add math functions (all take single argument):
+ * abs acos asin atan cos cosh exp int log sin sinh sqrt
+ * tan tanh
+ */
+ ;
+ }
+#endif /* KSH */
+ if (es->noassign) {
+ es->val = tempvar();
+ es->val->flag |= EXPRLVALUE;
+ } else {
+ tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP);
+ es->val = global(tvar);
+ afree(tvar, ATEMP);
+ }
+ es->tok = VAR;
+ } else if (digit(c)) {
+ for (; c != '_' && (letnum(c) || c == '#'); c = *cp++)
+ ;
+ tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP);
+ es->val = tempvar();
+ es->val->flag &= ~INTEGER;
+ es->val->type = 0;
+ es->val->val.s = tvar;
+ if (setint_v(es->val, es->val) == NULL)
+ evalerr(es, ET_BADLIT, tvar);
+ afree(tvar, ATEMP);
+ es->tok = LIT;
+ } else {
+ int i, n0;
+
+ for (i = 0; (n0 = opinfo[i].name[0]); i++)
+ if (c == n0
+ && strncmp(cp, opinfo[i].name, opinfo[i].len) == 0)
+ {
+ es->tok = (enum token) i;
+ cp += opinfo[i].len;
+ break;
+ }
+ if (!n0)
+ es->tok = BAD;
+ }
+ es->tokp = cp;
+}
+
+/* Do a ++ or -- operation */
+static struct tbl *
+do_ppmm(es, op, vasn, is_prefix)
+ Expr_state *es;
+ enum token op;
+ struct tbl *vasn;
+ bool_t is_prefix;
+{
+ struct tbl *vl;
+ int oval;
+
+ assign_check(es, op, vasn);
+
+ vl = intvar(es, vasn);
+ oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
+ if (vasn->flag & INTEGER)
+ setint_v(vasn, vl);
+ else
+ setint(vasn, vl->val.i);
+ if (!is_prefix) /* undo the inc/dec */
+ vl->val.i = oval;
+
+ return vl;
+}
+
+static void
+assign_check(es, op, vasn)
+ Expr_state *es;
+ enum token op;
+ struct tbl *vasn;
+{
+ if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
+ evalerr(es, ET_LVALUE, opinfo[(int) op].name);
+ else if (vasn->flag & RDONLY)
+ evalerr(es, ET_RDONLY, opinfo[(int) op].name);
+}
+
+static struct tbl *
+tempvar()
+{
+ register struct tbl *vp;
+
+ vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
+ vp->flag = ISSET|INTEGER;
+ vp->type = 0;
+ vp->areap = ATEMP;
+ vp->val.i = 0;
+ vp->name[0] = '\0';
+ return vp;
+}
+
+/* cast (string) variable to temporary integer variable */
+static struct tbl *
+intvar(es, vp)
+ Expr_state *es;
+ struct tbl *vp;
+{
+ struct tbl *vq;
+
+ /* try to avoid replacing a temp var with another temp var */
+ if (vp->name[0] == '\0'
+ && (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
+ return vp;
+
+ vq = tempvar();
+ if (setint_v(vq, vp) == NULL) {
+ if (vp->flag & EXPRINEVAL)
+ evalerr(es, ET_RECURSIVE, vp->name);
+ es->evaling = vp;
+ vp->flag |= EXPRINEVAL;
+ v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR);
+ vp->flag &= ~EXPRINEVAL;
+ es->evaling = (struct tbl *) 0;
+ }
+ return vq;
+}
diff --git a/shells/pdksh/files/history.c b/shells/pdksh/files/history.c
new file mode 100644
index 00000000000..0c9329a052f
--- /dev/null
+++ b/shells/pdksh/files/history.c
@@ -0,0 +1,1190 @@
+/*
+ * command history
+ *
+ * only implements in-memory history.
+ */
+
+/*
+ * This file contains
+ * a) the original in-memory history mechanism
+ * b) a simple file saving history mechanism done by sjg@zen
+ * define EASY_HISTORY to get this
+ * c) a more complicated mechanism done by pc@hillside.co.uk
+ * that more closely follows the real ksh way of doing
+ * things. You need to have the mmap system call for this
+ * to work on your system
+ */
+
+#include "sh.h"
+#include "ksh_stat.h"
+
+#ifdef HISTORY
+# ifdef EASY_HISTORY
+
+# ifndef HISTFILE
+# ifdef OS2
+# define HISTFILE "history.ksh"
+# else /* OS2 */
+# define HISTFILE ".pdksh_history"
+# endif /* OS2 */
+# endif
+
+# else
+/* Defines and includes for the complicated case */
+
+# include <sys/file.h>
+# include <sys/mman.h>
+
+/*
+ * variables for handling the data file
+ */
+static int histfd;
+static int hsize;
+
+static int hist_count_lines ARGS((unsigned char *, int));
+static int hist_shrink ARGS((unsigned char *, int));
+static unsigned char *hist_skip_back ARGS((unsigned char *,int *,int));
+static void histload ARGS((Source *, unsigned char *, int));
+static void histinsert ARGS((Source *, int, unsigned char *));
+static void writehistfile ARGS((int, char *));
+static int sprinkle ARGS((int));
+
+# ifdef MAP_FILE
+# define MAP_FLAGS (MAP_FILE|MAP_PRIVATE)
+# else
+# define MAP_FLAGS MAP_PRIVATE
+# endif
+
+# endif /* of EASY_HISTORY */
+
+static int hist_execute ARGS((char *cmd));
+static int hist_replace ARGS((char **hp, const char *pat, const char *rep,
+ int global));
+static char **hist_get ARGS((const char *str, int approx, int allow_cur));
+static char **hist_get_newest ARGS((int allow_cur));
+static char **hist_get_oldest ARGS(());
+static void histbackup ARGS((void));
+
+static char **current; /* current postition in history[] */
+static int curpos; /* current index in history[] */
+static char *hname; /* current name of history file */
+static int hstarted; /* set after hist_init() called */
+static Source *hist_source;
+
+
+int
+c_fc(wp)
+ char **wp;
+{
+ struct shf *shf;
+ struct temp UNINITIALIZED(*tf);
+ char *p, *editor = (char *) 0;
+ int gflag = 0, lflag = 0, nflag = 0, sflag = 0, rflag = 0;
+ int optc;
+ char *first = (char *) 0, *last = (char *) 0;
+ char **hfirst, **hlast, **hp;
+
+ while ((optc = ksh_getopt(wp, &builtin_opt, "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != EOF)
+ switch (optc) {
+ case 'e':
+ p = builtin_opt.optarg;
+ if (strcmp(p, "-") == 0)
+ sflag++;
+ else {
+ editor = str_nsave(p, strlen(p) + 4, ATEMP);
+ strcat(editor, " $_");
+ }
+ break;
+ case 'g': /* non-at&t ksh */
+ gflag++;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 'n':
+ nflag++;
+ break;
+ case 'r':
+ rflag++;
+ break;
+ case 's': /* posix version of -e - */
+ sflag++;
+ break;
+ /* kludge city - accept -num as -- -num (kind of) */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ p = shf_smprintf("-%c%s",
+ optc, builtin_opt.optarg);
+ if (!first)
+ first = p;
+ else if (!last)
+ last = p;
+ else {
+ bi_errorf("too many arguments");
+ return 1;
+ }
+ break;
+ case '?':
+ return 1;
+ }
+ wp += builtin_opt.optind;
+
+ /* Substitute and execute command */
+ if (sflag) {
+ char *pat = (char *) 0, *rep = (char *) 0;
+
+ if (editor || lflag || nflag || rflag) {
+ bi_errorf("can't use -e, -l, -n, -r with -s (-e -)");
+ return 1;
+ }
+
+ /* Check for pattern replacement argument */
+ if (*wp && **wp && (p = strchr(*wp + 1, '='))) {
+ pat = str_save(*wp, ATEMP);
+ p = pat + (p - *wp);
+ *p++ = '\0';
+ rep = p;
+ wp++;
+ }
+ /* Check for search prefix */
+ if (!first && (first = *wp))
+ wp++;
+ if (last || *wp) {
+ bi_errorf("too many arguments");
+ return 1;
+ }
+
+ hp = first ? hist_get(first, FALSE, FALSE)
+ : hist_get_newest(FALSE);
+ if (!hp)
+ return 1;
+ return hist_replace(hp, pat, rep, gflag);
+ }
+
+ if (editor && (lflag || nflag)) {
+ bi_errorf("can't use -l, -n with -e");
+ return 1;
+ }
+
+ if (!first && (first = *wp))
+ wp++;
+ if (!last && (last = *wp))
+ wp++;
+ if (*wp) {
+ bi_errorf("too many arguments");
+ return 1;
+ }
+ if (!first) {
+ hfirst = lflag ? hist_get("-16", TRUE, TRUE)
+ : hist_get_newest(FALSE);
+ if (!hfirst)
+ return 1;
+ /* can't fail if hfirst didn't fail */
+ hlast = hist_get_newest(FALSE);
+ } else {
+ /* POSIX says not an error if first/last out of bounds
+ * when range is specified; at&t ksh and pdksh allow out of
+ * bounds for -l as well.
+ */
+ hfirst = hist_get(first, (lflag || last) ? TRUE : FALSE,
+ lflag ? TRUE : FALSE);
+ if (!hfirst)
+ return 1;
+ hlast = last ? hist_get(last, TRUE, lflag ? TRUE : FALSE)
+ : (lflag ? hist_get_newest(FALSE) : hfirst);
+ if (!hlast)
+ return 1;
+ }
+ if (hfirst > hlast) {
+ char **temp;
+
+ temp = hfirst; hfirst = hlast; hlast = temp;
+ rflag = !rflag; /* POSIX */
+ }
+
+ /* List history */
+ if (lflag) {
+ char *s, *t;
+ const char *nfmt = nflag ? "\t" : "%d\t";
+
+ for (hp = rflag ? hlast : hfirst;
+ hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)
+ {
+ shf_fprintf(shl_stdout, nfmt,
+ hist_source->line - (int) (histptr - hp));
+ /* print multi-line commands correctly */
+ for (s = *hp; (t = strchr(s, '\n')); s = t)
+ shf_fprintf(shl_stdout, "%.*s\t", ++t - s, s);
+ shf_fprintf(shl_stdout, "%s\n", s);
+ }
+ shf_flush(shl_stdout);
+ return 0;
+ }
+
+ /* Run editor on selected lines, then run resulting commands */
+
+ tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps);
+ if (!(shf = tf->shf)) {
+ bi_errorf("cannot create temp file %s - %s",
+ tf->name, strerror(errno));
+ return 1;
+ }
+ for (hp = rflag ? hlast : hfirst;
+ hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1)
+ shf_fprintf(shf, "%s\n", *hp);
+ if (shf_close(shf) == EOF) {
+ bi_errorf("error writing temporary file - %s", strerror(errno));
+ return 1;
+ }
+
+ /* Ignore setstr errors here (arbitrary) */
+ setstr(local("_", FALSE), tf->name, KSH_RETURN_ERROR);
+
+ /* XXX: source should not get trashed by this.. */
+ {
+ Source *sold = source;
+ int ret;
+
+ ret = command(editor ? editor : "${FCEDIT:-/bin/ed} $_");
+ source = sold;
+ if (ret)
+ return ret;
+ }
+
+ {
+ struct stat statb;
+ XString xs;
+ char *xp;
+ int n;
+
+ if (!(shf = shf_open(tf->name, O_RDONLY, 0, 0))) {
+ bi_errorf("cannot open temp file %s", tf->name);
+ return 1;
+ }
+
+ n = fstat(shf_fileno(shf), &statb) < 0 ? 128
+ : statb.st_size + 1;
+ Xinit(xs, xp, n, hist_source->areap);
+ while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) {
+ xp += n;
+ if (Xnleft(xs, xp) <= 0)
+ XcheckN(xs, xp, Xlength(xs, xp));
+ }
+ if (n < 0) {
+ bi_errorf("error reading temp file %s - %s",
+ tf->name, strerror(shf_errno(shf)));
+ shf_close(shf);
+ return 1;
+ }
+ shf_close(shf);
+ *xp = '\0';
+ strip_nuls(Xstring(xs, xp), Xlength(xs, xp));
+ return hist_execute(Xstring(xs, xp));
+ }
+}
+
+/* Save cmd in history, execute cmd (cmd gets trashed) */
+static int
+hist_execute(cmd)
+ char *cmd;
+{
+ Source *sold;
+ int ret;
+ char *p, *q;
+
+ histbackup();
+
+ for (p = cmd; p; p = q) {
+ if ((q = strchr(p, '\n'))) {
+ *q++ = '\0'; /* kill the newline */
+ if (!*q) /* ignore trailing newline */
+ q = (char *) 0;
+ }
+#ifdef EASY_HISTORY
+ if (p != cmd)
+ histappend(p, TRUE);
+ else
+#endif /* EASY_HISTORY */
+ histsave(++(hist_source->line), p, 1);
+
+ shellf("%s\n", p); /* POSIX doesn't say this is done... */
+ if ((p = q)) /* restore \n (trailing \n not restored) */
+ q[-1] = '\n';
+ }
+
+ /* Commands are executed here instead of pushing them onto the
+ * input 'cause posix says the redirection and variable assignments
+ * in
+ * X=y fc -e - 42 2> /dev/null
+ * are to effect the repeated commands environment.
+ */
+ /* XXX: source should not get trashed by this.. */
+ sold = source;
+ ret = command(cmd);
+ source = sold;
+ return ret;
+}
+
+static int
+hist_replace(hp, pat, rep, global)
+ char **hp;
+ const char *pat;
+ const char *rep;
+ int global;
+{
+ char *line;
+
+ if (!pat)
+ line = str_save(*hp, ATEMP);
+ else {
+ char *s, *s1;
+ int pat_len = strlen(pat);
+ int rep_len = strlen(rep);
+ int len;
+ XString xs;
+ char *xp;
+ int any_subst = 0;
+
+ Xinit(xs, xp, 128, ATEMP);
+ for (s = *hp; (s1 = strstr(s, pat))
+ && (!any_subst || global) ; s = s1 + pat_len)
+ {
+ any_subst = 1;
+ len = s1 - s;
+ XcheckN(xs, xp, len + rep_len);
+ memcpy(xp, s, len); /* first part */
+ xp += len;
+ memcpy(xp, rep, rep_len); /* replacement */
+ xp += rep_len;
+ }
+ if (!any_subst) {
+ bi_errorf("substitution failed");
+ return 1;
+ }
+ len = strlen(s) + 1;
+ XcheckN(xs, xp, len);
+ memcpy(xp, s, len);
+ xp += len;
+ line = Xclose(xs, xp);
+ }
+ return hist_execute(line);
+}
+
+/*
+ * get pointer to history given pattern
+ * pattern is a number or string
+ */
+static char **
+hist_get(str, approx, allow_cur)
+ const char *str;
+ int approx;
+ int allow_cur;
+{
+ char **hp = (char **) 0;
+ int n;
+
+ if (getn(str, &n)) {
+ hp = histptr + (n < 0 ? n : (n - hist_source->line));
+ if (hp < history) {
+ if (approx)
+ hp = hist_get_oldest();
+ else {
+ bi_errorf("%s: not in history", str);
+ hp = (char **) 0;
+ }
+ } else if (hp > histptr) {
+ if (approx)
+ hp = hist_get_newest(allow_cur);
+ else {
+ bi_errorf("%s: not in history", str);
+ hp = (char **) 0;
+ }
+ } else if (!allow_cur && hp == histptr) {
+ bi_errorf("%s: invalid range", str);
+ hp = (char **) 0;
+ }
+ } else {
+ int anchored = *str == '?' ? (++str, 0) : 1;
+
+ /* the -1 is to avoid the current fc command */
+ n = findhist(histptr - history - 1, 0, str, anchored);
+ if (n < 0) {
+ bi_errorf("%s: not in history", str);
+ hp = (char **) 0;
+ } else
+ hp = &history[n];
+ }
+ return hp;
+}
+
+/* Return a pointer to the newest command in the history */
+static char **
+hist_get_newest(allow_cur)
+ int allow_cur;
+{
+ if (histptr < history || (!allow_cur && histptr == history)) {
+ bi_errorf("no history (yet)");
+ return (char **) 0;
+ }
+ if (allow_cur)
+ return histptr;
+ return histptr - 1;
+}
+
+/* Return a pointer to the newest command in the history */
+static char **
+hist_get_oldest()
+{
+ if (histptr <= history) {
+ bi_errorf("no history (yet)");
+ return (char **) 0;
+ }
+ return history;
+}
+
+/******************************/
+/* Back up over last histsave */
+/******************************/
+static void
+histbackup()
+{
+ static int last_line = -1;
+
+ if (histptr >= history && last_line != hist_source->line) {
+ hist_source->line--;
+ afree((void*)*histptr, APERM);
+ histptr--;
+ last_line = hist_source->line;
+ }
+}
+
+/*
+ * Return the current position.
+ */
+char **
+histpos()
+{
+ return current;
+}
+
+int
+histN()
+{
+ return curpos;
+}
+
+int
+histnum(n)
+ int n;
+{
+ int last = histptr - history;
+
+ if (n < 0 || n >= last) {
+ current = histptr;
+ curpos = last;
+ return last;
+ } else {
+ current = &history[n];
+ curpos = n;
+ return n;
+ }
+}
+
+/*
+ * This will become unecessary if hist_get is modified to allow
+ * searching from positions other than the end, and in either
+ * direction.
+ */
+int
+findhist(start, fwd, str, anchored)
+ int start;
+ int fwd;
+ const char *str;
+ int anchored;
+{
+ char **hp;
+ int maxhist = histptr - history;
+ int incr = fwd ? 1 : -1;
+ int len = strlen(str);
+
+ if (start < 0 || start >= maxhist)
+ start = maxhist;
+
+ hp = &history[start];
+ for (; hp >= history && hp <= histptr; hp += incr)
+ if ((anchored && strncmp(*hp, str, len) == 0)
+ || (!anchored && strstr(*hp, str)))
+ return hp - history;
+
+ return -1;
+}
+
+/*
+ * set history
+ * this means reallocating the dataspace
+ */
+void
+sethistsize(n)
+ int n;
+{
+ if (n > 0 && n != histsize) {
+ int cursize = histptr - history;
+
+ /* save most recent history */
+ if (n < cursize) {
+ memmove(history, histptr - n, n * sizeof(char *));
+ cursize = n;
+ }
+
+ history = (char **)aresize(history, n*sizeof(char *), APERM);
+
+ histsize = n;
+ histptr = history + cursize;
+ }
+}
+
+/*
+ * set history file
+ * This can mean reloading/resetting/starting history file
+ * maintenance
+ */
+void
+sethistfile(name)
+ const char *name;
+{
+ /* if not started then nothing to do */
+ if (hstarted == 0)
+ return;
+
+ /* if the name is the same as the name we have */
+ if (hname && strcmp(hname, name) == 0)
+ return;
+
+ /*
+ * its a new name - possibly
+ */
+# ifdef EASY_HISTORY
+ if (hname) {
+ afree(hname, APERM);
+ hname = NULL;
+ }
+# else
+ if (histfd) {
+ /* yes the file is open */
+ (void) close(histfd);
+ histfd = 0;
+ hsize = 0;
+ afree(hname, APERM);
+ hname = NULL;
+ /* let's reset the history */
+ histptr = history - 1;
+ hist_source->line = 0;
+ }
+# endif
+
+ hist_init(hist_source);
+}
+
+/*
+ * initialise the history vector
+ */
+void
+init_histvec()
+{
+ if (history == (char **)NULL) {
+ histsize = HISTORYSIZE;
+ history = (char **)alloc(histsize*sizeof (char *), APERM);
+ histptr = history - 1;
+ }
+}
+
+# ifdef EASY_HISTORY
+/*
+ * save command in history
+ */
+void
+histsave(lno, cmd, dowrite)
+ int lno; /* ignored (compatibility with COMPLEX_HISTORY) */
+ const char *cmd;
+ int dowrite; /* ignored (compatibility with COMPLEX_HISTORY) */
+{
+ register char **hp = histptr;
+ char *cp;
+
+ if (++hp >= history + histsize) { /* remove oldest command */
+ afree((void*)history[0], APERM);
+ memmove(history, history + 1,
+ sizeof(history[0]) * (histsize - 1));
+ hp = &history[histsize - 1];
+ }
+ *hp = str_save(cmd, APERM);
+ /* trash trailing newline but allow imbedded newlines */
+ cp = *hp + strlen(*hp);
+ if (cp > *hp && cp[-1] == '\n')
+ cp[-1] = '\0';
+ histptr = hp;
+}
+
+/*
+ * Append an entry to the last saved command. Used for multiline
+ * commands
+ */
+void
+histappend(cmd, nl_separate)
+ const char *cmd;
+ int nl_separate;
+{
+ int hlen, clen;
+ char *p;
+
+ hlen = strlen(*histptr);
+ clen = strlen(cmd);
+ if (clen > 0 && cmd[clen-1] == '\n')
+ clen--;
+ p = *histptr = (char *) aresize(*histptr, hlen + clen + 2, APERM);
+ p += hlen;
+ if (nl_separate)
+ *p++ = '\n';
+ memcpy(p, cmd, clen);
+ p[clen] = '\0';
+}
+
+/*
+ * 92-04-25 <sjg@zen>
+ * A simple history file implementation.
+ * At present we only save the history when we exit.
+ * This can cause problems when there are multiple shells are
+ * running under the same user-id. The last shell to exit gets
+ * to save its history.
+ */
+void
+hist_init(s)
+ Source *s;
+{
+ char *f;
+ FILE *fh;
+
+ if (Flag(FTALKING) == 0)
+ return;
+
+ hstarted = 1;
+
+ hist_source = s;
+
+ if ((f = str_val(global("HISTFILE"))) == NULL || *f == '\0') {
+# if 1 /* Don't use history file unless the user asks for it */
+ hname = NULL;
+ return;
+# else
+ char *home = str_val(global("HOME"));
+ int len;
+
+ if (home == NULL)
+ home = null;
+ f = HISTFILE;
+ hname = alloc(len = strlen(home) + strlen(f) + 2, APERM);
+ shf_snprintf(hname, len, "%s/%s", home, f);
+# endif
+ } else
+ hname = str_save(f, APERM);
+
+ if ((fh = fopen(hname, "r"))) {
+ int pos = 0, nread = 0;
+ int contin = 0; /* continuation of previous command */
+ char *end;
+ char hline[LINE + 1];
+
+ while (1) {
+ if (pos >= nread) {
+ pos = 0;
+ nread = fread(hline, 1, LINE, fh);
+ if (nread <= 0)
+ break;
+ hline[nread] = '\0';
+ }
+ end = strchr(hline + pos, 0); /* will always succeed */
+ if (contin)
+ histappend(hline + pos, 0);
+ else {
+ hist_source->line++;
+ histsave(0, hline + pos, 0);
+ }
+ pos = end - hline + 1;
+ contin = end == &hline[nread];
+ }
+ fclose(fh);
+ }
+}
+
+/*
+ * save our history.
+ * We check that we do not have more than we are allowed.
+ * If the history file is read-only we do nothing.
+ * Handy for having all shells start with a useful history set.
+ */
+
+void
+hist_finish()
+{
+ static int once;
+ FILE *fh;
+ register int i;
+ register char **hp;
+
+ if (once++)
+ return;
+ /* check how many we have */
+ i = histptr - history;
+ if (i >= histsize)
+ hp = &histptr[-histsize];
+ else
+ hp = history;
+ if (hname && (fh = fopen(hname, "w")))
+ {
+ for (i = 0; hp + i <= histptr && hp[i]; i++)
+ fprintf(fh, "%s%c", hp[i], '\0');
+ fclose(fh);
+ }
+}
+
+# else /* EASY_HISTORY */
+
+/*
+ * Routines added by Peter Collinson BSDI(Europe)/Hillside Systems to
+ * a) permit HISTSIZE to control number of lines of history stored
+ * b) maintain a physical history file
+ *
+ * It turns out that there is a lot of ghastly hackery here
+ */
+
+
+/*
+ * save command in history
+ */
+void
+histsave(lno, cmd, dowrite)
+ int lno;
+ const char *cmd;
+ int dowrite;
+{
+ register char **hp;
+ char *c, *cp;
+
+ c = str_save(cmd, APERM);
+ if ((cp = strchr(c, '\n')) != NULL)
+ *cp = '\0';
+
+ if (histfd && dowrite)
+ writehistfile(lno, c);
+
+ hp = histptr;
+
+ if (++hp >= history + histsize) { /* remove oldest command */
+ afree((void*)*history, APERM);
+ for (hp = history; hp < history + histsize - 1; hp++)
+ hp[0] = hp[1];
+ }
+ *hp = c;
+ histptr = hp;
+}
+
+/*
+ * Write history data to a file nominated by HISTFILE
+ * if HISTFILE is unset then history still happens, but
+ * the data is not written to a file
+ * All copies of ksh looking at the file will maintain the
+ * same history. This is ksh behaviour.
+ *
+ * This stuff uses mmap()
+ * if your system ain't got it - then you'll have to undef HISTORYFILE
+ */
+
+/*
+ * Open a history file
+ * Format is:
+ * Bytes 1, 2: HMAGIC - just to check that we are dealing with
+ * the correct object
+ * Then follows a number of stored commands
+ * Each command is
+ * <command byte><command number(4 bytes)><bytes><null>
+ */
+# define HMAGIC1 0xab
+# define HMAGIC2 0xcd
+# define COMMAND 0xff
+
+void
+hist_init(s)
+ Source *s;
+{
+ unsigned char *base;
+ int lines;
+ int fd;
+
+ if (Flag(FTALKING) == 0)
+ return;
+
+ hstarted = 1;
+
+ hist_source = s;
+
+ hname = str_val(global("HISTFILE"));
+ if (hname == NULL)
+ return;
+ hname = str_save(hname, APERM);
+
+ retry:
+ /* we have a file and are interactive */
+ if ((fd = open(hname, O_RDWR|O_CREAT|O_APPEND, 0600)) < 0)
+ return;
+
+ histfd = savefd(fd, 0);
+
+ (void) flock(histfd, LOCK_EX);
+
+ hsize = lseek(histfd, 0L, SEEK_END);
+
+ if (hsize == 0) {
+ /* add magic */
+ if (sprinkle(histfd)) {
+ hist_finish();
+ return;
+ }
+ }
+ else if (hsize > 0) {
+ /*
+ * we have some data
+ */
+ base = (unsigned char *)mmap(0, hsize, PROT_READ, MAP_FLAGS, histfd, 0);
+ /*
+ * check on its validity
+ */
+ if ((int)base == -1 || *base != HMAGIC1 || base[1] != HMAGIC2) {
+ if ((int)base != -1)
+ munmap((caddr_t)base, hsize);
+ hist_finish();
+ unlink(hname);
+ goto retry;
+ }
+ if (hsize > 2) {
+ lines = hist_count_lines(base+2, hsize-2);
+ if (lines > histsize) {
+ /* we need to make the file smaller */
+ if (hist_shrink(base, hsize))
+ unlink(hname);
+ munmap((caddr_t)base, hsize);
+ hist_finish();
+ goto retry;
+ }
+ }
+ histload(hist_source, base+2, hsize-2);
+ munmap((caddr_t)base, hsize);
+ }
+ (void) flock(histfd, LOCK_UN);
+ hsize = lseek(histfd, 0L, SEEK_END);
+}
+
+typedef enum state {
+ shdr, /* expecting a header */
+ sline, /* looking for a null byte to end the line */
+ sn1, /* bytes 1 to 4 of a line no */
+ sn2, sn3, sn4,
+} State;
+
+static int
+hist_count_lines(base, bytes)
+ register unsigned char *base;
+ register int bytes;
+{
+ State state = shdr;
+ register lines = 0;
+
+ while (bytes--) {
+ switch (state)
+ {
+ case shdr:
+ if (*base == COMMAND)
+ state = sn1;
+ break;
+ case sn1:
+ state = sn2; break;
+ case sn2:
+ state = sn3; break;
+ case sn3:
+ state = sn4; break;
+ case sn4:
+ state = sline; break;
+ case sline:
+ if (*base == '\0')
+ lines++, state = shdr;
+ }
+ base++;
+ }
+ return lines;
+}
+
+/*
+ * Shrink the history file to histsize lines
+ */
+static int
+hist_shrink(oldbase, oldbytes)
+ unsigned char *oldbase;
+ int oldbytes;
+{
+ int fd;
+ char nfile[1024];
+ struct stat statb;
+ unsigned char *nbase = oldbase;
+ int nbytes = oldbytes;
+
+ nbase = hist_skip_back(nbase, &nbytes, histsize);
+ if (nbase == NULL)
+ return 1;
+ if (nbase == oldbase)
+ return 0;
+
+ /*
+ * create temp file
+ */
+ (void) shf_snprintf(nfile, sizeof(nfile), "%s.%d", hname, procpid);
+ if ((fd = creat(nfile, 0600)) < 0)
+ return 1;
+
+ if (sprinkle(fd)) {
+ close(fd);
+ unlink(nfile);
+ return 1;
+ }
+ if (write(fd, nbase, nbytes) != nbytes) {
+ close(fd);
+ unlink(nfile);
+ return 1;
+ }
+ /*
+ * worry about who owns this file
+ */
+ if (fstat(histfd, &statb) >= 0)
+ fchown(fd, statb.st_uid, statb.st_gid);
+ close(fd);
+
+ /*
+ * rename
+ */
+ if (rename(nfile, hname) < 0)
+ return 1;
+ return 0;
+}
+
+
+/*
+ * find a pointer to the data `no' back from the end of the file
+ * return the pointer and the number of bytes left
+ */
+static unsigned char *
+hist_skip_back(base, bytes, no)
+ unsigned char *base;
+ int *bytes;
+ int no;
+{
+ register int lines = 0;
+ register unsigned char *ep;
+
+ for (ep = base + *bytes; --ep > base; ) {
+ /* this doesn't really work: the 4 byte line number that is
+ * encoded after the COMMAND byte can itself contain the
+ * COMMAND byte....
+ */
+ for (; ep > base && *ep != COMMAND; ep--)
+ ;
+ if (ep == base)
+ break;
+ if (++lines == no) {
+ *bytes = *bytes - ((char *)ep - (char *)base);
+ return ep;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * load the history structure from the stored data
+ */
+static void
+histload(s, base, bytes)
+ Source *s;
+ register unsigned char *base;
+ register int bytes;
+{
+ State state;
+ int lno;
+ unsigned char *line;
+
+ for (state = shdr; bytes-- > 0; base++) {
+ switch (state) {
+ case shdr:
+ if (*base == COMMAND)
+ state = sn1;
+ break;
+ case sn1:
+ lno = (((*base)&0xff)<<24);
+ state = sn2;
+ break;
+ case sn2:
+ lno |= (((*base)&0xff)<<16);
+ state = sn3;
+ break;
+ case sn3:
+ lno |= (((*base)&0xff)<<8);
+ state = sn4;
+ break;
+ case sn4:
+ lno |= (*base)&0xff;
+ line = base+1;
+ state = sline;
+ break;
+ case sline:
+ if (*base == '\0') {
+ /* worry about line numbers */
+ if (histptr >= history && lno-1 != s->line) {
+ /* a replacement ? */
+ histinsert(s, lno, line);
+ }
+ else {
+ s->line = lno;
+ histsave(lno, (char *)line, 0);
+ }
+ state = shdr;
+ }
+ }
+ }
+}
+
+/*
+ * Insert a line into the history at a specified number
+ */
+static void
+histinsert(s, lno, line)
+ Source *s;
+ int lno;
+ unsigned char *line;
+{
+ register char **hp;
+
+ if (lno >= s->line-(histptr-history) && lno <= s->line) {
+ hp = &histptr[lno-s->line];
+ if (*hp)
+ afree((void*)*hp, APERM);
+ *hp = str_save((char *)line, APERM);
+ }
+}
+
+/*
+ * write a command to the end of the history file
+ * This *MAY* seem easy but it's also necessary to check
+ * that the history file has not changed in size.
+ * If it has - then some other shell has written to it
+ * and we should read those commands to update our history
+ */
+static void
+writehistfile(lno, cmd)
+ int lno;
+ char *cmd;
+{
+ int sizenow;
+ unsigned char *base;
+ unsigned char *new;
+ int bytes;
+ char hdr[5];
+
+ (void) flock(histfd, LOCK_EX);
+ sizenow = lseek(histfd, 0L, SEEK_END);
+ if (sizenow != hsize) {
+ /*
+ * Things have changed
+ */
+ if (sizenow > hsize) {
+ /* someone has added some lines */
+ bytes = sizenow - hsize;
+ base = (unsigned char *)mmap(0, sizenow, PROT_READ, MAP_FLAGS, histfd, 0);
+ if ((int)base == -1)
+ goto bad;
+ new = base + hsize;
+ if (*new != COMMAND) {
+ munmap((caddr_t)base, sizenow);
+ goto bad;
+ }
+ hist_source->line--;
+ histload(hist_source, new, bytes);
+ hist_source->line++;
+ lno = hist_source->line;
+ munmap((caddr_t)base, sizenow);
+ hsize = sizenow;
+ } else {
+ /* it has shrunk */
+ /* but to what? */
+ /* we'll give up for now */
+ goto bad;
+ }
+ }
+ /*
+ * we can write our bit now
+ */
+ hdr[0] = COMMAND;
+ hdr[1] = (lno>>24)&0xff;
+ hdr[2] = (lno>>16)&0xff;
+ hdr[3] = (lno>>8)&0xff;
+ hdr[4] = lno&0xff;
+ (void) write(histfd, hdr, 5);
+ (void) write(histfd, cmd, strlen(cmd)+1);
+ hsize = lseek(histfd, 0L, SEEK_END);
+ (void) flock(histfd, LOCK_UN);
+ return;
+bad:
+ hist_finish();
+}
+
+void
+hist_finish()
+{
+ (void) flock(histfd, LOCK_UN);
+ (void) close(histfd);
+ histfd = 0;
+}
+
+/*
+ * add magic to the history file
+ */
+static int
+sprinkle(fd)
+ int fd;
+{
+ static char mag[] = { HMAGIC1, HMAGIC2 };
+
+ return(write(fd, mag, 2) != 2);
+}
+
+# endif
+#else /* HISTORY */
+
+/* No history to be compiled in: dummy routines to avoid lots more ifdefs */
+void
+init_histvec()
+{
+}
+void
+hist_init(s)
+ Source *s;
+{
+}
+void
+hist_finish()
+{
+}
+void
+histsave(lno, cmd, dowrite)
+ int lno;
+ const char *cmd;
+ int dowrite;
+{
+ errorf("history not enabled");
+}
+#endif /* HISTORY */
diff --git a/shells/pdksh/files/install-sh b/shells/pdksh/files/install-sh
new file mode 100755
index 00000000000..0ff4b6a08e8
--- /dev/null
+++ b/shells/pdksh/files/install-sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+ echo "install: no destination specified"
+ exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+ dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0
diff --git a/shells/pdksh/files/io.c b/shells/pdksh/files/io.c
new file mode 100644
index 00000000000..a490aa8b5ba
--- /dev/null
+++ b/shells/pdksh/files/io.c
@@ -0,0 +1,551 @@
+/*
+ * shell buffered IO and formatted output
+ */
+
+#include <ctype.h>
+#include "sh.h"
+#include "ksh_stat.h"
+
+static int initio_done;
+
+/*
+ * formatted output functions
+ */
+
+
+/* A shell error occured (eg, syntax error, etc.) */
+void
+#ifdef HAVE_PROTOTYPES
+errorf(const char *fmt, ...)
+#else
+errorf(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list va;
+
+ shl_stdout_ok = 0; /* debugging: note that stdout not valid */
+ exstat = 1;
+ if (*fmt) {
+ error_prefix(TRUE);
+ SH_VA_START(va, fmt);
+ shf_vfprintf(shl_out, fmt, va);
+ va_end(va);
+ shf_putchar('\n', shl_out);
+ }
+ shf_flush(shl_out);
+ unwind(LERROR);
+}
+
+/* like errorf(), but no unwind is done */
+void
+#ifdef HAVE_PROTOTYPES
+warningf(int fileline, const char *fmt, ...)
+#else
+warningf(fileline, fmt, va_alist)
+ int fileline;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list va;
+
+ error_prefix(fileline);
+ SH_VA_START(va, fmt);
+ shf_vfprintf(shl_out, fmt, va);
+ va_end(va);
+ shf_putchar('\n', shl_out);
+ shf_flush(shl_out);
+}
+
+/* Used by built-in utilities to prefix shell and utility name to message
+ * (also unwinds environments for special builtins).
+ */
+void
+#ifdef HAVE_PROTOTYPES
+bi_errorf(const char *fmt, ...)
+#else
+bi_errorf(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list va;
+
+ shl_stdout_ok = 0; /* debugging: note that stdout not valid */
+ exstat = 1;
+ if (*fmt) {
+ error_prefix(TRUE);
+ /* not set when main() calls parse_args() */
+ if (builtin_argv0)
+ shf_fprintf(shl_out, "%s: ", builtin_argv0);
+ SH_VA_START(va, fmt);
+ shf_vfprintf(shl_out, fmt, va);
+ va_end(va);
+ shf_putchar('\n', shl_out);
+ }
+ shf_flush(shl_out);
+ /* POSIX special builtins and ksh special builtins cause
+ * non-interactive shells to exit.
+ * XXX odd use of KEEPASN; also may not want LERROR here
+ */
+ if ((builtin_flag & SPEC_BI)
+ || (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
+ {
+ builtin_argv0 = (char *) 0;
+ unwind(LERROR);
+ }
+}
+
+/* Called when something that shouldn't happen does */
+void
+#ifdef HAVE_PROTOTYPES
+internal_errorf(int jump, const char *fmt, ...)
+#else
+internal_errorf(jump, fmt, va_alist)
+ int jump;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list va;
+
+ error_prefix(TRUE);
+ shf_fprintf(shl_out, "internal error: ");
+ SH_VA_START(va, fmt);
+ shf_vfprintf(shl_out, fmt, va);
+ va_end(va);
+ shf_putchar('\n', shl_out);
+ shf_flush(shl_out);
+ if (jump)
+ unwind(LERROR);
+}
+
+/* used by error reporting functions to print "ksh: .kshrc[25]: " */
+void
+error_prefix(fileline)
+ int fileline;
+{
+ /* Avoid foo: foo[2]: ... */
+ if (!fileline || !source || !source->file
+ || strcmp(source->file, kshname) != 0)
+ shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
+ if (fileline && source && source->file != NULL) {
+ shf_fprintf(shl_out, "%s[%d]: ", source->file,
+ source->errline > 0 ? source->errline : source->line);
+ source->errline = 0;
+ }
+}
+
+/* printf to shl_out (stderr) with flush */
+void
+#ifdef HAVE_PROTOTYPES
+shellf(const char *fmt, ...)
+#else
+shellf(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list va;
+
+ if (!initio_done) /* shl_out may not be set up yet... */
+ return;
+ SH_VA_START(va, fmt);
+ shf_vfprintf(shl_out, fmt, va);
+ va_end(va);
+ shf_flush(shl_out);
+}
+
+/* printf to shl_stdout (stdout) */
+void
+#ifdef HAVE_PROTOTYPES
+shprintf(const char *fmt, ...)
+#else
+shprintf(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list va;
+
+ if (!shl_stdout_ok)
+ internal_errorf(1, "shl_stdout not valid");
+ SH_VA_START(va, fmt);
+ shf_vfprintf(shl_stdout, fmt, va);
+ va_end(va);
+}
+
+#ifdef KSH_DEBUG
+static struct shf *kshdebug_shf;
+
+void
+kshdebug_init_()
+{
+ if (kshdebug_shf)
+ shf_close(kshdebug_shf);
+ kshdebug_shf = shf_open("/tmp/ksh-debug.log",
+ O_WRONLY|O_APPEND|O_CREAT, 0600,
+ SHF_WR|SHF_MAPHI);
+ if (kshdebug_shf) {
+ shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
+ shf_flush(kshdebug_shf);
+ }
+}
+
+/* print to debugging log */
+void
+# ifdef HAVE_PROTOTYPES
+kshdebug_printf_(const char *fmt, ...)
+# else
+kshdebug_printf_(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+# endif
+{
+ va_list va;
+
+ if (!kshdebug_shf)
+ return;
+ SH_VA_START(va, fmt);
+ shf_fprintf(kshdebug_shf, "[%d] ", getpid());
+ shf_vfprintf(kshdebug_shf, fmt, va);
+ va_end(va);
+ shf_flush(kshdebug_shf);
+}
+
+void
+kshdebug_dump_(str, mem, nbytes)
+ const char *str;
+ const void *mem;
+ int nbytes;
+{
+ int i, j;
+ int nprow = 16;
+
+ if (!kshdebug_shf)
+ return;
+ shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
+ for (i = 0; i < nbytes; i += nprow) {
+ char c = '\t';
+ for (j = 0; j < nprow && i + j < nbytes; j++) {
+ shf_fprintf(kshdebug_shf, "%c%02x",
+ c, ((const unsigned char *) mem)[i + j]);
+ c = ' ';
+ }
+ shf_fprintf(kshdebug_shf, "\n");
+ }
+ shf_flush(kshdebug_shf);
+}
+#endif /* KSH_DEBUG */
+
+/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
+int
+can_seek(fd)
+ int fd;
+{
+ struct stat statb;
+
+ return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
+ SHF_UNBUF : 0;
+}
+
+struct shf shf_iob[3];
+
+void
+initio()
+{
+ shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
+ shf_fdopen(2, SHF_WR, shl_out);
+ shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
+ initio_done = 1;
+ kshdebug_init();
+}
+
+/* A dup2() with error checking */
+int
+ksh_dup2(ofd, nfd, errok)
+ int ofd;
+ int nfd;
+ int errok;
+{
+ int ret = dup2(ofd, nfd);
+
+ if (ret < 0 && errno != EBADF && !errok)
+ errorf("too many files open in shell");
+
+#ifdef DUP2_BROKEN
+ /* Ultrix systems like to preserve the close-on-exec flag */
+ if (ret >= 0)
+ (void) fcntl(nfd, F_SETFD, 0);
+#endif /* DUP2_BROKEN */
+
+ return ret;
+}
+
+/*
+ * move fd from user space (0<=fd<10) to shell space (fd>=10),
+ * set close-on-exec flag.
+ */
+int
+savefd(fd, noclose)
+ int fd;
+ int noclose;
+{
+ int nfd;
+
+ if (fd < FDBASE) {
+ nfd = ksh_dupbase(fd, FDBASE);
+ if (nfd < 0)
+ if (errno == EBADF)
+ return -1;
+ else
+ errorf("too many files open in shell");
+ if (!noclose)
+ close(fd);
+ } else
+ nfd = fd;
+ fd_clexec(nfd);
+ return nfd;
+}
+
+void
+restfd(fd, ofd)
+ int fd, ofd;
+{
+ if (fd == 2)
+ shf_flush(&shf_iob[fd]);
+ if (ofd < 0) /* original fd closed */
+ close(fd);
+ else {
+ ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
+ close(ofd);
+ }
+}
+
+void
+openpipe(pv)
+ register int *pv;
+{
+ if (pipe(pv) < 0)
+ errorf("can't create pipe - try again");
+ pv[0] = savefd(pv[0], 0);
+ pv[1] = savefd(pv[1], 0);
+}
+
+void
+closepipe(pv)
+ register int *pv;
+{
+ close(pv[0]);
+ close(pv[1]);
+}
+
+/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
+ * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
+ */
+int
+check_fd(name, mode, emsgp)
+ char *name;
+ int mode;
+ const char **emsgp;
+{
+ int fd, fl;
+
+ if (isdigit(name[0]) && !name[1]) {
+ fd = name[0] - '0';
+ if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
+ if (emsgp)
+ *emsgp = "bad file descriptor";
+ return -1;
+ }
+ fl &= O_ACCMODE;
+#ifdef OS2
+ if (mode == W_OK ) {
+ if (setmode(fd, O_TEXT) == -1) {
+ if (emsgp)
+ *emsgp = "couldn't set write mode";
+ return -1;
+ }
+ } else if (mode == R_OK)
+ if (setmode(fd, O_BINARY) == -1) {
+ if (emsgp)
+ *emsgp = "couldn't set read mode";
+ return -1;
+ }
+#else /* OS2 */
+ /* X_OK is a kludge to disable this check for dups (x<&1):
+ * historical shells never did this check (XXX don't know what
+ * posix has to say).
+ */
+ if (!(mode & X_OK) && fl != O_RDWR
+ && (((mode & R_OK) && fl != O_RDONLY)
+ || ((mode & W_OK) && fl != O_WRONLY)))
+ {
+ if (emsgp)
+ *emsgp = (fl == O_WRONLY) ?
+ "fd not open for reading"
+ : "fd not open for writing";
+ return -1;
+ }
+#endif /* OS2 */
+ return fd;
+ }
+#ifdef KSH
+ else if (name[0] == 'p' && !name[1])
+ return coproc_getfd(mode, emsgp);
+#endif /* KSH */
+ if (emsgp)
+ *emsgp = "illegal file descriptor name";
+ return -1;
+}
+
+#ifdef KSH
+/* Called once from main */
+void
+coproc_init()
+{
+ coproc.read = coproc.readw = coproc.write = -1;
+ coproc.njobs = 0;
+ coproc.id = 0;
+}
+
+/* Called by c_read() when eof is read - close fd if it is the co-process fd */
+void
+coproc_read_close(fd)
+ int fd;
+{
+ if (coproc.read >= 0 && fd == coproc.read) {
+ coproc_readw_close(fd);
+ close(coproc.read);
+ coproc.read = -1;
+ }
+}
+
+/* Called by c_read() and by iosetup() to close the other side of the
+ * read pipe, so reads will actually terminate.
+ */
+void
+coproc_readw_close(fd)
+ int fd;
+{
+ if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
+ close(coproc.readw);
+ coproc.readw = -1;
+ }
+}
+
+/* Called by c_print when a write to a fd fails with EPIPE and by iosetup
+ * when co-process input is dup'd
+ */
+void
+coproc_write_close(fd)
+ int fd;
+{
+ if (coproc.write >= 0 && fd == coproc.write) {
+ close(coproc.write);
+ coproc.write = -1;
+ }
+}
+
+/* Called to check for existance of/value of the co-process file descriptor.
+ * (Used by check_fd() and by c_read/c_print to deal with -p option).
+ */
+int
+coproc_getfd(mode, emsgp)
+ int mode;
+ const char **emsgp;
+{
+ int fd = (mode & R_OK) ? coproc.read : coproc.write;
+
+ if (fd >= 0)
+ return fd;
+ if (emsgp)
+ *emsgp = "no coprocess";
+ return -1;
+}
+
+/* called to close file descriptors related to the coprocess (if any)
+ * Should be called with SIGCHLD blocked.
+ */
+void
+coproc_cleanup(reuse)
+ int reuse;
+{
+ /* This to allow co-processes to share output pipe */
+ if (!reuse || coproc.readw < 0 || coproc.read < 0) {
+ if (coproc.read >= 0) {
+ close(coproc.read);
+ coproc.read = -1;
+ }
+ if (coproc.readw >= 0) {
+ close(coproc.readw);
+ coproc.readw = -1;
+ }
+ }
+ if (coproc.write >= 0) {
+ close(coproc.write);
+ coproc.write = -1;
+ }
+}
+#endif /* KSH */
+
+
+/*
+ * temporary files
+ */
+
+struct temp *
+maketemp(ap, type, tlist)
+ Area *ap;
+ Temp_type type;
+ struct temp **tlist;
+{
+ static unsigned int inc;
+ struct temp *tp;
+ int len;
+ int fd;
+ char *path;
+ const char *dir;
+
+ dir = tmpdir ? tmpdir : "/tmp";
+ /* The 20 + 20 is a paranoid worst case for pid/inc */
+ len = strlen(dir) + 3 + 20 + 20 + 1;
+ tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
+ tp->name = path = (char *) &tp[1];
+ tp->shf = (struct shf *) 0;
+ tp->type = type;
+ while (1) {
+ /* Note that temp files need to fit 8.3 DOS limits */
+ shf_snprintf(path, len, "%s/sh%05u.%03x",
+ dir, (unsigned) procpid, inc++);
+ /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
+ * really there.
+ */
+ fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
+ if (fd >= 0) {
+ tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
+ break;
+ }
+ if (errno != EINTR
+#ifdef EEXIST
+ && errno != EEXIST
+#endif /* EEXIST */
+#ifdef EISDIR
+ && errno != EISDIR
+#endif /* EISDIR */
+ )
+ /* Error must be printed by caller: don't know here if
+ * errorf() or bi_errorf() should be used.
+ */
+ break;
+ }
+ tp->next = NULL;
+ tp->pid = procpid;
+
+ tp->next = *tlist;
+ *tlist = tp;
+
+ return tp;
+}
diff --git a/shells/pdksh/files/jobs.c b/shells/pdksh/files/jobs.c
new file mode 100644
index 00000000000..2b3a63b9e72
--- /dev/null
+++ b/shells/pdksh/files/jobs.c
@@ -0,0 +1,1874 @@
+/*
+ * Process and job control
+ */
+
+/*
+ * Reworked/Rewritten version of Eric Gisin's/Ron Natalie's code by
+ * Larry Bouzane (larry@cs.mun.ca) and hacked again by
+ * Michael Rendell (michael@cs.mun.ca)
+ *
+ * The interface to the rest of the shell should probably be changed
+ * to allow use of vfork() when available but that would be way too much
+ * work :)
+ *
+ * Notes regarding the copious ifdefs:
+ * - JOB_SIGS is independent of JOBS - it is defined if there are modern
+ * signal and wait routines available. This is prefered, even when
+ * JOBS is not defined, since the shell will not otherwise notice when
+ * background jobs die until the shell waits for a foreground process
+ * to die.
+ * - TTY_PGRP defined iff JOBS is defined - defined if there are tty
+ * process groups
+ * - NEED_PGRP_SYNC defined iff JOBS is defined - see comment below
+ */
+
+#include "sh.h"
+#include "ksh_stat.h"
+#include "ksh_wait.h"
+#include "ksh_times.h"
+#include "tty.h"
+
+/* Start of system configuration stuff */
+
+/* We keep CHILD_MAX zombie processes around (exact value isn't critical) */
+#ifndef CHILD_MAX
+# if defined(HAVE_SYSCONF) && defined(_SC_CHILD_MAX)
+# define CHILD_MAX sysconf(_SC_CHILD_MAX)
+# else /* _SC_CHILD_MAX */
+# ifdef _POSIX_CHILD_MAX
+# define CHILD_MAX ((_POSIX_CHILD_MAX) * 2)
+# else /* _POSIX_CHILD_MAX */
+# define CHILD_MAX 20
+# endif /* _POSIX_CHILD_MAX */
+# endif /* _SC_CHILD_MAX */
+#endif /* !CHILD_MAX */
+
+#ifdef JOBS
+# if defined(HAVE_TCSETPGRP) || defined(TIOCSPGRP)
+# define TTY_PGRP
+# endif
+# ifdef BSD_PGRP
+# define setpgid setpgrp
+# define getpgID() getpgrp(0)
+# else
+# define getpgID() getpgrp()
+# endif
+# if defined(TTY_PGRP) && !defined(HAVE_TCSETPGRP)
+int tcsetpgrp ARGS((int fd, pid_t grp));
+int tcgetpgrp ARGS((int fd));
+
+int
+tcsetpgrp(fd, grp)
+ int fd;
+ pid_t grp;
+{
+ return ioctl(fd, TIOCSPGRP, &grp);
+}
+
+int
+tcgetpgrp(fd)
+ int fd;
+{
+ int r, grp;
+
+ if ((r = ioctl(fd, TIOCGPGRP, &grp)) < 0)
+ return r;
+ return grp;
+}
+# endif /* !HAVE_TCSETPGRP && TIOCSPGRP */
+#else /* JOBS */
+/* These so we can use ifdef xxx instead of if defined(JOBS) && defined(xxx) */
+# undef TTY_PGRP
+# undef NEED_PGRP_SYNC
+#endif /* JOBS */
+
+/* End of system configuration stuff */
+
+
+/* Order important! */
+#define PRUNNING 0
+#define PEXITED 1
+#define PSIGNALLED 2
+#define PSTOPPED 3
+
+typedef struct proc Proc;
+struct proc {
+ Proc *next; /* next process in pipeline (if any) */
+ int state;
+ WAIT_T status; /* wait status */
+ pid_t pid; /* process id */
+ char command[48]; /* process command string */
+};
+
+/* Notify/print flag - j_print() argument */
+#define JP_NONE 0 /* don't print anything */
+#define JP_SHORT 1 /* print signals processes were killed by */
+#define JP_MEDIUM 2 /* print [job-num] -/+ command */
+#define JP_LONG 3 /* print [job-num] -/+ pid command */
+#define JP_PGRP 4 /* print pgrp */
+
+/* put_job() flags */
+#define PJ_ON_FRONT 0 /* at very front */
+#define PJ_PAST_STOPPED 1 /* just past any stopped jobs */
+
+/* Job.flags values */
+#define JF_STARTED 0x001 /* set when all processes in job are started */
+#define JF_WAITING 0x002 /* set if j_waitj() is waiting on job */
+#define JF_W_ASYNCNOTIFY 0x004 /* set if waiting and async notification ok */
+#define JF_XXCOM 0x008 /* set for `command` jobs */
+#define JF_FG 0x010 /* running in foreground (also has tty pgrp) */
+#define JF_SAVEDTTY 0x020 /* j->ttystate is valid */
+#define JF_CHANGED 0x040 /* process has changed state */
+#define JF_KNOWN 0x080 /* $! referenced */
+#define JF_ZOMBIE 0x100 /* known, unwaited process */
+#define JF_REMOVE 0x200 /* flaged for removal (j_jobs()/j_noityf()) */
+#define JF_USETTYMODE 0x400 /* tty mode saved if process exits normally */
+#define JF_SAVEDTTYPGRP 0x800 /* j->saved_ttypgrp is valid */
+
+typedef struct job Job;
+struct job {
+ Job *next; /* next job in list */
+ int job; /* job number: %n */
+ int flags; /* see JF_* */
+ int state; /* job state */
+ int status; /* exit status of last process */
+ pid_t pgrp; /* process group of job */
+ pid_t ppid; /* pid of process that forked job */
+ INT32 age; /* number of jobs started */
+ clock_t systime; /* system time used by job */
+ clock_t usrtime; /* user time used by job */
+ Proc *proc_list; /* process list */
+ Proc *last_proc; /* last process in list */
+#ifdef KSH
+ Coproc_id coproc_id; /* 0 or id of coprocess output pipe */
+#endif /* KSH */
+#ifdef TTY_PGRP
+ TTY_state ttystate; /* saved tty state for stopped jobs */
+ pid_t saved_ttypgrp; /* saved tty process group for stopped jobs */
+#endif /* TTY_PGRP */
+};
+
+/* Flags for j_waitj() */
+#define JW_NONE 0x00
+#define JW_INTERRUPT 0x01 /* ^C will stop the wait */
+#define JW_ASYNCNOTIFY 0x02 /* asynchronous notification during wait ok */
+#define JW_STOPPEDWAIT 0x04 /* wait even if job stopped */
+
+/* Error codes for j_lookup() */
+#define JL_OK 0
+#define JL_NOSUCH 1 /* no such job */
+#define JL_AMBIG 2 /* %foo or %?foo is ambiguous */
+#define JL_INVALID 3 /* non-pid, non-% job id */
+
+static const char *const lookup_msgs[] = {
+ null,
+ "no such job",
+ "ambiguous",
+ "argument must be %job or process id",
+ (char *) 0
+ };
+clock_t j_systime, j_usrtime; /* user and system time of last j_waitjed job */
+
+static Job *job_list; /* job list */
+static Job *last_job;
+static Job *async_job;
+static pid_t async_pid;
+
+static int nzombie; /* # of zombies owned by this process */
+static INT32 njobs; /* # of jobs started */
+static int child_max; /* CHILD_MAX */
+
+
+#ifdef JOB_SIGS
+/* held_sigchld is set if sigchld occurs before a job is completely started */
+static int held_sigchld;
+#endif /* JOB_SIGS */
+
+#ifdef JOBS
+static struct shf *shl_j;
+#endif /* JOBS */
+
+#ifdef NEED_PGRP_SYNC
+/* On some systems, the kernel doesn't count zombie processes when checking
+ * if a process group is valid, which can cause problems in creating the
+ * pipeline "cmd1 | cmd2": if cmd1 can die (and go into the zombie state)
+ * before cmd2 is started, the kernel doesn't allow the setpgid() for cmd2
+ * to succeed. Solution is to create a pipe between the parent and the first
+ * process; the first process doesn't do anything until the pipe is closed
+ * and the parent doesn't close the pipe until all the processes are started.
+ */
+static int j_sync_pipe[2];
+static int j_sync_open;
+#endif /* NEED_PGRP_SYNC */
+
+#ifdef TTY_PGRP
+static int ttypgrp_ok; /* set if can use tty pgrps */
+static pid_t restore_ttypgrp = -1;
+static pid_t our_pgrp;
+static int const tt_sigs[] = { SIGTSTP, SIGTTIN, SIGTTOU };
+#endif /* TTY_PGRP */
+
+static void j_set_async ARGS((Job *j));
+static void j_startjob ARGS((Job *j));
+static int j_waitj ARGS((Job *j, int flags, const char *where));
+static RETSIGTYPE j_sigchld ARGS((int sig));
+static void j_print ARGS((Job *j, int how, struct shf *shf));
+static Job *j_lookup ARGS((const char *cp, int *ecodep));
+static Job *new_job ARGS((void));
+static Proc *new_proc ARGS((void));
+static void check_job ARGS((Job *j));
+static void put_job ARGS((Job *j, int where));
+static void remove_job ARGS((Job *j, const char *where));
+static void kill_job ARGS((Job *j));
+static void fill_command ARGS((char *c, int len, struct op *t));
+
+/* initialize job control */
+void
+j_init(mflagset)
+ int mflagset;
+{
+ child_max = CHILD_MAX; /* so syscon() isn't always being called */
+
+#ifdef JOB_SIGS
+ sigemptyset(&sm_default);
+ sigprocmask(SIG_SETMASK, &sm_default, (sigset_t *) 0);
+
+ sigemptyset(&sm_sigchld);
+ sigaddset(&sm_sigchld, SIGCHLD);
+
+ setsig(&sigtraps[SIGCHLD], j_sigchld,
+ SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
+#else /* JOB_SIGS */
+ /* Make sure SIGCHLD isn't ignored - can do odd things under SYSV */
+ setsig(&sigtraps[SIGCHLD], SIG_DFL, SS_RESTORE_ORIG|SS_FORCE);
+#endif /* JOB_SIGS */
+
+#ifdef JOBS
+ if (!mflagset && Flag(FTALKING))
+ Flag(FMONITOR) = 1;
+
+ /* shl_j is used to do asynchronous notification (used in
+ * an interrupt handler, so need a distinct shf)
+ */
+ shl_j = shf_fdopen(2, SHF_WR, (struct shf *) 0);
+
+# ifdef TTY_PGRP
+ if (Flag(FMONITOR) || Flag(FTALKING)) {
+ int i;
+
+ /* the TF_SHELL_USES test is a kludge that lets us know if
+ * if the signals have been changed by the shell.
+ */
+ for (i = NELEM(tt_sigs); --i >= 0; ) {
+ sigtraps[tt_sigs[i]].flags |= TF_SHELL_USES;
+ /* j_change() sets this to SS_RESTORE_DFL if FMONITOR */
+ setsig(&sigtraps[tt_sigs[i]], SIG_IGN,
+ SS_RESTORE_IGN|SS_FORCE);
+ }
+ }
+# endif /* TTY_PGRP */
+
+ /* j_change() calls tty_init() */
+ if (Flag(FMONITOR))
+ j_change();
+ else
+#endif /* JOBS */
+ if (Flag(FTALKING))
+ tty_init(TRUE);
+}
+
+/* job cleanup before shell exit */
+void
+j_exit()
+{
+ /* kill stopped, and possibly running, jobs */
+ Job *j;
+ int killed = 0;
+
+ for (j = job_list; j != (Job *) 0; j = j->next) {
+ if (j->ppid == procpid
+ && (j->state == PSTOPPED
+ || (j->state == PRUNNING
+ && ((j->flags & JF_FG)
+ || (Flag(FLOGIN) && !Flag(FNOHUP)
+ && procpid == kshpid)))))
+ {
+ killed = 1;
+ killpg(j->pgrp, SIGHUP);
+#ifdef JOBS
+ if (j->state == PSTOPPED)
+ killpg(j->pgrp, SIGCONT);
+#endif /* JOBS */
+ }
+ }
+ if (killed)
+ sleep(1);
+ j_notify();
+
+#ifdef JOBS
+# ifdef TTY_PGRP
+ if (kshpid == procpid && restore_ttypgrp >= 0) {
+ /* Need to restore the tty pgrp to what it was when the
+ * shell started up, so that the process that started us
+ * will be able to access the tty when we are done.
+ * Also need to restore our process group in case we are
+ * about to do an exec so that both our parent and the
+ * process we are to become will be able to access the tty.
+ */
+ tcsetpgrp(tty_fd, restore_ttypgrp);
+ setpgid(0, restore_ttypgrp);
+ }
+# endif /* TTY_PGRP */
+ if (Flag(FMONITOR)) {
+ Flag(FMONITOR) = 0;
+ j_change();
+ }
+#endif /* JOBS */
+}
+
+#ifdef JOBS
+/* turn job control on or off according to Flag(FMONITOR) */
+void
+j_change()
+{
+ int i;
+
+ if (Flag(FMONITOR)) {
+ /* Don't call get_tty() 'til we own the tty process group */
+ tty_