home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / optim.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-06-03  |  16.1 KB  |  886 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)optim.c    5.5 (Berkeley) 11/2/85";
  9. #endif not lint
  10.  
  11. /*
  12.  * Mail -- a program for sending and receiving mail.
  13.  *
  14.  * Network name modification routines.
  15.  */
  16.  
  17. #include "./rcv.h"
  18. #include "./configdefs.h"
  19. #include <ctype.h>
  20.  
  21. /*
  22.  * Map a name into the correct network "view" of the
  23.  * name.  This is done by prepending the name with the
  24.  * network address of the sender, then optimizing away
  25.  * nonsense.
  26.  */
  27.  
  28. char *
  29. netmap(name, from)
  30.     char name[], from[];
  31. {
  32.     char nbuf[BUFSIZ], ret[BUFSIZ];
  33.     register char *cp;
  34.  
  35.     if (strlen(from) == 0)
  36.         return(name);
  37.     if (any('@', name) || any('%', name))
  38.         return(savestr(arpafix(name, from)));
  39.     cp = revarpa(from);
  40.     if (cp == NOSTR)
  41.         return(name);
  42.     strcpy(nbuf, cp);
  43.     cp = &nbuf[strlen(nbuf) - 1];
  44.     while (!any(*cp, metanet) && cp > nbuf)
  45.         cp--;
  46.     if (cp == nbuf)
  47.         return(name);
  48.     *++cp = 0;
  49.     strcat(nbuf, revarpa(name));
  50.     optim(nbuf, ret);
  51.     cp = revarpa(ret);
  52.     if (!icequal(name, cp))
  53.         return(savestr(cp));
  54.     return(name);
  55. }
  56.  
  57. #ifdef NOT_USED
  58. /*
  59.  * Rename the given network path to use
  60.  * the kinds of names that we would right here.
  61.  */
  62.  
  63. char *
  64. rename(str)
  65.     char str[];
  66. {
  67.     register char *cp, *cp2;
  68.     char buf[BUFSIZ], path[BUFSIZ];
  69.     register int c, host;
  70.  
  71.     cp = str;
  72.     strcpy(path, "");
  73.     for (;;) {
  74.         if ((c = *cp++) == 0)
  75.             break;
  76.         cp2 = buf;
  77.         while (!any(c, metanet) && c != 0) {
  78.             *cp2++ = c;
  79.             c = *cp++;
  80.         }
  81.         *cp2 = 0;
  82.         if (c == 0) {
  83.             strcat(path, buf);
  84.             break;
  85.         }
  86.         host = netlook(buf, ntype(c));
  87.         strcat(path, netname(host));
  88.         stradd(path, c);
  89.     }
  90.     if (strcmp(str, path) != 0)
  91.         return(savestr(path));
  92.     return(str);
  93. }
  94. #endif NOT_USED
  95.  
  96. /*
  97.  * Turn a network machine name into a unique character
  98.  */
  99. netlook(machine, attnet)
  100.     char machine[];
  101. {
  102.     register struct netmach *np;
  103.     register char *cp, *cp2;
  104.     char nbuf[BUFSIZ];
  105.  
  106.     /*
  107.      * Make into lower case.
  108.      */
  109.  
  110.     for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++))
  111.         if (cp2 >= &nbuf[sizeof(nbuf)-1])
  112.             break;
  113.     *cp2 = 0;
  114.  
  115.     /*
  116.      * If a single letter machine, look through those first.
  117.      */
  118.  
  119.     if (strlen(nbuf) == 1)
  120.         for (np = netmach; np->nt_mid != 0; np++)
  121.             if (np->nt_mid == nbuf[0])
  122.                 return(nbuf[0]);
  123.  
  124.     /*
  125.      * Look for usual name
  126.      */
  127.  
  128.     for (np = netmach; np->nt_mid != 0; np++)
  129.         if (strcmp(np->nt_machine, nbuf) == 0)
  130.             return(np->nt_mid);
  131.  
  132.     /*
  133.      * Look in side hash table.
  134.      */
  135.  
  136.     return(mstash(nbuf, attnet));
  137. }
  138.  
  139. /*
  140.  * Make a little character.
  141.  */
  142.  
  143. little(c)
  144. register char c;
  145. {
  146.         return(isupper(c) ? tolower(c) : c);
  147. }
  148.  
  149. /*
  150.  * Turn a network unique character identifier into a network name.
  151.  */
  152.  
  153. char *
  154. netname(mid)
  155. {
  156.     register struct netmach *np;
  157.     char *mlook();
  158.  
  159.     if (mid & 0200)
  160.         return(mlook(mid));
  161.     for (np = netmach; np->nt_mid != 0; np++)
  162.         if (np->nt_mid == mid)
  163.             return(np->nt_machine);
  164.     return(NOSTR);
  165. }
  166.  
  167. /*
  168.  * Deal with arpa net addresses.  The way this is done is strange.
  169.  * In particular, if the destination arpa net host is not Berkeley,
  170.  * then the address is correct as stands.  Otherwise, we strip off
  171.  * the trailing @Berkeley, then cook up a phony person for it to
  172.  * be from and optimize the result.
  173.  */
  174. char *
  175. arpafix(name, from)
  176.     char name[];
  177.     char from[];
  178. {
  179.     register char *cp;
  180.     register int arpamach;
  181.     char newname[BUFSIZ];
  182.     char fake[5];
  183.     char fakepath[20];
  184.  
  185.     if (debug) {
  186.         fprintf(stderr, "arpafix(%s, %s)\n", name, from);
  187.     }
  188.     cp = rindex(name, '@');
  189.     if (cp == NOSTR)
  190.         cp = rindex(name, '%');
  191.     if (cp == NOSTR) {
  192.         fprintf(stderr, "Somethings amiss -- no @ or % in arpafix\n");
  193.         return(name);
  194.     }
  195.     cp++;
  196.     arpamach = netlook(cp, '@');
  197.     if (arpamach == 0) {
  198.         if (debug)
  199.             fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name);
  200.         return(name);
  201.     }
  202.     if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
  203.         if (debug)
  204.             fprintf(stderr, "machine %s known but remote, uses: %s\n",
  205.                 cp, name);
  206.         return(name);
  207.     }
  208.     strcpy(newname, name);
  209.     cp = rindex(newname, '@');
  210.     if (cp == NOSTR)
  211.         cp = rindex(newname, '%');
  212.     *cp = 0;
  213.     fake[0] = arpamach;
  214.     fake[1] = ':';
  215.     fake[2] = LOCAL;
  216.     fake[3] = ':';
  217.     fake[4] = 0;
  218.     prefer(fake);
  219.     strcpy(fakepath, netname(fake[0]));
  220.     stradd(fakepath, fake[1]);
  221.     strcat(fakepath, "daemon");
  222.     if (debug)
  223.         fprintf(stderr, "machine local, call netmap(%s, %s)\n",
  224.             newname, fakepath);
  225.     return(netmap(newname, fakepath));
  226. }
  227.  
  228. /*
  229.  * Take a network machine descriptor and find the types of connected
  230.  * nets and return it.
  231.  */
  232.  
  233. nettype(mid)
  234. {
  235.     register struct netmach *np;
  236.  
  237.     if (mid & 0200)
  238.         return(mtype(mid));
  239.     for (np = netmach; np->nt_mid != 0; np++)
  240.         if (np->nt_mid == mid)
  241.             return(np->nt_type);
  242.     return(0);
  243. }
  244.  
  245. /*
  246.  * Hashing routines to salt away machines seen scanning
  247.  * networks paths that we don't know about.
  248.  */
  249.  
  250. #define    XHSIZE        19        /* Size of extra hash table */
  251. #define    NXMID        (XHSIZE*3/4)    /* Max extra machines */
  252.  
  253. struct xtrahash {
  254.     char    *xh_name;        /* Name of machine */
  255.     short    xh_mid;            /* Machine ID */
  256.     short    xh_attnet;        /* Attached networks */
  257. } xtrahash[XHSIZE];
  258.  
  259. struct xtrahash    *xtab[XHSIZE];        /* F: mid-->machine name */
  260.  
  261. short    midfree;            /* Next free machine id */
  262.  
  263. /*
  264.  * Initialize the extra host hash table.
  265.  * Called by sreset.
  266.  */
  267.  
  268. minit()
  269. {
  270.     register struct xtrahash *xp, **tp;
  271.  
  272.     midfree = 0;
  273.     tp = &xtab[0];
  274.     for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
  275.         xp->xh_name = NOSTR;
  276.         xp->xh_mid = 0;
  277.         xp->xh_attnet = 0;
  278.         *tp++ = (struct xtrahash *) 0;
  279.     }
  280. }
  281.  
  282. /*
  283.  * Stash a net name in the extra host hash table.
  284.  * If a new entry is put in the hash table, deduce what
  285.  * net the machine is attached to from the net character.
  286.  *
  287.  * If the machine is already known, add the given attached
  288.  * net to those already known.
  289.  */
  290.  
  291. mstash(name, attnet)
  292.     char name[];
  293. {
  294.     register struct xtrahash *xp;
  295.     struct xtrahash *xlocate();
  296.     int x;
  297.  
  298.     xp = xlocate(name);
  299.     if (xp == (struct xtrahash *) 0) {
  300.         printf("Ran out of machine id spots\n");
  301.         return(0);
  302.     }
  303.     if (xp->xh_name == NOSTR) {
  304.         if (midfree >= XHSIZE) {
  305.             printf("Out of machine ids\n");
  306.             return(0);
  307.         }
  308.         xtab[midfree] = xp;
  309.         xp->xh_name = savestr(name);
  310.         xp->xh_mid = 0200 + midfree++;
  311.     }
  312.     x = ntype(attnet);
  313.     if (x == 0)
  314.         xp->xh_attnet |= SN;
  315.     else
  316.         xp->xh_attnet |= x;
  317.     return(xp->xh_mid);
  318. }
  319.  
  320. /*
  321.  * Search for the given name in the hash table
  322.  * and return the pointer to it if found, or to the first
  323.  * empty slot if not found.
  324.  *
  325.  * If no free slots can be found, return 0.
  326.  */
  327.  
  328. struct xtrahash *
  329. xlocate(name)
  330.     char name[];
  331. {
  332.     register int h, q, i;
  333.     register char *cp;
  334.     register struct xtrahash *xp;
  335.  
  336.     for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
  337.         ;
  338.     if (h < 0 && (h = -h) < 0)
  339.         h = 0;
  340.     h = h % XHSIZE;
  341.     cp = name;
  342.     for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
  343.         xp = &xtrahash[(h + q) % XHSIZE];
  344.         if (xp->xh_name == NOSTR)
  345.             return(xp);
  346.         if (strcmp(cp, xp->xh_name) == 0)
  347.             return(xp);
  348.         if (h - q < 0)
  349.             h += XHSIZE;
  350.         xp = &xtrahash[(h - q) % XHSIZE];
  351.         if (xp->xh_name == NOSTR)
  352.             return(xp);
  353.         if (strcmp(cp, xp->xh_name) == 0)
  354.             return(xp);
  355.     }
  356.     return((struct xtrahash *) 0);
  357. }
  358.  
  359. /*
  360.  * Return the name from the extra host hash table corresponding
  361.  * to the passed machine id.
  362.  */
  363.  
  364. char *
  365. mlook(mid)
  366. {
  367.     register int m;
  368.  
  369.     if ((mid & 0200) == 0)
  370.         return(NOSTR);
  371.     m = mid & 0177;
  372.     if (m >= midfree) {
  373.         printf("Use made of undefined machine id\n");
  374.         return(NOSTR);
  375.     }
  376.     return(xtab[m]->xh_name);
  377. }
  378.  
  379. /*
  380.  * Return the bit mask of net's that the given extra host machine
  381.  * id has so far.
  382.  */
  383.  
  384. mtype(mid)
  385. {
  386.     register int m;
  387.  
  388.     if ((mid & 0200) == 0)
  389.         return(0);
  390.     m = mid & 0177;
  391.     if (m >= midfree) {
  392.         printf("Use made of undefined machine id\n");
  393.         return(0);
  394.     }
  395.     return(xtab[m]->xh_attnet);
  396. }
  397.  
  398. /*
  399.  * Take a network name and optimize it.  This gloriously messy
  400.  * operation takes place as follows:  the name with machine names
  401.  * in it is tokenized by mapping each machine name into a single
  402.  * character machine id (netlook).  The separator characters (network
  403.  * metacharacters) are left intact.  The last component of the network
  404.  * name is stripped off and assumed to be the destination user name --
  405.  * it does not participate in the optimization.  As an example, the
  406.  * name "research!vax135!research!ucbvax!bill" becomes, tokenized,
  407.  * "r!x!r!v!" and "bill"  A low level routine, optim1, fixes up the
  408.  * network part (eg, "r!x!r!v!"), then we convert back to network
  409.  * machine names and tack the user name on the end.
  410.  *
  411.  * The result of this is copied into the parameter "name"
  412.  */
  413.  
  414. optim(net, name)
  415.     char net[], name[];
  416. {
  417.     char netcomp[BUFSIZ], netstr[40], xfstr[40];
  418.     register char *cp, *cp2;
  419.     register int c;
  420.  
  421.     strcpy(netstr, "");
  422.     cp = net;
  423.     for (;;) {
  424.         /*
  425.          * Rip off next path component into netcomp
  426.          */
  427.         cp2 = netcomp;
  428.         while (*cp && !any(*cp, metanet))
  429.             *cp2++ = *cp++;
  430.         *cp2 = 0;
  431.         /*
  432.          * If we hit null byte, then we just scanned
  433.          * the destination user name.  Go off and optimize
  434.          * if its so.
  435.          */
  436.         if (*cp == 0)
  437.             break;
  438.         if ((c = netlook(netcomp, *cp)) == 0) {
  439.             printf("No host named \"%s\"\n", netcomp);
  440. err:
  441.             strcpy(name, net);
  442.             return;
  443.         }
  444.         stradd(netstr, c);
  445.         stradd(netstr, *cp++);
  446.         /*
  447.          * If multiple network separators given,
  448.          * throw away the extras.
  449.          */
  450.         while (any(*cp, metanet))
  451.             cp++;
  452.     }
  453.     if (strlen(netcomp) == 0) {
  454.         printf("net name syntax\n");
  455.         goto err;
  456.     }
  457.     optim1(netstr, xfstr);
  458.  
  459.     /*
  460.      * Convert back to machine names.
  461.      */
  462.  
  463.     cp = xfstr;
  464.     strcpy(name, "");
  465.     while (*cp) {
  466.         if ((cp2 = netname(*cp++)) == NOSTR) {
  467.             printf("Made up bad net name\n");
  468.             printf("Machine code %c (0%o)\n", cp[-1], cp[-1]);
  469.             printf("Sorry -- dumping now.  Alert K. Shoens\n");
  470.             core();
  471.             goto err;
  472.         }
  473.         strcat(name, cp2);
  474.         stradd(name, *cp++);
  475.     }
  476.     strcat(name, netcomp);
  477. }
  478.  
  479. /*
  480.  * Take a string of network machine id's and separators and
  481.  * optimize them.  We process these by pulling off maximal
  482.  * leading strings of the same type, passing these to the appropriate
  483.  * optimizer and concatenating the results.
  484.  */
  485.  
  486. optim1(netstr, name)
  487.     char netstr[], name[];
  488. {
  489.     char path[40], rpath[40];
  490.     register char *cp, *cp2;
  491.     register int tp, nc;
  492.  
  493.     cp = netstr;
  494.     prefer(cp);
  495.     strcpy(name, "");
  496.     /*
  497.      * If the address ultimately points back to us,
  498.      * just return a null network path.
  499.      */
  500.     if (strlen(cp) > 1 && cp[strlen(cp) - 2] == LOCAL)
  501.         return;
  502.     while (*cp != 0) {
  503.         strcpy(path, "");
  504.         tp = ntype(cp[1]);
  505.         nc = cp[1];
  506.         while (*cp && tp == ntype(cp[1])) {
  507.             stradd(path, *cp++);
  508.             cp++;
  509.         }
  510.         switch (netkind(tp)) {
  511.         default:
  512.             strcpy(rpath, path);
  513.             break;
  514.  
  515.         case IMPLICIT:
  516.             optimimp(path, rpath);
  517.             break;
  518.  
  519.         case EXPLICIT:
  520.             optimex(path, rpath);
  521.             break;
  522.         }
  523.         for (cp2 = rpath; *cp2 != 0; cp2++) {
  524.             stradd(name, *cp2);
  525.             stradd(name, nc);
  526.         }
  527.     }
  528.     optiboth(name);
  529.     prefer(name);
  530. }
  531.  
  532. /*
  533.  * Return the network of the separator --
  534.  *    AN for arpa net
  535.  *    BN for Bell labs net
  536.  *    SN for Schmidt (berkeley net)
  537.  *    0 if we don't know.
  538.  */
  539.  
  540. ntype(nc)
  541.     register int nc;
  542. {
  543.     register struct ntypetab *np;
  544.  
  545.     for (np = ntypetab; np->nt_char != 0; np++)
  546.         if (np->nt_char == nc)
  547.             return(np->nt_bcode);
  548.     return(0);
  549. }
  550.  
  551. /*
  552.  * Return the kind of routing used for the particular net
  553.  * EXPLICIT means explicitly routed
  554.  * IMPLICIT means implicitly routed
  555.  * 0 means don't know
  556.  */
  557.  
  558. netkind(nt)
  559.     register int nt;
  560. {
  561.     register struct nkindtab *np;
  562.  
  563.     for (np = nkindtab; np->nk_type != 0; np++)
  564.         if (np->nk_type == nt)
  565.             return(np->nk_kind);
  566.     return(0);
  567. }
  568.  
  569. /*
  570.  * Do name optimization for an explicitly routed network (eg BTL network).
  571.  */
  572.  
  573. optimex(net, name)
  574.     char net[], name[];
  575. {
  576.     register char *cp, *rp;
  577.     register int m;
  578.     char *rindex();
  579.  
  580.     strcpy(name, net);
  581.     cp = name;
  582.     if (strlen(cp) == 0)
  583.         return; /* error */
  584.     if (cp[strlen(cp)-1] == LOCAL) {
  585.         name[0] = 0;
  586.         return;
  587.     }
  588.     for (cp = name; *cp; cp++) {
  589.         m = *cp;
  590.         rp = rindex(cp+1, m);
  591.         if (rp != NOSTR)
  592.             strcpy(cp, rp);
  593.     }
  594.     return;
  595. }
  596.  
  597. /*
  598.  * Do name optimization for implicitly routed network (eg, arpanet,
  599.  * Berkeley network)
  600.  */
  601.  
  602. optimimp(net, name)
  603.     char net[], name[];
  604. {
  605.     register char *cp;
  606.     register int m;
  607.  
  608.     cp = net;
  609.     if (strlen(cp) == 0)
  610.         return; /* error */
  611.     m = cp[strlen(cp) - 1];
  612.     if (m == LOCAL) {
  613.         strcpy(name, "");
  614.         return;
  615.     }
  616.     name[0] = m;
  617.     name[1] = 0;
  618. }
  619.  
  620. /*
  621.  * Perform global optimization on the given network path.
  622.  * The trick here is to look ahead to see if there are any loops
  623.  * in the path and remove them.  The interpretation of loops is
  624.  * more strict here than in optimex since both the machine and net
  625.  * type must match.
  626.  */
  627.  
  628. optiboth(net)
  629.     char net[];
  630. {
  631.     register char *cp, *cp2;
  632.     char *rpair();
  633.  
  634.     cp = net;
  635.     if (strlen(cp) == 0)
  636.         return;
  637.     if ((strlen(cp) % 2) != 0) {
  638.         printf("Strange arg to optiboth\n");
  639.         return;
  640.     }
  641.     while (*cp) {
  642.         cp2 = rpair(cp+2, *cp);
  643.         if (cp2 != NOSTR)
  644.             strcpy(cp, cp2);
  645.         cp += 2;
  646.     }
  647. }
  648.  
  649. /*
  650.  * Find the rightmost instance of the given (machine, type) pair.
  651.  */
  652.  
  653. char *
  654. rpair(str, mach)
  655.     char str[];
  656. {
  657.     register char *cp, *last;
  658.  
  659.     cp = str;
  660.     last = NOSTR;
  661.     while (*cp) {
  662.         if (*cp == mach)
  663.             last = cp;
  664.         cp += 2;
  665.     }
  666.     return(last);
  667. }
  668.  
  669. /*
  670.  * Change the network separators in the given network path
  671.  * to the preferred network transmission means.
  672.  */
  673.  
  674. prefer(name)
  675.     char name[];
  676. {
  677.     register char *cp;
  678.     register int state, n;
  679.  
  680.     state = LOCAL;
  681.     for (cp = name; *cp; cp += 2) {
  682.         n = best(state, *cp);
  683.         if (n)
  684.             cp[1] = n;
  685.         state = *cp;
  686.     }
  687. }
  688.  
  689. /*
  690.  * Return the best network separator for the given machine pair.
  691.  */
  692.  
  693. best(src, dest)
  694. {
  695.     register int dtype, stype;
  696.     register struct netorder *np;
  697.  
  698.     stype = nettype(src);
  699.     dtype = nettype(dest);
  700.     fflush(stdout);
  701.     if (stype == 0 || dtype == 0) {
  702.         printf("ERROR:  unknown internal machine id\n");
  703.         return(0);
  704.     }
  705.     if ((stype & dtype) == 0)
  706.         return(0);
  707.     np = &netorder[0];
  708.     while ((np->no_stat & stype & dtype) == 0)
  709.         np++;
  710.     return(np->no_char);
  711. }
  712.  
  713. #ifdef    GETHOST
  714. /*
  715.  * Initialize the network name of the current host.
  716.  */
  717. inithost()
  718. {
  719.     register struct netmach *np;
  720.     static char host[64];
  721.  
  722.     gethostname(host, sizeof host);
  723.     for (np = netmach; np->nt_machine != 0; np++)
  724.         if (strcmp(np->nt_machine, EMPTY) == 0)
  725.             break;
  726.     if (np->nt_machine == 0) {
  727.         printf("Cannot find empty slot for dynamic host entry\n");
  728.         exit(1);
  729.     }
  730.     np->nt_machine = host;
  731. }
  732. #endif    GETHOST
  733.  
  734. /*
  735.  * Code to twist around arpa net names.
  736.  */
  737.  
  738. #define WORD 257            /* Token for a string */
  739.  
  740. static    char netbuf[256];
  741. static    char *yylval;
  742.  
  743. /*
  744.  * Reverse all of the arpa net addresses in the given name to
  745.  * be of the form "host @ user" instead of "user @ host"
  746.  * This function is its own inverse.
  747.  */
  748.  
  749. char *
  750. revarpa(str)
  751.     char str[];
  752. {
  753.  
  754.     if (yyinit(str) < 0)
  755.         return(NOSTR);
  756.     if (name())
  757.         return(NOSTR);
  758.     if (strcmp(str, netbuf) == 0)
  759.         return(str);
  760.     return(savestr(netbuf));
  761. }
  762.  
  763. /*
  764.  * Parse (by recursive descent) network names, using the following grammar:
  765.  *    name:
  766.  *        term {':' term}
  767.  *        term {'^' term}
  768.  *        term {'!' term}
  769.  *        term '@' name
  770.  *        term '%' name
  771.  *
  772.  *    term:
  773.  *        string of characters.
  774.  */
  775.  
  776. name()
  777. {
  778.     register int t;
  779.     register char *cp;
  780.  
  781.     for (;;) {
  782.         t = yylex();
  783.         if (t != WORD)
  784.             return(-1);
  785.         cp = yylval;
  786.         t = yylex();
  787.         switch (t) {
  788.         case 0:
  789.             strcat(netbuf, cp);
  790.             return(0);
  791.  
  792.         case '@':
  793.         case '%':
  794.             if (name())
  795.                 return(-1);
  796.             stradd(netbuf, '@');
  797.             strcat(netbuf, cp);
  798.             return(0);
  799.  
  800.         case WORD:
  801.             return(-1);
  802.  
  803.         default:
  804.             strcat(netbuf, cp);
  805.             stradd(netbuf, t);
  806.         }
  807.     }
  808. }
  809.  
  810. /*
  811.  * Scanner for network names.
  812.  */
  813.  
  814. static    char *charp;            /* Current input pointer */
  815. static    int nexttok;            /* Salted away next token */
  816.  
  817. /*
  818.  * Initialize the network name scanner.
  819.  */
  820.  
  821. yyinit(str)
  822.     char str[];
  823. {
  824.     static char lexbuf[BUFSIZ];
  825.  
  826.     netbuf[0] = 0;
  827.     if (strlen(str) >= sizeof lexbuf - 1)
  828.         return(-1);
  829.     nexttok = 0;
  830.     strcpy(lexbuf, str);
  831.     charp = lexbuf;
  832.     return(0);
  833. }
  834.  
  835. /*
  836.  * Scan and return a single token.
  837.  * yylval is set to point to a scanned string.
  838.  */
  839.  
  840. yylex()
  841. {
  842.     register char *cp, *l_dot;
  843.     register int s;
  844.  
  845.     if (nexttok) {
  846.         s = nexttok;
  847.         nexttok = 0;
  848.         return(s);
  849.     }
  850.     cp = charp;
  851.     while (*cp && isspace(*cp))
  852.         cp++;
  853.     if (*cp == 0)
  854.         return(0);
  855.     if (any(*cp, metanet)) {
  856.         charp = cp+1;
  857.         return(*cp);
  858.     }
  859.     l_dot = cp;
  860.     while (*cp && !any(*cp, metanet) && !any(*cp, " \t"))
  861.         cp++;
  862.     if (any(*cp, metanet))
  863.         nexttok = *cp;
  864.     if (*cp == 0)
  865.         charp = cp;
  866.     else
  867.         charp = cp+1;
  868.     *cp = 0;
  869.     yylval = l_dot;
  870.     return(WORD);
  871. }
  872.  
  873. /*
  874.  * Add a single character onto a string.
  875.  */
  876.  
  877. stradd(str, c)
  878.     register char *str;
  879.     register int c;
  880. {
  881.  
  882.     str += strlen(str);
  883.     *str++ = c;
  884.     *str = 0;
  885. }
  886.