|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)names.c 2.9 (Berkeley) 8/11/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * Mail -- a mail program ! 7: * ! 8: * Handle name lists. ! 9: */ ! 10: ! 11: #include "rcv.h" ! 12: ! 13: /* ! 14: * Allocate a single element of a name list, ! 15: * initialize its name field to the passed ! 16: * name and return it. ! 17: */ ! 18: ! 19: struct name * ! 20: nalloc(str) ! 21: char str[]; ! 22: { ! 23: register struct name *np; ! 24: ! 25: np = (struct name *) salloc(sizeof *np); ! 26: np->n_flink = NIL; ! 27: np->n_blink = NIL; ! 28: np->n_type = -1; ! 29: np->n_name = savestr(str); ! 30: return(np); ! 31: } ! 32: ! 33: /* ! 34: * Find the tail of a list and return it. ! 35: */ ! 36: ! 37: struct name * ! 38: tailof(name) ! 39: struct name *name; ! 40: { ! 41: register struct name *np; ! 42: ! 43: np = name; ! 44: if (np == NIL) ! 45: return(NIL); ! 46: while (np->n_flink != NIL) ! 47: np = np->n_flink; ! 48: return(np); ! 49: } ! 50: ! 51: /* ! 52: * Extract a list of names from a line, ! 53: * and make a list of names from it. ! 54: * Return the list or NIL if none found. ! 55: */ ! 56: ! 57: struct name * ! 58: extract(line, ntype) ! 59: char line[]; ! 60: { ! 61: register char *cp; ! 62: register struct name *top, *np, *t; ! 63: char nbuf[BUFSIZ], abuf[BUFSIZ]; ! 64: ! 65: if (line == NOSTR || strlen(line) == 0) ! 66: return(NIL); ! 67: top = NIL; ! 68: np = NIL; ! 69: cp = line; ! 70: while ((cp = yankword(cp, nbuf)) != NOSTR) { ! 71: if (np != NIL && equal(nbuf, "at")) { ! 72: strcpy(abuf, nbuf); ! 73: if ((cp = yankword(cp, nbuf)) == NOSTR) { ! 74: strcpy(nbuf, abuf); ! 75: goto normal; ! 76: } ! 77: strcpy(abuf, np->n_name); ! 78: stradd(abuf, '@'); ! 79: strcat(abuf, nbuf); ! 80: np->n_name = savestr(abuf); ! 81: continue; ! 82: } ! 83: normal: ! 84: t = nalloc(nbuf); ! 85: t->n_type = ntype; ! 86: if (top == NIL) ! 87: top = t; ! 88: else ! 89: np->n_flink = t; ! 90: t->n_blink = np; ! 91: np = t; ! 92: } ! 93: return(top); ! 94: } ! 95: ! 96: /* ! 97: * Turn a list of names into a string of the same names. ! 98: */ ! 99: ! 100: char * ! 101: detract(np, ntype) ! 102: register struct name *np; ! 103: { ! 104: register int s; ! 105: register char *cp, *top; ! 106: register struct name *p; ! 107: register int comma; ! 108: ! 109: comma = ntype & GCOMMA; ! 110: if (np == NIL) ! 111: return(NOSTR); ! 112: ntype &= ~GCOMMA; ! 113: s = 0; ! 114: if (debug && comma) ! 115: fprintf(stderr, "detract asked to insert commas\n"); ! 116: for (p = np; p != NIL; p = p->n_flink) { ! 117: if (ntype && (p->n_type & GMASK) != ntype) ! 118: continue; ! 119: s += strlen(p->n_name) + 1; ! 120: if (comma) ! 121: s++; ! 122: } ! 123: if (s == 0) ! 124: return(NOSTR); ! 125: s += 2; ! 126: top = salloc(s); ! 127: cp = top; ! 128: for (p = np; p != NIL; p = p->n_flink) { ! 129: if (ntype && (p->n_type & GMASK) != ntype) ! 130: continue; ! 131: cp = copy(p->n_name, cp); ! 132: if (comma && p->n_flink != NIL) ! 133: *cp++ = ','; ! 134: *cp++ = ' '; ! 135: } ! 136: *--cp = 0; ! 137: if (comma && *--cp == ',') ! 138: *cp = 0; ! 139: return(top); ! 140: } ! 141: ! 142: /* ! 143: * Grab a single word (liberal word) ! 144: * Throw away things between ()'s. ! 145: */ ! 146: ! 147: char * ! 148: yankword(ap, wbuf) ! 149: char *ap, wbuf[]; ! 150: { ! 151: register char *cp, *cp2; ! 152: ! 153: do { ! 154: for (cp = ap; *cp && any(*cp, " \t,"); cp++) ! 155: ; ! 156: if (*cp == '(') { ! 157: while (*cp && *cp != ')') ! 158: cp++; ! 159: if (*cp) ! 160: cp++; ! 161: } ! 162: if (*cp == '\0') ! 163: return(NOSTR); ! 164: } while (any(*cp, " \t,(")); ! 165: for (cp2 = wbuf; *cp && !any(*cp, " \t,("); *cp2++ = *cp++) ! 166: ; ! 167: *cp2 = '\0'; ! 168: return(cp); ! 169: } ! 170: ! 171: /* ! 172: * Verify that all the users in the list of names are ! 173: * legitimate. Bitch about and delink those who aren't. ! 174: */ ! 175: ! 176: struct name * ! 177: verify(names) ! 178: struct name *names; ! 179: { ! 180: register struct name *np, *top, *t, *x; ! 181: register char *cp; ! 182: ! 183: #ifdef SENDMAIL ! 184: return(names); ! 185: #else ! 186: top = names; ! 187: np = names; ! 188: while (np != NIL) { ! 189: if (np->n_type & GDEL) { ! 190: np = np->n_flink; ! 191: continue; ! 192: } ! 193: for (cp = "!:@^"; *cp; cp++) ! 194: if (any(*cp, np->n_name)) ! 195: break; ! 196: if (*cp != 0) { ! 197: np = np->n_flink; ! 198: continue; ! 199: } ! 200: cp = np->n_name; ! 201: while (*cp == '\\') ! 202: cp++; ! 203: if (equal(cp, "msgs") || ! 204: getuserid(cp) != -1) { ! 205: np = np->n_flink; ! 206: continue; ! 207: } ! 208: fprintf(stderr, "Can't send to %s\n", np->n_name); ! 209: senderr++; ! 210: if (np == top) { ! 211: top = np->n_flink; ! 212: if (top != NIL) ! 213: top->n_blink = NIL; ! 214: np = top; ! 215: continue; ! 216: } ! 217: x = np->n_blink; ! 218: t = np->n_flink; ! 219: x->n_flink = t; ! 220: if (t != NIL) ! 221: t->n_blink = x; ! 222: np = t; ! 223: } ! 224: return(top); ! 225: #endif ! 226: } ! 227: ! 228: /* ! 229: * For each recipient in the passed name list with a / ! 230: * in the name, append the message to the end of the named file ! 231: * and remove him from the recipient list. ! 232: * ! 233: * Recipients whose name begins with | are piped through the given ! 234: * program and removed. ! 235: */ ! 236: ! 237: struct name * ! 238: outof(names, fo, hp) ! 239: struct name *names; ! 240: FILE *fo; ! 241: struct header *hp; ! 242: { ! 243: register int c; ! 244: register struct name *np, *top, *t, *x; ! 245: long now; ! 246: char *date, *fname, *shell, *ctime(); ! 247: FILE *fout, *fin; ! 248: int ispipe, s, pid; ! 249: extern char tempEdit[]; ! 250: ! 251: top = names; ! 252: np = names; ! 253: time(&now); ! 254: date = ctime(&now); ! 255: while (np != NIL) { ! 256: if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { ! 257: np = np->n_flink; ! 258: continue; ! 259: } ! 260: ispipe = np->n_name[0] == '|'; ! 261: if (ispipe) ! 262: fname = np->n_name+1; ! 263: else ! 264: fname = expand(np->n_name); ! 265: ! 266: /* ! 267: * See if we have copied the complete message out yet. ! 268: * If not, do so. ! 269: */ ! 270: ! 271: if (image < 0) { ! 272: if ((fout = fopen(tempEdit, "a")) == NULL) { ! 273: perror(tempEdit); ! 274: senderr++; ! 275: goto cant; ! 276: } ! 277: image = open(tempEdit, 2); ! 278: unlink(tempEdit); ! 279: if (image < 0) { ! 280: perror(tempEdit); ! 281: senderr++; ! 282: goto cant; ! 283: } ! 284: else { ! 285: rewind(fo); ! 286: fprintf(fout, "From %s %s", myname, date); ! 287: puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); ! 288: while ((c = getc(fo)) != EOF) ! 289: putc(c, fout); ! 290: rewind(fo); ! 291: putc('\n', fout); ! 292: fflush(fout); ! 293: if (ferror(fout)) ! 294: perror(tempEdit); ! 295: fclose(fout); ! 296: } ! 297: } ! 298: ! 299: /* ! 300: * Now either copy "image" to the desired file ! 301: * or give it as the standard input to the desired ! 302: * program as appropriate. ! 303: */ ! 304: ! 305: if (ispipe) { ! 306: wait(&s); ! 307: switch (pid = fork()) { ! 308: case 0: ! 309: sigchild(); ! 310: sigsys(SIGHUP, SIG_IGN); ! 311: sigsys(SIGINT, SIG_IGN); ! 312: sigsys(SIGQUIT, SIG_IGN); ! 313: close(0); ! 314: dup(image); ! 315: close(image); ! 316: if ((shell = value("SHELL")) == NOSTR) ! 317: shell = SHELL; ! 318: execl(shell, shell, "-c", fname, 0); ! 319: perror(shell); ! 320: exit(1); ! 321: break; ! 322: ! 323: case -1: ! 324: perror("fork"); ! 325: senderr++; ! 326: goto cant; ! 327: } ! 328: } ! 329: else { ! 330: if ((fout = fopen(fname, "a")) == NULL) { ! 331: perror(fname); ! 332: senderr++; ! 333: goto cant; ! 334: } ! 335: fin = Fdopen(image, "r"); ! 336: if (fin == NULL) { ! 337: fprintf(stderr, "Can't reopen image\n"); ! 338: fclose(fout); ! 339: senderr++; ! 340: goto cant; ! 341: } ! 342: rewind(fin); ! 343: while ((c = getc(fin)) != EOF) ! 344: putc(c, fout); ! 345: if (ferror(fout)) ! 346: senderr++, perror(fname); ! 347: fclose(fout); ! 348: fclose(fin); ! 349: } ! 350: ! 351: cant: ! 352: ! 353: /* ! 354: * In days of old we removed the entry from the ! 355: * the list; now for sake of header expansion ! 356: * we leave it in and mark it as deleted. ! 357: */ ! 358: ! 359: #ifdef CRAZYWOW ! 360: if (np == top) { ! 361: top = np->n_flink; ! 362: if (top != NIL) ! 363: top->n_blink = NIL; ! 364: np = top; ! 365: continue; ! 366: } ! 367: x = np->n_blink; ! 368: t = np->n_flink; ! 369: x->n_flink = t; ! 370: if (t != NIL) ! 371: t->n_blink = x; ! 372: np = t; ! 373: #endif ! 374: ! 375: np->n_type |= GDEL; ! 376: np = np->n_flink; ! 377: } ! 378: if (image >= 0) { ! 379: close(image); ! 380: image = -1; ! 381: } ! 382: return(top); ! 383: } ! 384: ! 385: /* ! 386: * Determine if the passed address is a local "send to file" address. ! 387: * If any of the network metacharacters precedes any slashes, it can't ! 388: * be a filename. We cheat with .'s to allow path names like ./... ! 389: */ ! 390: isfileaddr(name) ! 391: char *name; ! 392: { ! 393: register char *cp; ! 394: extern char *metanet; ! 395: ! 396: if (any('@', name)) ! 397: return(0); ! 398: if (*name == '+') ! 399: return(1); ! 400: for (cp = name; *cp; cp++) { ! 401: if (*cp == '.') ! 402: continue; ! 403: if (any(*cp, metanet)) ! 404: return(0); ! 405: if (*cp == '/') ! 406: return(1); ! 407: } ! 408: return(0); ! 409: } ! 410: ! 411: /* ! 412: * Map all of the aliased users in the invoker's mailrc ! 413: * file and insert them into the list. ! 414: * Changed after all these months of service to recursively ! 415: * expand names (2/14/80). ! 416: */ ! 417: ! 418: struct name * ! 419: usermap(names) ! 420: struct name *names; ! 421: { ! 422: register struct name *new, *np, *cp; ! 423: struct name *getto; ! 424: struct grouphead *gh; ! 425: register int metoo; ! 426: ! 427: new = NIL; ! 428: np = names; ! 429: getto = NIL; ! 430: metoo = (value("metoo") != NOSTR); ! 431: while (np != NIL) { ! 432: if (np->n_name[0] == '\\') { ! 433: cp = np->n_flink; ! 434: new = put(new, np); ! 435: np = cp; ! 436: continue; ! 437: } ! 438: gh = findgroup(np->n_name); ! 439: cp = np->n_flink; ! 440: if (gh != NOGRP) ! 441: new = gexpand(new, gh, metoo, np->n_type); ! 442: else ! 443: new = put(new, np); ! 444: np = cp; ! 445: } ! 446: return(new); ! 447: } ! 448: ! 449: /* ! 450: * Recursively expand a group name. We limit the expansion to some ! 451: * fixed level to keep things from going haywire. ! 452: * Direct recursion is not expanded for convenience. ! 453: */ ! 454: ! 455: struct name * ! 456: gexpand(nlist, gh, metoo, ntype) ! 457: struct name *nlist; ! 458: struct grouphead *gh; ! 459: { ! 460: struct group *gp; ! 461: struct grouphead *ngh; ! 462: struct name *np; ! 463: static int depth; ! 464: char *cp; ! 465: ! 466: if (depth > MAXEXP) { ! 467: printf("Expanding alias to depth larger than %d\n", MAXEXP); ! 468: return(nlist); ! 469: } ! 470: depth++; ! 471: for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { ! 472: cp = gp->ge_name; ! 473: if (*cp == '\\') ! 474: goto quote; ! 475: if (strcmp(cp, gh->g_name) == 0) ! 476: goto quote; ! 477: if ((ngh = findgroup(cp)) != NOGRP) { ! 478: nlist = gexpand(nlist, ngh, metoo, ntype); ! 479: continue; ! 480: } ! 481: quote: ! 482: np = nalloc(cp); ! 483: np->n_type = ntype; ! 484: /* ! 485: * At this point should allow to expand ! 486: * to self if only person in group ! 487: */ ! 488: if (gp == gh->g_list && gp->ge_link == NOGE) ! 489: goto skip; ! 490: if (!metoo && strcmp(cp, myname) == 0) ! 491: np->n_type |= GDEL; ! 492: skip: ! 493: nlist = put(nlist, np); ! 494: } ! 495: depth--; ! 496: return(nlist); ! 497: } ! 498: ! 499: ! 500: ! 501: /* ! 502: * Compute the length of the passed name list and ! 503: * return it. ! 504: */ ! 505: ! 506: lengthof(name) ! 507: struct name *name; ! 508: { ! 509: register struct name *np; ! 510: register int c; ! 511: ! 512: for (c = 0, np = name; np != NIL; c++, np = np->n_flink) ! 513: ; ! 514: return(c); ! 515: } ! 516: ! 517: /* ! 518: * Concatenate the two passed name lists, return the result. ! 519: */ ! 520: ! 521: struct name * ! 522: cat(n1, n2) ! 523: struct name *n1, *n2; ! 524: { ! 525: register struct name *tail; ! 526: ! 527: if (n1 == NIL) ! 528: return(n2); ! 529: if (n2 == NIL) ! 530: return(n1); ! 531: tail = tailof(n1); ! 532: tail->n_flink = n2; ! 533: n2->n_blink = tail; ! 534: return(n1); ! 535: } ! 536: ! 537: /* ! 538: * Unpack the name list onto a vector of strings. ! 539: * Return an error if the name list won't fit. ! 540: */ ! 541: ! 542: char ** ! 543: unpack(np) ! 544: struct name *np; ! 545: { ! 546: register char **ap, **top; ! 547: register struct name *n; ! 548: char *cp; ! 549: char hbuf[10]; ! 550: int t, extra, metoo, verbose; ! 551: ! 552: n = np; ! 553: if ((t = lengthof(n)) == 0) ! 554: panic("No names to unpack"); ! 555: ! 556: /* ! 557: * Compute the number of extra arguments we will need. ! 558: * We need at least two extra -- one for "mail" and one for ! 559: * the terminating 0 pointer. Additional spots may be needed ! 560: * to pass along -r and -f to the host mailer. ! 561: */ ! 562: ! 563: extra = 2; ! 564: if (rflag != NOSTR) ! 565: extra += 2; ! 566: #ifdef SENDMAIL ! 567: extra++; ! 568: metoo = value("metoo") != NOSTR; ! 569: if (metoo) ! 570: extra++; ! 571: verbose = value("verbose") != NOSTR; ! 572: if (verbose) ! 573: extra++; ! 574: #endif SENDMAIL ! 575: if (hflag) ! 576: extra += 2; ! 577: top = (char **) salloc((t + extra) * sizeof cp); ! 578: ap = top; ! 579: *ap++ = "send-mail"; ! 580: if (rflag != NOSTR) { ! 581: *ap++ = "-r"; ! 582: *ap++ = rflag; ! 583: } ! 584: #ifdef SENDMAIL ! 585: *ap++ = "-i"; ! 586: if (metoo) ! 587: *ap++ = "-m"; ! 588: if (verbose) ! 589: *ap++ = "-v"; ! 590: #endif SENDMAIL ! 591: if (hflag) { ! 592: *ap++ = "-h"; ! 593: sprintf(hbuf, "%d", hflag); ! 594: *ap++ = savestr(hbuf); ! 595: } ! 596: while (n != NIL) { ! 597: if (n->n_type & GDEL) { ! 598: n = n->n_flink; ! 599: continue; ! 600: } ! 601: *ap++ = n->n_name; ! 602: n = n->n_flink; ! 603: } ! 604: *ap = NOSTR; ! 605: return(top); ! 606: } ! 607: ! 608: /* ! 609: * See if the user named himself as a destination ! 610: * for outgoing mail. If so, set the global flag ! 611: * selfsent so that we avoid removing his mailbox. ! 612: */ ! 613: ! 614: mechk(names) ! 615: struct name *names; ! 616: { ! 617: register struct name *np; ! 618: ! 619: for (np = names; np != NIL; np = np->n_flink) ! 620: if ((np->n_type & GDEL) == 0 && equal(np->n_name, myname)) { ! 621: selfsent++; ! 622: return; ! 623: } ! 624: } ! 625: ! 626: /* ! 627: * Remove all of the duplicates from the passed name list by ! 628: * insertion sorting them, then checking for dups. ! 629: * Return the head of the new list. ! 630: */ ! 631: ! 632: struct name * ! 633: elide(names) ! 634: struct name *names; ! 635: { ! 636: register struct name *np, *t, *new; ! 637: struct name *x; ! 638: ! 639: if (names == NIL) ! 640: return(NIL); ! 641: new = names; ! 642: np = names; ! 643: np = np->n_flink; ! 644: if (np != NIL) ! 645: np->n_blink = NIL; ! 646: new->n_flink = NIL; ! 647: while (np != NIL) { ! 648: t = new; ! 649: while (nstrcmp(t->n_name, np->n_name) < 0) { ! 650: if (t->n_flink == NIL) ! 651: break; ! 652: t = t->n_flink; ! 653: } ! 654: ! 655: /* ! 656: * If we ran out of t's, put the new entry after ! 657: * the current value of t. ! 658: */ ! 659: ! 660: if (nstrcmp(t->n_name, np->n_name) < 0) { ! 661: t->n_flink = np; ! 662: np->n_blink = t; ! 663: t = np; ! 664: np = np->n_flink; ! 665: t->n_flink = NIL; ! 666: continue; ! 667: } ! 668: ! 669: /* ! 670: * Otherwise, put the new entry in front of the ! 671: * current t. If at the front of the list, ! 672: * the new guy becomes the new head of the list. ! 673: */ ! 674: ! 675: if (t == new) { ! 676: t = np; ! 677: np = np->n_flink; ! 678: t->n_flink = new; ! 679: new->n_blink = t; ! 680: t->n_blink = NIL; ! 681: new = t; ! 682: continue; ! 683: } ! 684: ! 685: /* ! 686: * The normal case -- we are inserting into the ! 687: * middle of the list. ! 688: */ ! 689: ! 690: x = np; ! 691: np = np->n_flink; ! 692: x->n_flink = t; ! 693: x->n_blink = t->n_blink; ! 694: t->n_blink->n_flink = x; ! 695: t->n_blink = x; ! 696: } ! 697: ! 698: /* ! 699: * Now the list headed up by new is sorted. ! 700: * Go through it and remove duplicates. ! 701: */ ! 702: ! 703: np = new; ! 704: while (np != NIL) { ! 705: t = np; ! 706: while (t->n_flink!=NIL && ! 707: icequal(np->n_name,t->n_flink->n_name)) ! 708: t = t->n_flink; ! 709: if (t == np || t == NIL) { ! 710: np = np->n_flink; ! 711: continue; ! 712: } ! 713: ! 714: /* ! 715: * Now t points to the last entry with the same name ! 716: * as np. Make np point beyond t. ! 717: */ ! 718: ! 719: np->n_flink = t->n_flink; ! 720: if (t->n_flink != NIL) ! 721: t->n_flink->n_blink = np; ! 722: np = np->n_flink; ! 723: } ! 724: return(new); ! 725: } ! 726: ! 727: /* ! 728: * Version of strcmp which ignores case differences. ! 729: */ ! 730: ! 731: nstrcmp(s1, s2) ! 732: register char *s1, *s2; ! 733: { ! 734: register int c1, c2; ! 735: ! 736: do { ! 737: c1 = *s1++; ! 738: c2 = *s2++; ! 739: } while (c1 && c1 == c2); ! 740: return(c1 - c2); ! 741: } ! 742: ! 743: /* ! 744: * Put another node onto a list of names and return ! 745: * the list. ! 746: */ ! 747: ! 748: struct name * ! 749: put(list, node) ! 750: struct name *list, *node; ! 751: { ! 752: node->n_flink = list; ! 753: node->n_blink = NIL; ! 754: if (list != NIL) ! 755: list->n_blink = node; ! 756: return(node); ! 757: } ! 758: ! 759: /* ! 760: * Determine the number of elements in ! 761: * a name list and return it. ! 762: */ ! 763: ! 764: count(np) ! 765: register struct name *np; ! 766: { ! 767: register int c = 0; ! 768: ! 769: while (np != NIL) { ! 770: c++; ! 771: np = np->n_flink; ! 772: } ! 773: return(c); ! 774: } ! 775: ! 776: cmpdomain(name, dname) ! 777: register char *name, *dname; ! 778: { ! 779: char buf[BUFSIZ]; ! 780: ! 781: strcpy(buf, dname); ! 782: buf[strlen(name)] = '\0'; ! 783: return(icequal(name, buf)); ! 784: } ! 785: ! 786: /* ! 787: * Delete the given name from a namelist, using the passed ! 788: * function to compare the names. ! 789: */ ! 790: struct name * ! 791: delname(np, name, cmpfun) ! 792: register struct name *np; ! 793: char name[]; ! 794: int (* cmpfun)(); ! 795: { ! 796: register struct name *p; ! 797: ! 798: for (p = np; p != NIL; p = p->n_flink) ! 799: if ((* cmpfun)(p->n_name, name)) { ! 800: if (p->n_blink == NIL) { ! 801: if (p->n_flink != NIL) ! 802: p->n_flink->n_blink = NIL; ! 803: np = p->n_flink; ! 804: continue; ! 805: } ! 806: if (p->n_flink == NIL) { ! 807: if (p->n_blink != NIL) ! 808: p->n_blink->n_flink = NIL; ! 809: continue; ! 810: } ! 811: p->n_blink->n_flink = p->n_flink; ! 812: p->n_flink->n_blink = p->n_blink; ! 813: } ! 814: return(np); ! 815: } ! 816: ! 817: /* ! 818: * Call the given routine on each element of the name ! 819: * list, replacing said value if need be. ! 820: */ ! 821: ! 822: mapf(np, from) ! 823: register struct name *np; ! 824: char *from; ! 825: { ! 826: register struct name *p; ! 827: ! 828: for (p = np; p != NIL; p = p->n_flink) ! 829: p->n_name = netmap(p->n_name, from); ! 830: } ! 831: ! 832: /* ! 833: * Pretty print a name list ! 834: * Uncomment it if you need it. ! 835: */ ! 836: ! 837: prettyprint(name) ! 838: struct name *name; ! 839: { ! 840: register struct name *np; ! 841: ! 842: np = name; ! 843: while (np != NIL) { ! 844: fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); ! 845: np = np->n_flink; ! 846: } ! 847: fprintf(stderr, "\n"); ! 848: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.