1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.set.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ 2: /* 3: * sh.set.c: Setting and Clearing of variables 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: sh.set.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #include "ed.h" 45: #include "tw.h" 46: 47: extern Char HistLit; 48: extern bool GotTermCaps; 49: 50: static Char *getinx __P((Char *, int *)); 51: static void asx __P((Char *, int, Char *)); 52: static struct varent *getvx __P((Char *, int)); 53: static Char *xset __P((Char *, Char ***)); 54: static Char *operate __P((int, Char *, Char *)); 55: static void putn1 __P((int)); 56: static struct varent *madrof __P((Char *, struct varent *)); 57: static void unsetv1 __P((struct varent *)); 58: static void exportpath __P((Char **)); 59: static void balance __P((struct varent *, int, int)); 60: 61: /* 62: * C Shell 63: */ 64: 65: void 66: doset(v) 67: register Char **v; 68: { 69: register Char *p; 70: Char *vp, op; 71: Char **vecp; 72: bool hadsub; 73: int subscr; 74: 75: v++; 76: p = *v++; 77: if (p == 0) { 78: prvars(); 79: return; 80: } 81: do { 82: hadsub = 0; 83: vp = p; 84: if (letter(*p)) 85: for (; alnum(*p); p++) 86: continue; 87: if (vp == p || !letter(*vp)) 88: stderror(ERR_NAME | ERR_VARBEGIN); 89: if ((p - vp) > MAXVARLEN) { 90: stderror(ERR_NAME | ERR_VARTOOLONG); 91: return; 92: } 93: if (*p == '[') { 94: hadsub++; 95: p = getinx(p, &subscr); 96: } 97: if (op = *p) { 98: *p++ = 0; 99: if (*p == 0 && *v && **v == '(') 100: p = *v++; 101: } 102: else if (*v && eq(*v, STRequal)) { 103: op = '=', v++; 104: if (*v) 105: p = *v++; 106: } 107: if (op && op != '=') 108: stderror(ERR_NAME | ERR_SYNTAX); 109: if (eq(p, STRLparen)) { 110: register Char **e = v; 111: 112: if (hadsub) 113: stderror(ERR_NAME | ERR_SYNTAX); 114: for (;;) { 115: if (!*e) 116: stderror(ERR_NAME | ERR_MISSING, ')'); 117: if (**e == ')') 118: break; 119: e++; 120: } 121: p = *e; 122: *e = 0; 123: vecp = saveblk(v); 124: set1(vp, vecp, &shvhed); 125: *e = p; 126: v = e + 1; 127: } 128: else if (hadsub) 129: asx(vp, subscr, Strsave(p)); 130: else 131: set(vp, Strsave(p)); 132: if (eq(vp, STRpath)) { 133: exportpath(adrof(STRpath)->vec); 134: dohash(); 135: } 136: else if (eq(vp, STRhstc)) { 137: register Char *pn = value(STRhstc); 138: 139: HIST = *pn++; 140: HISTSUB = *pn; 141: } 142: else if (eq(vp, STRhstl)) { 143: HistLit = 1; 144: } 145: else if (eq(vp, STRuser)) { 146: Setenv(STRUSER, value(vp)); 147: Setenv(STRLOGNAME, value(vp)); 148: } 149: else if (eq(vp, STRwordchars)) { 150: word_chars = value(vp); 151: } 152: else if (eq(vp, STRterm)) { 153: #ifdef DOESNT_WORK_RIGHT 154: register Char *cp; 155: 156: #endif 157: Setenv(STRTRM, value(vp)); 158: #ifdef DOESNT_WORK_RIGHT 159: cp = getenv("TERMCAP"); 160: if (cp && (*cp != '/')) /* if TERMCAP and not a path */ 161: Unsetenv(STRTRMCAP); 162: #endif /* DOESNT_WORK_RIGHT */ 163: GotTermCaps = 0; 164: ed_I(); /* reset the editor */ 165: } 166: else if (eq(vp, STRhome)) { 167: register Char *cp; 168: 169: cp = Strsave(value(vp)); /* get the old value back */ 170: 171: /* 172: * convert to cononical pathname (possibly resolving symlinks) 173: */ 174: cp = dcanon(cp, cp); 175: 176: set(vp, Strsave(cp)); /* have to save the new val */ 177: 178: /* and now mirror home with HOME */ 179: Setenv(STRHOME, cp); 180: /* fix directory stack for new tilde home */ 181: dtilde(); 182: xfree((ptr_t) cp); 183: } 184: else if (eq(vp, STRedit)) { 185: editing = 1; 186: /* PWP: add more stuff in here later */ 187: } 188: else if (eq(vp, STRshlvl)) { 189: Setenv(STRSHLVL, value(vp)); 190: } 191: else if (eq(vp, STRbKslash_quote)) { 192: bslash_quote = 1; 193: } 194: else if (eq(vp, STRrecognize_only_executables)) { 195: tw_clear_comm_list(); 196: } 197: else if (eq(vp, STRwatch)) { 198: resetwatch(); 199: } 200: } while (p = *v++); 201: } 202: 203: static Char * 204: getinx(cp, ip) 205: register Char *cp; 206: register int *ip; 207: { 208: *ip = 0; 209: *cp++ = 0; 210: while (*cp && Isdigit(*cp)) 211: *ip = *ip * 10 + *cp++ - '0'; 212: if (*cp++ != ']') 213: stderror(ERR_NAME | ERR_SUBSCRIPT); 214: return (cp); 215: } 216: 217: static void 218: asx(vp, subscr, p) 219: Char *vp; 220: int subscr; 221: Char *p; 222: { 223: register struct varent *v = getvx(vp, subscr); 224: 225: xfree((ptr_t) v->vec[subscr - 1]); 226: v->vec[subscr - 1] = globone(p, G_APPEND); 227: } 228: 229: static struct varent * 230: getvx(vp, subscr) 231: Char *vp; 232: int subscr; 233: { 234: register struct varent *v = adrof(vp); 235: 236: if (v == 0) 237: udvar(vp); 238: if (subscr < 1 || subscr > blklen(v->vec)) 239: stderror(ERR_NAME | ERR_RANGE); 240: return (v); 241: } 242: 243: void 244: dolet(v) 245: Char **v; 246: { 247: register Char *p; 248: Char *vp, c, op; 249: bool hadsub; 250: int subscr; 251: 252: v++; 253: p = *v++; 254: if (p == 0) { 255: prvars(); 256: return; 257: } 258: do { 259: hadsub = 0; 260: vp = p; 261: if (letter(*p)) 262: for (; alnum(*p); p++) 263: continue; 264: if (vp == p || !letter(*vp)) 265: stderror(ERR_NAME | ERR_VARBEGIN); 266: if ((p - vp) > MAXVARLEN) 267: stderror(ERR_NAME | ERR_VARTOOLONG); 268: if (*p == '[') { 269: hadsub++; 270: p = getinx(p, &subscr); 271: } 272: if (*p == 0 && *v) 273: p = *v++; 274: if (op = *p) 275: *p++ = 0; 276: else 277: stderror(ERR_NAME | ERR_ASSIGN); 278: 279: /* 280: * if there is no expression after the '=' then print a "Syntax Error" 281: * message - strike 282: */ 283: if (*p == '\0' && *v == NULL) 284: stderror(ERR_NAME | ERR_ASSIGN); 285: 286: vp = Strsave(vp); 287: if (op == '=') { 288: c = '='; 289: p = xset(p, &v); 290: } 291: else { 292: c = *p++; 293: if (any("+-", c)) { 294: if (c != op || *p) 295: stderror(ERR_NAME | ERR_UNKNOWNOP); 296: p = Strsave(STR1); 297: } 298: else { 299: if (any("<>", op)) { 300: if (c != op) 301: stderror(ERR_NAME | ERR_UNKNOWNOP); 302: c = *p++; 303: stderror(ERR_NAME | ERR_SYNTAX); 304: } 305: if (c != '=') 306: stderror(ERR_NAME | ERR_UNKNOWNOP); 307: p = xset(p, &v); 308: } 309: } 310: if (op == '=') 311: if (hadsub) 312: asx(vp, subscr, p); 313: else 314: set(vp, p); 315: else if (hadsub) { 316: struct varent *gv = getvx(vp, subscr); 317: 318: asx(vp, subscr, operate(op, gv->vec[subscr - 1], p)); 319: } 320: else 321: set(vp, operate(op, value(vp), p)); 322: if (eq(vp, STRpath)) { 323: exportpath(adrof(STRpath)->vec); 324: dohash(); 325: } 326: xfree((ptr_t) vp); 327: if (c != '=') 328: xfree((ptr_t) p); 329: } while (p = *v++); 330: } 331: 332: static Char * 333: xset(cp, vp) 334: Char *cp, ***vp; 335: { 336: register Char *dp; 337: 338: if (*cp) { 339: dp = Strsave(cp); 340: --(*vp); 341: xfree((ptr_t) ** vp); 342: **vp = dp; 343: } 344: return (putn(exp(vp))); 345: } 346: 347: static Char * 348: operate(op, vp, p) 349: Char op, *vp, *p; 350: { 351: Char opr[2]; 352: Char *vec[5]; 353: register Char **v = vec; 354: Char **vecp = v; 355: register int i; 356: 357: if (op != '=') { 358: if (*vp) 359: *v++ = vp; 360: opr[0] = op; 361: opr[1] = 0; 362: *v++ = opr; 363: if (op == '<' || op == '>') 364: *v++ = opr; 365: } 366: *v++ = p; 367: *v++ = 0; 368: i = exp(&vecp); 369: if (*vecp) 370: stderror(ERR_NAME | ERR_EXPRESSION); 371: return (putn(i)); 372: } 373: 374: static Char *putp; 375: 376: Char * 377: putn(n) 378: register int n; 379: { 380: int num; 381: static Char number[15]; 382: 383: putp = number; 384: if (n < 0) { 385: n = -n; 386: *putp++ = '-'; 387: } 388: num = 2; /* comfuse lint */ 389: if (sizeof(int) == num && n == -32768) { 390: *putp++ = '3'; 391: n = 2768; 392: #ifdef pdp11 393: } 394: #else 395: } 396: else { 397: num = 4; /* comfuse lint */ 398: if (sizeof(int) == num && n == -2147483648) { 399: *putp++ = '2'; 400: n = 147483648; 401: } 402: } 403: #endif 404: putn1(n); 405: *putp = 0; 406: return (Strsave(number)); 407: } 408: 409: static void 410: putn1(n) 411: register int n; 412: { 413: if (n > 9) 414: putn1(n / 10); 415: *putp++ = n % 10 + '0'; 416: } 417: 418: int 419: getn(cp) 420: register Char *cp; 421: { 422: register int n; 423: int sign; 424: 425: sign = 0; 426: if (cp[0] == '+' && cp[1]) 427: cp++; 428: if (*cp == '-') { 429: sign++; 430: cp++; 431: if (!Isdigit(*cp)) 432: stderror(ERR_NAME | ERR_BADNUM); 433: } 434: n = 0; 435: while (Isdigit(*cp)) 436: n = n * 10 + *cp++ - '0'; 437: if (*cp) 438: stderror(ERR_NAME | ERR_BADNUM); 439: return (sign ? -n : n); 440: } 441: 442: Char * 443: value1(var, head) 444: Char *var; 445: struct varent *head; 446: { 447: register struct varent *vp; 448: 449: vp = adrof1(var, head); 450: return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]); 451: } 452: 453: static struct varent * 454: madrof(pat, vp) 455: Char *pat; 456: register struct varent *vp; 457: { 458: register struct varent *vp1; 459: 460: for (; vp; vp = vp->v_right) { 461: if (vp->v_left && (vp1 = madrof(pat, vp->v_left))) 462: return vp1; 463: if (Gmatch(vp->v_name, pat)) 464: return vp; 465: } 466: return vp; 467: } 468: 469: struct varent * 470: adrof1(name, v) 471: register Char *name; 472: register struct varent *v; 473: { 474: register cmp; 475: 476: v = v->v_left; 477: while (v && ((cmp = *name - *v->v_name) || (cmp = Strcmp(name, v->v_name)))) 478: if (cmp < 0) 479: v = v->v_left; 480: else 481: v = v->v_right; 482: return v; 483: } 484: 485: /* 486: * The caller is responsible for putting value in a safe place 487: */ 488: void 489: set(var, val) 490: Char *var, *val; 491: { 492: register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **))); 493: 494: vec[0] = val; 495: vec[1] = 0; 496: set1(var, vec, &shvhed); 497: } 498: 499: void 500: set1(var, vec, head) 501: Char *var, **vec; 502: struct varent *head; 503: { 504: register Char **oldv = vec; 505: 506: gflag = 0; 507: tglob(oldv); 508: if (gflag) { 509: vec = globall(oldv); 510: if (vec == 0) { 511: blkfree(oldv); 512: stderror(ERR_NAME | ERR_NOMATCH); 513: return; 514: } 515: blkfree(oldv); 516: gargv = 0; 517: } 518: setq(var, vec, head); 519: } 520: 521: 522: void 523: setq(name, vec, p) 524: Char *name, **vec; 525: register struct varent *p; 526: { 527: register struct varent *c; 528: register f; 529: 530: f = 0; /* tree hangs off the header's left link */ 531: while (c = p->v_link[f]) { 532: if ((f = *name - *c->v_name) == 0 && 533: (f = Strcmp(name, c->v_name)) == 0) { 534: blkfree(c->vec); 535: goto found; 536: } 537: p = c; 538: f = f > 0; 539: } 540: p->v_link[f] = c = (struct varent *) xmalloc((size_t)sizeof(struct varent)); 541: c->v_name = Strsave(name); 542: c->v_bal = 0; 543: c->v_left = c->v_right = 0; 544: c->v_parent = p; 545: balance(p, f, 0); 546: found: 547: trim(c->vec = vec); 548: } 549: 550: void 551: unset(v) 552: Char *v[]; 553: { 554: register bool did_only; 555: 556: did_only = adrof(STRrecognize_only_executables) != 0; 557: unset1(v, &shvhed); 558: if (adrof(STRhstc) == 0) { 559: HIST = '!'; 560: HISTSUB = '^'; 561: } 562: if (adrof(STRhstl) == 0) 563: HistLit = 0; 564: if (adrof(STRwordchars) == 0) 565: word_chars = STR_WORD_CHARS; 566: if (adrof(STRedit) == 0) 567: editing = 0; 568: if (adrof(STRbKslash_quote) == 0) 569: bslash_quote = 0; 570: if (did_only && adrof(STRrecognize_only_executables) == 0) 571: tw_clear_comm_list(); 572: } 573: 574: void 575: unset1(v, head) 576: register Char *v[]; 577: struct varent *head; 578: { 579: register struct varent *vp; 580: register int cnt; 581: 582: while (*++v) { 583: cnt = 0; 584: while (vp = madrof(*v, head->v_left)) 585: unsetv1(vp), cnt++; 586: if (cnt == 0) 587: setname(short2str(*v)); 588: } 589: } 590: 591: void 592: unsetv(var) 593: Char *var; 594: { 595: register struct varent *vp; 596: 597: if ((vp = adrof1(var, &shvhed)) == 0) 598: udvar(var); 599: unsetv1(vp); 600: } 601: 602: static void 603: unsetv1(p) 604: register struct varent *p; 605: { 606: register struct varent *c, *pp; 607: register f; 608: 609: /* 610: * Free associated memory first to avoid complications. 611: */ 612: blkfree(p->vec); 613: xfree((ptr_t) p->v_name); 614: /* 615: * If p is missing one child, then we can move the other into where p is. 616: * Otherwise, we find the predecessor of p, which is guaranteed to have no 617: * right child, copy it into p, and move it's left child into it. 618: */ 619: if (p->v_right == 0) 620: c = p->v_left; 621: else if (p->v_left == 0) 622: c = p->v_right; 623: else { 624: for (c = p->v_left; c->v_right; c = c->v_right); 625: p->v_name = c->v_name; 626: p->vec = c->vec; 627: p = c; 628: c = p->v_left; 629: } 630: /* 631: * Move c into where p is. 632: */ 633: pp = p->v_parent; 634: f = pp->v_right == p; 635: if (pp->v_link[f] = c) 636: c->v_parent = pp; 637: /* 638: * Free the deleted node, and rebalance. 639: */ 640: xfree((ptr_t) p); 641: balance(pp, f, 1); 642: } 643: 644: void 645: setNS(cp) 646: Char *cp; 647: { 648: set(cp, Strsave(STRNULL)); 649: } 650: 651: void 652: shift(v) 653: register Char **v; 654: { 655: register struct varent *argv; 656: register Char *name; 657: 658: v++; 659: name = *v; 660: if (name == 0) 661: name = STRargv; 662: else 663: (void) strip(name); 664: argv = adrof(name); 665: if (argv == 0) 666: udvar(name); 667: if (argv->vec[0] == 0) 668: stderror(ERR_NAME | ERR_NOMORE); 669: lshift(argv->vec, 1); 670: } 671: 672: static void 673: exportpath(val) 674: Char **val; 675: { 676: Char exppath[BUFSIZ]; 677: 678: exppath[0] = 0; 679: if (val) 680: while (*val) { 681: if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) { 682: xprintf("Warning: ridiculously long PATH truncated\n"); 683: break; 684: } 685: (void) Strcat(exppath, *val++); 686: if (*val == 0 || eq(*val, STRRparen)) 687: break; 688: (void) Strcat(exppath, STRcolon); 689: } 690: Setenv(STRPATH, exppath); 691: } 692: 693: #ifndef lint 694: /* 695: * Lint thinks these have null effect 696: */ 697: /* macros to do single rotations on node p */ 698: #define rright(p) (\ 699: t = (p)->v_left,\ 700: (t)->v_parent = (p)->v_parent,\ 701: ((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\ 702: (t->v_right = (p))->v_parent = t,\ 703: (p) = t) 704: #define rleft(p) (\ 705: t = (p)->v_right,\ 706: (t)->v_parent = (p)->v_parent,\ 707: ((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\ 708: (t->v_left = (p))->v_parent = t,\ 709: (p) = t) 710: #else 711: struct varent * 712: rleft(p) 713: struct varent *p; 714: { 715: return (p); 716: } 717: struct varent * 718: rright(p) 719: struct varent *p; 720: { 721: return (p); 722: } 723: 724: #endif /* ! lint */ 725: 726: 727: /* 728: * Rebalance a tree, starting at p and up. 729: * F == 0 means we've come from p's left child. 730: * D == 1 means we've just done a delete, otherwise an insert. 731: */ 732: static void 733: balance(p, f, d) 734: register struct varent *p; 735: register int f, d; 736: { 737: register struct varent *pp; 738: 739: #ifndef lint 740: register struct varent *t; /* used by the rotate macros */ 741: 742: #endif 743: register ff; 744: 745: /* 746: * Ok, from here on, p is the node we're operating on; pp is it's parent; f 747: * is the branch of p from which we have come; ff is the branch of pp which 748: * is p. 749: */ 750: for (; pp = p->v_parent; p = pp, f = ff) { 751: ff = pp->v_right == p; 752: if (f ^ d) { /* right heavy */ 753: switch (p->v_bal) { 754: case -1: /* was left heavy */ 755: p->v_bal = 0; 756: break; 757: case 0: /* was balanced */ 758: p->v_bal = 1; 759: break; 760: case 1: /* was already right heavy */ 761: switch (p->v_right->v_bal) { 762: case 1: /* sigle rotate */ 763: pp->v_link[ff] = rleft(p); 764: p->v_left->v_bal = 0; 765: p->v_bal = 0; 766: break; 767: case 0: /* single rotate */ 768: pp->v_link[ff] = rleft(p); 769: p->v_left->v_bal = 1; 770: p->v_bal = -1; 771: break; 772: case -1: /* double rotate */ 773: (void) rright(p->v_right); 774: pp->v_link[ff] = rleft(p); 775: p->v_left->v_bal = 776: p->v_bal < 1 ? 0 : -1; 777: p->v_right->v_bal = 778: p->v_bal > -1 ? 0 : 1; 779: p->v_bal = 0; 780: break; 781: } 782: break; 783: } 784: } 785: else { /* left heavy */ 786: switch (p->v_bal) { 787: case 1: /* was right heavy */ 788: p->v_bal = 0; 789: break; 790: case 0: /* was balanced */ 791: p->v_bal = -1; 792: break; 793: case -1: /* was already left heavy */ 794: switch (p->v_left->v_bal) { 795: case -1: /* single rotate */ 796: pp->v_link[ff] = rright(p); 797: p->v_right->v_bal = 0; 798: p->v_bal = 0; 799: break; 800: case 0: /* signle rotate */ 801: pp->v_link[ff] = rright(p); 802: p->v_right->v_bal = -1; 803: p->v_bal = 1; 804: break; 805: case 1: /* double rotate */ 806: (void) rleft(p->v_left); 807: pp->v_link[ff] = rright(p); 808: p->v_left->v_bal = 809: p->v_bal < 1 ? 0 : -1; 810: p->v_right->v_bal = 811: p->v_bal > -1 ? 0 : 1; 812: p->v_bal = 0; 813: break; 814: } 815: break; 816: } 817: } 818: /* 819: * If from insert, then we terminate when p is balanced. If from 820: * delete, then we terminate when p is unbalanced. 821: */ 822: if ((p->v_bal == 0) ^ d) 823: break; 824: } 825: } 826: 827: void 828: plist(p) 829: register struct varent *p; 830: { 831: register struct varent *c; 832: register len; 833: 834: if (setintr) 835: #ifdef BSDSIGS 836: (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 837: #else /* BSDSIGS */ 838: (void) sigrelse(SIGINT); 839: #endif /* BSDSIGS */ 840: 841: for (;;) { 842: while (p->v_left) 843: p = p->v_left; 844: x: 845: if (p->v_parent == 0) /* is it the header? */ 846: return; 847: len = blklen(p->vec); 848: xprintf(short2str(p->v_name)); 849: xputchar('\t'); 850: if (len != 1) 851: xputchar('('); 852: blkpr(p->vec); 853: if (len != 1) 854: xputchar(')'); 855: xputchar('\n'); 856: if (p->v_right) { 857: p = p->v_right; 858: continue; 859: } 860: do { 861: c = p; 862: p = p->v_parent; 863: } while (p->v_right == c); 864: goto x; 865: } 866: }