summaryrefslogtreecommitdiff
path: root/usr/src/cmd/csh/sh.func.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/csh/sh.func.c')
-rw-r--r--usr/src/cmd/csh/sh.func.c1645
1 files changed, 1645 insertions, 0 deletions
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);
+ }
+}