/* * 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. */ #include "sh.h" #include "sh.tconst.h" /* * C Shell */ void asx(tchar *, int, tchar *); void putn1(int); void set(tchar *, tchar *); void set1(tchar *, tchar **, struct varent *); void setq(tchar *, tchar **, struct varent *); void unset1(tchar *[], struct varent *); void unsetv1(struct varent *); void exportpath(tchar **); void balance(struct varent *, int, int); tchar *operate(tchar, tchar *, tchar *); tchar *getinx(tchar *, int *); tchar *xset(tchar *, tchar ***); struct varent *getvx(tchar *, int); void doset(tchar **v) { 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 /* "(" */)) { 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" */)) { 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(tchar *cp, 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); } void asx(tchar *vp, int subscr, tchar *p) { 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(tchar *vp, int subscr) { 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 }; void dolet(tchar **v) { 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(tchar *cp, tchar ***vp) { 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(tchar op, tchar *vp, tchar *p) { tchar opr[2]; tchar *vec[5]; tchar **v = vec; tchar **vecp = v; 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(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)); } void putn1(int n) { #ifdef TRACE tprintf("TRACE- putn1()\n"); #endif if (n > 9) putn1(n / 10); *putp++ = n % 10 + '0'; } int getn(tchar *cp) { 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(tchar *var, struct varent *head) { 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(tchar *pat, struct varent *vp) { 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(tchar *name, struct varent *v) { int 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 */ void set(tchar *var, tchar *val) { 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); } void set1(tchar *var, tchar **vec, struct varent *head) { 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); } void setq(tchar *name, tchar **vec, struct varent *p) { struct varent *c; int 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); } void unset(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 } void unset1(tchar *v[], struct varent *head) { struct varent *vp; 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); } } void unsetv(tchar *var) { struct varent *vp; #ifdef TRACE tprintf("TRACE- unsetv()\n"); #endif if ((vp = adrof1(var, &shvhed)) == 0) udvar(var); unsetv1(vp); } void unsetv1(struct varent *p) { struct varent *c, *pp; int 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(p); balance(pp, f, 1); } void setNS(tchar *cp) { #ifdef TRACE tprintf("TRACE- setNS()\n"); #endif set(cp, S_ /* "" */); } void shift(tchar **v) { struct varent *argv; 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); } void exportpath(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. */ void balance(struct varent *p, int f, int d) { struct varent *pp; struct varent *t; /* used by the rotate macros */ int 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; } } void plist(struct varent *p) { struct varent *c; int 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; } }