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

Defined functions

arpafix defined in line 175; used 2 times
best defined in line 696; used 1 times
inithost defined in line 720; used 1 times
little defined in line 141; used 2 times
minit defined in line 269; used 1 times
mlook defined in line 366; used 2 times
mstash defined in line 293; used 1 times
mtype defined in line 386; used 1 times
name defined in line 779; used 60 times
netkind defined in line 560; used 1 times
netlook defined in line 97; used 3 times
netmap defined in line 28; used 3 times
netname defined in line 154; used 4 times
nettype defined in line 234; used 4 times
ntype defined in line 542; used 4 times
optiboth defined in line 631; used 1 times
optim defined in line 416; used 1 times
  • in line 50
optim1 defined in line 488; used 1 times
optimex defined in line 575; used 1 times
optimimp defined in line 604; used 1 times
prefer defined in line 677; used 3 times
rename defined in line 62; used 1 times
revarpa defined in line 752; used 4 times
rpair defined in line 656; used 3 times
stradd defined in line 880; used 12 times
xlocate defined in line 330; used 2 times
yyinit defined in line 824; used 1 times
yylex defined in line 843; used 2 times

Defined variables

charp defined in line 817; used 5 times
midfree defined in line 262; used 6 times
netbuf defined in line 743; used 8 times
nexttok defined in line 818; used 5 times
sccsid defined in line 8; never used
xtab defined in line 260; used 4 times
xtrahash defined in line 258; used 4 times
yylval defined in line 744; used 2 times

Defined struct's

xtrahash defined in line 254; used 18 times

Defined macros

NXMID defined in line 252; never used
WORD defined in line 741; used 2 times
XHSIZE defined in line 251; used 10 times
Last modified: 1985-11-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2606
Valid CSS Valid XHTML 1.0 Strict