summaryrefslogtreecommitdiffstats
path: root/contrib/tcsh/sh.func.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcsh/sh.func.c')
-rw-r--r--contrib/tcsh/sh.func.c2683
1 files changed, 2683 insertions, 0 deletions
diff --git a/contrib/tcsh/sh.func.c b/contrib/tcsh/sh.func.c
new file mode 100644
index 0000000..d3b890f
--- /dev/null
+++ b/contrib/tcsh/sh.func.c
@@ -0,0 +1,2683 @@
+/* $Header: /p/tcsh/cvsroot/tcsh/sh.func.c,v 3.162 2011/02/26 00:07:06 christos Exp $ */
+/*
+ * sh.func.c: csh builtin functions
+ */
+/*-
+ * Copyright (c) 1980, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "sh.h"
+
+RCSID("$tcsh: sh.func.c,v 3.162 2011/02/26 00:07:06 christos Exp $")
+
+#include "ed.h"
+#include "tw.h"
+#include "tc.h"
+#ifdef WINNT_NATIVE
+#include "nt.const.h"
+#endif /* WINNT_NATIVE */
+
+#if defined (NLS_CATALOGS) && defined(HAVE_ICONV)
+static iconv_t catgets_iconv; /* Or (iconv_t)-1 */
+#endif
+
+/*
+ * C shell
+ */
+
+extern int MapsAreInited;
+extern int NLSMapsAreInited;
+extern int GotTermCaps;
+
+static int zlast = -1;
+
+static void islogin (void);
+static void preread (void);
+static void doagain (void);
+static const char *isrchx (int);
+static void search (int, int, Char *);
+static int getword (struct Strbuf *);
+static struct wordent *histgetword (struct wordent *);
+static void toend (void);
+static void xecho (int, Char **);
+static int islocale_var (Char *);
+static void wpfree (struct whyle *);
+
+const struct biltins *
+isbfunc(struct command *t)
+{
+ Char *cp = t->t_dcom[0];
+ const struct biltins *bp, *bp1, *bp2;
+ static struct biltins label = {"", dozip, 0, 0};
+ static struct biltins foregnd = {"%job", dofg1, 0, 0};
+ static struct biltins backgnd = {"%job &", dobg1, 0, 0};
+
+ /*
+ * We never match a builtin that has quoted the first
+ * character; this has been the traditional way to escape
+ * builtin commands.
+ */
+ if (*cp & QUOTE)
+ return NULL;
+
+ if (*cp != ':' && lastchr(cp) == ':') {
+ label.bname = short2str(cp);
+ return (&label);
+ }
+ if (*cp == '%') {
+ if (t->t_dflg & F_AMPERSAND) {
+ t->t_dflg &= ~F_AMPERSAND;
+ backgnd.bname = short2str(cp);
+ return (&backgnd);
+ }
+ foregnd.bname = short2str(cp);
+ return (&foregnd);
+ }
+#ifdef WARP
+ /*
+ * This is a perhaps kludgy way to determine if the warp builtin is to be
+ * acknowledged or not. If checkwarp() fails, then we are to assume that
+ * the warp command is invalid, and carry on as we would handle any other
+ * non-builtin command. -- JDK 2/4/88
+ */
+ if (eq(STRwarp, cp) && !checkwarp()) {
+ return (0); /* this builtin disabled */
+ }
+#endif /* WARP */
+ /*
+ * 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 = ((char) *cp) - *bp->bname) == 0 &&
+ (i = StrQcmp(cp, str2short(bp->bname))) == 0)
+ return bp;
+ if (i < 0)
+ bp2 = bp;
+ else
+ bp1 = bp + 1;
+ }
+#ifdef WINNT_NATIVE
+ return nt_check_additional_builtins(cp);
+#endif /*WINNT_NATIVE*/
+ return (0);
+}
+
+void
+func(struct command *t, const struct biltins *bp)
+{
+ int i;
+
+ xechoit(t->t_dcom);
+ setname(bp->bname);
+ i = blklen(t->t_dcom) - 1;
+ if (i < bp->minargs)
+ stderror(ERR_NAME | ERR_TOOFEW);
+ if (i > bp->maxargs)
+ stderror(ERR_NAME | ERR_TOOMANY);
+ (*bp->bfunct) (t->t_dcom, t);
+}
+
+/*ARGSUSED*/
+void
+doonintr(Char **v, struct command *c)
+{
+ Char *cp;
+ Char *vv = v[1];
+
+ USE(c);
+ if (parintr.sa_handler == SIG_IGN)
+ return;
+ if (setintr && intty)
+ stderror(ERR_NAME | ERR_TERMINAL);
+ cp = gointr;
+ gointr = 0;
+ xfree(cp);
+ if (vv == 0) {
+ if (setintr)
+ sigset_interrupting(SIGINT, queue_pintr);
+ else
+ (void) signal(SIGINT, SIG_DFL);
+ gointr = 0;
+ }
+ else if (eq((vv = strip(vv)), STRminus)) {
+ (void) signal(SIGINT, SIG_IGN);
+ gointr = Strsave(STRminus);
+ }
+ else {
+ gointr = Strsave(vv);
+ sigset_interrupting(SIGINT, queue_pintr);
+ }
+}
+
+/*ARGSUSED*/
+void
+donohup(Char **v, struct command *c)
+{
+ USE(c);
+ USE(v);
+ if (intty)
+ stderror(ERR_NAME | ERR_TERMINAL);
+ if (setintr == 0) {
+ (void) signal(SIGHUP, SIG_IGN);
+ phup_disabled = 1;
+#ifdef CC
+ submit(getpid());
+#endif /* CC */
+ }
+}
+
+/*ARGSUSED*/
+void
+dohup(Char **v, struct command *c)
+{
+ USE(c);
+ USE(v);
+ if (intty)
+ stderror(ERR_NAME | ERR_TERMINAL);
+ if (setintr == 0)
+ (void) signal(SIGHUP, SIG_DFL);
+}
+
+
+/*ARGSUSED*/
+void
+dozip(Char **v, struct command *c)
+{
+ USE(c);
+ USE(v);
+}
+
+/*ARGSUSED*/
+void
+dofiletest(Char **v, struct command *c)
+{
+ Char **globbed, **fileptr, *ftest, *res;
+
+ USE(c);
+ if (*(ftest = *++v) != '-')
+ stderror(ERR_NAME | ERR_FILEINQ);
+ ++v;
+
+ v = glob_all_or_error(v);
+ globbed = v;
+ cleanup_push(globbed, blk_cleanup);
+
+ while (*(fileptr = v++) != '\0') {
+ res = filetest(ftest, &fileptr, 0);
+ cleanup_push(res, xfree);
+ xprintf("%S", res);
+ cleanup_until(res);
+ if (*v)
+ xprintf(" ");
+ }
+ xprintf("\n");
+
+ cleanup_until(globbed);
+}
+
+void
+prvars(void)
+{
+ plist(&shvhed, VAR_ALL);
+}
+
+/*ARGSUSED*/
+void
+doalias(Char **v, struct command *c)
+{
+ struct varent *vp;
+ Char *p;
+
+ USE(c);
+ v++;
+ p = *v++;
+ if (p == 0)
+ plist(&aliases, VAR_ALL);
+ else if (*v == 0) {
+ vp = adrof1(strip(p), &aliases);
+ if (vp && vp->vec)
+ blkpr(vp->vec), xputchar('\n');
+ }
+ else {
+ if (eq(p, STRalias) || eq(p, STRunalias)) {
+ setname(short2str(p));
+ stderror(ERR_NAME | ERR_DANGER);
+ }
+ set1(strip(p), saveblk(v), &aliases, VAR_READWRITE);
+ tw_cmd_free();
+ }
+}
+
+/*ARGSUSED*/
+void
+unalias(Char **v, struct command *c)
+{
+ USE(c);
+ unset1(v, &aliases);
+ tw_cmd_free();
+}
+
+/*ARGSUSED*/
+void
+dologout(Char **v, struct command *c)
+{
+ USE(c);
+ USE(v);
+ islogin();
+ goodbye(NULL, NULL);
+}
+
+/*ARGSUSED*/
+void
+dologin(Char **v, struct command *c)
+{
+#ifdef WINNT_NATIVE
+ USE(c);
+ USE(v);
+#else /* !WINNT_NATIVE */
+ char **p = short2blk(v);
+
+ USE(c);
+ cleanup_push((Char **)p, blk_cleanup);
+ islogin();
+ rechist(NULL, adrof(STRsavehist) != NULL);
+ sigaction(SIGTERM, &parterm, NULL);
+ (void) execv(_PATH_BIN_LOGIN, p);
+ (void) execv(_PATH_USRBIN_LOGIN, p);
+ cleanup_until((Char **)p);
+ untty();
+ xexit(1);
+#endif /* !WINNT_NATIVE */
+}
+
+
+#ifdef NEWGRP
+/*ARGSUSED*/
+void
+donewgrp(Char **v, struct command *c)
+{
+ char **p;
+ if (chkstop == 0 && setintr)
+ panystop(0);
+ sigaction(SIGTERM, &parterm, NULL);
+ p = short2blk(v);
+ /*
+ * From Beto Appleton (beto@aixwiz.austin.ibm.com)
+ * Newgrp can take 2 arguments...
+ */
+ (void) execv(_PATH_BIN_NEWGRP, p);
+ (void) execv(_PATH_USRBIN_NEWGRP, p);
+ blkfree((Char **) p);
+ untty();
+ xexit(1);
+}
+#endif /* NEWGRP */
+
+static void
+islogin(void)
+{
+ if (chkstop == 0 && setintr)
+ panystop(0);
+ if (loginsh)
+ return;
+ stderror(ERR_NOTLOGIN);
+}
+
+void
+doif(Char **v, struct command *kp)
+{
+ int i;
+ Char **vv;
+
+ v++;
+ i = noexec ? 1 : expr(&v);
+ vv = v;
+ if (*vv == NULL)
+ stderror(ERR_NAME | ERR_EMPTYIF);
+ if (eq(*vv, STRthen)) {
+ if (*++vv)
+ stderror(ERR_NAME | ERR_IMPRTHEN);
+ setname(short2str(STRthen));
+ /*
+ * If expression was zero, then scan to else , otherwise just fall into
+ * following code.
+ */
+ if (!i)
+ search(TC_IF, 0, NULL);
+ 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)
+{
+ kp->t_dflg &= F_SAVE;
+ kp->t_dflg |= F_REPEAT;
+ /*
+ * 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), NULL, NULL, TRUE);
+}
+
+/*ARGSUSED*/
+void
+doelse (Char **v, struct command *c)
+{
+ USE(c);
+ USE(v);
+ if (!noexec)
+ search(TC_ELSE, 0, NULL);
+}
+
+/*ARGSUSED*/
+void
+dogoto(Char **v, struct command *c)
+{
+ Char *lp;
+
+ USE(c);
+ lp = globone(v[1], G_ERROR);
+ cleanup_push(lp, xfree);
+ if (!noexec)
+ gotolab(lp);
+ cleanup_until(lp);
+}
+
+void
+gotolab(Char *lab)
+{
+ struct whyle *wp;
+ /*
+ * 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.
+ */
+ zlast = TC_GOTO;
+ for (wp = whyles; wp; wp = wp->w_next)
+ if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) {
+ search(TC_BREAK, 0, NULL);
+ btell(&wp->w_end);
+ }
+ else {
+ bseek(&wp->w_end);
+ }
+ search(TC_GOTO, 0, lab);
+ /*
+ * Eliminate loops which were exited.
+ */
+ wfree();
+}
+
+/*ARGSUSED*/
+void
+doswitch(Char **v, struct command *c)
+{
+ Char *cp, *lp;
+
+ USE(c);
+ v++;
+ if (!*v || *(*v++) != '(')
+ stderror(ERR_SYNTAX);
+ cp = **v == ')' ? STRNULL : *v++;
+ if (*(*v++) != ')')
+ v--;
+ if (*v)
+ stderror(ERR_SYNTAX);
+ lp = globone(cp, G_ERROR);
+ cleanup_push(lp, xfree);
+ if (!noexec)
+ search(TC_SWITCH, 0, lp);
+ cleanup_until(lp);
+}
+
+/*ARGSUSED*/
+void
+dobreak(Char **v, struct command *c)
+{
+ USE(v);
+ USE(c);
+ if (whyles == NULL)
+ stderror(ERR_NAME | ERR_NOTWHILE);
+ if (!noexec)
+ toend();
+}
+
+/*ARGSUSED*/
+void
+doexit(Char **v, struct command *c)
+{
+ USE(c);
+
+ if (chkstop == 0 && (intty || intact) && evalvec == 0)
+ panystop(0);
+ /*
+ * Don't DEMAND parentheses here either.
+ */
+ v++;
+ if (*v) {
+ setv(STRstatus, putn(expr(&v)), VAR_READWRITE);
+ if (*v)
+ stderror(ERR_NAME | ERR_EXPRESSION);
+ }
+ btoeof();
+#if 0
+ if (intty)
+#endif
+ /* Always close, why only on ttys? */
+ xclose(SHIN);
+}
+
+/*ARGSUSED*/
+void
+doforeach(Char **v, struct command *c)
+{
+ Char *cp, *sp;
+ struct whyle *nwp;
+ int gflag;
+
+ USE(c);
+ v++;
+ cp = sp = strip(*v);
+ if (!letter(*cp))
+ stderror(ERR_NAME | ERR_VARBEGIN);
+ do {
+ cp++;
+ } while (alnum(*cp));
+ if (*cp != '\0')
+ stderror(ERR_NAME | ERR_VARALNUM);
+ cp = *v++;
+ if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
+ stderror(ERR_NAME | ERR_NOPAREN);
+ v++;
+ gflag = tglob(v);
+ if (gflag) {
+ v = globall(v, gflag);
+ if (v == 0 && !noexec)
+ stderror(ERR_NAME | ERR_NOMATCH);
+ }
+ else {
+ v = saveblk(v);
+ trim(v);
+ }
+ nwp = xcalloc(1, sizeof *nwp);
+ nwp->w_fe = nwp->w_fe0 = v;
+ btell(&nwp->w_start);
+ nwp->w_fename = Strsave(cp);
+ nwp->w_next = whyles;
+ nwp->w_end.type = TCSH_F_SEEK;
+ whyles = nwp;
+ /*
+ * Pre-read the loop so as to be more comprehensible to a terminal user.
+ */
+ zlast = TC_FOREACH;
+ if (intty)
+ preread();
+ if (!noexec)
+ doagain();
+}
+
+/*ARGSUSED*/
+void
+dowhile(Char **v, struct command *c)
+{
+ int status;
+ int again = whyles != 0 &&
+ SEEKEQ(&whyles->w_start, &lineloc) &&
+ whyles->w_fename == 0;
+
+ USE(c);
+ v++;
+ /*
+ * Implement prereading here also, taking care not to evaluate the
+ * expression before the loop has been read up from a terminal.
+ */
+ if (noexec)
+ status = 0;
+ else if (intty && !again)
+ status = !exp0(&v, 1);
+ else
+ status = !expr(&v);
+ if (*v && !noexec)
+ stderror(ERR_NAME | ERR_EXPRESSION);
+ if (!again) {
+ struct whyle *nwp = xcalloc(1, sizeof(*nwp));
+
+ nwp->w_start = lineloc;
+ nwp->w_end.type = TCSH_F_SEEK;
+ nwp->w_end.f_seek = 0;
+ nwp->w_end.a_seek = 0;
+ nwp->w_next = whyles;
+ whyles = nwp;
+ zlast = TC_WHILE;
+ if (intty) {
+ /*
+ * The tty preread
+ */
+ preread();
+ doagain();
+ return;
+ }
+ }
+ if (status)
+ /* We ain't gonna loop no more, no more! */
+ toend();
+}
+
+static void
+preread(void)
+{
+ int old_pintr_disabled;
+
+ whyles->w_end.type = TCSH_I_SEEK;
+ if (setintr)
+ pintr_push_enable(&old_pintr_disabled);
+ search(TC_BREAK, 0, NULL); /* read the expression in */
+ if (setintr)
+ cleanup_until(&old_pintr_disabled);
+ btell(&whyles->w_end);
+}
+
+/*ARGSUSED*/
+void
+doend(Char **v, struct command *c)
+{
+ USE(v);
+ USE(c);
+ if (!whyles)
+ stderror(ERR_NAME | ERR_NOTWHILE);
+ btell(&whyles->w_end);
+ if (!noexec)
+ doagain();
+}
+
+/*ARGSUSED*/
+void
+docontin(Char **v, struct command *c)
+{
+ USE(v);
+ USE(c);
+ if (!whyles)
+ stderror(ERR_NAME | ERR_NOTWHILE);
+ if (!noexec)
+ doagain();
+}
+
+static void
+doagain(void)
+{
+ /* 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(NULL, NULL);
+ return;
+ }
+ setv(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE);
+ bseek(&whyles->w_start);
+}
+
+void
+dorepeat(Char **v, struct command *kp)
+{
+ int i = 1;
+
+ do {
+ i *= getn(v[1]);
+ lshift(v, 2);
+ } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0);
+ if (noexec)
+ i = 1;
+
+ if (setintr) {
+ pintr_disabled++;
+ cleanup_push(&pintr_disabled, disabled_cleanup);
+ }
+ while (i > 0) {
+ if (setintr && pintr_disabled == 1) {
+ cleanup_until(&pintr_disabled);
+ pintr_disabled++;
+ cleanup_push(&pintr_disabled, disabled_cleanup);
+ }
+ reexecute(kp);
+ --i;
+ }
+ if (setintr && pintr_disabled == 1)
+ cleanup_until(&pintr_disabled);
+ donefds();
+}
+
+/*ARGSUSED*/
+void
+doswbrk(Char **v, struct command *c)
+{
+ USE(v);
+ USE(c);
+ if (!noexec)
+ search(TC_BRKSW, 0, NULL);
+}
+
+int
+srchx(Char *cp)
+{
+ struct srch *sp, *sp1, *sp2;
+ int i;
+
+ /*
+ * Ignore keywords inside heredocs
+ */
+ if (inheredoc)
+ return -1;
+
+ /*
+ * 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, str2short(sp->s_name))) == 0)
+ return sp->s_value;
+ if (i < 0)
+ sp2 = sp;
+ else
+ sp1 = sp + 1;
+ }
+ return (-1);
+}
+
+static const char *
+isrchx(int n)
+{
+ struct srch *sp, *sp2;
+
+ for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++)
+ if (sp->s_value == n)
+ return (sp->s_name);
+ return ("");
+}
+
+
+static int Stype;
+static Char *Sgoal;
+
+static void
+search(int type, int level, Char *goal)
+{
+ struct Strbuf word = Strbuf_INIT;
+ Char *cp;
+ struct whyle *wp;
+ int wlevel = 0;
+ struct wordent *histent = NULL, *ohistent = NULL;
+
+ Stype = type;
+ Sgoal = goal;
+ if (type == TC_GOTO) {
+ struct Ain a;
+ a.type = TCSH_F_SEEK;
+ a.f_seek = 0;
+ a.a_seek = 0;
+ bseek(&a);
+ }
+ cleanup_push(&word, Strbuf_cleanup);
+ do {
+
+ if (intty) {
+ histent = xmalloc(sizeof(*histent));
+ ohistent = xmalloc(sizeof(*histent));
+ ohistent->word = STRNULL;
+ ohistent->next = histent;
+ histent->prev = ohistent;
+ }
+
+ if (intty && fseekp == feobp && aret == TCSH_F_SEEK)
+ printprompt(1, isrchx(type == TC_BREAK ? zlast : type));
+ /* xprintf("? "), flush(); */
+ (void) getword(&word);
+ Strbuf_terminate(&word);
+
+ if (intty && Strlen(word.s) > 0) {
+ histent->word = Strsave(word.s);
+ histent->next = xmalloc(sizeof(*histent));
+ histent->next->prev = histent;
+ histent = histent->next;
+ }
+
+ switch (srchx(word.s)) {
+
+ case TC_ELSE:
+ if (level == 0 && type == TC_IF)
+ goto end;
+ break;
+
+ case TC_IF:
+ while (getword(&word))
+ continue;
+ if ((type == TC_IF || type == TC_ELSE) &&
+ eq(word.s, STRthen))
+ level++;
+ break;
+
+ case TC_ENDIF:
+ if (type == TC_IF || type == TC_ELSE)
+ level--;
+ break;
+
+ case TC_FOREACH:
+ case TC_WHILE:
+ wlevel++;
+ if (type == TC_BREAK)
+ level++;
+ break;
+
+ case TC_END:
+ if (type == TC_BRKSW) {
+ if (wlevel == 0) {
+ wp = whyles;
+ if (wp) {
+ whyles = wp->w_next;
+ wpfree(wp);
+ }
+ }
+ }
+ if (type == TC_BREAK)
+ level--;
+ wlevel--;
+ break;
+
+ case TC_SWITCH:
+ if (type == TC_SWITCH || type == TC_BRKSW)
+ level++;
+ break;
+
+ case TC_ENDSW:
+ if (type == TC_SWITCH || type == TC_BRKSW)
+ level--;
+ break;
+
+ case TC_LABEL:
+ if (type == TC_GOTO && getword(&word) && eq(word.s, goal))
+ level = -1;
+ break;
+
+ default:
+ if (type != TC_GOTO && (type != TC_SWITCH || level != 0))
+ break;
+ if (word.len == 0 || word.s[word.len - 1] != ':')
+ break;
+ word.s[--word.len] = 0;
+ if ((type == TC_GOTO && eq(word.s, goal)) ||
+ (type == TC_SWITCH && eq(word.s, STRdefault)))
+ level = -1;
+ break;
+
+ case TC_CASE:
+ if (type != TC_SWITCH || level != 0)
+ break;
+ (void) getword(&word);
+ if (word.len != 0 && word.s[word.len - 1] == ':')
+ word.s[--word.len] = 0;
+ cp = strip(Dfix1(word.s));
+ cleanup_push(cp, xfree);
+ if (Gmatch(goal, cp))
+ level = -1;
+ cleanup_until(cp);
+ break;
+
+ case TC_DEFAULT:
+ if (type == TC_SWITCH && level == 0)
+ level = -1;
+ break;
+ }
+ if (intty) {
+ ohistent->prev = histgetword(histent);
+ ohistent->prev->next = ohistent;
+ savehist(ohistent, 0);
+ freelex(ohistent);
+ xfree(ohistent);
+ } else
+ (void) getword(NULL);
+ } while (level >= 0);
+ end:
+ cleanup_until(&word);
+}
+
+static struct wordent *
+histgetword(struct wordent *histent)
+{
+ int found = 0, first;
+ eChar c, d;
+ int e;
+ struct Strbuf *tmp;
+ tmp = xmalloc(sizeof(*tmp));
+ tmp->size = 0;
+ tmp->s = NULL;
+ c = readc(1);
+ d = 0;
+ e = 0;
+ for (;;) {
+ tmp->len = 0;
+ Strbuf_terminate (tmp);
+ while (c == ' ' || c == '\t')
+ c = readc(1);
+ if (c == '#')
+ do
+ c = readc(1);
+ while (c != CHAR_ERR && c != '\n');
+ if (c == CHAR_ERR)
+ goto past;
+ if (c == '\n')
+ goto nl;
+ unreadc(c);
+ found = 1;
+ first = 1;
+ do {
+ e = (c == '\\');
+ c = readc(1);
+ if (c == '\\' && !e) {
+ if ((c = readc(1)) == '\n') {
+ e = 1;
+ c = ' ';
+ } else {
+ unreadc(c);
+ c = '\\';
+ }
+ }
+ if ((c == '\'' || c == '"') && !e) {
+ if (d == 0)
+ d = c;
+ else if (d == c)
+ d = 0;
+ }
+ if (c == CHAR_ERR)
+ goto past;
+
+ Strbuf_append1(tmp, (Char) c);
+
+ if (!first && !d && c == '(' && !e) {
+ break;
+ }
+ first = 0;
+ } while (d || e || (c != ' ' && c != '\t' && c != '\n'));
+ tmp->len--;
+ if (tmp->len) {
+ Strbuf_terminate(tmp);
+ histent->word = Strsave(tmp->s);
+ histent->next = xmalloc(sizeof (*histent));
+ histent->next->prev = histent;
+ histent = histent->next;
+ }
+ if (c == '\n') {
+ nl:
+ tmp->len = 0;
+ Strbuf_append1(tmp, (Char) c);
+ Strbuf_terminate(tmp);
+ histent->word = Strsave(tmp->s);
+ return histent;
+ }
+ }
+
+past:
+ switch (Stype) {
+
+ case TC_IF:
+ stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
+ break;
+
+ case TC_ELSE:
+ stderror(ERR_NAME | ERR_NOTFOUND, "endif");
+ break;
+
+ case TC_BRKSW:
+ case TC_SWITCH:
+ stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
+ break;
+
+ case TC_BREAK:
+ stderror(ERR_NAME | ERR_NOTFOUND, "end");
+ break;
+
+ case TC_GOTO:
+ setname(short2str(Sgoal));
+ stderror(ERR_NAME | ERR_NOTFOUND, "label");
+ break;
+
+ default:
+ break;
+ }
+ /* NOTREACHED */
+ return NULL;
+}
+
+static int
+getword(struct Strbuf *wp)
+{
+ int found = 0, first;
+ eChar c, d;
+
+ if (wp)
+ wp->len = 0;
+ c = readc(1);
+ d = 0;
+ do {
+ while (c == ' ' || c == '\t')
+ c = readc(1);
+ if (c == '#')
+ do
+ c = readc(1);
+ while (c != CHAR_ERR && c != '\n');
+ if (c == CHAR_ERR)
+ goto past;
+ if (c == '\n') {
+ if (wp)
+ break;
+ return (0);
+ }
+ unreadc(c);
+ found = 1;
+ first = 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 == CHAR_ERR)
+ goto past;
+ if (wp)
+ Strbuf_append1(wp, (Char) c);
+ if (!first && !d && c == '(') {
+ if (wp)
+ goto past_word_end;
+ else
+ break;
+ }
+ first = 0;
+ } while ((d || (c != ' ' && c != '\t')) && c != '\n');
+ } while (wp == 0);
+
+ past_word_end:
+ unreadc(c);
+ if (found) {
+ wp->len--;
+ Strbuf_terminate(wp);
+ }
+
+ return (found);
+
+past:
+ switch (Stype) {
+
+ case TC_IF:
+ stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
+ break;
+
+ case TC_ELSE:
+ stderror(ERR_NAME | ERR_NOTFOUND, "endif");
+ break;
+
+ case TC_BRKSW:
+ case TC_SWITCH:
+ stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
+ break;
+
+ case TC_BREAK:
+ stderror(ERR_NAME | ERR_NOTFOUND, "end");
+ break;
+
+ case TC_GOTO:
+ setname(short2str(Sgoal));
+ stderror(ERR_NAME | ERR_NOTFOUND, "label");
+ break;
+
+ default:
+ break;
+ }
+ /* NOTREACHED */
+ return (0);
+}
+
+static void
+toend(void)
+{
+ if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) {
+ search(TC_BREAK, 0, NULL);
+ btell(&whyles->w_end);
+ whyles->w_end.f_seek--;
+ }
+ else {
+ bseek(&whyles->w_end);
+ }
+ wfree();
+}
+
+static void
+wpfree(struct whyle *wp)
+{
+ if (wp->w_fe0)
+ blkfree(wp->w_fe0);
+ xfree(wp->w_fename);
+ xfree(wp);
+}
+
+void
+wfree(void)
+{
+ struct Ain o;
+ struct whyle *nwp;
+#ifdef lint
+ nwp = NULL; /* sun lint is dumb! */
+#endif
+
+#ifdef FDEBUG
+ static const char foo[] = "IAFE";
+#endif /* FDEBUG */
+
+ btell(&o);
+
+#ifdef FDEBUG
+ xprintf("o->type %c o->a_seek %d o->f_seek %d\n",
+ foo[o.type + 1], o.a_seek, o.f_seek);
+#endif /* FDEBUG */
+
+ for (; whyles; whyles = nwp) {
+ struct whyle *wp = whyles;
+ nwp = wp->w_next;
+
+#ifdef FDEBUG
+ xprintf("start->type %c start->a_seek %d start->f_seek %d\n",
+ foo[wp->w_start.type+1],
+ wp->w_start.a_seek, wp->w_start.f_seek);
+ xprintf("end->type %c end->a_seek %d end->f_seek %d\n",
+ foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek);
+#endif /* FDEBUG */
+
+ /*
+ * XXX: We free loops that have different seek types.
+ */
+ if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type &&
+ wp->w_start.type == o.type) {
+ if (wp->w_end.type == TCSH_F_SEEK) {
+ if (o.f_seek >= wp->w_start.f_seek &&
+ (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
+ break;
+ }
+ else {
+ if (o.a_seek >= wp->w_start.a_seek &&
+ (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
+ break;
+ }
+ }
+
+ wpfree(wp);
+ }
+}
+
+/*ARGSUSED*/
+void
+doecho(Char **v, struct command *c)
+{
+ USE(c);
+ xecho(' ', v);
+}
+
+/*ARGSUSED*/
+void
+doglob(Char **v, struct command *c)
+{
+ USE(c);
+ xecho(0, v);
+ flush();
+}
+
+static void
+xecho(int sep, Char **v)
+{
+ Char *cp, **globbed = NULL;
+ int nonl = 0;
+ int echo_style = ECHO_STYLE;
+ struct varent *vp;
+
+ if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL &&
+ vp->vec[0] != NULL) {
+ if (Strcmp(vp->vec[0], STRbsd) == 0)
+ echo_style = BSD_ECHO;
+ else if (Strcmp(vp->vec[0], STRsysv) == 0)
+ echo_style = SYSV_ECHO;
+ else if (Strcmp(vp->vec[0], STRboth) == 0)
+ echo_style = BOTH_ECHO;
+ else if (Strcmp(vp->vec[0], STRnone) == 0)
+ echo_style = NONE_ECHO;
+ }
+
+ v++;
+ if (*v == 0)
+ goto done;
+ if (setintr) {
+ int old_pintr_disabled;
+ pintr_push_enable(&old_pintr_disabled);
+ v = glob_all_or_error(v);
+ cleanup_until(&old_pintr_disabled);
+ } else {
+ v = glob_all_or_error(v);
+ }
+ globbed = v;
+ if (globbed != NULL)
+ cleanup_push(globbed, blk_cleanup);
+
+ if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn))
+ nonl++, v++;
+
+ while ((cp = *v++) != 0) {
+ Char c;
+
+ if (setintr) {
+ int old_pintr_disabled;
+
+ pintr_push_enable(&old_pintr_disabled);
+ cleanup_until(&old_pintr_disabled);
+ }
+ while ((c = *cp++) != 0) {
+ if ((echo_style & SYSV_ECHO) != 0 && c == '\\') {
+ switch (c = *cp++) {
+ case 'a':
+ c = '\a';
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'c':
+ nonl = 1;
+ goto done;
+ case 'e':
+#if 0 /* Windows does not understand \e */
+ c = '\e';
+#else
+ c = CTL_ESC('\033');
+#endif
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '0':
+ c = 0;
+ if (*cp >= '0' && *cp < '8')
+ c = c * 8 + *cp++ - '0';
+ if (*cp >= '0' && *cp < '8')
+ c = c * 8 + *cp++ - '0';
+ if (*cp >= '0' && *cp < '8')
+ c = c * 8 + *cp++ - '0';
+ break;
+ case '\0':
+ c = '\\';
+ cp--;
+ break;
+ default:
+ xputchar('\\' | QUOTE);
+ break;
+ }
+ }
+ xputwchar(c | QUOTE);
+
+ }
+ if (*v)
+ xputchar(sep | QUOTE);
+ }
+done:
+ if (sep && nonl == 0)
+ xputchar('\n');
+ else
+ flush();
+ if (globbed != NULL)
+ cleanup_until(globbed);
+}
+
+/* check whether an environment variable should invoke 'set_locale()' */
+static int
+islocale_var(Char *var)
+{
+ static Char *locale_vars[] = {
+ STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC,
+ STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0
+ };
+ Char **v;
+
+ for (v = locale_vars; *v; ++v)
+ if (eq(var, *v))
+ return 1;
+ return 0;
+}
+
+static void
+xlate_cr_cleanup(void *dummy)
+{
+ USE(dummy);
+ xlate_cr = 0;
+}
+
+/*ARGSUSED*/
+void
+doprintenv(Char **v, struct command *c)
+{
+ Char *e;
+
+ USE(c);
+ v++;
+ if (*v == 0) {
+ Char **ep;
+
+ xlate_cr = 1;
+ cleanup_push(&xlate_cr, xlate_cr_cleanup);
+ for (ep = STR_environ; *ep; ep++) {
+ if (setintr) {
+ int old_pintr_disabled;
+
+ pintr_push_enable(&old_pintr_disabled);
+ cleanup_until(&old_pintr_disabled);
+ }
+ xprintf("%S\n", *ep);
+ }
+ cleanup_until(&xlate_cr);
+ }
+ else if ((e = tgetenv(*v)) != NULL) {
+ int old_output_raw;
+
+ old_output_raw = output_raw;
+ output_raw = 1;
+ cleanup_push(&old_output_raw, output_raw_restore);
+ xprintf("%S\n", e);
+ cleanup_until(&old_output_raw);
+ }
+ else
+ setcopy(STRstatus, STR1, VAR_READWRITE);
+}
+
+/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
+ (and anything else with a modern compiler) */
+
+/*ARGSUSED*/
+void
+dosetenv(Char **v, struct command *c)
+{
+ Char *vp, *lp;
+
+ USE(c);
+ if (*++v == 0) {
+ doprintenv(--v, 0);
+ return;
+ }
+
+ vp = *v++;
+ lp = vp;
+
+ if (!letter(*lp))
+ stderror(ERR_NAME | ERR_VARBEGIN);
+ do {
+ lp++;
+ } while (alnum(*lp));
+ if (*lp != '\0')
+ stderror(ERR_NAME | ERR_VARALNUM);
+
+ if ((lp = *v++) == 0)
+ lp = STRNULL;
+
+ lp = globone(lp, G_APPEND);
+ cleanup_push(lp, xfree);
+ tsetenv(vp, lp);
+ if (eq(vp, STRKPATH)) {
+ importpath(lp);
+ dohash(NULL, NULL);
+ cleanup_until(lp);
+ return;
+ }
+
+#ifdef apollo
+ if (eq(vp, STRSYSTYPE)) {
+ dohash(NULL, NULL);
+ cleanup_until(lp);
+ return;
+ }
+#endif /* apollo */
+
+ /* dspkanji/dspmbyte autosetting */
+ /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
+#if defined(DSPMBYTE)
+ if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) {
+ autoset_dspmbyte(lp);
+ }
+#endif
+
+ if (islocale_var(vp)) {
+#ifdef NLS
+ int k;
+
+# ifdef SETLOCALEBUG
+ dont_free = 1;
+# endif /* SETLOCALEBUG */
+ (void) setlocale(LC_ALL, "");
+# ifdef LC_COLLATE
+ (void) setlocale(LC_COLLATE, "");
+# endif
+# ifdef LC_CTYPE
+ (void) setlocale(LC_CTYPE, ""); /* for iscntrl */
+# endif /* LC_CTYPE */
+# if defined(AUTOSET_KANJI)
+ autoset_kanji();
+# endif /* AUTOSET_KANJI */
+# ifdef NLS_CATALOGS
+# ifdef LC_MESSAGES
+ (void) setlocale(LC_MESSAGES, "");
+# endif /* LC_MESSAGES */
+ nlsclose();
+ nlsinit();
+# endif /* NLS_CATALOGS */
+# ifdef SETLOCALEBUG
+ dont_free = 0;
+# endif /* SETLOCALEBUG */
+# ifdef STRCOLLBUG
+ fix_strcoll_bug();
+# endif /* STRCOLLBUG */
+ tw_cmd_free(); /* since the collation sequence has changed */
+ for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++)
+ continue;
+ AsciiOnly = MB_CUR_MAX == 1 && k > 0377;
+#else /* !NLS */
+ AsciiOnly = 0;
+#endif /* NLS */
+ NLSMapsAreInited = 0;
+ ed_Init();
+ if (MapsAreInited && !NLSMapsAreInited)
+ ed_InitNLSMaps();
+ cleanup_until(lp);
+ return;
+ }
+
+#ifdef NLS_CATALOGS
+ if (eq(vp, STRNLSPATH)) {
+ nlsclose();
+ nlsinit();
+ }
+#endif
+
+ if (eq(vp, STRNOREBIND)) {
+ NoNLSRebind = 1;
+ MapsAreInited = 0;
+ NLSMapsAreInited = 0;
+ ed_InitMaps();
+ cleanup_until(lp);
+ return;
+ }
+#ifdef WINNT_NATIVE
+ if (eq(vp, STRtcshlang)) {
+ nlsinit();
+ cleanup_until(lp);
+ return;
+ }
+#endif /* WINNT_NATIVE */
+ if (eq(vp, STRKTERM)) {
+ char *t;
+
+ setv(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */
+ cleanup_ignore(lp);
+ cleanup_until(lp);
+ t = short2str(lp);
+ if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) {
+ editing = 1;
+ noediting = 0;
+ setNS(STRedit);
+ }
+ GotTermCaps = 0;
+ ed_Init();
+ return;
+ }
+
+ if (eq(vp, STRKHOME)) {
+ Char *canon;
+ /*
+ * convert to canonical pathname (possibly resolving symlinks)
+ */
+ canon = dcanon(lp, lp);
+ cleanup_ignore(lp);
+ cleanup_until(lp);
+ cleanup_push(canon, xfree);
+ setv(STRhome, quote(canon), VAR_READWRITE); /* lp memory used here */
+ cleanup_ignore(canon);
+ cleanup_until(canon);
+
+ /* fix directory stack for new tilde home */
+ dtilde();
+ return;
+ }
+
+ if (eq(vp, STRKSHLVL)) {
+ setv(STRshlvl, quote(lp), VAR_READWRITE); /* lp memory used here */
+ cleanup_ignore(lp);
+ cleanup_until(lp);
+ return;
+ }
+
+ if (eq(vp, STRKUSER)) {
+ setv(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */
+ cleanup_ignore(lp);
+ cleanup_until(lp);
+ return;
+ }
+
+ if (eq(vp, STRKGROUP)) {
+ setv(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */
+ cleanup_ignore(lp);
+ cleanup_until(lp);
+ return;
+ }
+
+#ifdef COLOR_LS_F
+ if (eq(vp, STRLS_COLORS)) {
+ parseLS_COLORS(lp);
+ cleanup_until(lp);
+ return;
+ }
+#endif /* COLOR_LS_F */
+
+#ifdef SIG_WINDOW
+ /*
+ * Load/Update $LINES $COLUMNS
+ */
+ if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) ||
+ eq(vp, STRTERMCAP)) {
+ cleanup_until(lp);
+ check_window_size(1);
+ return;
+ }
+
+ /*
+ * Change the size to the one directed by $LINES and $COLUMNS
+ */
+ if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) {
+#if 0
+ GotTermCaps = 0;
+#endif
+ cleanup_until(lp);
+ ed_Init();
+ return;
+ }
+#endif /* SIG_WINDOW */
+ cleanup_until(lp);
+}
+
+/*ARGSUSED*/
+void
+dounsetenv(Char **v, struct command *c)
+{
+ Char **ep, *p, *n, *name;
+ int i, maxi;
+
+ USE(c);
+ /*
+ * Find the longest environment variable
+ */
+ for (maxi = 0, ep = STR_environ; *ep; ep++) {
+ for (i = 0, p = *ep; *p && *p != '='; p++, i++)
+ continue;
+ if (i > maxi)
+ maxi = i;
+ }
+
+ name = xmalloc((maxi + 1) * sizeof(Char));
+ cleanup_push(name, xfree);
+
+ while (++v && *v)
+ for (maxi = 1; maxi;)
+ for (maxi = 0, ep = STR_environ; *ep; ep++) {
+ for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
+ continue;
+ *n = '\0';
+ if (!Gmatch(name, *v))
+ continue;
+ maxi = 1;
+
+ /* Unset the name. This wasn't being done until
+ * later but most of the stuff following won't
+ * work (particularly the setlocale() and getenv()
+ * stuff) as intended until the name is actually
+ * removed. (sg)
+ */
+ Unsetenv(name);
+
+ if (eq(name, STRNOREBIND)) {
+ NoNLSRebind = 0;
+ MapsAreInited = 0;
+ NLSMapsAreInited = 0;
+ ed_InitMaps();
+ }
+#ifdef apollo
+ else if (eq(name, STRSYSTYPE))
+ dohash(NULL, NULL);
+#endif /* apollo */
+ else if (islocale_var(name)) {
+#ifdef NLS
+ int k;
+
+# ifdef SETLOCALEBUG
+ dont_free = 1;
+# endif /* SETLOCALEBUG */
+ (void) setlocale(LC_ALL, "");
+# ifdef LC_COLLATE
+ (void) setlocale(LC_COLLATE, "");
+# endif
+# ifdef LC_CTYPE
+ (void) setlocale(LC_CTYPE, ""); /* for iscntrl */
+# endif /* LC_CTYPE */
+# ifdef NLS_CATALOGS
+# ifdef LC_MESSAGES
+ (void) setlocale(LC_MESSAGES, "");
+# endif /* LC_MESSAGES */
+ nlsclose();
+ nlsinit();
+# endif /* NLS_CATALOGS */
+# ifdef SETLOCALEBUG
+ dont_free = 0;
+# endif /* SETLOCALEBUG */
+# ifdef STRCOLLBUG
+ fix_strcoll_bug();
+# endif /* STRCOLLBUG */
+ tw_cmd_free();/* since the collation sequence has changed */
+ for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++)
+ continue;
+ AsciiOnly = MB_CUR_MAX == 1 && k > 0377;
+#else /* !NLS */
+ AsciiOnly = getenv("LANG") == NULL &&
+ getenv("LC_CTYPE") == NULL;
+#endif /* NLS */
+ NLSMapsAreInited = 0;
+ ed_Init();
+ if (MapsAreInited && !NLSMapsAreInited)
+ ed_InitNLSMaps();
+
+ }
+#ifdef WINNT_NATIVE
+ else if (eq(name,(STRtcshlang))) {
+ nls_dll_unload();
+ nlsinit();
+ }
+#endif /* WINNT_NATIVE */
+#ifdef COLOR_LS_F
+ else if (eq(name, STRLS_COLORS))
+ parseLS_COLORS(n);
+#endif /* COLOR_LS_F */
+#ifdef NLS_CATALOGS
+ else if (eq(name, STRNLSPATH)) {
+ nlsclose();
+ nlsinit();
+ }
+#endif
+ /*
+ * start again cause the environment changes
+ */
+ break;
+ }
+ cleanup_until(name);
+}
+
+void
+tsetenv(const Char *name, const Char *val)
+{
+#ifdef SETENV_IN_LIB
+/*
+ * XXX: This does not work right, since tcsh cannot track changes to
+ * the environment this way. (the builtin setenv without arguments does
+ * not print the right stuff neither does unsetenv). This was for Mach,
+ * it is not needed anymore.
+ */
+#undef setenv
+ char *cname;
+
+ if (name == NULL)
+ return;
+ cname = strsave(short2str(name));
+ setenv(cname, short2str(val), 1);
+ xfree(cname);
+#else /* !SETENV_IN_LIB */
+ Char **ep = STR_environ;
+ const Char *ccp;
+ Char *cp, *dp;
+ Char *blk[2];
+ Char **oep = ep;
+
+#ifdef WINNT_NATIVE
+ nt_set_env(name,val);
+#endif /* WINNT_NATIVE */
+ for (; *ep; ep++) {
+#ifdef WINNT_NATIVE
+ for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp);
+ ccp++, dp++)
+#else
+ for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++)
+#endif /* WINNT_NATIVE */
+ continue;
+ if (*ccp != 0 || *dp != '=')
+ continue;
+ cp = Strspl(STRequal, val);
+ xfree(*ep);
+ *ep = strip(Strspl(name, cp));
+ xfree(cp);
+ blkfree((Char **) environ);
+ environ = short2blk(STR_environ);
+ return;
+ }
+ cp = Strspl(name, STRequal);
+ blk[0] = strip(Strspl(cp, val));
+ xfree(cp);
+ blk[1] = 0;
+ STR_environ = blkspl(STR_environ, blk);
+ blkfree((Char **) environ);
+ environ = short2blk(STR_environ);
+ xfree(oep);
+#endif /* SETENV_IN_LIB */
+}
+
+void
+Unsetenv(Char *name)
+{
+ Char **ep = STR_environ;
+ Char *cp, *dp;
+ Char **oep = ep;
+
+#ifdef WINNT_NATIVE
+ nt_set_env(name,NULL);
+#endif /*WINNT_NATIVE */
+ for (; *ep; ep++) {
+ for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
+ continue;
+ if (*cp != 0 || *dp != '=')
+ continue;
+ cp = *ep;
+ *ep = 0;
+ STR_environ = blkspl(STR_environ, ep + 1);
+ blkfree((Char **) environ);
+ environ = short2blk(STR_environ);
+ *ep = cp;
+ xfree(cp);
+ xfree(oep);
+ return;
+ }
+}
+
+/*ARGSUSED*/
+void
+doumask(Char **v, struct command *c)
+{
+ Char *cp = v[1];
+ int i;
+
+ USE(c);
+ if (cp == 0) {
+ i = (int)umask(0);
+ (void) umask(i);
+ xprintf("%o\n", i);
+ return;
+ }
+ i = 0;
+ while (Isdigit(*cp) && *cp != '8' && *cp != '9')
+ i = i * 8 + *cp++ - '0';
+ if (*cp || i < 0 || i > 0777)
+ stderror(ERR_NAME | ERR_MASK);
+ (void) umask(i);
+}
+
+#ifndef HAVENOLIMIT
+# ifndef BSDLIMIT
+ typedef long RLIM_TYPE;
+# ifdef _OSD_POSIX /* BS2000 */
+# include <ulimit.h>
+# endif
+# ifndef RLIM_INFINITY
+# if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY)
+ extern RLIM_TYPE ulimit();
+# endif /* ! _MINIX && !__clipper__ */
+# define RLIM_INFINITY 0x003fffff
+# define RLIMIT_FSIZE 1
+# endif /* RLIM_INFINITY */
+# ifdef aiws
+# define toset(a) (((a) == 3) ? 1004 : (a) + 1)
+# define RLIMIT_DATA 3
+# define RLIMIT_STACK 1005
+# else /* aiws */
+# define toset(a) ((a) + 1)
+# endif /* aiws */
+# else /* BSDLIMIT */
+# if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__)
+ typedef rlim_t RLIM_TYPE;
+# else
+# if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3)
+ typedef rlim_t RLIM_TYPE;
+# else
+# if defined(_SX)
+ typedef long long RLIM_TYPE;
+# else /* !_SX */
+ typedef unsigned long RLIM_TYPE;
+# endif /* _SX */
+# endif /* SOLARIS2 || (sgi && SYSVREL > 3) */
+# endif /* BSD4_4 && !__386BSD__ */
+# endif /* BSDLIMIT */
+
+# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT)
+/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */
+/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */
+# ifndef RLIMIT_CPU
+# define RLIMIT_CPU 0
+# define RLIMIT_FSIZE 1
+# define RLIMIT_DATA 2
+# define RLIMIT_STACK 3
+# define RLIMIT_CORE 4
+# define RLIMIT_RSS 5
+# define RLIMIT_NOFILE 6
+# endif /* RLIMIT_CPU */
+# ifndef RLIM_INFINITY
+# define RLIM_INFINITY 0x7fffffff
+# endif /* RLIM_INFINITY */
+ /*
+ * old versions of HP/UX counted limits in 512 bytes
+ */
+# ifndef SIGRTMIN
+# define FILESIZE512
+# endif /* SIGRTMIN */
+# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */
+
+# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX)
+/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */
+/* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */
+/* than include both and get warnings, we define the extra SVR4 limits here. */
+/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */
+/* RLIMIT_VMEM based on it? */
+# ifndef RLIMIT_VMEM
+# define RLIMIT_VMEM 6
+# endif
+# ifndef RLIMIT_AS
+# define RLIMIT_AS RLIMIT_VMEM
+# endif
+# endif /* SYSVREL > 3 && BSDLIMIT */
+
+# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__))
+# if defined(RLIMIT_AS) && !defined(RLIMIT_VMEM)
+# define RLIMIT_VMEM RLIMIT_AS
+# endif
+/*
+ * Oh well, <asm-generic/resource.h> has it, but <bits/resource.h> does not
+ * Linux headers: When the left hand does not know what the right hand does.
+ */
+# if defined(RLIMIT_RTPRIO) && !defined(RLIMIT_RTTIME)
+# define RLIMIT_RTTIME (RLIMIT_RTPRIO + 1)
+# endif
+# endif
+
+struct limits limits[] =
+{
+# ifdef RLIMIT_CPU
+ { RLIMIT_CPU, "cputime", 1, "seconds" },
+# endif /* RLIMIT_CPU */
+
+# ifdef RLIMIT_FSIZE
+# ifndef aiws
+ { RLIMIT_FSIZE, "filesize", 1024, "kbytes" },
+# else
+ { RLIMIT_FSIZE, "filesize", 512, "blocks" },
+# endif /* aiws */
+# endif /* RLIMIT_FSIZE */
+
+# ifdef RLIMIT_DATA
+ { RLIMIT_DATA, "datasize", 1024, "kbytes" },
+# endif /* RLIMIT_DATA */
+
+# ifdef RLIMIT_STACK
+# ifndef aiws
+ { RLIMIT_STACK, "stacksize", 1024, "kbytes" },
+# else
+ { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"},
+# endif /* aiws */
+# endif /* RLIMIT_STACK */
+
+# ifdef RLIMIT_CORE
+ { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" },
+# endif /* RLIMIT_CORE */
+
+# ifdef RLIMIT_RSS
+ { RLIMIT_RSS, "memoryuse", 1024, "kbytes" },
+# endif /* RLIMIT_RSS */
+
+# ifdef RLIMIT_UMEM
+ { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" },
+# endif /* RLIMIT_UMEM */
+
+# ifdef RLIMIT_VMEM
+ { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" },
+# endif /* RLIMIT_VMEM */
+
+# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */
+ { RLIMIT_HEAP, "heapsize", 1024, "kbytes" },
+# endif /* RLIMIT_HEAP */
+
+# ifdef RLIMIT_NOFILE
+ { RLIMIT_NOFILE, "descriptors", 1, "" },
+# endif /* RLIMIT_NOFILE */
+
+# ifdef RLIMIT_CONCUR
+ { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" },
+# endif /* RLIMIT_CONCUR */
+
+# ifdef RLIMIT_MEMLOCK
+ { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" },
+# endif /* RLIMIT_MEMLOCK */
+
+# ifdef RLIMIT_NPROC
+ { RLIMIT_NPROC, "maxproc", 1, "" },
+# endif /* RLIMIT_NPROC */
+
+# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
+ { RLIMIT_OFILE, "openfiles", 1, "" },
+# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */
+
+# ifdef RLIMIT_SBSIZE
+ { RLIMIT_SBSIZE, "sbsize", 1, "" },
+# endif /* RLIMIT_SBSIZE */
+
+# ifdef RLIMIT_SWAP
+ { RLIMIT_SWAP, "swapsize", 1024, "kbytes" },
+# endif /* RLIMIT_SWAP */
+
+# ifdef RLIMIT_LOCKS
+ { RLIMIT_LOCKS, "maxlocks", 1, "" },
+# endif /* RLIMIT_LOCKS */
+
+# ifdef RLIMIT_SIGPENDING
+ { RLIMIT_SIGPENDING,"maxsignal", 1, "" },
+# endif /* RLIMIT_SIGPENDING */
+
+# ifdef RLIMIT_MSGQUEUE
+ { RLIMIT_MSGQUEUE, "maxmessage", 1, "" },
+# endif /* RLIMIT_MSGQUEUE */
+
+# ifdef RLIMIT_NICE
+ { RLIMIT_NICE, "maxnice", 1, "" },
+# endif /* RLIMIT_NICE */
+
+# ifdef RLIMIT_RTPRIO
+ { RLIMIT_RTPRIO, "maxrtprio", 1, "" },
+# endif /* RLIMIT_RTPRIO */
+
+# ifdef RLIMIT_RTTIME
+ { RLIMIT_RTTIME, "maxrttime", 1, "usec" },
+# endif /* RLIMIT_RTTIME */
+
+ { -1, NULL, 0, NULL }
+};
+
+static struct limits *findlim (Char *);
+static RLIM_TYPE getval (struct limits *, Char **);
+static int strtail (Char *, const char *);
+static void limtail (Char *, const char *);
+static void limtail2 (Char *, const char *, const char *);
+static void plim (struct limits *, int);
+static int setlim (struct limits *, int, RLIM_TYPE);
+
+#ifdef convex
+static RLIM_TYPE
+restrict_limit(double value)
+{
+ /*
+ * is f too large to cope with? return the maximum or minimum int
+ */
+ if (value > (double) INT_MAX)
+ return (RLIM_TYPE) INT_MAX;
+ else if (value < (double) INT_MIN)
+ return (RLIM_TYPE) INT_MIN;
+ else
+ return (RLIM_TYPE) value;
+}
+#else /* !convex */
+# define restrict_limit(x) ((RLIM_TYPE) (x))
+#endif /* convex */
+
+
+static struct limits *
+findlim(Char *cp)
+{
+ struct limits *lp, *res;
+
+ res = NULL;
+ for (lp = limits; lp->limconst >= 0; lp++)
+ if (prefix(cp, str2short(lp->limname))) {
+ if (res)
+ stderror(ERR_NAME | ERR_AMBIG);
+ res = lp;
+ }
+ if (res)
+ return (res);
+ stderror(ERR_NAME | ERR_LIMIT);
+ /* NOTREACHED */
+ return (0);
+}
+
+/*ARGSUSED*/
+void
+dolimit(Char **v, struct command *c)
+{
+ struct limits *lp;
+ RLIM_TYPE limit;
+ int hard = 0;
+
+ USE(c);
+ v++;
+ if (*v && eq(*v, STRmh)) {
+ 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;
+ }
+ limit = getval(lp, v + 1);
+ if (setlim(lp, hard, limit) < 0)
+ stderror(ERR_SILENT);
+}
+
+static RLIM_TYPE
+getval(struct limits *lp, Char **v)
+{
+ float f;
+ Char *cp = *v++;
+
+ f = atof(short2str(cp));
+
+# ifdef convex
+ /*
+ * is f too large to cope with. limit f to minint, maxint - X-6768 by
+ * strike
+ */
+ if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) {
+ stderror(ERR_NAME | ERR_TOOLARGE);
+ }
+# endif /* convex */
+
+ while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
+ cp++;
+ if (*cp == 0) {
+ if (*v == 0)
+ return restrict_limit((f * lp->limdiv) + 0.5);
+ cp = *v;
+ }
+ switch (*cp) {
+# ifdef RLIMIT_CPU
+ case ':':
+ if (lp->limconst != RLIMIT_CPU)
+ goto badscal;
+ return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1))));
+ case 'h':
+ if (lp->limconst != RLIMIT_CPU)
+ goto badscal;
+ limtail(cp, "hours");
+ f *= 3600.0;
+ break;
+# endif /* RLIMIT_CPU */
+ case 'm':
+# ifdef RLIMIT_CPU
+ if (lp->limconst == RLIMIT_CPU) {
+ limtail(cp, "minutes");
+ f *= 60.0;
+ break;
+ }
+# endif /* RLIMIT_CPU */
+ limtail2(cp, "megabytes", "mbytes");
+ f *= 1024.0 * 1024.0;
+ break;
+# ifdef RLIMIT_CPU
+ case 's':
+ if (lp->limconst != RLIMIT_CPU)
+ goto badscal;
+ limtail(cp, "seconds");
+ break;
+# endif /* RLIMIT_CPU */
+ case 'G':
+ *cp = 'g';
+ /*FALLTHROUGH*/
+ case 'g':
+# ifdef RLIMIT_CPU
+ if (lp->limconst == RLIMIT_CPU)
+ goto badscal;
+# endif /* RLIMIT_CPU */
+ limtail2(cp, "gigabytes", "gbytes");
+ f *= 1024.0 * 1024.0 * 1024.0;
+ break;
+ case 'M':
+# ifdef RLIMIT_CPU
+ if (lp->limconst == RLIMIT_CPU)
+ goto badscal;
+# endif /* RLIMIT_CPU */
+ *cp = 'm';
+ limtail2(cp, "megabytes", "mbytes");
+ f *= 1024.0 * 1024.0;
+ break;
+ case 'k':
+# ifdef RLIMIT_CPU
+ if (lp->limconst == RLIMIT_CPU)
+ goto badscal;
+# endif /* RLIMIT_CPU */
+ limtail2(cp, "kilobytes", "kbytes");
+ f *= 1024.0;
+ break;
+ case 'b':
+# ifdef RLIMIT_CPU
+ if (lp->limconst == RLIMIT_CPU)
+ goto badscal;
+# endif /* RLIMIT_CPU */
+ limtail(cp, "blocks");
+ f *= 512.0;
+ break;
+ case 'u':
+ limtail(cp, "unlimited");
+ return ((RLIM_TYPE) RLIM_INFINITY);
+ default:
+# ifdef RLIMIT_CPU
+badscal:
+# endif /* RLIMIT_CPU */
+ stderror(ERR_NAME | ERR_SCALEF);
+ }
+# ifdef convex
+ return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5));
+# else
+ f += 0.5;
+ if (f > (float) ((RLIM_TYPE) RLIM_INFINITY))
+ return ((RLIM_TYPE) RLIM_INFINITY);
+ else
+ return ((RLIM_TYPE) f);
+# endif /* convex */
+}
+
+static int
+strtail(Char *cp, const char *str)
+{
+ while (*cp && *cp == (Char)*str)
+ cp++, str++;
+ return (*cp != '\0');
+}
+
+static void
+limtail(Char *cp, const char *str)
+{
+ if (strtail(cp, str))
+ stderror(ERR_BADSCALE, str);
+}
+
+static void
+limtail2(Char *cp, const char *str1, const char *str2)
+{
+ if (strtail(cp, str1) && strtail(cp, str2))
+ stderror(ERR_BADSCALE, str1);
+}
+
+/*ARGSUSED*/
+static void
+plim(struct limits *lp, int hard)
+{
+# ifdef BSDLIMIT
+ struct rlimit rlim;
+# endif /* BSDLIMIT */
+ RLIM_TYPE limit;
+ int xdiv = lp->limdiv;
+
+ xprintf("%-13.13s", lp->limname);
+
+# ifndef BSDLIMIT
+ limit = ulimit(lp->limconst, 0);
+# ifdef aiws
+ if (lp->limconst == RLIMIT_DATA)
+ limit -= 0x20000000;
+# endif /* aiws */
+# else /* BSDLIMIT */
+ (void) getrlimit(lp->limconst, &rlim);
+ limit = hard ? rlim.rlim_max : rlim.rlim_cur;
+# endif /* BSDLIMIT */
+
+# if !defined(BSDLIMIT) || defined(FILESIZE512)
+ /*
+ * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024
+ * blocks. Note we cannot pre-multiply cause we might overflow (A/UX)
+ */
+ if (lp->limconst == RLIMIT_FSIZE) {
+ if (limit >= (RLIM_INFINITY / 512))
+ limit = RLIM_INFINITY;
+ else
+ xdiv = (xdiv == 1024 ? 2 : 1);
+ }
+# endif /* !BSDLIMIT || FILESIZE512 */
+
+ if (limit == RLIM_INFINITY)
+ xprintf("unlimited");
+ else
+# if defined(RLIMIT_CPU) && defined(_OSD_POSIX)
+ if (lp->limconst == RLIMIT_CPU &&
+ (unsigned long)limit >= 0x7ffffffdUL)
+ xprintf("unlimited");
+ else
+# endif
+# ifdef RLIMIT_CPU
+ if (lp->limconst == RLIMIT_CPU)
+ psecs(limit);
+ else
+# endif /* RLIMIT_CPU */
+ xprintf("%ld %s", (long) (limit / xdiv), lp->limscale);
+ xputchar('\n');
+}
+
+/*ARGSUSED*/
+void
+dounlimit(Char **v, struct command *c)
+{
+ struct limits *lp;
+ int lerr = 0;
+ int hard = 0;
+ int force = 0;
+
+ USE(c);
+ while (*++v && **v == '-') {
+ Char *vp = *v;
+ while (*++vp)
+ switch (*vp) {
+ case 'f':
+ force = 1;
+ break;
+ case 'h':
+ hard = 1;
+ break;
+ default:
+ stderror(ERR_ULIMUS);
+ break;
+ }
+ }
+
+ if (*v == 0) {
+ for (lp = limits; lp->limconst >= 0; lp++)
+ if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
+ lerr++;
+ if (!force && lerr)
+ stderror(ERR_SILENT);
+ return;
+ }
+ while (*v) {
+ lp = findlim(*v++);
+ if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force)
+ stderror(ERR_SILENT);
+ }
+}
+
+static int
+setlim(struct limits *lp, int hard, RLIM_TYPE limit)
+{
+# ifdef BSDLIMIT
+ struct rlimit rlim;
+
+ (void) getrlimit(lp->limconst, &rlim);
+
+# ifdef FILESIZE512
+ /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
+ if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
+ limit /= 512;
+# endif /* FILESIZE512 */
+ if (hard)
+ rlim.rlim_max = limit;
+ else if (limit == RLIM_INFINITY && euid != 0)
+ rlim.rlim_cur = rlim.rlim_max;
+ else
+ rlim.rlim_cur = limit;
+
+ if (rlim.rlim_cur > rlim.rlim_max)
+ rlim.rlim_max = rlim.rlim_cur;
+
+ if (setrlimit(lp->limconst, &rlim) < 0) {
+# else /* BSDLIMIT */
+ if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
+ limit /= 512;
+# ifdef aiws
+ if (lp->limconst == RLIMIT_DATA)
+ limit += 0x20000000;
+# endif /* aiws */
+ if (ulimit(toset(lp->limconst), limit) < 0) {
+# endif /* BSDLIMIT */
+ int err;
+ char *op, *type;
+
+ err = errno;
+ op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") :
+ CGETS(15, 3, "set"));
+ cleanup_push(op, xfree);
+ type = strsave(hard ? CGETS(15, 4, " hard") : "");
+ cleanup_push(type, xfree);
+ xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname,
+ lp->limname, op, type, strerror(err));
+ cleanup_until(op);
+ return (-1);
+ }
+ return (0);
+}
+
+#endif /* !HAVENOLIMIT */
+
+/*ARGSUSED*/
+void
+dosuspend(Char **v, struct command *c)
+{
+#ifdef BSDJOBS
+ struct sigaction old;
+#endif /* BSDJOBS */
+
+ USE(c);
+ USE(v);
+
+ if (loginsh)
+ stderror(ERR_SUSPLOG);
+ untty();
+
+#ifdef BSDJOBS
+ sigaction(SIGTSTP, NULL, &old);
+ signal(SIGTSTP, SIG_DFL);
+ (void) kill(0, SIGTSTP);
+ /* the shell stops here */
+ sigaction(SIGTSTP, &old, NULL);
+#else /* !BSDJOBS */
+ stderror(ERR_JOBCONTROL);
+#endif /* BSDJOBS */
+
+#ifdef BSDJOBS
+ if (tpgrp != -1) {
+ if (grabpgrp(FSHTTY, opgrp) == -1)
+ stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno));
+ (void) setpgid(0, shpgrp);
+ (void) tcsetpgrp(FSHTTY, shpgrp);
+ }
+#endif /* BSDJOBS */
+ (void) setdisc(FSHTTY);
+}
+
+/* This is the dreaded EVAL built-in.
+ * If you don't fiddle with file descriptors, and reset didfds,
+ * this command will either ignore redirection inside or outside
+ * its arguments, e.g. eval "date >x" vs. eval "date" >x
+ * The stuff here seems to work, but I did it by trial and error rather
+ * than really knowing what was going on. If tpgrp is zero, we are
+ * probably a background eval, e.g. "eval date &", and we want to
+ * make sure that any processes we start stay in our pgrp.
+ * This is also the case for "time eval date" -- stay in same pgrp.
+ * Otherwise, under stty tostop, processes will stop in the wrong
+ * pgrp, with no way for the shell to get them going again. -IAN!
+ */
+
+struct doeval_state
+{
+ Char **evalvec, *evalp;
+ int didfds;
+#ifndef CLOSE_ON_EXEC
+ int didcch;
+#endif
+ int saveIN, saveOUT, saveDIAG;
+ int SHIN, SHOUT, SHDIAG;
+};
+
+static void
+doeval_cleanup(void *xstate)
+{
+ struct doeval_state *state;
+
+ state = xstate;
+ evalvec = state->evalvec;
+ evalp = state->evalp;
+ doneinp = 0;
+#ifndef CLOSE_ON_EXEC
+ didcch = state->didcch;
+#endif /* CLOSE_ON_EXEC */
+ didfds = state->didfds;
+ xclose(SHIN);
+ xclose(SHOUT);
+ xclose(SHDIAG);
+ close_on_exec(SHIN = dmove(state->saveIN, state->SHIN), 1);
+ close_on_exec(SHOUT = dmove(state->saveOUT, state->SHOUT), 1);
+ close_on_exec(SHDIAG = dmove(state->saveDIAG, state->SHDIAG), 1);
+}
+
+static Char **Ggv;
+/*ARGSUSED*/
+void
+doeval(Char **v, struct command *c)
+{
+ struct doeval_state state;
+ int gflag, my_reenter;
+ Char **gv;
+ jmp_buf_t osetexit;
+
+ USE(c);
+ v++;
+ if (*v == 0)
+ return;
+ gflag = tglob(v);
+ if (gflag) {
+ gv = v = globall(v, gflag);
+ if (v == 0)
+ stderror(ERR_NOMATCH);
+ cleanup_push(gv, blk_cleanup);
+ v = copyblk(v);
+ }
+ else {
+ gv = NULL;
+ v = copyblk(v);
+ trim(v);
+ }
+
+ Ggv = gv;
+ state.evalvec = evalvec;
+ state.evalp = evalp;
+ state.didfds = didfds;
+#ifndef CLOSE_ON_EXEC
+ state.didcch = didcch;
+#endif /* CLOSE_ON_EXEC */
+ state.SHIN = SHIN;
+ state.SHOUT = SHOUT;
+ state.SHDIAG = SHDIAG;
+
+ (void)close_on_exec(state.saveIN = dcopy(SHIN, -1), 1);
+ (void)close_on_exec(state.saveOUT = dcopy(SHOUT, -1), 1);
+ (void)close_on_exec(state.saveDIAG = dcopy(SHDIAG, -1), 1);
+
+ cleanup_push(&state, doeval_cleanup);
+
+ getexit(osetexit);
+
+ /* PWP: setjmp/longjmp bugfix for optimizing compilers */
+#ifdef cray
+ my_reenter = 1; /* assume non-zero return val */
+ if (setexit() == 0) {
+ my_reenter = 0; /* Oh well, we were wrong */
+#else /* !cray */
+ if ((my_reenter = setexit()) == 0) {
+#endif /* cray */
+ evalvec = v;
+ evalp = 0;
+ (void)close_on_exec(SHIN = dcopy(0, -1), 1);
+ (void)close_on_exec(SHOUT = dcopy(1, -1), 1);
+ (void)close_on_exec(SHDIAG = dcopy(2, -1), 1);
+#ifndef CLOSE_ON_EXEC
+ didcch = 0;
+#endif /* CLOSE_ON_EXEC */
+ didfds = 0;
+ gv = Ggv;
+ process(0);
+ Ggv = gv;
+ }
+
+ if (my_reenter == 0) {
+ cleanup_until(&state);
+ if (Ggv)
+ cleanup_until(Ggv);
+ }
+
+ resexit(osetexit);
+ if (my_reenter)
+ stderror(ERR_SILENT);
+}
+
+/*************************************************************************/
+/* print list of builtin commands */
+
+static void
+lbuffed_cleanup (void *dummy)
+{
+ USE(dummy);
+ lbuffed = 1;
+}
+
+/*ARGSUSED*/
+void
+dobuiltins(Char **v, struct command *c)
+{
+ /* would use print_by_column() in tw.parse.c but that assumes
+ * we have an array of Char * to pass.. (sg)
+ */
+ const struct biltins *b;
+ int row, col, columns, rows;
+ unsigned int w, maxwidth;
+
+ USE(c);
+ USE(v);
+ lbuffed = 0; /* turn off line buffering */
+ cleanup_push(&lbuffed, lbuffed_cleanup);
+
+ /* find widest string */
+ for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b)
+ maxwidth = max(maxwidth, strlen(b->bname));
+ ++maxwidth; /* for space */
+
+ columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */
+ if (!columns)
+ columns = 1;
+ rows = (nbfunc + (columns - 1)) / columns;
+
+ for (b = bfunc, row = 0; row < rows; row++) {
+ for (col = 0; col < columns; col++) {
+ if (b < &bfunc[nbfunc]) {
+ w = strlen(b->bname);
+ xprintf("%s", b->bname);
+ if (col < (columns - 1)) /* Not last column? */
+ for (; w < maxwidth; w++)
+ xputchar(' ');
+ ++b;
+ }
+ }
+ if (row < (rows - 1)) {
+ if (Tty_raw_mode)
+ xputchar('\r');
+ xputchar('\n');
+ }
+ }
+#ifdef WINNT_NATIVE
+ nt_print_builtins(maxwidth);
+#else
+ if (Tty_raw_mode)
+ xputchar('\r');
+ xputchar('\n');
+#endif /* WINNT_NATIVE */
+
+ cleanup_until(&lbuffed); /* turn back on line buffering */
+ flush();
+}
+
+#ifdef NLS_CATALOGS
+char *
+xcatgets(nl_catd ctd, int set_id, int msg_id, const char *s)
+{
+ char *res;
+
+ errno = 0;
+ while ((res = catgets(ctd, set_id, msg_id, s)) == s && errno == EINTR) {
+ handle_pending_signals();
+ errno = 0;
+ }
+ return res;
+}
+
+
+# if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO)
+char *
+iconv_catgets(nl_catd ctd, int set_id, int msg_id, const char *s)
+{
+ static char *buf = NULL;
+ static size_t buf_size = 0;
+
+ char *orig, *dest, *p;
+ ICONV_CONST char *src;
+ size_t src_size, dest_size;
+
+ orig = xcatgets(ctd, set_id, msg_id, s);
+ if (catgets_iconv == (iconv_t)-1 || orig == s)
+ return orig;
+ src = orig;
+ src_size = strlen(src) + 1;
+ if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL)
+ return orig;
+ dest = buf;
+ while (src_size != 0) {
+ dest_size = buf + buf_size - dest;
+ if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size)
+ == (size_t)-1) {
+ switch (errno) {
+ case E2BIG:
+ if ((p = xrealloc(buf, buf_size * 2)) == NULL)
+ return orig;
+ buf_size *= 2;
+ dest = p + (dest - buf);
+ buf = p;
+ break;
+
+ case EILSEQ: case EINVAL: default:
+ return orig;
+ }
+ }
+ }
+ return buf;
+}
+# endif /* HAVE_ICONV && HAVE_NL_LANGINFO */
+#endif /* NLS_CATALOGS */
+
+void
+nlsinit(void)
+{
+#ifdef NLS_CATALOGS
+ static const char default_catalog[] = "tcsh";
+
+ char *catalog = (char *)(intptr_t)default_catalog;
+
+ if (adrof(STRcatalog) != NULL)
+ catalog = xasprintf("tcsh.%s", short2str(varval(STRcatalog)));
+#ifdef NL_CAT_LOCALE /* POSIX-compliant. */
+ /*
+ * Check if LC_MESSAGES is set in the environment and use it, if so.
+ * If not, fall back to the setting of LANG.
+ */
+ catd = catopen(catalog, tgetenv(STRLC_MESSAGES) ? NL_CAT_LOCALE : 0);
+#else /* pre-POSIX */
+# ifndef MCLoadBySet
+# define MCLoadBySet 0
+# endif
+ catd = catopen(catalog, MCLoadBySet);
+#endif
+ if (catalog != default_catalog)
+ xfree(catalog);
+#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO)
+ /* xcatgets (), not CGETS, the charset name should be in ASCII anyway. */
+ catgets_iconv = iconv_open (nl_langinfo (CODESET),
+ xcatgets(catd, 255, 1, "UTF-8"));
+#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */
+#endif /* NLS_CATALOGS */
+#ifdef WINNT_NATIVE
+ nls_dll_init();
+#endif /* WINNT_NATIVE */
+ errinit(); /* init the errorlist in correct locale */
+ mesginit(); /* init the messages for signals */
+ dateinit(); /* init the messages for dates */
+ editinit(); /* init the editor messages */
+ terminit(); /* init the termcap messages */
+}
+
+void
+nlsclose(void)
+{
+#ifdef NLS_CATALOGS
+#if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO)
+ if (catgets_iconv != (iconv_t)-1) {
+ iconv_close(catgets_iconv);
+ catgets_iconv = (iconv_t)-1;
+ }
+#endif /* HAVE_ICONV && HAVE_NL_LANGINFO */
+ if (catd != (nl_catd)-1) {
+ /*
+ * catclose can call other functions which can call longjmp
+ * making us re-enter this code. Prevent infinite recursion
+ * by resetting catd. Problem reported and solved by:
+ * Gerhard Niklasch
+ */
+ nl_catd oldcatd = catd;
+ catd = (nl_catd)-1;
+ while (catclose(oldcatd) == -1 && errno == EINTR)
+ handle_pending_signals();
+ }
+#endif /* NLS_CATALOGS */
+}
OpenPOWER on IntegriCloud