Annotation of 42BSD/ucb/Mail/optim.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.