summaryrefslogtreecommitdiff
path: root/usr/src/cmd/csh
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/csh
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/csh')
-rw-r--r--usr/src/cmd/csh/Makefile101
-rw-r--r--usr/src/cmd/csh/README27
-rw-r--r--usr/src/cmd/csh/csh.xcl43
-rw-r--r--usr/src/cmd/csh/i386/Makefile89
-rw-r--r--usr/src/cmd/csh/i386/signal.c247
-rw-r--r--usr/src/cmd/csh/i386/signal.h73
-rw-r--r--usr/src/cmd/csh/make.sh.tconst.h.ed11
-rw-r--r--usr/src/cmd/csh/printf.c762
-rw-r--r--usr/src/cmd/csh/sh.c1398
-rw-r--r--usr/src/cmd/csh/sh.char.c115
-rw-r--r--usr/src/cmd/csh/sh.char.h68
-rw-r--r--usr/src/cmd/csh/sh.debug.c55
-rw-r--r--usr/src/cmd/csh/sh.dir.c743
-rw-r--r--usr/src/cmd/csh/sh.dir.h26
-rw-r--r--usr/src/cmd/csh/sh.dol.c756
-rw-r--r--usr/src/cmd/csh/sh.err.c211
-rw-r--r--usr/src/cmd/csh/sh.exec.c466
-rw-r--r--usr/src/cmd/csh/sh.exp.c707
-rw-r--r--usr/src/cmd/csh/sh.file.c821
-rw-r--r--usr/src/cmd/csh/sh.func.c1645
-rw-r--r--usr/src/cmd/csh/sh.glob.c972
-rw-r--r--usr/src/cmd/csh/sh.h627
-rw-r--r--usr/src/cmd/csh/sh.hist.c167
-rw-r--r--usr/src/cmd/csh/sh.init.c206
-rw-r--r--usr/src/cmd/csh/sh.lex.c1429
-rw-r--r--usr/src/cmd/csh/sh.local.h58
-rw-r--r--usr/src/cmd/csh/sh.misc.c482
-rw-r--r--usr/src/cmd/csh/sh.parse.c696
-rw-r--r--usr/src/cmd/csh/sh.print.c228
-rw-r--r--usr/src/cmd/csh/sh.proc.c1247
-rw-r--r--usr/src/cmd/csh/sh.proc.h95
-rw-r--r--usr/src/cmd/csh/sh.sem.c523
-rw-r--r--usr/src/cmd/csh/sh.set.c804
-rw-r--r--usr/src/cmd/csh/sh.tchar.c857
-rw-r--r--usr/src/cmd/csh/sh.tconst.c205
-rw-r--r--usr/src/cmd/csh/sh.time.c262
-rw-r--r--usr/src/cmd/csh/sparc/Makefile89
-rw-r--r--usr/src/cmd/csh/sparc/signal.c271
-rw-r--r--usr/src/cmd/csh/sparc/signal.h77
-rw-r--r--usr/src/cmd/csh/stubs.c26
-rw-r--r--usr/src/cmd/csh/wait.h110
-rw-r--r--usr/src/cmd/csh/wait3.c136
42 files changed, 17931 insertions, 0 deletions
diff --git a/usr/src/cmd/csh/Makefile b/usr/src/cmd/csh/Makefile
new file mode 100644
index 0000000000..869fe7efc3
--- /dev/null
+++ b/usr/src/cmd/csh/Makefile
@@ -0,0 +1,101 @@
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+# Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+# Copyright (c) 1980 Regents of the University of California.
+# All rights reserved. The Berkeley Software License Agreement
+# specifies the terms and conditions for redistribution.
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# C Shell with process control; VM/UNIX VAX Makefile
+# Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
+#
+
+include ../Makefile.cmd
+
+ED= ed
+#
+# For message catalogue files
+#
+GREP= egrep
+SED= sed
+POFILE= csh.po
+CLOBBERFILES += sh.tconst.h
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+PFOBJS = sh_policy.o
+
+POBJS = \
+sh.o sh.char.o sh.debug.o\
+sh.dir.o sh.dol.o sh.err.o sh.exec.o sh.exp.o\
+sh.file.o sh.func.o sh.glob.o sh.hist.o\
+sh.init.o sh.lex.o sh.misc.o sh.parse.o\
+sh.print.o sh.proc.o sh.sem.o sh.set.o\
+sh.tchar.o sh.time.o stubs.o wait3.o printf.o
+
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+CPPFLAGS += -I ../sh
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(MACH)
+
+PFPOFILES= $(PFOBJS:%.o=%.po)
+
+POFILES= \
+sh.po sh.char.po sh.debug.po\
+sh.dir.po sh.dol.po sh.err.po sh.exec.po sh.exp.po\
+sh.file.po sh.func.po sh.glob.po sh.hist.po\
+sh.init.po sh.lex.po sh.misc.po sh.parse.po\
+sh.print.po sh.proc.po sh.sem.po sh.set.po\
+sh.tchar.po sh.time.po stubs.po wait3.po\
+$(PFPOFILES)
+
+XGETFLAGS= -a -x csh.xcl
+
+
+#
+# For message catalogue files
+#
+_msg: $(MSGDOMAIN) sh.tconst.h .WAIT $(POFILE)
+ $(RM) $(POFILE)
+ cat $(POFILES) > $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+
+$(POFILE): $(POFILES)
+ $(RM) $@; cat $(POFILES) > $@
+
+# based on .c.po, BUILD.po from Makefile.master
+%.po: ../sh/%.c
+ $(COMPILE.cpp) $< > $(<F).i
+ $(XGETTEXT) $(XGETFLAGS) $(<F).i ;\
+ $(RM) $@ ;\
+ sed "/^domain/d" < messages.po > $@ ;\
+ $(RM) messages.po $(<F).i
+
+$(PROG): $$(POBJS)
+ $(LINK.c) $(POBJS) -o $@
+
+sh.tconst.h:
+ $(RM) $@; $(ED) sh.tconst.c < make.sh.tconst.h.ed
+
+clobber: local_clobber $(MACH)
+
+local_clobber:
+ $(RM) $(CLOBBERFILES)
+
+$(MACH): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/csh/README b/usr/src/cmd/csh/README
new file mode 100644
index 0000000000..95e57a8378
--- /dev/null
+++ b/usr/src/cmd/csh/README
@@ -0,0 +1,27 @@
+[seizo:09/09/92]
+To fix #1098866, the directory structure is modified.
+This directory contains machine independent source codes of csh.
+Two files are currently machine dependent. These are
+ signal.c and signal.h
+Machine dependent files are moved under $(MACH) directory.
+
+So, if you are going to port csh for other architecture,
+you have to do:
+ 1) create a directory for the new architecture.
+ (Say, intel)
+
+ 2) create following files.
+ (You can use sparc/{Makefile, signal.c, signal.h} as templates.
+ intel/Makefile
+ intel/signal.c
+ You need to modify sigvechandler()
+ intel/signal.h
+ You need to modify struct sigcontext.
+
+In future, I am planning to rewrite csh so it uses modern
+signal interface so csh will not have any machine dependent
+portion.
+
+usr/src/cmd/csh/SCCS/{s.signal.c, s.signal.h} are move under
+usr/src/cmd/csh/sparc/SCCS. So, if you wish to see sccs histories
+of signal.c and signal.h, please refer to usr/src/cmd/csh/sparc/SCCS.
diff --git a/usr/src/cmd/csh/csh.xcl b/usr/src/cmd/csh/csh.xcl
new file mode 100644
index 0000000000..0ce57aa03f
--- /dev/null
+++ b/usr/src/cmd/csh/csh.xcl
@@ -0,0 +1,43 @@
+msgid " "
+msgid " "
+msgid " \b\b"
+msgid ""
+msgid "%ld %t"
+msgid "&"
+msgid "(null)"
+msgid "+"
+msgid "-"
+msgid "../"
+msgid "./"
+msgid "/"
+msgid "/.login"
+msgid "/bin/login"
+msgid "/dev/null"
+msgid "/etc"
+msgid "0123456789ABCDEF"
+msgid "0123456789abcdef"
+msgid "0X"
+msgid "0x"
+msgid ":"
+msgid "? "
+msgid "HOME"
+msgid "LC_CTYPE"
+msgid "LC_MESSAGES"
+msgid "Mail"
+msgid "PATH"
+msgid "Signal 32"
+msgid "TERM"
+msgid "TS"
+msgid "USER"
+msgid "\015\n"
+msgid "\07"
+msgid "\b\b \b\b"
+msgid "\b\b"
+msgid "\r"
+msgid "^R\n"
+msgid "login"
+msgid "vb"
+msgid "getwd: can't stat /"
+msgid "getwd: can't stat ."
+msgid "getwd: can't open .."
+msgid "getwd: read error in .."
diff --git a/usr/src/cmd/csh/i386/Makefile b/usr/src/cmd/csh/i386/Makefile
new file mode 100644
index 0000000000..8abdf43d36
--- /dev/null
+++ b/usr/src/cmd/csh/i386/Makefile
@@ -0,0 +1,89 @@
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+#
+# Copyright (c) 1980 Regents of the University of California.
+# All rights reserved. The Berkeley Software License Agreement
+# specifies the terms and conditions for redistribution.
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# C Shell with process control; VM/UNIX VAX Makefile
+# Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
+#
+
+CSH_PROG = csh
+PROG = $(CSH_PROG)
+PFCSH_PROG= pfcsh
+ROOTPFCSH= $(ROOTBIN)/$(PFCSH_PROG)
+
+include ../../Makefile.cmd
+
+MBCHAR = -DMBCHAR # Define this line to include multibyte input support
+DEFS = -DVFORK -DFILEC -DBSD_COMP -DFIVE # No TELL when MBCHAR
+CPPFLAGS= -I. -s $(DEFS) $(MBCHAR) $(CPPFLAGS.master)
+CPPFLAGS += -I ../../sh
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+LAZYLIBS = $(ZLAZYLOAD) -lsecdb $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -lsecdb
+LDLIBS += -lcurses $(LAZYLIBS)
+
+PFOBJS = sh_policy.o
+
+HDDEP = sh.o sh.dir.o sh.dol.o sh.err.o sh.exec.o sh.exp.o sh.file.o \
+ sh.func.o sh.glob.o sh.hist.o sh.init.o sh.lex.o sh.misc.o \
+ sh.parse.o sh.proc.o sh.sem.o sh.set.o sh.time.o
+
+COMMONOBJS= printf.o sh.char.o sh.dir.o sh.dol.o sh.err.o \
+ sh.exec.o sh.exp.o sh.file.o sh.func.o sh.glob.o sh.hist.o sh.init.o \
+ sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.proc.o sh.sem.o sh.set.o \
+ sh.time.o sh.tchar.o sh.tconst.o sh.o \
+ wait3.o
+
+LOCALOBJS= signal.o
+
+COMMONSRCS= $(COMMONOBJS:%.o=../%.c)
+PFSRCS= $(PFOBJS:%=pfcsh_objs/%)
+
+.KEEP_STATE:
+
+.PARALLEL: $(COMMONOBJS) $(LOCALOBJS)
+
+all: $(PROG)
+
+# build rule for common source above
+%.o: ../%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.o: ../../sh/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+$(CSH_PROG): sh.tconst.h .WAIT $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS)
+ $(LINK.c) $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(ROOTPFCSH): $(ROOTPROG)
+ $(RM) $@
+ $(LN) $(ROOTPROG) $@
+
+sh.tconst.h: ../sh.tconst.c ../make.sh.tconst.h.ed
+ $(RM) $@
+ ed ../sh.tconst.c < ../make.sh.tconst.h.ed
+
+$(HDDEP): sh.tconst.h
+
+install: all $(ROOTBINPROG) $(ROOTPROG) $(ROOTPFCSH)
+
+lint: sh.tconst.h
+ $(LINT.c) $(COMMONSRCS) $(PFSRCS) signal.c
+
+clean:
+ $(RM) $(LOCALOBJS) $(COMMONOBJS) $(PFOBJS) sh.tconst.h
+
+clobber: clean
+ $(RM) $(PROG)
diff --git a/usr/src/cmd/csh/i386/signal.c b/usr/src/cmd/csh/i386/signal.c
new file mode 100644
index 0000000000..092a200ab5
--- /dev/null
+++ b/usr/src/cmd/csh/i386/signal.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * 4.3BSD signal compatibility functions
+ *
+ * the implementation interprets signal masks equal to -1 as "all of the
+ * signals in the signal set", thereby allowing signals with numbers
+ * above 32 to be blocked when referenced in code such as:
+ *
+ * for (i = 0; i < NSIG; i++)
+ * mask |= sigmask(i)
+ */
+
+#include <sys/types.h>
+#include <sys/siginfo.h>
+#include <sys/ucontext.h>
+#include <signal.h>
+#include "signal.h"
+#include <errno.h>
+#include <stdio.h>
+
+#define set2mask(setp) ((setp)->__sigbits[0])
+#define mask2set(mask, setp) \
+ ((mask) == -1 ? sigfillset(setp) : sigemptyset(setp), (((setp)->__sigbits[0]) = (mask)))
+
+void (*_siguhandler[NSIG])() = { 0 };
+
+/*
+ * sigstack is emulated with sigaltstack by guessing an appropriate
+ * value for the stack size - on machines that have stacks that grow
+ * upwards, the ss_sp arguments for both functions mean the same thing,
+ * (the initial stack pointer sigstack() is also the stack base
+ * sigaltstack()), so a "very large" value should be chosen for the
+ * stack size - on machines that have stacks that grow downwards, the
+ * ss_sp arguments mean opposite things, so 0 should be used (hopefully
+ * these machines don't have hardware stack bounds registers that pay
+ * attention to sigaltstack()'s size argument.
+ */
+
+#ifdef sun
+#define SIGSTACKSIZE 0
+#endif
+
+
+/*
+ * sigvechandler is the real signal handler installed for all
+ * signals handled in the 4.3BSD compatibility interface - it translates
+ * SVR4 signal hander arguments into 4.3BSD signal handler arguments
+ * and then calls the real handler
+ */
+
+static void
+sigvechandler(sig, sip, ucp)
+ int sig;
+ siginfo_t *sip;
+ ucontext_t *ucp;
+{
+ struct sigcontext sc;
+ int code;
+ char *addr;
+ register int i, j;
+ int gwinswitch = 0;
+
+ sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
+ sc.sc_mask = set2mask(&ucp->uc_sigmask);
+
+ /*
+ * Machine dependent code begins
+ */
+ sc.sc_sp = (int) ucp->uc_mcontext.gregs[UESP];
+ sc.sc_pc = (int) ucp->uc_mcontext.gregs[EIP];
+ sc.sc_ps = (int) ucp->uc_mcontext.gregs[EFL];
+ sc.sc_eax = (int) ucp->uc_mcontext.gregs[EAX];
+ sc.sc_edx = (int) ucp->uc_mcontext.gregs[EDX];
+
+ /*
+ * Machine dependent code ends
+ */
+
+ if (sip != NULL)
+ if ((code = sip->si_code) == BUS_OBJERR)
+ code = SEGV_MAKE_ERR(sip->si_errno);
+
+ if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS)
+ if (sip != NULL)
+ addr = (char *)sip->si_addr;
+ else
+ addr = SIG_NOADDR;
+
+ (*_siguhandler[sig])(sig, code, &sc, addr);
+
+ if (sc.sc_onstack)
+ ucp->uc_stack.ss_flags |= SS_ONSTACK;
+ else
+ ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
+ mask2set(sc.sc_mask, &ucp->uc_sigmask);
+
+ /*
+ * Machine dependent code begins
+ */
+ ucp->uc_mcontext.gregs[UESP] = (int) sc.sc_sp;
+ ucp->uc_mcontext.gregs[EIP] = (int) sc.sc_pc;
+ ucp->uc_mcontext.gregs[EFL] = (int) sc.sc_ps;
+ ucp->uc_mcontext.gregs[EAX] = (int) sc.sc_eax;
+ ucp->uc_mcontext.gregs[EDX] = (int) sc.sc_edx;
+ /*
+ * Machine dependent code ends
+ */
+
+ setcontext (ucp);
+}
+
+sigsetmask(mask)
+ int mask;
+{
+ sigset_t oset;
+ sigset_t nset;
+
+ (void) sigprocmask(0, (sigset_t *)0, &nset);
+ mask2set(mask, &nset);
+ (void) sigprocmask(SIG_SETMASK, &nset, &oset);
+ return set2mask(&oset);
+}
+
+sigblock(mask)
+ int mask;
+{
+ sigset_t oset;
+ sigset_t nset;
+
+ (void) sigprocmask(0, (sigset_t *)0, &nset);
+ mask2set(mask, &nset);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+ return set2mask(&oset);
+}
+
+sigpause(mask)
+ int mask;
+{
+ sigset_t set;
+
+ (void) sigprocmask(0, (sigset_t *)0, &set);
+ mask2set(mask, &set);
+ return (sigsuspend(&set));
+}
+
+sigvec(sig, nvec, ovec)
+ int sig;
+ struct sigvec *nvec;
+ struct sigvec *ovec;
+{
+ struct sigaction nact;
+ struct sigaction oact;
+ struct sigaction *nactp;
+ void (*ohandler)(), (*nhandler)();
+
+ if (sig <= 0 || sig >= NSIG) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ohandler = _siguhandler[sig];
+
+ if (nvec) {
+ _sigaction(sig, (struct sigaction *)0, &nact);
+ nhandler = nvec->sv_handler;
+ _siguhandler[sig] = nhandler;
+ if (nhandler != SIG_DFL && nhandler != SIG_IGN)
+ nact.sa_handler = (void (*)())sigvechandler;
+ else
+ nact.sa_handler = nhandler;
+ mask2set(nvec->sv_mask, &nact.sa_mask);
+ /*
+ if ( sig == SIGTSTP || sig == SIGSTOP )
+ nact.sa_handler = SIG_DFL; */
+ nact.sa_flags = SA_SIGINFO;
+ if (!(nvec->sv_flags & SV_INTERRUPT))
+ nact.sa_flags |= SA_RESTART;
+ if (nvec->sv_flags & SV_RESETHAND)
+ nact.sa_flags |= SA_RESETHAND;
+ if (nvec->sv_flags & SV_ONSTACK)
+ nact.sa_flags |= SA_ONSTACK;
+ nactp = &nact;
+ } else
+ nactp = (struct sigaction *)0;
+
+ if (_sigaction(sig, nactp, &oact) < 0) {
+ _siguhandler[sig] = ohandler;
+ return -1;
+ }
+
+ if (ovec) {
+ if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
+ ovec->sv_handler = oact.sa_handler;
+ else
+ ovec->sv_handler = ohandler;
+ ovec->sv_mask = set2mask(&oact.sa_mask);
+ ovec->sv_flags = 0;
+ if (oact.sa_flags & SA_ONSTACK)
+ ovec->sv_flags |= SV_ONSTACK;
+ if (oact.sa_flags & SA_RESETHAND)
+ ovec->sv_flags |= SV_RESETHAND;
+ if (!(oact.sa_flags & SA_RESTART))
+ ovec->sv_flags |= SV_INTERRUPT;
+ }
+
+ return 0;
+}
+
+
+void (*
+signal(s, a))()
+ int s;
+ void (*a)();
+{
+ struct sigvec osv;
+ struct sigvec nsv;
+ static int mask[NSIG];
+ static int flags[NSIG];
+
+ nsv.sv_handler = a;
+ nsv.sv_mask = mask[s];
+ nsv.sv_flags = flags[s];
+ if (sigvec(s, &nsv, &osv) < 0)
+ return (SIG_ERR);
+ if (nsv.sv_mask != osv.sv_mask || nsv.sv_flags != osv.sv_flags) {
+ mask[s] = nsv.sv_mask = osv.sv_mask;
+ flags[s] = nsv.sv_flags = osv.sv_flags & ~SV_RESETHAND;
+ if (sigvec(s, &nsv, (struct sigvec *)0) < 0)
+ return (SIG_ERR);
+ }
+ return (osv.sv_handler);
+}
diff --git a/usr/src/cmd/csh/i386/signal.h b/usr/src/cmd/csh/i386/signal.h
new file mode 100644
index 0000000000..51cfd8945a
--- /dev/null
+++ b/usr/src/cmd/csh/i386/signal.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+
+#ifndef CSH_SIGNAL_H
+#define CSH_SIGNAL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * 4.3BSD signal compatibility header
+ *
+ */
+#define sigmask(m) (m > 32 ? 0 : (1 << ((m)-1)))
+
+/*
+ * 4.3BSD signal vector structure used in sigvec call.
+ */
+struct sigvec {
+ void (*sv_handler)(); /* signal handler */
+ int sv_mask; /* signal mask to apply */
+ int sv_flags; /* see signal options below */
+};
+
+#define SV_ONSTACK 0x0001 /* take signal on signal stack */
+#define SV_INTERRUPT 0x0002 /* do not restart system on signal return */
+#define SV_RESETHAND 0x0004 /* reset handler to SIG_DFL when signal taken */
+
+#define sv_onstack sv_flags
+
+/*
+ * Machine dependent deta structure
+ */
+struct sigcontext {
+ int sc_onstack; /* sigstack state to restore */
+ int sc_mask; /* signal mask to restore */
+ int sc_sp; /* sp to restore */
+ int sc_pc; /* pc to retore */
+ int sc_ps; /* psl to restore */
+ int sc_eax; /* eax to restore */
+ int sc_edx; /* edx to restore */
+};
+
+#define SI_DFLCODE 1
+
+#define BUS_HWERR BUS_ADRERR /* misc hardware error (e.g. timeout) */
+#define BUS_ALIGN BUS_ADRALN /* hardware alignment error */
+
+#define SEGV_NOMAP SEGV_MAPERR /* no mapping at the fault address */
+#define SEGV_PROT SEGV_ACCERR /* access exceeded protections */
+
+/*
+ * The SEGV_CODE(code) will be SEGV_NOMAP, SEGV_PROT, or SEGV_OBJERR.
+ * In the SEGV_OBJERR case, doing a SEGV_ERRNO(code) gives an errno value
+ * reported by the underlying file object mapped at the fault address.
+ */
+
+#define SIG_NOADDR ((char *)~0)
+
+#define SEGV_MAKE_ERR(e) (((e) << 8) | SEGV_MAPERR)
+
+#endif /* CSH_SIGNAL_H */
diff --git a/usr/src/cmd/csh/make.sh.tconst.h.ed b/usr/src/cmd/csh/make.sh.tconst.h.ed
new file mode 100644
index 0000000000..2e5c9443fc
--- /dev/null
+++ b/usr/src/cmd/csh/make.sh.tconst.h.ed
@@ -0,0 +1,11 @@
+!#ident "%Z%%M% %I% %E% SMI"
+v/^tchar/d
+1,$s/=.*/;/
+1,$s/^tchar/extern tchar/
+1i
+/* DON'T EDIT THIS FILE.
+ * This file was made from sh.tconst by the ed script make.sh.tconst.h.ed.
+ */
+.
+w sh.tconst.h
+q
diff --git a/usr/src/cmd/csh/printf.c b/usr/src/cmd/csh/printf.c
new file mode 100644
index 0000000000..68272cb5a4
--- /dev/null
+++ b/usr/src/cmd/csh/printf.c
@@ -0,0 +1,762 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Hacked "printf" which prints through putbyte and Putchar.
+ * putbyte() is used to send a pure byte, which might be a part
+ * of a mutlibyte character, mainly for %s. A control character
+ * for putbyte() may be QUOTE'd meaning not to convert it to ^x
+ * sequence. In all other cases Putchar() is used to send a character
+ * in tchar (== wchar_t + * optional QUOE.)
+ * DONT USE WITH STDIO!
+ * This printf has been hacked again so that it understands tchar string
+ * when the format specifier %t is used. Also %c has been expanded
+ * to take a tchar character as well as normal int.
+ * %t is supported in its simplest form; no width or precision will
+ * be understood.
+ * Assumption here is that sizeof(tchar)<=sizeof(int) so that tchar is
+ * passed as int. Otherwise, %T must be specified instead of %c to
+ * print a character in tchar.
+ */
+
+#include <stdarg.h>
+#include <values.h>
+#include "sh.h" /* For tchar. */
+
+#define HIBITLL (1ULL << 63)
+
+void _print(char *format, va_list *args);
+
+static char *p;
+
+int
+printf(const char *format, ...)
+{
+ va_list stupid;
+
+ p = (char *)gettext(format);
+ va_start(stupid, format);
+ _print(p, &stupid);
+ va_end(stupid);
+}
+
+/*
+ * Floating-point code is included or not, depending
+ * on whether the preprocessor variable FLOAT is 1 or 0.
+ */
+
+/* Maximum number of digits in any integer (long) representation */
+#define MAXDIGS 20
+
+/* Convert a digit character to the corresponding number */
+#define tonumber(x) ((x) - '0')
+
+/* Convert a number between 0 and 9 to the corresponding digit */
+#define todigit(x) ((x) + '0')
+
+/* Maximum total number of digits in E format */
+#define MAXECVT 17
+
+/* Maximum number of digits after decimal point in F format */
+#define MAXFCVT 60
+
+/* Maximum significant figures in a floating-point number */
+#define MAXFSIG 17
+
+/* Maximum number of characters in an exponent */
+#define MAXESIZ 4
+
+/* Maximum (positive) exponent or greater */
+#define MAXEXP 40
+
+
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+/* If this symbol is nonzero, allow '0' as a flag */
+#define FZERO 1
+
+#if FLOAT
+/*
+ * System-supplied routines for floating conversion
+ */
+char *fcvt();
+char *ecvt();
+#endif
+
+void
+_print(char *format, va_list *args)
+{
+ /* Current position in format */
+ char *cp;
+
+ /* Starting and ending points for value to be printed */
+ char *bp, *p;
+ tchar *tbp, *tep; /* For "%t". */
+ tchar tcbuf[2]; /* For "%c" or "%T". */
+
+ /* Field width and precision */
+ int width, prec;
+
+ /* Format code */
+ char fcode;
+
+ /* Number of padding zeroes required on the left */
+ int lzero;
+
+ /* Flags - nonzero if corresponding character appears in format */
+ bool length; /* l */
+ bool double_length; /* ll */
+ bool fplus; /* + */
+ bool fminus; /* - */
+ bool fblank; /* blank */
+ bool fsharp; /* # */
+#if FZERO
+ bool fzero; /* 0 */
+#endif
+
+ /* Pointer to sign, "0x", "0X", or empty */
+ char *prefix;
+#if FLOAT
+ /* Exponent or empty */
+ char *suffix;
+
+ /* Buffer to create exponent */
+ char expbuf[MAXESIZ + 1];
+
+ /* Number of padding zeroes required on the right */
+ int rzero;
+
+ /* The value being converted, if real */
+ double dval;
+
+ /* Output values from fcvt and ecvt */
+ int decpt, sign;
+
+ /* Scratch */
+ int k;
+
+ /* Values are developed in this buffer */
+ char buf[max(MAXDIGS, max(MAXFCVT + DMAXEXP, MAXECVT) + 1)];
+#else
+ char buf[MAXDIGS];
+#endif
+ /* The value being converted, if integer */
+ long long val;
+
+ /* Set to point to a translate table for digits of whatever radix */
+ char *tab;
+
+ /* Work variables */
+ int n, hradix, lowbit;
+
+ cp = format;
+
+ /*
+ * The main loop -- this loop goes through one iteration
+ * for each ordinary character or format specification.
+ */
+ while (*cp)
+ if (*cp != '%') {
+ /* Ordinary (non-%) character */
+ putbyte (*cp++);
+ } else {
+ /*
+ * % has been found.
+ * First, parse the format specification.
+ */
+
+ /* Scan the <flags> */
+ fplus = fminus = fblank = fsharp = 0;
+#if FZERO
+ fzero = 0;
+#endif
+scan:
+ switch (*++cp) {
+ case '+':
+ fplus = 1;
+ goto scan;
+ case '-':
+ fminus = 1;
+ goto scan;
+ case ' ':
+ fblank = 1;
+ goto scan;
+ case '#':
+ fsharp = 1;
+ goto scan;
+#if FZERO
+ case '0':
+ fzero = 1;
+ goto scan;
+#endif
+ }
+
+ /* Scan the field width */
+ if (*cp == '*') {
+ width = va_arg (*args, int);
+ if (width < 0) {
+ width = -width;
+ fminus = 1;
+ }
+ cp++;
+ } else {
+ width = 0;
+ while (isdigit(*cp)) {
+ n = tonumber(*cp++);
+ width = width * 10 + n;
+ }
+ }
+
+ /* Scan the precision */
+ if (*cp == '.') {
+
+ /* '*' instead of digits? */
+ if (*++cp == '*') {
+ prec = va_arg(*args, int);
+ cp++;
+ } else {
+ prec = 0;
+ while (isdigit(*cp)) {
+ n = tonumber(*cp++);
+ prec = prec * 10 + n;
+ }
+ }
+ } else {
+ prec = -1;
+ }
+
+ /* Scan the length modifier */
+ double_length = length = 0;
+ switch (*cp) {
+ case 'l':
+ if (*(cp + 1) == 'l') {
+ cp++;
+ double_length = 1;
+ } else {
+ length = 1;
+ }
+ /* No break */
+ case 'h':
+ cp++;
+ }
+
+ /*
+ * The character addressed by cp must be the
+ * format letter -- there is nothing left for
+ * it to be.
+ *
+ * The status of the +, -, #, blank, and 0
+ * flags are reflected in the variables
+ * "fplus", "fminus", "fsharp", "fblank",
+ * and "fzero", respectively.
+ * "width" and "prec" contain numbers
+ * corresponding to the digit strings
+ * before and after the decimal point,
+ * respectively. If there was no decimal
+ * point, "prec" is -1.
+ *
+ * The following switch sets things up
+ * for printing. What ultimately gets
+ * printed will be padding blanks, a prefix,
+ * left padding zeroes, a value, right padding
+ * zeroes, a suffix, and more padding
+ * blanks. Padding blanks will not appear
+ * simultaneously on both the left and the
+ * right. Each case in this switch will
+ * compute the value, and leave in several
+ * variables the information necessary to
+ * construct what is to be printed.
+ *
+ * The prefix is a sign, a blank, "0x", "0X",
+ * or null, and is addressed by "prefix".
+ *
+ * The suffix is either null or an exponent,
+ * and is addressed by "suffix".
+ *
+ * The value to be printed starts at "bp"
+ * and continues up to and not including "p".
+ *
+ * "lzero" and "rzero" will contain the number
+ * of padding zeroes required on the left
+ * and right, respectively. If either of
+ * these variables is negative, it will be
+ * treated as if it were zero.
+ *
+ * The number of padding blanks, and whether
+ * they go on the left or the right, will be
+ * computed on exit from the switch.
+ */
+
+ lzero = 0;
+ prefix = "";
+#if FLOAT
+ rzero = lzero;
+ suffix = prefix;
+#endif
+ switch (fcode = *cp++) {
+
+ /*
+ * fixed point representations
+ *
+ * "hradix" is half the radix for the conversion.
+ * Conversion is unsigned unless fcode is 'd'.
+ * HIBITLL is 1000...000 binary, and is equal to
+ * the maximum negative number.
+ * We assume a 2's complement machine
+ */
+
+ case 'D':
+ case 'U':
+ length = 1;
+ case 'd':
+ case 'u':
+ hradix = 5;
+ goto fixed;
+
+ case 'O':
+ length = 1;
+ case 'o':
+ hradix = 4;
+ goto fixed;
+
+ case 'X':
+ case 'x':
+ hradix = 8;
+
+fixed:
+ /* Establish default precision */
+ if (prec < 0) {
+ prec = 1;
+ }
+
+ /* Fetch the argument to be printed */
+ if (double_length) {
+ val = va_arg(*args, long long);
+ } else if (length) {
+ val = va_arg(*args, long);
+ } else if (fcode == 'd') {
+ val = va_arg(*args, int);
+ } else {
+ val = va_arg(*args, unsigned);
+ }
+
+ /* If signed conversion, establish sign */
+ if (fcode == 'd' || fcode == 'D') {
+ if (val < 0) {
+ prefix = "-";
+ /*
+ * Negate, checking in
+ * advance for possible
+ * overflow.
+ */
+ if (val != HIBITLL) {
+ val = -val;
+ }
+ } else if (fplus) {
+ prefix = "+";
+ } else if (fblank) {
+ prefix = " ";
+ }
+ }
+#if FZERO
+ if (fzero) {
+ int n = width - strlen(prefix);
+ if (n > prec) {
+ prec = n;
+ }
+ }
+#endif
+ /* Set translate table for digits */
+ if (fcode == 'X') {
+ tab = "0123456789ABCDEF";
+ } else {
+ tab = "0123456789abcdef";
+ }
+
+ /* Develop the digits of the value */
+ p = bp = buf + MAXDIGS;
+ while (val) {
+ lowbit = val & 1;
+ val = (val >> 1) & ~HIBITLL;
+ *--bp = tab[val % hradix * 2 + lowbit];
+ val /= hradix;
+ }
+
+ /* Calculate padding zero requirement */
+ lzero = bp - p + prec;
+
+ /* Handle the # flag */
+ if (fsharp && bp != p) {
+ switch (fcode) {
+ case 'o':
+ if (lzero < 1)
+ lzero = 1;
+ break;
+ case 'x':
+ prefix = "0x";
+ break;
+ case 'X':
+ prefix = "0X";
+ break;
+ }
+ }
+
+ break;
+#if FLOAT
+ case 'E':
+ case 'e':
+ /*
+ * E-format. The general strategy
+ * here is fairly easy: we take
+ * what ecvt gives us and re-format it.
+ */
+
+ /* Establish default precision */
+ if (prec < 0) {
+ prec = 6;
+ }
+
+ /* Fetch the value */
+ dval = va_arg(*args, double);
+
+ /* Develop the mantissa */
+ bp = ecvt(dval,
+ min(prec + 1, MAXECVT),
+ &decpt,
+ &sign);
+
+ /* Determine the prefix */
+e_merge:
+ if (sign) {
+ prefix = "-";
+ } else if (fplus) {
+ prefix = "+";
+ } else if (fblank) {
+ prefix = " ";
+ }
+
+ /* Place the first digit in the buffer */
+ p = &buf[0];
+ *p++ = *bp != '\0' ? *bp++ : '0';
+
+ /* Put in a decimal point if needed */
+ if (prec != 0 || fsharp) {
+ *p++ = '.';
+ }
+
+ /* Create the rest of the mantissa */
+ rzero = prec;
+ while (rzero > 0 && *bp != '\0') {
+ --rzero;
+ *p++ = *bp++;
+ }
+
+ bp = &buf[0];
+
+ /* Create the exponent */
+ suffix = &expbuf[MAXESIZ];
+ *suffix = '\0';
+ if (dval != 0) {
+ n = decpt - 1;
+ if (n < 0) {
+ n = -n;
+ }
+ while (n != 0) {
+ *--suffix = todigit(n % 10);
+ n /= 10;
+ }
+ }
+
+ /* Prepend leading zeroes to the exponent */
+ while (suffix > &expbuf[MAXESIZ - 2]) {
+ *--suffix = '0';
+ }
+
+ /* Put in the exponent sign */
+ *--suffix = (decpt > 0 || dval == 0) ?
+ '+' : '-';
+
+ /* Put in the e */
+ *--suffix = isupper(fcode) ? 'E' : 'e';
+
+ break;
+
+ case 'f':
+ /*
+ * F-format floating point. This is
+ * a good deal less simple than E-format.
+ * The overall strategy will be to call
+ * fcvt, reformat its result into buf,
+ * and calculate how many trailing
+ * zeroes will be required. There will
+ * never be any leading zeroes needed.
+ */
+
+ /* Establish default precision */
+ if (prec < 0) {
+ prec = 6;
+ }
+
+ /* Fetch the value */
+ dval = va_arg(*args, double);
+
+ /* Do the conversion */
+ bp = fcvt(dval,
+ min(prec, MAXFCVT),
+ &decpt,
+ &sign);
+
+ /* Determine the prefix */
+f_merge:
+ if (sign && decpt > -prec &&
+ *bp != '\0' && *bp != '0') {
+ prefix = "-";
+ } else if (fplus) {
+ prefix = "+";
+ } else if (fblank) {
+ prefix = " ";
+ }
+
+ /* Initialize buffer pointer */
+ p = &buf[0];
+
+ /* Emit the digits before the decimal point */
+ n = decpt;
+ k = 0;
+ if (n <= 0) {
+ *p++ = '0';
+ } else {
+ do {
+ if (*bp == '\0' ||
+ k >= MAXFSIG) {
+ *p++ = '0';
+ } else {
+ *p++ = *bp++;
+ ++k;
+ }
+ } while (--n != 0);
+ }
+
+ /* Decide whether we need a decimal point */
+ if (fsharp || prec > 0) {
+ *p++ = '.';
+ }
+
+ /* Digits (if any) after the decimal point */
+ n = min(prec, MAXFCVT);
+ rzero = prec - n;
+ while (--n >= 0) {
+ if (++decpt <= 0 || *bp == '\0' ||
+ k >= MAXFSIG) {
+ *p++ = '0';
+ } else {
+ *p++ = *bp++;
+ ++k;
+ }
+ }
+
+ bp = &buf[0];
+
+ break;
+
+ case 'G':
+ case 'g':
+ /*
+ * g-format. We play around a bit
+ * and then jump into e or f, as needed.
+ */
+
+ /* Establish default precision */
+ if (prec < 0) {
+ prec = 6;
+ }
+
+ /* Fetch the value */
+ dval = va_arg(*args, double);
+
+ /* Do the conversion */
+ bp = ecvt(dval,
+ min(prec, MAXECVT),
+ &decpt,
+ &sign);
+ if (dval == 0) {
+ decpt = 1;
+ }
+
+ k = prec;
+ if (!fsharp) {
+ n = strlen(bp);
+ if (n < k) {
+ k = n;
+ }
+ while (k >= 1 && bp[k-1] == '0') {
+ --k;
+ }
+ }
+
+ if (decpt < -3 || decpt > prec) {
+ prec = k - 1;
+ goto e_merge;
+ } else {
+ prec = k - decpt;
+ goto f_merge;
+ }
+
+#endif
+ case 'c':
+#ifdef MBCHAR_1 /* sizeof(int)>=sizeof(tchar) */
+/*
+ * A tchar arg is passed as int so we used the normal %c to specify
+ * such an arugument.
+ */
+ tcbuf[0] = va_arg(*args, int);
+ tbp = &tcbuf[0];
+ tep = tbp + 1;
+ fcode = 't'; /* Fake the rest of code. */
+ break;
+#else
+/*
+ * We would have to invent another new format speficier such as "%T" to
+ * take a tchar arg. Let's worry about when that time comes.
+ */
+ /*
+ * Following code take care of a char arg
+ * only.
+ */
+ buf[0] = va_arg(*args, int);
+ bp = &buf[0];
+ p = bp + 1;
+ break;
+ case 'T': /* Corresponding arg is tchar. */
+ tcbuf[0] = va_arg(*args, tchar);
+ tbp = &tcbuf[0];
+ tep = tbp + 1;
+ fcode = 't'; /* Fake the rest of code. */
+ break;
+#endif
+ case 's':
+ bp = va_arg(*args, char *);
+ if (bp == 0) {
+nullstr: bp = "(null)";
+ p = bp + strlen("(null)");
+ break;
+ }
+ if (prec < 0) {
+ prec = MAXINT;
+ }
+ for (n = 0; *bp++ != '\0' && n < prec; n++)
+ ;
+ p = --bp;
+ bp -= n;
+ break;
+
+ case 't':
+ /*
+ * Special format specifier "%t" tells
+ * printf() to print char strings written
+ * as tchar string.
+ */
+ tbp = va_arg(*args, tchar *);
+ if (tbp == 0) {
+ fcode = 's'; /* Act as if it were %s. */
+ goto nullstr;
+ }
+ if (prec < 0) {
+ prec = MAXINT;
+ }
+ for (n = 0; *tbp++ != 0 && n < prec; n++)
+ ;
+ tep = --tbp;
+ tbp -= n;
+
+ /*
+ * Just to make the following padding
+ * calculation not to go very crazy...
+ */
+ bp = NULL;
+ p = bp + n;
+ break;
+
+ case '\0':
+ cp--;
+ break;
+
+ default:
+ p = bp = &fcode;
+ p++;
+ break;
+
+ }
+ if (fcode != '\0') {
+ /* Calculate number of padding blanks */
+ int nblank;
+ nblank = width
+#if FLOAT
+ - (rzero < 0 ? 0: rzero)
+ - strlen(suffix)
+#endif
+ - (p - bp)
+ - (lzero < 0 ? 0 : lzero)
+ - strlen(prefix);
+
+ /* Blanks on left if required */
+ if (!fminus) {
+ while (--nblank >= 0) {
+ Putchar(' ');
+ }
+ }
+
+ /* Prefix, if any */
+ while (*prefix != '\0') {
+ Putchar(*prefix++);
+ }
+
+ /* Zeroes on the left */
+ while (--lzero >= 0) {
+ Putchar('0');
+ }
+
+ /* The value itself */
+ if (fcode == 't') { /* %t is special. */
+ while (tbp < tep) {
+ Putchar(*tbp++);
+ }
+ } else { /* For rest of the cases. */
+ while (bp < p) {
+ putbyte(*bp++);
+ }
+ }
+#if FLOAT
+ /* Zeroes on the right */
+ while (--rzero >= 0)
+ Putchar('0');
+
+ /* The suffix */
+ while (*suffix != '\0') {
+ Putchar(*suffix++);
+ }
+#endif
+ /* Blanks on the right if required */
+ if (fminus) {
+ while (--nblank >= 0) {
+ Putchar(' ');
+ }
+ }
+ }
+ }
+}
diff --git a/usr/src/cmd/csh/sh.c b/usr/src/cmd/csh/sh.c
new file mode 100644
index 0000000000..9d3e30860a
--- /dev/null
+++ b/usr/src/cmd/csh/sh.c
@@ -0,0 +1,1398 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <locale.h>
+#include "sh.h"
+/* #include <sys/ioctl.h> */
+#include <fcntl.h>
+#include <sys/filio.h>
+#include "sh.tconst.h"
+#include <pwd.h>
+#include <stdlib.h>
+#include "sh_policy.h" /* for pfcsh */
+
+/*
+ * We use these csh(1) private versions of the select macros, (see select(3C))
+ * so as not to be limited by the size of struct fd_set (ie 1024).
+ */
+#define CSH_FD_SET(n, p) ((*((p) + ((n)/NFDBITS))) |= (1 << ((n) % NFDBITS)))
+#define CSH_FD_CLR(n, p) ((*((p) + ((n)/NFDBITS))) &= ~(1 << ((n) % NFDBITS)))
+#define CSH_FD_ISSET(n, p) ((*((p) + ((n)/NFDBITS))) & (1 << ((n) % NFDBITS)))
+#define CSH_FD_ZERO(p, n) memset((void *)(p), 0, (n))
+
+tchar *pathlist[] = { S_usrbin/*"/usr/bin"*/, S_DOT /*"."*/, 0 };
+tchar *dumphist[] = { S_history /*"history"*/, S_h /*"-h"*/, 0, 0 };
+tchar *loadhist[] = { S_source /*"source"*/, S_h /*"-h"*/, S_NDOThistory /*"~/.history"*/, 0 };
+tchar HIST = '!';
+tchar HISTSUB = '^';
+int nofile;
+bool reenter;
+bool nverbose;
+bool nexececho;
+bool quitit;
+bool fast;
+bool batch;
+bool prompt = 1;
+bool enterhist = 0;
+
+extern gid_t getegid(), getgid();
+extern uid_t geteuid(), getuid();
+extern tchar **strblktotsblk(/* char **, int */);
+
+int siglwp();
+int sigwaiting();
+
+main(c, av)
+ int c;
+ char **av;
+{
+ register tchar **v, *cp, *p, *q, *r;
+ register int f;
+ struct sigvec osv;
+ struct sigaction sa;
+ tchar s_prompt[MAXHOSTNAMELEN+3];
+
+ pfcshflag = 0;
+
+ /*
+ * set up the error exit, if there is an error before
+ * this is done, it will core dump, and we don't
+ * tolerate core dumps
+ */
+ haderr = 0;
+ setexit();
+ if ( haderr ) {
+ /*
+ * if were here, there was an error in the csh
+ * startup so just punt
+ */
+ printf("csh startup error, csh exiting...\n");
+ flush();
+ exitstat();
+ }
+
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ /*
+ * This is a profile shell if the simple name of argv[0] is
+ * pfcsh or -pfcsh
+ */
+ p = strtots(NOSTR, "pfcsh");
+ r = strtots(NOSTR, "-pfcsh");
+ if ((p != NOSTR) && (r != NOSTR) &&
+ ((q = strtots(NOSTR, *av)) != NOSTR)) {
+ if (c > 0 && (eq(p, simple(q)) || eq(r, simple(q)))) {
+ pfcshflag = 1;
+ }
+ XFREE(q);
+ }
+
+ if (p != NOSTR)
+ XFREE(p);
+ if (r != NOSTR)
+ XFREE(r);
+
+ if (pfcshflag == 1) {
+ secpolicy_init();
+ }
+
+ /* Copy arguments */
+ v = strblktotsblk(av, c);
+
+ /*
+ * Initialize paraml list
+ */
+ paraml.next = paraml.prev = &paraml;
+
+ settimes(); /* Immed. estab. timing base */
+
+ if (eq(v[0], S_aout/*"a.out"*/)) /* A.out's are quittable */
+ quitit = 1;
+ uid = getuid();
+ loginsh = **v == '-';
+ if (loginsh)
+ (void) time(&chktim);
+
+ /*
+ * Move the descriptors to safe places.
+ * The variable didfds is 0 while we have only FSH* to work with.
+ * When didfds is true, we have 0,1,2 and prefer to use these.
+ *
+ * Also, setup data for csh internal file descriptor book keeping.
+ */
+ initdesc(c, av);
+
+ /*
+ * Initialize the shell variables.
+ * ARGV and PROMPT are initialized later.
+ * STATUS is also munged in several places.
+ * CHILD is munged when forking/waiting
+ */
+
+ /* don't do globbing here, just set exact copies */
+ setNS(S_noglob);
+
+ set(S_status /* "status" */, S_0 /* "0" */);
+ dinit(cp = getenvs_("HOME")); /* dinit thinks that HOME==cwd in a */
+ /* login shell */
+ if (cp == NOSTR)
+ fast++; /* No home -> can't read scripts */
+ else {
+ if (strlen_(cp) >= BUFSIZ - 10) {
+ cp = NOSTR;
+ fast++;
+ printf("%s\n", gettext("Pathname too long"));
+ set(S_home /* "home" */, savestr(cp));
+ local_setenv(S_HOME, savestr(cp));
+ }
+ set(S_home /* "home" */, savestr(cp));
+ }
+ /*
+ * Grab other useful things from the environment.
+ * Should we grab everything??
+ */
+ if ((cp = getenvs_("USER")) != NOSTR)
+ set(S_user/*"user"*/, savestr(cp));
+ else {
+ /*
+ * If USER is not defined, set it here.
+ */
+ struct passwd *pw;
+ pw = getpwuid(getuid());
+
+ if (pw != NULL) {
+ set(S_user, strtots((tchar *)0, pw->pw_name ));
+ local_setenv(S_USER, strtots((tchar *)0, pw->pw_name));
+ }
+ else if (loginsh) { /* Give up setting USER variable. */
+ printf("Warning: USER environment variable could not be set.\n");
+ }
+ }
+ if ((cp = getenvs_("TERM")) != NOSTR)
+ set(S_term/*"term"*/, savestr(cp));
+ /*
+ * Re-initialize path if set in environment
+ */
+ if ((cp = getenvs_("PATH")) == NOSTR)
+ set1(S_path/*"path"*/, saveblk(pathlist), &shvhed);
+ else
+ importpath(cp);
+ set(S_shell/*"shell"*/, S_SHELLPATH);
+
+ doldol = putn(getpid()); /* For $$ */
+
+ /* restore globbing until the user says otherwise */
+ unsetv(S_noglob);
+
+ /*
+ * Record the interrupt states from the parent process.
+ * If the parent is non-interruptible our hand must be forced
+ * or we (and our children) won't be either.
+ * Our children inherit termination from our parent.
+ * We catch it only if we are the login shell.
+ */
+ /* parents interruptibility */
+ (void) sigvec(SIGINT, (struct sigvec *)0, &osv);
+ parintr = osv.sv_handler;
+ /* parents terminability */
+ (void) sigvec(SIGTERM, (struct sigvec *)0, &osv);
+ parterm = osv.sv_handler;
+
+ _signal(SIGLWP, siglwp);
+ _signal(SIGWAITING, sigwaiting);
+ if (loginsh) {
+ (void) signal(SIGHUP, phup); /* exit processing on HUP */
+ (void) signal(SIGXCPU, phup); /* ...and on XCPU */
+ (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */
+ }
+
+ /*
+ * Process the arguments.
+ *
+ * Note that processing of -v/-x is actually delayed till after
+ * script processing.
+ */
+ c--, v++;
+ while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) {
+ do switch (*cp++) {
+
+ case 'b': /* -b Next arg is input file */
+ batch++;
+ break;
+
+ case 'c': /* -c Command input from arg */
+ if (c == 1)
+ exit(0);
+ c--, v++;
+ arginp = v[0];
+ prompt = 0;
+ nofile++;
+ cflg++;
+ break;
+
+ case 'e': /* -e Exit on any error */
+ exiterr++;
+ break;
+
+ case 'f': /* -f Fast start */
+ fast++;
+ break;
+
+ case 'i': /* -i Interactive, even if !intty */
+ intact++;
+ nofile++;
+ break;
+
+ case 'n': /* -n Don't execute */
+ noexec++;
+ break;
+
+ case 'q': /* -q (Undoc'd) ... die on quit */
+ quitit = 1;
+ break;
+
+ case 's': /* -s Read from std input */
+ nofile++;
+ break;
+
+ case 't': /* -t Read one line from input */
+ onelflg = 2;
+ prompt = 0;
+ nofile++;
+ break;
+#ifdef TRACE
+ case 'T': /* -T trace switch on */
+ trace_init();
+ break;
+#endif
+
+ case 'v': /* -v Echo hist expanded input */
+ nverbose = 1; /* ... later */
+ break;
+
+ case 'x': /* -x Echo just before execution */
+ nexececho = 1; /* ... later */
+ break;
+
+ case 'V': /* -V Echo hist expanded input */
+ setNS(S_verbose/*"verbose"*/); /* NOW! */
+ break;
+
+ case 'X': /* -X Echo just before execution */
+ setNS(S_echo/*"echo"*/); /* NOW! */
+ break;
+
+ } while (*cp);
+ v++, c--;
+ }
+
+ if (quitit) /* With all due haste, for debugging */
+ (void) signal(SIGQUIT, SIG_DFL);
+
+ /*
+ * Unless prevented by -c, -i, -s, or -t, if there
+ * are remaining arguments the first of them is the name
+ * of a shell file from which to read commands.
+ */
+ if (!batch && (uid != geteuid() || getgid() != getegid())) {
+ errno = EACCES;
+ child++; /* So this ... */
+ Perror(S_csh/*"csh"*/); /* ... doesn't return */
+ }
+
+ if (nofile == 0 && c > 0) {
+ nofile = open_(v[0], 0);
+ if (nofile < 0) {
+ child++; /* So this ... */
+ Perror(v[0]); /* ... doesn't return */
+ }
+ file = v[0];
+ SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */
+ (void) fcntl(SHIN, F_SETFD, 1);
+ prompt = 0;
+ c--, v++;
+ }
+
+ /*
+ * Consider input a tty if it really is or we are interactive.
+ */
+ intty = intact || isatty(SHIN);
+
+ /*
+ * Decide whether we should play with signals or not.
+ * If we are explicitly told (via -i, or -) or we are a login
+ * shell (arg0 starts with -) or the input and output are both
+ * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
+ * Note that in only the login shell is it likely that parent
+ * may have set signals to be ignored
+ */
+ if (loginsh || intact || intty && isatty(SHOUT))
+ setintr = 1;
+#ifdef TELL
+ settell();
+#endif
+ /*
+ * Save the remaining arguments in argv.
+ */
+ setq(S_argv/*"argv"*/, v, &shvhed);
+
+ /*
+ * Set up the prompt.
+ */
+ if (prompt) {
+ gethostname_(s_prompt, MAXHOSTNAMELEN);
+ strcat_(s_prompt, uid == 0 ? S_SHARPSP/*"# "*/ : S_PERSENTSP/*"% "*/);
+ set(S_prompt/*"prompt"*/, s_prompt);
+ }
+
+ /*
+ * If we are an interactive shell, then start fiddling
+ * with the signals; this is a tricky game.
+ */
+ shpgrp = getpgid(0);
+ opgrp = tpgrp = -1;
+ if (setintr) {
+ **av = '-';
+ if (!quitit) /* Wary! */
+ (void) signal(SIGQUIT, SIG_IGN);
+ (void) signal(SIGINT, pintr);
+ (void) sigblock(sigmask(SIGINT));
+ (void) signal(SIGTERM, SIG_IGN);
+ if (quitit == 0 && arginp == 0) {
+ (void) signal(SIGTSTP, SIG_IGN);
+ (void) signal(SIGTTIN, SIG_IGN);
+ (void) signal(SIGTTOU, SIG_IGN);
+ /*
+ * Wait till in foreground, in case someone
+ * stupidly runs
+ * csh &
+ * dont want to try to grab away the tty.
+ */
+ if (isatty(FSHDIAG))
+ f = FSHDIAG;
+ else if (isatty(FSHOUT))
+ f = FSHOUT;
+ else if (isatty(OLDSTD))
+ f = OLDSTD;
+ else
+ f = -1;
+retry:
+ if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 &&
+ tpgrp != -1) {
+ if (tpgrp != shpgrp) {
+ void (*old)() = (void (*)())signal(SIGTTIN, SIG_DFL);
+ (void) kill(0, SIGTTIN);
+ (void) signal(SIGTTIN, old);
+ goto retry;
+ }
+ opgrp = shpgrp;
+ shpgrp = getpid();
+ tpgrp = shpgrp;
+ (void) setpgid(0, shpgrp);
+ (void) ioctl(f, TIOCSPGRP, (char *)&shpgrp);
+ (void) fcntl(dcopy(f, FSHTTY), F_SETFD, 1);
+ } else {
+notty:
+ printf("Warning: no access to tty; thus no job control in this shell...\n");
+ tpgrp = -1;
+ }
+ }
+ }
+ if (setintr == 0 && parintr == SIG_DFL)
+ setintr++;
+
+ /*
+ * Set SIGCHLD handler, making sure that reads restart after it runs.
+ */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = pchild;
+ sa.sa_flags = SA_RESTART;
+ (void) sigaction(SIGCHLD, &sa, (struct sigaction *) NULL);
+
+ /*
+ * Set an exit here in case of an interrupt or error reading
+ * the shell start-up scripts.
+ */
+ setexit();
+ haderr = 0; /* In case second time through */
+ if (!fast && reenter == 0) {
+ reenter++;
+
+ /*
+ * If this is a login csh, and /etc/.login exists,
+ * source /etc/.login first.
+ */
+ if (loginsh) {
+ tchar tmp_etc[4+1]; /*strlen("/etc")+1 */
+ tchar tmp_login[7+1]; /*strlen("/.login")+1*/
+
+ strtots(tmp_etc, "/etc");
+ strtots(tmp_login, "/.login");
+ srccat_inlogin(tmp_etc, tmp_login);
+ }
+
+ /* Will have value("home") here because set fast if don't */
+ srccat(value(S_home/*"home"*/), S_SLADOTcshrc/*"/.cshrc"*/);
+
+ /*Hash path*/
+ if (!fast && !arginp && !onelflg && !havhash)
+ dohash(xhash);
+
+
+ /*
+ * Reconstruct the history list now, so that it's
+ * available from within .login.
+ */
+ dosource(loadhist);
+ if (loginsh) {
+ srccat_inlogin(value(S_home/*"home"*/), S_SLADOTlogin/*"/.login"*/);
+ }
+
+ /*
+ * To get cdpath hashing $cdpath must have a
+ * value, not $CDPATH. So if after reading
+ * the startup files ( .cshrc ), and
+ * user has specified a value for cdpath, then
+ * cache $cdpath paths. xhash2 is global array
+ * for $cdpath caching.
+ */
+ if (!fast && !arginp && !onelflg && !havhash2 )
+ dohash(xhash2);
+ }
+
+ /*
+ * Now are ready for the -v and -x flags
+ */
+ if (nverbose)
+ setNS(S_verbose/*"verbose"*/);
+ if (nexececho)
+ setNS(S_echo/*"echo"*/);
+
+ /*
+ * All the rest of the world is inside this call.
+ * The argument to process indicates whether it should
+ * catch "error unwinds". Thus if we are a interactive shell
+ * our call here will never return by being blown past on an error.
+ */
+ process(setintr);
+
+ /*
+ * Mop-up.
+ */
+ if (loginsh) {
+ printf("logout\n");
+ (void) close(SHIN); /* No need for unsetfd(). */
+ child++;
+ goodbye();
+ }
+ rechist();
+ exitstat();
+}
+
+untty()
+{
+
+ if (tpgrp > 0) {
+ (void) setpgid(0, opgrp);
+ (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&opgrp);
+ }
+}
+
+importpath(cp)
+ tchar *cp;
+{
+ register int i = 0;
+ register tchar *dp;
+ register tchar **pv;
+ int c;
+ static tchar dot[2] = {'.', 0};
+
+ for (dp = cp; *dp; dp++)
+ if (*dp == ':')
+ i++;
+ /*
+ * i+2 where i is the number of colons in the path.
+ * There are i+1 directories in the path plus we need
+ * room for a zero terminator.
+ */
+ pv = (tchar **) calloc((unsigned) (i + 2), sizeof (tchar **));
+ dp = cp;
+ i = 0;
+ if (*dp)
+ for (;;) {
+ if ((c = *dp) == ':' || c == 0) {
+ *dp = 0;
+ pv[i++] = savestr(*cp ? cp : dot);
+ if (c) {
+ cp = dp + 1;
+ *dp = ':';
+ } else
+ break;
+ }
+ dp++;
+ }
+ pv[i] = 0;
+ set1(S_path /*"path"*/, pv, &shvhed);
+}
+
+/*
+ * Source to the file which is the catenation of the argument names.
+ */
+srccat(cp, dp)
+ tchar *cp, *dp;
+{
+ register tchar *ep = strspl(cp, dp);
+ register int unit = dmove(open_(ep, 0), -1);
+
+ (void) fcntl(unit, F_SETFD, 1);
+ xfree(ep);
+#ifdef INGRES
+ srcunit(unit, 0, 0);
+#else
+ srcunit(unit, 1, 0);
+#endif
+}
+
+/*
+ * Source to the file which is the catenation of the argument names.
+ * This one does not check the ownership.
+ */
+srccat_inlogin(cp, dp)
+ tchar *cp, *dp;
+{
+ register tchar *ep = strspl(cp, dp);
+ register int unit = dmove(open_(ep, 0), -1);
+
+ (void) fcntl(unit, F_SETFD, 1);
+ xfree(ep);
+ srcunit(unit, 0, 0);
+}
+
+/*
+ * Source to a unit. If onlyown it must be our file or our group or
+ * we don't chance it. This occurs on ".cshrc"s and the like.
+ */
+srcunit(unit, onlyown, hflg)
+ register int unit;
+ bool onlyown;
+ bool hflg;
+{
+ /* We have to push down a lot of state here */
+ /* All this could go into a structure */
+ int oSHIN = -1, oldintty = intty;
+ struct whyle *oldwhyl = whyles;
+ tchar *ogointr = gointr, *oarginp = arginp;
+ tchar *oevalp = evalp, **oevalvec = evalvec;
+ int oonelflg = onelflg;
+ bool oenterhist = enterhist;
+ tchar OHIST = HIST;
+#ifdef TELL
+ bool otell = cantell;
+#endif
+ struct Bin saveB;
+
+ /* The (few) real local variables */
+ jmp_buf oldexit;
+ int reenter, omask;
+
+ if (unit < 0)
+ return;
+ if (didfds)
+ donefds();
+ if (onlyown) {
+ struct stat stb;
+
+ if (fstat(unit, &stb) < 0 ||
+ (stb.st_uid != uid && stb.st_gid != getgid())) {
+ (void) close(unit);
+ unsetfd(unit);
+ return;
+ }
+ }
+
+ /*
+ * There is a critical section here while we are pushing down the
+ * input stream since we have stuff in different structures.
+ * If we weren't careful an interrupt could corrupt SHIN's Bin
+ * structure and kill the shell.
+ *
+ * We could avoid the critical region by grouping all the stuff
+ * in a single structure and pointing at it to move it all at
+ * once. This is less efficient globally on many variable references
+ * however.
+ */
+ getexit(oldexit);
+ reenter = 0;
+ if (setintr)
+ omask = sigblock(sigmask(SIGINT));
+ setexit();
+ reenter++;
+ if (reenter == 1) {
+ /* Setup the new values of the state stuff saved above */
+ copy( (char *)&saveB, (char *)&B, sizeof saveB);
+ fbuf = (tchar **) 0;
+ fseekp = feobp = fblocks = 0;
+ oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
+ intty = isatty(SHIN), whyles = 0, gointr = 0;
+ evalvec = 0; evalp = 0;
+ enterhist = hflg;
+ if (enterhist)
+ HIST = '\0';
+ /*
+ * Now if we are allowing commands to be interrupted,
+ * we let ourselves be interrupted.
+ */
+ if (setintr)
+ (void) sigsetmask(omask);
+#ifdef TELL
+ settell();
+#endif
+ process(0); /* 0 -> blow away on errors */
+ }
+ if (setintr)
+ (void) sigsetmask(omask);
+ if (oSHIN >= 0) {
+ register int i;
+
+ /* We made it to the new state... free up its storage */
+ /* This code could get run twice but xfree doesn't care */
+ for (i = 0; i < fblocks; i++)
+ xfree(fbuf[i]);
+ xfree( (char *)fbuf);
+
+ /* Reset input arena */
+ copy( (char *)&B, (char *)&saveB, sizeof B);
+
+ (void) close(SHIN), SHIN = oSHIN;
+ unsetfd(SHIN);
+ arginp = oarginp, onelflg = oonelflg;
+ evalp = oevalp, evalvec = oevalvec;
+ intty = oldintty, whyles = oldwhyl, gointr = ogointr;
+ if (enterhist)
+ HIST = OHIST;
+ enterhist = oenterhist;
+#ifdef TELL
+ cantell = otell;
+#endif
+ }
+
+ resexit(oldexit);
+ /*
+ * If process reset() (effectively an unwind) then
+ * we must also unwind.
+ */
+ if (reenter >= 2)
+ error(NULL);
+}
+
+rechist()
+{
+ tchar buf[BUFSIZ];
+ int fp, ftmp, oldidfds;
+
+ if (!fast) {
+ if (value(S_savehist/*"savehist"*/)[0] == '\0')
+ return;
+ (void) strcpy_(buf, value(S_home/*"home"*/));
+ (void) strcat_(buf, S_SLADOThistory/*"/.history"*/);
+ fp = creat_(buf, 0666);
+ if (fp == -1)
+ return;
+ oldidfds = didfds;
+ didfds = 0;
+ ftmp = SHOUT;
+ SHOUT = fp;
+ (void) strcpy_(buf, value(S_savehist/*"savehist"*/));
+ dumphist[2] = buf;
+ dohist(dumphist);
+ (void) close(fp);
+ unsetfd(fp);
+ SHOUT = ftmp;
+ didfds = oldidfds;
+ }
+}
+
+goodbye()
+{
+ if (loginsh) {
+ (void) signal(SIGQUIT, SIG_IGN);
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGTERM, SIG_IGN);
+ setintr = 0; /* No interrupts after "logout" */
+ if (adrof(S_home/*"home"*/))
+ srccat(value(S_home/*"home"*/), S_SLADOTlogout/*"/.logout"*/);
+ }
+ rechist();
+ exitstat();
+}
+
+exitstat()
+{
+
+#ifdef PROF
+ monitor(0);
+#endif
+ /*
+ * Note that if STATUS is corrupted (i.e. getn bombs)
+ * then error will exit directly because we poke child here.
+ * Otherwise we might continue unwarrantedly (sic).
+ */
+ child++;
+ untty();
+ exit(getn(value(S_status/*"status"*/)));
+}
+
+/*
+ * in the event of a HUP we want to save the history
+ */
+void
+phup()
+{
+ rechist();
+ exit(1);
+}
+
+tchar *jobargv[2] = { S_jobs/*"jobs"*/, 0 };
+/*
+ * Catch an interrupt, e.g. during lexical input.
+ * If we are an interactive shell, we reset the interrupt catch
+ * immediately. In any case we drain the shell output,
+ * and finally go through the normal error mechanism, which
+ * gets a chance to make the shell go away.
+ */
+void
+pintr()
+{
+ pintr1(1);
+}
+
+pintr1(wantnl)
+ bool wantnl;
+{
+ register tchar **v;
+ int omask;
+
+ omask = sigblock(0);
+ if (setintr) {
+ (void) sigsetmask(omask & ~sigmask(SIGINT));
+ if (pjobs) {
+ pjobs = 0;
+ printf("\n");
+ dojobs(jobargv);
+ bferr("Interrupted");
+ }
+ }
+ (void) sigsetmask(omask & ~sigmask(SIGCHLD));
+ draino();
+
+ /*
+ * If we have an active "onintr" then we search for the label.
+ * Note that if one does "onintr -" then we shan't be interruptible
+ * so we needn't worry about that here.
+ */
+ if (gointr) {
+ search(ZGOTO, 0, gointr);
+ timflg = 0;
+ if (v = pargv)
+ pargv = 0, blkfree(v);
+ if (v = gargv)
+ gargv = 0, blkfree(v);
+ reset();
+ } else if (intty && wantnl)
+ printf("\n"); /* Some like this, others don't */
+ error(NULL);
+}
+
+/*
+ * Process is the main driving routine for the shell.
+ * It runs all command processing, except for those within { ... }
+ * in expressions (which is run by a routine evalav in sh.exp.c which
+ * is a stripped down process), and `...` evaluation which is run
+ * also by a subset of this code in sh.glob.c in the routine backeval.
+ *
+ * The code here is a little strange because part of it is interruptible
+ * and hence freeing of structures appears to occur when none is necessary
+ * if this is ignored.
+ *
+ * Note that if catch is not set then we will unwind on any error.
+ * If an end-of-file occurs, we return.
+ */
+process(catch)
+ bool catch;
+{
+ jmp_buf osetexit;
+ register struct command *t;
+
+ getexit(osetexit);
+ for (;;) {
+ pendjob();
+ paraml.next = paraml.prev = &paraml;
+ paraml.word = S_ /*""*/;
+ t = 0;
+ setexit();
+ justpr = enterhist; /* execute if not entering history */
+
+ /*
+ * Interruptible during interactive reads
+ */
+ if (setintr)
+ (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
+
+ /*
+ * For the sake of reset()
+ */
+ freelex(&paraml), freesyn(t), t = 0;
+
+ if (haderr) {
+ if (!catch) {
+ /* unwind */
+ doneinp = 0;
+ resexit(osetexit);
+ reset();
+ }
+ haderr = 0;
+ /*
+ * Every error is eventually caught here or
+ * the shell dies. It is at this
+ * point that we clean up any left-over open
+ * files, by closing all but a fixed number
+ * of pre-defined files. Thus routines don't
+ * have to worry about leaving files open due
+ * to deeper errors... they will get closed here.
+ */
+ closem();
+ continue;
+ }
+ if (doneinp) {
+ doneinp = 0;
+ break;
+ }
+ if (chkstop)
+ chkstop--;
+ if (neednote)
+ pnote();
+ if (intty && prompt && evalvec == 0) {
+ mailchk();
+ /*
+ * If we are at the end of the input buffer
+ * then we are going to read fresh stuff.
+ * Otherwise, we are rereading input and don't
+ * need or want to prompt.
+ */
+ if (fseekp == feobp)
+ printprompt();
+ }
+ err = 0;
+
+ /*
+ * Echo not only on VERBOSE, but also with history expansion.
+ */
+ if (lex(&paraml) && intty ||
+ adrof(S_verbose /*"verbose"*/)) {
+ haderr = 1;
+ prlex(&paraml);
+ haderr = 0;
+ }
+
+ /*
+ * The parser may lose space if interrupted.
+ */
+ if (setintr)
+ (void) sigblock(sigmask(SIGINT));
+
+ /*
+ * Save input text on the history list if
+ * reading in old history, or it
+ * is from the terminal at the top level and not
+ * in a loop.
+ */
+ if (enterhist || catch && intty && !whyles)
+ savehist(&paraml);
+
+ /*
+ * Print lexical error messages, except when sourcing
+ * history lists.
+ */
+ if (!enterhist && err)
+ error("%s", gettext(err));
+
+ /*
+ * If had a history command :p modifier then
+ * this is as far as we should go
+ */
+ if (justpr)
+ reset();
+
+ alias(&paraml);
+
+ /*
+ * Parse the words of the input into a parse tree.
+ */
+ t = syntax(paraml.next, &paraml, 0);
+ if (err)
+ error("%s", gettext(err));
+
+ /*
+ * Execute the parse tree
+ */
+ {
+ /*
+ * POSIX requires SIGCHLD to be held
+ * until all processes have joined the
+ * process group in order to avoid race
+ * condition.
+ */
+ int omask;
+
+ omask = sigblock(sigmask(SIGCHLD));
+ execute(t, tpgrp);
+ (void)sigsetmask(omask &~ sigmask(SIGCHLD));
+ }
+
+ if (err)
+ error("%s", gettext(err));
+ /*
+ * Made it!
+ */
+ freelex(&paraml), freesyn(t);
+ }
+ resexit(osetexit);
+}
+
+dosource(t)
+ register tchar **t;
+{
+ register tchar *f;
+ register int u;
+ bool hflg = 0;
+ tchar buf[BUFSIZ];
+
+ t++;
+ if (*t && eq(*t, S_h /*"-h"*/)) {
+ if (*++t == NOSTR)
+ bferr("Too few arguments.");
+ hflg++;
+ }
+ (void) strcpy_(buf, *t);
+ f = globone(buf);
+ u = dmove(open_(f, 0), -1);
+ xfree(f);
+ freelex(&paraml);
+ if (u < 0 && !hflg)
+ Perror(f);
+ (void) fcntl(u, F_SETFD, 1);
+ srcunit(u, 0, hflg);
+}
+
+/*
+ * Check for mail.
+ * If we are a login shell, then we don't want to tell
+ * about any mail file unless its been modified
+ * after the time we started.
+ * This prevents us from telling the user things he already
+ * knows, since the login program insists on saying
+ * "You have mail."
+ */
+mailchk()
+{
+ register struct varent *v;
+ register tchar **vp;
+ time_t t;
+ int intvl, cnt;
+ struct stat stb;
+ bool new;
+
+ v = adrof(S_mail /*"mail"*/);
+ if (v == 0)
+ return;
+ (void) time(&t);
+ vp = v->vec;
+ cnt = blklen(vp);
+ intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL;
+ if (intvl < 1)
+ intvl = 1;
+ if (chktim + intvl > t)
+ return;
+ for (; *vp; vp++) {
+ if (stat_(*vp, &stb) < 0)
+ continue;
+ new = stb.st_mtime > time0.tv_sec;
+ if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime ||
+ (stb.st_atime <= chktim && stb.st_mtime <= chktim) ||
+ loginsh && !new)
+ continue;
+ if (cnt == 1)
+ printf("You have %smail.\n", new ? "new " : "");
+ else
+ printf("%s in %t.\n", new ? "New mail" : "Mail", *vp);
+ }
+ chktim = t;
+}
+
+/*
+ * Extract a home directory from the password file
+ * The argument points to a buffer where the name of the
+ * user whose home directory is sought is currently.
+ * We write the home directory of the user back there.
+ */
+gethdir(home)
+ tchar *home;
+{
+ /* getpwname will not be modified, so we need temp. buffer */
+ char home_str[BUFSIZ];
+ tchar home_ts[BUFSIZ];
+ register struct passwd *pp /*= getpwnam(home)*/;
+
+ pp = getpwnam(tstostr(home_str, home));
+ if (pp == 0)
+ return (1);
+ (void) strcpy_(home, strtots(home_ts, pp->pw_dir));
+ return (0);
+}
+
+
+/*
+#ifdef PROF
+done(i)
+#else
+exit(i)
+#endif
+ int i;
+{
+
+ untty();
+ _exit(i);
+}
+*/
+
+printprompt()
+{
+ register tchar *cp;
+
+ if (!whyles) {
+ /*
+ * Print the prompt string
+ */
+ for (cp = value(S_prompt /*"prompt"*/); *cp; cp++)
+ if (*cp == HIST)
+ printf("%d", eventno + 1);
+ else {
+ if (*cp == '\\' && cp[1] == HIST)
+ cp++;
+ Putchar(*cp | QUOTE);
+ }
+ } else
+ /*
+ * Prompt for forward reading loop
+ * body content.
+ */
+ printf("? ");
+ flush();
+}
+
+/*
+ * Save char * block.
+ */
+tchar **
+strblktotsblk(v, num)
+ register char **v;
+ int num;
+{
+ register tchar **newv =
+ (tchar **) calloc((unsigned) (num+ 1), sizeof (tchar **));
+ tchar **onewv = newv;
+
+ while (*v && num--)
+ *newv++ = strtots(NOSTR,*v++);
+ *newv = 0;
+ return (onewv);
+}
+
+
+sigwaiting()
+{
+ _signal(SIGWAITING, sigwaiting);
+}
+
+siglwp()
+{
+ _signal(SIGLWP, siglwp);
+}
+
+
+/*
+ * Following functions and data are used for csh to do its
+ * file descriptors book keeping.
+ */
+
+static int *fdinuse = NULL; /* The list of files opened by csh */
+static int nbytesused = 0; /* no of bytes allocated to fdinuse */
+static int max_fd = 0; /* The maximum descriptor in fdinuse */
+static int my_pid; /* The process id set in initdesc() */
+static int NoFile = NOFILE; /* The number of files I can use. */
+
+/*
+ * Get the number of files this csh can use.
+ *
+ * Move the initial descriptors to their eventual
+ * resting places, closing all other units.
+ *
+ * Also, reserve 0/1/2, so NIS+ routines do not get
+ * hold of them. And initialize fdinuse list and set
+ * the current process id.
+ *
+ * If this csh was invoked from setuid'ed script file,
+ * do not close the third argument passed. The file
+ * must be one of /dev/fd/0,1,2,,,
+ * (execv() always passes three arguments when it execs a script
+ * file in a form of #! /bin/csh -b.)
+ *
+ * If is_reinit is set in initdesc_x(), then we only close the file
+ * descriptors that we actually opened (as recorded in fdinuse).
+ */
+initdesc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ initdesc_x(argc, argv, 0);
+}
+
+reinitdesc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ initdesc_x(argc, argv, 1);
+}
+
+/*
+ * Callback functions for closing all file descriptors.
+ */
+static int
+close_except(void *cd, int fd)
+{
+ int script_fd = *(int *)cd;
+
+ if (fd >= 3 && fd < NoFile && fd != script_fd)
+ (void) close(fd);
+ return (0);
+}
+
+static int
+close_inuse(void *cd, int fd)
+{
+ int script_fd = *(int *)cd;
+
+ if (fd >= 3 && fd < NoFile && fd != script_fd &&
+ CSH_FD_ISSET(fd, fdinuse)) {
+ (void) close(fd);
+ unsetfd(fd);
+ }
+ return (0);
+}
+
+initdesc_x(argc, argv, is_reinit)
+ int argc;
+ char *argv[];
+ int is_reinit;
+{
+
+ int script_fd = -1;
+ struct stat buf;
+ struct rlimit rlp;
+
+ /*
+ * Get pid of this shell
+ */
+ my_pid = getpid();
+
+ /*
+ * Get the hard limit numbers of descriptors
+ * this csh can use.
+ */
+ if (getrlimit(RLIMIT_NOFILE, &rlp) == 0)
+ NoFile = rlp.rlim_cur;
+
+ /*
+ * If this csh was invoked for executing setuid script file,
+ * the third argument passed is the special file name
+ * which should not be closed. This special file name is
+ * in the form /dev/fd/X.
+ */
+ if (argc >= 3)
+ if (sscanf(argv[2], "/dev/fd/%d", &script_fd) != 1)
+ script_fd = -1;
+ else
+ fcntl(script_fd, F_SETFD, 1); /* Make sure to close
+ * this file on exec.
+ */
+
+ if (fdinuse == NULL) {
+ nbytesused = sizeof(int) * howmany(NoFile, sizeof(int) * NBBY);
+ fdinuse = (int *) xalloc(nbytesused);
+ }
+
+ /*
+ * Close all files except 0/1/2 to get a clean
+ * file descritor space.
+ */
+ if (!is_reinit)
+ (void) fdwalk(close_except, &script_fd);
+ else
+ (void) fdwalk(close_inuse, &script_fd);
+
+ didfds = 0; /* 0, 1, 2 aren't set up */
+
+ if (fstat(0, &buf) < 0)
+ open("/dev/null", 0);
+
+ (void) fcntl(SHIN = dcopy(0, FSHIN), F_SETFD, 1);
+ (void) fcntl(SHOUT = dcopy(1, FSHOUT), F_SETFD, 1);
+ (void) fcntl(SHDIAG = dcopy(2, FSHDIAG), F_SETFD, 1);
+ (void) fcntl(OLDSTD = dcopy(SHIN, FOLDSTD), F_SETFD, 1);
+
+ /*
+ * Open 0/1/2 to avoid Nis+ functions to pick them up.
+ * Now, 0/1/2 are saved, close them and open them.
+ */
+ close(0); close(1); close(2);
+ open("/dev/null", 0);
+ dup(0);
+ dup(0);
+
+ /*
+ * Clear fd_set mask
+ */
+ if ( ! is_reinit)
+ CSH_FD_ZERO(fdinuse, nbytesused);
+}
+
+/*
+ * This routine is called after an error to close up
+ * any units which may have been left open accidentally.
+ *
+ * You only need to remove files in fdinuse list.
+ * After you have removed the files, you can clear the
+ * list and max_fd.
+ */
+closem()
+{
+ register int f;
+
+ for (f = 3; f <= max_fd; f++) {
+ if (CSH_FD_ISSET(f, fdinuse) &&
+ f != SHIN && f != SHOUT && f != SHDIAG &&
+ f != OLDSTD && f != FSHTTY)
+ close(f);
+ }
+ CSH_FD_ZERO(fdinuse, nbytesused);
+ max_fd = 0;
+}
+
+/*
+ * Reset my_pid when a new process is created. Only call this
+ * if you want the process to affect fdinuse (e.g., fork, but
+ * not vfork).
+ */
+new_process()
+{
+ my_pid = getpid();
+}
+
+
+/*
+ * Whenever Csh open/create/dup/pipe a file or files,
+ * Csh keeps track of its open files. The open files
+ * are kept in "fdinuse, Fd In Use" list.
+ *
+ * When a file descriptor is newly allocated, setfd() is
+ * used to mark the fact in "fdinuse" list.
+ * For example,
+ * fd = open("newfile", 0);
+ * setfd(fd);
+ *
+ * When a file is freed by close() function, unsetfd() is
+ * used to remove the fd from "fdinuse" list.
+ * For example,
+ * close(fd);
+ * unsetfd(fd);
+ */
+setfd(fd)
+ int fd;
+{
+ /*
+ * Because you want to avoid
+ * conflict due to vfork().
+ */
+ if (my_pid != getpid())
+ return;
+
+ if (fd >= NoFile || fd < 0)
+ return;
+
+ if (fd > max_fd)
+ max_fd = fd;
+ CSH_FD_SET(fd, fdinuse);
+}
+
+unsetfd(fd)
+ int fd;
+{
+ register int i;
+
+ /*
+ * Because you want to avoid
+ * conflict due to vfork().
+ */
+ if (my_pid != getpid())
+ return;
+
+ if (fd >= NoFile || fd < 0)
+ return;
+
+ CSH_FD_CLR(fd, fdinuse);
+ if (fd == max_fd) {
+ for (i = max_fd-1; i >= 3; i--)
+ if (CSH_FD_ISSET(i, fdinuse)) {
+ max_fd = i;
+ return;
+ }
+ max_fd = 0;
+ }
+}
+
+/*
+ * A generic call back routine to output error messages from the
+ * policy backing functions called by pfcsh.
+ */
+void
+secpolicy_print(int level, const char *msg)
+{
+ switch (level) {
+ case SECPOLICY_WARN:
+ default:
+ haderr = 1;
+ printf("%s: ", msg); /* printf() does gettext() */
+ break;
+ case SECPOLICY_ERROR:
+ bferr(msg); /* bferr() does gettext() */
+ break;
+ }
+}
diff --git a/usr/src/cmd/csh/sh.char.c b/usr/src/cmd/csh/sh.char.c
new file mode 100644
index 0000000000..8c79005dd7
--- /dev/null
+++ b/usr/src/cmd/csh/sh.char.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.char.h"
+
+unsigned short _cmap[128] = {
+/* nul soh stx etx */
+ 0, 0, 0, 0,
+
+/* eot enq ack bel */
+ 0, 0, 0, 0,
+
+/* bs ht nl vt */
+ 0, _SP|_META, _NL|_META, 0,
+
+/* np cr so si */
+ 0, 0, 0, 0,
+
+/* dle dc1 dc2 dc3 */
+ 0, 0, 0, 0,
+
+/* dc4 nak syn etb */
+ 0, 0, 0, 0,
+
+/* can em sub esc */
+ 0, 0, 0, 0,
+
+/* fs gs rs us */
+ 0, 0, 0, 0,
+
+/* sp ! " # */
+ _SP|_META, 0, _Q, _META,
+
+/* $ % & ' */
+ _DOL, 0, _META, _Q,
+
+/* ( ) * + */
+ _META, _META, _GLOB, 0,
+
+/* , - . / */
+ 0, 0, 0, 0,
+
+/* 0 1 2 3 */
+ _DIG, _DIG, _DIG, _DIG,
+
+/* 4 5 6 7 */
+ _DIG, _DIG, _DIG, _DIG,
+
+/* 8 9 : ; */
+ _DIG, _DIG, 0, _META,
+
+/* < = > ? */
+ _META, 0, _META, _GLOB,
+
+/* @ A B C */
+ 0, _LET, _LET, _LET,
+
+/* D E F G */
+ _LET, _LET, _LET, _LET,
+
+/* H I J K */
+ _LET, _LET, _LET, _LET,
+
+/* L M N O */
+ _LET, _LET, _LET, _LET,
+
+/* P Q R S */
+ _LET, _LET, _LET, _LET,
+
+/* T U V W */
+ _LET, _LET, _LET, _LET,
+
+/* X Y Z [ */
+ _LET, _LET, _LET, _GLOB,
+
+/* \ ] ^ _ */
+ _ESC, 0, 0, _LET,
+
+/* ` a b c */
+ _Q1|_GLOB, _LET, _LET, _LET,
+
+/* d e f g */
+ _LET, _LET, _LET, _LET,
+
+/* h i j k */
+ _LET, _LET, _LET, _LET,
+
+/* l m n o */
+ _LET, _LET, _LET, _LET,
+
+/* p q r s */
+ _LET, _LET, _LET, _LET,
+
+/* t u v w */
+ _LET, _LET, _LET, _LET,
+
+/* x y z { */
+ _LET, _LET, _LET, _GLOB,
+
+/* | } ~ del */
+ _META, 0, 0, 0,
+};
diff --git a/usr/src/cmd/csh/sh.char.h b/usr/src/cmd/csh/sh.char.h
new file mode 100644
index 0000000000..3a46db7ba9
--- /dev/null
+++ b/usr/src/cmd/csh/sh.char.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Macros to classify characters.
+ */
+
+#ifdef MBCHAR
+#include <wchar.h>
+#include <wctype.h>
+#define isauxspZ (!isascii(Z)&&!(Z&QUOTE)&&iswspace(Z))
+#define isauxsp(c) (Z=((unsigned)(c)), isauxspZ)
+/* Regocnizes non-ASCII space characters. */
+#else
+#include <ctype.h>
+/* macros of macros to reduce further #ifdef MBCHAR later. Please be patient!*/
+#define iswdigit(c) isdigit(c)
+#define iswalpha(c) isalpha(c)
+#define isphonogram(c) 0
+#define isideogram(c) 0
+#define isauxsp(c) 0
+#define isauxspZ 0
+#endif
+extern unsigned short _cmap[];/* Defined in sh.char.c */
+unsigned int Z; /* A place to save macro arg to avoid side-effect!*/
+
+#define _Q 0x01 /* '" */
+#define _Q1 0x02 /* ` */
+#define _SP 0x04 /* space and tab */
+#define _NL 0x08 /* \n */
+#define _META 0x10 /* lex meta characters, sp #'`";&<>()|\t\n */
+#define _GLOB 0x20 /* glob characters, *?{[` */
+#define _ESC 0x40 /* \ */
+#define _DOL 0x80 /* $ */
+#define _DIG 0x100 /* 0-9 */
+#define _LET 0x200 /* a-z, A-Z, _ NO LONGER OF REAL USE. */
+
+
+#define quoted(c) ((unsigned)(c) & QUOTE)
+
+#define cmapZ(bits) (isascii(Z)?(_cmap[Z] & (bits)):0)
+#define cmap(c, bits) (Z=((unsigned)(c)), cmapZ(bits))
+
+#define isglob(c) cmap(c, _GLOB)
+#define ismeta(c) cmap(c, _META)
+#define digit(c) cmap(c, _DIG)
+#define issp(c) (Z=((unsigned)(c)), cmapZ( _SP)||isauxspZ)
+/*WAS isspace(c)*/
+#define isspnl(c) (Z=((unsigned)(c)), cmapZ( _SP|_NL)||isauxspZ)
+#define letter(c) \
+ (Z=((unsigned)(c)), !quoted(Z)&&(iswalpha(Z)||((Z)=='_')\
+ ||isphonogram(Z)||isideogram(Z)))
+#define alnum(c) \
+ (Z=((unsigned)(c)), !quoted(Z)&&(iswalpha(Z)||((Z)=='_')\
+ ||iswdigit(Z)||isphonogram(Z)||isideogram(Z)))
diff --git a/usr/src/cmd/csh/sh.debug.c b/usr/src/cmd/csh/sh.debug.c
new file mode 100644
index 0000000000..379a327f93
--- /dev/null
+++ b/usr/src/cmd/csh/sh.debug.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+
+
+#ifdef TRACE
+#include <stdio.h>
+FILE *trace;
+/*
+ * Trace routines
+ */
+#define TRACEFILE "/tmp/trace.XXXXXX"
+
+/*
+ * Initialie trace file.
+ * Called from main.
+ */
+trace_init()
+{
+ extern char *mktemp();
+ char name[128];
+ char *p;
+
+ strcpy(name, TRACEFILE);
+ p = mktemp(name);
+ trace = fopen(p, "w");
+}
+
+/*
+ * write message to trace file
+ */
+/*VARARGS1*/
+tprintf(fmt,a,b,c,d,e,f,g,h,i,j)
+ char *fmt;
+{
+ if (trace) {
+ fprintf(trace, fmt, a,b,c,d,e,f,g,h,i,j);
+ fflush(trace);
+ }
+}
+#endif
diff --git a/usr/src/cmd/csh/sh.dir.c b/usr/src/cmd/csh/sh.dir.c
new file mode 100644
index 0000000000..407b1ec6cc
--- /dev/null
+++ b/usr/src/cmd/csh/sh.dir.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.dir.h"
+#include "sh.tconst.h"
+
+/*
+ * C Shell - directory management
+ */
+
+struct directory *dfind();
+tchar *dfollow();
+tchar *dcanon();
+struct directory dhead; /* "head" of loop */
+int printd; /* force name to be printed */
+static tchar *fakev[] = { S_dirs, NOSTR };
+
+/*
+ * dinit - initialize current working directory
+ */
+dinit(hp)
+ tchar *hp;
+{
+ register tchar *cp;
+ register struct directory *dp;
+ tchar path[MAXPATHLEN];
+
+#ifdef TRACE
+ tprintf("TRACE- dinit()\n");
+#endif
+ /*
+ * If this is a login shell, we should have a home directory. But,
+ * if we got here via 'su - <user>' where the user has no directory
+ * in his passwd file, then su has passed HOME=<nothing>, so hp is
+ * non-null, but has zero length. Thus, we do not know the current
+ * working directory based on the home directory.
+ */
+ if (loginsh && hp && *hp)
+ cp = hp;
+ else {
+ cp = getwd_(path);
+ if (cp == NULL) {
+ printf ("Warning: cannot determine current directory\n");
+ cp = S_DOT;
+ }
+ }
+ dp = (struct directory *)calloc(sizeof (struct directory), 1);
+ dp->di_name = savestr(cp);
+ dp->di_count = 0;
+ dhead.di_next = dhead.di_prev = dp;
+ dp->di_next = dp->di_prev = &dhead;
+ printd = 0;
+ dnewcwd(dp);
+}
+
+/*
+ * dodirs - list all directories in directory loop
+ */
+dodirs(v)
+ tchar **v;
+{
+ register struct directory *dp;
+ bool lflag;
+ tchar *hp = value(S_home);
+
+#ifdef TRACE
+ tprintf("TRACE- dodirs()\n");
+#endif
+ if (*hp == '\0')
+ hp = NOSTR;
+ if (*++v != NOSTR)
+ if (eq(*v, S_MINl /* "-l" */) && *++v == NOSTR)
+ lflag = 1;
+ else
+ error("Usage: dirs [ -l ]");
+ else
+ lflag = 0;
+ dp = dcwd;
+ do {
+ if (dp == &dhead)
+ continue;
+ if (!lflag && hp != NOSTR) {
+ dtildepr(hp, dp->di_name);
+ } else
+ printf("%t", dp->di_name);
+ printf(" ");
+ } while ((dp = dp->di_prev) != dcwd);
+ printf("\n");
+}
+
+dtildepr(home, dir)
+ register tchar *home, *dir;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dtildepr()\n");
+#endif
+ if (!eq(home, S_SLASH /* "/" */) && prefix(home, dir))
+ printf("~%t", dir + strlen_(home));
+ else
+ printf("%t", dir);
+}
+
+/*
+ * dochngd - implement chdir command.
+ */
+dochngd(v)
+ tchar **v;
+{
+ register tchar *cp;
+ register struct directory *dp;
+
+#ifdef TRACE
+ tprintf("TRACE- dochngd()\n");
+#endif
+ printd = 0;
+ if (*++v == NOSTR) {
+ if ((cp = value(S_home)) == NOSTR || *cp == 0)
+ bferr("No home directory");
+ if (chdir_(cp) < 0)
+ bferr("Can't change to home directory");
+ cp = savestr(cp);
+ } else if ((dp = dfind(*v)) != 0) {
+ printd = 1;
+ if (chdir_(dp->di_name) < 0)
+ Perror(dp->di_name);
+ dcwd->di_prev->di_next = dcwd->di_next;
+ dcwd->di_next->di_prev = dcwd->di_prev;
+ goto flushcwd;
+ } else
+ cp = dfollow(*v);
+ dp = (struct directory *)calloc(sizeof (struct directory), 1);
+ dp->di_name = cp;
+ dp->di_count = 0;
+ dp->di_next = dcwd->di_next;
+ dp->di_prev = dcwd->di_prev;
+ dp->di_prev->di_next = dp;
+ dp->di_next->di_prev = dp;
+flushcwd:
+ dfree(dcwd);
+ dnewcwd(dp);
+}
+
+/*
+ * dfollow - change to arg directory; fall back on cdpath if not valid
+ */
+tchar *
+dfollow(cp)
+ register tchar *cp;
+{
+ register tchar *dp;
+ struct varent *c;
+ int cdhashval, cdhashval1;
+ int index;
+ int slash; /*slashes in the argument*/
+ tchar *fullpath;
+ tchar *slashcp; /*cp string prepended with a slash*/
+
+#ifdef TRACE
+ tprintf("TRACE- dfollow()\n");
+#endif
+ cp = globone(cp);
+ if (chdir_(cp) >= 0)
+ goto gotcha;
+
+ /*
+ * If the directory argument has a slash in it,
+ * for example, directory/directory, then can't
+ * find that in the cache table.
+ */
+ slash = any('/', cp);
+
+ /*
+ * Try interpreting wrt successive components of cdpath.
+ * cdpath caching is turned off or directory argument
+ * has a slash in it.
+ */
+ if (cp[0] != '/'
+ && !prefix(S_DOTSLA /* "./" */, cp)
+ && !prefix(S_DOTDOTSLA /* "../" */, cp)
+ && (c = adrof(S_cdpath))
+ && ( !havhash2 || slash) ) {
+ tchar **cdp;
+ register tchar *p;
+ tchar buf[MAXPATHLEN];
+
+ for (cdp = c->vec; *cdp; cdp++) {
+ for (dp = buf, p = *cdp; *dp++ = *p++;)
+ ;
+ dp[-1] = '/';
+ for (p = cp; *dp++ = *p++;)
+ ;
+ if (chdir_(buf) >= 0) {
+ printd = 1;
+ xfree(cp);
+ cp = savestr(buf);
+ goto gotcha;
+ }
+ }
+ }
+
+ /* cdpath caching turned on */
+ if (cp[0] != '/'
+ && !prefix(S_DOTSLA /* "./" */, cp)
+ && !prefix(S_DOTDOTSLA /* "../" */, cp)
+ && (c = adrof(S_cdpath))
+ && havhash2 && !slash ) {
+ tchar **pv;
+
+ /* If no cdpath or no paths in cdpath, leave */
+ if ( c == 0 || c->vec[0]== 0 )
+ pv = justabs;
+ else
+ pv = c->vec;
+
+ slashcp = strspl(S_SLASH, cp);
+
+ cdhashval = hashname(cp);
+
+ /*index points to next path component to test*/
+ index=0;
+
+ /*
+ * Look at each path in cdpath until get a match.
+ * Only look at those path beginning with a slash
+ */
+ do {
+ /* only check cache for absolute pathnames */
+ if ( pv[0][0] == '/' ) {
+ cdhashval1 = hash(cdhashval, index);
+ if (bit(xhash2, cdhashval1)) {
+ /*
+ * concatenate found path with
+ * arg directory
+ */
+ fullpath = strspl(*pv, slashcp);
+ if (chdir_(fullpath) >= 0) {
+ printd = 1;
+ xfree(cp);
+ cp = savestr(fullpath);
+ xfree(slashcp);
+ xfree(fullpath);
+ goto gotcha;
+ }
+ }
+ }
+ /*
+ * relative pathnames are not cached, and must be
+ * checked manually
+ */
+ else {
+ register tchar *p;
+ tchar buf[MAXPATHLEN];
+
+ for (dp = buf, p = *pv; *dp++ = *p++; )
+ ;
+ dp[-1] = '/';
+ for (p = cp; *dp++ = *p++; )
+ ;
+ if (chdir_(buf) >= 0) {
+ printd = 1;
+ xfree(cp);
+ cp = savestr(buf);
+ xfree(slashcp);
+ goto gotcha;
+ }
+ }
+ pv++;
+ index++;
+ } while (*pv);
+ }
+
+ /*
+ * Try dereferencing the variable named by the argument.
+ */
+ dp = value(cp);
+ if ((dp[0] == '/' || dp[0] == '.') && chdir_(dp) >= 0) {
+ xfree(cp);
+ cp = savestr(dp);
+ printd = 1;
+ goto gotcha;
+ }
+ xfree(cp); /* XXX, use after free */
+ Perror(cp);
+
+gotcha:
+ if (*cp != '/') {
+ register tchar *p, *q;
+ int cwdlen;
+ int len;
+
+ /*
+ * All in the name of efficiency?
+ */
+
+ if ( ( cwdlen = (strlen_(dcwd->di_name) ) ) == 1 ){
+ if ( *dcwd->di_name == '/' ) /* root */
+ cwdlen = 0;
+ else
+ {
+ /*
+ * if we are here, when the shell started
+ * it was unable to getwd(), lets try it again
+ */
+ tchar path[MAXPATHLEN];
+
+ p = getwd_(path);
+ if (p == NULL)
+ error("cannot determine current directory");
+ else
+ {
+ xfree(dcwd->di_name);
+ dcwd->di_name = savestr(p);
+ xfree(cp);
+ cp = savestr(p);
+ return dcanon(cp, cp);
+ }
+
+ }
+ }
+ /*
+ *
+ * for (p = cp; *p++;)
+ * ;
+ * dp = (tchar *)xalloc((unsigned) (cwdlen + (p - cp) + 1)*sizeof (tchar))
+ */
+ len = strlen_(cp);
+ dp = (tchar *)xalloc((unsigned) (cwdlen + len + 2)*sizeof(tchar));
+ for (p = dp, q = dcwd->di_name; *p++ = *q++;)
+ ;
+ if (cwdlen)
+ p[-1] = '/';
+ else
+ p--; /* don't add a / after root */
+ for (q = cp; *p++ = *q++;)
+ ;
+ xfree(cp);
+ cp = dp;
+ dp += cwdlen;
+ } else
+ dp = cp;
+ return dcanon(cp, dp);
+}
+
+/*
+ * dopushd - push new directory onto directory stack.
+ * with no arguments exchange top and second.
+ * with numeric argument (+n) bring it to top.
+ */
+dopushd(v)
+ tchar **v;
+{
+ register struct directory *dp;
+
+#ifdef TRACE
+ tprintf("TRACE- dopushd()\n");
+#endif
+ printd = 1;
+ if (*++v == NOSTR) {
+ if ((dp = dcwd->di_prev) == &dhead)
+ dp = dhead.di_prev;
+ if (dp == dcwd)
+ bferr("No other directory");
+ if (chdir_(dp->di_name) < 0)
+ Perror(dp->di_name);
+ dp->di_prev->di_next = dp->di_next;
+ dp->di_next->di_prev = dp->di_prev;
+ dp->di_next = dcwd->di_next;
+ dp->di_prev = dcwd;
+ dcwd->di_next->di_prev = dp;
+ dcwd->di_next = dp;
+ } else if (dp = dfind(*v)) {
+ if (chdir_(dp->di_name) < 0)
+ Perror(dp->di_name);
+ } else {
+ register tchar *cp;
+
+ cp = dfollow(*v);
+ dp = (struct directory *)calloc(sizeof (struct directory), 1);
+ dp->di_name = cp;
+ dp->di_count = 0;
+ dp->di_prev = dcwd;
+ dp->di_next = dcwd->di_next;
+ dcwd->di_next = dp;
+ dp->di_next->di_prev = dp;
+ }
+ dnewcwd(dp);
+}
+
+/*
+ * dfind - find a directory if specified by numeric (+n) argument
+ */
+struct directory *
+dfind(cp)
+ register tchar *cp;
+{
+ register struct directory *dp;
+ register int i;
+ register tchar *ep;
+
+#ifdef TRACE
+ tprintf("TRACE- dfind()\n");
+#endif
+ if (*cp++ != '+')
+ return (0);
+ for (ep = cp; digit(*ep); ep++)
+ continue;
+ if (*ep)
+ return (0);
+ i = getn(cp);
+ if (i <= 0)
+ return (0);
+ for (dp = dcwd; i != 0; i--) {
+ if ((dp = dp->di_prev) == &dhead)
+ dp = dp->di_prev;
+ if (dp == dcwd)
+ bferr("Directory stack not that deep");
+ }
+ return (dp);
+}
+
+/*
+ * dopopd - pop a directory out of the directory stack
+ * with a numeric argument just discard it.
+ */
+dopopd(v)
+ tchar **v;
+{
+ register struct directory *dp, *p;
+
+#ifdef TRACE
+ tprintf("TRACE- dopopd()\n");
+#endif
+ printd = 1;
+ if (*++v == NOSTR)
+ dp = dcwd;
+ else if ((dp = dfind(*v)) == 0)
+ bferr("Invalid argument");
+ if (dp->di_prev == &dhead && dp->di_next == &dhead)
+ bferr("Directory stack empty");
+ if (dp == dcwd) {
+ if ((p = dp->di_prev) == &dhead)
+ p = dhead.di_prev;
+ if (chdir_(p->di_name) < 0)
+ Perror(p->di_name);
+ }
+ dp->di_prev->di_next = dp->di_next;
+ dp->di_next->di_prev = dp->di_prev;
+ if (dp == dcwd)
+ dnewcwd(p);
+ else
+ dodirs(fakev);
+ dfree(dp);
+}
+
+/*
+ * dfree - free the directory (or keep it if it still has ref count)
+ */
+dfree(dp)
+ register struct directory *dp;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dfree()\n");
+#endif
+ if (dp->di_count != 0)
+ dp->di_next = dp->di_prev = 0;
+ else
+ xfree(dp->di_name), xfree( (tchar *)dp);
+}
+
+/*
+ * dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
+ * We are of course assuming that the file system is standardly
+ * constructed (always have ..'s, directories have links).
+ *
+ * If the hardpaths shell variable is set, resolve the
+ * resulting pathname to contain no symbolic link components.
+ */
+tchar *
+dcanon(cp, p)
+ register tchar *cp, *p;
+{
+ register tchar *sp; /* rightmost component currently under
+ consideration */
+ register tchar *p1, /* general purpose */
+ *p2;
+ bool slash, dotdot, hardpaths;
+
+#ifdef TRACE
+ tprintf("TRACE- dcannon()\n");
+#endif
+
+ if (*cp != '/')
+ abort();
+
+ if (hardpaths = (adrof(S_hardpaths) != NULL)) {
+ /*
+ * Be paranoid: don't trust the initial prefix
+ * to be symlink-free.
+ */
+ p = cp;
+ }
+
+ /*
+ * Loop invariant: cp points to the overall path start,
+ * p to its as yet uncanonicalized trailing suffix.
+ */
+ while (*p) { /* for each component */
+ sp = p; /* save slash address */
+
+ while (*++p == '/') /* flush extra slashes */
+ ;
+ if (p != ++sp)
+ for (p1 = sp, p2 = p; *p1++ = *p2++;)
+ ;
+
+ p = sp; /* save start of component */
+ slash = 0;
+ if (*p)
+ while (*++p) /* find next slash or end of path */
+ if (*p == '/') {
+ slash = 1;
+ *p = '\0';
+ break;
+ }
+
+ if (*sp == '\0') {
+ /* component is null */
+ if (--sp == cp) /* if path is one tchar (i.e. /) */
+ break;
+ else
+ *sp = '\0';
+ continue;
+ }
+
+ if (sp[0] == '.' && sp[1] == '\0') {
+ /* Squeeze out component consisting of "." */
+ if (slash) {
+ for (p1 = sp, p2 = p + 1; *p1++ = *p2++;)
+ ;
+ p = --sp;
+ } else if (--sp != cp)
+ *sp = '\0';
+ continue;
+ }
+
+ /*
+ * At this point we have a path of the form "x/yz",
+ * where "x" is null or rooted at "/", "y" is a single
+ * component, and "z" is possibly null. The pointer cp
+ * points to the start of "x", sp to the start of "y",
+ * and p to the beginning of "z", which has been forced
+ * to a null.
+ */
+ /*
+ * Process symbolic link component. Provided that either
+ * the hardpaths shell variable is set or "y" is really
+ * ".." we replace the symlink with its contents. The
+ * second condition for replacement is necessary to make
+ * the command "cd x/.." produce the same results as the
+ * sequence "cd x; cd ..".
+ *
+ * Note that the two conditions correspond to different
+ * potential symlinks. When hardpaths is set, we must
+ * check "x/y"; otherwise, when "y" is known to be "..",
+ * we check "x".
+ */
+ dotdot = sp[0] == '.' && sp[1] == '.' && sp[2] == '\0';
+ if (hardpaths || dotdot) {
+ tchar link[MAXPATHLEN];
+ int cc;
+ tchar *newcp;
+
+ /*
+ * Isolate the end of the component that is to
+ * be checked for symlink-hood.
+ */
+ sp--;
+ if (! hardpaths)
+ *sp = '\0';
+
+ /*
+ * See whether the component is really a symlink by
+ * trying to read it. If the read succeeds, it is.
+ */
+ if ((hardpaths || sp > cp) &&
+ (cc = readlink_(cp, link, MAXPATHLEN)) >= 0) {
+ /*
+ * readlink_ put null, so we don't need this.
+ */
+ /* link[cc] = '\0'; */
+
+ /* Restore path. */
+ if (slash)
+ *p = '/';
+
+ /*
+ * Point p at the start of the trailing
+ * path following the symlink component.
+ * It's already there is hardpaths is set.
+ */
+ if (! hardpaths) {
+ /* Restore path as well. */
+ *(p = sp) = '/';
+ }
+
+ /*
+ * Find length of p.
+ */
+ for (p1 = p; *p1++;)
+ ;
+
+ if (*link != '/') {
+ /*
+ * Relative path: replace the symlink
+ * component with its value. First,
+ * set sp to point to the slash at
+ * its beginning. If hardpaths is
+ * set, this is already the case.
+ */
+ if (! hardpaths) {
+ while (*--sp != '/')
+ ;
+ }
+
+ /*
+ * Terminate the leading part of the
+ * path, including trailing slash.
+ */
+ sp++;
+ *sp = '\0';
+
+ /*
+ * New length is: "x/" + link + "z"
+ */
+ p1 = newcp = (tchar *)xalloc((unsigned)
+ ((sp - cp) + cc + (p1 - p))*sizeof (tchar));
+ /*
+ * Copy new path into newcp
+ */
+ for (p2 = cp; *p1++ = *p2++;)
+ ;
+ for (p1--, p2 = link; *p1++ = *p2++;)
+ ;
+ for (p1--, p2 = p; *p1++ = *p2++;)
+ ;
+ /*
+ * Restart canonicalization at
+ * expanded "/y".
+ */
+ p = sp - cp - 1 + newcp;
+ } else {
+ /*
+ * New length is: link + "z"
+ */
+ p1 = newcp = (tchar *)xalloc((unsigned)
+ (cc + (p1 - p))*sizeof (tchar));
+ /*
+ * Copy new path into newcp
+ */
+ for (p2 = link; *p1++ = *p2++;)
+ ;
+ for (p1--, p2 = p; *p1++ = *p2++;)
+ ;
+ /*
+ * Restart canonicalization at beginning
+ */
+ p = newcp;
+ }
+ xfree(cp);
+ cp = newcp;
+ continue; /* canonicalize the link */
+ }
+
+ /* The component wasn't a symlink after all. */
+ if (! hardpaths)
+ *sp = '/';
+ }
+
+ if (dotdot) {
+ if (sp != cp)
+ while (*--sp != '/')
+ ;
+ if (slash) {
+ for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;)
+ ;
+ p = sp;
+ } else if (cp == sp)
+ *++sp = '\0';
+ else
+ *sp = '\0';
+ continue;
+ }
+
+ if (slash)
+ *p = '/';
+ }
+ return cp;
+}
+
+/*
+ * dnewcwd - make a new directory in the loop the current one
+ * and export its name to the PWD environment variable.
+ */
+dnewcwd(dp)
+ register struct directory *dp;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dnewcwd()\n");
+#endif
+ dcwd = dp;
+#ifdef notdef
+ /*
+ * If we have a fast version of getwd available
+ * and hardpaths is set, it would be reasonable
+ * here to verify that dcwd->di_name really does
+ * name the current directory. Later...
+ */
+#endif notdef
+
+ didchdir=1;
+ set(S_cwd, savestr(dcwd->di_name));
+ didchdir=0;
+ local_setenv(S_PWD, dcwd->di_name);
+ if (printd)
+ dodirs(fakev);
+}
diff --git a/usr/src/cmd/csh/sh.dir.h b/usr/src/cmd/csh/sh.dir.h
new file mode 100644
index 0000000000..78ece4a533
--- /dev/null
+++ b/usr/src/cmd/csh/sh.dir.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Structure for entries in directory stack.
+ */
+struct directory {
+ struct directory *di_next; /* next in loop */
+ struct directory *di_prev; /* prev in loop */
+ unsigned short *di_count; /* refcount of processes */
+ tchar *di_name; /* actual name */
+};
+struct directory *dcwd; /* the one we are in now */
diff --git a/usr/src/cmd/csh/sh.dol.c b/usr/src/cmd/csh/sh.dol.c
new file mode 100644
index 0000000000..ed97399eb5
--- /dev/null
+++ b/usr/src/cmd/csh/sh.dol.c
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h> /* for lseek prototype */
+#include "sh.h"
+#include "sh.tconst.h"
+
+/*
+ * C shell
+ */
+
+/*
+ * These routines perform variable substitution and quoting via ' and ".
+ * To this point these constructs have been preserved in the divided
+ * input words. Here we expand variables and turn quoting via ' and " into
+ * QUOTE bits on characters (which prevent further interpretation).
+ * If the `:q' modifier was applied during history expansion, then
+ * some QUOTEing may have occurred already, so we dont "trim()" here.
+ */
+
+int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
+tchar *Dcp, **Dvp; /* Input vector for Dreadc */
+
+#define DEOF -1
+
+#define unDgetC(c) Dpeekc = c
+
+#define QUOTES (_Q|_Q1|_ESC) /* \ ' " ` */
+
+/*
+ * The following variables give the information about the current
+ * $ expansion, recording the current word position, the remaining
+ * words within this expansion, the count of remaining words, and the
+ * information about any : modifier which is being applied.
+ */
+tchar *dolp; /* Remaining chars from this word */
+tchar **dolnxt; /* Further words */
+int dolcnt; /* Count of further words */
+tchar dolmod; /* : modifier character */
+int dolmcnt; /* :gx -> 10000, else 1 */
+
+/*
+ * Fix up the $ expansions and quotations in the
+ * argument list to command t.
+ */
+Dfix(t)
+ register struct command *t;
+{
+ register tchar **pp;
+ register tchar *p;
+
+#ifdef TRACE
+ tprintf("TRACE- Dfix()\n");
+#endif
+ if (noexec)
+ return;
+ /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
+ for (pp = t->t_dcom; p = *pp++;)
+ while (*p)
+ if (cmap(*p++, _DOL|QUOTES)) { /* $, \, ', ", ` */
+ Dfix2(t->t_dcom); /* found one */
+ blkfree(t->t_dcom);
+ t->t_dcom = gargv;
+ gargv = 0;
+ return;
+ }
+}
+
+/*
+ * $ substitute one word, for i/o redirection
+ */
+tchar *
+Dfix1(cp)
+ register tchar *cp;
+{
+ tchar *Dv[2];
+
+#ifdef TRACE
+ tprintf("TRACE- Dfix1()\n");
+#endif
+ if (noexec)
+ return (0);
+ Dv[0] = cp; Dv[1] = NOSTR;
+ Dfix2(Dv);
+ if (gargc != 1) {
+ setname(cp);
+ bferr("Ambiguous");
+ }
+ cp = savestr(gargv[0]);
+ blkfree(gargv), gargv = 0;
+ return (cp);
+}
+
+/*
+ * Subroutine to do actual fixing after state initialization.
+ */
+Dfix2(v)
+ tchar **v;
+{
+ tchar *agargv[GAVSIZ];
+
+#ifdef TRACE
+ tprintf("TRACE- Dfix2()\n");
+#endif
+ ginit(agargv); /* Initialize glob's area pointers */
+ Dvp = v; Dcp = S_ /* "" */;/* Setup input vector for Dreadc */
+ unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */
+ dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */
+ while (Dword())
+ continue;
+ gargv = copyblk(gargv);
+}
+
+/*
+ * Get a word. This routine is analogous to the routine
+ * word() in sh.lex.c for the main lexical input. One difference
+ * here is that we don't get a newline to terminate our expansion.
+ * Rather, DgetC will return a DEOF when we hit the end-of-input.
+ */
+Dword()
+{
+ register int c, c1;
+ static tchar *wbuf = NULL;
+ static int wbufsiz = BUFSIZ;
+ register int wp = 0;
+ register bool dolflg;
+ bool sofar = 0;
+#define DYNAMICBUFFER() \
+ do { \
+ if (wp >= wbufsiz) { \
+ wbufsiz += BUFSIZ; \
+ wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
+ } \
+ } while (0)
+
+#ifdef TRACE
+ tprintf("TRACE- Dword()\n");
+#endif
+ if (wbuf == NULL)
+ wbuf = xalloc((wbufsiz+1) * sizeof (tchar));
+loop:
+ c = DgetC(DODOL);
+ switch (c) {
+
+ case DEOF:
+deof:
+ if (sofar == 0)
+ return (0);
+ /* finish this word and catch the code above the next time */
+ unDredc(c);
+ /* fall into ... */
+
+ case '\n':
+ wbuf[wp] = 0;
+ goto ret;
+
+ case ' ':
+ case '\t':
+ goto loop;
+
+ case '`':
+ /* We preserve ` quotations which are done yet later */
+ wbuf[wp++] = c;
+ case '\'':
+ case '"':
+ /*
+ * Note that DgetC never returns a QUOTES character
+ * from an expansion, so only true input quotes will
+ * get us here or out.
+ */
+ c1 = c;
+ dolflg = c1 == '"' ? DODOL : 0;
+ for (;;) {
+ c = DgetC(dolflg);
+ if (c == c1)
+ break;
+ if (c == '\n' || c == DEOF)
+ error("Unmatched %c", (tchar) c1);
+ if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
+ --wp;
+ DYNAMICBUFFER();
+ switch (c1) {
+
+ case '"':
+ /*
+ * Leave any `s alone for later.
+ * Other chars are all quoted, thus `...`
+ * can tell it was within "...".
+ */
+ wbuf[wp++] = c == '`' ? '`' : c | QUOTE;
+ break;
+
+ case '\'':
+ /* Prevent all further interpretation */
+ wbuf[wp++] = c | QUOTE;
+ break;
+
+ case '`':
+ /* Leave all text alone for later */
+ wbuf[wp++] = c;
+ break;
+ }
+ }
+ if (c1 == '`') {
+ DYNAMICBUFFER();
+ wbuf[wp++] = '`';
+ }
+ goto pack; /* continue the word */
+
+ case '\\':
+ c = DgetC(0); /* No $ subst! */
+ if (c == '\n' || c == DEOF)
+ goto loop;
+ c |= QUOTE;
+ break;
+#ifdef MBCHAR /* Could be a space char from aux. codeset. */
+ default:
+ if (isauxsp(c)) goto loop;
+#endif /* MBCHAR */
+ }
+ unDgetC(c);
+pack:
+ sofar = 1;
+ /* pack up more characters in this word */
+ for (;;) {
+ c = DgetC(DODOL);
+ if (c == '\\') {
+ c = DgetC(0);
+ if (c == DEOF)
+ goto deof;
+ if (c == '\n')
+ c = ' ';
+ else
+ c |= QUOTE;
+ }
+ if (c == DEOF)
+ goto deof;
+ if (cmap(c, _SP|_NL|_Q|_Q1) ||
+ isauxsp(c)) { /* sp \t\n'"` or aux. sp */
+ unDgetC(c);
+ if (cmap(c, QUOTES))
+ goto loop;
+ DYNAMICBUFFER();
+ wbuf[wp++] = 0;
+ goto ret;
+ }
+ DYNAMICBUFFER();
+ wbuf[wp++] = c;
+ }
+ret:
+ Gcat(S_ /* "" */, wbuf);
+ return (1);
+}
+
+/*
+ * Get a character, performing $ substitution unless flag is 0.
+ * Any QUOTES character which is returned from a $ expansion is
+ * QUOTEd so that it will not be recognized above.
+ */
+DgetC(flag)
+ register int flag;
+{
+ register int c;
+
+top:
+ if (c = Dpeekc) {
+ Dpeekc = 0;
+ return (c);
+ }
+ if (lap) {
+ c = *lap++ & (QUOTE|TRIM);
+ if (c == 0) {
+ lap = 0;
+ goto top;
+ }
+quotspec:
+ /*
+ * don't quote things if there was an error (err!=0)
+ * the input is original, not from a substitution and
+ * therefore should not be quoted
+ */
+ if (!err && cmap(c, QUOTES))
+ return (c | QUOTE);
+ return (c);
+ }
+ if (dolp) {
+ if (c = *dolp++ & (QUOTE|TRIM))
+ goto quotspec;
+ if (dolcnt > 0) {
+ setDolp(*dolnxt++);
+ --dolcnt;
+ return (' ');
+ }
+ dolp = 0;
+ }
+ if (dolcnt > 0) {
+ setDolp(*dolnxt++);
+ --dolcnt;
+ goto top;
+ }
+ c = Dredc();
+ if (c == '$' && flag) {
+ Dgetdol();
+ goto top;
+ }
+ return (c);
+}
+
+tchar *nulvec[] = { 0 };
+struct varent nulargv = { nulvec, S_argv, 0 };
+
+/*
+ * Handle the multitudinous $ expansion forms.
+ * Ugh.
+ */
+Dgetdol()
+{
+ register tchar *np;
+ register struct varent *vp;
+ tchar name[MAX_VREF_LEN];
+ int c, sc;
+ int subscr = 0, lwb = 1, upb = 0;
+ bool dimen = 0, bitset = 0;
+ tchar wbuf[BUFSIZ];
+
+#ifdef TRACE
+ tprintf("TRACE- Dgetdol()\n");
+#endif
+ dolmod = dolmcnt = 0;
+ c = sc = DgetC(0);
+ if (c == '{')
+ c = DgetC(0); /* sc is { to take } later */
+ if ((c & TRIM) == '#')
+ dimen++, c = DgetC(0); /* $# takes dimension */
+ else if (c == '?')
+ bitset++, c = DgetC(0); /* $? tests existence */
+ switch (c) {
+
+ case '$':
+ if (dimen || bitset)
+syntax:
+ error("Variable syntax"); /* No $?$, $#$ */
+ setDolp(doldol);
+ goto eatbrac;
+
+ case '<'|QUOTE:
+ if (dimen || bitset)
+ goto syntax; /* No $?<, $#< */
+ for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) {
+ if (np >= &wbuf[BUFSIZ-1])
+ error("$< line too long");
+ if (*np <= 0 || *np == '\n')
+ break;
+ }
+ *np = 0;
+ /*
+ * KLUDGE: dolmod is set here because it will
+ * cause setDolp to call domod and thus to copy wbuf.
+ * Otherwise setDolp would use it directly. If we saved
+ * it ourselves, no one would know when to free it.
+ * The actual function of the 'q' causes filename
+ * expansion not to be done on the interpolated value.
+ */
+ dolmod = 'q';
+ dolmcnt = 10000;
+ setDolp(wbuf);
+ goto eatbrac;
+
+ case DEOF:
+ case '\n':
+ goto syntax;
+
+ case '*':
+ (void) strcpy_(name, S_argv);
+ vp = adrof(S_argv);
+ subscr = -1; /* Prevent eating [...] */
+ break;
+
+ default:
+ np = name;
+ if (digit(c)) {
+ if (dimen)
+ goto syntax; /* No $#1, e.g. */
+ subscr = 0;
+ do {
+ subscr = subscr * 10 + c - '0';
+ c = DgetC(0);
+ } while (digit(c));
+ unDredc(c);
+ if (subscr < 0)
+ error("Subscript out of range");
+ if (subscr == 0) {
+ if (bitset) {
+ dolp = file ? S_1/*"1"*/ : S_0/*"0"*/;
+ goto eatbrac;
+ }
+ if (file == 0)
+ error("No file for $0");
+ setDolp(file);
+ goto eatbrac;
+ }
+ if (bitset)
+ goto syntax;
+ vp = adrof(S_argv);
+ if (vp == 0) {
+ vp = &nulargv;
+ goto eatmod;
+ }
+ break;
+ }
+ if (!alnum(c))
+ goto syntax;
+ for (;;) {
+ *np++ = c;
+ c = DgetC(0);
+ if (!alnum(c))
+ break;
+ /* if variable name is > 20, complain */
+ if (np >= &name[MAX_VAR_LEN])
+ error("Variable name too long");
+
+ }
+ *np++ = 0;
+ unDredc(c);
+ vp = adrof(name);
+ }
+ if (bitset) {
+ /* getenv() to getenv_(), because 'name''s type is now tchar * */
+ /* no need to xalloc */
+ dolp = (vp || getenv_(name)) ? S_1 /*"1"*/ : S_0/*"0"*/;
+ goto eatbrac;
+ }
+ if (vp == 0) {
+ /* getenv() to getenv_(), because 'name''s type is now tchar * */
+ /* no need to xalloc */
+ np = getenv_(name);
+ if (np) {
+ addla(np);
+ goto eatbrac;
+ }
+ udvar(name);
+ /*NOTREACHED*/
+ }
+ c = DgetC(0);
+ upb = blklen(vp->vec);
+ if (dimen == 0 && subscr == 0 && c == '[') {
+ np = name;
+ for (;;) {
+ c = DgetC(DODOL); /* Allow $ expand within [ ] */
+ if (c == ']')
+ break;
+ if (c == '\n' || c == DEOF)
+ goto syntax;
+ if (np >= &name[MAX_VREF_LEN])
+ error("Variable reference too long");
+ *np++ = c;
+ }
+ *np = 0, np = name;
+ if (dolp || dolcnt) /* $ exp must end before ] */
+ goto syntax;
+ if (!*np)
+ goto syntax;
+ if (digit(*np)) {
+ register int i = 0;
+
+ while (digit(*np))
+ i = i * 10 + *np++ - '0';
+/* if ((i < 0 || i > upb) && !any(*np, "-*")) {*/
+ if ((i < 0 || i > upb) && (*np!='-') && (*np!='*')) {
+oob:
+ setname(vp->v_name);
+ error("Subscript out of range");
+ }
+ lwb = i;
+ if (!*np)
+ upb = lwb, np = S_AST/*"*"*/;
+ }
+ if (*np == '*')
+ np++;
+ else if (*np != '-')
+ goto syntax;
+ else {
+ register int i = upb;
+
+ np++;
+ if (digit(*np)) {
+ i = 0;
+ while (digit(*np))
+ i = i * 10 + *np++ - '0';
+ if (i < 0 || i > upb)
+ goto oob;
+ }
+ if (i < lwb)
+ upb = lwb - 1;
+ else
+ upb = i;
+ }
+ if (lwb == 0) {
+ if (upb != 0)
+ goto oob;
+ upb = -1;
+ }
+ if (*np)
+ goto syntax;
+ } else {
+ if (subscr > 0)
+ if (subscr > upb)
+ lwb = 1, upb = 0;
+ else
+ lwb = upb = subscr;
+ unDredc(c);
+ }
+ if (dimen) {
+ tchar *cp = putn(upb - lwb + 1);
+
+ addla(cp);
+ xfree(cp);
+ } else {
+eatmod:
+ c = DgetC(0);
+ if (c == ':') {
+ c = DgetC(0), dolmcnt = 1;
+ if (c == 'g')
+ c = DgetC(0), dolmcnt = 10000;
+ if (!any(c, S_htrqxe))
+ error("Bad : mod in $");
+ dolmod = c;
+ if (c == 'q')
+ dolmcnt = 10000;
+ } else
+ unDredc(c);
+ dolnxt = &vp->vec[lwb - 1];
+ dolcnt = upb - lwb + 1;
+ }
+eatbrac:
+ if (sc == '{') {
+ c = Dredc();
+ if (c != '}')
+ goto syntax;
+ }
+}
+
+setDolp(cp)
+ register tchar *cp;
+{
+ register tchar *dp;
+
+#ifdef TRACE
+ tprintf("TRACE- setDolp()\n");
+#endif
+ if (dolmod == 0 || dolmcnt == 0) {
+ dolp = cp;
+ return;
+ }
+ dp = domod(cp, dolmod);
+ if (dp) {
+ dolmcnt--;
+ addla(dp);
+ xfree(dp);
+ } else
+ addla(cp);
+ dolp = S_/*""*/;
+}
+
+unDredc(c)
+ int c;
+{
+
+ Dpeekrd = c;
+}
+
+Dredc()
+{
+ register int c;
+
+ if (c = Dpeekrd) {
+ Dpeekrd = 0;
+ return (c);
+ }
+ if (Dcp && (c = *Dcp++))
+ return (c&(QUOTE|TRIM));
+ if (*Dvp == 0) {
+ Dcp = 0;
+ return (DEOF);
+ }
+ Dcp = *Dvp++;
+ return (' ');
+}
+
+Dtestq(c)
+ register int c;
+{
+
+ if (cmap(c, QUOTES))
+ gflag = 1;
+}
+
+/*
+ * Form a shell temporary file (in unit 0) from the words
+ * of the shell input up to a line the same as "term".
+ * Unit 0 should have been closed before this call.
+ */
+heredoc(term)
+ tchar *term;
+{
+ register int c;
+ tchar *Dv[2];
+ tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
+ int ocnt, lcnt, mcnt;
+ register tchar *lbp, *obp, *mbp;
+ tchar **vp;
+ bool quoted;
+ tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
+'X', 'X', 'X', 0};
+ int fd1;
+
+#ifdef TRACE
+ tprintf("TRACE- heredoc()\n");
+#endif
+ if ((fd1 = mkstemp_(shtemp)) < 0)
+ Perror(shtemp);
+ (void) unlink_(shtemp); /* 0 0 inode! */
+ unsetfd(fd1);
+ Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
+ trim(Dv); rscan(Dv, Dtestq); quoted = gflag;
+ ocnt = BUFSIZ; obp = obuf;
+ for (;;) {
+ /*
+ * Read up a line
+ */
+ lbp = lbuf; lcnt = BUFSIZ - 4;
+ for (;;) {
+ c = readc(1); /* 1 -> Want EOF returns */
+ if (c < 0) {
+ setname(term);
+ bferr("<< terminator not found");
+ }
+ if (c == '\n')
+ break;
+ if (c &= TRIM) {
+ *lbp++ = c;
+ if (--lcnt < 0) {
+ setname(S_LESLES/*"<<"*/);
+ error("Line overflow");
+ }
+ }
+ }
+ *lbp = 0;
+
+ /*
+ * Compare to terminator -- before expansion
+ */
+ if (eq(lbuf, term)) {
+ (void) write_(0, obuf, BUFSIZ - ocnt);
+ (void) lseek(0, (off_t)0, 0);
+ return;
+ }
+
+ /*
+ * If term was quoted or -n just pass it on
+ */
+ if (quoted || noexec) {
+ *lbp++ = '\n'; *lbp = 0;
+ for (lbp = lbuf; c = *lbp++;) {
+ *obp++ = c;
+ if (--ocnt == 0) {
+ (void) write_(0, obuf, BUFSIZ);
+ obp = obuf; ocnt = BUFSIZ;
+ }
+ }
+ continue;
+ }
+
+ /*
+ * Term wasn't quoted so variable and then command
+ * expand the input line
+ */
+ Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
+ for (;;) {
+ c = DgetC(DODOL);
+ if (c == DEOF)
+ break;
+ if ((c &= TRIM) == 0)
+ continue;
+ /* \ quotes \ $ ` here */
+ if (c =='\\') {
+ c = DgetC(0);
+/* if (!any(c, "$\\`"))*/
+ if ((c!='$')&&(c!='\\')&&(c!='`'))
+ unDgetC(c | QUOTE), c = '\\';
+ else
+ c |= QUOTE;
+ }
+ *mbp++ = c;
+ if (--mcnt == 0) {
+ setname(S_LESLES/*"<<"*/);
+ bferr("Line overflow");
+ }
+ }
+ *mbp++ = 0;
+
+ /*
+ * If any ` in line do command substitution
+ */
+ mbp = mbuf;
+ if (any('`', mbp)) {
+ /*
+ * 1 arg to dobackp causes substitution to be literal.
+ * Words are broken only at newlines so that all blanks
+ * and tabs are preserved. Blank lines (null words)
+ * are not discarded.
+ */
+ vp = dobackp(mbuf, 1);
+ } else
+ /* Setup trivial vector similar to return of dobackp */
+ Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
+
+ /*
+ * Resurrect the words from the command substitution
+ * each separated by a newline. Note that the last
+ * newline of a command substitution will have been
+ * discarded, but we put a newline after the last word
+ * because this represents the newline after the last
+ * input line!
+ */
+ for (; *vp; vp++) {
+ for (mbp = *vp; *mbp; mbp++) {
+ *obp++ = *mbp & TRIM;
+ if (--ocnt == 0) {
+ (void) write_(0, obuf, BUFSIZ);
+ obp = obuf; ocnt = BUFSIZ;
+ }
+ }
+ *obp++ = '\n';
+ if (--ocnt == 0) {
+ (void) write_(0, obuf, BUFSIZ);
+ obp = obuf; ocnt = BUFSIZ;
+ }
+ }
+ if (pargv)
+ blkfree(pargv), pargv = 0;
+ }
+}
diff --git a/usr/src/cmd/csh/sh.err.c b/usr/src/cmd/csh/sh.err.c
new file mode 100644
index 0000000000..ee4ebfbb89
--- /dev/null
+++ b/usr/src/cmd/csh/sh.err.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include <locale.h>
+#include <dirent.h>
+/*
+ * #include <sys/ioctl.h>
+ * #include <stdlib.h>
+ */
+#include "sh.tconst.h"
+/*
+ * C Shell
+ */
+
+
+bool errspl; /* Argument to error was spliced by seterr2 */
+tchar one[2] = { '1', 0 };
+tchar *onev[2] = { one, NOSTR };
+/*
+ * contains DIR * for last opendir_(), its left open if an error
+ * longjmp (reset) occurs before it gets closed via closedir.
+ * if its not null in the error handler, then closedir it.
+ */
+DIR *Dirp = NULL;
+
+/*
+ * Print error string s with optional argument arg.
+ * This routine always resets or exits. The flag haderr
+ * is set so the routine who catches the unwind can propogate
+ * it if they want.
+ *
+ * Note that any open files at the point of error will eventually
+ * be closed in the routine process in sh.c which is the only
+ * place error unwinds are ever caught.
+ */
+/*VARARGS1*/
+error(s, a1, a2)
+ char *s;
+{
+ register tchar **v;
+ register char *ep;
+
+ /*
+ * Must flush before we print as we wish output before the error
+ * to go on (some form of) standard output, while output after
+ * goes on (some form of) diagnostic output.
+ * If didfds then output will go to 1/2 else to FSHOUT/FSHDIAG.
+ * See flush in sh.print.c.
+ */
+ flush();
+ haderr = 1; /* Now to diagnostic output */
+ timflg = 0; /* This isn't otherwise reset */
+ if (v = pargv)
+ pargv = 0, blkfree(v);
+ if (v = gargv)
+ gargv = 0, blkfree(v);
+
+ /*
+ * A zero arguments causes no printing, else print
+ * an error diagnostic here.
+ */
+ if (s) {
+ printf(s, a1, a2), printf("\n");
+ }
+
+
+ didfds = 0; /* Forget about 0,1,2 */
+ if ((ep = err) && errspl) {
+ errspl = 0;
+ xfree(ep);
+ }
+ errspl = 0;
+
+ if ( Dirp ){
+ closedir(Dirp);
+ Dirp = NULL;
+ }
+
+ /*
+ * Go away if -e or we are a child shell
+ */
+ if (exiterr || child) {
+ exit(1);
+ }
+
+ /*
+ * Reset the state of the input.
+ * This buffered seek to end of file will also
+ * clear the while/foreach stack.
+ */
+ btoeof();
+
+ setq(S_status, onev, &shvhed);
+ if (tpgrp > 0)
+ (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
+ reset(); /* Unwind */
+}
+
+/*
+ * Perror is the shells version of perror which should otherwise
+ * never be called.
+ */
+Perror(s)
+ tchar *s;
+{
+ char chbuf[BUFSIZ];
+
+ /*
+ * Perror uses unit 2, thus if we didn't set up the fd's
+ * we must set up unit 2 now else the diagnostic will disappear
+ */
+ if (!didfds) {
+ register int oerrno = errno;
+
+ (void) dcopy(SHDIAG, 2);
+ errno = oerrno;
+ }
+ tstostr(chbuf, s);
+ perror(chbuf);
+ error(NULL); /* To exit or unwind */
+}
+
+bferr(cp)
+ char *cp;
+{
+
+ flush();
+ haderr = 1;
+ if( bname) printf("%t: ", bname);
+ error("%s", gettext(cp));
+}
+
+/*
+ * The parser and scanner set up errors for later by calling seterr,
+ * which sets the variable err as a side effect; later to be tested,
+ * e.g. in process.
+ */
+seterr(s)
+ char *s;
+{
+
+ if (err == 0)
+ err = s, errspl = 0;
+}
+
+/* Set err to a splice of cp and dp, to be freed later in error() */
+seterr2(cp, dp)
+ tchar *cp;
+ char *dp;
+{
+ char chbuf[BUFSIZ];
+ char *gdp;
+
+ if (err)
+ return;
+
+ /* Concatinate cp and dp in the allocated space. */
+ tstostr(chbuf, cp);
+ gdp = gettext(dp);
+ err = (char *)xalloc(strlen(chbuf)+strlen(gdp)+1);
+ strcpy(err, chbuf);
+ strcat(err, gdp);
+
+ errspl++;/* Remember to xfree(err). */
+}
+
+/* Set err to a splice of cp with a string form of character d */
+seterrc(cp, d)
+ char *cp;
+ tchar d;
+{
+ char chbuf[MB_LEN_MAX+1];
+
+ /* don't overwrite an existing error message */
+ if (err)
+ return;
+
+#ifdef MBCHAR
+ {
+ wchar_t wcd=(wchar_t)(d&TRIM);
+ int i;
+
+ i = wctomb(chbuf, wcd); /* chbuf holds d in multibyte representation. */
+ chbuf[(i>0)?i:0] = (char) 0;
+ }
+#else
+ chbuf[0]=(char)(d&TRIM); chbuf[1]=(char)0;
+#endif
+
+
+ /* Concatinate cp and d in the allocated space. */
+ err = (char *)xalloc(strlen(cp)+strlen(chbuf)+1);
+ strcpy(err, cp);
+ strcat(err, chbuf);
+
+ errspl++; /* Remember to xfree(err). */
+}
diff --git a/usr/src/cmd/csh/sh.exec.c b/usr/src/cmd/csh/sh.exec.c
new file mode 100644
index 0000000000..d0dd6dea7f
--- /dev/null
+++ b/usr/src/cmd/csh/sh.exec.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include <dirent.h>
+#include <string.h>
+#include "sh.tconst.h"
+#include "sh_policy.h"
+
+
+/*
+ * C shell
+ */
+
+/*
+ * System level search and execute of a command.
+ * We look in each directory for the specified command name.
+ * If the name contains a '/' then we execute only the full path name.
+ * If there is no search path then we execute only full path names.
+ */
+
+/*
+ * As we search for the command we note the first non-trivial error
+ * message for presentation to the user. This allows us often
+ * to show that a file has the wrong mode/no access when the file
+ * is not in the last component of the search path, so we must
+ * go on after first detecting the error.
+ */
+char *exerr; /* Execution error message */
+
+
+extern DIR *opendir_();
+
+
+doexec(t)
+ register struct command *t;
+{
+ tchar *sav;
+ register tchar *dp, **pv, **av;
+ register struct varent *v;
+ bool slash;
+ int hashval, hashval1, i;
+ tchar *blk[2];
+#ifdef TRACE
+ tprintf("TRACE- doexec()\n");
+#endif
+
+ /*
+ * Glob the command name. If this does anything, then we
+ * will execute the command only relative to ".". One special
+ * case: if there is no PATH, then we execute only commands
+ * which start with '/'.
+ */
+ dp = globone(t->t_dcom[0]);
+ sav = t->t_dcom[0];
+ exerr = 0; t->t_dcom[0] = dp;
+ setname(dp);
+ xfree(sav);
+ v = adrof(S_path /*"path"*/);
+ if (v == 0 && dp[0] != '/') {
+ pexerr();
+ }
+ slash = gflag;
+
+ /*
+ * Glob the argument list, if necessary.
+ * Otherwise trim off the quote bits.
+ */
+ gflag = 0; av = &t->t_dcom[1];
+ tglob(av);
+ if (gflag) {
+ av = glob(av);
+ if (av == 0)
+ error("No match");
+ }
+ blk[0] = t->t_dcom[0];
+ blk[1] = 0;
+ av = blkspl(blk, av);
+#ifdef VFORK
+ Vav = av;
+#endif
+ trim(av);
+ slash |= any('/', av[0]);
+
+ xechoit(av); /* Echo command if -x */
+ /*
+ * Since all internal file descriptors are set to close on exec,
+ * we don't need to close them explicitly here. Just reorient
+ * ourselves for error messages.
+ */
+ SHIN = 0; SHOUT = 1; SHDIAG = 2; OLDSTD = 0;
+
+ /*
+ * We must do this AFTER any possible forking (like `foo`
+ * in glob) so that this shell can still do subprocesses.
+ */
+ (void) sigsetmask(0);
+
+ /*
+ * If no path, no words in path, or a / in the filename
+ * then restrict the command search.
+ */
+ if (v == 0 || v->vec[0] == 0 || slash)
+ pv = justabs;
+ else
+ pv = v->vec;
+ sav = strspl(S_SLASH /* "/" */, *av); /* / command name for postpending */
+#ifdef VFORK
+ Vsav = sav;
+#endif
+ if (havhash)
+ hashval = hashname(*av);
+ i = 0;
+#ifdef VFORK
+ hits++;
+#endif
+ do {
+ if (!slash && pv[0][0] == '/' && havhash) {
+ hashval1 = hash(hashval, i);
+ if (!bit(xhash, hashval1))
+ goto cont;
+ }
+
+ if (pv[0][0] == 0 || eq(pv[0], S_DOT/*"."*/)) { /* don't make ./xxx */
+ texec(t, *av, av);
+ } else {
+ dp = strspl(*pv, sav);
+#ifdef VFORK
+ Vdp = dp;
+#endif
+ texec(t, dp, av);
+#ifdef VFORK
+ Vdp = 0;
+#endif
+ xfree(dp);
+ }
+#ifdef VFORK
+ misses++;
+#endif
+cont:
+ pv++;
+ i++;
+ } while (*pv);
+#ifdef VFORK
+ hits--;
+#endif
+#ifdef VFORK
+ Vsav = 0;
+ Vav = 0;
+#endif
+ xfree(sav);
+ xfree( (char *)av);
+ pexerr();
+}
+
+pexerr()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- pexerr()\n");
+#endif
+ /* Couldn't find the damn thing */
+ if (exerr)
+ bferr(exerr);
+ bferr("Command not found");
+}
+
+/*
+ * Execute command f, arg list t.
+ * Record error message if not found.
+ * Also do shell scripts here.
+ */
+texec(cmd, f, t)
+ register struct command *cmd;
+ tchar *f;
+ register tchar **t;
+{
+ register int pfstatus = 0;
+ register struct varent *v;
+ register tchar **vp;
+ tchar *lastsh[2];
+
+#ifdef TRACE
+ tprintf("TRACE- texec()\n");
+#endif
+ /* convert cfname and cargs from tchar to char */
+ tconvert(cmd, f, t);
+
+ if (pfcshflag == 1) {
+ pfstatus = secpolicy_pfexec((const char *)(cmd->cfname),
+ cmd->cargs, (const char **)NULL);
+ if (pfstatus != NOATTRS) {
+ errno = pfstatus;
+ }
+ }
+ if ((pfcshflag == 0) || (pfstatus == NOATTRS)) {
+ execv(cmd->cfname, cmd->cargs);
+ }
+
+ /*
+ * exec returned, free up allocations from above
+ * tconvert(), zero cfname and cargs to prevent
+ * duplicate free() in freesyn()
+ */
+ xfree(cmd->cfname);
+ chr_blkfree(cmd->cargs);
+ cmd->cfname = (char *) 0;
+ cmd->cargs = (char **) 0;
+
+ switch (errno) {
+ case ENOEXEC:
+ /* check that this is not a binary file */
+ {
+ register int ff = open_(f, 0);
+ tchar ch;
+
+ if (ff != -1 && read_(ff, &ch, 1) == 1 && !isprint(ch)
+ && !isspace(ch)) {
+ printf("Cannot execute binary file.\n");
+ Perror(f);
+ (void) close(ff);
+ unsetfd(ff);
+ return;
+ }
+ (void) close(ff);
+ unsetfd(ff);
+ }
+ /*
+ * If there is an alias for shell, then
+ * put the words of the alias in front of the
+ * argument list replacing the command name.
+ * Note no interpretation of the words at this point.
+ */
+ v = adrof1(S_shell /*"shell"*/, &aliases);
+ if (v == 0) {
+#ifdef OTHERSH
+ register int ff = open_(f, 0);
+ tchar ch;
+#endif
+
+ vp = lastsh;
+ vp[0] = adrof(S_shell /*"shell"*/) ? value(S_shell /*"shell"*/) : S_SHELLPATH/*SHELLPATH*/;
+ vp[1] = (tchar *) NULL;
+#ifdef OTHERSH
+ if (ff != -1 && read_(ff, &ch, 1) == 1 && ch != '#')
+ vp[0] = S_OTHERSH/*OTHERSH*/;
+ (void) close(ff);
+ unsetfd(ff);
+#endif
+ } else
+ vp = v->vec;
+ t[0] = f;
+ t = blkspl(vp, t); /* Splice up the new arglst */
+ f = *t;
+
+ tconvert(cmd, f, t); /* convert tchar to char */
+
+ /*
+ * now done with tchar arg list t,
+ * free the space calloc'd by above blkspl()
+ */
+ xfree((char *) t);
+
+ execv(cmd->cfname, cmd->cargs); /* exec the command */
+
+ /* exec returned, same free'ing as above */
+ xfree(cmd->cfname);
+ chr_blkfree(cmd->cargs);
+ cmd->cfname = (char *) 0;
+ cmd->cargs = (char **) 0;
+
+ /* The sky is falling, the sky is falling! */
+
+ case ENOMEM:
+ Perror(f);
+
+ case ENOENT:
+ break;
+
+ default:
+ if (exerr == 0) {
+ exerr = strerror(errno);
+ setname(f);
+ }
+ }
+}
+
+
+static
+tconvert(cmd, fname, list)
+register struct command *cmd;
+register tchar *fname, **list;
+{
+ register char **rc;
+ register int len;
+
+ cmd->cfname = tstostr(NULL, fname);
+
+ len = blklen(list);
+ rc = cmd->cargs = (char **)
+ calloc((u_int) (len + 1), sizeof(char **));
+ while (len--)
+ *rc++ = tstostr(NULL, *list++);
+ *rc = NULL;
+}
+
+
+/*ARGSUSED*/
+execash(t, kp)
+ tchar **t;
+ register struct command *kp;
+{
+#ifdef TRACE
+ tprintf("TRACE- execash()\n");
+#endif
+
+ rechist();
+ (void) signal(SIGINT, parintr);
+ (void) signal(SIGQUIT, parintr);
+ (void) signal(SIGTERM, parterm); /* if doexec loses, screw */
+ lshift(kp->t_dcom, 1);
+ exiterr++;
+ doexec(kp);
+ /*NOTREACHED*/
+}
+
+xechoit(t)
+ tchar **t;
+{
+#ifdef TRACE
+ tprintf("TRACE- xechoit()\n");
+#endif
+
+ if (adrof(S_echo /*"echo"*/)) {
+ flush();
+ haderr = 1;
+ blkpr(t), Putchar('\n');
+ haderr = 0;
+ }
+}
+
+/*
+ * This routine called when user enters "rehash".
+ * Both the path and cdpath caching arrays will
+ * be rehashed, via calling dohash. If either
+ * variable is not set with a value, then dohash
+ * just exits.
+ */
+
+dorehash()
+{
+ dohash(xhash);
+ dohash(xhash2);
+}
+
+/*
+ * Fill up caching arrays for path and cdpath
+ */
+dohash(cachearray)
+char cachearray[];
+{
+ struct stat stb;
+ DIR *dirp;
+ register struct dirent *dp;
+ register int cnt;
+ int i = 0;
+ struct varent *v;
+ tchar **pv;
+ int hashval;
+ tchar curdir_[MAXNAMLEN+1];
+
+#ifdef TRACE
+ tprintf("TRACE- dohash()\n");
+#endif
+ /* Caching $path */
+ if ( cachearray == xhash ) {
+ havhash = 1;
+ v = adrof(S_path /*"path"*/);
+ }else { /* Caching $cdpath */
+ havhash2 = 1;
+ v = adrof(S_cdpath /*"cdpath"*/);
+ }
+
+ for (cnt = 0; cnt < ( HSHSIZ / 8 ); cnt++)
+ cachearray[cnt] = 0;
+ if (v == 0)
+ {
+ return;
+ }
+ for (pv = v->vec; *pv; pv++, i++) {
+ if (pv[0][0] != '/')
+ continue;
+ dirp = opendir_(*pv);
+ if (dirp == NULL)
+ continue;
+ if (fstat(dirp->dd_fd, &stb) < 0 || !isdir(stb)) {
+ unsetfd(dirp->dd_fd);
+ closedir_(dirp);
+ continue;
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_ino == 0)
+ continue;
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
+ continue;
+ hashval = hash(hashname(strtots(curdir_,dp->d_name)), i);
+ bis(cachearray, hashval);
+ }
+ unsetfd(dirp->dd_fd);
+ closedir_(dirp);
+ }
+}
+
+dounhash()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dounhash()\n");
+#endif
+ havhash = 0;
+ havhash2 = 0;
+}
+
+#ifdef VFORK
+hashstat()
+{
+#ifdef TRACE
+ tprintf("TRACE- hashstat_()\n");
+#endif
+
+ if (hits+misses)
+ printf("%d hits, %d misses, %d%%\n",
+ hits, misses, 100 * hits / (hits + misses));
+}
+#endif
+
+/*
+ * Hash a command name.
+ */
+hashname(cp)
+ register tchar *cp;
+{
+ register long h = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- hashname()\n");
+#endif
+ while (*cp)
+ h = hash(h, *cp++);
+ return ((int) h);
+}
diff --git a/usr/src/cmd/csh/sh.exp.c b/usr/src/cmd/csh/sh.exp.c
new file mode 100644
index 0000000000..2fab609670
--- /dev/null
+++ b/usr/src/cmd/csh/sh.exp.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+
+/*
+ * C shell
+ */
+
+#define IGNORE 1 /* in ignore, it means to ignore value, just parse */
+#define NOGLOB 2 /* in ignore, it means not to globone */
+
+#define ADDOP 1
+#define MULOP 2
+#define EQOP 4
+#define RELOP 8
+#define RESTOP 16
+#define ANYOP 31
+
+#define EQEQ 1
+#define GTR 2
+#define LSS 4
+#define NOTEQ 6
+#define EQMATCH 7
+#define NOTEQMATCH 8
+
+/*
+ * Determine if file given by name is accessible with permissions
+ * given by mode.
+ *
+ * Borrowed from the Bourne sh, and modified a bit
+ *
+ * If the requested access is permitted, a value of 0 is
+ * returned. Otherwise, a value of -1 is returned and errno is
+ * set to indicate the error
+ */
+
+chk_access(path, mode)
+register tchar *path;
+mode_t mode;
+{
+ static int flag;
+ static uid_t euid;
+ struct stat statb;
+ mode_t ftype;
+ unsigned char name[MAXPATHLEN*MB_LEN_MAX]; /* General use buffer. */
+
+ /* convert tchar * to char * */
+ tstostr(name, path);
+
+ if(flag == 0) {
+ euid = geteuid();
+ flag = 1;
+ }
+ if (stat((char *)name, &statb) == 0) {
+ ftype = statb.st_mode & S_IFMT;
+ if(access((char *)name, 010|(mode>>6)) == 0) {
+ if(euid == 0) {
+ if (ftype != S_IFREG || mode != S_IEXEC)
+ return(0);
+ /* root can execute file as long as it has execute
+ permission for someone */
+ if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
+ return(0);
+ return(-1);
+ }
+ return(0);
+ }
+ }
+ return(-1);
+}
+
+exp(vp)
+ register tchar ***vp;
+{
+#ifdef TRACE
+ tprintf("TRACE- exp()\n");
+#endif
+
+ return (exp0(vp, 0));
+}
+
+exp0(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register int p1 = exp1(vp, ignore);
+#ifdef TRACE
+ tprintf("TRACE- exp0()\n");
+#endif
+
+#ifdef EDEBUG
+ etraci("exp0 p1", p1, vp);
+#endif
+ if (**vp && eq(**vp, S_BARBAR /*"||"*/)) {
+ register int p2;
+
+ (*vp)++;
+ p2 = exp0(vp, (ignore&IGNORE) || p1);
+#ifdef EDEBUG
+ etraci("exp0 p2", p2, vp);
+#endif
+ return (p1 || p2);
+ }
+ return (p1);
+}
+
+exp1(vp, ignore)
+ register tchar ***vp;
+{
+ register int p1 = exp2(vp, ignore);
+
+#ifdef TRACE
+ tprintf("TRACE- exp1()\n");
+#endif
+#ifdef EDEBUG
+ etraci("exp1 p1", p1, vp);
+#endif
+ if (**vp && eq(**vp, S_ANDAND /*"&&" */)) {
+ register int p2;
+
+ (*vp)++;
+ p2 = exp1(vp, (ignore&IGNORE) || !p1);
+#ifdef EDEBUG
+ etraci("exp1 p2", p2, vp);
+#endif
+ return (p1 && p2);
+ }
+ return (p1);
+}
+
+exp2(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register int p1 = exp2a(vp, ignore);
+
+#ifdef TRACE
+ tprintf("TRACE- exp2()\n");
+#endif
+#ifdef EDEBUG
+ etraci("exp3 p1", p1, vp);
+#endif
+ if (**vp && eq(**vp, S_BAR /*"|" */)) {
+ register int p2;
+
+ (*vp)++;
+ p2 = exp2(vp, ignore);
+#ifdef EDEBUG
+ etraci("exp3 p2", p2, vp);
+#endif
+ return (p1 | p2);
+ }
+ return (p1);
+}
+
+exp2a(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register int p1 = exp2b(vp, ignore);
+
+#ifdef TRACE
+ tprintf("TRACE- exp2a()\n");
+#endif
+#ifdef EDEBUG
+ etraci("exp2a p1", p1, vp);
+#endif
+ if (**vp && eq(**vp, S_HAT /*"^" */)) {
+ register int p2;
+
+ (*vp)++;
+ p2 = exp2a(vp, ignore);
+#ifdef EDEBUG
+ etraci("exp2a p2", p2, vp);
+#endif
+ return (p1 ^ p2);
+ }
+ return (p1);
+}
+
+exp2b(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register int p1 = exp2c(vp, ignore);
+
+#ifdef TRACE
+ tprintf("TRACE- exp2b()\n");
+#endif
+#ifdef EDEBUG
+ etraci("exp2b p1", p1, vp);
+#endif
+ if (**vp && eq(**vp, S_AND /*"&"*/)) {
+ register int p2;
+
+ (*vp)++;
+ p2 = exp2b(vp, ignore);
+#ifdef EDEBUG
+ etraci("exp2b p2", p2, vp);
+#endif
+ return (p1 & p2);
+ }
+ return (p1);
+}
+
+exp2c(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register tchar *p1 = exp3(vp, ignore);
+ register tchar *p2;
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- exp2c()\n");
+#endif
+#ifdef EDEBUG
+ etracc("exp2c p1", p1, vp);
+#endif
+ if (i = isa(**vp, EQOP)) {
+ (*vp)++;
+ if (i == EQMATCH || i == NOTEQMATCH)
+ ignore |= NOGLOB;
+ p2 = exp3(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp2c p2", p2, vp);
+#endif
+ if (!(ignore&IGNORE)) switch (i) {
+
+ case EQEQ:
+ i = eq(p1, p2);
+ break;
+
+ case NOTEQ:
+ i = !eq(p1, p2);
+ break;
+
+ case EQMATCH:
+ i = Gmatch(p1, p2);
+ break;
+
+ case NOTEQMATCH:
+ i = !Gmatch(p1, p2);
+ break;
+ }
+ xfree(p1), xfree(p2);
+ return (i);
+ }
+ i = egetn(p1);
+ xfree(p1);
+ return (i);
+}
+
+tchar *
+exp3(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register tchar *p1, *p2;
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- exp3()\n");
+#endif
+ p1 = exp3a(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp3 p1", p1, vp);
+#endif
+ if (i = isa(**vp, RELOP)) {
+ (*vp)++;
+ if (**vp && eq(**vp, S_EQ /*"=" */))
+ i |= 1, (*vp)++;
+ p2 = exp3(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp3 p2", p2, vp);
+#endif
+ if (!(ignore&IGNORE)) switch (i) {
+
+ case GTR:
+ i = egetn(p1) > egetn(p2);
+ break;
+
+ case GTR|1:
+ i = egetn(p1) >= egetn(p2);
+ break;
+
+ case LSS:
+ i = egetn(p1) < egetn(p2);
+ break;
+
+ case LSS|1:
+ i = egetn(p1) <= egetn(p2);
+ break;
+ }
+ xfree(p1), xfree(p2);
+ return (putn(i));
+ }
+ return (p1);
+}
+
+tchar *
+exp3a(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register tchar *p1, *p2, *op;
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- exp3a()\n");
+#endif
+ p1 = exp4(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp3a p1", p1, vp);
+#endif
+ op = **vp;
+ /* if (op && any(op[0], "<>") && op[0] == op[1]) { */
+ if (op && (op[0] == '<' || op[0] == '>') && op[0] == op[1]) {
+ (*vp)++;
+ p2 = exp3a(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp3a p2", p2, vp);
+#endif
+ if (op[0] == '<')
+ i = egetn(p1) << egetn(p2);
+ else
+ i = egetn(p1) >> egetn(p2);
+ xfree(p1), xfree(p2);
+ return (putn(i));
+ }
+ return (p1);
+}
+
+tchar *
+exp4(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register tchar *p1, *p2;
+ register int i = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- exp4()\n");
+#endif
+ p1 = exp5(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp4 p1", p1, vp);
+#endif
+ if (isa(**vp, ADDOP)) {
+ register tchar *op = *(*vp)++;
+
+ p2 = exp4(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp4 p2", p2, vp);
+#endif
+ if (!(ignore&IGNORE)) switch (op[0]) {
+
+ case '+':
+ i = egetn(p1) + egetn(p2);
+ break;
+
+ case '-':
+ i = egetn(p1) - egetn(p2);
+ break;
+ }
+ xfree(p1), xfree(p2);
+ return (putn(i));
+ }
+ return (p1);
+}
+
+tchar *
+exp5(vp, ignore)
+ register tchar ***vp;
+ bool ignore;
+{
+ register tchar *p1, *p2;
+ register int i = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- exp5()\n");
+#endif
+ p1 = exp6(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp5 p1", p1, vp);
+#endif
+ if (isa(**vp, MULOP)) {
+ register tchar *op = *(*vp)++;
+
+ p2 = exp5(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp5 p2", p2, vp);
+#endif
+ if (!(ignore&IGNORE)) switch (op[0]) {
+
+ case '*':
+ i = egetn(p1) * egetn(p2);
+ break;
+
+ case '/':
+ i = egetn(p2);
+ if (i == 0)
+ error("Divide by 0");
+ i = egetn(p1) / i;
+ break;
+
+ case '%':
+ i = egetn(p2);
+ if (i == 0)
+ error("Mod by 0");
+ i = egetn(p1) % i;
+ break;
+ }
+ xfree(p1), xfree(p2);
+ return (putn(i));
+ }
+ return (p1);
+}
+
+tchar *
+exp6(vp, ignore)
+ register tchar ***vp;
+{
+ int ccode, i;
+ register tchar *cp, *dp, *ep;
+
+#ifdef TRACE
+ tprintf("TRACE- exp6()\n");
+#endif
+ if (**vp == 0)
+ bferr("Expression syntax");
+ if (eq(**vp, S_EXAS /* "!" */)) {
+ (*vp)++;
+ cp = exp6(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp6 ! cp", cp, vp);
+#endif
+ i = egetn(cp);
+ xfree(cp);
+ return (putn(!i));
+ }
+ if (eq(**vp, S_TIL /*"~" */)) {
+ (*vp)++;
+ cp = exp6(vp, ignore);
+#ifdef EDEBUG
+ etracc("exp6 ~ cp", cp, vp);
+#endif
+ i = egetn(cp);
+ xfree(cp);
+ return (putn(~i));
+ }
+ if (eq(**vp, S_LPAR /*"(" */)) {
+ (*vp)++;
+ ccode = exp0(vp, ignore);
+#ifdef EDEBUG
+ etraci("exp6 () ccode", ccode, vp);
+#endif
+ if (*vp == 0 || **vp == 0 || ***vp != ')')
+ bferr("Expression syntax");
+ (*vp)++;
+ return (putn(ccode));
+ }
+ if (eq(**vp, S_LBRA /* "{" */)) {
+ register tchar **v;
+ struct command faket;
+ tchar *fakecom[2];
+
+ faket.t_dtyp = TCOM;
+ faket.t_dflg = 0;
+ faket.t_dcar = faket.t_dcdr = faket.t_dspr = (struct command *)0;
+ faket.t_dcom = fakecom;
+ fakecom[0] = S_BRAPPPBRA /*"{ ... }" */;
+ fakecom[1] = NOSTR;
+ (*vp)++;
+ v = *vp;
+ for (;;) {
+ if (!**vp)
+ bferr("Missing }");
+ if (eq(*(*vp)++, S_RBRA /*"}" */))
+ break;
+ }
+ if (ignore&IGNORE)
+ return (S_ /*""*/);
+ psavejob();
+ if (pfork(&faket, -1) == 0) {
+ *--(*vp) = 0;
+ evalav(v);
+ exitstat();
+ }
+ pwait();
+ prestjob();
+#ifdef EDEBUG
+ etraci("exp6 {} status", egetn(value("status")), vp);
+#endif
+ return (putn(egetn(value(S_status /*"status" */)) == 0));
+ }
+ if (isa(**vp, ANYOP))
+ return (S_ /*""*/);
+ cp = *(*vp)++;
+ if (*cp == '-' && any(cp[1], S_erwxfdzo /*"erwxfdzo" */)) {
+ struct stat stb;
+
+ if (cp[2] != '\0')
+ bferr("Malformed file inquiry");
+
+ /*
+ * Detect missing file names by checking for operator
+ * in the file name position. However, if an operator
+ * name appears there, we must make sure that there's
+ * no file by that name (e.g., "/") before announcing
+ * an error. Even this check isn't quite right, since
+ * it doesn't take globbing into account.
+ */
+ if (isa(**vp, ANYOP) && stat_(**vp, &stb))
+ bferr("Missing file name");
+ dp = *(*vp)++;
+
+ if (ignore&IGNORE)
+ return (S_ /*""*/);
+ ep = globone(dp);
+ switch (cp[1]) {
+
+ case 'r':
+ i = !chk_access(ep, S_IREAD);
+ break;
+
+ case 'w':
+ i = !chk_access(ep, S_IWRITE);
+ break;
+
+ case 'x':
+ i = !chk_access(ep, S_IEXEC);
+ break;
+
+ default:
+ if (stat_(ep, &stb)) {
+ xfree(ep);
+ return (S_0 /*"0"*/);
+ }
+ switch (cp[1]) {
+
+ case 'f':
+ i = (stb.st_mode & S_IFMT) == S_IFREG;
+ break;
+
+ case 'd':
+ i = (stb.st_mode & S_IFMT) == S_IFDIR;
+ break;
+
+ case 'z':
+ i = stb.st_size == 0;
+ break;
+
+ case 'e':
+ i = 1;
+ break;
+
+ case 'o':
+ i = stb.st_uid == uid;
+ break;
+ }
+ }
+#ifdef EDEBUG
+ etraci("exp6 -? i", i, vp);
+#endif
+ xfree(ep);
+ return (putn(i));
+ }
+#ifdef EDEBUG
+ etracc("exp6 default", cp, vp);
+#endif
+ return (ignore&NOGLOB ? savestr(cp) : globone(cp));
+}
+
+evalav(v)
+ register tchar **v;
+{
+ struct wordent paraml;
+ register struct wordent *hp = &paraml;
+ struct command *t;
+ register struct wordent *wdp = hp;
+
+#ifdef TRACE
+ tprintf("TRACE- evalav()\n");
+#endif
+ set(S_status /*"status" */, S_0 /*"0"*/);
+ hp->prev = hp->next = hp;
+ hp->word = S_ /*""*/;
+ while (*v) {
+ register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
+
+ new->prev = wdp;
+ new->next = hp;
+ wdp->next = new;
+ wdp = new;
+ wdp->word = savestr(*v++);
+ }
+ hp->prev = wdp;
+ alias(&paraml);
+ t = syntax(paraml.next, &paraml, 0);
+ if (err)
+ error("%s", gettext(err));
+ execute(t, -1);
+ freelex(&paraml), freesyn(t);
+}
+
+isa(cp, what)
+ register tchar *cp;
+ register int what;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- isa()\n");
+#endif
+ if (cp == 0)
+ return ((what & RESTOP) != 0);
+ if (cp[1] == 0) {
+ if (what & ADDOP && (*cp == '+' || *cp == '-'))
+ return (1);
+ if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
+ return (1);
+ if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
+ *cp == '~' || *cp == '^' || *cp == '"'))
+ return (1);
+ } else if (cp[2] == 0) {
+ if (what & RESTOP) {
+ if (cp[0] == '|' && cp[1] == '&')
+ return (1);
+ if (cp[0] == '<' && cp[1] == '<')
+ return (1);
+ if (cp[0] == '>' && cp[1] == '>')
+ return (1);
+ }
+ if (what & EQOP) {
+ if (cp[0] == '=') {
+ if (cp[1] == '=')
+ return (EQEQ);
+ if (cp[1] == '~')
+ return (EQMATCH);
+ } else if (cp[0] == '!') {
+ if (cp[1] == '=')
+ return (NOTEQ);
+ if (cp[1] == '~')
+ return (NOTEQMATCH);
+ }
+ }
+ }
+ if (what & RELOP) {
+ if (*cp == '<')
+ return (LSS);
+ if (*cp == '>')
+ return (GTR);
+ }
+ return (0);
+}
+
+egetn(cp)
+ register tchar *cp;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- egetn()\n");
+#endif
+ if (*cp && *cp != '-' && !digit(*cp))
+ bferr("Expression syntax");
+ return (getn(cp));
+}
+
+/* Phew! */
+
+#ifdef EDEBUG
+etraci(str, i, vp)
+ tchar *str;
+ int i;
+ tchar ***vp;
+{
+
+ printf("%s=%d\t", str, i);
+ blkpr(*vp);
+ printf("\n");
+}
+
+etracc(str, cp, vp)
+ tchar *str, *cp;
+ tchar ***vp;
+{
+
+ printf("%s=%s\t", str, cp);
+ blkpr(*vp);
+ printf("\n");
+}
+#endif
diff --git a/usr/src/cmd/csh/sh.file.c b/usr/src/cmd/csh/sh.file.c
new file mode 100644
index 0000000000..af9e543c52
--- /dev/null
+++ b/usr/src/cmd/csh/sh.file.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef FILEC
+/*
+ * Tenex style file name recognition, .. and more.
+ * History:
+ * Author: Ken Greer, Sept. 1975, CMU.
+ * Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
+ */
+
+#include "sh.h"
+#include <sys/types.h>
+#include <dirent.h>
+#include <pwd.h>
+#include "sh.tconst.h"
+
+#define TRUE 1
+#define FALSE 0
+#define ON 1
+#define OFF 0
+
+#define ESC '\033'
+
+extern DIR *opendir_();
+
+static char *BELL = "\07";
+static char *CTRLR = "^R\n";
+
+typedef enum {LIST, RECOGNIZE} COMMAND;
+
+static jmp_buf osetexit; /* saved setexit() state */
+static struct termios tty_save; /* saved terminal state */
+static struct termios tty_new; /* new terminal state */
+
+/*
+ * Put this here so the binary can be patched with adb to enable file
+ * completion by default. Filec controls completion, nobeep controls
+ * ringing the terminal bell on incomplete expansions.
+ */
+bool filec = 0;
+
+static
+setup_tty(on)
+ int on;
+{
+ int omask;
+#ifdef TRACE
+ tprintf("TRACE- setup_tty()\n");
+#endif
+
+ omask = sigblock(sigmask(SIGINT));
+ if (on) {
+ /*
+ * The shell makes sure that the tty is not in some weird state
+ * and fixes it if it is. But it should be noted that the
+ * tenex routine will not work correctly in CBREAK or RAW mode
+ * so this code below is, therefore, mandatory.
+ *
+ * Also, in order to recognize the ESC (filename-completion)
+ * character, set EOL to ESC. This way, ESC will terminate
+ * the line, but still be in the input stream.
+ * EOT (filename list) will also terminate the line,
+ * but will not appear in the input stream.
+ *
+ * The getexit/setexit contortions ensure that the
+ * tty state will be restored if the user types ^C.
+ */
+ (void) ioctl(SHIN, TCGETS, (char *)&tty_save);
+ getexit(osetexit);
+ if (setjmp(reslab)) {
+ (void) ioctl(SHIN, TCSETSW, (char *)&tty_save);
+ resexit(osetexit);
+ reset();
+ }
+ tty_new = tty_save;
+ tty_new.c_cc[VEOL] = ESC;
+ tty_new.c_iflag |= IMAXBEL | BRKINT | IGNPAR;
+ tty_new.c_lflag |= ICANON;
+ tty_new.c_lflag |= ECHOCTL;
+ tty_new.c_oflag &= ~OCRNL;
+ (void) ioctl(SHIN, TCSETSW, (char *)&tty_new);
+ } else {
+ /*
+ * Reset terminal state to what user had when invoked
+ */
+ (void) ioctl(SHIN, TCSETSW, (char *)&tty_save);
+ resexit(osetexit);
+ }
+ (void) sigsetmask(omask);
+}
+
+static
+termchars()
+{
+ extern char *tgetstr();
+ char bp[1024];
+ static char area[256];
+ static int been_here = 0;
+ char *ap = area;
+ register char *s;
+ char *term;
+
+#ifdef TRACE
+ tprintf("TRACE- termchars()\n");
+#endif
+ if (been_here)
+ return;
+ been_here = TRUE;
+
+ if ((term = getenv("TERM")) == NULL)
+ return;
+ if (tgetent(bp, term) != 1)
+ return;
+ if (s = tgetstr("vb", &ap)) /* Visible Bell */
+ BELL = s;
+}
+
+/*
+ * Move back to beginning of current line
+ */
+static
+back_to_col_1()
+{
+ int omask;
+
+#ifdef TRACE
+ tprintf("TRACE- back_to_col_1()\n");
+#endif
+ omask = sigblock(sigmask(SIGINT));
+ (void) write(SHOUT, "\r", 1);
+ (void) sigsetmask(omask);
+}
+
+/*
+ * Push string contents back into tty queue
+ */
+static
+pushback(string, echoflag)
+ tchar *string;
+ int echoflag;
+{
+ register tchar *p;
+ struct termios tty;
+ int omask;
+
+#ifdef TRACE
+ tprintf("TRACE- pushback()\n");
+#endif
+ omask = sigblock(sigmask(SIGINT));
+ tty = tty_new;
+ if (!echoflag)
+ tty.c_lflag &= ~ECHO;
+ (void) ioctl(SHIN, TCSETSF, (char *)&tty);
+
+ for (p = string; *p; p++){
+ char mbc[MB_LEN_MAX];
+ int i, j = wctomb(mbc, (wchar_t)*p);
+
+ if (j < 0) {
+ /* Error! But else what can we do? */
+ continue;
+ }
+ for (i = 0; i < j; ++i) {
+ /* XXX: no error recovery provision. */
+ (void) ioctl(SHIN, TIOCSTI, mbc + i);
+ }
+ }
+
+ if (tty.c_lflag != tty_new.c_lflag)
+ (void) ioctl(SHIN, TCSETS, (char *)&tty_new);
+ (void) sigsetmask(omask);
+}
+
+/*
+ * Concatenate src onto tail of des.
+ * Des is a string whose maximum length is count.
+ * Always null terminate.
+ */
+catn(des, src, count)
+ register tchar *des, *src;
+ register count;
+{
+#ifdef TRACE
+ tprintf("TRACE- catn()\n");
+#endif
+
+ while (--count >= 0 && *des)
+ des++;
+ while (--count >= 0)
+ if ((*des++ = *src++) == '\0')
+ return;
+ *des = '\0';
+}
+
+static
+max(a, b)
+{
+
+ return (a > b ? a : b);
+}
+
+/*
+ * Like strncpy but always leave room for trailing \0
+ * and always null terminate.
+ */
+copyn(des, src, count)
+ register tchar *des, *src;
+ register count;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- copyn()\n");
+#endif
+ while (--count >= 0)
+ if ((*des++ = *src++) == '\0')
+ return;
+ *des = '\0';
+}
+
+/*
+ * For qsort()
+ */
+static
+fcompare(file1, file2)
+ tchar **file1, **file2;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- fcompare()\n");
+#endif
+ return (strcoll_(*file1, *file2));
+}
+
+static char
+filetype(dir, file, nosym)
+ tchar *dir, *file;
+ int nosym;
+{
+ tchar path[MAXPATHLEN + 1];
+ struct stat statb;
+
+#ifdef TRACE
+ tprintf("TRACE- filetype()\n");
+#endif
+ if (dir) {
+ catn(strcpy_(path, dir), file, MAXPATHLEN);
+ if (nosym) {
+ if (stat_(path, &statb) < 0)
+ return (' ');
+ } else {
+ if (lstat_(path, &statb) < 0)
+ return (' ');
+ }
+ if ((statb.st_mode & S_IFMT) == S_IFLNK)
+ return ('@');
+ if ((statb.st_mode & S_IFMT) == S_IFDIR)
+ return ('/');
+ if (((statb.st_mode & S_IFMT) == S_IFREG) &&
+ (statb.st_mode & 011))
+ return ('*');
+ }
+ return (' ');
+}
+
+/*
+ * Print sorted down columns
+ */
+static
+print_by_column(dir, items, count, looking_for_command)
+ tchar *dir, *items[];
+ int looking_for_command;
+{
+ register int i, rows, r, c, maxwidth = 0, columns;
+
+#ifdef TRACE
+ tprintf("TRACE- print_by_column()\n");
+#endif
+ for (i = 0; i < count; i++)
+ maxwidth = max(maxwidth, tswidth(items[i]));
+
+ /* for the file tag and space */
+ maxwidth += looking_for_command ? 1 : 2;
+ columns = max(78 / maxwidth, 1);
+ rows = (count + (columns - 1)) / columns;
+
+ for (r = 0; r < rows; r++) {
+ for (c = 0; c < columns; c++) {
+ i = c * rows + r;
+ if (i < count) {
+ register int w;
+
+ /*
+ * Print filename followed by
+ * '@' or '/' or '*' or ' '
+ */
+ printf("%t", items[i]);
+ w = tswidth(items[i]);
+ if (!looking_for_command) {
+ printf("%c",
+ (tchar) filetype(dir, items[i], 0));
+ w++;
+ }
+ if (c < columns - 1) /* last column? */
+ for (; w < maxwidth; w++)
+ printf(" ");
+ }
+ }
+ printf("\n");
+ }
+}
+
+/*
+ * Expand file name with possible tilde usage
+ * ~person/mumble
+ * expands to
+ * home_directory_of_person/mumble
+ */
+tchar *
+tilde(new, old)
+ tchar *new, *old;
+{
+ register tchar *o, *p;
+ register struct passwd *pw;
+ static tchar person[40];
+ char person_[40]; /* work */
+ tchar *pw_dir; /* work */
+
+#ifdef TRACE
+ tprintf("TRACE- tilde()\n");
+#endif
+ if (old[0] != '~')
+ return (strcpy_(new, old));
+
+ for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
+ ;
+ *p = '\0';
+ if (person[0] == '\0')
+ (void) strcpy_(new, value(S_home /*"home"*/));
+ else {
+ pw = getpwnam(tstostr(person_,person));
+ if (pw == NULL)
+ return (NULL);
+ pw_dir = strtots((tchar *)NULL, pw->pw_dir); /* allocate */
+ (void) strcpy_(new, pw_dir);
+ xfree(pw_dir); /* free it */
+ }
+ (void) strcat_(new, o);
+ return (new);
+}
+
+/*
+ * Cause pending line to be printed
+ */
+static
+sim_retype()
+{
+#ifdef notdef
+ struct termios tty_pending;
+
+#ifdef TRACE
+ tprintf("TRACE- sim_retypr()\n");
+#endif
+ tty_pending = tty_new;
+ tty_pending.c_lflag |= PENDIN;
+
+ (void) ioctl(SHIN, TCSETS, (char *)&tty_pending);
+#else
+#ifdef TRACE
+ tprintf("TRACE- sim_retype()\n");
+#endif
+ (void) write(SHOUT, CTRLR, strlen(CTRLR));
+ printprompt();
+#endif
+}
+
+static
+beep_outc (c) {
+ char buf[1];
+
+ buf[0] = c;
+
+ (void) write (SHOUT, buf, 1);
+
+ return 0;
+}
+
+static
+beep()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- beep()\n");
+#endif
+ if (adrof(S_nobeep /*"nobeep" */) == 0)
+ (void) tputs (BELL, 0, beep_outc);
+}
+
+/*
+ * Erase that silly ^[ and print the recognized part of the string.
+ */
+static
+print_recognized_stuff(recognized_part)
+ tchar *recognized_part;
+{
+ int unit = didfds ? 1 : SHOUT;
+
+#ifdef TRACE
+ tprintf("TRACE- print_recognized_stuff()\n");
+#endif
+
+ /*
+ * An optimized erasing of that silly ^[
+ *
+ * One would think that line speeds have become fast enough that this
+ * isn't necessary, but it turns out that the visual difference is
+ * quite noticeable.
+ */
+ flush();
+ switch (tswidth(recognized_part)) {
+ case 0:
+ /* erase two characters: ^[ */
+ write(unit, "\b\b \b\b", sizeof "\b\b \b\b" - 1);
+ break;
+
+ case 1:
+ /* overstrike the ^, erase the [ */
+ write(unit, "\b\b", 2);
+ printf("%t", recognized_part);
+ write(unit, " \b\b", 4);
+ break;
+
+ default:
+ /* overstrike both characters ^[ */
+ write(unit, "\b\b", 2);
+ printf("%t", recognized_part);
+ break;
+ }
+ flush();
+}
+
+/*
+ * Parse full path in file into 2 parts: directory and file names
+ * Should leave final slash (/) at end of dir.
+ */
+static
+extract_dir_and_name(path, dir, name)
+ tchar *path, *dir, *name;
+{
+ register tchar *p;
+
+#ifdef TRACE
+ tprintf("TRACE- extract_dir_and_name()\n");
+#endif
+ p = rindex_(path, '/');
+ if (p == NOSTR) {
+ copyn(name, path, MAXNAMLEN);
+ dir[0] = '\0';
+ } else {
+ copyn(name, ++p, MAXNAMLEN);
+ copyn(dir, path, p - path);
+ }
+}
+
+tchar *
+getentry(dir_fd, looking_for_lognames)
+ DIR *dir_fd;
+{
+ register struct passwd *pw;
+ register struct dirent *dirp;
+ /*
+ * For char * -> tchar * Conversion
+ */
+ static tchar strbuf[MAXNAMLEN+1];
+
+#ifdef TRACE
+ tprintf("TRACE- getentry()\n");
+#endif
+ if (looking_for_lognames) {
+ if ((pw = getpwent ()) == NULL)
+ return (NULL);
+ return (strtots(strbuf,pw->pw_name));
+ }
+ if (dirp = readdir(dir_fd))
+ return (strtots(strbuf,dirp->d_name));
+ return (NULL);
+}
+
+static
+free_items(items)
+ register tchar **items;
+{
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- free_items()\n");
+#endif
+ for (i = 0; items[i]; i++)
+ free(items[i]);
+ free( (char *)items);
+}
+
+#define FREE_ITEMS(items) { \
+ int omask;\
+\
+ omask = sigblock(sigmask(SIGINT));\
+ free_items(items);\
+ items = NULL;\
+ (void) sigsetmask(omask);\
+}
+
+/*
+ * Perform a RECOGNIZE or LIST command on string "word".
+ */
+static
+search2(word, command, max_word_length)
+ tchar *word;
+ COMMAND command;
+{
+ static tchar **items = NULL;
+ register DIR *dir_fd;
+ register numitems = 0, ignoring = TRUE, nignored = 0;
+ register name_length, looking_for_lognames;
+ tchar tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
+ tchar name[MAXNAMLEN + 1], extended_name[MAXNAMLEN+1];
+ tchar *entry;
+#define MAXITEMS 1024
+#ifdef TRACE
+ tprintf("TRACE- search2()\n");
+#endif
+
+ if (items != NULL)
+ FREE_ITEMS(items);
+
+ looking_for_lognames = (*word == '~') && (index_(word, '/') == NULL);
+ if (looking_for_lognames) {
+ (void) setpwent();
+ copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */
+ } else {
+ extract_dir_and_name(word, dir, name);
+ if (tilde(tilded_dir, dir) == 0)
+ return (0);
+ dir_fd = opendir_(*tilded_dir ? tilded_dir : S_DOT /*"."*/);
+ if (dir_fd == NULL)
+ return (0);
+ }
+
+again: /* search for matches */
+ name_length = strlen_(name);
+ for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames); ) {
+ if (!is_prefix(name, entry))
+ continue;
+ /* Don't match . files on null prefix match */
+ if (name_length == 0 && entry[0] == '.' &&
+ !looking_for_lognames)
+ continue;
+ if (command == LIST) {
+ if (numitems >= MAXITEMS) {
+ printf ("\nYikes!! Too many %s!!\n",
+ looking_for_lognames ?
+ "names in password file":"files");
+ break;
+ }
+ if (items == NULL)
+ items = (tchar **) calloc(sizeof (items[1]),
+ MAXITEMS+1);
+ items[numitems] = (tchar *)xalloc((unsigned)(strlen_(entry) + 1)*sizeof(tchar));
+ copyn(items[numitems], entry, MAXNAMLEN);
+ numitems++;
+ } else { /* RECOGNIZE command */
+ if (ignoring && ignored(entry))
+ nignored++;
+ else if (recognize(extended_name,
+ entry, name_length, ++numitems))
+ break;
+ }
+ }
+ if (ignoring && numitems == 0 && nignored > 0) {
+ ignoring = FALSE;
+ nignored = 0;
+ if (looking_for_lognames)
+ (void)setpwent();
+ else
+ rewinddir(dir_fd);
+ goto again;
+ }
+
+ if (looking_for_lognames)
+ (void) endpwent();
+ else {
+ unsetfd(dir_fd->dd_fd);
+ closedir_(dir_fd);
+ }
+ if (command == RECOGNIZE && numitems > 0) {
+ if (looking_for_lognames)
+ copyn(word, S_TIL /*"~" */, 1);
+ else
+ /* put back dir part */
+ copyn(word, dir, max_word_length);
+ /* add extended name */
+ catn(word, extended_name, max_word_length);
+ return (numitems);
+ }
+ if (command == LIST) {
+ qsort( (char *)items, numitems, sizeof(items[1]),
+ (int (*)(const void *, const void *))fcompare);
+ /*
+ * Never looking for commands in this version, so final
+ * argument forced to 0. If command name completion is
+ * reinstated, this must change.
+ */
+ print_by_column(looking_for_lognames ? NULL : tilded_dir,
+ items, numitems, 0);
+ if (items != NULL)
+ FREE_ITEMS(items);
+ }
+ return (0);
+}
+
+/*
+ * Object: extend what user typed up to an ambiguity.
+ * Algorithm:
+ * On first match, copy full entry (assume it'll be the only match)
+ * On subsequent matches, shorten extended_name to the first
+ * character mismatch between extended_name and entry.
+ * If we shorten it back to the prefix length, stop searching.
+ */
+recognize(extended_name, entry, name_length, numitems)
+ tchar *extended_name, *entry;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- recognize()\n");
+#endif
+ if (numitems == 1) /* 1st match */
+ copyn(extended_name, entry, MAXNAMLEN);
+ else { /* 2nd and subsequent matches */
+ register tchar *x, *ent;
+ register int len = 0;
+
+ x = extended_name;
+ for (ent = entry; *x && *x == *ent++; x++, len++)
+ ;
+ *x = '\0'; /* Shorten at 1st char diff */
+ if (len == name_length) /* Ambiguous to prefix? */
+ return (-1); /* So stop now and save time */
+ }
+ return (0);
+}
+
+/*
+ * Return true if check items initial chars in template
+ * This differs from PWB imatch in that if check is null
+ * it items anything
+ */
+static
+is_prefix(check, template)
+ register tchar *check, *template;
+{
+#ifdef TRACE
+ tprintf("TRACE- is_prefix()\n");
+#endif
+
+ do
+ if (*check == 0)
+ return (TRUE);
+ while (*check++ == *template++);
+ return (FALSE);
+}
+
+/*
+ * Return true if the chars in template appear at the
+ * end of check, i.e., are its suffix.
+ */
+static
+is_suffix(check, template)
+ tchar *check, *template;
+{
+ register tchar *c, *t;
+
+#ifdef TRACE
+ tprintf("TRACE- is_suffix()\n");
+#endif
+ for (c = check; *c++;)
+ ;
+ for (t = template; *t++;)
+ ;
+ for (;;) {
+ if (t == template)
+ return (TRUE);
+ if (c == check || *--t != *--c)
+ return (FALSE);
+ }
+}
+
+tenex(inputline, inputline_size)
+ tchar *inputline;
+ int inputline_size;
+{
+ register int numitems, num_read, should_retype;
+ int i;
+
+#ifdef TRACE
+ tprintf("TRACE- tenex()\n");
+#endif
+ setup_tty(ON);
+ termchars();
+ num_read = 0;
+ should_retype = FALSE;
+ while ((i = read_(SHIN, inputline+num_read, inputline_size-num_read))
+ > 0) {
+ static tchar *delims = S_DELIM /*" '\"\t;&<>()|`"*/;
+ register tchar *str_end, *word_start, last_char;
+ register int space_left;
+ struct termios tty;
+ COMMAND command;
+
+ num_read += i;
+ inputline[num_read] = '\0';
+ last_char = inputline[num_read - 1] & TRIM;
+
+ if ((num_read == inputline_size) || (last_char == '\n'))
+ break;
+
+ str_end = &inputline[num_read];
+ if (last_char == ESC) {
+ command = RECOGNIZE;
+ *--str_end = '\0'; /* wipe out trailing ESC */
+ } else
+ command = LIST;
+
+ tty = tty_new;
+ tty.c_lflag &= ~ECHO;
+ (void) ioctl(SHIN, TCSETSF, (char *)&tty);
+
+ if (command == LIST)
+ printf("\n");
+ /*
+ * Find LAST occurence of a delimiter in the inputline.
+ * The word start is one character past it.
+ */
+ for (word_start = str_end; word_start > inputline;
+ --word_start) {
+ if (index_(delims, word_start[-1]) ||
+ isauxsp(word_start[-1]))
+ break;
+ }
+ space_left = inputline_size - (word_start - inputline) - 1;
+ numitems = search2(word_start, command, space_left);
+
+ /*
+ * Tabs in the input line cause trouble after a pushback.
+ * tty driver won't backspace over them because column
+ * positions are now incorrect. This is solved by retyping
+ * over current line.
+ */
+ if (index_(inputline, '\t')) { /* tab tchar in input line? */
+ back_to_col_1();
+ should_retype = TRUE;
+ }
+ if (command == LIST) /* Always retype after a LIST */
+ should_retype = TRUE;
+ if (should_retype)
+ printprompt();
+ pushback(inputline, should_retype);
+ num_read = 0; /* chars will be reread */
+ should_retype = FALSE;
+
+ /*
+ * Avoid a race condition by echoing what we're recognized
+ * _after_ pushing back the command line. This way, if the
+ * user waits until seeing this output before typing more
+ * stuff, the resulting keystrokes won't race with the STIed
+ * input we've pushed back. (Of course, if the user types
+ * ahead, the race still exists and it's quite possible that
+ * the pushed back input line will interleave with the
+ * keystrokes in unexpected ways.)
+ */
+ if (command == RECOGNIZE) {
+ /* print from str_end on */
+ print_recognized_stuff(str_end);
+ if (numitems != 1) /* Beep = No match/ambiguous */
+ beep();
+ }
+ }
+ setup_tty(OFF);
+ return (num_read);
+}
+
+static
+ignored(entry)
+ register tchar *entry;
+{
+ struct varent *vp;
+ register tchar **cp;
+
+#ifdef TRACE
+ tprintf("TRACE- ignored()\n");
+#endif
+ if ((vp = adrof(S_fignore /*"fignore"*/)) == NULL ||
+ (cp = vp->vec) == NULL)
+ return (FALSE);
+ for (; *cp != NULL; cp++)
+ if (is_suffix(entry, *cp))
+ return (TRUE);
+ return (FALSE);
+}
+#endif FILEC
diff --git a/usr/src/cmd/csh/sh.func.c b/usr/src/cmd/csh/sh.func.c
new file mode 100644
index 0000000000..c69f8882e1
--- /dev/null
+++ b/usr/src/cmd/csh/sh.func.c
@@ -0,0 +1,1645 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include <locale.h> /* For LC_ALL */
+#include "sh.tconst.h"
+#include <sys/types.h>
+#include <stdlib.h>
+
+/*
+ * N.B.: Some of the limits change from SunOS 4.x to SunOS 5.0. In
+ * particular, RLIMIT_RSS is gone and RLIMIT_VMEM is new. Beware of consusing
+ * the keywords that the command prints for these two. The old one was
+ * "memoryuse" and the new one is "memorysize". Note also that a given limit
+ * doesn't necessarily appear in the same position in the two releases.
+ */
+struct limits {
+ int limconst;
+ tchar *limname;
+ int limdiv;
+ tchar *limscale;
+} limits[] = {
+ RLIMIT_CPU, S_cputime, /* "cputime" */
+ 1, S_seconds, /* "seconds" */
+ RLIMIT_FSIZE, S_filesize, /* "filesize" */
+ 1024, S_kbytes, /* "kbytes" */
+ RLIMIT_DATA, S_datasize, /* "datasize" */
+ 1024, S_kbytes, /* "kbytes" */
+ RLIMIT_STACK, S_stacksize, /* "stacksize" */
+ 1024, S_kbytes, /* "kbytes" */
+ RLIMIT_CORE, S_coredumpsize, /* "coredumpsize" */
+ 1024, S_kbytes, /* "kbytes" */
+ RLIMIT_NOFILE, S_descriptors, /* "descriptors" */
+ 1, S_, /* "" */
+ RLIMIT_VMEM, S_memorysize, /* "memorysize" */
+ 1024, S_kbytes, /* "kbytes" */
+ -1, 0,
+};
+
+static int getval(struct limits *lp, tchar **v, rlim_t *);
+void islogin();
+int dolabel();
+void reexecute(struct command *kp);
+void preread_();
+void doagain();
+void toend();
+void wfree();
+void echo(tchar sep, tchar **v);
+void local_setenv(tchar *name, tchar *val);
+void local_unsetenv(tchar *name);
+void limtail(tchar *cp, tchar *str0);
+void plim(struct limits *lp, tchar hard);
+void search();
+
+#define BUFSZ 1028
+
+/*
+ * C shell
+ */
+
+struct
+biltins *
+isbfunc(struct command *t)
+{
+ tchar *cp = t->t_dcom[0];
+ struct biltins *bp, *bp1, *bp2;
+ int dofg1(), dobg1();
+
+ static struct biltins label = { S_, dolabel, 0, 0 };
+ static struct biltins foregnd = { S_Pjob, dofg1, 0, 0 };
+ static struct biltins backgnd = { S_PjobAND, dobg1, 0, 0 };
+#ifdef TRACE
+ tprintf("TRACE- isbfunc()\n");
+#endif
+ if (lastchr(cp) == ':') {
+ label.bname = cp;
+ return (&label);
+ }
+ if (*cp == '%') {
+ if (t->t_dflg & FAND) {
+ t->t_dflg &= ~FAND;
+ backgnd.bname = cp;
+ return (&backgnd);
+ }
+ foregnd.bname = cp;
+ return (&foregnd);
+ }
+ /*
+ * Binary search
+ * Bp1 is the beginning of the current search range.
+ * Bp2 is one past the end.
+ */
+ for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2; ) {
+ int i;
+
+ bp = bp1 + (bp2 - bp1 >> 1);
+ if ((i = *cp - *bp->bname) == 0 &&
+ (i = strcmp_(cp, bp->bname)) == 0) {
+ return (bp);
+ }
+ if (i < 0) {
+ bp2 = bp;
+ } else {
+ bp1 = bp + 1;
+ }
+ }
+ return (0);
+}
+
+void
+func(struct command *t, struct biltins *bp)
+{
+ int i;
+
+#ifdef TRACE
+ tprintf("TRACE- func()\n");
+#endif
+ xechoit(t->t_dcom);
+ setname(bp->bname);
+ i = blklen(t->t_dcom) - 1;
+ if (i < bp->minargs) {
+ bferr("Too few arguments");
+ }
+ if (i > bp->maxargs) {
+ bferr("Too many arguments");
+ }
+ (*bp->bfunct)(t->t_dcom, t);
+}
+
+int
+dolabel()
+{
+#ifdef TRACE
+ tprintf("TRACE- dolabel()\n");
+#endif
+
+}
+
+void
+doonintr(tchar **v)
+{
+ tchar *cp;
+ tchar *vv = v[1];
+
+#ifdef TRACE
+ tprintf("TRACE- doonintr()\n");
+#endif
+ if (parintr == SIG_IGN) {
+ return;
+ }
+ if (setintr && intty) {
+ bferr("Can't from terminal");
+ }
+ cp = gointr, gointr = 0, xfree(cp);
+ if (vv == 0) {
+ if (setintr) {
+ (void) sigblock(sigmask(SIGINT));
+ } else {
+ (void) signal(SIGINT, SIG_DFL);
+ }
+ gointr = 0;
+ } else if (eq((vv = strip(vv)), S_MINUS)) {
+ (void) signal(SIGINT, SIG_IGN);
+ gointr = S_MINUS;
+ } else {
+ gointr = savestr(vv);
+ (void) signal(SIGINT, pintr);
+ }
+}
+
+void
+donohup()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- donohup()\n");
+#endif
+ if (intty) {
+ bferr("Can't from terminal");
+ }
+ if (setintr == 0) {
+ (void) signal(SIGHUP, SIG_IGN);
+#ifdef CC
+ submit(getpid());
+#endif
+ }
+}
+
+void
+dozip()
+{
+ ;
+}
+
+void
+prvars()
+{
+#ifdef TRACE
+ tprintf("TRACE- prvars()\n");
+#endif
+
+ plist(&shvhed);
+}
+
+void
+doalias(tchar **v)
+{
+ struct varent *vp;
+ tchar *p;
+
+#ifdef TRACE
+ tprintf("TRACE- doalias()\n");
+#endif
+ v++;
+ p = *v++;
+ if (p == 0) {
+ plist(&aliases);
+ } else if (*v == 0) {
+ vp = adrof1(strip(p), &aliases);
+ if (vp) {
+ blkpr(vp->vec), printf("\n");
+ }
+ } else {
+ if (eq(p, S_alias) ||
+ eq(p, S_unalias)) {
+ setname(p);
+ bferr("Too dangerous to alias that");
+ }
+ set1(strip(p), saveblk(v), &aliases);
+ }
+}
+
+void
+unalias(tchar **v)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- unalias()\n");
+#endif
+ unset1(v, &aliases);
+}
+
+void
+dologout()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dologout()\n");
+#endif
+ islogin();
+ goodbye();
+}
+
+void
+dologin(tchar **v)
+{
+
+ char *v_; /* work */
+#ifdef TRACE
+ tprintf("TRACE- dologin()\n");
+#endif
+ islogin();
+ rechist();
+ (void) signal(SIGTERM, parterm);
+ if (v[1] != NULL) {
+ v_ = tstostr(NULL, v[1]); /* No need to free */
+ } else {
+ v_ = 0;
+ }
+ execl("/bin/login", "login", v_, 0);
+ untty();
+ exit(1);
+}
+
+#ifdef NEWGRP
+void
+donewgrp(tchar **v)
+{
+
+ char *v_; /* work */
+#ifdef TRACE
+ tprintf("TRACE- donewgrp()\n");
+#endif
+ if (chkstop == 0 && setintr) {
+ panystop(0);
+ }
+ (void) signal(SIGTERM, parterm);
+
+ if (v[1] != NULL) {
+ v_ = tstostr(NOSTR, v[1]); /* No need to free */
+ } else {
+ v_ = 0;
+ }
+ execl("/bin/newgrp", "newgrp", v_, 0);
+ execl("/usr/bin/newgrp", "newgrp", v_, 0);
+ untty();
+ exit(1);
+}
+#endif
+
+void
+islogin()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- islogin()\n");
+#endif
+ if (chkstop == 0 && setintr) {
+ panystop(0);
+ }
+ if (loginsh) {
+ return;
+ }
+ error("Not login shell");
+}
+
+void
+doif(tchar **v, struct command *kp)
+{
+ int i;
+ tchar **vv;
+
+#ifdef TRACE
+ tprintf("TRACE- doif()\n");
+#endif
+ v++;
+ i = exp(&v);
+ vv = v;
+ if (*vv == NOSTR) {
+ bferr("Empty if");
+ }
+ if (eq(*vv, S_then)) {
+ if (*++vv) {
+ bferr("Improper then");
+ }
+ setname(S_then);
+ /*
+ * If expression was zero, then scan to else,
+ * otherwise just fall into following code.
+ */
+ if (!i) {
+ search(ZIF, 0);
+ }
+ return;
+ }
+ /*
+ * Simple command attached to this if.
+ * Left shift the node in this tree, munging it
+ * so we can reexecute it.
+ */
+ if (i) {
+ lshift(kp->t_dcom, vv - kp->t_dcom);
+ reexecute(kp);
+ donefds();
+ }
+}
+
+/*
+ * Reexecute a command, being careful not
+ * to redo i/o redirection, which is already set up.
+ */
+void
+reexecute(struct command *kp)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- reexecute()\n");
+#endif
+ kp->t_dflg &= FSAVE;
+ kp->t_dflg |= FREDO;
+ /*
+ * If tty is still ours to arbitrate, arbitrate it;
+ * otherwise dont even set pgrp's as the jobs would
+ * then have no way to get the tty (we can't give it
+ * to them, and our parent wouldn't know their pgrp, etc.
+ */
+ execute(kp, tpgrp > 0 ? tpgrp : -1);
+}
+
+void
+doelse()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doelse()\n");
+#endif
+ search(ZELSE, 0);
+}
+
+void
+dogoto(tchar **v)
+{
+ struct whyle *wp;
+ tchar *lp;
+#ifdef TRACE
+ tprintf("TRACE- dogoto()\n");
+#endif
+
+ /*
+ * While we still can, locate any unknown ends of existing loops.
+ * This obscure code is the WORST result of the fact that we
+ * don't really parse.
+ */
+ for (wp = whyles; wp; wp = wp->w_next) {
+ if (wp->w_end == 0) {
+ search(ZBREAK, 0);
+ wp->w_end = btell();
+ } else {
+ bseek(wp->w_end);
+ }
+ }
+ search(ZGOTO, 0, lp = globone(v[1]));
+ xfree(lp);
+ /*
+ * Eliminate loops which were exited.
+ */
+ wfree();
+}
+
+void
+doswitch(tchar **v)
+{
+ tchar *cp, *lp;
+
+#ifdef TRACE
+ tprintf("TRACE- doswitch()\n");
+#endif
+ v++;
+ if (!*v || *(*v++) != '(') {
+ goto syntax;
+ }
+ cp = **v == ')' ? S_ : *v++;
+ if (*(*v++) != ')') {
+ v--;
+ }
+ if (*v) {
+syntax:
+ error("Syntax error");
+ }
+ search(ZSWITCH, 0, lp = globone(cp));
+ xfree(lp);
+}
+
+void
+dobreak()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dobreak()\n");
+#endif
+ if (whyles) {
+ toend();
+ } else {
+ bferr("Not in while/foreach");
+ }
+}
+
+void
+doexit(tchar **v)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doexit()\n");
+#endif
+ if (chkstop == 0) {
+ panystop(0);
+ }
+ /*
+ * Don't DEMAND parentheses here either.
+ */
+ v++;
+ if (*v) {
+ set(S_status, putn(exp(&v)));
+ if (*v) {
+ bferr("Expression syntax");
+ }
+ }
+ btoeof();
+ if (intty) {
+ (void) close(SHIN);
+ unsetfd(SHIN);
+ }
+}
+
+void
+doforeach(tchar **v)
+{
+ tchar *cp;
+ struct whyle *nwp;
+
+#ifdef TRACE
+ tprintf("TRACE- doforeach()\n");
+#endif
+ v++;
+ cp = strip(*v);
+ while (*cp && alnum(*cp)) {
+ cp++;
+ }
+ if (*cp || strlen_(*v) >= 20 || !letter(**v)) {
+ bferr("Invalid variable");
+ }
+ cp = *v++;
+ if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')') {
+ bferr("Words not ()'ed");
+ }
+ v++;
+ gflag = 0, tglob(v);
+ v = glob(v);
+ if (v == 0) {
+ bferr("No match");
+ }
+ nwp = (struct whyle *)calloc(1, sizeof (*nwp));
+ nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
+ nwp->w_start = btell();
+ nwp->w_fename = savestr(cp);
+ nwp->w_next = whyles;
+ whyles = nwp;
+ /*
+ * Pre-read the loop so as to be more
+ * comprehensible to a terminal user.
+ */
+ if (intty) {
+ preread_();
+ }
+ doagain();
+}
+
+void
+dowhile(tchar **v)
+{
+ int status;
+ bool again = whyles != 0 && whyles->w_start == lineloc &&
+ whyles->w_fename == 0;
+
+#ifdef TRACE
+ tprintf("TRACE- dowhile()\n");
+#endif
+ v++;
+ /*
+ * Implement prereading here also, taking care not to
+ * evaluate the expression before the loop has been read up
+ * from a terminal.
+ */
+ if (intty && !again) {
+ status = !exp0(&v, 1);
+ } else {
+ status = !exp(&v);
+ }
+ if (*v) {
+ bferr("Expression syntax");
+ }
+ if (!again) {
+ struct whyle *nwp = (struct whyle *)calloc(1, sizeof (*nwp));
+
+ nwp->w_start = lineloc;
+ nwp->w_end = 0;
+ nwp->w_next = whyles;
+ whyles = nwp;
+ if (intty) {
+ /*
+ * The tty preread
+ */
+ preread_();
+ doagain();
+ return;
+ }
+ }
+ if (status) {
+ /* We ain't gonna loop no more, no more! */
+ toend();
+ }
+}
+
+void
+preread_()
+{
+#ifdef TRACE
+ tprintf("TRACE- preread()\n");
+#endif
+
+ whyles->w_end = -1;
+ if (setintr) {
+ (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
+ }
+ search(ZBREAK, 0);
+ if (setintr) {
+ (void) sigblock(sigmask(SIGINT));
+ }
+ whyles->w_end = btell();
+}
+
+void
+doend()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doend()\n");
+#endif
+ if (!whyles) {
+ bferr("Not in while/foreach");
+ }
+ whyles->w_end = btell();
+ doagain();
+}
+
+void
+docontin()
+{
+#ifdef TRACE
+ tprintf("TRACE- docontin()\n");
+#endif
+
+ if (!whyles) {
+ bferr("Not in while/foreach");
+ }
+ doagain();
+}
+
+void
+doagain()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doagain()\n");
+#endif
+ /* Repeating a while is simple */
+ if (whyles->w_fename == 0) {
+ bseek(whyles->w_start);
+ return;
+ }
+ /*
+ * The foreach variable list actually has a spurious word
+ * ")" at the end of the w_fe list. Thus we are at the
+ * of the list if one word beyond this is 0.
+ */
+ if (!whyles->w_fe[1]) {
+ dobreak();
+ return;
+ }
+ set(whyles->w_fename, savestr(*whyles->w_fe++));
+ bseek(whyles->w_start);
+}
+
+void
+dorepeat(tchar **v, struct command *kp)
+{
+ int i, omask;
+
+#ifdef TRACE
+ tprintf("TRACE- dorepeat()\n");
+#endif
+ i = getn(v[1]);
+ if (setintr) {
+ omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
+ }
+ lshift(v, 2);
+ while (i > 0) {
+ if (setintr) {
+ (void) sigsetmask(omask);
+ }
+ reexecute(kp);
+ --i;
+ }
+ donefds();
+ if (setintr) {
+ (void) sigsetmask(omask);
+ }
+}
+
+void
+doswbrk()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doswbrk()\n");
+#endif
+ search(ZBRKSW, 0);
+}
+
+int
+srchx(tchar *cp)
+{
+ struct srch *sp, *sp1, *sp2;
+ int i;
+
+#ifdef TRACE
+ tprintf("TRACE- srchx()\n");
+#endif
+ /*
+ * Binary search
+ * Sp1 is the beginning of the current search range.
+ * Sp2 is one past the end.
+ */
+ for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2; ) {
+ sp = sp1 + (sp2 - sp1 >> 1);
+ if ((i = *cp - *sp->s_name) == 0 &&
+ (i = strcmp_(cp, sp->s_name)) == 0) {
+ return (sp->s_value);
+ }
+ if (i < 0) {
+ sp2 = sp;
+ } else {
+ sp1 = sp + 1;
+ }
+ }
+ return (-1);
+}
+
+tchar Stype;
+tchar *Sgoal;
+
+/*VARARGS2*/
+void
+search(type, level, goal)
+ int type; int level; tchar *goal;
+{
+ tchar wordbuf[BUFSIZ];
+ tchar *aword = wordbuf;
+ tchar *cp;
+
+#ifdef TRACE
+ tprintf("TRACE- search()\n");
+#endif
+ Stype = type; Sgoal = goal;
+ if (type == ZGOTO) {
+ bseek((off_t)0);
+ }
+ do {
+ if (intty && fseekp == feobp) {
+ printf("? "), flush();
+ }
+ aword[0] = 0;
+ (void) getword(aword);
+
+ switch (srchx(aword)) {
+
+ case ZELSE:
+ if (level == 0 && type == ZIF) {
+ return;
+ }
+ break;
+
+ case ZIF:
+ while (getword(aword)) {
+ continue;
+ }
+ if ((type == ZIF || type == ZELSE) &&
+ eq(aword, S_then)) {
+ level++;
+ }
+ break;
+
+ case ZENDIF:
+ if (type == ZIF || type == ZELSE) {
+ level--;
+ }
+ break;
+
+ case ZFOREACH:
+ case ZWHILE:
+ if (type == ZBREAK) {
+ level++;
+ }
+ break;
+
+ case ZEND:
+ if (type == ZBREAK) {
+ level--;
+ }
+ break;
+
+ case ZSWITCH:
+ if (type == ZSWITCH || type == ZBRKSW) {
+ level++;
+ }
+ break;
+
+ case ZENDSW:
+ if (type == ZSWITCH || type == ZBRKSW) {
+ level--;
+ }
+ break;
+
+ case ZLABEL:
+ if (type == ZGOTO && getword(aword) &&
+ eq(aword, goal)) {
+ level = -1;
+ }
+ break;
+
+ default:
+ if (type != ZGOTO && (type != ZSWITCH || level != 0)) {
+ break;
+ }
+ if (lastchr(aword) != ':') {
+ break;
+ }
+ aword[strlen_(aword) - 1] = 0;
+ if (type == ZGOTO && eq(aword, goal) ||
+ type == ZSWITCH && eq(aword, S_default)) {
+ level = -1;
+ }
+ break;
+
+ case ZCASE:
+ if (type != ZSWITCH || level != 0) {
+ break;
+ }
+ (void) getword(aword);
+ if (lastchr(aword) == ':') {
+ aword[strlen_(aword) - 1] = 0;
+ }
+ cp = strip(Dfix1(aword));
+ if (Gmatch(goal, cp)) {
+ level = -1;
+ }
+ xfree(cp);
+ break;
+
+ case ZDEFAULT:
+ if (type == ZSWITCH && level == 0) {
+ level = -1;
+ }
+ break;
+ }
+ (void) getword(NOSTR);
+ } while (level >= 0);
+}
+
+int
+getword(tchar *wp)
+{
+ int found = 0;
+ int c, d;
+#ifdef TRACE
+ tprintf("TRACE- getword()\n");
+#endif
+
+ c = readc(1);
+ d = 0;
+ do {
+ while (issp(c)) {
+ c = readc(1);
+ }
+ if (c == '#') {
+ do {
+ c = readc(1);
+ } while (c >= 0 && c != '\n');
+ }
+ if (c < 0) {
+ goto past;
+ }
+ if (c == '\n') {
+ if (wp) {
+ break;
+ }
+ return (0);
+ }
+
+ /* ( and ) form separate words */
+ if (c == '(' || c == ')') {
+ return (1);
+ }
+
+ unreadc(c);
+ found = 1;
+ do {
+ c = readc(1);
+ if (c == '\\' && (c = readc(1)) == '\n') {
+ c = ' ';
+ }
+ if (c == '\'' || c == '"') {
+ if (d == 0) {
+ d = c;
+ } else if (d == c) {
+ d = 0;
+ }
+ }
+ if (c < 0) {
+ goto past;
+ }
+ if (wp) {
+ *wp++ = c;
+ }
+ } while ((d || !issp(c) && c != '(' && c != ')') && c != '\n');
+ } while (wp == 0);
+ unreadc(c);
+ if (found) {
+ *--wp = 0;
+ }
+ return (found);
+
+past:
+ switch (Stype) {
+
+ case ZIF:
+ bferr("then/endif not found");
+
+ case ZELSE:
+ bferr("endif not found");
+
+ case ZBRKSW:
+ case ZSWITCH:
+ bferr("endsw not found");
+
+ case ZBREAK:
+ bferr("end not found");
+
+ case ZGOTO:
+ setname(Sgoal);
+ bferr("label not found");
+ }
+ /*NOTREACHED*/
+}
+
+void
+toend()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- toend()\n");
+#endif
+ if (whyles->w_end == 0) {
+ search(ZBREAK, 0);
+ whyles->w_end = btell() - 1;
+ } else {
+ bseek(whyles->w_end);
+ }
+ wfree();
+}
+
+void
+wfree()
+{
+ long o = btell();
+
+#ifdef TRACE
+ tprintf("TRACE- wfree()\n");
+#endif
+ while (whyles) {
+ struct whyle *wp = whyles;
+ struct whyle *nwp = wp->w_next;
+
+ if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end)) {
+ break;
+ }
+ if (wp->w_fe0) {
+ blkfree(wp->w_fe0);
+ }
+ if (wp->w_fename) {
+ xfree(wp->w_fename);
+ }
+ xfree((char *)wp);
+ whyles = nwp;
+ }
+}
+
+void
+doecho(tchar **v)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doecho()\n");
+#endif
+ echo(' ', v);
+}
+
+void
+doglob(tchar **v)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- doglob()\n");
+#endif
+ echo(0, v);
+ flush();
+}
+
+void
+echo(tchar sep, tchar **v)
+{
+ tchar *cp;
+ int nonl = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- echo()\n");
+#endif
+ if (setintr) {
+ (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
+ }
+ v++;
+ if (*v == 0) {
+ /*
+ * echo command needs to have newline when there are no
+ * flags or arguments. glob should have no newline. If
+ * the separator is a blank, we are doing an echo. If the
+ * separator is zero, we are globbing.
+ */
+ if (sep == (tchar)' ')
+ Putchar('\n');
+ return;
+ }
+ gflag = 0, tglob(v);
+ if (gflag) {
+ v = glob(v);
+ if (v == 0) {
+ bferr("No match");
+ }
+ }
+ /* check for -n arg, NOTE: it might be quoted */
+ if (sep == ' ' && *v && strlen_(*v) == 2 &&
+ ((**v&TRIM) == '-' && (*(*v + 1) & TRIM) == 'n' &&
+ (*(*v+2)&TRIM) == 0)) {
+ nonl++, v++;
+ }
+ while (cp = *v++) {
+ int c;
+
+ while (c = *cp++) {
+ Putchar(c | QUOTE);
+ }
+ if (*v) {
+ Putchar(sep | QUOTE);
+ }
+ }
+ if (sep && nonl == 0) {
+ Putchar('\n');
+ } else {
+ flush();
+ }
+ if (setintr) {
+ (void) sigblock(sigmask(SIGINT));
+ }
+ if (gargv) {
+ blkfree(gargv), gargv = 0;
+ }
+}
+
+extern char **environ;
+
+/*
+ * Check if the environment variable vp affects this csh's behavior
+ * and therefore we should call setlocale() or not.
+ * This function has two side effects when it returns 1:
+ * variable islocalevar_catnum is set to the LC_xxx value.
+ * variable islocalevar_catname is set to the string "LC_xxx"
+ */
+static int islocalevar_catnum;
+static char *islocalevar_catname;
+
+static
+bool
+islocalevar(tchar *vp)
+{
+ static struct lcinfo {
+ tchar * evname; /* The name of the env. var. */
+ } categories_we_care[] = {
+ S_LANG, S_LC_ALL, S_LC_CTYPE, S_LC_MESSAGES,
+ NOSTR /* assumption: LC_xxx >= 0 */
+ };
+ struct lcinfo *p = categories_we_care;
+
+ do {
+ if (strcmp_(vp, p->evname) == 0) {
+ return (1);
+ }
+ } while (((++p)->evname) != NOSTR);
+ return (0);
+}
+
+void
+dosetenv(tchar **v)
+{
+ tchar *vp, *lp;
+
+#ifdef TRACE
+ tprintf("TRACE- dosetenv()\n");
+#endif
+ v++;
+ if ((vp = *v++) == 0) {
+ char **ep;
+
+ if (setintr) {
+ (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
+ }
+ for (ep = environ; *ep; ep++) {
+ printf("%s\n", *ep);
+ }
+ return;
+ }
+
+ if ((lp = *v++) == 0) {
+ lp = S_; /* "" */
+ }
+ local_setenv(vp, lp = globone(lp));
+ if (eq(vp, S_PATH)) {
+ importpath(lp);
+ dohash(xhash);
+ } else if (islocalevar(vp)) {
+ if (!setlocale(LC_ALL, "")) {
+ error("Locale could not be set properly");
+ }
+ }
+
+ xfree(lp);
+}
+
+void
+dounsetenv(tchar **v)
+{
+#ifdef TRACE
+ tprintf("TRACE- dounsetenv()\n");
+#endif
+ v++;
+ do {
+ local_unsetenv(*v);
+ if (islocalevar(*v++)) {
+ setlocale(LC_ALL, ""); /* Hope no error! */
+ }
+ } while (*v);
+}
+
+void
+local_setenv(tchar *name, tchar *val)
+{
+ char **ep = environ;
+ tchar *cp;
+ char *dp;
+ tchar *ep_; /* temporary */
+ char *blk[2], **oep = ep;
+
+#ifdef TRACE
+ /* tprintf("TRACE- local_setenv(%t, %t)\n", name, val); */
+ /* printf("IN local_setenv args = (%t)\n", val); */
+#endif
+ for (; *ep; ep++) {
+#ifdef MBCHAR
+ for (cp = name, dp = *ep; *cp && *dp; cp++) {
+ /*
+ * This loop compares two chars in different
+ * representations, EUC (as char *) and wchar_t
+ * (in tchar), and ends when they are different.
+ */
+ wchar_t dwc;
+ int n;
+
+ n = mbtowc(&dwc, dp, MB_CUR_MAX);
+ if (n <= 0) {
+ break; /* Illegal multibyte. */
+ }
+ dp += n; /* Advance to next multibyte char. */
+ if (dwc == (wchar_t)(*cp & TRIM)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+#else /* !MBCHAR */
+ for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
+ continue;
+ }
+#endif /* !MBCHAR */
+ if (*cp != 0 || *dp != '=') {
+ continue;
+ }
+ cp = strspl(S_EQ, val);
+ xfree(*ep);
+ ep_ = strspl(name, cp); /* ep_ is xalloc'ed */
+ xfree(cp);
+ /*
+ * Trimming is not needed here.
+ * trim();
+ */
+ *ep = tstostr(NULL, ep_);
+ xfree(ep_); /* because temp. use */
+ return;
+ }
+ ep_ = strspl(name, S_EQ); /* ep_ is xalloc'ed */
+ blk[0] = tstostr(NULL, ep_);
+ blk[1] = 0;
+ xfree(ep_);
+ environ = (char **)blkspl_((unsigned char **)environ, blk);
+ xfree((void *)oep);
+ local_setenv(name, val);
+}
+
+void
+local_unsetenv(tchar *name)
+{
+ char **ep = environ;
+ tchar *cp;
+ char *dp;
+ char **oep = ep;
+ char *cp_; /* tmp use */
+ static cnt = 0; /* delete counter */
+
+#ifdef TRACE
+ tprintf("TRACE- local_unsetenv()\n");
+#endif
+ for (; *ep; ep++) {
+#ifdef MBCHAR
+ for (cp = name, dp = *ep; *cp && *dp; cp++) {
+ /*
+ * This loop compares two chars in different
+ * representations, EUC (as char *) and wchar_t
+ * (in tchar), and ends when they are different.
+ */
+ wchar_t dwc;
+ int n;
+
+ n = mbtowc(&dwc, dp, MB_CUR_MAX);
+ if (n <= 0) {
+ break; /* Illegal multibyte. */
+ }
+ dp += n; /* Advance to next multibyte char. */
+ if (dwc == (wchar_t)(*cp & TRIM)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+#else /* !MBCHAR */
+ for (cp = name, dp = *ep; *cp && (char)*cp == *dp; cp++, dp++) {
+ continue;
+ }
+#endif /* !MBCHAR */
+ if (*cp != 0 || *dp != '=') {
+ continue;
+ }
+ cp_ = *ep;
+ *ep = 0;
+ environ = (char **)blkspl_((unsigned char **)environ, ep+1);
+ *ep = cp_;
+ xfree(cp_);
+ xfree((void *)oep);
+ return;
+ }
+}
+
+void
+doumask(tchar **v)
+{
+ tchar *cp = v[1];
+ int i;
+
+#ifdef TRACE
+ tprintf("TRACE- dounmask()\n");
+#endif
+ if (cp == 0) {
+ i = umask(0);
+ (void) umask(i);
+ printf("%o\n", i);
+ return;
+ }
+ i = 0;
+ while (digit(*cp) && *cp != '8' && *cp != '9') {
+ i = i * 8 + *cp++ - '0';
+ }
+ if (*cp || i < 0 || i > 0777) {
+ bferr("Improper mask");
+ }
+ (void) umask(i);
+}
+
+
+struct limits *
+findlim(tchar *cp)
+{
+ struct limits *lp, *res;
+
+#ifdef TRACE
+ tprintf("TRACE- findlim()\n");
+#endif
+ res = 0;
+ for (lp = limits; lp->limconst >= 0; lp++) {
+ if (prefix(cp, lp->limname)) {
+ if (res) {
+ bferr("Ambiguous");
+ }
+ res = lp;
+ }
+ }
+ if (res) {
+ return (res);
+ }
+ bferr("No such limit");
+ /*NOTREACHED*/
+}
+
+void
+dolimit(tchar **v)
+{
+ struct limits *lp;
+ rlim_t limit;
+ tchar hard = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- dolimit()\n");
+#endif
+ v++;
+ if (*v && eq(*v, S_h)) {
+ hard = 1;
+ v++;
+ }
+ if (*v == 0) {
+ for (lp = limits; lp->limconst >= 0; lp++) {
+ plim(lp, hard);
+ }
+ return;
+ }
+ lp = findlim(v[0]);
+ if (v[1] == 0) {
+ plim(lp, hard);
+ return;
+ }
+ switch (getval(lp, v+1, &limit)) {
+ case 0:
+ error("Value specified for limit is too large");
+ return;
+ case (-1):
+ error("Numeric conversion failed");
+ return;
+ default:
+ if (setlim(lp, hard, limit) < 0) {
+ error(NOSTR);
+ }
+ }
+}
+
+static int
+getval(struct limits *lp, tchar **v, rlim_t *retval)
+{
+ rlim_t value, tmp, tmp2;
+ tchar *cp = *v++;
+ char chbuf[BUFSIZ * MB_LEN_MAX];
+
+#ifdef TRACE
+ tprintf("TRACE- getval()\n");
+#endif
+
+ tstostr(chbuf, cp);
+ errno = 0;
+ value = strtoull(chbuf, NULL, 0);
+/*
+ * we must accept zero, but the conversion can fail and give us
+ * zero as well...try to deal with it as gracefully as possible
+ * by checking for EINVAL
+ */
+ if (value == 0 && errno == EINVAL)
+ return (-1);
+
+ while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E') {
+ cp++;
+ }
+ if (*cp == 0) {
+ if (*v == 0) {
+ tmp = value * (rlim_t)lp->limdiv;
+ /* Check for overflow */
+ if (tmp >= value) {
+ *retval = tmp;
+ return (1);
+ } else {
+ return (0);
+ }
+ }
+ cp = *v;
+ }
+ switch (*cp) {
+
+ case ':':
+ if (lp->limconst != RLIMIT_CPU) {
+ goto badscal;
+ }
+ tstostr(chbuf, cp + 1);
+ tmp = strtoull(chbuf, NULL, 0);
+ tmp2 = value * 60 + tmp;
+ if (tmp2 >= value) {
+ *retval = tmp2;
+ return (1);
+ } else {
+ return (0);
+ }
+
+ case 'h':
+ if (lp->limconst != RLIMIT_CPU) {
+ goto badscal;
+ }
+ limtail(cp, S_hours);
+ tmp = value * 3600;
+ if (tmp < value) {
+ return (0);
+ }
+ value = tmp;
+ break;
+
+ case 'm':
+ if (lp->limconst == RLIMIT_CPU) {
+ limtail(cp, S_minutes);
+ tmp = value * 60;
+ if (tmp < value) {
+ return (0);
+ }
+ value = tmp;
+ break;
+ }
+ case 'M':
+ if (lp->limconst == RLIMIT_CPU) {
+ goto badscal;
+ }
+ *cp = 'm';
+ limtail(cp, S_megabytes);
+ tmp = value * 1024 * 1024;
+ if (tmp < value) {
+ return (0);
+ }
+ value = tmp;
+ break;
+
+ case 's':
+ if (lp->limconst != RLIMIT_CPU) {
+ goto badscal;
+ }
+ limtail(cp, S_seconds);
+ break;
+
+ case 'k':
+ if (lp->limconst == RLIMIT_CPU) {
+ goto badscal;
+ }
+ limtail(cp, S_kbytes);
+ tmp = value * 1024;
+ if (tmp < value) {
+ return (0);
+ }
+ value = tmp;
+ break;
+
+ case 'u':
+ limtail(cp, S_unlimited);
+ *retval = RLIM_INFINITY;
+ return (1);
+
+ default:
+badscal:
+ bferr("Improper or unknown scale factor");
+ }
+ *retval = value;
+ return (1);
+}
+
+void
+limtail(tchar *cp, tchar *str0)
+{
+ tchar *str = str0;
+#ifdef TRACE
+ tprintf("TRACE- limtail()\n");
+#endif
+
+ while (*cp && *cp == *str) {
+ cp++, str++;
+ }
+ if (*cp) {
+ error("Bad scaling; did you mean ``%t''?", str0);
+ }
+}
+
+void
+plim(struct limits *lp, tchar hard)
+{
+ struct rlimit rlim;
+ char buf[BUFSZ];
+ char *pbuf;
+ rlim_t limit;
+
+#ifdef TRACE
+ tprintf("TRACE- plim()\n");
+#endif
+ printf("%t \t", lp->limname);
+ (void) getrlimit(lp->limconst, &rlim);
+ limit = hard ? rlim.rlim_max : rlim.rlim_cur;
+ if (limit == RLIM_INFINITY) {
+ printf("unlimited");
+ } else if (lp->limconst == RLIMIT_CPU) {
+ psecs_ull(limit);
+ } else {
+ buf[BUFSZ - 1] = '\0';
+ pbuf = ulltostr((limit / lp->limdiv), &buf[BUFSZ - 1]);
+ printf("%s %t", pbuf, lp->limscale);
+ }
+ printf("\n");
+}
+
+void
+dounlimit(tchar **v)
+{
+ struct limits *lp;
+ int err = 0;
+ tchar hard = 0;
+#ifdef TRACE
+ tprintf("TRACE- dounlimit()\n");
+#endif
+
+ v++;
+ if (*v && eq(*v, S_h)) {
+ hard = 1;
+ v++;
+ }
+ if (*v == 0) {
+ for (lp = limits; lp->limconst >= 0; lp++) {
+ if (setlim(lp, hard, RLIM_INFINITY) < 0) {
+ err++;
+ }
+ }
+ if (err) {
+ error(NULL);
+ }
+ return;
+ }
+ while (*v) {
+ lp = findlim(*v++);
+ if (setlim(lp, hard, RLIM_INFINITY) < 0) {
+ error(NULL);
+ }
+ }
+}
+
+int
+setlim(struct limits *lp, tchar hard, rlim_t limit)
+{
+ struct rlimit rlim;
+
+#ifdef TRACE
+ tprintf("TRACE- setlim()\n");
+#endif
+ (void) getrlimit(lp->limconst, &rlim);
+ if (hard) {
+ rlim.rlim_max = limit;
+ } else if (limit == RLIM_INFINITY && geteuid() != 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ } else {
+ rlim.rlim_cur = limit;
+ }
+ if (setrlimit(lp->limconst, &rlim) < 0) {
+ printf("%t: %t: Can't %s%s limit\n", bname, lp->limname,
+ limit == RLIM_INFINITY ? "remove" : "set",
+ hard ? " hard" : "");
+ return (-1);
+ }
+ return (0);
+}
+
+void
+dosuspend()
+{
+ int ctpgrp;
+ void (*old)();
+
+#ifdef TRACE
+ tprintf("TRACE- dosuspend()\n");
+#endif
+ if (loginsh) {
+ error("Can't suspend a login shell (yet)");
+ }
+ if (getpid() == getsid(0)) {
+ error("Can't suspend this shell");
+ }
+ untty();
+ old = (void (*)())signal(SIGTSTP, SIG_DFL);
+ (void) kill(0, SIGTSTP);
+ /* the shell stops here */
+ (void) signal(SIGTSTP, old);
+ if (tpgrp != -1) {
+retry:
+ (void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp);
+ if (ctpgrp != opgrp) {
+ old = (void (*)())signal(SIGTTIN, SIG_DFL);
+ (void) kill(0, SIGTTIN);
+ (void) signal(SIGTTIN, old);
+ goto retry;
+ }
+ (void) setpgid(0, shpgrp);
+ (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
+ }
+}
+
+void
+doeval(tchar **v)
+{
+ tchar **oevalvec = evalvec;
+ tchar *oevalp = evalp;
+ jmp_buf osetexit;
+ int reenter;
+ tchar **gv = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- doeval()\n");
+#endif
+ v++;
+ if (*v == 0) {
+ return;
+ }
+ gflag = 0, tglob(v);
+ if (gflag) {
+ gv = v = glob(v);
+ gargv = 0;
+ if (v == 0) {
+ error("No match");
+ }
+ v = copyblk(v);
+ } else {
+ trim(v);
+ }
+ getexit(osetexit);
+ reenter = 0;
+ setexit();
+ reenter++;
+ if (reenter == 1) {
+ evalvec = v;
+ evalp = 0;
+ process(0);
+ }
+ evalvec = oevalvec;
+ evalp = oevalp;
+ doneinp = 0;
+ if (gv) {
+ blkfree(gv);
+ }
+ resexit(osetexit);
+ if (reenter >= 2) {
+ error(NULL);
+ }
+}
diff --git a/usr/src/cmd/csh/sh.glob.c b/usr/src/cmd/csh/sh.glob.c
new file mode 100644
index 0000000000..1d639392e5
--- /dev/null
+++ b/usr/src/cmd/csh/sh.glob.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+#include <dirent.h>
+#ifdef MBCHAR
+#include <widec.h> /* wcsetno() */
+#include <fnmatch.h> /* fnmatch() */
+#endif /* MBCHAR */
+
+/*
+ * C Shell
+ */
+
+int globcnt;
+
+tchar *gpath, *gpathp, *lastgpathp;
+int globbed;
+bool noglob;
+bool nonomatch;
+tchar *entp;
+tchar **sortbas;
+int sortscmp();
+extern DIR *opendir_();
+
+#define sort() qsort((char *)sortbas, &gargv[gargc] - sortbas, \
+ sizeof (*sortbas), (int (*)(const void *, \
+ const void *)) sortscmp), sortbas = &gargv[gargc]
+
+
+tchar **
+glob(v)
+ register tchar **v;
+{
+ tchar agpath[BUFSIZ];
+ tchar *agargv[GAVSIZ];
+
+ gpath = agpath; gpathp = gpath; *gpathp = 0;
+ lastgpathp = &gpath[BUFSIZ - 2];
+ ginit(agargv); globcnt = 0;
+#ifdef TRACE
+ tprintf("TRACE- glob()\n");
+#endif
+#ifdef GDEBUG
+ printf("glob entered: "); blkpr(v); printf("\n");
+#endif
+ noglob = adrof(S_noglob /* "noglob" */) != 0;
+ nonomatch = adrof(S_nonomatch /* "nonomatch" */) != 0;
+ globcnt = noglob | nonomatch;
+ while (*v)
+ collect(*v++);
+#ifdef GDEBUG
+ printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag);
+ blkpr(gargv); printf("\n");
+#endif
+ if (globcnt == 0 && (gflag&1)) {
+ blkfree(gargv), gargv = 0;
+ return (0);
+ } else
+ return (gargv = copyblk(gargv));
+}
+
+ginit(agargv)
+ tchar **agargv;
+{
+
+ agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
+ gnleft = NCARGS - 4;
+}
+
+collect(as)
+ register tchar *as;
+{
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- collect()\n");
+#endif
+ if (any('`', as)) {
+#ifdef GDEBUG
+ printf("doing backp of %t\n", as);
+#endif
+ (void) dobackp(as, 0);
+#ifdef GDEBUG
+ printf("backp done, acollect'ing\n");
+#endif
+ /*
+ * dobackp has the side effect of messing with
+ * gflag, since it does more globbing, so check
+ * if the results is still globbable
+ */
+ tglob(pargv);
+
+ for (i = 0; i < pargc; i++)
+ if (noglob) {
+ Gcat(pargv[i], S_ /* "" */);
+ sortbas = &gargv[gargc];
+ } else
+ acollect(pargv[i]);
+ if (pargv)
+ blkfree(pargv), pargv = 0;
+#ifdef GDEBUG
+ printf("acollect done\n");
+#endif
+ } else if (noglob || eq(as, S_LBRA /* "{" */) ||
+ eq(as, S_BRABRA /* "{}" */)) {
+ Gcat(as, S_ /* "" */);
+ sort();
+ } else
+ acollect(as);
+}
+
+acollect(as)
+ register tchar *as;
+{
+ register long ogargc = gargc;
+
+#ifdef TRACE
+ tprintf("TRACE- acollect()\n");
+#endif
+ gpathp = gpath; *gpathp = 0; globbed = 0;
+ expand(as);
+ if (gargc == ogargc) {
+ if (nonomatch) {
+ Gcat(as, S_ /* "" */);
+ sort();
+ }
+ } else
+ sort();
+}
+
+/*
+ * String compare for qsort. Also used by filec code in sh.file.c.
+ */
+sortscmp(a1, a2)
+ tchar **a1, **a2;
+{
+
+ return (strcoll_(*a1, *a2));
+}
+
+expand(as)
+ tchar *as;
+{
+ register tchar *cs;
+ register tchar *sgpathp, *oldcs;
+ struct stat stb;
+
+#ifdef TRACE
+ tprintf("TRACE- expand()\n");
+#endif
+ sgpathp = gpathp;
+ cs = as;
+ if (*cs == '~' && gpathp == gpath) {
+ addpath('~');
+ for (cs++; alnum(*cs) || *cs == '-'; )
+ addpath(*cs++);
+ if (!*cs || *cs == '/') {
+ if (gpathp != gpath + 1) {
+ *gpathp = 0;
+ if (gethdir(gpath + 1))
+ /*
+ * modified from %s to %t
+ */
+ error("Unknown user: %t", gpath + 1);
+ (void) strcpy_(gpath, gpath + 1);
+ } else
+ (void) strcpy_(gpath,
+ value(S_home /* "home" */));
+ gpathp = strend(gpath);
+ }
+ }
+ while (!isglob(*cs)) {
+ if (*cs == 0) {
+ if (!globbed)
+ Gcat(gpath, S_ /* "" */);
+ else if (lstat_(gpath, &stb) >= 0) {
+ Gcat(gpath, S_ /* "" */);
+ globcnt++;
+ }
+ goto endit;
+ }
+ addpath(*cs++);
+ }
+ oldcs = cs;
+ while (cs > as && *cs != '/')
+ cs--, gpathp--;
+ if (*cs == '/')
+ cs++, gpathp++;
+ *gpathp = 0;
+ if (*oldcs == '{') {
+ (void) execbrc(cs, NOSTR);
+ return;
+ }
+ matchdir_(cs);
+endit:
+ gpathp = sgpathp;
+ *gpathp = 0;
+}
+
+matchdir_(pattern)
+ tchar *pattern;
+{
+ struct stat stb;
+ register struct dirent *dp;
+ register DIR *dirp;
+ tchar curdir_[MAXNAMLEN+1];
+ int slproc = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- matchdir()\n");
+#endif
+ /*
+ * BSD's opendir would open "." if argument is NULL, but not S5
+ */
+
+ if (*gpath == NULL)
+ dirp = opendir_(S_DOT /* "." */);
+ else
+ dirp = opendir_(gpath);
+ if (dirp == NULL) {
+ if (globbed)
+ return;
+ goto patherr2;
+ }
+ if (fstat(dirp->dd_fd, &stb) < 0)
+ goto patherr1;
+ if (!isdir(stb)) {
+ errno = ENOTDIR;
+ goto patherr1;
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+
+ if (dp->d_ino == 0)
+ continue;
+ strtots(curdir_, dp->d_name);
+ slproc = 0;
+ if (match(curdir_, pattern, &slproc)) {
+ Gcat(gpath, curdir_);
+ globcnt++;
+ }
+ }
+ unsetfd(dirp->dd_fd);
+ closedir_(dirp);
+ return;
+
+patherr1:
+ unsetfd(dirp->dd_fd);
+ closedir_(dirp);
+patherr2:
+ Perror(gpath);
+}
+
+execbrc(p, s)
+ tchar *p, *s;
+{
+ tchar restbuf[BUFSIZ + 2];
+ register tchar *pe, *pm, *pl;
+ int brclev = 0;
+ tchar *lm, savec, *sgpathp;
+ int slproc = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- execbrc()\n");
+#endif
+ for (lm = restbuf; *p != '{'; *lm++ = *p++)
+ continue;
+ for (pe = ++p; *pe; pe++)
+ switch (*pe) {
+
+ case '{':
+ brclev++;
+ continue;
+
+ case '}':
+ if (brclev == 0)
+ goto pend;
+ brclev--;
+ continue;
+
+ case '[':
+ for (pe++; *pe && *pe != ']'; pe++)
+ continue;
+ if (!*pe)
+ error("Missing ]");
+ continue;
+ }
+pend:
+ if (brclev || !*pe)
+ error("Missing }");
+ for (pl = pm = p; pm <= pe; pm++)
+ switch (*pm & (QUOTE|TRIM)) {
+
+ case '{':
+ brclev++;
+ continue;
+
+ case '}':
+ if (brclev) {
+ brclev--;
+ continue;
+ }
+ goto doit;
+
+ case ',':
+ if (brclev)
+ continue;
+doit:
+ savec = *pm;
+ *pm = 0;
+ (void) strcpy_(lm, pl);
+ (void) strcat_(restbuf, pe + 1);
+ *pm = savec;
+ if (s == 0) {
+ sgpathp = gpathp;
+ expand(restbuf);
+ gpathp = sgpathp;
+ *gpathp = 0;
+ } else if (amatch(s, restbuf, &slproc))
+ return (1);
+ sort();
+ pl = pm + 1;
+ continue;
+
+ case '[':
+ for (pm++; *pm && *pm != ']'; pm++)
+ continue;
+ if (!*pm)
+ error("Missing ]");
+ continue;
+ }
+ return (0);
+}
+
+match(s, p, slproc)
+ tchar *s, *p;
+ int *slproc;
+{
+ register int c;
+ register tchar *sentp;
+ tchar sglobbed = globbed;
+
+#ifdef TRACE
+ tprintf("TRACE- match()\n");
+#endif
+ if (*s == '.' && *p != '.')
+ return (0);
+ sentp = entp;
+ entp = s;
+ c = amatch(s, p, slproc);
+ entp = sentp;
+ globbed = sglobbed;
+ return (c);
+}
+
+amatch(s, p, slproc)
+ register tchar *s, *p;
+ int *slproc;
+{
+ register int scc;
+ int ok, lc;
+ tchar *sgpathp;
+ struct stat stb;
+ int c, cc;
+
+#ifdef TRACE
+ tprintf("TRACE- amatch()\n");
+#endif
+ globbed = 1;
+ for (;;) {
+ scc = *s++ & TRIM;
+ switch (c = *p++) {
+
+ case '{':
+ return (execbrc(p - 1, s - 1));
+
+ case '[':
+ ok = 0;
+ lc = TRIM;
+ while (cc = *p++) {
+ if (cc == ']') {
+ if (ok)
+ break;
+ return (0);
+ }
+ if (cc == '-') {
+#ifdef MBCHAR
+ wchar_t rc = *p++;
+ if (rc == ']') {
+ p--;
+ continue;
+ }
+ /*
+ * Both ends of the char range
+ * must belong to the same codeset.
+ */
+ if (sh_bracket_exp(scc, lc, rc))
+ ok++;
+#else /* !MBCHAR */
+ if (lc <= scc && scc <= (int) *p++)
+ ok++;
+#endif /* !MBCHAR */
+ } else
+ if (scc == (lc = cc))
+ ok++;
+ }
+ if (cc == 0)
+ error("Missing ]");
+ continue;
+
+ case '*':
+ if (!*p)
+ return (1);
+ if (*p == '/') {
+ p++;
+ goto slash;
+ } else if (*p == '*') {
+ s--;
+ continue;
+ }
+
+ for (s--; *s; s++)
+ if (amatch(s, p, slproc))
+ return (1);
+
+ return (0);
+
+ case 0:
+ return (scc == 0);
+
+ default:
+ if ((c & TRIM) != scc)
+ return (0);
+ continue;
+
+ case '?':
+ if (scc == 0)
+ return (0);
+ continue;
+
+ case '/':
+ if (scc)
+ return (0);
+slash:
+ if (*slproc) /* Need to expand "/" only once */
+ return (0);
+ else
+ *slproc = 1;
+
+ s = entp;
+ sgpathp = gpathp;
+ while (*s)
+ addpath(*s++);
+ addpath('/');
+ if (stat_(gpath, &stb) == 0 && isdir(stb))
+ if (*p == 0) {
+ Gcat(gpath, S_ /* "" */);
+ globcnt++;
+ } else
+ expand(p);
+ gpathp = sgpathp;
+ *gpathp = 0;
+ return (0);
+ }
+ }
+}
+
+Gmatch(s, p)
+ register tchar *s, *p;
+{
+ register int scc;
+ int ok, lc;
+ int c, cc;
+
+#ifdef TRACE
+ tprintf("TRACE- Gmatch()\n");
+#endif
+ for (;;) {
+ scc = *s++ & TRIM;
+ switch (c = *p++) {
+
+ case '[':
+ ok = 0;
+ lc = TRIM;
+ while (cc = *p++) {
+ if (cc == ']') {
+ if (ok)
+ break;
+ return (0);
+ }
+ if (cc == '-') {
+#ifdef MBCHAR
+ wchar_t rc = *p++;
+ /*
+ * Both ends of the char range
+ * must belong to the same codeset...
+ */
+ if (sh_bracket_exp(scc, lc, rc))
+ ok++;
+#else /* !MBCHAR */
+ if (lc <= scc && scc <= (int) *p++)
+ ok++;
+#endif /* !MBCHAR */
+ } else
+ if (scc == (lc = cc))
+ ok++;
+ }
+ if (cc == 0)
+ bferr("Missing ]");
+ continue;
+
+ case '*':
+ if (!*p)
+ return (1);
+ for (s--; *s; s++)
+ if (Gmatch(s, p))
+ return (1);
+ return (0);
+
+ case 0:
+ return (scc == 0);
+
+ default:
+ if ((c & TRIM) != scc)
+ return (0);
+ continue;
+
+ case '?':
+ if (scc == 0)
+ return (0);
+ continue;
+
+ }
+ }
+}
+
+Gcat(s1, s2)
+ tchar *s1, *s2;
+{
+ register tchar *p, *q;
+ int n;
+
+#ifdef TRACE
+ tprintf("TRACE- Gcat()\n");
+#endif
+ for (p = s1; *p++; )
+ ;
+ for (q = s2; *q++; )
+ ;
+ gnleft -= (n = (p - s1) + (q - s2) - 1);
+ if (gnleft <= 0 || ++gargc >= GAVSIZ)
+ error("Arguments too long");
+ gargv[gargc] = 0;
+ p = gargv[gargc - 1] = (tchar *) xalloc((unsigned)n*sizeof (tchar));
+
+ for (q = s1; *p++ = *q++; )
+ ;
+ for (p--, q = s2; *p++ = *q++; )
+ ;
+}
+
+addpath(c)
+ tchar c;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- addpath()\n");
+#endif
+ if (gpathp >= lastgpathp)
+ error("Pathname too long");
+ *gpathp++ = c & TRIM;
+ *gpathp = 0;
+}
+
+rscan(t, f)
+ register tchar **t;
+ int (*f)();
+{
+ register tchar *p;
+
+#ifdef TRACE
+ tprintf("TRACE- rscan()\n");
+#endif
+ while (p = *t++)
+ while (*p)
+ (*f)(*p++);
+}
+
+trim(t)
+ register tchar **t;
+{
+ register tchar *p;
+
+#ifdef TRACE
+ tprintf("TRACE- trim()\n");
+#endif
+ while (p = *t++)
+ while (*p)
+ *p++ &= TRIM;
+}
+
+tglob(t)
+ register tchar **t;
+{
+ register tchar *p, c;
+
+#ifdef TRACE
+ tprintf("TRACE- tglob()\n");
+#endif
+ while (p = *t++) {
+ if (*p == '~')
+ gflag |= 2;
+ else if (*p == '{' && (p[1] == '\0' ||
+ p[1] == '}' && p[2] == '\0'))
+ continue;
+ while (c = *p++)
+ if (isglob(c))
+ gflag |= c == '{' ? 2 : 1;
+ }
+}
+
+tchar *
+globone(str)
+ register tchar *str;
+{
+ tchar *gv[2];
+ register tchar **gvp;
+ register tchar *cp;
+
+#ifdef TRACE
+ tprintf("TRACE- globone()\n");
+#endif
+ gv[0] = str;
+ gv[1] = 0;
+ gflag = 0;
+ tglob(gv);
+ if (gflag) {
+ gvp = glob(gv);
+ if (gvp == 0) {
+ setname(str);
+ bferr("No match");
+ }
+ cp = *gvp++;
+ if (cp == 0)
+ cp = S_ /* "" */;
+ else if (*gvp) {
+ setname(str);
+ bferr("Ambiguous");
+ } else
+ cp = strip(cp);
+/*
+ if (cp == 0 || *gvp) {
+ setname(str);
+ bferr(cp ? "Ambiguous" : "No output");
+ }
+*/
+ xfree((char *)gargv); gargv = 0;
+ } else {
+ trim(gv);
+ cp = savestr(gv[0]);
+ }
+ return (cp);
+}
+
+/*
+ * Command substitute cp. If literal, then this is
+ * a substitution from a << redirection, and so we should
+ * not crunch blanks and tabs, separating words only at newlines.
+ */
+tchar **
+dobackp(cp, literal)
+ tchar *cp;
+ bool literal;
+{
+ register tchar *lp, *rp;
+ tchar *ep;
+ tchar word[BUFSIZ];
+ tchar *apargv[GAVSIZ + 2];
+
+#ifdef TRACE
+ tprintf("TRACE- dobackp()\n");
+#endif
+ if (pargv) {
+ blkfree(pargv);
+ }
+ pargv = apargv;
+ pargv[0] = NOSTR;
+ pargcp = pargs = word;
+ pargc = 0;
+ pnleft = BUFSIZ - 4;
+ for (;;) {
+ for (lp = cp; *lp != '`'; lp++) {
+ if (*lp == 0) {
+ if (pargcp != pargs)
+ pword();
+#ifdef GDEBUG
+ printf("leaving dobackp\n");
+#endif
+ return (pargv = copyblk(pargv));
+ }
+ psave(*lp);
+ }
+ lp++;
+ for (rp = lp; *rp && *rp != '`'; rp++)
+ if (*rp == '\\') {
+ rp++;
+ if (!*rp)
+ goto oops;
+ }
+ if (!*rp)
+oops:
+ error("Unmatched `");
+ ep = savestr(lp);
+ ep[rp - lp] = 0;
+ backeval(ep, literal);
+#ifdef GDEBUG
+ printf("back from backeval\n");
+#endif
+ cp = rp + 1;
+ }
+}
+
+backeval(cp, literal)
+ tchar *cp;
+ bool literal;
+{
+ int pvec[2];
+ int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
+ tchar ibuf[BUFSIZ];
+ register int icnt = 0, c;
+ register tchar *ip;
+ bool hadnl = 0;
+ tchar *fakecom[2];
+ struct command faket;
+
+#ifdef TRACE
+ tprintf("TRACE- backeval()\n");
+#endif
+ faket.t_dtyp = TCOM;
+ faket.t_dflg = 0;
+ faket.t_dlef = 0;
+ faket.t_drit = 0;
+ faket.t_dspr = 0;
+ faket.t_dcom = fakecom;
+ fakecom[0] = S_QPPPQ; /* "` ... `" */;
+ fakecom[1] = 0;
+ /*
+ * We do the psave job to temporarily change the current job
+ * so that the following fork is considered a separate job.
+ * This is so that when backquotes are used in a
+ * builtin function that calls glob the "current job" is not corrupted.
+ * We only need one level of pushed jobs as long as we are sure to
+ * fork here.
+ */
+ psavejob();
+ /*
+ * It would be nicer if we could integrate this redirection more
+ * with the routines in sh.sem.c by doing a fake execute on a builtin
+ * function that was piped out.
+ */
+ mypipe(pvec);
+ if (pfork(&faket, -1) == 0) {
+ struct wordent paraml;
+ struct command *t;
+ tchar oHIST;
+
+ new_process();
+ (void) close(pvec[0]);
+ unsetfd(pvec[0]);
+ (void) dmove(pvec[1], 1);
+ (void) dmove(SHDIAG, 2);
+ reinitdesc(0, NULL);
+ arginp = cp;
+ while (*cp)
+ *cp++ &= TRIM;
+ /*
+ * disable history subsitution in sub-shell
+ * of `` evaluation prevents possible
+ * infinite recursion of `` evaluation
+ */
+ oHIST = HIST;
+ HIST = 0;
+ (void) lex(&paraml);
+ HIST = oHIST;
+ if (err)
+ error("%s", gettext(err));
+ alias(&paraml);
+ t = syntax(paraml.next, &paraml, 0);
+ if (err)
+ error("%s", gettext(err));
+ if (t)
+ t->t_dflg |= FPAR;
+ (void) signal(SIGTSTP, SIG_IGN);
+ (void) signal(SIGTTIN, SIG_IGN);
+ (void) signal(SIGTTOU, SIG_IGN);
+ execute(t, -1);
+ exitstat();
+ }
+ xfree(cp);
+ (void) close(pvec[1]);
+ unsetfd(pvec[1]);
+ do {
+ int cnt = 0;
+ for (;;) {
+ if (icnt == 0) {
+ ip = ibuf;
+ icnt = read_(pvec[0], ip, BUFSIZ);
+ if (icnt <= 0) {
+ c = -1;
+ break;
+ }
+ }
+ if (hadnl)
+ break;
+ --icnt;
+ c = (*ip++ & TRIM);
+ if (c == 0)
+ break;
+ if (c == '\n') {
+ /*
+ * Continue around the loop one
+ * more time, so that we can eat
+ * the last newline without terminating
+ * this word.
+ */
+ hadnl = 1;
+ continue;
+ }
+ if (!quoted && issp(c))
+ break;
+ cnt++;
+ psave(c | quoted);
+ }
+ /*
+ * Unless at end-of-file, we will form a new word
+ * here if there were characters in the word, or in
+ * any case when we take text literally. If
+ * we didn't make empty words here when literal was
+ * set then we would lose blank lines.
+ */
+ if (c != -1 && (cnt || literal)) {
+ if (pargc == GAVSIZ)
+ break;
+ pword();
+ }
+ hadnl = 0;
+ } while (c >= 0);
+#ifdef GDEBUG
+ printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
+ printf("also c = %c <%o>\n", (tchar) c, (tchar) c);
+#endif
+ (void) close(pvec[0]);
+ unsetfd(pvec[0]);
+ pwait();
+ prestjob();
+}
+
+psave(c)
+ tchar c;
+{
+#ifdef TRACE
+ tprintf("TRACE- psave()\n");
+#endif
+
+ if (--pnleft <= 0)
+ error("Word too long");
+ *pargcp++ = c;
+}
+
+pword()
+{
+#ifdef TRACE
+ tprintf("TRACE- pword()\n");
+#endif
+
+ psave(0);
+ if (pargc == GAVSIZ)
+ error("Too many words from ``");
+ pargv[pargc++] = savestr(pargs);
+ pargv[pargc] = NOSTR;
+#ifdef GDEBUG
+ printf("got word %t\n", pargv[pargc-1]);
+#endif
+ pargcp = pargs;
+ pnleft = BUFSIZ - 4;
+}
+
+
+
+/*
+ * returns pathname of the form dir/file;
+ * dir is a null-terminated string;
+ */
+char *
+makename(dir, file)
+ char *dir;
+ char *file;
+{
+ /*
+ * Maximum length of a
+ * file/dir name in ls-command;
+ * dfile is static as this is returned
+ * by makename();
+ */
+ static char dfile[MAXNAMLEN];
+
+ register char *dp, *fp;
+
+ dp = dfile;
+ fp = dir;
+ while (*fp)
+ *dp++ = *fp++;
+ if (dp > dfile && *(dp - 1) != '/')
+ *dp++ = '/';
+ fp = file;
+ while (*fp)
+ *dp++ = *fp++;
+ *dp = '\0';
+ /*
+ * dfile points to the absolute pathname. We are
+ * only interested in the last component.
+ */
+ return (rindex(dfile, '/') + 1);
+}
+
+sh_bracket_exp(t_ch, t_fch, t_lch)
+tchar t_ch;
+tchar t_fch;
+tchar t_lch;
+{
+ char t_char[MB_LEN_MAX + 1];
+ char t_patan[MB_LEN_MAX * 2 + 8];
+ char *p;
+ int i;
+
+ if ((t_ch == t_fch) || (t_ch == t_lch))
+ return(1);
+
+ p = t_patan;
+ if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0)
+ return(0);
+ t_char[i] = 0;
+
+ *p++ = '[';
+ if ((i = wctomb(p, (wchar_t)t_fch)) <= 0)
+ return(0);
+ p += i;
+ *p++ = '-';
+ if ((i = wctomb(p, (wchar_t)t_lch)) <= 0)
+ return(0);
+ p += i;
+ *p++ = ']';
+ *p = 0;
+
+ if (fnmatch(t_patan, t_char, FNM_NOESCAPE))
+ return(0);
+ return(1);
+}
diff --git a/usr/src/cmd/csh/sh.h b/usr/src/cmd/csh/sh.h
new file mode 100644
index 0000000000..72cebe7275
--- /dev/null
+++ b/usr/src/cmd/csh/sh.h
@@ -0,0 +1,627 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h> /* MB_xxx, mbxxx(), wcxxx() etc. */
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/siginfo.h>
+#include <sys/ucontext.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/termios.h>
+#include <sys/ttold.h>
+#include <errno.h>
+#include <signal.h> /* std sysV signal.h */
+#include <setjmp.h>
+#include <sys/resource.h>
+#include "signal.h" /* mainly BSD related signal.h */
+#include "sh.local.h"
+#include "sh.char.h"
+
+/*
+ * MAXHOSTNAMELEN is defined in param.h under SunOS
+ */
+#define MAXHOSTNAMELEN 64
+
+#ifdef MBCHAR
+# if !defined(MB_LEN_MAX) || !defined(MB_CUR_MAX)
+ Error: I need both ANSI macros!
+# endif
+#else
+# if !defined(MB_LEN_MAX)
+# define MB_LEN_MAX 1
+# endif
+# if !defined(MB_CUR_MAX)
+# define MB_CUR_MAX 1
+# endif
+#endif
+
+#ifndef MBCHAR /* Let's replace the ANSI functions with our own macro
+ * for efficiency!
+ */
+#define mbtowc(pwc, pmb, n_is_ignored) ((*(pwc)=*(pmb)), 1)
+#define wctomb(pmb, wc) ((*(pmb)=((char)wc)), 1)
+#endif/*!MBCHAR*/
+
+/*
+ * C shell
+ *
+ * Bill Joy, UC Berkeley
+ * October, 1978; May 1980
+ *
+ * Jim Kulp, IIASA, Laxenburg Austria
+ * April, 1980
+ */
+
+/*If we are setting the $cwd variable becuz we did a
+ cd, chdir, pushd, popd command, then set didchdir to
+ 1. This prevents globbing down when setting $cwd.
+ However, if the user set $cwd, we want the globbing
+ done; so, didchdir would be equal to 0 in that case.
+ */
+int didchdir;
+
+#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
+
+typedef char bool;
+
+/* tchar (Tagged CHARacter) is a place holder to keep a QUOTE bit and
+ * a character.
+ * For European language handling, lower 8 bits of tchar is used
+ * to store a character. For other languages, especially Asian, 16 bits
+ * are used to store a character.
+ * Following typedef's assume short int is a 16-bit entity and long int is
+ * a 32-bit entity.
+ * The QUOTE bit tells whether the character is subject to further
+ * interpretation such as history substitution, file mathing, command
+ * subsitution. TRIM is a mask to strip off the QUOTE bit.
+ */
+#ifdef MBCHAR /* For multibyte character handling. */
+typedef long int tchar;
+#define QUOTE 0x80000000
+#define TRIM 0x7fffffff
+#else/*!MBCHAR*/ /* European language requires only 8 bits. */
+typedef unsigned short int tchar;
+#define QUOTE 0x8000
+#define TRIM 0x00ff
+#endif/*!MBCHAR*/
+#define eq(a, b) (strcmp_(a, b) == 0)
+
+extern int Putchar(tchar);
+
+/*
+ * Global flags
+ */
+bool chkstop; /* Warned of stopped jobs... allow exit */
+bool didfds; /* Have setup i/o fd's for child */
+bool doneinp; /* EOF indicator after reset from readc */
+bool exiterr; /* Exit if error or non-zero exit status */
+bool child; /* Child shell ... errors cause exit */
+bool haderr; /* Reset was because of an error */
+bool intty; /* Input is a tty */
+bool cflg; /* invoked with -c option */
+bool intact; /* We are interactive... therefore prompt */
+bool justpr; /* Just print because of :p hist mod */
+bool loginsh; /* We are a loginsh -> .login/.logout */
+bool neednote; /* Need to pnotify() */
+bool noexec; /* Don't execute, just syntax check */
+bool pjobs; /* want to print jobs if interrupted */
+bool pfcshflag; /* set to 0 for pfcsh */
+bool setintr; /* Set interrupts on/off -> Wait intr... */
+bool timflg; /* Time the next waited for command */
+bool havhash; /* path hashing is available */
+bool havhash2; /* cdpath hashing is available */
+#ifdef FILEC
+bool filec; /* doing filename expansion */
+#endif
+
+/*
+ * Global i/o info
+ */
+tchar *arginp; /* Argument input for sh -c and internal `xx` */
+int onelflg; /* 2 -> need line for -t, 1 -> exit on read */
+tchar *file; /* Name of shell file for $0 */
+
+char *err; /* Error message from scanner/parser */
+struct timeval time0; /* Time at which the shell started */
+struct rusage ru0;
+
+/*
+ * Miscellany
+ */
+tchar *doldol; /* Character pid for $$ */
+int uid; /* Invokers uid */
+time_t chktim; /* Time mail last checked */
+int shpgrp; /* Pgrp of shell */
+int tpgrp; /* Terminal process group */
+/* If tpgrp is -1, leave tty alone! */
+int opgrp; /* Initial pgrp and tty pgrp */
+int oldisc; /* Initial line discipline or -1 */
+
+/*
+ * These are declared here because they want to be
+ * initialized in sh.init.c (to allow them to be made readonly)
+ */
+
+extern struct biltins {
+ tchar *bname;
+ int (*bfunct)();
+ short minargs, maxargs;
+} bfunc[];
+extern int nbfunc;
+
+extern struct srch {
+ tchar *s_name;
+ short s_value;
+} srchn[];
+extern int nsrchn;
+
+/*
+ * To be able to redirect i/o for builtins easily, the shell moves the i/o
+ * descriptors it uses away from 0,1,2.
+ * Ideally these should be in units which are closed across exec's
+ * (this saves work) but for version 6, this is not usually possible.
+ * The desired initial values for these descriptors are defined in
+ * sh.local.h.
+ */
+short SHIN; /* Current shell input (script) */
+short SHOUT; /* Shell output */
+short SHDIAG; /* Diagnostic output... shell errs go here */
+short OLDSTD; /* Old standard input (def for cmds) */
+
+/*
+ * Error control
+ *
+ * Errors in scanning and parsing set up an error message to be printed
+ * at the end and complete. Other errors always cause a reset.
+ * Because of source commands and .cshrc we need nested error catches.
+ */
+
+jmp_buf reslab;
+
+#define setexit() ((void) setjmp(reslab))
+#define reset() longjmp(reslab, 0)
+ /* Should use structure assignment here */
+#define getexit(a) copy((void *)(a), (void *)reslab, sizeof reslab)
+#define resexit(a) copy((void *)reslab, ((void *)(a)), sizeof reslab)
+
+tchar *gointr; /* Label for an onintr transfer */
+void (*parintr)(); /* Parents interrupt catch */
+void (*parterm)(); /* Parents terminate catch */
+
+
+/*
+ * Each level of input has a buffered input structure.
+ * There are one or more blocks of buffered input for each level,
+ * exactly one if the input is seekable and tell is available.
+ * In other cases, the shell buffers enough blocks to keep all loops
+ * in the buffer.
+ */
+struct Bin {
+ off_t Bfseekp; /* Seek pointer */
+ off_t Bfbobp; /* Seekp of beginning of buffers */
+ off_t Bfeobp; /* Seekp of end of buffers */
+ short Bfblocks; /* Number of buffer blocks */
+ tchar **Bfbuf; /* The array of buffer blocks */
+} B;
+
+#define fseekp B.Bfseekp
+#define fbobp B.Bfbobp
+#define feobp B.Bfeobp
+#define fblocks B.Bfblocks
+#define fbuf B.Bfbuf
+
+#define btell() fseekp
+
+#ifndef btell
+off_t btell();
+#endif
+
+/*
+ * The shell finds commands in loops by reseeking the input
+ * For whiles, in particular, it reseeks to the beginning of the
+ * line the while was on; hence the while placement restrictions.
+ */
+off_t lineloc;
+
+#ifdef TELL
+bool cantell; /* Is current source tellable ? */
+#endif
+
+/*
+ * Input lines are parsed into doubly linked circular
+ * lists of words of the following form.
+ */
+struct wordent {
+ tchar *word;
+ struct wordent *prev;
+ struct wordent *next;
+};
+
+/*
+ * During word building, both in the initial lexical phase and
+ * when expanding $ variable substitutions, expansion by `!' and `$'
+ * must be inhibited when reading ahead in routines which are themselves
+ * processing `!' and `$' expansion or after characters such as `\' or in
+ * quotations. The following flags are passed to the getC routines
+ * telling them which of these substitutions are appropriate for the
+ * next character to be returned.
+ */
+#define DODOL 1
+#define DOEXCL 2
+#define DOALL DODOL|DOEXCL
+
+/*
+ * Labuf implements a general buffer for lookahead during lexical operations.
+ * Text which is to be placed in the input stream can be stuck here.
+ * We stick parsed ahead $ constructs during initial input,
+ * process id's from `$$', and modified variable values (from qualifiers
+ * during expansion in sh.dol.c) here.
+ */
+tchar *labuf;
+
+tchar *lap;
+
+/*
+ * Parser structure
+ *
+ * Each command is parsed to a tree of command structures and
+ * flags are set bottom up during this process, to be propagated down
+ * as needed during the semantics/exeuction pass (sh.sem.c).
+ */
+struct command {
+ short t_dtyp; /* Type of node */
+ short t_dflg; /* Flags, e.g. FAND|... */
+ union {
+ tchar *T_dlef; /* Input redirect word */
+ struct command *T_dcar; /* Left part of list/pipe */
+ } L;
+ union {
+ tchar *T_drit; /* Output redirect word */
+ struct command *T_dcdr; /* Right part of list/pipe */
+ } R;
+#define t_dlef L.T_dlef
+#define t_dcar L.T_dcar
+#define t_drit R.T_drit
+#define t_dcdr R.T_dcdr
+ tchar **t_dcom; /* Command/argument vector */
+ char *cfname; /* char pathname for execv */
+ char **cargs; /* char arg vec for execv */
+ struct command *t_dspr; /* Pointer to ()'d subtree */
+ short t_nice;
+};
+
+#define TCOM 1 /* t_dcom <t_dlef >t_drit */
+#define TPAR 2 /* ( t_dspr ) <t_dlef >t_drit */
+#define TFIL 3 /* t_dlef | t_drit */
+#define TLST 4 /* t_dlef ; t_drit */
+#define TOR 5 /* t_dlef || t_drit */
+#define TAND 6 /* t_dlef && t_drit */
+
+#define FSAVE (FNICE|FTIME|FNOHUP) /* save these when re-doing */
+
+#define FAND (1<<0) /* executes in background */
+#define FCAT (1<<1) /* output is redirected >> */
+#define FPIN (1<<2) /* input is a pipe */
+#define FPOU (1<<3) /* output is a pipe */
+#define FPAR (1<<4) /* don't fork, last ()ized cmd */
+#define FINT (1<<5) /* should be immune from intr's */
+/* spare */
+#define FDIAG (1<<7) /* redirect unit 2 with unit 1 */
+#define FANY (1<<8) /* output was ! */
+#define FHERE (1<<9) /* input redirection is << */
+#define FREDO (1<<10) /* reexec aft if, repeat,... */
+#define FNICE (1<<11) /* t_nice is meaningful */
+#define FNOHUP (1<<12) /* nohup this command */
+#define FTIME (1<<13) /* time this command */
+
+/*
+ * The keywords for the parser
+ */
+#define ZBREAK 0
+#define ZBRKSW 1
+#define ZCASE 2
+#define ZDEFAULT 3
+#define ZELSE 4
+#define ZEND 5
+#define ZENDIF 6
+#define ZENDSW 7
+#define ZEXIT 8
+#define ZFOREACH 9
+#define ZGOTO 10
+#define ZIF 11
+#define ZLABEL 12
+#define ZLET 13
+#define ZSET 14
+#define ZSWITCH 15
+#define ZTEST 16
+#define ZTHEN 17
+#define ZWHILE 18
+
+/*
+ * Structure defining the existing while/foreach loops at this
+ * source level. Loops are implemented by seeking back in the
+ * input. For foreach (fe), the word list is attached here.
+ */
+struct whyle {
+ off_t w_start; /* Point to restart loop */
+ off_t w_end; /* End of loop (0 if unknown) */
+ tchar **w_fe, **w_fe0; /* Current/initial wordlist for fe */
+ tchar *w_fename; /* Name for fe */
+ struct whyle *w_next; /* Next (more outer) loop */
+} *whyles;
+
+/*
+ * Variable structure
+ *
+ * Aliases and variables are stored in AVL balanced binary trees.
+ */
+struct varent {
+ tchar **vec; /* Array of words which is the value */
+ tchar *v_name; /* Name of variable/alias */
+ struct varent *v_link[3]; /* The links, see below */
+ int v_bal; /* Balance factor */
+} shvhed, aliases;
+#define v_left v_link[0]
+#define v_right v_link[1]
+#define v_parent v_link[2]
+
+struct varent *adrof1();
+#define adrof(v) adrof1(v, &shvhed)
+#define value(v) value1(v, &shvhed)
+
+/*
+ * MAX_VAR_LEN - maximum variable name defined by csh man page to be 20
+ */
+#define MAX_VAR_LEN 20
+
+/*
+ * MAX_VREF_LEN - maximum variable reference $name[...]
+ * it can be as big as a csh word, which is 1024
+ */
+#define MAX_VREF_LEN 1024
+
+
+/*
+ * The following are for interfacing redo substitution in
+ * aliases to the lexical routines.
+ */
+struct wordent *alhistp; /* Argument list (first) */
+struct wordent *alhistt; /* Node after last in arg list */
+tchar **alvec; /* The (remnants of) alias vector */
+
+/*
+ * Filename/command name expansion variables
+ */
+short gflag; /* After tglob -> is globbing needed? */
+
+/*
+ * A reasonable limit on number of arguments would seem to be
+ * the maximum number of characters in an arg list / 6.
+ *
+ * XXX: With the new VM system, NCARGS has become enormous, making
+ * it impractical to allocate arrays with NCARGS / 6 entries on
+ * the stack. The proper fix is to revamp code elsewhere (in
+ * sh.dol.c and sh.glob.c) to use a different technique for handling
+ * command line arguments. In the meantime, we simply fall back
+ * on using the old value of NCARGS.
+ */
+#ifdef notyet
+#define GAVSIZ (NCARGS / 6)
+#else notyet
+#define GAVSIZ (10240 / 6)
+#endif notyet
+
+/*
+ * Variables for filename expansion
+ */
+tchar **gargv; /* Pointer to the (stack) arglist */
+long gargc; /* Number args in gargv */
+long gnleft;
+
+/*
+ * Variables for command expansion.
+ */
+tchar **pargv; /* Pointer to the argv list space */
+tchar *pargs; /* Pointer to start current word */
+long pargc; /* Count of arguments in pargv */
+long pnleft; /* Number of chars left in pargs */
+tchar *pargcp; /* Current index into pargs */
+
+/*
+ * History list
+ *
+ * Each history list entry contains an embedded wordlist
+ * from the scanner, a number for the event, and a reference count
+ * to aid in discarding old entries.
+ *
+ * Essentially "invisible" entries are put on the history list
+ * when history substitution includes modifiers, and thrown away
+ * at the next discarding since their event numbers are very negative.
+ */
+struct Hist {
+ struct wordent Hlex;
+ int Hnum;
+ int Href;
+ struct Hist *Hnext;
+} Histlist;
+
+struct wordent paraml; /* Current lexical word list */
+int eventno; /* Next events number */
+int lastev; /* Last event reference (default) */
+
+tchar HIST; /* history invocation character */
+tchar HISTSUB; /* auto-substitute character */
+
+/*
+ * In lines for frequently called functions
+ *
+ * WARNING: changes here also need to occur in the xfree() function in
+ * sh.misc.c.
+ */
+#if defined(sparc)
+#define XFREE(cp) { \
+ extern char end[]; \
+ char stack; \
+/*??*/ if (((char *)(cp)) >= end && ((char *)(cp)) < &stack) \
+/*??*/ free((void *)(cp)); \
+}
+#elif defined(i386)
+#define XFREE(cp) { \
+ extern char end[]; \
+ if (((char *)(cp)) >= end) \
+ free((void *)(cp)); \
+}
+#else
+#error XFREE macro is machine dependant and no machine type is recognized
+#endif
+void *alloctmp;
+#define xalloc(i) ((alloctmp = (void *)malloc(i)) ? alloctmp : (void *)nomem(i))/*??*/
+#define xrealloc(buf, i) ((alloctmp = (void *)realloc(buf, i)) ? alloctmp : \
+ (void *)nomem(i))
+
+tchar *Dfix1();
+tchar **blkcat();
+tchar **blkcpy();
+tchar **blkend();
+tchar **blkspl();
+char **blkspl_();
+void *malloc();
+tchar *cname();
+tchar **copyblk();
+tchar **dobackp();
+tchar *domod();
+struct wordent *dosub();
+tchar *exp3();
+tchar *exp3a();
+tchar *exp4();
+tchar *exp5();
+tchar *exp6();
+struct Hist *enthist();
+struct Hist *findev();
+struct wordent *freenod();
+char *getenv();
+tchar *getenv_(/* tchar * */);
+tchar *getenvs_(/* char * */);
+tchar *getinx();
+struct varent *getvx();
+struct passwd *getpwnam();
+struct wordent *gethent();
+struct wordent *getsub();
+char *getwd();
+tchar *getwd_();
+tchar **glob();
+tchar *globone();
+char *index();
+tchar *index_();
+struct biltins *isbfunc();
+off_t lseek();
+tchar *operate();
+void phup();
+void pintr();
+void pchild();
+tchar *putn();
+char *rindex();
+tchar *rindex_();
+tchar **saveblk();
+tchar *savestr();
+char *strcat();
+tchar *strcat_();
+int strlen_(tchar *);
+char *strcpy();
+tchar *strcpy_();
+tchar *strend();
+tchar *strip();
+tchar *strspl();
+tchar *subword();
+struct command *syntax();
+struct command *syn0();
+struct command *syn1();
+struct command *syn1a();
+struct command *syn1b();
+struct command *syn2();
+struct command *syn3();
+tchar *value1();
+tchar *xhome();
+tchar *xname();
+tchar *xset();
+
+#define NOSTR ((tchar *) 0)
+
+/*
+ * setname is a macro to copy the path in bname. (see sh.err.c)
+ * Here we are dynamically reallocating the bname to the new length
+ * to store the new path
+ */
+tchar *bname;
+#define setname(a) { \
+ bname = xrealloc(bname, (strlen_(a)+1) * sizeof (tchar)); \
+ strcpy_(bname, a); \
+ bname[strlen_(a)] = '\0'; \
+}
+
+#ifdef VFORK
+tchar *Vsav;
+tchar **Vav;
+tchar *Vdp;
+#endif
+
+tchar **evalvec;
+tchar *evalp;
+
+/* Conversion functions between char and tchar strings. */
+tchar *strtots(/* tchar * , char * */);
+char *tstostr(/* char * , tchar * */);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+
+/*
+ * Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
+ * to hash execs. If it is allocated (havhash true), then to tell
+ * whether ``name'' is (possibly) present in the i'th component
+ * of the variable path, you look at the bit in xhash indexed by
+ * hash(hashname("name"), i). This is setup automatically
+ * after .login is executed, and recomputed whenever ``path'' is
+ * changed.
+ * The two part hash function is designed to let texec() call the
+ * more expensive hashname() only once and the simple hash() several
+ * times (once for each path component checked).
+ * Byte size is assumed to be 8.
+ */
+#define HSHSIZ (32*1024) /* 4k bytes */
+#define HSHMASK (HSHSIZ - 1)
+#define HSHMUL 243
+
+/*
+ * The following two arrays are used for caching. xhash
+ * is for caching path variable and xhash2 is for cdpath
+ * variable.
+ */
+
+char xhash[HSHSIZ / 8];
+char xhash2[HSHSIZ / 8];
+#define hash(a, b) ((a) * HSHMUL + (b) & HSHMASK)
+#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
+#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
+#ifdef VFORK
+int hits, misses;
+#endif
+
+
diff --git a/usr/src/cmd/csh/sh.hist.c b/usr/src/cmd/csh/sh.hist.c
new file mode 100644
index 0000000000..a4418a95d4
--- /dev/null
+++ b/usr/src/cmd/csh/sh.hist.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+
+/*
+ * C shell
+ */
+
+savehist(sp)
+ struct wordent *sp;
+{
+ register struct Hist *hp, *np;
+ register int histlen = 0;
+ tchar *cp;
+
+#ifdef TRACE
+ tprintf("TRACE- savehist()\n");
+#endif
+ /* throw away null lines */
+ if (sp->next->word[0] == '\n')
+ return;
+ cp = value(S_history /*"history"*/);
+ if (*cp) {
+ register tchar *p = cp;
+
+ while (*p) {
+ if (!digit(*p)) {
+ histlen = 0;
+ break;
+ }
+ histlen = histlen * 10 + *p++ - '0';
+ }
+ }
+ for (hp = &Histlist; np = hp->Hnext;)
+ if (eventno - np->Href >= histlen || histlen == 0)
+ hp->Hnext = np->Hnext, hfree(np);
+ else
+ hp = np;
+ (void) enthist(++eventno, sp, 1);
+}
+
+struct Hist *
+enthist(event, lp, docopy)
+ int event;
+ register struct wordent *lp;
+ bool docopy;
+{
+ register struct Hist *np;
+
+#ifdef TRACE
+ tprintf("TRACE- enthist()\n");
+#endif
+ np = (struct Hist *) xalloc(sizeof *np);
+ np->Hnum = np->Href = event;
+ if (docopy)
+ copylex(&np->Hlex, lp);
+ else {
+ np->Hlex.next = lp->next;
+ lp->next->prev = &np->Hlex;
+ np->Hlex.prev = lp->prev;
+ lp->prev->next = &np->Hlex;
+ }
+ np->Hnext = Histlist.Hnext;
+ Histlist.Hnext = np;
+ return (np);
+}
+
+hfree(hp)
+ register struct Hist *hp;
+{
+#ifdef TRACE
+ tprintf("TRACE- hfree()\n");
+#endif
+
+ freelex(&hp->Hlex);
+ xfree( (tchar *)hp);
+}
+
+dohist(vp)
+ tchar **vp;
+{
+ int n, rflg = 0, hflg = 0;
+#ifdef TRACE
+ tprintf("TRACE- dohist()\n");
+#endif
+ if (getn(value(S_history /*"history"*/)) == 0)
+ return;
+ if (setintr)
+ (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
+ while (*++vp && **vp == '-') {
+ tchar *vp2 = *vp;
+
+ while (*++vp2)
+ switch (*vp2) {
+ case 'h':
+ hflg++;
+ break;
+ case 'r':
+ rflg++;
+ break;
+ case '-': /* ignore multiple '-'s */
+ break;
+ default:
+ printf("Unknown flag: -%c\n", *vp2);
+ error("Usage: history [-rh] [# number of events]");
+ }
+ }
+ if (*vp)
+ n = getn(*vp);
+ else {
+ n = getn(value(S_history /*"history"*/));
+ }
+ dohist1(Histlist.Hnext, &n, rflg, hflg);
+}
+
+dohist1(hp, np, rflg, hflg)
+ struct Hist *hp;
+ int *np, rflg, hflg;
+{
+ bool print = (*np) > 0;
+#ifdef TRACE
+ tprintf("TRACE- dohist1()\n");
+#endif
+top:
+ if (hp == 0)
+ return;
+ (*np)--;
+ hp->Href++;
+ if (rflg == 0) {
+ dohist1(hp->Hnext, np, rflg, hflg);
+ if (print)
+ phist(hp, hflg);
+ return;
+ }
+ if (*np >= 0)
+ phist(hp, hflg);
+ hp = hp->Hnext;
+ goto top;
+}
+
+phist(hp, hflg)
+ register struct Hist *hp;
+ int hflg;
+{
+#ifdef TRACE
+ tprintf("TRACE- phist()\n");
+#endif
+
+ if (hflg == 0)
+ printf("%6d\t", hp->Hnum);
+ prlex(&hp->Hlex);
+}
diff --git a/usr/src/cmd/csh/sh.init.c b/usr/src/cmd/csh/sh.init.c
new file mode 100644
index 0000000000..0f6d5e5c22
--- /dev/null
+++ b/usr/src/cmd/csh/sh.init.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+
+/*
+ * C shell
+ */
+
+extern int doalias();
+extern int dobg();
+extern int dobreak();
+extern int dochngd();
+extern int docontin();
+extern int dodirs();
+extern int doecho();
+extern int doelse();
+extern int doend();
+extern int doendif();
+extern int doendsw();
+extern int doeval();
+extern int doexit();
+extern int dofg();
+extern int doforeach();
+extern int doglob();
+extern int dogoto();
+extern int dohash();
+extern int dorehash();
+extern int dohist();
+extern int doif();
+extern int dojobs();
+extern int dokill();
+extern int dolet();
+extern int dolimit();
+extern int dologin();
+extern int dologout();
+#ifdef NEWGRP
+extern int donewgrp();
+#endif
+extern int donice();
+extern int donotify();
+extern int donohup();
+extern int doonintr();
+extern int dopopd();
+extern int dopushd();
+extern int dorepeat();
+extern int doset();
+extern int dosetenv();
+extern int dosource();
+extern int dostop();
+extern int dosuspend();
+extern int doswbrk();
+extern int doswitch();
+extern int dotime();
+extern int dounlimit();
+extern int doumask();
+extern int dowait();
+extern int dowhile();
+extern int dozip();
+extern int execash();
+extern int goodbye();
+#ifdef VFORK
+extern int hashstat();
+#endif
+extern int shift();
+#ifdef OLDMALLOC
+extern int showall();
+#endif
+extern int unalias();
+extern int dounhash();
+extern int unset();
+extern int dounsetenv();
+
+#define INF 1000
+
+struct biltins bfunc[] = {
+ S_AT, dolet, 0, INF,
+ S_alias, doalias, 0, INF,
+#ifdef OLDMALLOC
+ S_alloc, showall, 0, 1,
+#endif
+ S_bg, dobg, 0, INF,
+ S_break, dobreak, 0, 0,
+ S_breaksw, doswbrk, 0, 0,
+#ifdef IIASA
+ S_bye, goodbye, 0, 0,
+#endif
+ S_case, dozip, 0, 1,
+ S_cd, dochngd, 0, 1,
+ S_chdir, dochngd, 0, 1,
+ S_continue, docontin, 0, 0,
+ S_default, dozip, 0, 0,
+ S_dirs, dodirs, 0, 1,
+ S_echo, doecho, 0, INF,
+ S_else, doelse, 0, INF,
+ S_end, doend, 0, 0,
+ S_endif, dozip, 0, 0,
+ S_endsw, dozip, 0, 0,
+ S_eval, doeval, 0, INF,
+ S_exec, execash, 1, INF,
+ S_exit, doexit, 0, INF,
+ S_fg, dofg, 0, INF,
+ S_foreach, doforeach, 3, INF,
+#ifdef IIASA
+ S_gd, dopushd, 0, 1,
+#endif
+ S_glob, doglob, 0, INF,
+ S_goto, dogoto, 1, 1,
+#ifdef VFORK
+ S_hashstat, hashstat, 0, 0,
+#endif
+ S_history, dohist, 0, 2,
+ S_if, doif, 1, INF,
+ S_jobs, dojobs, 0, 1,
+ S_kill, dokill, 1, INF,
+ S_limit, dolimit, 0, 3,
+ S_login, dologin, 0, 1,
+ S_logout, dologout, 0, 0,
+#ifdef NEWGRP
+ S_newgrp, donewgrp, 1, 1,
+#endif
+ S_nice, donice, 0, INF,
+ S_nohup, donohup, 0, INF,
+ S_notify, donotify, 0, INF,
+ S_onintr, doonintr, 0, 2,
+ S_popd, dopopd, 0, 1,
+ S_pushd, dopushd, 0, 1,
+#ifdef IIASA
+ S_rd, dopopd, 0, 1,
+#endif
+ S_rehash, dorehash, 0, 0,
+ S_repeat, dorepeat, 2, INF,
+ S_set, doset, 0, INF,
+ S_setenv, dosetenv, 0, 2,
+ S_shift, shift, 0, 1,
+ S_source, dosource, 1, 2,
+ S_stop, dostop, 1, INF,
+ S_suspend, dosuspend, 0, 0,
+ S_switch, doswitch, 1, INF,
+ S_time, dotime, 0, INF,
+ S_umask, doumask, 0, 1,
+ S_unalias, unalias, 1, INF,
+ S_unhash, dounhash, 0, 0,
+ S_unlimit, dounlimit, 0, INF,
+ S_unset, unset, 1, INF,
+ S_unsetenv, dounsetenv, 1, INF,
+ S_wait, dowait, 0, 0,
+ S_while, dowhile, 1, INF,
+};
+int nbfunc = sizeof bfunc / sizeof *bfunc;
+
+#define ZBREAK 0
+#define ZBRKSW 1
+#define ZCASE 2
+#define ZDEFAULT 3
+#define ZELSE 4
+#define ZEND 5
+#define ZENDIF 6
+#define ZENDSW 7
+#define ZEXIT 8
+#define ZFOREACH 9
+#define ZGOTO 10
+#define ZIF 11
+#define ZLABEL 12
+#define ZLET 13
+#define ZSET 14
+#define ZSWITCH 15
+#define ZTEST 16
+#define ZTHEN 17
+#define ZWHILE 18
+
+struct srch srchn[] = {
+ S_AT, ZLET,
+ S_break, ZBREAK,
+ S_breaksw, ZBRKSW,
+ S_case, ZCASE,
+ S_default, ZDEFAULT,
+ S_else, ZELSE,
+ S_end, ZEND,
+ S_endif, ZENDIF,
+ S_endsw, ZENDSW,
+ S_exit, ZEXIT,
+ S_foreach, ZFOREACH,
+ S_goto, ZGOTO,
+ S_if, ZIF,
+ S_label, ZLABEL,
+ S_set, ZSET,
+ S_switch, ZSWITCH,
+ S_while, ZWHILE
+};
+int nsrchn = sizeof srchn / sizeof *srchn;
+
diff --git a/usr/src/cmd/csh/sh.lex.c b/usr/src/cmd/csh/sh.lex.c
new file mode 100644
index 0000000000..4a743e8e65
--- /dev/null
+++ b/usr/src/cmd/csh/sh.lex.c
@@ -0,0 +1,1429 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h> /* for lseek prototype */
+#include "sh.h"
+#include "sh.tconst.h"
+#include <sys/filio.h>
+#include <sys/ttold.h>
+#define RAW O_RAW
+/*
+ * C shell
+ */
+
+/*
+ * These lexical routines read input and form lists of words.
+ * There is some involved processing here, because of the complications
+ * of input buffering, and especially because of history substitution.
+ */
+
+tchar *word();
+
+/*
+ * Peekc is a peek characer for getC, peekread for readc.
+ * There is a subtlety here in many places... history routines
+ * will read ahead and then insert stuff into the input stream.
+ * If they push back a character then they must push it behind
+ * the text substituted by the history substitution. On the other
+ * hand in several places we need 2 peek characters. To make this
+ * all work, the history routines read with getC, and make use both
+ * of ungetC and unreadc. The key observation is that the state
+ * of getC at the call of a history reference is such that calls
+ * to getC from the history routines will always yield calls of
+ * readc, unless this peeking is involved. That is to say that during
+ * getexcl the variables lap, exclp, and exclnxt are all zero.
+ *
+ * Getdol invokes history substitution, hence the extra peek, peekd,
+ * which it can ungetD to be before history substitutions.
+ */
+tchar peekc, peekd;
+tchar peekread;
+
+tchar *exclp; /* (Tail of) current word from ! subst */
+struct wordent *exclnxt; /* The rest of the ! subst words */
+int exclc; /* Count of remainig words in ! subst */
+tchar *alvecp; /* "Globp" for alias resubstitution */
+
+/*
+ * Lex returns to its caller not only a wordlist (as a "var" parameter)
+ * but also whether a history substitution occurred. This is used in
+ * the main (process) routine to determine whether to echo, and also
+ * when called by the alias routine to determine whether to keep the
+ * argument list.
+ */
+bool hadhist;
+
+tchar getCtmp;
+#define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
+#define ungetC(c) peekc = c
+#define ungetD(c) peekd = c
+
+lex(hp)
+ register struct wordent *hp;
+{
+ register struct wordent *wdp;
+ int c;
+
+#ifdef TRACE
+ tprintf("TRACE- lex()\n");
+#endif
+ lineloc = btell();
+ hp->next = hp->prev = hp;
+ hp->word = S_ /*""*/;
+ alvecp = 0, hadhist = 0;
+ do
+ c = readc(0);
+ while (issp(c));
+ /* make sure history is enabled */
+ if (HIST && c == HISTSUB && intty)
+ /* ^lef^rit from tty is short !:s^lef^rit */
+ getexcl(c);
+ else
+ unreadc(c);
+ wdp = hp;
+ /*
+ * The following loop is written so that the links needed
+ * by freelex will be ready and rarin to go even if it is
+ * interrupted.
+ */
+ do {
+ register struct wordent *new = (struct wordent *) xalloc(sizeof *wdp);
+
+ new->word = 0;
+ new->prev = wdp;
+ new->next = hp;
+ wdp->next = new;
+ wdp = new;
+ wdp->word = word();
+ } while (wdp->word[0] != '\n');
+#ifdef TRACE
+ tprintf("Exiting lex()\n");
+#endif
+ hp->prev = wdp;
+ return (hadhist);
+}
+
+prlex(sp0)
+ struct wordent *sp0;
+{
+ register struct wordent *sp = sp0->next;
+
+#ifdef TRACE
+ tprintf("TRACE- prlex()\n");
+#endif
+ for (;;) {
+ printf("%t", sp->word);
+ sp = sp->next;
+ if (sp == sp0)
+ break;
+ if (sp->word[0] != '\n')
+ Putchar(' ');
+ }
+}
+
+copylex(hp, fp)
+ register struct wordent *hp;
+ register struct wordent *fp;
+{
+ register struct wordent *wdp;
+
+#ifdef TRACE
+ tprintf("TRACE- copylex()\n");
+#endif
+ wdp = hp;
+ fp = fp->next;
+ do {
+ register struct wordent *new = (struct wordent *) xalloc(sizeof *wdp);
+
+ new->prev = wdp;
+ new->next = hp;
+ wdp->next = new;
+ wdp = new;
+ wdp->word = savestr(fp->word);
+ fp = fp->next;
+ } while (wdp->word[0] != '\n');
+ hp->prev = wdp;
+}
+
+freelex(vp)
+ register struct wordent *vp;
+{
+ register struct wordent *fp;
+
+#ifdef TRACE
+ tprintf("TRACE- freelex()\n");
+#endif
+ while (vp->next != vp) {
+ fp = vp->next;
+ vp->next = fp->next;
+ XFREE(fp->word)
+ XFREE( (char *)fp)
+ }
+ vp->prev = vp;
+}
+
+tchar *
+word()
+{
+ register tchar c, c1;
+ register tchar *wp;
+ tchar wbuf[BUFSIZ];
+ register bool dolflg;
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- word()\n");
+#endif
+ wp = wbuf;
+ i = BUFSIZ - 4;
+loop:
+ while (issp(c = getC(DOALL)))
+ ;
+ if (cmap(c, _META|_ESC)||isauxsp(c))
+ switch (c) {
+ case '&':
+ case '|':
+ case '<':
+ case '>':
+ *wp++ = c;
+ c1 = getC(DOALL);
+ if (c1 == c)
+ *wp++ = c1;
+ else
+ ungetC(c1);
+ goto ret;
+
+ case '#':
+ if (intty)
+ break;
+ c = 0;
+ do {
+ c1 = c;
+ c = getC(0);
+ } while (c != '\n');
+ if (c1 == '\\')
+ goto loop;
+ /* fall into ... */
+
+ case ';':
+ case '(':
+ case ')':
+ case '\n':
+ *wp++ = c;
+ goto ret;
+
+ case '\\':
+ c = getC(0);
+ if (c == '\n') {
+ if (onelflg == 1)
+ onelflg = 2;
+ goto loop;
+ }
+ if (c != HIST)
+ *wp++ = '\\', --i;
+ c |= QUOTE;
+ }
+ c1 = 0;
+ dolflg = DOALL;
+ for (;;) {
+ if (c1) {
+ if (c == c1) {
+ c1 = 0;
+ dolflg = DOALL;
+ } else if (c == '\\') {
+ c = getC(0);
+ if (c == HIST)
+ c |= QUOTE;
+ else {
+ if (c == '\n')
+ /*
+ if (c1 == '`')
+ c = ' ';
+ else
+ */
+ c |= QUOTE;
+ ungetC(c);
+ c = '\\';
+ }
+ } else if (c == '\n') {
+ seterrc(gettext("Unmatched "), c1);
+ ungetC(c);
+ break;
+ }
+ } else if (cmap(c, _META|_Q|_Q1|_ESC)||isauxsp(c)) {
+ if (c == '\\') {
+ c = getC(0);
+ if (c == '\n') {
+ if (onelflg == 1)
+ onelflg = 2;
+ break;
+ }
+ if (c != HIST)
+ *wp++ = '\\', --i;
+ c |= QUOTE;
+ } else if (cmap(c, _Q|_Q1)) { /* '"` */
+ c1 = c;
+ dolflg = c == '"' ? DOALL : DOEXCL;
+ } else if (c != '#' || !intty) {
+ ungetC(c);
+ break;
+ }
+ }
+ if (--i > 0) {
+ *wp++ = c;
+ c = getC(dolflg);
+ } else {
+ seterr("Word too long");
+ wp = &wbuf[1];
+ break;
+ }
+ }
+ret:
+ *wp = 0;
+#ifdef TRACE
+ tprintf("word() returning:%t\n", wbuf);
+#endif
+ return (savestr(wbuf));
+}
+
+getC1(flag)
+ register int flag;
+{
+ register tchar c;
+
+top:
+ if (c = peekc) {
+ peekc = 0;
+ return (c);
+ }
+ if (lap) {
+ if ((c = *lap++) == 0)
+ lap = 0;
+ else {
+ /*
+ * don't quote things if there was an error (err!=0)
+ * the input is original, not from a substitution and
+ * therefore should not be quoted
+ */
+ if (!err && cmap(c, _META|_Q|_Q1)||isauxsp(c))
+ c |= QUOTE;
+ return (c);
+ }
+ }
+ if (c = peekd) {
+ peekd = 0;
+ return (c);
+ }
+ if (exclp) {
+ if (c = *exclp++)
+ return (c);
+ if (exclnxt && --exclc >= 0) {
+ exclnxt = exclnxt->next;
+ setexclp(exclnxt->word);
+ return (' ');
+ }
+ exclp = 0;
+ exclnxt = 0;
+ }
+ if (exclnxt) {
+ exclnxt = exclnxt->next;
+ if (--exclc < 0)
+ exclnxt = 0;
+ else
+ setexclp(exclnxt->word);
+ goto top;
+ }
+ c = readc(0);
+ if (c == '$' && (flag & DODOL)) {
+ getdol();
+ goto top;
+ }
+ if (c == HIST && (flag & DOEXCL)) {
+ getexcl(0);
+ goto top;
+ }
+ return (c);
+}
+
+getdol()
+{
+ register tchar *np, *p;
+ tchar name[MAX_VREF_LEN];
+ register int c;
+ int sc;
+ bool special = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- getdol()\n");
+#endif
+ np = name, *np++ = '$';
+ c = sc = getC(DOEXCL);
+ if (isspnl(c)) {
+ ungetD(c);
+ ungetC('$' | QUOTE);
+ return;
+ }
+ if (c == '{')
+ *np++ = c, c = getC(DOEXCL);
+ if (c == '#' || c == '?')
+ special++, *np++ = c, c = getC(DOEXCL);
+ *np++ = c;
+ switch (c) {
+
+ case '<':
+ case '$':
+ case '*':
+ if (special)
+ goto vsyn;
+ goto ret;
+
+ case '\n':
+ ungetD(c);
+ np--;
+ goto vsyn;
+
+ default:
+ p = np;
+ if (digit(c)) {
+ /* make sure the variable names are MAX_VAR_LEN chars or less */
+ while (digit(c = getC(DOEXCL)) && (np-p) < MAX_VAR_LEN) {
+ *np++ = c;
+ }
+ } else if (letter(c)) {
+ while ((letter(c = getC(DOEXCL)) || digit(c)) &&
+ (np-p) < MAX_VAR_LEN ) {
+ *np++ = c;
+ }
+ }
+ else
+ goto vsyn;
+
+ if( (np - p) > MAX_VAR_LEN )
+ {
+ seterr("Variable name too long");
+ goto ret;
+ }
+ }
+ if (c == '[') {
+ *np++ = c;
+ do {
+ c = getC(DOEXCL);
+ if (c == '\n') {
+ ungetD(c);
+ np--;
+ goto vsyn;
+ }
+ /* need to leave space for possible modifiers */
+ if (np >= &name[MAX_VREF_LEN - 8])
+ {
+ seterr("Variable reference too long");
+ goto ret;
+ }
+ *np++ = c;
+ } while (c != ']');
+ c = getC(DOEXCL);
+ }
+ if (c == ':') {
+ *np++ = c, c = getC(DOEXCL);
+ if (c == 'g')
+ *np++ = c, c = getC(DOEXCL);
+ *np++ = c;
+ if (!any(c, S_htrqxe))
+ goto vsyn;
+ } else
+ ungetD(c);
+ if (sc == '{') {
+ c = getC(DOEXCL);
+ if (c != '}') {
+ ungetC(c);
+ goto vsyn;
+ }
+ *np++ = c;
+ }
+ret:
+ *np = 0;
+ addla(name);
+ return;
+
+vsyn:
+ seterr("Variable syntax");
+ goto ret;
+}
+
+addla(cp)
+ tchar *cp;
+{
+ tchar *buf;
+ int len = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- addla()\n");
+#endif
+ if (lap) {
+ len = strlen_(lap);
+ buf = xalloc((len+1) * sizeof (tchar));
+ (void) strcpy_(buf, lap);
+ }
+ len += strlen_(cp);
+
+ /* len+5 is allow 4 additional charecters just to be safe */
+ labuf = xrealloc(labuf, (len+5) * sizeof (tchar));
+ (void) strcpy_(labuf, cp);
+ if (lap) {
+ (void) strcat_(labuf, buf);
+ free(buf);
+ }
+ lap = labuf;
+}
+
+tchar lhsb[32];
+tchar slhs[32];
+tchar rhsb[64];
+int quesarg;
+
+getexcl(sc)
+ tchar sc;
+{
+ register struct wordent *hp, *ip;
+ int left, right, dol;
+ register int c;
+
+#ifdef TRACE
+ tprintf("TRACE- getexcl()\n");
+#endif
+ if (sc == 0) {
+ sc = getC(0);
+ if (sc != '{') {
+ ungetC(sc);
+ sc = 0;
+ }
+ }
+ quesarg = -1;
+ lastev = eventno;
+ hp = gethent(sc);
+ if (hp == 0)
+ return;
+ hadhist = 1;
+ dol = 0;
+ if (hp == alhistp)
+ for (ip = hp->next->next; ip != alhistt; ip = ip->next)
+ dol++;
+ else
+ for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
+ dol++;
+ left = 0, right = dol;
+ if (sc == HISTSUB) {
+ ungetC('s'), unreadc(HISTSUB), c = ':';
+ goto subst;
+ }
+ c = getC(0);
+ /* if (!any(c, ":^$*-%")) */ /* change needed for char -> tchar */
+ if (! (c == ':' || c == '^' || c == '$' || c == '*' ||
+ c == '-' || c == '%' ))
+ goto subst;
+ left = right = -1;
+ if (c == ':') {
+ c = getC(0);
+ unreadc(c);
+ if (letter(c) || c == '&') {
+ c = ':';
+ left = 0, right = dol;
+ goto subst;
+ }
+ } else
+ ungetC(c);
+ if (!getsel(&left, &right, dol))
+ return;
+ c = getC(0);
+ if (c == '*')
+ ungetC(c), c = '-';
+ if (c == '-') {
+ if (!getsel(&left, &right, dol))
+ return;
+ c = getC(0);
+ }
+subst:
+ exclc = right - left + 1;
+ while (--left >= 0)
+ hp = hp->next;
+ if (sc == HISTSUB || c == ':') {
+ do {
+ hp = getsub(hp);
+ c = getC(0);
+ } while (c == ':');
+ }
+ unreadc(c);
+ if (sc == '{') {
+ c = getC(0);
+ if (c != '}')
+ seterr("Bad ! form");
+ }
+ exclnxt = hp;
+}
+
+struct wordent *
+getsub(en)
+ struct wordent *en;
+{
+ register tchar *cp;
+ int delim;
+ register int c;
+ int sc;
+ bool global = 0;
+ tchar orhsb[(sizeof rhsb)/(sizeof rhsb[0])];
+
+#ifdef TRACE
+ tprintf("TRACE- getsub()\n");
+#endif
+ exclnxt = 0;
+ sc = c = getC(0);
+ if (c == 'g')
+ global++, c = getC(0);
+ switch (c) {
+
+ case 'p':
+ justpr++;
+ goto ret;
+
+ case 'x':
+ case 'q':
+ global++;
+ /* fall into ... */
+
+ case 'h':
+ case 'r':
+ case 't':
+ case 'e':
+ break;
+
+ case '&':
+ if (slhs[0] == 0) {
+ seterr("No prev sub");
+ goto ret;
+ }
+ (void) strcpy_(lhsb, slhs);
+ break;
+
+/*
+ case '~':
+ if (lhsb[0] == 0)
+ goto badlhs;
+ break;
+*/
+
+ case 's':
+ delim = getC(0);
+ if (alnum(delim) || isspnl(delim)){
+ unreadc(delim);
+bads:
+ lhsb[0] = 0;
+ seterr("Bad substitute");
+ goto ret;
+ }
+ cp = lhsb;
+ for (;;) {
+ c = getC(0);
+ if (c == '\n') {
+ unreadc(c);
+ break;
+ }
+ if (c == delim)
+ break;
+ if (cp > &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
+ goto bads;
+ if (c == '\\') {
+ c = getC(0);
+ if (c != delim && c != '\\')
+ *cp++ = '\\';
+ }
+ *cp++ = c;
+ }
+ if (cp != lhsb)
+ *cp++ = 0;
+ else if (lhsb[0] == 0) {
+/*badlhs:*/
+ seterr("No prev lhs");
+ goto ret;
+ }
+ cp = rhsb;
+ (void) strcpy_(orhsb, cp);
+ for (;;) {
+ c = getC(0);
+ if (c == '\n') {
+ unreadc(c);
+ break;
+ }
+ if (c == delim)
+ break;
+/*
+ if (c == '~') {
+ if (&cp[strlen_(orhsb)]
+ > &rhsb[(sizeof rhsb)/(sizeof rhsb[0]) - 2])
+ goto toorhs;
+ (void) strcpy_(cp, orhsb);
+ cp = strend(cp);
+ continue;
+ }
+*/
+ if (cp > &rhsb[(sizeof rhsb)/(sizeof rhsb[0]) - 2]) {
+/*toorhs:*/
+ seterr("Rhs too long");
+ goto ret;
+ }
+ if (c == '\\') {
+ c = getC(0);
+ if (c != delim /* && c != '~' */)
+ *cp++ = '\\';
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ break;
+
+ default:
+ if (c == '\n')
+ unreadc(c);
+ seterrc(gettext("Bad ! modifier: "), c);
+ goto ret;
+ }
+ (void) strcpy_(slhs, lhsb);
+ if (exclc)
+ en = dosub(sc, en, global);
+ret:
+ return (en);
+}
+
+struct wordent *
+dosub(sc, en, global)
+ int sc;
+ struct wordent *en;
+ bool global;
+{
+ struct wordent lex;
+ bool didsub = 0;
+ struct wordent *hp = &lex;
+ register struct wordent *wdp;
+ register int i = exclc;
+
+#ifdef TRACE
+ tprintf("TRACE- dosub()\n");
+#endif
+ wdp = hp;
+ while (--i >= 0) {
+ register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
+
+ new->prev = wdp;
+ new->next = hp;
+ wdp->next = new;
+ wdp = new;
+ en = en->next;
+ wdp->word = global || didsub == 0 ?
+ subword(en->word, sc, &didsub) : savestr(en->word);
+ }
+ if (didsub == 0)
+ seterr("Modifier failed");
+ hp->prev = wdp;
+ return (&enthist(-1000, &lex, 0)->Hlex);
+}
+
+tchar *
+subword(cp, type, adid)
+ tchar *cp;
+ int type;
+ bool *adid;
+{
+ tchar wbuf[BUFSIZ];
+ register tchar *wp, *mp, *np;
+ register int i;
+
+#ifdef TRACE
+ tprintf("TRACE- subword()\n");
+#endif
+ switch (type) {
+
+ case 'r':
+ case 'e':
+ case 'h':
+ case 't':
+ case 'q':
+ case 'x':
+ wp = domod(cp, type);
+ if (wp == 0)
+ return (savestr(cp));
+ *adid = 1;
+ return (wp);
+
+ default:
+ wp = wbuf;
+ i = BUFSIZ - 4;
+ for (mp = cp; *mp; mp++)
+ if (matchs(mp, lhsb)) {
+ for (np = cp; np < mp;)
+ *wp++ = *np++, --i;
+ for (np = rhsb; *np; np++) switch (*np) {
+
+ case '\\':
+ if (np[1] == '&')
+ np++;
+ /* fall into ... */
+
+ default:
+ if (--i < 0)
+ goto ovflo;
+ *wp++ = *np;
+ continue;
+
+ case '&':
+ i -= strlen_(lhsb);
+ if (i < 0)
+ goto ovflo;
+ *wp = 0;
+ (void) strcat_(wp, lhsb);
+ wp = strend(wp);
+ continue;
+ }
+ mp += strlen_(lhsb);
+ i -= strlen_(mp);
+ if (i < 0) {
+ovflo:
+ seterr("Subst buf ovflo");
+ return (S_ /*""*/);
+ }
+ *wp = 0;
+ (void) strcat_(wp, mp);
+ *adid = 1;
+ return (savestr(wbuf));
+ }
+ return (savestr(cp));
+ }
+}
+
+tchar *
+domod(cp, type)
+ tchar *cp;
+ int type;
+{
+ register tchar *wp, *xp;
+ register int c;
+
+#ifdef TRACE
+ tprintf("TRACE- domod()\n");
+#endif
+ switch (type) {
+
+ case 'x':
+ case 'q':
+ wp = savestr(cp);
+ for (xp = wp; c = *xp; xp++)
+ if (!issp(c) || type == 'q')
+ *xp |= QUOTE;
+ return (wp);
+
+ case 'h':
+ case 't':
+ if (!any('/', cp))
+ return (type == 't' ? savestr(cp) : 0);
+ wp = strend(cp);
+ while (*--wp != '/')
+ continue;
+ if (type == 'h')
+ xp = savestr(cp), xp[wp - cp] = 0;
+ else
+ xp = savestr(wp + 1);
+ return (xp);
+
+ case 'e':
+ case 'r':
+ wp = strend(cp);
+ for (wp--; wp >= cp && *wp != '/'; wp--)
+ if (*wp == '.') {
+ if (type == 'e')
+ xp = savestr(wp + 1);
+ else
+ xp = savestr(cp), xp[wp - cp] = 0;
+ return (xp);
+ }
+ return (savestr(type == 'e' ? S_ /*""*/ : cp));
+ }
+ return (0);
+}
+
+matchs(str, pat)
+ register tchar *str, *pat;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- matchs()\n");
+#endif
+ while (*str && *pat && *str == *pat)
+ str++, pat++;
+ return (*pat == 0);
+}
+
+getsel(al, ar, dol)
+ register int *al, *ar;
+ int dol;
+{
+ register int c = getC(0);
+ register int i;
+ bool first = *al < 0;
+
+#ifdef TRACE
+ tprintf("TRACE- getsel()\n");
+#endif
+ switch (c) {
+
+ case '%':
+ if (quesarg == -1)
+ goto bad;
+ if (*al < 0)
+ *al = quesarg;
+ *ar = quesarg;
+ break;
+
+ case '-':
+ if (*al < 0) {
+ *al = 0;
+ *ar = dol - 1;
+ unreadc(c);
+ }
+ return (1);
+
+ case '^':
+ if (*al < 0)
+ *al = 1;
+ *ar = 1;
+ break;
+
+ case '$':
+ if (*al < 0)
+ *al = dol;
+ *ar = dol;
+ break;
+
+ case '*':
+ if (*al < 0)
+ *al = 1;
+ *ar = dol;
+ if (*ar < *al) {
+ *ar = 0;
+ *al = 1;
+ return (1);
+ }
+ break;
+
+ default:
+ if (digit(c)) {
+ i = 0;
+ while (digit(c)) {
+ i = i * 10 + c - '0';
+ c = getC(0);
+ }
+ if (i < 0)
+ i = dol + 1;
+ if (*al < 0)
+ *al = i;
+ *ar = i;
+ } else
+ if (*al < 0)
+ *al = 0, *ar = dol;
+ else
+ *ar = dol - 1;
+ unreadc(c);
+ break;
+ }
+ if (first) {
+ c = getC(0);
+ unreadc(c);
+ /* if (any(c, "-$*")) */ /* char -> tchar */
+ if (c == '-' || c == '$' || c == '*')
+ return (1);
+ }
+ if (*al > *ar || *ar > dol) {
+bad:
+ seterr("Bad ! arg selector");
+ return (0);
+ }
+ return (1);
+
+}
+
+struct wordent *
+gethent(sc)
+ int sc;
+{
+ register struct Hist *hp;
+ register tchar *np;
+ register int c;
+ int event;
+ bool back = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- gethent()\n");
+#endif
+ c = sc == HISTSUB ? HIST : getC(0);
+ if (c == HIST) {
+ if (alhistp)
+ return (alhistp);
+ event = eventno;
+ goto skip;
+ }
+ switch (c) {
+
+ case ':':
+ case '^':
+ case '$':
+ case '*':
+ case '%':
+ ungetC(c);
+ if (lastev == eventno && alhistp)
+ return (alhistp);
+ event = lastev;
+ break;
+
+ case '-':
+ back = 1;
+ c = getC(0);
+ goto number;
+
+ case '#': /* !# is command being typed in (mrh) */
+ return(&paraml);
+
+ default:
+ /*if (any(c, "(=~")) {*/
+ if (c == '(' || c == '=' || c == '~') {
+ unreadc(c);
+ ungetC(HIST);
+ return (0);
+ }
+ if (digit(c))
+ goto number;
+ np = lhsb;
+ /* while (!any(c, ": \t\\\n}")) { */
+ while (! (c == ':' || c == '\\' || isspnl(c) || c == '}')) {
+ if (np < &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
+ *np++ = c;
+ c = getC(0);
+ }
+ unreadc(c);
+ if (np == lhsb) {
+ ungetC(HIST);
+ return (0);
+ }
+ *np++ = 0;
+ hp = findev(lhsb, 0);
+ if (hp)
+ lastev = hp->Hnum;
+ return (&hp->Hlex);
+
+ case '?':
+ np = lhsb;
+ for (;;) {
+ c = getC(0);
+ if (c == '\n') {
+ unreadc(c);
+ break;
+ }
+ if (c == '?')
+ break;
+ if (np < &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
+ *np++ = c;
+ }
+ if (np == lhsb) {
+ if (lhsb[0] == 0) {
+ seterr("No prev search");
+ return (0);
+ }
+ } else
+ *np++ = 0;
+ hp = findev(lhsb, 1);
+ if (hp)
+ lastev = hp->Hnum;
+ return (&hp->Hlex);
+
+ number:
+ event = 0;
+ while (digit(c)) {
+ event = event * 10 + c - '0';
+ c = getC(0);
+ }
+ if (back)
+ event = eventno + (alhistp == 0) - (event ? event : 0);
+ unreadc(c);
+ break;
+ }
+skip:
+ for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
+ if (hp->Hnum == event) {
+ hp->Href = eventno;
+ lastev = hp->Hnum;
+ return (&hp->Hlex);
+ }
+ np = putn(event);
+ noev(np);
+ return (0);
+}
+
+struct Hist *
+findev(cp, anyarg)
+ tchar *cp;
+ bool anyarg;
+{
+ register struct Hist *hp;
+
+#ifdef TRACE
+ tprintf("TRACE- findev()\n");
+#endif
+ for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
+ tchar *dp;
+ register tchar *p, *q;
+ register struct wordent *lp = hp->Hlex.next;
+ int argno = 0;
+
+ if (lp->word[0] == '\n')
+ continue;
+ if (!anyarg) {
+ p = cp;
+ q = lp->word;
+ do
+ if (!*p)
+ return (hp);
+ while (*p++ == *q++);
+ continue;
+ }
+ do {
+ for (dp = lp->word; *dp; dp++) {
+ p = cp;
+ q = dp;
+ do
+ if (!*p) {
+ quesarg = argno;
+ return (hp);
+ }
+ while (*p++ == *q++);
+ }
+ lp = lp->next;
+ argno++;
+ } while (lp->word[0] != '\n');
+ }
+ noev(cp);
+ return (0);
+}
+
+noev(cp)
+ tchar *cp;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- noev()\n");
+#endif
+ seterr2(cp, ": Event not found");
+}
+
+setexclp(cp)
+ register tchar *cp;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- setexclp()\n");
+#endif
+ if (cp && cp[0] == '\n')
+ return;
+ exclp = cp;
+}
+
+unreadc(c)
+ tchar c;
+{
+
+ peekread = c;
+}
+
+readc(wanteof)
+ bool wanteof;
+{
+ register int c;
+ static sincereal;
+
+ if (c = peekread) {
+ peekread = 0;
+ return (c);
+ }
+top:
+ if (alvecp) {
+ if (c = *alvecp++)
+ return (c);
+ if (*alvec) {
+ alvecp = *alvec++;
+ return (' ');
+ }
+ }
+ if (alvec) {
+ if (alvecp = *alvec) {
+ alvec++;
+ goto top;
+ }
+ /* Infinite source! */
+ return ('\n');
+ }
+ if (evalp) {
+ if (c = *evalp++)
+ return (c);
+ if (*evalvec) {
+ evalp = *evalvec++;
+ return (' ');
+ }
+ evalp = 0;
+ }
+ if (evalvec) {
+ if (evalvec == (tchar **)1) {
+ doneinp = 1;
+ reset();
+ }
+ if (evalp = *evalvec) {
+ evalvec++;
+ goto top;
+ }
+ evalvec = (tchar **)1;
+ return ('\n');
+ }
+ do {
+ if (arginp == (tchar *) 1 || onelflg == 1) {
+ if (wanteof)
+ return (-1);
+ exitstat();
+ }
+ if (arginp) {
+ if ((c = *arginp++) == 0) {
+ arginp = (tchar *) 1;
+ return ('\n');
+ }
+ return (c);
+ }
+reread:
+ c = bgetc();
+ if (c < 0) {
+ struct sgttyb tty;
+
+ if (wanteof)
+ return (-1);
+ /* was isatty but raw with ignoreeof yields problems */
+ if (ioctl(SHIN, TIOCGETP, (char *)&tty) == 0 &&
+ (tty.sg_flags & RAW) == 0) {
+ /* was 'short' for FILEC */
+ int ctpgrp;
+
+ if (++sincereal > 25)
+ goto oops;
+ if (tpgrp != -1 &&
+ ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp) == 0 &&
+ tpgrp != ctpgrp) {
+ (void) ioctl(FSHTTY, TIOCSPGRP,
+ (char *)&tpgrp);
+ (void) killpg(ctpgrp, SIGHUP);
+printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp);
+ goto reread;
+ }
+ if (adrof(S_ignoreeof/*"ignoreeof"*/)) {
+ if (loginsh)
+ printf("\nUse \"logout\" to logout.\n");
+ else
+ printf("\nUse \"exit\" to leave csh.\n");
+ reset();
+ }
+ if (chkstop == 0) {
+ panystop(1);
+ }
+ }
+oops:
+ doneinp = 1;
+ reset();
+ }
+ sincereal = 0;
+ if (c == '\n' && onelflg)
+ onelflg--;
+ } while (c == 0);
+ return (c);
+}
+
+bgetc()
+{
+ register int buf, off, c;
+#ifdef FILEC
+ tchar ttyline[BUFSIZ];
+ register int numleft = 0, roomleft;
+#endif
+
+#ifdef TELL
+ if (cantell) {
+ if (fseekp < fbobp || fseekp > feobp) {
+ fbobp = feobp = fseekp;
+ (void) lseek(SHIN, fseekp, 0);
+ }
+ if (fseekp == feobp) {
+ fbobp = feobp;
+ do
+ c = read_(SHIN, fbuf[0], BUFSIZ);
+ while (c < 0 && errno == EINTR);
+ if (c <= 0)
+ return (-1);
+ feobp += c;
+ }
+ c = fbuf[0][fseekp - fbobp];
+ fseekp++;
+ return (c);
+ }
+#endif
+again:
+ buf = (int) fseekp / BUFSIZ;
+ if (buf >= fblocks) {
+ register tchar **nfbuf =
+ (tchar **) calloc((unsigned) (fblocks + 2),
+ sizeof (tchar **));
+
+ if (fbuf) {
+ (void) blkcpy(nfbuf, fbuf);
+ xfree( (char *)fbuf);
+ }
+ fbuf = nfbuf;
+ fbuf[fblocks] = (tchar *)calloc(BUFSIZ, sizeof (tchar));
+ fblocks++;
+ goto again;
+ }
+ if (fseekp >= feobp) {
+ buf = (int) feobp / BUFSIZ;
+ off = (int) feobp % BUFSIZ;
+#ifndef FILEC
+ for (;;) {
+ c = read_(SHIN, fbuf[buf] + off, BUFSIZ - off);
+#else
+ roomleft = BUFSIZ - off;
+ for (;;) {
+ if (filec && intty) {
+ c = numleft ? numleft : tenex(ttyline, BUFSIZ);
+ if (c > roomleft) {
+ /* start with fresh buffer */
+ feobp = fseekp = fblocks * BUFSIZ;
+ numleft = c;
+ goto again;
+ }
+ if (c > 0)
+ copy(fbuf[buf] + off, ttyline, c*sizeof(tchar));
+ numleft = 0;
+ } else
+ c = read_(SHIN, fbuf[buf] + off, roomleft);
+#endif
+ if (c >= 0)
+ break;
+ if (errno == EWOULDBLOCK) {
+ int off = 0;
+
+ (void) ioctl(SHIN, FIONBIO, (char *)&off);
+ } else if (errno != EINTR)
+ break;
+ }
+ if (c <= 0)
+ return (-1);
+ feobp += c;
+#ifndef FILEC
+ goto again;
+#else
+ if (filec && !intty)
+ goto again;
+#endif
+ }
+ c = fbuf[buf][(int) fseekp % BUFSIZ];
+ fseekp++;
+ return (c);
+}
+
+bfree()
+{
+ register int sb, i;
+
+#ifdef TELL
+ if (cantell)
+ return;
+#endif
+ if (whyles)
+ return;
+ sb = (int) (fseekp - 1) / BUFSIZ;
+ if (sb > 0) {
+ for (i = 0; i < sb; i++)
+ xfree(fbuf[i]);
+ (void) blkcpy(fbuf, &fbuf[sb]);
+ fseekp -= BUFSIZ * sb;
+ feobp -= BUFSIZ * sb;
+ fblocks -= sb;
+ }
+}
+
+bseek(l)
+ off_t l;
+{
+ register struct whyle *wp;
+
+ fseekp = l;
+#ifdef TELL
+ if (!cantell) {
+#endif
+ if (!whyles)
+ return;
+ for (wp = whyles; wp->w_next; wp = wp->w_next)
+ continue;
+ if (wp->w_start > l)
+ l = wp->w_start;
+#ifdef TELL
+ }
+#endif
+}
+
+/* any similarity to bell telephone is purely accidental */
+#ifndef btell
+off_t
+btell()
+{
+
+ return (fseekp);
+}
+#endif
+
+btoeof()
+{
+
+ (void) lseek(SHIN, (off_t)0, 2);
+ fseekp = feobp;
+ wfree();
+ bfree();
+}
+
+#ifdef TELL
+settell()
+{
+
+ cantell = 0;
+ if (arginp || onelflg || intty)
+ return;
+ if (lseek(SHIN, (off_t)0, 1) < 0 || errno == ESPIPE)
+ return;
+ fbuf = (tchar **) calloc(2, sizeof (tchar **));
+ fblocks = 1;
+ fbuf[0] = (tchar *)calloc(BUFSIZ, sizeof (tchar));
+ fseekp = fbobp = feobp = lseek(SHIN, (off_t)0, 1);
+ cantell = 1;
+}
+#endif
+
diff --git a/usr/src/cmd/csh/sh.local.h b/usr/src/cmd/csh/sh.local.h
new file mode 100644
index 0000000000..78bc22bb6b
--- /dev/null
+++ b/usr/src/cmd/csh/sh.local.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file defines certain local parameters
+ * A symbol should be defined in Makefile for local conditional
+ * compilation, e.g. IIASA or ERNIE, to be tested here and elsewhere.
+ */
+
+/*
+ * Fundamental definitions which may vary from system to system.
+ *
+ * BUFSIZ The i/o buffering size; also limits word size
+ * SHELLPATH Where the shell will live; initalizes $shell
+ * MAILINTVL How often to mailcheck; more often is more expensive
+ * OTHERSH Shell for scripts which don't start with #
+ */
+
+#define BUFSIZ 1024 /* default buffer size */
+#define PATHSIZ 16384 /* allow longer PATH environment variables */
+#define SHELLPATH "/bin/csh"
+#define OTHERSH "/bin/sh"
+#define FORKSLEEP 10 /* delay loop on non-interactive fork failure */
+#define MAILINTVL 600 /* 10 minutes */
+
+/*
+ * The shell moves std in/out/diag and the old std input away from units
+ * 0, 1, and 2 so that it is easy to set up these standards for invoked
+ * commands.
+ */
+#define FSHTTY 15 /* /dev/tty when manip pgrps */
+#define FSHIN 16 /* Preferred desc for shell input */
+#define FSHOUT 17 /* ... shell output */
+#define FSHDIAG 18 /* ... shell diagnostics */
+#define FOLDSTD 19 /* ... old std input */
+
+#ifdef IIASA
+#undef OTHERSH
+#endif
+
+#define copy(to, from, size) bcopy(from, to, size)
+
+#ifdef PROF
+#define exit(n) done(n)
+#endif
diff --git a/usr/src/cmd/csh/sh.misc.c b/usr/src/cmd/csh/sh.misc.c
new file mode 100644
index 0000000000..4f67243a5f
--- /dev/null
+++ b/usr/src/cmd/csh/sh.misc.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2000 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+/*
+ * C Shell
+ */
+
+any(c, s)
+ register int c;
+ register tchar *s;
+{
+
+ while (s && *s)
+ if (*s++ == c)
+ return (1);
+ return (0);
+}
+
+onlyread(cp)
+ tchar *cp;
+{
+ extern char end[];
+
+ return ((char *)cp < end);
+}
+
+
+/*
+ * WARNING: changes here also need to occur in the XFREE macro in sh.h.
+ */
+
+xfree(cp)
+ char *cp;
+{
+ extern char end[];
+
+#if defined(sparc)
+ if ((char *)cp >= end && (char *)cp < (char *)&cp)
+ free(cp);
+#elif defined(i386)
+ if ((char *)cp >= end)
+ free(cp);
+#else
+#error xfree function is machine dependent and no machine type is recognized
+#endif
+}
+
+tchar *
+savestr(s)
+ register tchar *s;
+{
+ tchar *n;
+ register tchar *p;
+
+ if (s == 0)
+ s = S_ /* "" */;
+#ifndef m32
+ for (p = s; *p++; )
+ ;
+ n = p = (tchar *)xalloc((unsigned) (p - s)*sizeof (tchar));
+ while (*p++ = *s++)
+ ;
+ return (n);
+#else
+ p = (tchar *) xalloc((strlen_(s) + 1)*sizeof (tchar));
+ strcpy_(p, s);
+ return (p);
+#endif
+}
+
+void *
+calloc(i, j)
+ register unsigned i;
+ unsigned j;
+{
+ register char *cp;
+
+ i *= j;
+ cp = (char *)xalloc(i);
+ bzero(cp, (int)i);
+ return (cp);
+}
+
+nomem(i)
+ unsigned i;
+{
+#ifdef debug
+ static tchar *av[2] = {0, 0};
+#endif
+
+ child++;
+#ifndef debug
+ error("Out of memory");
+#ifdef lint
+ i = i;
+#endif
+#else
+ showall(av);
+ printf("i=%d: Out of memory\n", i);
+ chdir("/usr/bill/cshcore");
+ abort();
+#endif
+ return (0); /* fool lint */
+}
+
+tchar **
+blkend(up)
+ register tchar **up;
+{
+
+ while (*up)
+ up++;
+ return (up);
+}
+
+blkpr(av)
+ register tchar **av;
+{
+
+ for (; *av; av++) {
+ printf("%t", *av);
+ if (av[1])
+ printf(" ");
+ }
+}
+
+blklen(av)
+ register tchar **av;
+{
+ register int i = 0;
+
+ while (*av++)
+ i++;
+ return (i);
+}
+
+tchar **
+blkcpy(oav, bv)
+ tchar **oav;
+ register tchar **bv;
+{
+ register tchar **av = oav;
+
+ while (*av++ = *bv++)
+ continue;
+ return (oav);
+}
+
+tchar **
+blkcat(up, vp)
+ tchar **up, **vp;
+{
+
+ (void) blkcpy(blkend(up), vp);
+ return (up);
+}
+
+blkfree(av0)
+ tchar **av0;
+{
+ register tchar **av = av0;
+
+ for (; *av; av++)
+ XFREE(*av)
+ XFREE((tchar *)av0)
+}
+
+tchar **
+saveblk(v)
+ register tchar **v;
+{
+ register tchar **newv =
+ (tchar **) calloc((unsigned) (blklen(v) + 1),
+ sizeof (tchar **));
+ tchar **onewv = newv;
+
+ while (*v)
+ *newv++ = savestr(*v++);
+ return (onewv);
+}
+
+tchar *
+strspl(cp, dp)
+ tchar *cp, *dp;
+{
+ tchar *ep;
+ register tchar *p, *q;
+
+#ifndef m32
+ for (p = cp; *p++; )
+ ;
+ for (q = dp; *q++; )
+ ;
+ ep = (tchar *) xalloc((unsigned) (((p - cp) +
+ (q - dp) - 1))*sizeof (tchar));
+ for (p = ep, q = cp; *p++ = *q++; )
+ ;
+ for (p--, q = dp; *p++ = *q++; )
+ ;
+#else
+ int len1 = strlen_(cp);
+ int len2 = strlen_(dp);
+
+ ep = (tchar *)xalloc((unsigned) (len1 + len2 + 1)*sizeof (tchar));
+ strcpy_(ep, cp);
+ strcat_(ep, dp);
+#endif
+ return (ep);
+}
+
+tchar **
+blkspl(up, vp)
+ register tchar **up, **vp;
+{
+ register tchar **wp =
+ (tchar **) calloc((unsigned) (blklen(up) + blklen(vp) + 1),
+ sizeof (tchar **));
+
+ (void) blkcpy(wp, up);
+ return (blkcat(wp, vp));
+}
+
+lastchr(cp)
+ register tchar *cp;
+{
+
+ if (!*cp)
+ return (0);
+ while (cp[1])
+ cp++;
+ return (*cp);
+}
+
+donefds()
+{
+ (void) close(0);
+ (void) close(1);
+ (void) close(2);
+
+ /*
+ * To avoid NIS+ functions to get hold of 0/1/2,
+ * use descriptor 0, and dup it to 1 and 2.
+ */
+ open("/dev/null", 0);
+ dup(0); dup(0);
+ didfds = 0;
+}
+
+/*
+ * Move descriptor i to j.
+ * If j is -1 then we just want to get i to a safe place,
+ * i.e. to a unit > 2. This also happens in dcopy.
+ */
+dmove(i, j)
+ register int i, j;
+{
+ int fd;
+
+ if (i == j || i < 0)
+ return (i);
+ if (j >= 0) {
+ fd = dup2(i, j);
+ if (fd != -1)
+ setfd(fd);
+ } else
+ j = dcopy(i, j);
+ if (j != i) {
+ (void) close(i);
+ unsetfd(i);
+ }
+ return (j);
+}
+
+dcopy(i, j)
+ register int i, j;
+{
+
+ int fd;
+
+ if (i == j || i < 0 || j < 0 && i > 2)
+ return (i);
+ if (j >= 0) {
+ fd = dup2(i, j);
+ if (fd != -1)
+ setfd(fd);
+ return (j);
+ }
+ (void) close(j);
+ unsetfd(j);
+ return (renum(i, j));
+}
+
+renum(i, j)
+ register int i, j;
+{
+ register int k = dup(i);
+
+ if (k < 0)
+ return (-1);
+ if (j == -1 && k > 2) {
+ setfd(k);
+ return (k);
+ }
+ if (k != j) {
+ j = renum(k, j);
+ (void) close(k); /* no need ofr unsetfd() */
+ return (j);
+ }
+ return (k);
+}
+
+#ifndef copy
+copy(to, from, size)
+ register tchar *to, *from;
+ register int size;
+{
+
+ if (size)
+ do
+ *to++ = *from++;
+ while (--size != 0);
+}
+#endif
+
+/*
+ * Left shift a command argument list, discarding
+ * the first c arguments. Used in "shift" commands
+ * as well as by commands like "repeat".
+ */
+lshift(v, c)
+ register tchar **v;
+ register int c;
+{
+ register tchar **u = v;
+
+ while (*u && --c >= 0)
+ xfree(*u++);
+ (void) blkcpy(v, u);
+}
+
+number(cp)
+ tchar *cp;
+{
+
+ if (*cp == '-') {
+ cp++;
+ if (!digit(*cp++))
+ return (0);
+ }
+ while (*cp && digit(*cp))
+ cp++;
+ return (*cp == 0);
+}
+
+tchar **
+copyblk(v)
+ register tchar **v;
+{
+ register tchar **nv =
+ (tchar **) calloc((unsigned) (blklen(v) + 1),
+ sizeof (tchar **));
+
+ return (blkcpy(nv, v));
+}
+
+tchar *
+strend(cp)
+ register tchar *cp;
+{
+
+ while (*cp)
+ cp++;
+ return (cp);
+}
+
+tchar *
+strip(cp)
+ tchar *cp;
+{
+ register tchar *dp = cp;
+
+ while (*dp++ &= TRIM)
+ continue;
+ return (cp);
+}
+
+udvar(name)
+ tchar *name;
+{
+
+ setname(name);
+ bferr("Undefined variable");
+}
+
+prefix(sub, str)
+ register tchar *sub, *str;
+{
+
+ for (;;) {
+ if (*sub == 0)
+ return (1);
+ if (*str == 0)
+ return (0);
+ if (*sub++ != *str++)
+ return (0);
+ }
+}
+
+/*
+ * blk*_ routines
+ */
+
+char **
+blkend_(up)
+ register char **up;
+{
+
+ while (*up)
+ up++;
+ return (up);
+}
+
+blklen_(av)
+ register char **av;
+{
+ register int i = 0;
+
+ while (*av++)
+ i++;
+ return (i);
+}
+
+char **
+blkcpy_(oav, bv)
+ char **oav;
+ register char **bv;
+{
+ register char **av = oav;
+
+ while (*av++ = *bv++)
+ continue;
+ return (oav);
+}
+
+char **
+blkcat_(up, vp)
+ char **up, **vp;
+{
+
+ (void) blkcpy_(blkend_(up), vp);
+ return (up);
+}
+
+char **
+blkspl_(up, vp)
+ register char **up, **vp;
+{
+ register char **wp =
+ (char **) calloc((unsigned) (blklen_(up) + blklen_(vp) + 1),
+ sizeof (char **));
+
+ (void) blkcpy_(wp, up);
+ return (blkcat_(wp, vp));
+}
diff --git a/usr/src/cmd/csh/sh.parse.c b/usr/src/cmd/csh/sh.parse.c
new file mode 100644
index 0000000000..f77feca7bc
--- /dev/null
+++ b/usr/src/cmd/csh/sh.parse.c
@@ -0,0 +1,696 @@
+/*
+ * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+
+/*
+ * C shell
+ */
+
+/*
+ * Perform aliasing on the word list lex
+ * Do a (very rudimentary) parse to separate into commands.
+ * If word 0 of a command has an alias, do it.
+ * Repeat a maximum of 20 times.
+ */
+alias(lex)
+ register struct wordent *lex;
+{
+ int aleft = 21;
+ jmp_buf osetexit;
+
+#ifdef TRACE
+ tprintf("TRACE- alias()\n");
+#endif
+ getexit(osetexit);
+ setexit();
+ if (haderr) {
+ resexit(osetexit);
+ reset();
+ }
+ if (--aleft == 0)
+ error("Alias loop");
+ asyntax(lex->next, lex);
+ resexit(osetexit);
+}
+
+asyntax(p1, p2)
+ register struct wordent *p1, *p2;
+{
+#ifdef TRACE
+ tprintf("TRACE- asyntax()\n");
+#endif
+
+ while (p1 != p2)
+ /* if (any(p1->word[0], ";&\n")) */ /* For char -> tchar */
+ if (p1->word[0] == ';' ||
+ p1->word[0] == '&' ||
+ p1->word[0] == '\n')
+ p1 = p1->next;
+ else {
+ asyn0(p1, p2);
+ return;
+ }
+}
+
+asyn0(p1, p2)
+ struct wordent *p1;
+ register struct wordent *p2;
+{
+ register struct wordent *p;
+ register int l = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- asyn0()\n");
+#endif
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ if (l < 0)
+ error("Too many )'s");
+ continue;
+
+ case '>':
+ if (p->next != p2 && eq(p->next->word, S_AND /* "&"*/))
+ p = p->next;
+ continue;
+
+ case '&':
+ case '|':
+ case ';':
+ case '\n':
+ if (l != 0)
+ continue;
+ asyn3(p1, p);
+ asyntax(p->next, p2);
+ return;
+ }
+ if (l == 0)
+ asyn3(p1, p2);
+}
+
+asyn3(p1, p2)
+ struct wordent *p1;
+ register struct wordent *p2;
+{
+ register struct varent *ap;
+ struct wordent alout;
+ register bool redid;
+
+#ifdef TRACE
+ tprintf("TRACE- asyn3()\n");
+#endif
+ if (p1 == p2)
+ return;
+ if (p1->word[0] == '(') {
+ for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
+ if (p2 == p1)
+ return;
+ if (p2 == p1->next)
+ return;
+ asyn0(p1->next, p2);
+ return;
+ }
+ ap = adrof1(p1->word, &aliases);
+ if (ap == 0)
+ return;
+ alhistp = p1->prev;
+ alhistt = p2;
+ alvec = ap->vec;
+ redid = lex(&alout);
+ alhistp = alhistt = 0;
+ alvec = 0;
+ if (err) {
+ freelex(&alout);
+ error("%s", gettext(err));
+ }
+ if (p1->word[0] && eq(p1->word, alout.next->word)) {
+ tchar *cp = alout.next->word;
+
+ alout.next->word = strspl(S_TOPBIT /*"\200"*/, cp);
+ XFREE(cp)
+ }
+ p1 = freenod(p1, redid ? p2 : p1->next);
+ if (alout.next != &alout) {
+ p1->next->prev = alout.prev->prev;
+ alout.prev->prev->next = p1->next;
+ alout.next->prev = p1;
+ p1->next = alout.next;
+ XFREE(alout.prev->word)
+ XFREE( (tchar *)alout.prev)
+ }
+ reset(); /* throw! */
+}
+
+struct wordent *
+freenod(p1, p2)
+ register struct wordent *p1, *p2;
+{
+ register struct wordent *retp = p1->prev;
+
+#ifdef TRACE
+ tprintf("TRACE- freenod()\n");
+#endif
+ while (p1 != p2) {
+ XFREE(p1->word)
+ p1 = p1->next;
+ XFREE( (tchar *)p1->prev)
+ }
+ retp->next = p2;
+ p2->prev = retp;
+ return (retp);
+}
+
+#define PHERE 1
+#define PIN 2
+#define POUT 4
+#define PDIAG 8
+
+/*
+ * syntax
+ * empty
+ * syn0
+ */
+struct command *
+syntax(p1, p2, flags)
+ register struct wordent *p1, *p2;
+ int flags;
+{
+#ifdef TRACE
+ tprintf("TRACE- syntax()\n");
+#endif
+
+ while (p1 != p2)
+ /* if (any(p1->word[0], ";&\n")) */ /* for char -> tchar */
+ if (p1->word[0] == ';' ||
+ p1->word[0] == '&' ||
+ p1->word[0] == '\n')
+ p1 = p1->next;
+ else
+ return (syn0(p1, p2, flags));
+ return (0);
+}
+
+/*
+ * syn0
+ * syn1
+ * syn1 & syntax
+ */
+struct command *
+syn0(p1, p2, flags)
+ struct wordent *p1, *p2;
+ int flags;
+{
+ register struct wordent *p;
+ register struct command *t, *t1;
+ int l;
+
+#ifdef TRACE
+ tprintf("TRACE- syn0()\n");
+#endif
+ l = 0;
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ if (l < 0)
+ seterr("Too many )'s");
+ continue;
+
+ case '|':
+ if (p->word[1] == '|')
+ continue;
+ /* fall into ... */
+
+ case '>':
+ if (p->next != p2 && eq(p->next->word, S_AND /*"&"*/))
+ p = p->next;
+ continue;
+
+ case '&':
+ if (l != 0)
+ break;
+ if (p->word[1] == '&')
+ continue;
+ t1 = syn1(p1, p, flags);
+ if (t1->t_dtyp == TLST ||
+ t1->t_dtyp == TAND ||
+ t1->t_dtyp == TOR) {
+ t = (struct command *) calloc(1, sizeof (*t));
+ t->t_dtyp = TPAR;
+ t->t_dflg = FAND|FINT;
+ t->t_dspr = t1;
+ t1 = t;
+ } else
+ t1->t_dflg |= FAND|FINT;
+ t = (struct command *) calloc(1, sizeof (*t));
+ t->t_dtyp = TLST;
+ t->t_dflg = 0;
+ t->t_dcar = t1;
+ t->t_dcdr = syntax(p, p2, flags);
+ return(t);
+ }
+ if (l == 0)
+ return (syn1(p1, p2, flags));
+ seterr("Too many ('s");
+ return (0);
+}
+
+/*
+ * syn1
+ * syn1a
+ * syn1a ; syntax
+ */
+struct command *
+syn1(p1, p2, flags)
+ struct wordent *p1, *p2;
+ int flags;
+{
+ register struct wordent *p;
+ register struct command *t;
+ int l;
+
+#ifdef TRACE
+ tprintf("TRACE- syn1()\n");
+#endif
+ l = 0;
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ continue;
+
+ case ';':
+ case '\n':
+ if (l != 0)
+ break;
+ t = (struct command *) calloc(1, sizeof (*t));
+ t->t_dtyp = TLST;
+ t->t_dcar = syn1a(p1, p, flags);
+ t->t_dcdr = syntax(p->next, p2, flags);
+ if (t->t_dcdr == 0)
+ t->t_dcdr = t->t_dcar, t->t_dcar = 0;
+ return (t);
+ }
+ return (syn1a(p1, p2, flags));
+}
+
+/*
+ * syn1a
+ * syn1b
+ * syn1b || syn1a
+ */
+struct command *
+syn1a(p1, p2, flags)
+ struct wordent *p1, *p2;
+ int flags;
+{
+ register struct wordent *p;
+ register struct command *t;
+ register int l = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- syn1a()\n");
+#endif
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ continue;
+
+ case '|':
+ if (p->word[1] != '|')
+ continue;
+ if (l == 0) {
+ t = (struct command *) calloc(1, sizeof (*t));
+ t->t_dtyp = TOR;
+ t->t_dcar = syn1b(p1, p, flags);
+ t->t_dcdr = syn1a(p->next, p2, flags);
+ t->t_dflg = 0;
+ return (t);
+ }
+ continue;
+ }
+ return (syn1b(p1, p2, flags));
+}
+
+/*
+ * syn1b
+ * syn2
+ * syn2 && syn1b
+ */
+struct command *
+syn1b(p1, p2, flags)
+ struct wordent *p1, *p2;
+ int flags;
+{
+ register struct wordent *p;
+ register struct command *t;
+ register int l = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- syn1b()\n");
+#endif
+ l = 0;
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ continue;
+
+ case '&':
+ if (p->word[1] == '&' && l == 0) {
+ t = (struct command *) calloc(1, sizeof (*t));
+ t->t_dtyp = TAND;
+ t->t_dcar = syn2(p1, p, flags);
+ t->t_dcdr = syn1b(p->next, p2, flags);
+ t->t_dflg = 0;
+ return (t);
+ }
+ continue;
+ }
+ return (syn2(p1, p2, flags));
+}
+
+/*
+ * syn2
+ * syn3
+ * syn3 | syn2
+ * syn3 |& syn2
+ */
+struct command *
+syn2(p1, p2, flags)
+ struct wordent *p1, *p2;
+ int flags;
+{
+ register struct wordent *p, *pn;
+ register struct command *t;
+ register int l = 0;
+ int f;
+
+#ifdef TRACE
+ tprintf("TRACE- syn2()\n");
+#endif
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ l++;
+ continue;
+
+ case ')':
+ l--;
+ continue;
+
+ case '|':
+ if (l != 0)
+ continue;
+ t = (struct command *) calloc(1, sizeof (*t));
+ f = flags | POUT;
+ pn = p->next;
+ if (pn != p2 && pn->word[0] == '&') {
+ f |= PDIAG;
+ t->t_dflg |= FDIAG;
+ }
+ t->t_dtyp = TFIL;
+ t->t_dcar = syn3(p1, p, f);
+ if (pn != p2 && pn->word[0] == '&')
+ p = pn;
+ t->t_dcdr = syn2(p->next, p2, flags | PIN);
+ return (t);
+ }
+ return (syn3(p1, p2, flags));
+}
+
+tchar RELPAR[] = {'<', '>', '(', ')', 0}; /* "<>()" */
+
+/*
+ * syn3
+ * ( syn0 ) [ < in ] [ > out ]
+ * word word* [ < in ] [ > out ]
+ * KEYWORD ( word* ) word* [ < in ] [ > out ]
+ *
+ * KEYWORD = (@ exit foreach if set switch test while)
+ */
+struct command *
+syn3(p1, p2, flags)
+ struct wordent *p1, *p2;
+ int flags;
+{
+ register struct wordent *p;
+ struct wordent *lp, *rp;
+ register struct command *t;
+ register int l;
+ tchar **av;
+ int n, c;
+ bool specp = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- syn3()\n");
+#endif
+ if (p1 != p2) {
+ p = p1;
+again:
+ switch (srchx(p->word)) {
+
+ case ZELSE:
+ p = p->next;
+ if (p != p2)
+ goto again;
+ break;
+
+ case ZEXIT:
+ case ZFOREACH:
+ case ZIF:
+ case ZLET:
+ case ZSET:
+ case ZSWITCH:
+ case ZWHILE:
+ specp = 1;
+ break;
+ }
+ }
+ n = 0;
+ l = 0;
+ for (p = p1; p != p2; p = p->next)
+ switch (p->word[0]) {
+
+ case '(':
+ if (specp)
+ n++;
+ l++;
+ continue;
+
+ case ')':
+ if (specp)
+ n++;
+ l--;
+ continue;
+
+ case '>':
+ case '<':
+ if (l != 0) {
+ if (specp)
+ n++;
+ continue;
+ }
+ if (p->next == p2)
+ continue;
+ if (any(p->next->word[0], RELPAR))
+ continue;
+ n--;
+ continue;
+
+ default:
+ if (!specp && l != 0)
+ continue;
+ n++;
+ continue;
+ }
+ if (n < 0)
+ n = 0;
+ t = (struct command *) calloc(1, sizeof (*t));
+ av = (tchar **) calloc((unsigned) (n + 1), sizeof (tchar **));
+ t->t_dcom = av;
+ n = 0;
+ if (p2->word[0] == ')')
+ t->t_dflg = FPAR;
+ lp = 0;
+ rp = 0;
+ l = 0;
+ for (p = p1; p != p2; p = p->next) {
+ c = p->word[0];
+ switch (c) {
+
+ case '(':
+ if (l == 0) {
+ if (lp != 0 && !specp)
+ seterr("Badly placed (");
+ lp = p->next;
+ }
+ l++;
+ goto savep;
+
+ case ')':
+ l--;
+ if (l == 0)
+ rp = p;
+ goto savep;
+
+ case '>':
+ if (l != 0)
+ goto savep;
+ if (p->word[1] == '>')
+ t->t_dflg |= FCAT;
+ if (p->next != p2 && eq(p->next->word, S_AND /*"&"*/)) {
+ t->t_dflg |= FDIAG, p = p->next;
+ if (flags & (POUT|PDIAG))
+ goto badout;
+ }
+ if (p->next != p2 && eq(p->next->word, S_EXAS /*"!"*/))
+ t->t_dflg |= FANY, p = p->next;
+ if (p->next == p2) {
+missfile:
+ seterr("Missing name for redirect");
+ continue;
+ }
+ p = p->next;
+ if (any(p->word[0], RELPAR))
+ goto missfile;
+ if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit)
+badout:
+ seterr("Ambiguous output redirect");
+ else
+ t->t_drit = savestr(p->word);
+ continue;
+
+ case '<':
+ if (l != 0)
+ goto savep;
+ if (p->word[1] == '<')
+ t->t_dflg |= FHERE;
+ if (p->next == p2)
+ goto missfile;
+ p = p->next;
+ if (any(p->word[0], RELPAR))
+ goto missfile;
+ if ((flags & PHERE) && (t->t_dflg & FHERE))
+ seterr("Can't << within ()'s");
+ else if ((flags & PIN) || t->t_dlef)
+ seterr("Ambiguous input redirect");
+ else
+ t->t_dlef = savestr(p->word);
+ continue;
+
+savep:
+ if (!specp)
+ continue;
+ default:
+ if (l != 0 && !specp)
+ continue;
+ if (err == 0)
+ av[n] = savestr(p->word);
+ n++;
+ continue;
+ }
+ }
+ if (lp != 0 && !specp) {
+ if (n != 0)
+ seterr("Badly placed ()'s");
+ t->t_dtyp = TPAR;
+ t->t_dspr = syn0(lp, rp, PHERE);
+ } else {
+ if (n == 0)
+ seterr("Invalid null command");
+ t->t_dtyp = TCOM;
+ }
+ return (t);
+}
+
+freesyn(t)
+ register struct command *t;
+{
+#ifdef TRACE
+ tprintf("TRACE- freesyn()\n");
+#endif
+ if (t == 0)
+ return;
+ switch (t->t_dtyp) {
+
+ case TCOM:
+ blkfree(t->t_dcom);
+ if (t->cfname)
+ xfree(t->cfname);
+ if (t->cargs)
+ chr_blkfree(t->cargs);
+ goto lr;
+
+ case TPAR:
+ freesyn(t->t_dspr);
+ /* fall into ... */
+
+lr:
+ XFREE(t->t_dlef)
+ XFREE(t->t_drit)
+ break;
+
+ case TAND:
+ case TOR:
+ case TFIL:
+ case TLST:
+ freesyn(t->t_dcar), freesyn(t->t_dcdr);
+ break;
+ }
+ XFREE( (tchar *)t)
+}
+
+
+chr_blkfree(vec)
+register char **vec;
+{
+ register char **av;
+
+ for (av = vec; *av; av++)
+ xfree(*av);
+ xfree(vec);
+}
diff --git a/usr/src/cmd/csh/sh.print.c b/usr/src/cmd/csh/sh.print.c
new file mode 100644
index 0000000000..29fc570a09
--- /dev/null
+++ b/usr/src/cmd/csh/sh.print.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+
+void p2dig_ull(unsigned long long i);
+void p2dig_int(int i);
+void flush();
+
+/*
+ * C Shell
+ */
+
+void
+psecs_ull(unsigned long long l)
+{
+ unsigned long long i;
+
+ i = l / 3600;
+ if (i) {
+ printf("%llu:", i);
+ i = l % 3600;
+ p2dig_ull(i / 60);
+ goto minsec;
+ }
+ i = l;
+ printf("%llu", i / 60);
+minsec:
+ i %= 60;
+ printf(":");
+ p2dig_ull(i);
+}
+
+void
+psecs_int(int l)
+{
+ int i;
+
+ i = l / 3600;
+ if (i) {
+ printf("%d:", i);
+ i = l % 3600;
+ p2dig_int(i / 60);
+ goto minsec;
+ }
+ i = l;
+ printf("%d", i / 60);
+minsec:
+ i %= 60;
+ printf(":");
+ p2dig_int(i);
+}
+
+void
+p2dig_ull(unsigned long long i)
+{
+ printf("%llu%llu", i / 10, i % 10);
+}
+
+void
+p2dig_int(int i)
+{
+ printf("%d%d", i / 10, i % 10);
+}
+
+char linbuf[128];
+char *linp = linbuf;
+
+#ifdef MBCHAR
+
+/*
+ * putbyte() send a byte to SHOUT. No interpretation is done
+ * except an un-QUOTE'd control character, which is displayed
+ * as ^x.
+ */
+void
+putbyte(int c)
+{
+
+ if ((c & QUOTE) == 0 && (c == 0177 || c < ' ' && c != '\t' &&
+ c != '\n')) {
+ putbyte('^');
+ if (c == 0177) {
+ c = '?';
+ } else {
+ c |= 'A' - 1;
+ }
+ }
+ c &= TRIM;
+ *linp++ = c;
+
+ if (c == '\n' || linp >= &linbuf[sizeof (linbuf) - 1 - MB_CUR_MAX]) {
+ /* 'cause the next Putchar() call may overflow the buffer. */
+ flush();
+ }
+}
+
+/*
+ * Putchar(tc) does what putbyte(c) do for a byte c.
+ * Note that putbyte(c) just send the byte c (provided c is not
+ * a control character) as it is, while Putchar(tc) may expand the
+ * character tc to some byte sequnce that represents the character
+ * in EUC form.
+ */
+Putchar(tchar tc)
+{
+ int n;
+
+ if (isascii(tc&TRIM)) {
+ putbyte((int)tc);
+ return;
+ }
+ tc &= TRIM;
+ n = wctomb(linp, tc);
+ if (n == -1) {
+ return;
+ }
+ linp += n;
+ if (linp >= &linbuf[sizeof (linbuf) - 1 - MB_CUR_MAX]) {
+ flush();
+ }
+}
+
+#else /* !MBCHAR */
+
+/*
+ * putbyte() send a byte to SHOUT. No interpretation is done
+ * except an un-QUOTE'd control character, which is displayed
+ * as ^x.
+ */
+void
+putbyte(int c)
+{
+
+ if ((c & QUOTE) == 0 && (c == 0177 || c < ' ' && c != '\t' &&
+ c != '\n')) {
+ putbyte('^');
+ if (c == 0177) {
+ c = '?';
+ } else {
+ c |= 'A' - 1;
+ }
+ }
+ c &= TRIM;
+ *linp++ = c;
+ if (c == '\n' || linp >= &linbuf[sizeof (linbuf) - 2]) {
+ flush();
+ }
+}
+
+/*
+ * Putchar(tc) does what putbyte(c) do for a byte c.
+ * For single-byte character only environment, there is no
+ * difference between Putchar() and putbyte() though.
+ */
+Putchar(tc)
+ tchar tc;
+{
+ putbyte((int)tc);
+}
+
+#endif /* !MBCHAR */
+
+void
+draino()
+{
+ linp = linbuf;
+}
+
+void
+flush()
+{
+ int unit;
+ int lmode;
+
+ if (linp == linbuf) {
+ return;
+ }
+ if (haderr) {
+ unit = didfds ? 2 : SHDIAG;
+ } else {
+ unit = didfds ? 1 : SHOUT;
+ }
+#ifdef TIOCLGET
+ if (didfds == 0 && ioctl(unit, TIOCLGET, (char *)&lmode) == 0 &&
+ lmode&LFLUSHO) {
+ lmode = LFLUSHO;
+ (void) ioctl(unit, TIOCLBIC, (char *)&lmode);
+ (void) write(unit, "\n", 1);
+ }
+#endif
+ (void) write(unit, linbuf, linp - linbuf);
+ linp = linbuf;
+}
+
+/*
+ * Should not be needed.
+ */
+void
+write_string(char *s)
+{
+ int unit;
+ /*
+ * First let's make it sure to flush out things.
+ */
+ flush();
+
+ if (haderr) {
+ unit = didfds ? 2 : SHDIAG;
+ } else {
+ unit = didfds ? 1 : SHOUT;
+ }
+
+ (void) write(unit, s, strlen(s));
+}
diff --git a/usr/src/cmd/csh/sh.proc.c b/usr/src/cmd/csh/sh.proc.c
new file mode 100644
index 0000000000..195d2b07a1
--- /dev/null
+++ b/usr/src/cmd/csh/sh.proc.c
@@ -0,0 +1,1247 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.dir.h"
+#include "sh.proc.h"
+#include "wait.h"
+#include "sh.tconst.h"
+
+/*
+ * C Shell - functions that manage processes, handling hanging, termination
+ */
+
+#define BIGINDEX 9 /* largest desirable job index */
+
+/*
+ * pchild - called at interrupt level by the SIGCHLD signal
+ * indicating that at least one child has terminated or stopped
+ * thus at least one wait system call will definitely return a
+ * childs status. Top level routines (like pwait) must be sure
+ * to mask interrupts when playing with the proclist data structures!
+ */
+void
+pchild()
+{
+ register struct process *pp;
+ register struct process *fp;
+ register int pid;
+ union wait w;
+ int jobflags;
+ struct rusage ru;
+
+#ifdef TRACE
+ tprintf("TRACE- pchile()\n");
+#endif
+loop:
+ pid = csh_wait3(&w, (setintr ? WNOHANG|WUNTRACED:WNOHANG), &ru);
+ /*
+ * SysV sends a SIGCHLD when the child process
+ * receives a SIGCONT, and result of that action is ignored here
+ */
+ if ( w.w_status == WCONTFLG )
+ return;
+ if (pid <= 0) {
+ if (errno == EINTR) {
+ errno = 0;
+ goto loop;
+ }
+ pnoprocesses = pid == -1;
+ return;
+ }
+ for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
+ if (pid == pp->p_pid)
+ goto found;
+ goto loop;
+found:
+ if (pid == atoi_(value(S_child /*"child"*/)))
+ unsetv(S_child /*"child"*/);
+ pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED);
+ if (WIFSTOPPED(w)) {
+ pp->p_flags |= PSTOPPED;
+ pp->p_reason = w.w_stopsig;
+ } else {
+ if (pp->p_flags & (PTIME|PPTIME) || adrof(S_time /*"time"*/))
+ (void) gettimeofday(&pp->p_etime, (struct timezone *)0);
+ pp->p_rusage = ru;
+ if (WIFSIGNALED(w)) {
+ if (w.w_termsig == SIGINT)
+ pp->p_flags |= PINTERRUPTED;
+ else
+ pp->p_flags |= PSIGNALED;
+ if (w.w_coredump)
+ pp->p_flags |= PDUMPED;
+ pp->p_reason = w.w_termsig;
+ } else {
+ pp->p_reason = w.w_retcode;
+ if (pp->p_reason != 0)
+ pp->p_flags |= PAEXITED;
+ else
+ pp->p_flags |= PNEXITED;
+ }
+ }
+ jobflags = 0;
+ fp = pp;
+ do {
+ if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 &&
+ !child && adrof(S_time /*"time"*/) &&
+ fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=
+ atoi_(value(S_time /*"time"*/)))
+ fp->p_flags |= PTIME;
+ jobflags |= fp->p_flags;
+ } while ((fp = fp->p_friends) != pp);
+ pp->p_flags &= ~PFOREGND;
+ if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
+ pp->p_flags &= ~PPTIME;
+ pp->p_flags |= PTIME;
+ }
+ if ((jobflags & (PRUNNING|PREPORTED)) == 0) {
+ fp = pp;
+ do {
+ if (fp->p_flags&PSTOPPED)
+ fp->p_flags |= PREPORTED;
+ } while((fp = fp->p_friends) != pp);
+ while(fp->p_pid != fp->p_jobid)
+ fp = fp->p_friends;
+ if (jobflags&PSTOPPED) {
+ if (pcurrent && pcurrent != fp)
+ pprevious = pcurrent;
+ pcurrent = fp;
+ } else
+ pclrcurr(fp);
+ if (jobflags&PFOREGND) {
+ if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) ||
+#ifdef IIASA
+ jobflags & PAEXITED ||
+#endif
+ !eq(dcwd->di_name, fp->p_cwd->di_name)) {
+ ; /* print in pjwait */
+ }
+ } else {
+ if (jobflags&PNOTIFY || adrof(S_notify /*"notify"*/)) {
+ write_string("\015\n");
+ flush();
+ (void) pprint(pp, NUMBER|NAME|REASON);
+ if ((jobflags&PSTOPPED) == 0)
+ pflush(pp);
+ } else {
+ fp->p_flags |= PNEEDNOTE;
+ neednote++;
+ }
+ }
+ }
+ goto loop;
+}
+
+pnote()
+{
+ register struct process *pp;
+ int flags, omask;
+
+#ifdef TRACE
+ tprintf("TRACE- pnote()\n");
+#endif
+ neednote = 0;
+ for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {
+ if (pp->p_flags & PNEEDNOTE) {
+ omask = sigblock(sigmask(SIGCHLD));
+ pp->p_flags &= ~PNEEDNOTE;
+ flags = pprint(pp, NUMBER|NAME|REASON);
+ if ((flags&(PRUNNING|PSTOPPED)) == 0)
+ pflush(pp);
+ (void) sigsetmask(omask);
+ }
+ }
+}
+
+/*
+ * pwait - wait for current job to terminate, maintaining integrity
+ * of current and previous job indicators.
+ */
+pwait()
+{
+ register struct process *fp, *pp;
+ int omask;
+
+#ifdef TRACE
+ tprintf("TRACE- pwait()\n");
+#endif
+ /*
+ * Here's where dead procs get flushed.
+ */
+ omask = sigblock(sigmask(SIGCHLD));
+ for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)
+ if (pp->p_pid == 0) {
+ fp->p_next = pp->p_next;
+ xfree(pp->p_command);
+ if (pp->p_cwd && --pp->p_cwd->di_count == 0)
+ if (pp->p_cwd->di_next == 0)
+ dfree(pp->p_cwd);
+ xfree( (tchar *)pp);
+ pp = fp;
+ }
+ (void) sigsetmask(omask);
+ pjwait(pcurrjob);
+}
+
+/*
+ * pjwait - wait for a job to finish or become stopped
+ * It is assumed to be in the foreground state (PFOREGND)
+ */
+pjwait(pp)
+ register struct process *pp;
+{
+ register struct process *fp;
+ int jobflags, reason, omask;
+
+#ifdef TRACE
+ tprintf("TRACE- pjwait()\n");
+#endif
+ while (pp->p_pid != pp->p_jobid)
+ pp = pp->p_friends;
+ fp = pp;
+ do {
+ if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)
+ printf("BUG: waiting for background job!\n");
+ } while ((fp = fp->p_friends) != pp);
+ /*
+ * Now keep pausing as long as we are not interrupted (SIGINT),
+ * and the target process, or any of its friends, are running
+ */
+ fp = pp;
+ omask = sigblock(sigmask(SIGCHLD));
+ for (;;) {
+ jobflags = 0;
+ do
+ jobflags |= fp->p_flags;
+ while ((fp = (fp->p_friends)) != pp);
+ if ((jobflags & PRUNNING) == 0)
+ break;
+ sigpause(sigblock(0) &~ sigmask(SIGCHLD));
+ }
+ (void) sigsetmask(omask);
+ if (tpgrp > 0) /* get tty back */
+ (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp);
+ if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||
+ !eq(dcwd->di_name, fp->p_cwd->di_name)) {
+ if (jobflags&PSTOPPED)
+ printf("\n");
+ (void) pprint(pp, AREASON|SHELLDIR);
+ }
+ if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&
+ (!gointr || !eq(gointr, S_MINUS /*"-"*/))) {
+ if ((jobflags & PSTOPPED) == 0)
+ pflush(pp);
+ pintr1(0);
+ /*NOTREACHED*/
+ }
+ reason = 0;
+ fp = pp;
+ do {
+ if (fp->p_reason)
+ reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ?
+ fp->p_reason | ABN_TERM : fp->p_reason;
+ } while ((fp = fp->p_friends) != pp);
+ set(S_status/*"status"*/, putn(reason));
+ if (reason && exiterr)
+ exitstat();
+ pflush(pp);
+}
+
+/*
+ * dowait - wait for all processes to finish
+ */
+dowait()
+{
+ register struct process *pp;
+ int omask;
+
+#ifdef TRACE
+ tprintf("TRACE- dowait()\n");
+#endif
+ pjobs++;
+ omask = sigblock(sigmask(SIGCHLD));
+loop:
+ for (pp = proclist.p_next; pp; pp = pp->p_next)
+ if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */
+ pp->p_flags&PRUNNING) {
+ sigpause(0);
+ goto loop;
+ }
+ (void) sigsetmask(omask);
+ pjobs = 0;
+}
+
+/*
+ * pflushall - flush all jobs from list (e.g. at fork())
+ */
+pflushall()
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- pflush()\n");
+#endif
+ for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)
+ if (pp->p_pid)
+ pflush(pp);
+}
+
+/*
+ * pflush - flag all process structures in the same job as the
+ * the argument process for deletion. The actual free of the
+ * space is not done here since pflush is called at interrupt level.
+ */
+pflush(pp)
+ register struct process *pp;
+{
+ register struct process *np;
+ register int index;
+
+#ifdef TRACE
+ tprintf("TRACE- pflush()\n");
+#endif
+ if (pp->p_pid == 0) {
+ printf("BUG: process flushed twice");
+ return;
+ }
+ while (pp->p_pid != pp->p_jobid)
+ pp = pp->p_friends;
+ pclrcurr(pp);
+ if (pp == pcurrjob)
+ pcurrjob = 0;
+ index = pp->p_index;
+ np = pp;
+ do {
+ np->p_index = np->p_pid = 0;
+ np->p_flags &= ~PNEEDNOTE;
+ } while ((np = np->p_friends) != pp);
+ if (index == pmaxindex) {
+ for (np = proclist.p_next, index = 0; np; np = np->p_next)
+ if (np->p_index > (tchar)index)
+ index = np->p_index;
+ pmaxindex = index;
+ }
+}
+
+/*
+ * pclrcurr - make sure the given job is not the current or previous job;
+ * pp MUST be the job leader
+ */
+pclrcurr(pp)
+ register struct process *pp;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- pclrcurr()\n");
+#endif
+ if (pp == pcurrent)
+ if (pprevious != PNULL) {
+ pcurrent = pprevious;
+ pprevious = pgetcurr(pp);
+ } else {
+ pcurrent = pgetcurr(pp);
+ pprevious = pgetcurr(pp);
+ }
+ else if (pp == pprevious)
+ pprevious = pgetcurr(pp);
+}
+
+/* +4 here is 1 for '\0', 1 ea for << >& >> */
+tchar command[PMAXLEN+4];
+int cmdlen;
+tchar *cmdp;
+/*
+ * palloc - allocate a process structure and fill it up.
+ * an important assumption is made that the process is running.
+ */
+palloc(pid, t)
+ int pid;
+ register struct command *t;
+{
+ register struct process *pp;
+ int i;
+
+#ifdef TRACE
+ tprintf("TRACE- palloc()\n");
+#endif
+ pp = (struct process *)calloc(1, sizeof(struct process));
+ pp->p_pid = pid;
+ pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;
+ if (t->t_dflg & FTIME)
+ pp->p_flags |= PPTIME;
+ cmdp = command;
+ cmdlen = 0;
+ padd(t);
+ *cmdp++ = 0;
+ if (t->t_dflg & FPOU) {
+ pp->p_flags |= PPOU;
+ if (t->t_dflg & FDIAG)
+ pp->p_flags |= PDIAG;
+ }
+ pp->p_command = savestr(command);
+ if (pcurrjob) {
+ struct process *fp;
+ /* careful here with interrupt level */
+ pp->p_cwd = 0;
+ pp->p_index = pcurrjob->p_index;
+ pp->p_friends = pcurrjob;
+ pp->p_jobid = pcurrjob->p_pid;
+ for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
+ ;
+ fp->p_friends = pp;
+ } else {
+ pcurrjob = pp;
+ pp->p_jobid = pid;
+ pp->p_friends = pp;
+ pp->p_cwd = dcwd;
+ dcwd->di_count++;
+ if (pmaxindex < BIGINDEX)
+ pp->p_index = ++pmaxindex;
+ else {
+ struct process *np;
+
+ for (i = 1; ; i++) {
+ for (np = proclist.p_next; np; np = np->p_next)
+ if (np->p_index == i)
+ goto tryagain;
+ pp->p_index = i;
+ if (i > pmaxindex)
+ pmaxindex = i;
+ break;
+ tryagain:;
+ }
+ }
+ pprevious = pcurrent;
+ pcurrent = pp;
+ }
+ pp->p_next = proclist.p_next;
+ proclist.p_next = pp;
+ (void) gettimeofday(&pp->p_btime, (struct timezone *)0);
+}
+
+padd(t)
+ register struct command *t;
+{
+ tchar **argp;
+
+#ifdef TRACE
+ tprintf("TRACE- padd()\n");
+#endif
+ if (t == 0)
+ return;
+ switch (t->t_dtyp) {
+
+ case TPAR:
+ pads(S_LBRASP /*"( "*/);
+ padd(t->t_dspr);
+ pads(S_SPRBRA /*" )"*/);
+ break;
+
+ case TCOM:
+ for (argp = t->t_dcom; *argp; argp++) {
+ pads(*argp);
+ if (argp[1])
+ pads(S_SP /*" "*/);
+ }
+ break;
+
+ case TOR:
+ case TAND:
+ case TFIL:
+ case TLST:
+ padd(t->t_dcar);
+ switch (t->t_dtyp) {
+ case TOR:
+ pads(S_SPBARBARSP /*" || " */);
+ break;
+ case TAND:
+ pads(S_SPANDANDSP /*" && "*/);
+ break;
+ case TFIL:
+ pads(S_SPBARSP /*" | "*/);
+ break;
+ case TLST:
+ pads(S_SEMICOLONSP /*"; "*/);
+ break;
+ }
+ padd(t->t_dcdr);
+ return;
+ }
+ if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {
+ pads((t->t_dflg & FHERE) ? S_SPLESLESSP /*" << " */ : S_SPLESSP /*" < "*/);
+ pads(t->t_dlef);
+ }
+ if ((t->t_dflg & FPOU) == 0 && t->t_drit) {
+ pads((t->t_dflg & FCAT) ? S_SPGTRGTRSP /*" >>" */ : S_SPGTR /*" >"*/);
+ if (t->t_dflg & FDIAG)
+ pads(S_AND /*"&"*/);
+ pads(S_SP /*" "*/);
+ pads(t->t_drit);
+ }
+}
+
+pads(cp)
+ tchar *cp;
+{
+ register int i = strlen_(cp);
+
+#ifdef TRACE
+ tprintf("TRACE- pads()\n");
+#endif
+ if (cmdlen >= PMAXLEN)
+ return;
+ if (cmdlen + i >= PMAXLEN) {
+ (void) strcpy_(cmdp, S_SPPPP /*" ..."*/);
+ cmdlen = PMAXLEN;
+ cmdp += 4;
+ return;
+ }
+ (void) strcpy_(cmdp, cp);
+ cmdp += i;
+ cmdlen += i;
+}
+
+/*
+ * psavejob - temporarily save the current job on a one level stack
+ * so another job can be created. Used for { } in exp6
+ * and `` in globbing.
+ */
+psavejob()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- psavejob()\n");
+#endif
+ pholdjob = pcurrjob;
+ pcurrjob = PNULL;
+}
+
+/*
+ * prestjob - opposite of psavejob. This may be missed if we are interrupted
+ * somewhere, but pendjob cleans up anyway.
+ */
+prestjob()
+{
+
+#ifdef TRACE
+ tprintf("TRACE- prestjob()\n");
+#endif
+ pcurrjob = pholdjob;
+ pholdjob = PNULL;
+}
+
+/*
+ * pendjob - indicate that a job (set of commands) has been completed
+ * or is about to begin.
+ */
+pendjob()
+{
+ register struct process *pp, *tp;
+
+#ifdef TRACE
+ tprintf("TRACE- pendjob()\n");
+#endif
+ if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {
+ pp = pcurrjob;
+ while (pp->p_pid != pp->p_jobid)
+ pp = pp->p_friends;
+ printf("[%d]", pp->p_index);
+ tp = pp;
+ do {
+ printf(" %d", pp->p_pid);
+ pp = pp->p_friends;
+ } while (pp != tp);
+ printf("\n");
+ }
+ pholdjob = pcurrjob = 0;
+}
+
+/*
+ * pprint - print a job
+ */
+pprint(pp, flag)
+ register struct process *pp;
+{
+ register status, reason;
+ struct process *tp;
+ extern char *linp, linbuf[];
+ int jobflags, pstatus;
+ char *format;
+
+#ifdef TRACE
+ tprintf("TRACE- pprint()\n");
+#endif
+ while (pp->p_pid != pp->p_jobid)
+ pp = pp->p_friends;
+ if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
+ pp->p_flags &= ~PPTIME;
+ pp->p_flags |= PTIME;
+ }
+ tp = pp;
+ status = reason = -1;
+ jobflags = 0;
+ do {
+ jobflags |= pp->p_flags;
+ pstatus = pp->p_flags & PALLSTATES;
+ if (tp != pp && linp != linbuf && !(flag&FANCY) &&
+ (pstatus == status && pp->p_reason == reason ||
+ !(flag&REASON)))
+ printf(" ");
+ else {
+ if (tp != pp && linp != linbuf)
+ printf("\n");
+ if(flag&NUMBER)
+ if (pp == tp)
+ printf("[%d]%s %c ", pp->p_index,
+ pp->p_index < 10 ? " " : "",
+ pp==pcurrent ? '+' :
+ (pp == pprevious ? (tchar) '-'
+ : (tchar) ' '));
+ else
+ printf(" ");
+ if (flag&FANCY)
+ printf("%5d ", pp->p_pid);
+ if (flag&(REASON|AREASON)) {
+ if (flag&NAME)
+ format = "%-21s";
+ else
+ format = "%s";
+ if (pstatus == status)
+ if (pp->p_reason == reason) {
+ printf(format, "");
+ goto prcomd;
+ } else
+ reason = pp->p_reason;
+ else {
+ status = pstatus;
+ reason = pp->p_reason;
+ }
+ switch (status) {
+
+ case PRUNNING:
+ printf(format, "Running ");
+ break;
+
+ case PINTERRUPTED:
+ case PSTOPPED:
+ case PSIGNALED:
+ if ((flag&(REASON|AREASON))
+ && reason != SIGINT
+ && reason != SIGPIPE)
+ printf(format,
+ strsignal(pp->p_reason));
+ break;
+
+ case PNEXITED:
+ case PAEXITED:
+ if (flag & REASON)
+ if (pp->p_reason)
+ printf("Exit %-16d", pp->p_reason);
+ else
+ printf(format, "Done");
+ break;
+
+ default:
+ printf("BUG: status=%-9o", status);
+ }
+ }
+ }
+prcomd:
+ if (flag&NAME) {
+ printf("%t", pp->p_command);
+ if (pp->p_flags & PPOU)
+ printf(" |");
+ if (pp->p_flags & PDIAG)
+ printf("&");
+ }
+ if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED)
+ printf(" (core dumped)");
+ if (tp == pp->p_friends) {
+ if (flag&AMPERSAND)
+ printf(" &");
+ if (flag&JOBDIR &&
+ !eq(tp->p_cwd->di_name, dcwd->di_name)) {
+ printf(" (wd: ");
+ dtildepr(value(S_home /*"home"*/), tp->p_cwd->di_name);
+ printf(")");
+ }
+ }
+ if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) {
+ if (linp != linbuf)
+ printf("\n\t");
+ { static struct rusage zru;
+ prusage(&zru, &pp->p_rusage, &pp->p_etime,
+ &pp->p_btime);
+ }
+ }
+ if (tp == pp->p_friends) {
+ if (linp != linbuf)
+ printf("\n");
+ if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
+ printf("(wd now: ");
+ dtildepr(value(S_home /* "home" */), dcwd->di_name);
+ printf(")\n");
+ }
+ }
+ } while ((pp = pp->p_friends) != tp);
+ if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) {
+ if (jobflags & NUMBER)
+ printf(" ");
+ ptprint(tp);
+ }
+ return (jobflags);
+}
+
+ptprint(tp)
+ register struct process *tp;
+{
+ struct timeval tetime, diff;
+ static struct timeval ztime;
+ struct rusage ru;
+ static struct rusage zru;
+ register struct process *pp = tp;
+
+#ifdef TRACE
+ tprintf("TRACE- ptprint()\n");
+#endif
+ ru = zru;
+ tetime = ztime;
+ do {
+ ruadd(&ru, &pp->p_rusage);
+ tvsub(&diff, &pp->p_etime, &pp->p_btime);
+ if (timercmp(&diff, &tetime, >))
+ tetime = diff;
+ } while ((pp = pp->p_friends) != tp);
+ prusage(&zru, &ru, &tetime, &ztime);
+}
+
+/*
+ * dojobs - print all jobs
+ */
+dojobs(v)
+ tchar **v;
+{
+ register struct process *pp;
+ register int flag = NUMBER|NAME|REASON;
+ int i;
+
+#ifdef TRACE
+ tprintf("TRACE- dojobs()\n");
+#endif
+ if (chkstop)
+ chkstop = 2;
+ if (*++v) {
+ if (v[1] || !eq(*v, S_DASHl /*"-l"*/))
+ error("Usage: jobs [ -l ]");
+ flag |= FANCY|JOBDIR;
+ }
+ for (i = 1; i <= pmaxindex; i++)
+ for (pp = proclist.p_next; pp; pp = pp->p_next)
+ if (pp->p_index == i && pp->p_pid == pp->p_jobid) {
+ pp->p_flags &= ~PNEEDNOTE;
+ if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED)))
+ pflush(pp);
+ break;
+ }
+}
+
+/*
+ * dofg - builtin - put the job into the foreground
+ */
+dofg(v)
+ tchar **v;
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- dofg()\n");
+#endif
+ okpcntl();
+ ++v;
+ do {
+ pp = pfind(*v);
+ pstart(pp, 1);
+ pjwait(pp);
+ } while (*v && *++v);
+}
+
+/*
+ * %... - builtin - put the job into the foreground
+ */
+dofg1(v)
+ tchar **v;
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- untty()\n");
+#endif
+ okpcntl();
+ pp = pfind(v[0]);
+ pstart(pp, 1);
+ pjwait(pp);
+}
+
+/*
+ * dobg - builtin - put the job into the background
+ */
+dobg(v)
+ tchar **v;
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- dobg()\n");
+#endif
+ okpcntl();
+ ++v;
+ do {
+ pp = pfind(*v);
+ pstart(pp, 0);
+ } while (*v && *++v);
+}
+
+/*
+ * %... & - builtin - put the job into the background
+ */
+dobg1(v)
+ tchar **v;
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- dobg1()\n");
+#endif
+ pp = pfind(v[0]);
+ pstart(pp, 0);
+}
+
+/*
+ * dostop - builtin - stop the job
+ */
+dostop(v)
+ tchar **v;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- dostop()\n");
+#endif
+ pkill(++v, SIGSTOP);
+}
+
+/*
+ * dokill - builtin - superset of kill (1)
+ */
+dokill(v)
+ tchar **v;
+{
+ register int signum;
+ register tchar *name;
+
+#ifdef TRACE
+ tprintf("TRACE- dokill()\n");
+#endif
+ v++;
+ if (v[0] && v[0][0] == '-') {
+ if (v[0][1] == 'l') {
+ for (signum = 1; signum <= NSIG-1; signum++) {
+ char sbuf[BUFSIZ];
+ if (sig2str(signum, sbuf) == 0)
+ printf("%s ", sbuf);
+ if (signum % 8 == 0)
+ Putchar('\n');
+ }
+ Putchar('\n');
+ return;
+ }
+ if (digit(v[0][1])) {
+ signum = atoi_(v[0]+1);
+ if (signum < 0 || signum > NSIG)
+ bferr("Bad signal number");
+ } else {
+ int signo;
+ char sbuf[BUFSIZ];
+ name = &v[0][1];
+ tstostr(sbuf, name);
+ if (str2sig(sbuf, &signo) == 0) {
+ signum = signo;
+ goto gotsig;
+ }
+ if (eq(name, S_IOT /*"IOT"*/)) {
+ signum = SIGABRT;
+ goto gotsig;
+ }
+ setname(name);
+ bferr("Unknown signal; kill -l lists signals");
+ }
+gotsig:
+ v++;
+ } else
+ signum = SIGTERM;
+ pkill(v, signum);
+}
+
+pkill(v, signum)
+ tchar **v;
+ int signum;
+{
+ register struct process *pp, *np;
+ register int jobflags = 0;
+ int omask, pid, err = 0;
+ tchar *cp;
+
+#ifdef TRACE
+ tprintf("TRACE- pkill()\n");
+#endif
+ omask = sigmask(SIGCHLD);
+ if (setintr)
+ omask |= sigmask(SIGINT);
+ omask = sigblock(omask) & ~omask;
+ while (*v) {
+ cp = globone(*v);
+ if (*cp == '%') {
+ np = pp = pfind(cp);
+ do
+ jobflags |= np->p_flags;
+ while ((np = np->p_friends) != pp);
+ switch (signum) {
+
+ case SIGSTOP:
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ if ((jobflags & PRUNNING) == 0) {
+ /* %s -> %t */
+ printf("%t: Already stopped\n", cp);
+ err++;
+ goto cont;
+ }
+ }
+ if (killpg(pp->p_jobid, signum) < 0) {
+ /* %s -> %t */
+ printf("%t: ", cp);
+ printf("%s\n", strerror(errno));
+ err++;
+ }
+ if (signum == SIGTERM || signum == SIGHUP)
+ (void) killpg(pp->p_jobid, SIGCONT);
+ } else if (!(digit(*cp) || *cp == '-'))
+ bferr("Arguments should be jobs or process id's");
+ else {
+ pid = atoi_(cp);
+ if (kill(pid, signum) < 0) {
+ printf("%d: ", pid);
+ printf("%s\n", strerror(errno));
+ err++;
+ goto cont;
+ }
+ if (signum == SIGTERM || signum == SIGHUP)
+ (void) kill(pid, SIGCONT);
+ }
+cont:
+ xfree(cp);
+ v++;
+ }
+ (void) sigsetmask(omask);
+ if (err)
+ error(NULL);
+}
+
+/*
+ * pstart - start the job in foreground/background
+ */
+pstart(pp, foregnd)
+ register struct process *pp;
+ int foregnd;
+{
+ register struct process *np;
+ int omask, jobflags = 0;
+
+#ifdef TRACE
+ tprintf("TRACE- pstart()\n");
+#endif
+ omask = sigblock(sigmask(SIGCHLD));
+ np = pp;
+ do {
+ jobflags |= np->p_flags;
+ if (np->p_flags&(PRUNNING|PSTOPPED)) {
+ np->p_flags |= PRUNNING;
+ np->p_flags &= ~PSTOPPED;
+ if (foregnd)
+ np->p_flags |= PFOREGND;
+ else
+ np->p_flags &= ~PFOREGND;
+ }
+ } while((np = np->p_friends) != pp);
+
+ if (foregnd)
+ pclrcurr(pp);
+ else
+ {
+ if ( pprevious && (pprevious->p_flags & PSTOPPED) )
+ {
+ pcurrent = pprevious;
+ pprevious = pgetcurr(PNULL);
+ }
+ else
+ {
+ pcurrent = pgetcurr(pp);
+ if ( !pcurrent || (pcurrent->p_flags & PRUNNING) )
+ pcurrent = pp;
+ else
+ pprevious = pp;
+ }
+ }
+ (void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND);
+ if (foregnd)
+ (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid);
+ if (jobflags&PSTOPPED)
+ (void) killpg(pp->p_jobid, SIGCONT);
+ (void) sigsetmask(omask);
+}
+
+panystop(neednl)
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- panystop()\n");
+#endif
+ chkstop = 2;
+ for (pp = proclist.p_next; pp; pp = pp->p_next)
+ if (pp->p_flags & PSTOPPED)
+ error("\nThere are stopped jobs" + 1 - neednl);
+}
+
+struct process *
+pfind(cp)
+ tchar *cp;
+{
+ register struct process *pp, *np;
+
+#ifdef TRACE
+ tprintf("TRACE- pfind()\n");
+#endif
+ if (cp == 0 || cp[1] == 0 || eq(cp, S_PARCENTPARCENT /*"%%"*/) ||
+ eq(cp, S_PARCENTPLUS /*"%+"*/)) {
+ if (pcurrent == PNULL)
+ if ( (pcurrent = pgetcurr(PNULL)) == PNULL )
+ bferr("No current job");
+ return (pcurrent);
+ }
+ if (eq(cp, S_PARCENTMINUS /*"%-"*/) ||
+ eq(cp, S_PARCENTSHARP /*"%#"*/)) {
+ if (pprevious == PNULL)
+ bferr("No previous job");
+ return (pprevious);
+ }
+ if (digit(cp[1])) {
+ int index = atoi_(cp+1);
+ for (pp = proclist.p_next; pp; pp = pp->p_next)
+ if (pp->p_index == index && pp->p_pid == pp->p_jobid)
+ return (pp);
+ bferr("No such job");
+ }
+ np = PNULL;
+ for (pp = proclist.p_next; pp; pp = pp->p_next)
+ if (pp->p_pid == pp->p_jobid) {
+ if (cp[1] == '?') {
+ register tchar *dp;
+ for (dp = pp->p_command; *dp; dp++) {
+ if (*dp != cp[2])
+ continue;
+ if (prefix(cp+2, dp))
+ goto match;
+ }
+ } else if (prefix(cp+1, pp->p_command)) {
+match:
+ if (np)
+ bferr("Ambiguous");
+ np = pp;
+ }
+ }
+ if (np)
+ return (np);
+ if (cp[1] == '?')
+ bferr("No job matches pattern");
+ else
+ bferr("No such job");
+ /*NOTREACHED*/
+}
+
+/*
+ * pgetcurr - find most recent job that is not pp, preferably stopped
+ */
+struct process *
+pgetcurr(pp)
+ register struct process *pp;
+{
+ register struct process *np;
+ register struct process *xp = PNULL;
+
+#ifdef TRACE
+ tprintf("TRACE- pgetcurr()\n");
+#endif
+ for (np = proclist.p_next; np; np = np->p_next)
+ if (np != pcurrent && np != pp && np->p_pid &&
+ np->p_pid == np->p_jobid) {
+ if (np->p_flags & PSTOPPED)
+ return (np);
+ if (xp == PNULL)
+ xp = np;
+ }
+ return (xp);
+}
+
+/*
+ * donotify - flag the job so as to report termination asynchronously
+ */
+donotify(v)
+ tchar **v;
+{
+ register struct process *pp;
+
+#ifdef TRACE
+ tprintf("TRACE- donotify()\n");
+#endif
+ pp = pfind(*++v);
+ pp->p_flags |= PNOTIFY;
+}
+
+/*
+ * Do the fork and whatever should be done in the child side that
+ * should not be done if we are not forking at all (like for simple builtin's)
+ * Also do everything that needs any signals fiddled with in the parent side
+ *
+ * Wanttty tells whether process and/or tty pgrps are to be manipulated:
+ * -1: leave tty alone; inherit pgrp from parent
+ * 0: already have tty; manipulate process pgrps only
+ * 1: want to claim tty; manipulate process and tty pgrps
+ * It is usually just the value of tpgrp.
+ */
+pfork(t, wanttty)
+ struct command *t; /* command we are forking for */
+ int wanttty;
+{
+ register int pid;
+ bool ignint = 0;
+ int pgrp, omask;
+ int child_pid;
+
+#ifdef TRACE
+ tprintf("TRACE- pfork()\n");
+#endif
+ /*
+ * A child will be uninterruptible only under very special
+ * conditions. Remember that the semantics of '&' is
+ * implemented by disconnecting the process from the tty so
+ * signals do not need to ignored just for '&'.
+ * Thus signals are set to default action for children unless:
+ * we have had an "onintr -" (then specifically ignored)
+ * we are not playing with signals (inherit action)
+ */
+ if (setintr)
+ ignint = (tpgrp == -1 && (t->t_dflg&FINT))
+ || (gointr && eq(gointr, S_MINUS /*"-"*/));
+ /*
+ * Hold SIGCHLD until we have the process installed in our table.
+ */
+ omask = sigblock(sigmask(SIGCHLD));
+ while ((pid = fork()) < 0)
+ if (setintr == 0)
+ sleep(FORKSLEEP);
+ else {
+ (void) sigsetmask(omask);
+ error("Fork failed");
+ }
+
+ /*
+ * setup the process group
+ */
+ if (pid == 0)
+ child_pid = getpid();
+ else
+ child_pid = pid;
+ pgrp = pcurrjob ? pcurrjob->p_jobid : child_pid;
+
+ if (pid == 0) {
+ int sigttou;
+ settimes();
+ pflushall();
+ pcurrjob = PNULL;
+ child++;
+ if (setintr) {
+ setintr = 0; /* until I think otherwise */
+ /*
+ * Children just get blown away on SIGINT, SIGQUIT
+ * unless "onintr -" seen.
+ */
+ (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
+ (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
+ if (wanttty >= 0) {
+ /* make stoppable */
+ (void) signal(SIGTSTP, SIG_DFL);
+ (void) signal(SIGTTIN, SIG_DFL);
+ (void) signal(SIGTTOU, SIG_DFL);
+ }
+ (void) signal(SIGTERM, parterm);
+ } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ }
+ if (wanttty >= 0 && tpgrp >= 0)
+ (void) setpgid(0, pgrp);
+ if (wanttty > 0) {
+ sigttou = sigblock (sigmask(SIGTTOU)|
+ sigmask(SIGTTIN)|
+ sigmask(SIGTSTP));
+ (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp);
+ sigsetmask (sigttou);
+ }
+ if (tpgrp > 0)
+ tpgrp = 0; /* gave tty away */
+ /*
+ * Nohup and nice apply only to TCOM's but it would be
+ * nice (?!?) if you could say "nohup (foo;bar)"
+ * Then the parser would have to know about nice/nohup/time
+ */
+ if (t->t_dflg & FNOHUP)
+ (void) signal(SIGHUP, SIG_IGN);
+ if (t->t_dflg & FNICE)
+ (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
+ } else {
+ if (wanttty >= 0 && tpgrp >= 0)
+ setpgid(pid, pgrp);
+ palloc(pid, t);
+ (void) sigsetmask(omask);
+ }
+
+ return (pid);
+}
+
+okpcntl()
+{
+#ifdef TRACE
+ tprintf("TRACE- okpcntl()\n");
+#endif
+
+ if (tpgrp == -1)
+ error("No job control in this shell");
+ if (tpgrp == 0)
+ error("No job control in subshells");
+}
+
diff --git a/usr/src/cmd/csh/sh.proc.h b/usr/src/cmd/csh/sh.proc.h
new file mode 100644
index 0000000000..63e39ef437
--- /dev/null
+++ b/usr/src/cmd/csh/sh.proc.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * C shell - process structure declarations
+ */
+
+/*
+ * Structure for each process the shell knows about:
+ * allocated and filled by pcreate.
+ * flushed by pflush; freeing always happens at top level
+ * so the interrupt level has less to worry about.
+ * processes are related to "friends" when in a pipeline;
+ * p_friends links makes a circular list of such jobs
+ */
+struct process {
+ struct process *p_next; /* next in global "proclist" */
+ struct process *p_friends; /* next in job list (or self) */
+ struct directory *p_cwd; /* cwd of the job (only in head) */
+ short unsigned p_flags; /* various job status flags */
+ tchar p_reason; /* reason for entering this state */
+ tchar p_index; /* shorthand job index */
+ int p_pid;
+ int p_jobid; /* pid of job leader */
+ /* if a job is stopped/background p_jobid gives its pgrp */
+ struct timeval p_btime; /* begin time */
+ struct timeval p_etime; /* end time */
+ struct rusage p_rusage;
+ tchar *p_command; /* first PMAXLEN chars of command */
+};
+
+/* added for status */
+#define ABN_TERM 0200
+
+/* flag values for p_flags */
+#define PRUNNING (1<<0) /* running */
+#define PSTOPPED (1<<1) /* stopped */
+#define PNEXITED (1<<2) /* normally exited */
+#define PAEXITED (1<<3) /* abnormally exited */
+#define PSIGNALED (1<<4) /* terminated by a signal != SIGINT */
+
+#define PALLSTATES (PRUNNING|PSTOPPED|PNEXITED|PAEXITED|PSIGNALED|PINTERRUPTED)
+#define PNOTIFY (1<<5) /* notify async when done */
+#define PTIME (1<<6) /* job times should be printed */
+#define PAWAITED (1<<7) /* top level is waiting for it */
+#define PFOREGND (1<<8) /* started in shells pgrp */
+#define PDUMPED (1<<9) /* process dumped core */
+#define PDIAG (1<<10) /* diagnostic output also piped out */
+#define PPOU (1<<11) /* piped output */
+#define PREPORTED (1<<12) /* status has been reported */
+#define PINTERRUPTED (1<<13) /* job stopped via interrupt signal */
+#define PPTIME (1<<14) /* time individual process */
+#define PNEEDNOTE (1<<15) /* notify as soon as practical */
+
+#define PNULL (struct process *)0
+#define PMAXLEN 80
+
+/* defines for arguments to pprint */
+#define NUMBER 01
+#define NAME 02
+#define REASON 04
+#define AMPERSAND 010
+#define FANCY 020
+#define SHELLDIR 040 /* print shell's dir if not the same */
+#define JOBDIR 0100 /* print job's dir if not the same */
+#define AREASON 0200
+
+struct process proclist; /* list head of all processes */
+bool pnoprocesses; /* pchild found nothing to wait for */
+
+struct process *pholdjob; /* one level stack of current jobs */
+
+struct process *pcurrjob; /* current job */
+struct process *pcurrent; /* current job in table */
+struct process *pprevious; /* previous job in table */
+
+short pmaxindex; /* current maximum job index */
+
+int psigint();
+struct process *pgetcurr();
+struct process *plookup();
+struct process *pfind();
diff --git a/usr/src/cmd/csh/sh.sem.c b/usr/src/cmd/csh/sh.sem.c
new file mode 100644
index 0000000000..e55a747e12
--- /dev/null
+++ b/usr/src/cmd/csh/sh.sem.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include "sh.h"
+#include "sh.proc.h"
+#include "sh.tconst.h"
+
+/*
+ * C shell
+ */
+
+/*
+ * Return true if there is a back-quote (`) anywhere in the argument list.
+ * Its presence would cause glob() to be invoked in the child process
+ * and this would cause chaos if the child is created with vfork().
+ */
+static bool
+AnyBquote(struct command *t)
+{
+ tchar **pp;
+ tchar *p;
+
+ if (noexec)
+ return (0);
+ for (pp = t->t_dcom; p = *pp++;) {
+ if (any('`', p))
+ return (1);
+ }
+ return (0);
+}
+
+/*VARARGS 1*/
+execute(t, wanttty, pipein, pipeout)
+ register struct command *t;
+ int wanttty, *pipein, *pipeout;
+{
+ bool forked = 0;
+ struct biltins *bifunc;
+ int pid = 0;
+ int pv[2];
+ extern int globcnt;
+#ifdef TRACE
+ tprintf("TRACE- execute()\n");
+#endif
+
+ if (t == 0)
+ return;
+ if ((t->t_dflg & FAND) && wanttty > 0)
+ wanttty = 0;
+ switch (t->t_dtyp) {
+
+ case TCOM:
+ if (t->t_dcom[0][0] == (tchar)S_TOPBIT[0])
+ (void) strcpy_(t->t_dcom[0], t->t_dcom[0] + 1);
+ if ((t->t_dflg & FREDO) == 0)
+ Dfix(t); /* $ " ' \ */
+ if (t->t_dcom[0] == 0)
+ return;
+ /* fall into... */
+
+ case TPAR:
+ if (t->t_dflg & FPOU)
+ mypipe(pipeout);
+ /*
+ * Must do << early so parent will know
+ * where input pointer should be.
+ * If noexec then this is all we do.
+ */
+ if (t->t_dflg & FHERE) {
+ (void) close(0);
+ unsetfd(0);
+ heredoc(t->t_dlef);
+ if (noexec) {
+ (void) close(0);
+ unsetfd(0);
+ }
+ }
+ if (noexec)
+ break;
+
+ set(S_status, S_0);
+
+ /*
+ * This mess is the necessary kludge to handle the prefix
+ * builtins: nice, nohup, time. These commands can also
+ * be used by themselves, and this is not handled here.
+ * This will also work when loops are parsed.
+ */
+ while (t->t_dtyp == TCOM)
+ if (eq(t->t_dcom[0], S_nice /*"nice"*/))
+ if (t->t_dcom[1])
+ /*if (any(t->t_dcom[1][0], "+-"))*/
+ if (t->t_dcom[1][0] == '+' ||
+ t->t_dcom[1][0] == '-')
+ if (t->t_dcom[2]) {
+ setname(S_nice /*"nice"*/);
+ t->t_nice = getn(t->t_dcom[1]);
+ lshift(t->t_dcom, 2);
+ t->t_dflg |= FNICE;
+ } else
+ break;
+ else {
+ t->t_nice = 4;
+ lshift(t->t_dcom, 1);
+ t->t_dflg |= FNICE;
+ }
+ else
+ break;
+ else if (eq(t->t_dcom[0], S_nohup /*"nohup"*/))
+ if (t->t_dcom[1]) {
+ t->t_dflg |= FNOHUP;
+ lshift(t->t_dcom, 1);
+ } else
+ break;
+ else if (eq(t->t_dcom[0], S_time /*"time"*/))
+ if (t->t_dcom[1]) {
+ t->t_dflg |= FTIME;
+ lshift(t->t_dcom, 1);
+ } else
+ break;
+ else
+ break;
+ /*
+ * Check if we have a builtin function and remember which one.
+ */
+ bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0;
+
+ /*
+ * We fork only if we are timed, or are not the end of
+ * a parenthesized list and not a simple builtin function.
+ * Simple meaning one that is not pipedout, niced, nohupped,
+ * or &'d.
+ * It would be nice(?) to not fork in some of these cases.
+ */
+ if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 &&
+ (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP))))
+#ifdef VFORK
+ if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) ||
+ bifunc || AnyBquote(t))
+#endif
+ { forked++; pid = pfork(t, wanttty); }
+#ifdef VFORK
+ else {
+ void vffree();
+ struct sv {
+ int mask, child, setintr, haderr, didfds;
+ int SHIN, SHOUT, SHDIAG, OLDSTD, tpgrp;
+ struct sigvec sigv;
+ } sv;
+
+ /*
+ * Prepare for the vfork by saving everything
+ * that the child corrupts before it exec's.
+ * Note that in some signal implementations
+ * which keep the signal info in user space
+ * (e.g. Sun's) it will also be necessary to
+ * save and restore the current sigvec's for
+ * the signals the child touches before it
+ * exec's.
+ */
+ sv.mask = sigblock(sigmask(SIGCHLD));
+ sv.child = child; sv.setintr = setintr;
+ sv.haderr = haderr; sv.didfds = didfds;
+ sv.SHIN = SHIN; sv.SHOUT = SHOUT;
+ sv.SHDIAG = SHDIAG; sv.OLDSTD = OLDSTD;
+ sv.tpgrp = tpgrp;
+ Vsav = Vdp = 0; Vav = 0;
+ (void) sigvec(SIGINT, (struct sigvec *)0, &sv.sigv);
+ pid = vfork();
+ if (pid < 0) {
+ (void) sigsetmask(sv.mask);
+ error("Vfork failed");
+ }
+ forked++;
+ if (pid) { /* parent */
+ int ppid;
+ closelog();
+ child = sv.child; setintr = sv.setintr;
+ haderr = sv.haderr; didfds = sv.didfds;
+ SHIN = sv.SHIN;
+ SHOUT = sv.SHOUT; SHDIAG = sv.SHDIAG;
+ OLDSTD = sv.OLDSTD; tpgrp = sv.tpgrp;
+ xfree(Vsav); Vsav = 0;
+ xfree(Vdp); Vdp = 0;
+ xfree( (tchar *)Vav); Vav = 0;
+ /* this is from pfork() */
+ ppid = pcurrjob ? pcurrjob->p_jobid : pid;
+ if (wanttty >= 0 && tpgrp >= 0)
+ setpgid (ppid, ppid);
+ palloc(pid, t);
+ /*
+ * Restore SIGINT handler.
+ */
+ (void) sigvec(SIGINT, &sv.sigv, (struct sigvec *)0);
+ (void) sigsetmask(sv.mask);
+ } else { /* child */
+ /* this is from pfork() */
+ int pgrp;
+ bool ignint = 0;
+ int sigttou;
+ if (setintr)
+ ignint =
+ (tpgrp == -1 && (t->t_dflg&FINT))
+ || gointr
+ && eq(gointr, S_MINUS/*"-"*/);
+ pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
+ child++;
+ if (setintr) {
+ setintr = 0;
+#ifdef notdef
+ (void) signal(SIGCHLD, SIG_DFL);
+#endif
+ (void) signal(SIGINT, ignint ?
+ SIG_IGN : vffree);
+ (void) signal(SIGQUIT, ignint ?
+ SIG_IGN : SIG_DFL);
+ if (wanttty >= 0) {
+ (void) signal(SIGTSTP, SIG_DFL);
+ (void) signal(SIGTTIN, SIG_DFL);
+ (void) signal(SIGTTOU, SIG_DFL);
+ }
+ (void) signal(SIGTERM, parterm);
+ } else if (tpgrp == -1 && (t->t_dflg&FINT)) {
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ }
+ if (wanttty >= 0 && tpgrp >= 0)
+ (void) setpgid(0, pgrp);
+ if (wanttty > 0) {
+ sigttou = sigblock (
+ sigmask(SIGTTOU) |
+ sigmask(SIGTTIN) |
+ sigmask(SIGTSTP));
+ (void) ioctl(FSHTTY, TIOCSPGRP,
+ (tchar *)&pgrp);
+ sigsetmask (sigttou);
+ }
+ if (tpgrp > 0)
+ tpgrp = 0;
+ if (t->t_dflg & FNOHUP)
+ (void) signal(SIGHUP, SIG_IGN);
+ if (t->t_dflg & FNICE)
+ (void) setpriority(PRIO_PROCESS,
+ 0, t->t_nice);
+ }
+
+ }
+#endif
+ if (pid != 0) {
+ /*
+ * It would be better if we could wait for the
+ * whole job when we knew the last process
+ * had been started. Pwait, in fact, does
+ * wait for the whole job anyway, but this test
+ * doesn't really express our intentions.
+ */
+ if (didfds==0 && t->t_dflg&FPIN) {
+ (void) close(pipein[0]);
+ unsetfd(pipein[0]);
+ (void) close(pipein[1]);
+ unsetfd(pipein[1]);
+ }
+ if ((t->t_dflg & (FPOU|FAND)) == 0)
+ pwait();
+ break;
+ }
+ doio(t, pipein, pipeout);
+ if (t->t_dflg & FPOU) {
+ (void) close(pipeout[0]);
+ (void) unsetfd(pipeout[0]);
+ (void) close(pipeout[1]);
+ (void) unsetfd(pipeout[1]);
+ }
+
+ /*
+ * Perform a builtin function.
+ * If we are not forked, arrange for possible stopping
+ */
+ if (bifunc) {
+ func(t, bifunc);
+ if (forked)
+ exitstat();
+ break;
+ }
+ if (t->t_dtyp != TPAR) {
+ doexec(t);
+ /*NOTREACHED*/
+ }
+ /*
+ * For () commands must put new 0,1,2 in FSH* and recurse
+ */
+ OLDSTD = dcopy(0, FOLDSTD);
+ SHOUT = dcopy(1, FSHOUT);
+ SHDIAG = dcopy(2, FSHDIAG);
+ (void) close(SHIN);
+ (void) unsetfd(SHIN);
+ SHIN = -1;
+ didfds = 0;
+ wanttty = -1;
+ t->t_dspr->t_dflg |= t->t_dflg & FINT;
+ execute(t->t_dspr, wanttty);
+ exitstat();
+
+ case TFIL:
+ t->t_dcar->t_dflg |= FPOU |
+ (t->t_dflg & (FPIN|FAND|FDIAG|FINT));
+ execute(t->t_dcar, wanttty, pipein, pv);
+ t->t_dcdr->t_dflg |= FPIN |
+ (t->t_dflg & (FPOU|FAND|FPAR|FINT));
+ if (wanttty > 0)
+ wanttty = 0; /* got tty already */
+ execute(t->t_dcdr, wanttty, pv, pipeout);
+ break;
+
+ case TLST:
+ if (t->t_dcar) {
+ t->t_dcar->t_dflg |= t->t_dflg & FINT;
+ execute(t->t_dcar, wanttty);
+ /*
+ * In strange case of A&B make a new job after A
+ */
+ if (t->t_dcar->t_dflg&FAND && t->t_dcdr &&
+ (t->t_dcdr->t_dflg&FAND) == 0)
+ pendjob();
+ }
+ if (t->t_dcdr) {
+ t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
+ execute(t->t_dcdr, wanttty);
+ }
+ break;
+
+ case TOR:
+ case TAND:
+ if (t->t_dcar) {
+ t->t_dcar->t_dflg |= t->t_dflg & FINT;
+ execute(t->t_dcar, wanttty);
+ if ((getn(value(S_status/*"status"*/)) == 0) != (t->t_dtyp == TAND))
+ return;
+ }
+ if (t->t_dcdr) {
+ t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT);
+ execute(t->t_dcdr, wanttty);
+ }
+ break;
+ }
+ /*
+ * Fall through for all breaks from switch
+ *
+ * If there will be no more executions of this
+ * command, flush all file descriptors.
+ * Places that turn on the FREDO bit are responsible
+ * for doing donefds after the last re-execution
+ */
+ if (didfds && !(t->t_dflg & FREDO))
+ donefds();
+
+ /*
+ * If glob() was called and arguments list is not yet
+ * free'ed, free them here.
+ */
+ if (gargv) {
+ blkfree(gargv);
+ gargv = 0;
+ globcnt = 0;
+ }
+}
+
+#ifdef VFORK
+void
+vffree()
+{
+ register tchar **v;
+
+#ifdef TRACE
+ tprintf("TRACE- vffree()\n");
+#endif
+ if (v = gargv)
+ gargv = 0, xfree( (tchar *)v);
+ if (v = pargv)
+ pargv = 0, xfree( (tchar *)v);
+ _exit(1);
+}
+#endif
+
+/*
+ * Perform io redirection.
+ * We may or maynot be forked here.
+ */
+doio(t, pipein, pipeout)
+ register struct command *t;
+ int *pipein, *pipeout;
+{
+ register tchar *cp, *dp;
+ register int flags = t->t_dflg;
+ int fd;
+
+#ifdef TRACE
+ tprintf("TRACE- doio()\n");
+#endif
+ if (didfds || (flags & FREDO))
+ return;
+ if ((flags & FHERE) == 0) { /* FHERE already done */
+ (void) close(0);
+ (void) unsetfd(0);
+ if (cp = t->t_dlef) {
+ dp = Dfix1(cp);
+ cp = globone(dp);
+ xfree(dp);
+ xfree(cp);
+ if (open_(cp, 0) < 0)
+ Perror(cp);
+ } else if (flags & FPIN) {
+ fd = dup(pipein[0]);
+ if (fd != -1)
+ setfd(fd);
+ (void) close(pipein[0]);
+ (void) unsetfd(pipein[0]);
+ (void) close(pipein[1]);
+ (void) unsetfd(pipein[1]);
+ } else if ((flags & FINT) && tpgrp == -1) {
+ (void) close(0); /* no need for unsetfd */
+ (void) open("/dev/null", 0); /* no need for setfd */
+ } else {
+ fd = dup(OLDSTD);
+ if (fd != -1)
+ setfd(fd);
+ }
+ }
+ (void) close(1);
+ (void) unsetfd(1);
+ if (cp = t->t_drit) {
+ dp = Dfix1(cp);
+ cp = globone(dp);
+ xfree(dp);
+ if ((flags & FCAT) && open_(cp, 1) >= 0)
+ (void) lseek(1, (off_t)0, 2);
+ else {
+ if (!(flags & FANY) && adrof(S_noclobber/*"noclobber"*/)) {
+ if (flags & FCAT)
+ Perror(cp);
+ chkclob(cp);
+ }
+ if (creat_(cp, 0666) < 0)
+ Perror(cp);
+ }
+ xfree(cp);
+ } else if (flags & FPOU) {
+ fd = dup(pipeout[1]);
+ if (fd != -1)
+ setfd (fd);
+ }
+ else {
+ fd = dup(SHOUT);
+ if (fd != -1)
+ setfd(fd);
+ }
+
+ (void) close(2);
+ (void) unsetfd(2);
+ if (flags & FDIAG) {
+ fd = dup(1);
+ if (fd != -1)
+ setfd(fd);
+ }
+ else {
+ fd = dup(SHDIAG);
+ if (fd != -1)
+ setfd(fd);
+ }
+ didfds = 1;
+}
+
+mypipe(pv)
+ register int *pv;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- mypipe()\n");
+#endif
+ if (pipe(pv) < 0)
+ goto oops;
+ setfd(pv[0]);
+ setfd(pv[1]);
+
+ pv[0] = dmove(pv[0], -1);
+ pv[1] = dmove(pv[1], -1);
+ if (pv[0] >= 0 && pv[1] >= 0)
+ return;
+oops:
+ error("Can't make pipe");
+}
+
+chkclob(cp)
+ register tchar *cp;
+{
+ struct stat stb;
+ unsigned short type;
+
+#ifdef TRACE
+ tprintf("TRACE- chkclob()\n");
+#endif
+ if (stat_(cp, &stb) < 0)
+ return;
+ type = stb.st_mode & S_IFMT;
+ if (type == S_IFCHR || type == S_IFIFO)
+ return;
+ error("%t: File exists", cp);
+}
diff --git a/usr/src/cmd/csh/sh.set.c b/usr/src/cmd/csh/sh.set.c
new file mode 100644
index 0000000000..b6d03027b6
--- /dev/null
+++ b/usr/src/cmd/csh/sh.set.c
@@ -0,0 +1,804 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+extern didchdir;
+
+/*
+ * C Shell
+ */
+
+doset(v)
+ register tchar **v;
+{
+ register tchar *p;
+ tchar *vp, op;
+ tchar **vecp;
+ bool hadsub;
+ int subscr;
+ tchar *retp;
+
+#ifdef TRACE
+ tprintf("TRACE- doset()\n");
+#endif
+ v++;
+ p = *v++;
+ if (p == 0) {
+ prvars();
+ return;
+ }
+ do {
+ hadsub = 0;
+ /*
+ * check for proper variable syntax
+ * must be alphanumeric, start with a letter and
+ * be at most 20 characters
+ */
+ for (vp = p; alnum(*p); p++)
+ continue;
+ if (vp == p || !letter(*vp))
+ goto setsyn;
+ if ( (p - vp) > MAX_VAR_LEN )
+ bferr("Variable name too long");
+ if (*p == '[') {
+ hadsub++;
+ p = getinx(p, &subscr);
+ }
+ if (op = *p) {
+ *p++ = 0;
+ if (*p == 0 && *v && **v == '(')
+ p = *v++;
+ } else if (*v && eq(*v, S_EQ/*"="*/)) {
+ op = '=', v++;
+ if (*v)
+ p = *v++;
+ }
+ if (op && op != '=')
+setsyn:
+ bferr("Syntax error");
+ if (eq(p, S_LPAR/*"("*/)) {
+ register tchar **e = v;
+
+ if (hadsub)
+ goto setsyn;
+ for (;;) {
+ if (!*e)
+ bferr("Missing )");
+ if (**e == ')')
+ break;
+ e++;
+ }
+ p = *e;
+ *e = 0;
+ vecp = saveblk(v);
+ set1(vp, vecp, &shvhed);
+ *e = p;
+ v = e + 1;
+ } else if (hadsub) {
+ retp = savestr(p);
+ asx(vp, subscr, retp);
+ xfree(retp);
+ retp = 0;
+ } else
+ set(vp, savestr(p));
+ if (eq(vp, S_path/*"path"*/)) {
+ exportpath(adrof(S_path/*"path"*/)->vec);
+ dohash(xhash);
+ } else if (eq(vp, S_histchars/*"histchars"*/)) {
+ register tchar *p = value(S_histchars/*"histchars"*/);
+ HIST = *p++;
+ HISTSUB = *p;
+ } else if (eq(vp, S_user/*"user"*/))
+ local_setenv(S_USER/*"USER"*/, value(vp));
+ else if (eq(vp, S_term/*"term"*/))
+ local_setenv(S_TERM/*"TERM"*/, value(vp));
+ else if (eq(vp, S_home/*"home"*/))
+ local_setenv(S_HOME/*"HOME"*/, value(vp));
+#ifdef FILEC
+ else if (eq(vp, S_filec/*"filec"*/))
+ filec = 1;
+ else if (eq(vp, S_cdpath/*"cdpath"*/))
+ dohash(xhash2);
+#endif
+ } while (p = *v++);
+}
+
+tchar *
+getinx(cp, ip)
+ register tchar *cp;
+ register int *ip;
+{
+
+#ifdef TRACE
+ tprintf("TRACE- getinx()\n");
+#endif
+ *ip = 0;
+ *cp++ = 0;
+ while (*cp && digit(*cp))
+ *ip = *ip * 10 + *cp++ - '0';
+ if (*cp++ != ']')
+ bferr("Subscript error");
+ return (cp);
+}
+
+asx(vp, subscr, p)
+ tchar *vp;
+ int subscr;
+ tchar *p;
+{
+ register struct varent *v = getvx(vp, subscr);
+
+#ifdef TRACE
+ tprintf("TRACE- asx()\n");
+#endif
+ xfree(v->vec[subscr - 1]);
+ v->vec[subscr - 1] = globone(p);
+}
+
+struct varent *
+getvx(vp, subscr)
+ tchar *vp;
+{
+ register struct varent *v = adrof(vp);
+
+#ifdef TRACE
+ tprintf("TRACE- getvx()\n");
+#endif
+ if (v == 0)
+ udvar(vp);
+ if (subscr < 1 || subscr > blklen(v->vec))
+ bferr("Subscript out of range");
+ return (v);
+}
+
+tchar plusplus[2] = { '1', 0 };
+
+dolet(v)
+ tchar **v;
+{
+ register tchar *p;
+ tchar *vp, c, op;
+ bool hadsub;
+ int subscr;
+
+ v++;
+ p = *v++;
+ if (p == 0) {
+ prvars();
+ return;
+ }
+ do {
+ hadsub = 0;
+ for (vp = p; alnum(*p); p++)
+ continue;
+ if (vp == p || !letter(*vp))
+ goto letsyn;
+ if (*p == '[') {
+ hadsub++;
+ p = getinx(p, &subscr);
+ }
+ if (*p == 0 && *v)
+ p = *v++;
+ if (op = *p)
+ *p++ = 0;
+ else
+ goto letsyn;
+ vp = savestr(vp);
+ if (op == '=') {
+ c = '=';
+ p = xset(p, &v);
+ } else {
+ c = *p++;
+ /* if (any(c, "+-")) { */
+ if (c == '+' || c == '-') {
+ if (c != op || *p)
+ goto letsyn;
+ p = plusplus;
+ } else {
+ /*if (any(op, "<>")) {*/
+ if (op == '<' || op == '>') {
+ if (c != op)
+ goto letsyn;
+ c = *p++;
+letsyn:
+ bferr("Syntax error");
+ }
+ if (c != '=')
+ goto letsyn;
+ p = xset(p, &v);
+ }
+ }
+ if (op == '=')
+ if (hadsub)
+ asx(vp, subscr, p);
+ else
+ set(vp, p);
+ else
+ if (hadsub)
+#ifndef V6
+ /* avoid bug in vax CC */
+ {
+ struct varent *gv = getvx(vp, subscr);
+
+ asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
+ }
+#else
+ asx(vp, subscr, operate(op, getvx(vp, subscr)->vec[subscr - 1], p));
+#endif
+ else
+ set(vp, operate(op, value(vp), p));
+ if (eq(vp, S_path/*"path"*/)) {
+ exportpath(adrof(S_path/*"path"*/)->vec);
+ dohash(xhash);
+ }
+
+ if (eq(vp, S_cdpath/*"cdpath"*/))
+ dohash(xhash2);
+
+ XFREE(vp)
+ if (c != '=')
+ XFREE(p)
+ } while (p = *v++);
+}
+
+tchar *
+xset(cp, vp)
+ tchar *cp, ***vp;
+{
+ register tchar *dp;
+
+#ifdef TRACE
+ tprintf("TRACE- xset()\n");
+#endif
+ if (*cp) {
+ dp = savestr(cp);
+ --(*vp);
+ xfree(**vp);
+ **vp = dp;
+ }
+ return (putn(exp(vp)));
+}
+
+tchar *
+operate(op, vp, p)
+ tchar op, *vp, *p;
+{
+ tchar opr[2];
+ tchar *vec[5];
+ register tchar **v = vec;
+ tchar **vecp = v;
+ register int i;
+
+ if (op != '=') {
+ if (*vp)
+ *v++ = vp;
+ opr[0] = op;
+ opr[1] = 0;
+ *v++ = opr;
+ if (op == '<' || op == '>')
+ *v++ = opr;
+ }
+ *v++ = p;
+ *v++ = 0;
+ i = exp(&vecp);
+ if (*vecp)
+ bferr("Expression syntax");
+ return (putn(i));
+}
+
+static tchar *putp;
+
+tchar *
+putn(n)
+ register int n;
+{
+ static tchar number[15];
+
+#ifdef TRACE
+ tprintf("TRACE- putn()\n");
+#endif
+ putp = number;
+ if (n < 0) {
+ n = -n;
+ *putp++ = '-';
+ }
+ if (sizeof (int) == 2 && n == -32768) {
+ *putp++ = '3';
+ n = 2768;
+#ifdef pdp11
+ }
+#else
+ } else if (sizeof (int) == 4 && n == 0x80000000) {
+ *putp++ = '2';
+ n = 147483648;
+ }
+#endif
+ putn1(n);
+ *putp = 0;
+ return (savestr(number));
+}
+
+putn1(n)
+ register int n;
+{
+#ifdef TRACE
+ tprintf("TRACE- putn1()\n");
+#endif
+ if (n > 9)
+ putn1(n / 10);
+ *putp++ = n % 10 + '0';
+}
+
+getn(cp)
+ register tchar *cp;
+{
+ register int n;
+ int sign;
+
+#ifdef TRACE
+ tprintf("TRACE- getn()\n");
+#endif
+ sign = 0;
+ if (cp[0] == '+' && cp[1])
+ cp++;
+ if (*cp == '-') {
+ sign++;
+ cp++;
+ if (!digit(*cp))
+ goto badnum;
+ }
+ n = 0;
+ while (digit(*cp))
+ n = n * 10 + *cp++ - '0';
+ if (*cp)
+ goto badnum;
+ return (sign ? -n : n);
+badnum:
+ bferr("Badly formed number");
+ return (0);
+}
+
+tchar *
+value1(var, head)
+ tchar *var;
+ struct varent *head;
+{
+ register struct varent *vp;
+
+#ifdef TRACE
+ tprintf("TRACE- value1()\n");
+#endif
+ vp = adrof1(var, head);
+ return (vp == 0 || vp->vec[0] == 0 ? S_/*""*/ : vp->vec[0]);
+}
+
+struct varent *
+madrof(pat, vp)
+ tchar *pat;
+ register struct varent *vp;
+{
+ register struct varent *vp1;
+
+#ifdef TRACE
+ tprintf("TRACE- madrof()\n");
+#endif
+ for (; vp; vp = vp->v_right) {
+ if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
+ return vp1;
+ if (Gmatch(vp->v_name, pat))
+ return vp;
+ }
+ return vp;
+}
+
+struct varent *
+adrof1(name, v)
+ register tchar *name;
+ register struct varent *v;
+{
+ register cmp;
+
+#ifdef TRACE
+ tprintf("TRACE- adrof1()\n");
+#endif
+ v = v->v_left;
+ while (v && ((cmp = *name - *v->v_name) ||
+ (cmp = strcmp_(name, v->v_name))))
+ if (cmp < 0)
+ v = v->v_left;
+ else
+ v = v->v_right;
+ return v;
+}
+
+/*
+ * The caller is responsible for putting value in a safe place
+ */
+set(var, val)
+ tchar *var, *val;
+{
+ register tchar **vec = (tchar **) xalloc(2 * sizeof (tchar **));
+
+#ifdef TRACE
+ tprintf("TRACE- set()\n");
+#endif
+ vec[0] = onlyread(val) ? savestr(val) : val;
+ vec[1] = 0;
+ set1(var, vec, &shvhed);
+}
+
+set1(var, vec, head)
+ tchar *var, **vec;
+ struct varent *head;
+{
+ register tchar **oldv = vec;
+
+#ifdef TRACE
+ tprintf("TRACE- set1()\n");
+#endif
+ gflag = 0;
+ /* If setting cwd variable via "set cwd=/tmp/something"
+ * then do globbing. But if we are setting the cwd
+ * becuz of a cd, chdir, pushd, popd, do not do globbing.
+ */
+ if ( (!(eq(var,S_cwd))) || (eq(var,S_cwd) && (didchdir == 0)) )
+ {
+ tglob(oldv);
+ }
+ if (gflag) {
+ vec = glob(oldv);
+ if (vec == 0) {
+ bferr("No match");
+ blkfree(oldv);
+ return;
+ }
+ blkfree(oldv);
+ gargv = 0;
+ }
+ setq(var, vec, head);
+}
+
+setq(name, vec, p)
+ tchar *name, **vec;
+ register struct varent *p;
+{
+ register struct varent *c;
+ register f;
+
+#ifdef TRACE
+ tprintf("TRACE- setq()\n");
+#endif
+ f = 0; /* tree hangs off the header's left link */
+ while (c = p->v_link[f]) {
+ if ((f = *name - *c->v_name) == 0 &&
+ (f = strcmp_(name, c->v_name)) == 0) {
+ blkfree(c->vec);
+ goto found;
+ }
+ p = c;
+ f = f > 0;
+ }
+ p->v_link[f] = c = (struct varent *)xalloc(sizeof (struct varent));
+ c->v_name = savestr(name);
+ c->v_bal = 0;
+ c->v_left = c->v_right = 0;
+ c->v_parent = p;
+ balance(p, f, 0);
+found:
+ trim(c->vec = vec);
+}
+
+unset(v)
+ tchar *v[];
+{
+
+#ifdef TRACE
+ tprintf("TRACE- unset()\n");
+#endif
+ unset1(v, &shvhed);
+ if (adrof(S_histchars/*"histchars"*/) == 0) {
+ HIST = '!';
+ HISTSUB = '^';
+ }
+#ifdef FILEC
+ if (adrof(S_filec/*"filec"*/) == 0)
+ filec = 0;
+#endif
+}
+
+unset1(v, head)
+ register tchar *v[];
+ struct varent *head;
+{
+ register struct varent *vp;
+ register int cnt;
+
+#ifdef TRACE
+ tprintf("TRACE- unset1()\n");
+#endif
+ while (*++v) {
+ cnt = 0;
+ while (vp = madrof(*v, head->v_left))
+ unsetv1(vp), cnt++;
+ if (cnt == 0)
+ setname(*v);
+ }
+}
+
+unsetv(var)
+ tchar *var;
+{
+ register struct varent *vp;
+
+#ifdef TRACE
+ tprintf("TRACE- unsetv()\n");
+#endif
+ if ((vp = adrof1(var, &shvhed)) == 0)
+ udvar(var);
+ unsetv1(vp);
+}
+
+unsetv1(p)
+ register struct varent *p;
+{
+ register struct varent *c, *pp;
+ register f;
+
+#ifdef TRACE
+ tprintf("TRACE- unsetv1()\n");
+#endif
+ /*
+ * Free associated memory first to avoid complications.
+ */
+ blkfree(p->vec);
+ XFREE(p->v_name);
+ /*
+ * If p is missing one child, then we can move the other
+ * into where p is. Otherwise, we find the predecessor
+ * of p, which is guaranteed to have no right child, copy
+ * it into p, and move it's left child into it.
+ */
+ if (p->v_right == 0)
+ c = p->v_left;
+ else if (p->v_left == 0)
+ c = p->v_right;
+ else {
+ for (c = p->v_left; c->v_right; c = c->v_right)
+ ;
+ p->v_name = c->v_name;
+ p->vec = c->vec;
+ p = c;
+ c = p->v_left;
+ }
+ /*
+ * Move c into where p is.
+ */
+ pp = p->v_parent;
+ f = pp->v_right == p;
+ if (pp->v_link[f] = c)
+ c->v_parent = pp;
+ /*
+ * Free the deleted node, and rebalance.
+ */
+ XFREE( (tchar *)p);
+ balance(pp, f, 1);
+}
+
+setNS(cp)
+ tchar *cp;
+{
+#ifdef TRACE
+ tprintf("TRACE- setNS()\n");
+#endif
+
+ set(cp, S_/*""*/);
+}
+
+shift(v)
+ register tchar **v;
+{
+ register struct varent *argv;
+ register tchar *name;
+
+#ifdef TRACE
+ tprintf("TRACE- shift()\n");
+#endif
+ v++;
+ name = *v;
+ if (name == 0)
+ name = S_argv/*"argv"*/;
+ else
+ (void) strip(name);
+ argv = adrof(name);
+ if (argv == 0)
+ udvar(name);
+ if (argv->vec[0] == 0)
+ bferr("No more words");
+ lshift(argv->vec, 1);
+}
+
+exportpath(val)
+ tchar **val;
+{
+ tchar exppath[PATHSIZ];
+
+#ifdef TRACE
+ tprintf("TRACE- exportpath()\n");
+#endif
+ exppath[0] = 0;
+ if (val)
+ while (*val) {
+ if (strlen_(*val) + strlen_(exppath) + 2 > PATHSIZ) {
+ printf("Warning: ridiculously long PATH truncated\n");
+ break;
+ }
+ (void) strcat_(exppath, *val++);
+ if (*val == 0 || eq(*val, S_RPAR/*")"*/))
+ break;
+ (void) strcat_(exppath, S_COLON/*":"*/);
+ }
+ local_setenv(S_PATH/*"PATH"*/, exppath);
+}
+
+ /* macros to do single rotations on node p */
+#define rright(p) (\
+ t = (p)->v_left,\
+ (t)->v_parent = (p)->v_parent,\
+ ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
+ (t->v_right = (p))->v_parent = t,\
+ (p) = t)
+#define rleft(p) (\
+ t = (p)->v_right,\
+ (t)->v_parent = (p)->v_parent,\
+ ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
+ (t->v_left = (p))->v_parent = t,\
+ (p) = t)
+
+/*
+ * Rebalance a tree, starting at p and up.
+ * F == 0 means we've come from p's left child.
+ * D == 1 means we've just done a delete, otherwise an insert.
+ */
+balance(p, f, d)
+ register struct varent *p;
+ register f;
+{
+ register struct varent *pp;
+ register struct varent *t; /* used by the rotate macros */
+ register ff;
+
+#ifdef TRACE
+ tprintf("TRACE- balance()\n");
+#endif
+ /*
+ * Ok, from here on, p is the node we're operating on;
+ * pp is it's parent; f is the branch of p from which we have come;
+ * ff is the branch of pp which is p.
+ */
+ for (; pp = p->v_parent; p = pp, f = ff) {
+ ff = pp->v_right == p;
+ if (f ^ d) { /* right heavy */
+ switch (p->v_bal) {
+ case -1: /* was left heavy */
+ p->v_bal = 0;
+ break;
+ case 0: /* was balanced */
+ p->v_bal = 1;
+ break;
+ case 1: /* was already right heavy */
+ switch (p->v_right->v_bal) {
+ case 1: /* sigle rotate */
+ pp->v_link[ff] = rleft(p);
+ p->v_left->v_bal = 0;
+ p->v_bal = 0;
+ break;
+ case 0: /* single rotate */
+ pp->v_link[ff] = rleft(p);
+ p->v_left->v_bal = 1;
+ p->v_bal = -1;
+ break;
+ case -1: /* double rotate */
+ rright(p->v_right);
+ pp->v_link[ff] = rleft(p);
+ p->v_left->v_bal =
+ p->v_bal < 1 ? 0 : -1;
+ p->v_right->v_bal =
+ p->v_bal > -1 ? 0 : 1;
+ p->v_bal = 0;
+ break;
+ }
+ break;
+ }
+ } else { /* left heavy */
+ switch (p->v_bal) {
+ case 1: /* was right heavy */
+ p->v_bal = 0;
+ break;
+ case 0: /* was balanced */
+ p->v_bal = -1;
+ break;
+ case -1: /* was already left heavy */
+ switch (p->v_left->v_bal) {
+ case -1: /* single rotate */
+ pp->v_link[ff] = rright(p);
+ p->v_right->v_bal = 0;
+ p->v_bal = 0;
+ break;
+ case 0: /* signle rotate */
+ pp->v_link[ff] = rright(p);
+ p->v_right->v_bal = -1;
+ p->v_bal = 1;
+ break;
+ case 1: /* double rotate */
+ rleft(p->v_left);
+ pp->v_link[ff] = rright(p);
+ p->v_left->v_bal =
+ p->v_bal < 1 ? 0 : -1;
+ p->v_right->v_bal =
+ p->v_bal > -1 ? 0 : 1;
+ p->v_bal = 0;
+ break;
+ }
+ break;
+ }
+ }
+ /*
+ * If from insert, then we terminate when p is balanced.
+ * If from delete, then we terminate when p is unbalanced.
+ */
+ if ((p->v_bal == 0) ^ d)
+ break;
+ }
+}
+
+plist(p)
+ register struct varent *p;
+{
+ register struct varent *c;
+ register len;
+
+#ifdef TRACE
+ tprintf("TRACE- plist()\n");
+#endif
+ if (setintr)
+ (void) sigsetmask(sigblock(0) & ~ sigmask(SIGINT));
+ for (;;) {
+ while (p->v_left)
+ p = p->v_left;
+ x:
+ if (p->v_parent == 0) /* is it the header? */
+ return;
+ len = blklen(p->vec);
+ printf("%t", p->v_name);
+ Putchar('\t');
+ if (len != 1)
+ Putchar('(');
+ blkpr(p->vec);
+ if (len != 1)
+ Putchar(')');
+ Putchar('\n');
+ if (p->v_right) {
+ p = p->v_right;
+ continue;
+ }
+ do {
+ c = p;
+ p = p->v_parent;
+ } while (p->v_right == c);
+ goto x;
+ }
+}
diff --git a/usr/src/cmd/csh/sh.tchar.c b/usr/src/cmd/csh/sh.tchar.c
new file mode 100644
index 0000000000..9c75f0e72d
--- /dev/null
+++ b/usr/src/cmd/csh/sh.tchar.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright 2000 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This module provides with system/library function substitutes for tchar
+ * datatype. This also includes two conversion functions between tchar and
+ * char arrays.
+ *
+ * T. Kurosaka, Palo Alto, California, USA
+ * March 1989
+ *
+ * Implementation Notes:
+ * Many functions defined here use a "char" buffer chbuf[]. In the
+ * first attempt, there used to be only one chbuf defined as static
+ * (private) variable and shared by these functions. csh linked with that
+ * version of this file misbehaved in interpreting "eval `tset ....`".
+ * (in general, builtin function with back-quoted expression).
+ * This bug seemed to be caused by sharing of chbuf
+ * by these functions simultanously (thru vfork() mechanism?). We could not
+ * identify which two functions interfere each other so we decided to
+ * have each of these function its private instance of chbuf.
+ * The size of chbuf[] might be much bigger than necessary for some functions.
+ */
+#ifdef DBG
+#include <stdio.h> /* For <assert.h> needs stderr defined. */
+#else /* !DBG */
+#define NDEBUG /* Disable assert(). */
+#endif /* !DBG */
+
+#include <assert.h>
+#include "sh.h"
+
+#ifdef MBCHAR
+#include <widec.h> /* For wcsetno() */
+#endif
+
+#include <sys/param.h> /* MAXPATHLEN */
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/*
+ * strtots(to, from): convert a char string 'from' into a tchar buffer 'to'.
+ * 'to' is assumed to have the enough size to hold the conversion result.
+ * When 'to' is NOSTR(=(tchar *)0), strtots() attempts to allocate a space
+ * automatically using xalloc(). It is caller's responsibility to
+ * free the space allocated in this way, by calling XFREE(ptr).
+ * In either case, strtots() returns the pointer to the conversion
+ * result (i.e. 'to', if 'to' wasn't NOSTR, or the allocated space.).
+ * When a conversion or allocateion failed, NOSTR is returned.
+ */
+
+tchar *
+strtots(tchar *to, char *from)
+{
+ int i;
+
+ if (to == NOSTR) { /* Need to xalloc(). */
+ int i;
+
+ i = mbstotcs(NOSTR, from, 0);
+ if (i < 0) {
+ return (NOSTR);
+ }
+
+ /* Allocate space for the resulting tchar array. */
+ to = (tchar *)xalloc(i * sizeof (tchar));
+ }
+ i = mbstotcs(to, from, INT_MAX);
+ if (i < 0) {
+ return (NOSTR);
+ }
+ return (to);
+}
+
+char *
+tstostr(char *to, tchar *from)
+{
+ tchar *ptc;
+ wchar_t wc;
+ char *pmb;
+ int len;
+
+ if (to == (char *)NULL) { /* Need to xalloc(). */
+ int i;
+ int i1;
+ char junk[MB_LEN_MAX];
+
+ /* Get sum of byte counts for each char in from. */
+ i = 0;
+ ptc = from;
+ while (wc = (wchar_t)((*ptc++)&TRIM)) {
+ if ((i1 = wctomb(junk, wc)) <= 0) {
+ i1 = 1;
+ }
+ i += i1;
+ }
+
+ /* Allocate that much. */
+ to = (char *)xalloc(i + 1);
+ }
+
+ ptc = from;
+ pmb = to;
+ while (wc = (wchar_t)((*ptc++)&TRIM)) {
+ if ((len = wctomb(pmb, wc)) <= 0) {
+ *pmb = (unsigned char)wc;
+ len = 1;
+ }
+ pmb += len;
+ }
+ *pmb = (char)0;
+ return (to);
+}
+
+/*
+ * mbstotcs(to, from, tosize) is similar to strtots() except that
+ * this returns # of tchars of the resulting tchar string.
+ * When NULL is give as the destination, no real conversion is carried out,
+ * and the function reports how many tchar characters would be made in
+ * the converted result including the terminating 0.
+ * tchar *to; - Destination buffer, or NULL.
+ * char *from; - Source string.
+ * int tosize; - Size of to, in terms of # of tchars.
+ */
+int
+mbstotcs(tchar *to, char *from, int tosize)
+{
+ tchar *ptc = to;
+ char *pmb = from;
+ wchar_t wc;
+ int chcnt = 0;
+ int j;
+
+
+ /* Just count how many tchar would be in the result. */
+ if (to == (tchar *)NULL) {
+ while (*pmb) {
+ if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
+ j = 1;
+ }
+ pmb += j;
+ chcnt++;
+ }
+ chcnt++; /* For terminator. */
+ return (chcnt); /* # of chars including terminating zero. */
+ } else { /* Do the real conversion. */
+ while (*pmb) {
+ if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
+ wc = (unsigned char)*pmb;
+ j = 1;
+ }
+ pmb += j;
+ *(ptc++) = (tchar)wc;
+ if (++chcnt >= tosize) {
+ break;
+ }
+ }
+ /* Terminate with zero only when space is left. */
+ if (chcnt < tosize) {
+ *ptc = (tchar)0;
+ ++chcnt;
+ }
+ return (chcnt); /* # of chars including terminating zero. */
+ }
+}
+
+
+/* tchar version of STRING functions. */
+
+/*
+ * Returns the number of
+ * non-NULL tchar elements in tchar string argument.
+ */
+int
+strlen_(tchar *s)
+{
+ int n;
+
+ n = 0;
+ while (*s++) {
+ n++;
+ }
+ return (n);
+}
+
+/*
+ * Concatenate tchar string s2 on the end of s1. S1's space must be large
+ * enough. Return s1.
+ */
+tchar *
+strcat_(tchar *s1, tchar *s2)
+{
+ tchar *os1;
+
+ os1 = s1;
+ while (*s1++)
+ ;
+ --s1;
+ while (*s1++ = *s2++)
+ ;
+ return (os1);
+}
+
+/*
+ * Compare tchar strings: s1>s2: >0 s1==s2: 0 s1<s2: <0
+ * BUGS: Comparison between two characters are done by subtracting two chars
+ * after converting each to an unsigned long int value. It might not make
+ * a whole lot of sense to do that if the characters are in represented
+ * as wide characters and the two characters belong to different codesets.
+ * Therefore, this function should be used only to test the equallness.
+ */
+int
+strcmp_(tchar *s1, tchar *s2)
+{
+ while (*s1 == *s2++) {
+ if (*s1++ == (tchar)0) {
+ return (0);
+ }
+ }
+ return (((unsigned long)*s1) - ((unsigned long)*(--s2)));
+}
+
+/*
+ * This is only used in sh.glob.c for sorting purpose.
+ */
+int
+strcoll_(tchar *s1, tchar *s2)
+{
+ char buf1[BUFSIZ];
+ char buf2[BUFSIZ];
+
+ tstostr(buf1, s1);
+ tstostr(buf2, s2);
+ return (strcoll(buf1, buf2));
+}
+
+/*
+ * Copy tchar string s2 to s1. s1 must be large enough.
+ * return s1
+ */
+tchar *
+strcpy_(tchar *s1, tchar *s2)
+{
+ tchar *os1;
+
+ os1 = s1;
+ while (*s1++ = *s2++)
+ ;
+ return (os1);
+}
+
+/*
+ * Return the ptr in sp at which the character c appears;
+ * NULL if not found
+ */
+tchar *
+index_(tchar *sp, tchar c)
+{
+
+ do {
+ if (*sp == c) {
+ return (sp);
+ }
+ } while (*sp++);
+ return (NULL);
+}
+
+/*
+ * Return the ptr in sp at which the character c last
+ * appears; NOSTR if not found
+ */
+
+tchar *
+rindex_(tchar *sp, tchar c)
+{
+ tchar *r;
+
+ r = NOSTR;
+ do {
+ if (*sp == c) {
+ r = sp;
+ }
+ } while (*sp++);
+ return (r);
+}
+
+/* Additional misc functions. */
+
+/* Calculate the display width of a string. */
+tswidth(tchar *ts)
+{
+#ifdef MBCHAR
+ wchar_t tc;
+ int w = 0;
+ int p_col;
+
+ while (tc = *ts++) {
+ if ((p_col = wcwidth((wchar_t)tc)) > 0)
+ w += p_col;
+ }
+ return (w);
+#else /* !MBCHAR --- one char always occupies one column. */
+ return (strlen_(ts));
+#endif
+}
+
+/*
+ * Two getenv() substitute functions. They differ in the type of arguments.
+ * BUGS: Both returns the pointer to an allocated space where the env var's
+ * values is stored. This space is freed automatically on the successive
+ * call of either function. Therefore the caller must copy the contents
+ * if it needs to access two env vars. There is an arbitary limitation
+ * on the number of chars of a env var name.
+ */
+#define LONGEST_ENVVARNAME 256 /* Too big? */
+tchar *
+getenv_(tchar *name_)
+{
+ char name[LONGEST_ENVVARNAME * MB_LEN_MAX];
+
+ assert(strlen_(name_) < LONGEST_ENVVARNAME);
+ return (getenvs_(tstostr(name, name_)));
+}
+
+tchar *
+getenvs_(char *name)
+{
+ static tchar *pbuf = (tchar *)NULL;
+ char *val;
+
+ if (pbuf) {
+ XFREE((void *)pbuf);
+ pbuf = NOSTR;
+ }
+ val = getenv(name);
+ if (val == (char *)NULL) {
+ return (NOSTR);
+ }
+ return (pbuf = strtots(NOSTR, val));
+}
+
+/* Followings are the system call interface for tchar strings. */
+
+/*
+ * creat() and open() replacement.
+ * BUGS: An unusually long file name could be dangerous.
+ */
+int
+creat_(tchar *name_, int mode)
+{
+ int fd;
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, name_);
+ fd = creat((char *)chbuf, mode);
+ if (fd != -1) {
+ setfd(fd);
+ }
+ return (fd);
+}
+
+/*VARARGS2*/
+int
+open_(path_, flags, mode)
+ tchar *path_;
+ int flags;
+ int mode; /* May be omitted. */
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+ int fd;
+
+ tstostr(chbuf, path_);
+ fd = open((char *)chbuf, flags, mode);
+ if (fd != -1) {
+ setfd(fd);
+ }
+ return (fd);
+}
+
+/*
+ * mkstemp replacement
+ */
+int
+mkstemp_(tchar *name_)
+{
+ int fd;
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, name_);
+ fd = mkstemp((char *)chbuf);
+ if (fd != -1) {
+ setfd(fd);
+ strtots(name_, chbuf);
+ }
+ return (fd);
+}
+
+/*
+ * read() and write() reaplacement.
+ * int d;
+ * tchar *buf; - where the result be stored. Not NULL terminated.
+ * int nchreq; - # of tchars requrested.
+ */
+int
+read_(int d, tchar *buf, int nchreq)
+{
+ unsigned char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
+#ifdef MBCHAR
+ /*
+ * We would have to read more than tchar bytes
+ * when there are multibyte characters in the file.
+ */
+ int i, j, fflags;
+ unsigned char *s; /* Byte being scanned for a multibyte char. */
+ /* Points to the pos where next read() to read the data into. */
+ unsigned char *p;
+ tchar *t;
+ wchar_t wc;
+ int b_len;
+ int nchread = 0; /* Count how many bytes has been read. */
+ int nbytread = 0; /* Total # of bytes read. */
+ /* # of bytes needed to complete the last char just read. */
+ int delta;
+ unsigned char *q; /* q points to the first invalid byte. */
+#ifdef DBG
+ tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
+ d, buf, nchreq);
+#endif /* DBG */
+ /*
+ * Step 1: We collect the exact number of bytes that make
+ * nchreq characters into chbuf.
+ * We must be careful not to read too many bytes as we
+ * cannot push back such over-read bytes.
+ * The idea we use here is that n multibyte characters are stored
+ * in no less than n but less than n*MB_CUR_MAX bytes.
+ */
+ assert(nchreq <= BUFSIZ);
+ delta = 0;
+ p = s = chbuf;
+ t = buf;
+ while (nchread < nchreq) {
+ int m; /* # of bytes to try to read this time. */
+ int k; /* # of bytes successfully read. */
+
+retry:
+ /*
+ * Let's say the (N+1)'th byte bN is actually the first
+ * byte of a three-byte character c.
+ * In that case, p, s, q look like this:
+ *
+ * /-- already read--\ /-- not yet read --\
+ * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ...
+ * ^ ^ ^
+ * | | |
+ * p s q
+ * \----------/
+ * c hasn't been completed
+ *
+ * Just after the next read(), p and q will be adavanced to:
+ *
+ * /-- already read-----------------------\ /-- not yet -
+ * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ... bX bX+1 bX+2...
+ * ^ ^ ^
+ * | | |
+ * s p q
+ * \----------/
+ * c has been completed
+ * but hasn't been scanned
+ */
+ m = nchreq - nchread;
+ assert(p + m < chbuf + sizeof (chbuf));
+ k = read(d, p, m);
+ /*
+ * when child sets O_NDELAY or O_NONBLOCK on stdin
+ * and exits and we are interactive then turn the modes off
+ * and retry
+ */
+ if (k == 0) {
+ if ((intty && !onelflg && !cflg) &&
+ ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
+ fflags &= ~O_NDELAY;
+ fcntl(d, F_SETFL, fflags);
+ goto retry;
+ }
+ } else if (k < 0) {
+ if (errno == EAGAIN) {
+ fflags = fcntl(d, F_GETFL, 0);
+ fflags &= ~O_NONBLOCK;
+ fcntl(d, F_SETFL, fflags);
+ goto retry;
+ }
+ return (-1);
+ }
+ nbytread += k;
+ q = p + k;
+ delta = 0;
+
+ /* Try scaning characters in s..q-1 */
+ while (s < q) {
+ /* Convert the collected bytes into tchar array. */
+ if (*s == 0) {
+ /* NUL is treated as a normal char here. */
+ *t++ = 0;
+ s++;
+ nchread++;
+ continue;
+ }
+
+ if ((b_len = q - s) > (int)MB_CUR_MAX) {
+ b_len = MB_CUR_MAX;
+ }
+ if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) {
+ if (b_len < (unsigned int)MB_CUR_MAX) {
+ /*
+ * Needs more byte to complete this char
+ * In order to read() more than delta
+ * bytes.
+ */
+ break;
+ }
+
+ wc = (unsigned char)*s;
+ j = 1;
+ }
+
+ *t++ = wc;
+ nchread++;
+ s += j;
+ }
+
+ if (k < m) {
+ /* We've read as many bytes as possible. */
+ while (s < q) {
+ if ((b_len = q - s) > (int)MB_CUR_MAX) {
+ b_len = MB_CUR_MAX;
+ }
+ if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) {
+ wc = (unsigned char)*s;
+ j = 1;
+ }
+ *t++ = wc;
+ nchread++;
+ s += j;
+ }
+ return (nchread);
+ }
+
+ p = q;
+ }
+
+ if ((delta = q - s) == 0) {
+ return (nchread);
+ }
+
+ if (*(s + delta - 1) == '\n') {
+ while (s < q) {
+ if ((b_len = q - s) > (int)MB_CUR_MAX) {
+ b_len = MB_CUR_MAX;
+ }
+ if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) {
+ wc = (unsigned char)*s;
+ j = 1;
+ }
+ *t++ = wc;
+ nchread++;
+ s += j;
+ }
+ return (nchread);
+ }
+
+ for (; delta < (int)MB_CUR_MAX; delta++, q++) {
+ assert((q + 1) < (chbuf + sizeof (chbuf)));
+ if (read(d, q, 1) != 1) {
+ break;
+ }
+ if (*q == '\n') {
+ break;
+ }
+ if (mbtowc(&wc, (char *)s, delta) > 0) {
+ *t = wc;
+ return (nchread + 1);
+ }
+ }
+
+ while (s < q) {
+ if ((b_len = q - s) > (int)MB_CUR_MAX) {
+ b_len = MB_CUR_MAX;
+ }
+ if ((j = mbtowc(&wc, (char *)s, b_len)) <= 0) {
+ wc = (unsigned char)*s;
+ j = 1;
+ }
+ *t++ = wc;
+ nchread++;
+ s += j;
+ }
+ return (nchread);
+#else /* !MBCHAR */
+ /* One byte always represents one tchar. Easy! */
+ int i;
+ unsigned char *s;
+ tchar *t;
+ int nchread;
+
+#ifdef DBG
+ tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
+ d, buf, nchreq);
+#endif /* DBG */
+ assert(nchreq <= BUFSIZ);
+retry:
+ nchread = read(d, (char *)chbuf, nchreq);
+ /*
+ * when child sets O_NDELAY or O_NONBLOCK on stdin
+ * and exits and we are interactive then turn the modes off
+ * and retry
+ */
+ if (nchread == 0) {
+ if ((intty && !onelflg && !cflg) &&
+ ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
+ fflags &= ~O_NDELAY;
+ fcntl(d, F_SETFL, fflags);
+ goto retry;
+ }
+ } else if (nchread < 0) {
+ if (errno == EAGAIN) {
+ fflags = fcntl(d, F_GETFL, 0);
+ fflags &= ~O_NONBLOCK;
+ fcntl(d, F_SETFL, fflags);
+ goto retry;
+ }
+ len = 0;
+ } else {
+ for (i = 0, t = buf, s = chbuf; i < nchread; ++i) {
+ *t++ = ((tchar)*s++);
+ }
+ }
+ return (nchread);
+#endif
+}
+
+/*
+ * BUG: write_() returns -1 on failure, or # of BYTEs it has written.
+ * For consistency and symmetry, it should return the number of
+ * characters it has actually written, but that is technically
+ * difficult although not impossible. Anyway, the return
+ * value of write() has never been used by the original csh,
+ * so this bug should be OK.
+ */
+int
+write_(int d, tchar *buf, int nch)
+{
+ unsigned char chbuf[BUFSIZ*MB_LEN_MAX]; /* General use buffer. */
+#ifdef MBCHAR
+ tchar *pt;
+ unsigned char *pc;
+ wchar_t wc;
+ int i, j;
+
+#ifdef DBG
+ tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
+ d, buf, nch); /* Hope printf() doesn't call write_() itself! */
+#endif /* DBG */
+ assert(nch * MB_CUR_MAX < sizeof (chbuf));
+ i = nch;
+ pt = buf;
+ pc = chbuf;
+ while (i--) {
+ /*
+ * Convert to tchar string.
+ * NUL is treated as normal char here.
+ */
+ wc = (wchar_t)((*pt++)&TRIM);
+ if (wc == (wchar_t)0) {
+ *pc++ = 0;
+ } else {
+ if ((j = wctomb((char *)pc, wc)) <= 0) {
+ *pc = (unsigned char)wc;
+ j = 1;
+ }
+ pc += j;
+ }
+ }
+ return (write(d, chbuf, pc - chbuf));
+#else /* !MBCHAR */
+ /* One byte always represents one tchar. Easy! */
+ int i;
+ unsigned char *s;
+ tchar *t;
+
+#ifdef DBG
+ tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
+ d, buf, nch); /* Hope printf() doesn't call write_() itself! */
+#endif /* DBG */
+ assert(nch <= sizeof (chbuf));
+ for (i = 0, t = buf, s = chbuf; i < nch; ++i) {
+ *s++ = (char)((*t++)&0xff);
+ }
+ return (write(d, (char *)chbuf, nch));
+#endif
+}
+
+#undef chbuf
+
+#include <sys/types.h>
+#include <sys/stat.h> /* satruct stat */
+#include <dirent.h> /* DIR */
+
+extern DIR *Dirp;
+
+int
+stat_(tchar *path, struct stat *buf)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, path);
+ return (stat((char *)chbuf, buf));
+}
+
+int
+lstat_(tchar *path, struct stat *buf)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, path);
+ return (lstat((char *)chbuf, buf));
+}
+
+int
+chdir_(tchar *path)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, path);
+ return (chdir((char *)chbuf));
+}
+
+tchar *
+getwd_(tchar *path)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+ int rc;
+
+ rc = (int)getwd((char *)chbuf);
+ if (rc == 0) {
+ return (0);
+ } else {
+ return (strtots(path, chbuf));
+ }
+}
+
+int
+unlink_(tchar *path)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, path);
+ return (unlink((char *)chbuf));
+}
+
+DIR *
+opendir_(tchar *dirname)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+
+ extern DIR *opendir();
+ DIR *dir;
+
+ dir = opendir(tstostr(chbuf, dirname));
+ if (dir != NULL) {
+ setfd(dir->dd_fd);
+ }
+ return (Dirp = dir);
+}
+
+int
+closedir_(DIR *dirp)
+{
+ int ret;
+ extern int closedir();
+
+ ret = closedir(dirp);
+ Dirp = NULL;
+ return (ret);
+}
+
+int
+gethostname_(tchar *name, int namelen)
+{
+ char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
+
+ assert(namelen < BUFSIZ);
+ if (gethostname((char *)chbuf, sizeof (chbuf)) != 0) {
+ return (-1);
+ }
+ if (mbstotcs(name, chbuf, namelen) < 0) {
+ return (-1);
+ }
+ return (0); /* Succeeded. */
+}
+
+int
+readlink_(tchar *path, tchar *buf, int bufsiz)
+{
+ char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
+ char chpath[MAXPATHLEN + 1];
+ int i;
+
+ tstostr(chpath, path);
+ i = readlink(chpath, (char *)chbuf, sizeof (chbuf));
+ if (i < 0) {
+ return (-1);
+ }
+ chbuf[i] = (char)0; /* readlink() doesn't put NULL. */
+ i = mbstotcs(buf, chbuf, bufsiz);
+ if (i < 0) {
+ return (-1);
+ }
+ return (i - 1); /* Return # of tchars EXCLUDING the terminating NULL. */
+}
+
+int
+atoi_(tchar *str)
+{
+ char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
+
+ tstostr(chbuf, str);
+ return (atoi((char *)chbuf));
+}
+
+tchar *
+simple(tchar *s)
+{
+ register tchar *sname = s;
+
+ while (1) {
+ if (any('/', sname)) {
+ while (*sname++ != '/')
+ ;
+ } else {
+ return (sname);
+ }
+ }
+}
diff --git a/usr/src/cmd/csh/sh.tconst.c b/usr/src/cmd/csh/sh.tconst.c
new file mode 100644
index 0000000000..e8f16a346f
--- /dev/null
+++ b/usr/src/cmd/csh/sh.tconst.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2000 by Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * C shell
+ */
+
+/*
+ * These tchar constants used to be defined as
+ * character string constants.
+ */
+
+#include "sh.h"
+
+tchar S_[] = {0};
+tchar S_0[]={'0', 0};
+tchar S_1[]={'1', 0};
+tchar S_AND[] = {'&', 0}; /* & */
+tchar S_ANDAND[] = {'&', '&', 0}; /* && */
+tchar S_AST[]={'*', 0};
+tchar S_AT[] = { '@', 0 };
+tchar S_BAR[] = {'|', 0}; /* | */
+tchar S_BARBAR[] = {'|','|', 0}; /* || */
+tchar S_BRABRA[] = {'{', '}', 0}; /* {} */
+tchar S_BRAPPPBRA[] = {'{', ' ', '.', '.', '.', ' ', '}', 0}; /* { ... } */
+tchar S_COLON[] = {':', 0}; /*:*/
+tchar S_DASHl[] = {'-', 'l', 0}; /*-l */
+tchar S_DELIM[] = {' ','\'','"','\t',';','&','<','>','(',')','|','`',0};
+tchar S_DOT[] = {'.', 0};
+tchar S_DOTDOTSLA[]={'.', '.', '/', 0};
+tchar S_DOTSLA[]={'.', '/', 0};
+tchar S_EQ[] = {'=', 0}; /*=*/
+tchar S_EXAS[] = {'!', 0}; /* ! */
+tchar S_HAT[] = {'^', 0}; /* ^ */
+tchar S_HOME[] = {'H','O','M','E',0};/*HOME*/
+tchar S_IOT[] = {'I', 'O', 'T', 0}; /*IOT*/
+tchar S_LANG[]={'L', 'A', 'N', 'G', 0}; /*LANG*/
+tchar S_LBRA[] = {'{', 0}; /* { */
+tchar S_LBRASP[] = {'(', ' ', 0}; /*( */
+tchar S_LC_ALL[]={'L', 'C', '_', 'A', 'L', 'L', 0}; /*LC_ALL*/
+tchar S_LC_CTYPE[]={'L', 'C', '_', 'C', 'T', 'Y', 'P', 'E', 0}; /*LC_CTYPE*/
+tchar S_LC_MESSAGES[]={'L', 'C', '_',
+ 'M', 'E', 'S', 'S', 'A', 'G', 'E', 'S', 0}; /*LC_MESSAGES*/
+tchar S_LESLES[]={'<', '<', 0};
+tchar S_LPAR[] = {'(', 0}; /* ( */
+tchar S_MINUS[] = {'-',0};/*"-"*/
+tchar S_MINl[]={'-', 'l', 0};
+tchar S_NDOThistory[] = {'~','/','.','h','i','s','t','o','r','y',0};
+tchar S_OTHERSH[] = {'/','b','i','n','/','s','h',0};
+tchar S_PARCENTMINUS[] = {'%', '-', 0}; /*%-*/
+tchar S_PARCENTPARCENT[] = {'%', '%', 0}; /*%%*/
+tchar S_PARCENTPLUS[] = {'%', '+', 0}; /*%+*/
+tchar S_PARCENTSHARP[] = {'%', '#', 0}; /*%#*/
+tchar S_PATH[] = {'P','A','T','H',0};/*"PATH"*/
+tchar S_PERSENTSP[] = {'%',' ',0};
+tchar S_PWD[]={'P', 'W', 'D', 0};
+tchar S_Pjob[] = {'%','j','o','b', 0}; /*"%job"*/
+tchar S_PjobAND[] = {'%','j','o','b',' ','&',0}; /*"%job &"*/
+tchar S_QPPPQ[] = {'`', ' ', '.', '.', '.', ' ', '`', 0}; /*` ... `*/
+tchar S_RBRA[] = {'}', 0}; /* } */
+tchar S_RPAR[] = {')', 0}; /*)*/
+tchar S_SEMICOLONSP[] = {';', ' ', 0}; /* | */
+tchar S_SHARPSP[] = {'#',' ',0};
+tchar S_SHELLPATH[] = {'/','b','i','n','/','c','s','h',0};
+tchar S_SLADOTcshrc[] = {'/','.','c','s','h','r','c', 0};
+tchar S_SLADOThistory[] = {'/','.','h','i','s','t','o','r','y', 0};
+tchar S_SLADOTlogin[] = {'/','.','l','o','g','i','n', 0};
+tchar S_SLADOTlogout[] = {'/','.','l','o','g','o','u','t', 0};
+tchar S_SLASH[] = {'/', 0}; /* "/" */
+tchar S_SP[] = {' ', 0}; /* */
+tchar S_SPANDANDSP[] = {' ', '&', '&', ' ', 0}; /* && */
+tchar S_SPBARBARSP[] = {' ', '|', '|', ' ', 0}; /* || */
+tchar S_SPBARSP[] = {' ', '|', ' ', 0}; /* | */
+tchar S_SPGTRGTRSP[] = {' ', '>', '>', ' ', 0}; /* >> */
+tchar S_SPGTR[] = {' ', '>',0}; /* > */
+tchar S_SPLESLESSP[] = {' ', '<', '<', ' ', 0}; /* << */
+tchar S_SPLESSP[] = {' ', '<', ' ', 0}; /* < */
+tchar S_SPPPP[] = {' ', '.', '.', '.', 0}; /* ... */
+tchar S_SPRBRA[] = {' ', ')', 0}; /* )*/
+tchar S_TERM[] = {'T','E','R','M',0};/*TERM*/
+tchar S_TIL[] = {'~', 0}; /* ~ */
+tchar S_TOPBIT[] = {(tchar)QUOTE, 0}; /* Was "\200". A hack! */
+tchar S_USAGEFORMAT[] = {'%','U','u',' ','%','S','s',' ','%','E',' ','%','P', ' ','%','X','+','%','D','k',' ','%','I','+','%','O','i','o',' ','%','F','p','f','+', '%','W','w',0};
+tchar S_USER[] = {'U','S','E','R',0};/*USER*/
+tchar S_alias[] = { 'a','l','i','a','s', 0 };
+tchar S_alloc[] = { 'a','l','l','o','c', 0};
+tchar S_aout[] = {'a','.','o','u','t',0};
+tchar S_argv[]={'a', 'r', 'g', 'v', 0};
+tchar S_bg[] = { 'b','g', 0};
+tchar S_bin[] = {'/','b','i','n',0};
+tchar S_break[] = { 'b','r','e','a','k', 0};
+tchar S_breaksw[] = { 'b','r','e','a','k','s','w', 0};
+tchar S_bye[] = { 'b','y','e', 0};
+tchar S_case[] = { 'c','a','s','e', 0};
+tchar S_cd[] = { 'c','d', 0};
+tchar S_cdpath[]={'c', 'd', 'p', 'a', 't', 'h', 0};
+tchar S_chdir[] = { 'c','h','d','i','r', 0};
+tchar S_child[] = {'c', 'h', 'i', 'l', 'd', 0}; /*child */
+tchar S_continue[] = { 'c','o','n','t','i','n','u','e', 0};
+tchar S_coredumpsize[] = {'c','o','r','e','d','u','m','p','s','i','z','e',0};/*"coredumpsize"*/
+tchar S_cputime[] = {'c','p','u','t','i','m','e',0};/*"cputime"*/
+tchar S_csh[]={'c', 's', 'h', 0};
+tchar S_cwd[]={'c', 'w', 'd', 0};
+tchar S_datasize[] = {'d','a','t','a','s','i','z','e',0};/*"datasize"*/
+tchar S_default[] = { 'd','e','f','a','u','l','t', 0 };
+tchar S_descriptors[] = {'d', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 's', 0};
+tchar S_dirs[] = { 'd','i','r','s', 0 };
+tchar S_echo[] = {'e','c','h','o', 0};
+tchar S_else[] = { 'e','l','s','e', 0 };
+tchar S_end[] = { 'e','n','d', 0 };
+tchar S_endif[] = { 'e','n','d','i','f', 0 };
+tchar S_endsw[] = { 'e','n','d','s','w', 0 };
+tchar S_erwxfdzo[] = {'e', 'r', 'w', 'x', 'f', 'd', 'z', 'o', 0}; /* erwxfdzo */
+tchar S_eval[] = { 'e','v','a','l', 0 };
+tchar S_exec[] = { 'e','x','e','c', 0 };
+tchar S_exit[] = { 'e','x','i','t', 0 };
+tchar S_fg[] = { 'f','g', 0 };
+tchar S_fignore[] = {'f','i','g','n','o','r','e',0};
+tchar S_filec[] = {'f','i','l','e','c',0};/*filec*/
+tchar S_filesize[] = {'f','i','l','e','s','i','z','e',0};/*"filesize"*/
+tchar S_foreach[] = { 'f','o','r','e','a','c','h', 0 };
+tchar S_gd[] = { 'g','d', 0 };
+tchar S_glob[] = { 'g','l','o','b', 0 };
+tchar S_goto[] = { 'g','o','t','o', 0 };
+tchar S_h[] = {'-','h',0};
+tchar S_hardpaths[]={'h', 'a', 'r', 'd', 'p', 'a', 't', 'h', 's', 0};
+tchar S_hashstat[] = { 'h','a','s','h','s','t','a','t', 0 };
+tchar S_histchars[] = {'h','i','s','t','c','h','a','r','s',0}; /*histchars*/
+tchar S_history[] = {'h','i','s','t','o','r','y',0};
+tchar S_home[]={'h', 'o', 'm', 'e', 0};
+tchar S_hours[] = {'h','o','u','r','s',0};/*"hours"*/
+tchar S_htrqxe[]={'h', 't', 'r', 'q', 'x', 'e', 0};
+tchar S_if[] = { 'i','f', 0 };
+tchar S_ignoreeof[] = {'i','g','n','o','r','e','e','o','f',0}; /*"ignoreeof"*/
+tchar S_jobs[] = {'j','o','b','s', 0};
+tchar S_kbytes[] = {'k','b','y','t','e','s',0};/*"kbytes"*/
+tchar S_kill[] = { 'k','i','l','l', 0 };
+tchar S_label[] = { 'l','a','b','e','l', 0 };
+tchar S_limit[] = { 'l','i','m','i','t', 0 };
+tchar S_login[] = { 'l','o','g','i','n', 0 };
+tchar S_logout[] = { 'l','o','g','o','u','t', 0 };
+tchar S_mail[] = {'m','a','i','l', 0};
+tchar S_megabytes[] = {'m','e','g','a','b','y','t','e','s',0};/*"megabytes"*/
+tchar S_memorysize[] = {'m','e','m','o','r','y','s','i','z','e',0};/*"memorysize"*/
+tchar S_minutes[]={'m','i','n','u','t','e','s',0};/*"minutes"*/
+tchar S_n[] = {'-','n',0};/*"-n"*/
+tchar S_newgrp[] = { 'n','e','w','g','r','p', 0 };
+tchar S_nice[] = { 'n','i','c','e', 0 };
+tchar S_nobeep[] = {'n', 'o', 'b', 'e', 'e', 'p', 0};
+tchar S_noclobber[] = {'n','o','c','l','o','b','b','e','r',0};/*noclobber*/
+tchar S_noglob[] = {'n', 'o', 'g', 'l', 'o', 'b', 0}; /*noglob */
+tchar S_nohup[] = {'n', 'o', 'h', 'u', 'p', 0}; /*nohup */
+tchar S_nonomatch[] = {'n', 'o', 'n', 'o', 'm', 'a', 't', 'c', 'h', 0}; /*nonomatch */
+tchar S_notify[] = {'n', 'o', 't', 'i', 'f', 'y', 0}; /*nofify */
+tchar S_onintr[] = { 'o','n','i','n','t','r', 0 };
+tchar S_path[] = {'p','a','t','h', 0}; /*path*/
+tchar S_popd[] = { 'p','o','p','d', 0 };
+tchar S_prompt[] = {'p','r','o','m','p','t', 0};
+tchar S_pushd[] = { 'p','u','s','h','d', 0 };
+tchar S_rd[] = { 'r','d', 0 };
+tchar S_rehash[] = { 'r','e','h','a','s','h', 0 };
+tchar S_repeat[] = { 'r','e','p','e','a','t', 0 };
+tchar S_savehist[] = {'s','a','v','e','h','i','s','t', 0};
+tchar S_seconds[] = {'s','e','c','o','n','d','s',0};/*"seconds"*/
+tchar S_set[] = { 's','e','t', 0 };
+tchar S_setenv[] = { 's','e','t','e','n','v', 0 };
+tchar S_shell[] = {'s','h','e','l','l', 0};
+tchar S_shift[] = { 's','h','i','f','t', 0 };
+tchar S_source[] = {'s','o','u','r','c','e',0};
+tchar S_stacksize[] = {'s','t','a','c','k','s','i','z','e',0};/*"stacksize"*/
+tchar S_status[]={'s', 't', 'a', 't', 'u', 's', 0};
+tchar S_stop[] = { 's','t','o','p', 0 };
+tchar S_suspend[] = { 's','u','s','p','e','n','d', 0 };
+tchar S_switch[] = { 's','w','i','t','c','h', 0 };
+tchar S_term[] = {'t','e','r','m', 0};
+tchar S_then[] = {'t','h','e','n',0}; /*"then"*/
+tchar S_time[] = {'t', 'i', 'm', 'e', 0}; /*time*/
+tchar S_umask[] = { 'u','m','a','s','k', 0 };
+tchar S_unalias[] = { 'u','n','a','l','i','a','s', 0 };
+tchar S_unhash[] = { 'u','n','h','a','s','h', 0 };
+tchar S_unlimit[] = { 'u','n','l','i','m','i','t', 0 };
+tchar S_unlimited[] = {'u','n','l','i','m','i','t','e','d',0};/*"unlimited"*/
+tchar S_unset[] = { 'u','n','s','e','t', 0 };
+tchar S_unsetenv[] = { 'u','n','s','e','t','e','n','v', 0 };
+tchar S_user[] = {'u','s','e','r', 0};
+tchar S_usrbin[] = {'/','u','s','r','/','b','i','n',0};
+tchar S_usrucb[] = {'/','u','s','r','/','u','c','b',0};
+tchar S_verbose[] = {'v','e','r','b','o','s','e', 0};
+tchar S_wait[] = { 'w','a','i','t', 0 };
+tchar S_while[] = { 'w','h','i','l','e', 0 };
+/* Dummy search path for just absolute search when no path */
+tchar *justabs[] = { S_ /* "" */, 0 };
diff --git a/usr/src/cmd/csh/sh.time.c b/usr/src/cmd/csh/sh.time.c
new file mode 100644
index 0000000000..0564f29e07
--- /dev/null
+++ b/usr/src/cmd/csh/sh.time.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sh.h"
+#include "sh.tconst.h"
+
+void ruadd(struct rusage *ru, struct rusage *ru2);
+void prusage(struct rusage *r0, struct rusage *r1, struct timeval *e,
+ struct timeval *b);
+void pdeltat(struct timeval *t1, struct timeval *t0);
+void tvadd(struct timeval *tsum, struct timeval *t0);
+void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0);
+
+/*
+ * C Shell - routines handling process timing and niceing
+ */
+
+void
+settimes()
+{
+ struct rusage ruch;
+
+#ifdef TRACE
+ tprintf("TRACE- settimes()\n");
+#endif
+ (void) gettimeofday(&time0, (struct timezone *)0);
+ (void) getrusage(RUSAGE_SELF, &ru0);
+ (void) getrusage(RUSAGE_CHILDREN, &ruch);
+ ruadd(&ru0, &ruch);
+}
+
+/*
+ * dotime is only called if it is truly a builtin function and not a
+ * prefix to another command
+ */
+void
+dotime()
+{
+ struct timeval timedol;
+ struct rusage ru1, ruch;
+
+#ifdef TRACE
+ tprintf("TRACE- dotime()\n");
+#endif
+ (void) getrusage(RUSAGE_SELF, &ru1);
+ (void) getrusage(RUSAGE_CHILDREN, &ruch);
+ ruadd(&ru1, &ruch);
+ (void) gettimeofday(&timedol, (struct timezone *)0);
+ prusage(&ru0, &ru1, &timedol, &time0);
+}
+
+/*
+ * donice is only called when it's on the line by itself or with a +- value
+ */
+void
+donice(tchar **v)
+{
+ tchar *cp;
+ int nval;
+
+#ifdef TRACE
+ tprintf("TRACE- donice()\n");
+#endif
+ v++;
+ cp = *v++;
+ if (cp == 0) {
+ nval = 4;
+ } else if (*v == 0 && (cp[0] == '+' || cp[0] == '-')) {
+ nval = getn(cp);
+ }
+ (void) setpriority(PRIO_PROCESS, 0, nval);
+}
+
+void
+ruadd(struct rusage *ru, struct rusage *ru2)
+{
+ long *lp, *lp2;
+ int cnt;
+ /*
+ * The SunOS 4.x <sys/rusage.h> has ru_first and ru_last #defines
+ * as below.
+ * The SVR4/POSIX <sys/resource.h> does not have these defined for
+ * struct rusage
+ * The #defines below are here so that the original csh logic
+ * for ruadd remains clear now that there is no longer a private copy
+ * of the old <sys/resource.h>
+ */
+#define ru_first ru_ixrss
+#define ru_last ru_nivcsw
+
+#ifdef TRACE
+ tprintf("TRACE- ruadd()\n");
+#endif
+ tvadd(&ru->ru_utime, &ru2->ru_utime);
+ tvadd(&ru->ru_stime, &ru2->ru_stime);
+ if (ru2->ru_maxrss > ru->ru_maxrss) {
+ ru->ru_maxrss = ru2->ru_maxrss;
+ }
+ cnt = &ru->ru_last - &ru->ru_first + 1;
+ lp = &ru->ru_first;
+ lp2 = &ru2->ru_first;
+ do {
+ *lp++ += *lp2++;
+ } while (--cnt > 0);
+}
+
+void
+prusage(struct rusage *r0, struct rusage *r1, struct timeval *e,
+ struct timeval *b)
+{
+#define pgtok(p) ((p * pgsize) / 1024)
+ static int pgsize;
+
+ time_t t =
+ (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 +
+ (r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 +
+ (r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 +
+ (r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000;
+ tchar *cp;
+ int i;
+ struct varent *vp = adrof(S_time);
+ int ms =
+ (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000;
+
+#ifdef TRACE
+ tprintf("TRACE- prusage()\n");
+#endif
+ if (pgsize == 0) {
+ pgsize = getpagesize();
+ }
+
+ cp = S_USAGEFORMAT; /* "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww" */
+ if (vp && vp->vec[0] && vp->vec[1]) {
+ cp = vp->vec[1];
+ }
+ for (; *cp; cp++) {
+ if (*cp != '%') {
+ Putchar(*cp);
+ } else if (cp[1]) {
+ switch (*++cp) {
+
+ case 'U':
+ pdeltat(&r1->ru_utime, &r0->ru_utime);
+ break;
+
+ case 'S':
+ pdeltat(&r1->ru_stime, &r0->ru_stime);
+ break;
+
+ case 'E':
+ psecs_int(ms / 100);
+ break;
+
+ case 'P':
+ printf("%d%%", (int)(t * 100 /
+ ((ms ? ms : 1))));
+ break;
+
+ case 'W':
+ i = r1->ru_nswap - r0->ru_nswap;
+ printf("%d", i);
+ break;
+
+ case 'X':
+ printf("%d", t == 0 ? 0 :
+ pgtok((r1->ru_ixrss - r0->ru_ixrss) / t));
+ break;
+
+ case 'D':
+ printf("%d", t == 0 ? 0 :
+ pgtok((r1->ru_idrss + r1->ru_isrss-
+ (r0->ru_idrss + r0->ru_isrss)) / t));
+ break;
+
+ case 'K':
+ printf("%d", t == 0 ? 0 :
+ pgtok(((r1->ru_ixrss + r1->ru_isrss +
+ r1->ru_idrss) - (r0->ru_ixrss +
+ r0->ru_idrss + r0->ru_isrss)) / t));
+ break;
+
+ case 'M':
+ printf("%d", r1->ru_maxrss / 2);
+ break;
+
+ case 'F':
+ printf("%d", r1->ru_majflt - r0->ru_majflt);
+ break;
+
+ case 'R':
+ printf("%d", r1->ru_minflt - r0->ru_minflt);
+ break;
+
+ case 'I':
+ printf("%d", r1->ru_inblock - r0->ru_inblock);
+ break;
+
+ case 'O':
+ printf("%d", r1->ru_oublock - r0->ru_oublock);
+ break;
+ }
+ }
+ }
+ Putchar('\n');
+#undef pgtok
+}
+
+void
+pdeltat(struct timeval *t1, struct timeval *t0)
+{
+ struct timeval td;
+
+#ifdef TRACE
+ tprintf("TRACE- pdeltat()\n");
+#endif
+ tvsub(&td, t1, t0);
+ /* change printf formats */
+ printf("%d.%01d", td.tv_sec, td.tv_usec / 100000);
+}
+
+void
+tvadd(struct timeval *tsum, struct timeval *t0)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- tvadd()\n");
+#endif
+ tsum->tv_sec += t0->tv_sec;
+ tsum->tv_usec += t0->tv_usec;
+ if (tsum->tv_usec > 1000000) {
+ tsum->tv_sec++;
+ tsum->tv_usec -= 1000000;
+ }
+}
+
+void
+tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
+{
+
+#ifdef TRACE
+ tprintf("TRACE- tvsub()\n");
+#endif
+ tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
+ tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
+ if (tdiff->tv_usec < 0) {
+ tdiff->tv_sec--;
+ tdiff->tv_usec += 1000000;
+ }
+}
diff --git a/usr/src/cmd/csh/sparc/Makefile b/usr/src/cmd/csh/sparc/Makefile
new file mode 100644
index 0000000000..a70d8110c7
--- /dev/null
+++ b/usr/src/cmd/csh/sparc/Makefile
@@ -0,0 +1,89 @@
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+# Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+# Copyright (c) 1980 Regents of the University of California.
+# All rights reserved. The Berkeley Software License Agreement
+# specifies the terms and conditions for redistribution.
+
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# C Shell with process control; VM/UNIX VAX Makefile
+# Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
+#
+
+CSH_PROG = csh
+PROG = $(CSH_PROG)
+PFCSH_PROG= pfcsh
+ROOTPFCSH= $(ROOTBIN)/$(PFCSH_PROG)
+
+include ../../Makefile.cmd
+
+MBCHAR = -DMBCHAR # Define this line to include multibyte input support
+DEFS = -DVFORK -DFILEC -DBSD_COMP -DFIVE # No TELL when MBCHAR
+CPPFLAGS= -I. -s $(DEFS) $(MBCHAR) $(CPPFLAGS.master)
+CPPFLAGS += -I ../../sh
+CPPFLAGS += -D_FILE_OFFSET_BITS=64
+LAZYLIBS = $(ZLAZYLOAD) -lsecdb $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -lsecdb
+LDLIBS += -lcurses $(LAZYLIBS)
+
+PFOBJS = sh_policy.o
+
+HDDEP = sh.o sh.dir.o sh.dol.o sh.err.o sh.exec.o sh.exp.o sh.file.o \
+ sh.func.o sh.glob.o sh.hist.o sh.init.o sh.lex.o sh.misc.o \
+ sh.parse.o sh.proc.o sh.sem.o sh.set.o sh.time.o
+
+COMMONOBJS= printf.o sh.char.o sh.dir.o sh.dol.o sh.err.o \
+ sh.exec.o sh.exp.o sh.file.o sh.func.o sh.glob.o sh.hist.o sh.init.o \
+ sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.proc.o sh.sem.o sh.set.o \
+ sh.time.o sh.tchar.o sh.tconst.o sh.o \
+ wait3.o
+
+LOCALOBJS= signal.o
+
+COMMONSRCS= $(COMMONOBJS:%.o=../%.c)
+PFSRCS= ../../sh/sh_policy.c
+
+.KEEP_STATE:
+
+.PARALLEL: $(COMMONOBJS) $(LOCALOBJS)
+
+all: $(PROG)
+
+# build rule for common source above
+%.o: ../%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.o: ../../sh/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+$(CSH_PROG): sh.tconst.h .WAIT $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS)
+ $(LINK.c) $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(ROOTPFCSH): $(ROOTPROG)
+ $(RM) $@
+ $(LN) $(ROOTPROG) $@
+
+sh.tconst.h: ../sh.tconst.c ../make.sh.tconst.h.ed
+ $(RM) $@
+ ed ../sh.tconst.c < ../make.sh.tconst.h.ed
+
+$(HDDEP): sh.tconst.h
+
+install: all $(ROOTBINPROG) $(ROOTPROG) $(ROOTPFCSH)
+
+lint: sh.tconst.h
+ $(LINT.c) $(COMMONSRCS) $(PFSRCS) signal.c $(LDLIBS)
+
+clean:
+ $(RM) $(LOCALOBJS) $(COMMONOBJS) $(PFOBJS) sh.tconst.h
+
+clobber: clean
+ $(RM) $(PROG)
diff --git a/usr/src/cmd/csh/sparc/signal.c b/usr/src/cmd/csh/sparc/signal.c
new file mode 100644
index 0000000000..02447723ff
--- /dev/null
+++ b/usr/src/cmd/csh/sparc/signal.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * 4.3BSD signal compatibility functions
+ *
+ * the implementation interprets signal masks equal to -1 as "all of the
+ * signals in the signal set", thereby allowing signals with numbers
+ * above 32 to be blocked when referenced in code such as:
+ *
+ * for (i = 0; i < NSIG; i++)
+ * mask |= sigmask(i)
+ */
+
+#include <sys/types.h>
+#include <sys/siginfo.h>
+#include <sys/ucontext.h>
+#include <signal.h>
+#include "signal.h"
+#include <errno.h>
+#include <stdio.h>
+
+#define set2mask(setp) ((setp)->__sigbits[0])
+#define mask2set(mask, setp) \
+ ((mask) == -1 ? sigfillset(setp) : sigemptyset(setp), (((setp)->__sigbits[0]) = (mask)))
+
+void (*_siguhandler[NSIG])() = { 0 };
+
+/*
+ * sigstack is emulated with sigaltstack by guessing an appropriate
+ * value for the stack size - on machines that have stacks that grow
+ * upwards, the ss_sp arguments for both functions mean the same thing,
+ * (the initial stack pointer sigstack() is also the stack base
+ * sigaltstack()), so a "very large" value should be chosen for the
+ * stack size - on machines that have stacks that grow downwards, the
+ * ss_sp arguments mean opposite things, so 0 should be used (hopefully
+ * these machines don't have hardware stack bounds registers that pay
+ * attention to sigaltstack()'s size argument.
+ */
+
+#ifdef sun
+#define SIGSTACKSIZE 0
+#endif
+
+
+/*
+ * sigvechandler is the real signal handler installed for all
+ * signals handled in the 4.3BSD compatibility interface - it translates
+ * SVR4 signal hander arguments into 4.3BSD signal handler arguments
+ * and then calls the real handler
+ */
+
+static void
+sigvechandler(sig, sip, ucp)
+ int sig;
+ siginfo_t *sip;
+ ucontext_t *ucp;
+{
+ struct sigcontext sc;
+ int code;
+ char *addr;
+ register int i, j;
+ int gwinswitch = 0;
+
+ sc.sc_onstack = ((ucp->uc_stack.ss_flags & SS_ONSTACK) != 0);
+ sc.sc_mask = set2mask(&ucp->uc_sigmask);
+
+ /*
+ * Machine dependent code begins
+ */
+ sc.sc_sp = ucp->uc_mcontext.gregs[REG_O6];
+ sc.sc_pc = ucp->uc_mcontext.gregs[REG_PC];
+ sc.sc_npc = ucp->uc_mcontext.gregs[REG_nPC];
+ sc.sc_psr = ucp->uc_mcontext.gregs[REG_PSR];
+ sc.sc_g1 = ucp->uc_mcontext.gregs[REG_G1];
+ sc.sc_o0 = ucp->uc_mcontext.gregs[REG_O0];
+ if (ucp->uc_mcontext.gwins != (gwindows_t *)0) {
+ gwinswitch = 1;
+ sc.sc_wbcnt = ucp->uc_mcontext.gwins->wbcnt;
+ for (i = 0; i < MAXWINDOW; i++) {
+ for (j = 0; j < 16; j++)
+ sc.sc_spbuf[i][j] = (int)ucp->uc_mcontext.gwins->spbuf[j];
+ for (j = 0; j < 8; j++)
+ sc.sc_wbuf[i][j] = ucp->uc_mcontext.gwins->wbuf[i].rw_local[j];
+ for (j = 0; j < 8; j++)
+ sc.sc_wbuf[i][j+8] = ucp->uc_mcontext.gwins->wbuf[i].rw_in[j];
+ }
+ }
+ /*
+ * Machine dependent code ends
+ */
+
+ if (sip != NULL)
+ if ((code = sip->si_code) == BUS_OBJERR)
+ code = SEGV_MAKE_ERR(sip->si_errno);
+
+ if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS)
+ if (sip != NULL)
+ addr = (char *)sip->si_addr;
+ else
+ addr = SIG_NOADDR;
+
+ (*_siguhandler[sig])(sig, code, &sc, addr);
+
+ if (sc.sc_onstack)
+ ucp->uc_stack.ss_flags |= SS_ONSTACK;
+ else
+ ucp->uc_stack.ss_flags &= ~SS_ONSTACK;
+ mask2set(sc.sc_mask, &ucp->uc_sigmask);
+
+ /*
+ * Machine dependent code begins
+ */
+ ucp->uc_mcontext.gregs[REG_O6] = sc.sc_sp;
+ ucp->uc_mcontext.gregs[REG_PC] = sc.sc_pc;
+ ucp->uc_mcontext.gregs[REG_nPC] = sc.sc_npc;
+ ucp->uc_mcontext.gregs[REG_PSR] = sc.sc_psr;
+ ucp->uc_mcontext.gregs[REG_G1] = sc.sc_g1;
+ ucp->uc_mcontext.gregs[REG_O0] = sc.sc_o0;
+ if (gwinswitch == 1) {
+ ucp->uc_mcontext.gwins->wbcnt = sc.sc_wbcnt;
+ for (i = 0; i < MAXWINDOW; i++) {
+ for (j = 0; j < 16; j++)
+ ucp->uc_mcontext.gwins->spbuf[j] = (greg_t *)sc.sc_spbuf[i][j];
+ for (j = 0; j < 8; j++)
+ ucp->uc_mcontext.gwins->wbuf[i].rw_local[j] = sc.sc_wbuf[i][j];
+ for (j = 0; j < 8; j++)
+ ucp->uc_mcontext.gwins->wbuf[i].rw_in[j] = sc.sc_wbuf[i][j+8];
+ }
+ }
+ /*
+ * Machine dependent code ends
+ */
+
+ setcontext (ucp);
+}
+
+sigsetmask(mask)
+ int mask;
+{
+ sigset_t oset;
+ sigset_t nset;
+
+ (void) sigprocmask(0, (sigset_t *)0, &nset);
+ mask2set(mask, &nset);
+ (void) sigprocmask(SIG_SETMASK, &nset, &oset);
+ return set2mask(&oset);
+}
+
+sigblock(mask)
+ int mask;
+{
+ sigset_t oset;
+ sigset_t nset;
+
+ (void) sigprocmask(0, (sigset_t *)0, &nset);
+ mask2set(mask, &nset);
+ (void) sigprocmask(SIG_BLOCK, &nset, &oset);
+ return set2mask(&oset);
+}
+
+sigpause(mask)
+ int mask;
+{
+ sigset_t set;
+
+ (void) sigprocmask(0, (sigset_t *)0, &set);
+ mask2set(mask, &set);
+ return (sigsuspend(&set));
+}
+
+sigvec(sig, nvec, ovec)
+ int sig;
+ struct sigvec *nvec;
+ struct sigvec *ovec;
+{
+ struct sigaction nact;
+ struct sigaction oact;
+ struct sigaction *nactp;
+ void (*ohandler)(), (*nhandler)();
+
+ if (sig <= 0 || sig >= NSIG) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ohandler = _siguhandler[sig];
+
+ if (nvec) {
+ _sigaction(sig, (struct sigaction *)0, &nact);
+ nhandler = nvec->sv_handler;
+ _siguhandler[sig] = nhandler;
+ if (nhandler != SIG_DFL && nhandler != SIG_IGN)
+ nact.sa_handler = (void (*)())sigvechandler;
+ else
+ nact.sa_handler = nhandler;
+ mask2set(nvec->sv_mask, &nact.sa_mask);
+ /*
+ if ( sig == SIGTSTP || sig == SIGSTOP )
+ nact.sa_handler = SIG_DFL; */
+ nact.sa_flags = SA_SIGINFO;
+ if (!(nvec->sv_flags & SV_INTERRUPT))
+ nact.sa_flags |= SA_RESTART;
+ if (nvec->sv_flags & SV_RESETHAND)
+ nact.sa_flags |= SA_RESETHAND;
+ if (nvec->sv_flags & SV_ONSTACK)
+ nact.sa_flags |= SA_ONSTACK;
+ nactp = &nact;
+ } else
+ nactp = (struct sigaction *)0;
+
+ if (_sigaction(sig, nactp, &oact) < 0) {
+ _siguhandler[sig] = ohandler;
+ return -1;
+ }
+
+ if (ovec) {
+ if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
+ ovec->sv_handler = oact.sa_handler;
+ else
+ ovec->sv_handler = ohandler;
+ ovec->sv_mask = set2mask(&oact.sa_mask);
+ ovec->sv_flags = 0;
+ if (oact.sa_flags & SA_ONSTACK)
+ ovec->sv_flags |= SV_ONSTACK;
+ if (oact.sa_flags & SA_RESETHAND)
+ ovec->sv_flags |= SV_RESETHAND;
+ if (!(oact.sa_flags & SA_RESTART))
+ ovec->sv_flags |= SV_INTERRUPT;
+ }
+
+ return 0;
+}
+
+
+void (*
+signal(s, a))()
+ int s;
+ void (*a)();
+{
+ struct sigvec osv;
+ struct sigvec nsv;
+ static int mask[NSIG];
+ static int flags[NSIG];
+
+ nsv.sv_handler = a;
+ nsv.sv_mask = mask[s];
+ nsv.sv_flags = flags[s];
+ if (sigvec(s, &nsv, &osv) < 0)
+ return (SIG_ERR);
+ if (nsv.sv_mask != osv.sv_mask || nsv.sv_flags != osv.sv_flags) {
+ mask[s] = nsv.sv_mask = osv.sv_mask;
+ flags[s] = nsv.sv_flags = osv.sv_flags & ~SV_RESETHAND;
+ if (sigvec(s, &nsv, (struct sigvec *)0) < 0)
+ return (SIG_ERR);
+ }
+ return (osv.sv_handler);
+}
diff --git a/usr/src/cmd/csh/sparc/signal.h b/usr/src/cmd/csh/sparc/signal.h
new file mode 100644
index 0000000000..8861cbac9e
--- /dev/null
+++ b/usr/src/cmd/csh/sparc/signal.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef CSH_SIGNAL_H
+#define CSH_SIGNAL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * 4.3BSD signal compatibility header
+ *
+ */
+#define sigmask(m) (m > 32 ? 0 : (1 << ((m)-1)))
+
+/*
+ * 4.3BSD signal vector structure used in sigvec call.
+ */
+struct sigvec {
+ void (*sv_handler)(); /* signal handler */
+ int sv_mask; /* signal mask to apply */
+ int sv_flags; /* see signal options below */
+};
+
+#define SV_ONSTACK 0x0001 /* take signal on signal stack */
+#define SV_INTERRUPT 0x0002 /* do not restart system on signal return */
+#define SV_RESETHAND 0x0004 /* reset handler to SIG_DFL when signal taken */
+
+#define sv_onstack sv_flags
+
+/*
+ * Machine dependent data structure
+ */
+struct sigcontext {
+ int sc_onstack; /* sigstack state to restore */
+ int sc_mask; /* signal mask to restore */
+#define MAXWINDOW 31 /* max usable windows in sparc */
+ long sc_sp; /* sp to restore */
+ long sc_pc; /* pc to retore */
+ long sc_npc; /* next pc to restore */
+ long sc_psr; /* psr to restore */
+ long sc_g1; /* register that must be restored */
+ long sc_o0;
+ long sc_wbcnt; /* number of outstanding windows */
+ long *sc_spbuf[MAXWINDOW]; /* sp's for each wbuf */
+ long sc_wbuf[MAXWINDOW][16]; /* outstanding window save buffer */
+};
+
+#define SI_DFLCODE 1
+
+#define BUS_HWERR BUS_ADRERR /* misc hardware error (e.g. timeout) */
+#define BUS_ALIGN BUS_ADRALN /* hardware alignment error */
+
+#define SEGV_NOMAP SEGV_MAPERR /* no mapping at the fault address */
+#define SEGV_PROT SEGV_ACCERR /* access exceeded protections */
+
+/*
+ * The SEGV_CODE(code) will be SEGV_NOMAP, SEGV_PROT, or SEGV_OBJERR.
+ * In the SEGV_OBJERR case, doing a SEGV_ERRNO(code) gives an errno value
+ * reported by the underlying file object mapped at the fault address.
+ */
+
+#define SIG_NOADDR ((char *)~0)
+
+#define SEGV_MAKE_ERR(e) (((e) << 8) | SEGV_MAPERR)
+
+#endif /* CSH_SIGNAL_H */
diff --git a/usr/src/cmd/csh/stubs.c b/usr/src/cmd/csh/stubs.c
new file mode 100644
index 0000000000..8237fc9fb9
--- /dev/null
+++ b/usr/src/cmd/csh/stubs.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+getdomainname()
+{
+ return;
+}
+
+yp_unbind()
+{
+ return;
+}
diff --git a/usr/src/cmd/csh/wait.h b/usr/src/cmd/csh/wait.h
new file mode 100644
index 0000000000..97b3579bc8
--- /dev/null
+++ b/usr/src/cmd/csh/wait.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1994 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ *
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file holds definitions relevent to the wait system call.
+ * Some of the options here are available only through the ``wait3''
+ * entry point; the old entry point with one argument has more fixed
+ * semantics, never returning status of unstopped children, hanging until
+ * a process terminates if any are outstanding, and never returns
+ * detailed information about process resource utilization (<vtimes.h>).
+ */
+
+#ifndef _sys_wait_h
+#define _sys_wait_h
+
+#include <sys/isa_defs.h> /* included for _LITTLE_ENDIAN define */
+
+/*
+ * Structure of the information in the first word returned by both
+ * wait and wait3. If w_stopval==WSTOPPED, then the second structure
+ * describes the information returned, else the first. See WUNTRACED below.
+ */
+union wait {
+ int w_status; /* used in syscall */
+ /*
+ * Terminated process status.
+ */
+ struct {
+#if defined(_LITTLE_ENDIAN)
+ unsigned short w_Termsig:7; /* termination signal */
+ unsigned short w_Coredump:1; /* core dump indicator */
+ unsigned short w_Retcode:8; /* exit code if w_termsig==0 */
+#elif defined(_BIG_ENDIAN)
+ unsigned short w_Fill1:16; /* high 16 bits unused */
+ unsigned short w_Retcode:8; /* exit code if w_termsig==0 */
+ unsigned short w_Coredump:1; /* core dump indicator */
+ unsigned short w_Termsig:7; /* termination signal */
+#else
+#error NO ENDIAN defined.
+#endif
+ } w_T;
+ /*
+ * Stopped process status. Returned
+ * only for traced children unless requested
+ * with the WUNTRACED option bit.
+ */
+ struct {
+#if defined(_LITTLE_ENDIAN)
+ unsigned short w_Stopval:8; /* == W_STOPPED if stopped */
+ unsigned short w_Stopsig:8; /* signal that stopped us */
+#elif defined(_BIG_ENDIAN)
+ unsigned short w_Fill2:16; /* high 16 bits unused */
+ unsigned short w_Stopsig:8; /* signal that stopped us */
+ unsigned short w_Stopval:8; /* == W_STOPPED if stopped */
+#else
+#error NO ENDIAN defined.
+#endif
+ } w_S;
+};
+#define w_termsig w_T.w_Termsig
+#define w_coredump w_T.w_Coredump
+#define w_retcode w_T.w_Retcode
+#define w_stopval w_S.w_Stopval
+#define w_stopsig w_S.w_Stopsig
+
+
+#define WSTOPPED 0177 /* value of s.stopval if process is stopped */
+#define WCONTFLG 0177777 /* value of w.w_status due to SIGCONT, sysV */
+
+/*
+ * Option bits for the second argument of wait3. WNOHANG causes the
+ * wait to not hang if there are no stopped or terminated processes, rather
+ * returning an error indication in this case (pid==0). WUNTRACED
+ * indicates that the caller should receive status about untraced children
+ * which stop due to signals. If children are stopped and a wait without
+ * this option is done, it is as though they were still running... nothing
+ * about them is returned.
+ */
+#define WNOHANG 1 /* dont hang in wait */
+#define WUNTRACED 2 /* tell about stopped, untraced children */
+
+#define WIFSTOPPED(x) ((x).w_stopval == WSTOPPED)
+#define WIFSIGNALED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig != 0)
+#define WIFEXITED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig == 0)
+
+#ifdef KERNEL
+/*
+ * Arguments to wait4() system call, included here so it may be called by
+ * other routines in the kernel
+ */
+struct wait4_args {
+ int pid;
+ union wait *status;
+ int options;
+ struct rusage *rusage;
+};
+#endif KERNEL
+
+#endif /*!_sys_wait_h*/
diff --git a/usr/src/cmd/csh/wait3.c b/usr/src/cmd/csh/wait3.c
new file mode 100644
index 0000000000..b2ae68c95a
--- /dev/null
+++ b/usr/src/cmd/csh/wait3.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley Software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Compatibility lib for BSD's wait3(). It is not
+ * binary compatible, since BSD's WNOHANG and WUNTRACED
+ * carry different #define values.
+ */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <wait.h>
+#include <sys/siginfo.h>
+#include <sys/procset.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+
+/*
+ * Since sysV does not support rusage as in BSD, an approximate approach
+ * is:
+ * ...
+ * call times
+ * call waitid
+ * if ( a child is found )
+ * call times again
+ * rusage ~= diff in the 2 times call
+ * ...
+ *
+ */
+
+/*
+ * XXX: There is now a wait3 function in libc which should be used instead
+ * of this local version of wait3. With the addition of a wait3 prototype
+ * in <sys/wait.h> as per the X/Open XPG4v2 specification, compilation of
+ * the csh utility will result in warnings, hence the renaming of the local
+ * version. Using the libc wait3 rather than the local version results in
+ * a failure with csh, however, this version should eventually be dropped
+ * in favor of the libc wait3 with appropriate updates made to sh.proc.c
+ * to account for the difference in implementation of the local versus
+ * the libc versions. This should probably be done as part of an overall
+ * effort to rid csh of local versions of functions now in libc.
+ */
+
+csh_wait3(status, options, rp)
+ int *status;
+ int options;
+ struct rusage *rp;
+
+{
+ struct tms before_tms;
+ struct tms after_tms;
+ siginfo_t info;
+ int error;
+
+ if (rp)
+ memset((void *)rp, 0, sizeof(struct rusage));
+ memset((void *)&info, 0, sizeof(siginfo_t));
+ if ( times(&before_tms) == -1 )
+ return (-1); /* errno is set by times() */
+
+ /*
+ * BSD's wait3() only supports WNOHANG & WUNTRACED
+ */
+ options |= (WNOHANG|WUNTRACED|WEXITED|WSTOPPED|WTRAPPED|WCONTINUED);
+ error = waitid(P_ALL, 0, &info, options);
+ if ( error == 0 ) {
+ clock_t diffu; /* difference in usertime (ticks) */
+ clock_t diffs; /* difference in systemtime (ticks) */
+
+ if ( (options & WNOHANG) && (info.si_pid == 0) )
+ return (0); /* no child found */
+
+ if (rp) {
+ if ( times(&after_tms) == -1 )
+ return (-1); /* errno set by times() */
+ /*
+ * The system/user time is an approximation only !!!
+ */
+ diffu = after_tms.tms_cutime - before_tms.tms_cutime;
+ diffs = after_tms.tms_cstime - before_tms.tms_cstime;
+ rp->ru_utime.tv_sec = diffu/HZ;
+ rp->ru_utime.tv_usec = (diffu % HZ) / HZ * 1000000;
+ rp->ru_stime.tv_sec = diffs/HZ;
+ rp->ru_stime.tv_usec = (diffs % HZ) / HZ * 1000000;
+ }
+ *status = wstat(info.si_code, info.si_status);
+ return (info.si_pid);
+
+ } else {
+ return (-1); /* error number is set by waitid() */
+ }
+}
+
+/*
+ * Convert the status code to old style wait status
+ */
+wstat(code, status)
+ int code;
+ int status;
+{
+ register stat = (status & 0377);
+
+ switch (code) {
+ case CLD_EXITED:
+ stat <<= 8;
+ break;
+ case CLD_DUMPED:
+ stat |= WCOREFLG;
+ break;
+ case CLD_KILLED:
+ break;
+ case CLD_TRAPPED:
+ case CLD_STOPPED:
+ stat <<= 8;
+ stat |= WSTOPFLG;
+ break;
+ case CLD_CONTINUED:
+ stat = WCONTFLG;
+ break;
+ }
+ return (stat);
+}