1: /*
   2:  * Copyright (c) 1989, 1993
   3:  *	The Regents of the University of California.  All rights reserved.
   4:  *
   5:  * This code is derived from software contributed to Berkeley by
   6:  * Ozan Yigit at York University.
   7:  *
   8:  * Redistribution and use in source and binary forms, with or without
   9:  * modification, are permitted provided that the following conditions
  10:  * are met:
  11:  * 1. Redistributions of source code must retain the above copyright
  12:  *    notice, this list of conditions and the following disclaimer.
  13:  * 2. Redistributions in binary form must reproduce the above copyright
  14:  *    notice, this list of conditions and the following disclaimer in the
  15:  *    documentation and/or other materials provided with the distribution.
  16:  * 3. All advertising materials mentioning features or use of this software
  17:  *    must display the following acknowledgement:
  18:  *	This product includes software developed by the University of
  19:  *	California, Berkeley and its contributors.
  20:  * 4. Neither the name of the University nor the names of its contributors
  21:  *    may be used to endorse or promote products derived from this software
  22:  *    without specific prior written permission.
  23:  *
  24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34:  * SUCH DAMAGE.
  35:  */
  36: 
  37: #if !defined(lint) && defined(DOSCCS)
  38: static char sccsid[] = "@(#)eval.c	8.1 (Berkeley) 6/6/93";
  39: #endif
  40: 
  41: /*
  42:  * eval.c
  43:  * Facility: m4 macro processor
  44:  * by: oz
  45:  */
  46: 
  47: #include <sys/types.h>
  48: #include <errno.h>
  49: #include <stdio.h>
  50: #include <string.h>
  51: #include "mdef.h"
  52: #include "stdd.h"
  53: #include "extern.h"
  54: #include "pathnames.h"
  55: 
  56: /*
  57:  * eval - evaluate built-in macros.
  58:  *	  argc - number of elements in argv.
  59:  *	  argv - element vector :
  60:  *			argv[0] = definition of a user
  61:  *				  macro or nil if built-in.
  62:  *			argv[1] = name of the macro or
  63:  *				  built-in.
  64:  *			argv[2] = parameters to user-defined
  65:  *			   .	  macro or built-in.
  66:  *			   .
  67:  *
  68:  * Note that the minimum value for argc is 3. A call in the form
  69:  * of macro-or-builtin() will result in:
  70:  *			argv[0] = nullstr
  71:  *			argv[1] = macro-or-builtin
  72:  *			argv[2] = nullstr
  73:  */
  74: 
  75: void
  76: eval(argv, argc, td)
  77: register char *argv[];
  78: register int argc;
  79: register int td;
  80: {
  81:     register int c, n;
  82:     static int sysval = 0;
  83: 
  84: #ifdef DEBUG
  85:     printf("argc = %d\n", argc);
  86:     for (n = 0; n < argc; n++)
  87:         printf("argv[%d] = %s\n", n, argv[n]);
  88: #endif
  89:  /*
  90:   * if argc == 3 and argv[2] is null, then we
  91:   * have macro-or-builtin() type call. We adjust
  92:   * argc to avoid further checking..
  93:   */
  94:     if (argc == 3 && !*(argv[2]))
  95:         argc--;
  96: 
  97:     switch (td & ~STATIC) {
  98: 
  99:     case DEFITYPE:
 100:         if (argc > 2)
 101:             dodefine(argv[2], (argc > 3) ? argv[3] : null);
 102:         break;
 103: 
 104:     case PUSDTYPE:
 105:         if (argc > 2)
 106:             dopushdef(argv[2], (argc > 3) ? argv[3] : null);
 107:         break;
 108: 
 109:     case DUMPTYPE:
 110:         dodump(argv, argc);
 111:         break;
 112: 
 113:     case EXPRTYPE:
 114:     /*
 115: 	 * doexpr - evaluate arithmetic
 116: 	 * expression
 117: 	 */
 118:         if (argc > 2)
 119:             pbnum(expr(argv[2]));
 120:         break;
 121: 
 122:     case IFELTYPE:
 123:         if (argc > 4)
 124:             doifelse(argv, argc);
 125:         break;
 126: 
 127:     case IFDFTYPE:
 128:     /*
 129: 	 * doifdef - select one of two
 130: 	 * alternatives based on the existence of
 131: 	 * another definition
 132: 	 */
 133:         if (argc > 3) {
 134:             if (lookup(argv[2]) != nil)
 135:                 pbstr(argv[3]);
 136:             else if (argc > 4)
 137:                 pbstr(argv[4]);
 138:         }
 139:         break;
 140: 
 141:     case LENGTYPE:
 142:     /*
 143: 	 * dolen - find the length of the
 144: 	 * argument
 145: 	 */
 146:         if (argc > 2)
 147:             pbnum((argc > 2) ? strlen(argv[2]) : 0);
 148:         break;
 149: 
 150:     case INCRTYPE:
 151:     /*
 152: 	 * doincr - increment the value of the
 153: 	 * argument
 154: 	 */
 155:         if (argc > 2)
 156:             pbnum(atoi(argv[2]) + 1);
 157:         break;
 158: 
 159:     case DECRTYPE:
 160:     /*
 161: 	 * dodecr - decrement the value of the
 162: 	 * argument
 163: 	 */
 164:         if (argc > 2)
 165:             pbnum(atoi(argv[2]) - 1);
 166:         break;
 167: 
 168:     case SYSCTYPE:
 169:     /*
 170: 	 * dosys - execute system command
 171: 	 */
 172:         if (argc > 2)
 173:             sysval = system(argv[2]);
 174:         break;
 175: 
 176:     case SYSVTYPE:
 177:     /*
 178: 	 * dosysval - return value of the last
 179: 	 * system call.
 180: 	 *
 181: 	 */
 182:         pbnum(sysval);
 183:         break;
 184: 
 185:     case INCLTYPE:
 186:         if (argc > 2)
 187:             if (!doincl(argv[2]))
 188:                 oops("%s: %s", argv[2], strerror(errno));
 189:         break;
 190: 
 191:     case SINCTYPE:
 192:         if (argc > 2)
 193:             (void) doincl(argv[2]);
 194:         break;
 195: #ifdef EXTENDED
 196:     case PASTTYPE:
 197:         if (argc > 2)
 198:             if (!dopaste(argv[2]))
 199:                 oops("%s: %s", argv[2], strerror(errno));
 200:         break;
 201: 
 202:     case SPASTYPE:
 203:         if (argc > 2)
 204:             (void) dopaste(argv[2]);
 205:         break;
 206: #endif
 207:     case CHNQTYPE:
 208:         dochq(argv, argc);
 209:         break;
 210: 
 211:     case CHNCTYPE:
 212:         dochc(argv, argc);
 213:         break;
 214: 
 215:     case SUBSTYPE:
 216:     /*
 217: 	 * dosub - select substring
 218: 	 *
 219: 	 */
 220:         if (argc > 3)
 221:             dosub(argv, argc);
 222:         break;
 223: 
 224:     case SHIFTYPE:
 225:     /*
 226: 	 * doshift - push back all arguments
 227: 	 * except the first one (i.e. skip
 228: 	 * argv[2])
 229: 	 */
 230:         if (argc > 3) {
 231:             for (n = argc - 1; n > 3; n--) {
 232:                 putback(rquote);
 233:                 pbstr(argv[n]);
 234:                 putback(lquote);
 235:                 putback(',');
 236:             }
 237:             putback(rquote);
 238:             pbstr(argv[3]);
 239:             putback(lquote);
 240:         }
 241:         break;
 242: 
 243:     case DIVRTYPE:
 244:         if (argc > 2 && (n = atoi(argv[2])) != 0)
 245:             dodiv(n);
 246:         else {
 247:             active = stdout;
 248:             oindex = 0;
 249:         }
 250:         break;
 251: 
 252:     case UNDVTYPE:
 253:         doundiv(argv, argc);
 254:         break;
 255: 
 256:     case DIVNTYPE:
 257:     /*
 258: 	 * dodivnum - return the number of
 259: 	 * current output diversion
 260: 	 */
 261:         pbnum(oindex);
 262:         break;
 263: 
 264:     case UNDFTYPE:
 265:     /*
 266: 	 * doundefine - undefine a previously
 267: 	 * defined macro(s) or m4 keyword(s).
 268: 	 */
 269:         if (argc > 2)
 270:             for (n = 2; n < argc; n++)
 271:                 remhash(argv[n], ALL);
 272:         break;
 273: 
 274:     case POPDTYPE:
 275:     /*
 276: 	 * dopopdef - remove the topmost
 277: 	 * definitions of macro(s) or m4
 278: 	 * keyword(s).
 279: 	 */
 280:         if (argc > 2)
 281:             for (n = 2; n < argc; n++)
 282:                 remhash(argv[n], TOP);
 283:         break;
 284: 
 285:     case MKTMTYPE:
 286:     /*
 287: 	 * dotemp - create a temporary file
 288: 	 */
 289:         if (argc > 2)
 290:             pbstr(mktemp(argv[2]));
 291:         break;
 292: 
 293:     case TRNLTYPE:
 294:     /*
 295: 	 * dotranslit - replace all characters in
 296: 	 * the source string that appears in the
 297: 	 * "from" string with the corresponding
 298: 	 * characters in the "to" string.
 299: 	 */
 300:         if (argc > 3) {
 301:             char temp[MAXTOK];
 302:             if (argc > 4)
 303:                 map(temp, argv[2], argv[3], argv[4]);
 304:             else
 305:                 map(temp, argv[2], argv[3], null);
 306:             pbstr(temp);
 307:         }
 308:         else if (argc > 2)
 309:             pbstr(argv[2]);
 310:         break;
 311: 
 312:     case INDXTYPE:
 313:     /*
 314: 	 * doindex - find the index of the second
 315: 	 * argument string in the first argument
 316: 	 * string. -1 if not present.
 317: 	 */
 318:         pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
 319:         break;
 320: 
 321:     case ERRPTYPE:
 322:     /*
 323: 	 * doerrp - print the arguments to stderr
 324: 	 * file
 325: 	 */
 326:         if (argc > 2) {
 327:             for (n = 2; n < argc; n++)
 328:                 fprintf(stderr, "%s ", argv[n]);
 329:             fprintf(stderr, "\n");
 330:         }
 331:         break;
 332: 
 333:     case DNLNTYPE:
 334:     /*
 335: 	 * dodnl - eat-up-to and including
 336: 	 * newline
 337: 	 */
 338:         while ((c = gpbc()) != '\n' && c != EOF)
 339:             ;
 340:         break;
 341: 
 342:     case M4WRTYPE:
 343:     /*
 344: 	 * dom4wrap - set up for
 345: 	 * wrap-up/wind-down activity
 346: 	 */
 347:         m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
 348:         break;
 349: 
 350:     case EXITTYPE:
 351:     /*
 352: 	 * doexit - immediate exit from m4.
 353: 	 */
 354:         exit((argc > 2) ? atoi(argv[2]) : 0);
 355:         break;
 356: 
 357:     case DEFNTYPE:
 358:         if (argc > 2)
 359:             for (n = 2; n < argc; n++)
 360:                 dodefn(argv[n]);
 361:         break;
 362: 
 363:     default:
 364:         oops("%s: major botch.", "eval");
 365:         break;
 366:     }
 367: }
 368: 
 369: char *dumpfmt = "`%s'\t`%s'\n";        /* format string for dumpdef   */
 370: 
 371: /*
 372:  * expand - user-defined macro expansion
 373:  */
 374: void
 375: expand(argv, argc)
 376: register char *argv[];
 377: register int argc;
 378: {
 379:     register char *t;
 380:     register char *p;
 381:     register int n;
 382:     register int argno;
 383: 
 384:     t = argv[0];               /* defn string as a whole */
 385:     p = t;
 386:     while (*p)
 387:         p++;
 388:     p--;                   /* last character of defn */
 389:     while (p > t) {
 390:         if (*(p - 1) != ARGFLAG)
 391:             putback(*p);
 392:         else {
 393:             switch (*p) {
 394: 
 395:             case '#':
 396:                 pbnum(argc - 2);
 397:                 break;
 398:             case '0':
 399:             case '1':
 400:             case '2':
 401:             case '3':
 402:             case '4':
 403:             case '5':
 404:             case '6':
 405:             case '7':
 406:             case '8':
 407:             case '9':
 408:                 if ((argno = *p - '0') < argc - 1)
 409:                     pbstr(argv[argno + 1]);
 410:                 break;
 411:             case '*':
 412:                 for (n = argc - 1; n > 2; n--) {
 413:                     pbstr(argv[n]);
 414:                     putback(',');
 415:                 }
 416:                 pbstr(argv[2]);
 417:                 break;
 418:             default:
 419:                 putback(*p);
 420:                 putback('$');
 421:                 break;
 422:             }
 423:             p--;
 424:         }
 425:         p--;
 426:     }
 427:     if (p == t)            /* do last character */
 428:         putback(*p);
 429: }
 430: 
 431: /*
 432:  * dodefine - install definition in the table
 433:  */
 434: void
 435: dodefine(name, defn)
 436: register char *name;
 437: register char *defn;
 438: {
 439:     register ndptr p;
 440: 
 441:     if (!*name)
 442:         oops("null definition.");
 443:     if (STREQ(name, defn))
 444:         oops("%s: recursive definition.", name);
 445:     if ((p = lookup(name)) == nil)
 446:         p = addent(name);
 447:     else if (p->defn != null)
 448:         free((char *) p->defn);
 449:     if (!*defn)
 450:         p->defn = null;
 451:     else
 452:         p->defn = xstrdup(defn);
 453:     p->type = MACRTYPE;
 454: }
 455: 
 456: /*
 457:  * dodefn - push back a quoted definition of
 458:  *      the given name.
 459:  */
 460: void
 461: dodefn(name)
 462: char *name;
 463: {
 464:     register ndptr p;
 465: 
 466:     if ((p = lookup(name)) != nil && p->defn != null) {
 467:         putback(rquote);
 468:         pbstr(p->defn);
 469:         putback(lquote);
 470:     }
 471: }
 472: 
 473: /*
 474:  * dopushdef - install a definition in the hash table
 475:  *      without removing a previous definition. Since
 476:  *      each new entry is entered in *front* of the
 477:  *      hash bucket, it hides a previous definition from
 478:  *      lookup.
 479:  */
 480: void
 481: dopushdef(name, defn)
 482: register char *name;
 483: register char *defn;
 484: {
 485:     register ndptr p;
 486: 
 487:     if (!*name)
 488:         oops("null definition");
 489:     if (STREQ(name, defn))
 490:         oops("%s: recursive definition.", name);
 491:     p = addent(name);
 492:     if (!*defn)
 493:         p->defn = null;
 494:     else
 495:         p->defn = xstrdup(defn);
 496:     p->type = MACRTYPE;
 497: }
 498: 
 499: /*
 500:  * dodumpdef - dump the specified definitions in the hash
 501:  *      table to stderr. If nothing is specified, the entire
 502:  *      hash table is dumped.
 503:  */
 504: void
 505: dodump(argv, argc)
 506: register char *argv[];
 507: register int argc;
 508: {
 509:     register int n;
 510:     ndptr p;
 511: 
 512:     if (argc > 2) {
 513:         for (n = 2; n < argc; n++)
 514:             if ((p = lookup(argv[n])) != nil)
 515:                 fprintf(stderr, dumpfmt, p->name,
 516:                     p->defn);
 517:     }
 518:     else {
 519:         for (n = 0; n < HASHSIZE; n++)
 520:             for (p = hashtab[n]; p != nil; p = p->nxtptr)
 521:                 fprintf(stderr, dumpfmt, p->name,
 522:                     p->defn);
 523:     }
 524: }
 525: 
 526: /*
 527:  * doifelse - select one of two alternatives - loop.
 528:  */
 529: void
 530: doifelse(argv, argc)
 531: register char *argv[];
 532: register int argc;
 533: {
 534:     cycle {
 535:         if (STREQ(argv[2], argv[3]))
 536:             pbstr(argv[4]);
 537:         else if (argc == 6)
 538:             pbstr(argv[5]);
 539:         else if (argc > 6) {
 540:             argv += 3;
 541:             argc -= 3;
 542:             continue;
 543:         }
 544:         break;
 545:     }
 546: }
 547: 
 548: /*
 549:  * doinclude - include a given file.
 550:  */
 551: int
 552: doincl(ifile)
 553: char *ifile;
 554: {
 555:     if (ilevel + 1 == MAXINP)
 556:         oops("too many include files.");
 557:     if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
 558:         ilevel++;
 559:         bbase[ilevel] = bufbase = bp;
 560:         return (1);
 561:     }
 562:     else
 563:         return (0);
 564: }
 565: 
 566: #ifdef EXTENDED
 567: /*
 568:  * dopaste - include a given file without any
 569:  *           macro processing.
 570:  */
 571: int
 572: dopaste(pfile)
 573: char *pfile;
 574: {
 575:     FILE *pf;
 576:     register int c;
 577: 
 578:     if ((pf = fopen(pfile, "r")) != NULL) {
 579:         while ((c = getc(pf)) != EOF)
 580:             putc(c, active);
 581:         (void) fclose(pf);
 582:         return (1);
 583:     }
 584:     else
 585:         return (0);
 586: }
 587: #endif
 588: 
 589: /*
 590:  * dochq - change quote characters
 591:  */
 592: void
 593: dochq(argv, argc)
 594: register char *argv[];
 595: register int argc;
 596: {
 597:     if (argc > 2) {
 598:         if (*argv[2])
 599:             lquote = *argv[2];
 600:         if (argc > 3) {
 601:             if (*argv[3])
 602:                 rquote = *argv[3];
 603:         }
 604:         else
 605:             rquote = lquote;
 606:     }
 607:     else {
 608:         lquote = LQUOTE;
 609:         rquote = RQUOTE;
 610:     }
 611: }
 612: 
 613: /*
 614:  * dochc - change comment characters
 615:  */
 616: void
 617: dochc(argv, argc)
 618: register char *argv[];
 619: register int argc;
 620: {
 621:     if (argc > 2) {
 622:         if (*argv[2])
 623:             scommt = *argv[2];
 624:         if (argc > 3) {
 625:             if (*argv[3])
 626:                 ecommt = *argv[3];
 627:         }
 628:         else
 629:             ecommt = ECOMMT;
 630:     }
 631:     else {
 632:         scommt = SCOMMT;
 633:         ecommt = ECOMMT;
 634:     }
 635: }
 636: 
 637: /*
 638:  * dodivert - divert the output to a temporary file
 639:  */
 640: void
 641: dodiv(n)
 642: register int n;
 643: {
 644:     if (n < 0 || n >= MAXOUT)
 645:         n = 0;             /* bitbucket */
 646:     if (outfile[n] == NULL) {
 647:         m4temp[UNIQUE] = n + '0';
 648:         if ((outfile[n] = fopen(m4temp, "w")) == NULL)
 649:             oops("%s: cannot divert.", m4temp);
 650:     }
 651:     oindex = n;
 652:     active = outfile[n];
 653: }
 654: 
 655: /*
 656:  * doundivert - undivert a specified output, or all
 657:  *              other outputs, in numerical order.
 658:  */
 659: void
 660: doundiv(argv, argc)
 661: register char *argv[];
 662: register int argc;
 663: {
 664:     register int ind;
 665:     register int n;
 666: 
 667:     if (argc > 2) {
 668:         for (ind = 2; ind < argc; ind++) {
 669:             n = atoi(argv[ind]);
 670:             if (n > 0 && n < MAXOUT && outfile[n] != NULL)
 671:                 getdiv(n);
 672: 
 673:         }
 674:     }
 675:     else
 676:         for (n = 1; n < MAXOUT; n++)
 677:             if (outfile[n] != NULL)
 678:                 getdiv(n);
 679: }
 680: 
 681: /*
 682:  * dosub - select substring
 683:  */
 684: void
 685: dosub(argv, argc)
 686: register char *argv[];
 687: register int argc;
 688: {
 689:     register char *ap, *fc, *k;
 690:     register int nc;
 691: 
 692:     if (argc < 5)
 693:         nc = MAXTOK;
 694:     else
 695: #ifdef EXPR
 696:         nc = expr(argv[4]);
 697: #else
 698:         nc = atoi(argv[4]);
 699: #endif
 700:     ap = argv[2];              /* target string */
 701: #ifdef EXPR
 702:     fc = ap + expr(argv[3]);       /* first char */
 703: #else
 704:     fc = ap + atoi(argv[3]);       /* first char */
 705: #endif
 706:     if (fc >= ap && fc < ap + strlen(ap))
 707:         for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
 708:             putback(*k);
 709: }
 710: 
 711: /*
 712:  * map:
 713:  * map every character of s1 that is specified in from
 714:  * into s3 and replace in s. (source s1 remains untouched)
 715:  *
 716:  * This is a standard implementation of map(s,from,to) function of ICON
 717:  * language. Within mapvec, we replace every character of "from" with
 718:  * the corresponding character in "to". If "to" is shorter than "from",
 719:  * than the corresponding entries are null, which means that those
 720:  * characters dissapear altogether. Furthermore, imagine
 721:  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
 722:  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
 723:  * ultimately maps to `*'. In order to achieve this effect in an efficient
 724:  * manner (i.e. without multiple passes over the destination string), we
 725:  * loop over mapvec, starting with the initial source character. if the
 726:  * character value (dch) in this location is different than the source
 727:  * character (sch), sch becomes dch, once again to index into mapvec, until
 728:  * the character value stabilizes (i.e. sch = dch, in other words
 729:  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
 730:  * character, it will stabilize, since mapvec[0] == 0 at all times. At the
 731:  * end, we restore mapvec* back to normal where mapvec[n] == n for
 732:  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
 733:  * about 5 times faster than any algorithm that makes multiple passes over
 734:  * destination string.
 735:  */
 736: void
 737: map(dest, src, from, to)
 738: register char *dest;
 739: register char *src;
 740: register char *from;
 741: register char *to;
 742: {
 743:     register char *tmp;
 744:     register char sch, dch;
 745:     static char mapvec[128] = {
 746:         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
 747:         12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
 748:         24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
 749:         36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 750:         48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
 751:         60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
 752:         72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
 753:         84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
 754:         96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
 755:         108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
 756:         120, 121, 122, 123, 124, 125, 126, 127
 757:     };
 758: 
 759:     if (*src) {
 760:         tmp = from;
 761:     /*
 762: 	 * create a mapping between "from" and
 763: 	 * "to"
 764: 	 */
 765:         while (*from)
 766:             mapvec[*from++] = (*to) ? *to++ : (char) 0;
 767: 
 768:         while (*src) {
 769:             sch = *src++;
 770:             dch = mapvec[sch];
 771:             while (dch != sch) {
 772:                 sch = dch;
 773:                 dch = mapvec[sch];
 774:             }
 775:             if (*dest = dch)
 776:                 dest++;
 777:         }
 778:     /*
 779: 	 * restore all the changed characters
 780: 	 */
 781:         while (*tmp) {
 782:             mapvec[*tmp] = *tmp;
 783:             tmp++;
 784:         }
 785:     }
 786:     *dest = (char) 0;
 787: }

Defined functions

dochc defined in line 616; used 1 times
dochq defined in line 592; used 1 times
dodefine defined in line 434; used 1 times
dodefn defined in line 460; used 1 times
dodiv defined in line 640; used 1 times
dodump defined in line 504; used 1 times
doifelse defined in line 529; used 1 times
doincl defined in line 551; used 2 times
dopaste defined in line 571; used 2 times
dopushdef defined in line 480; used 1 times
dosub defined in line 684; used 1 times
doundiv defined in line 659; used 1 times
eval defined in line 75; never used
expand defined in line 374; never used
map defined in line 736; used 2 times

Defined variables

dumpfmt defined in line 369; used 2 times
sccsid defined in line 38; never used
Last modified: 1994-04-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1984
Valid CSS Valid XHTML 1.0 Strict