1: #
   2: 
   3: /*
   4:  * Mail -- a mail program
   5:  *
   6:  * Handle name lists.
   7:  */
   8: 
   9: #include "rcv.h"
  10: 
  11: static char *SccsId = "@(#)names.c	2.8 1/22/83";
  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: }

Defined functions

cat defined in line 521; used 3 times
cmpdomain defined in line 776; used 1 times
count defined in line 764; used 2 times
delname defined in line 790; used 5 times
detract defined in line 100; used 5 times
elide defined in line 632; used 4 times
extract defined in line 57; used 6 times
gexpand defined in line 455; used 3 times
isfileaddr defined in line 390; used 1 times
lengthof defined in line 506; used 1 times
mapf defined in line 822; used 2 times
mechk defined in line 614; used 1 times
nalloc defined in line 19; used 2 times
nstrcmp defined in line 731; used 2 times
outof defined in line 237; used 2 times
prettyprint defined in line 837; never used
put defined in line 748; used 4 times
tailof defined in line 37; used 1 times
unpack defined in line 542; used 2 times
usermap defined in line 418; used 2 times
verify defined in line 176; used 2 times
yankword defined in line 147; used 3 times

Defined variables

SccsId defined in line 11; never used
Last modified: 1983-01-23
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1546
Valid CSS Valid XHTML 1.0 Strict