home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / tahoe / names.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-18  |  15.4 KB  |  865 lines

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