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