home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / m4 / m4.c next >
Encoding:
C/C++ Source or Header  |  1979-01-10  |  15.0 KB  |  900 lines

  1. #include <stdio.h>
  2. #include <signal.h>
  3.  
  4. #define ERROR NULL
  5. #define    READ    "r"
  6. #define    WRITE    "w"
  7.  
  8. #define    EOS    0
  9. int    lpar    = '(';
  10. #define    LPAR    lpar
  11. #define    RPAR    ')'
  12. #define    COMMA    ','
  13. #define    GRAVE    '`'
  14. #define    ACUTE    '\''
  15. #define LBRAK    '['
  16. #define RBRAK    ']'
  17. #ifdef  M4
  18. char    lquote    LBRAK;
  19. char    rquote    RBRAK;
  20. #endif
  21. #ifndef M4
  22. char    lquote    = GRAVE;
  23. char    rquote    = ACUTE;
  24. #endif
  25. #define    COMMENT    '#'
  26. #define    ALPH    1
  27. #define    DIG    2
  28.  
  29. #define    HSHSIZ    199    /* prime */
  30. #define    STACKS    50
  31. #define    SAVS    4096
  32. #define    TOKS    128
  33.  
  34. #define    putbak(c)    *ip++ = c;
  35. #define    getchr()    (ip>cur_ip?*--ip: getc(infile[infptr]))
  36. #define    putchr(c)    if (cp==NULL) {if (curfile)putc(c,curfile);} else *op++ = c
  37. char    type[] = {
  38.     0,    0,    0,    0,    0,    0,    0,    0,
  39.     0,    0,    0,    0,    0,    0,    0,    0,
  40.     0,    0,    0,    0,    0,    0,    0,    0,
  41.     0,    0,    0,    0,    0,    0,    0,    0,
  42.     0,    0,    0,    0,    0,    0,    0,    0,
  43.     0,    0,    0,    0,    0,    0,    0,    0,
  44.     DIG,    DIG,    DIG,    DIG,    DIG,    DIG,    DIG,    DIG,
  45.     DIG,    DIG,    0,    0,    0,    0,    0,    0,
  46.     0,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,
  47.     ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,
  48.     ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,
  49.     ALPH,    ALPH,    ALPH,    0,    0,    0,    0,    ALPH,
  50.     0,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,
  51.     ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,
  52.     ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,    ALPH,
  53.     ALPH,    ALPH,    ALPH,    0,    0,    0,    0,    0,
  54. };
  55.  
  56. char    token[TOKS];
  57. char    eoa[]    = "\0";
  58. struct    nlist {
  59.     char    *name;
  60.     char    *def;
  61.     struct    nlist *next;
  62. };
  63.  
  64. struct    nlist    *hshtab[HSHSIZ];
  65. char    ibuf[SAVS+TOKS];
  66. char    obuf[SAVS+TOKS];
  67. char    *op    = obuf;
  68. char    *ip    = ibuf;
  69. char *ip_stk[10] = {ibuf};
  70. char *cur_ip = ibuf;
  71. struct call {
  72.     char    **argp;
  73.     int    plev;
  74. };
  75. struct    call    *cp = NULL;
  76.  
  77. char    *makeloc;
  78. char    *ifdefloc;
  79. char    *lenloc;
  80. char    *undefloc;
  81. char    *shiftloc;
  82. char    *cqloc;
  83. char    *defloc;
  84. char    *evaloc;
  85. char    *incrloc;
  86. char    *substrloc;
  87. char    *indexloc;
  88. char    *transloc;
  89. char    *ifloc;
  90. char    *divloc;
  91. char    *divnumloc;
  92. char    *undivloc;
  93. char    *dnlloc;
  94. char    *inclloc;
  95. char    *sinclloc;
  96. char    *syscmdloc;
  97. char    *dumploc;
  98. char    *errploc;
  99.  
  100. char    *tempname;
  101. struct nlist    *lookup();
  102. char    *install();
  103. char    *malloc();
  104. char    *mktemp();
  105. char    *copy();
  106. long    ctol();
  107. int    hshval;
  108. FILE    *olist[11] = { stdout };
  109. int    okret;
  110. int    curout    = 0;
  111. FILE    *curfile = { stdout };
  112. FILE    *infile[10] = { stdin };
  113. int    infptr    = 0;
  114.  
  115. main(argc, argv)
  116. char **argv;
  117. {
  118.     char *argstk[STACKS+10];
  119.     struct call callst[STACKS];
  120.     register char *tp, **ap;
  121.     int delexit(), catchsig();
  122.     register t;
  123.     int i;
  124.  
  125. #ifdef gcos
  126. #ifdef M4
  127.     install("GCOS", eoa);
  128. #endif
  129. #ifndef M4
  130.     install("gcos", eoa);
  131. #endif
  132. #endif
  133. #ifdef unix
  134. #ifdef M4
  135.     install("UNIX", eoa);
  136. #endif
  137. #ifndef M4
  138.     install("unix", eoa);
  139. #endif
  140. #endif
  141.  
  142. #ifdef M4
  143.     makeloc = install("MAKETEMP", eoa);
  144.     ifdefloc = install("IFDEF", eoa);
  145.     lenloc = install("LEN", eoa);
  146.     undefloc = install("UNDEFINE", eoa);
  147.     shiftloc = install("SHIFT", eoa);
  148.     cqloc = install("CHANGEQUOTE", eoa);
  149.     defloc = install("DEFINE", eoa);
  150.     evaloc = install("EVAL", eoa);
  151.     inclloc = install("INCLUDE", eoa);
  152.     sinclloc = install("SINCLUDE", eoa);
  153.     syscmdloc = install("SYSCMD", eoa);
  154.     dumploc = install("DUMPDEF", eoa);
  155.     errploc = install("ERRPRINT", eoa);
  156.     incrloc = install("INCR", eoa);
  157.     substrloc = install("SUBSTR", eoa);
  158.     indexloc = install("INDEX", eoa);
  159.     transloc = install("TRANSLIT", eoa);
  160.     ifloc = install("IFELSE", eoa);
  161.     divloc = install("DIVERT", eoa);
  162.     divnumloc = install("DIVNUM", eoa);
  163.     undivloc = install("UNDIVERT", eoa);
  164.     dnlloc = install("DNL", eoa);
  165. #endif
  166.  
  167. #ifndef M4
  168.     makeloc = install("maketemp", eoa);
  169.     ifdefloc = install("ifdef", eoa);
  170.     lenloc = install("len", eoa);
  171.     undefloc = install("undefine", eoa);
  172.     shiftloc = install("shift", eoa);
  173.     cqloc = install("changequote", eoa);
  174.     defloc = install("define", eoa);
  175.     evaloc = install("eval", eoa);
  176.     inclloc = install("include", eoa);
  177.     sinclloc = install("sinclude", eoa);
  178.     syscmdloc = install("syscmd", eoa);
  179.     dumploc = install("dumpdef", eoa);
  180.     errploc = install("errprint", eoa);
  181.     incrloc = install("incr", eoa);
  182.     substrloc = install("substr", eoa);
  183.     indexloc = install("index", eoa);
  184.     transloc = install("translit", eoa);
  185.     ifloc = install("ifelse", eoa);
  186.     divloc = install("divert", eoa);
  187.     divnumloc = install("divnum", eoa);
  188.     undivloc = install("undivert", eoa);
  189.     dnlloc = install("dnl", eoa);
  190. #endif
  191.     ap = argstk;
  192. #ifndef gcos
  193.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  194.         signal(SIGHUP, catchsig);
  195.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  196.         signal(SIGINT, catchsig);
  197.     tempname = mktemp("/tmp/m4aXXXXX");
  198.     close(creat(tempname, 0));
  199. #endif
  200. #ifdef gcos
  201.     tempname = "m4.tempa";
  202. #endif
  203.     if (argc>1)
  204.         putbak(0);
  205.     for (;;) {
  206.         tp = token;
  207.         *tp++ = t = getchr();
  208.         *tp = EOS;
  209.         if (t<=0) {
  210.             if (infptr > 0) {
  211.                 fclose(infile[infptr]);
  212.                 infptr--;
  213.                 cur_ip = ip_stk[infptr];
  214.                 continue;
  215.             }
  216.             if (argc<=1)
  217.                 break;
  218.             argc--;
  219.             argv++;
  220.             if (infile[infptr]!=stdin)
  221.                 fclose(infile[infptr]);
  222.             if (**argv=='-')
  223.                 infile[infptr] = stdin;
  224.             else if ((infile[infptr]=fopen(argv[0], READ))==ERROR) {
  225.                 fprintf(stderr, "m4: file not found: %s\n", argv[0]);
  226.                 delexit();
  227.             }
  228.             continue;
  229.         }
  230.         if (type[t]==ALPH) {
  231.             while ((t=type[*tp++=getchr()])==ALPH||t==DIG);
  232.             putbak(*--tp);
  233.             *tp = EOS;
  234.             if (*ap = lookup(token)->def) {
  235.                 if (++ap >= &argstk[STACKS]) {
  236.                     fprintf(stderr, "m4: arg stack overflow\n");
  237.                     delexit();
  238.                 }
  239.                 if (cp==NULL)
  240.                     cp = callst;
  241.                 else if (++cp > &callst[STACKS]) {
  242.                     fprintf(stderr, "m4: call stack overflow\n");
  243.                     delexit();
  244.                 }
  245.                 cp->argp = ap;
  246.                 *ap++ = op;
  247.                 puttok();
  248.                 *op++ = '\0';
  249.                 t = getchr();
  250.                 putbak(t);
  251.                 if (t!=LPAR) {
  252.                     /* if (t!=' ' && t!='\t') */
  253.                         putbak(')');
  254.                     putbak('(');
  255.                 }
  256.                 else    /* try to fix arg count */
  257.                     *ap++ = op;
  258.                 cp->plev = 0;
  259.             } else
  260.                 puttok();
  261.         } else if (t==lquote) {
  262.             i = 1;
  263.             for (;;) {
  264.                 t = getchr();
  265.                 if (t==rquote) {
  266.                     i--;
  267.                     if (i==0)
  268.                         break;
  269.                 } else if (t==lquote)
  270.                     i++;
  271.                 else if (t<0) {
  272.                     fprintf(stderr, "m4: EOF in string\n");
  273.                     delexit();
  274.                 }
  275.                 putchr(t);
  276.             }
  277.         } else if (t==COMMENT) {
  278.             putbak(t);
  279.             while ((t = getchr())!='\n'&& t>=0)
  280.                 if (cp==NULL)
  281.                     putchr(t);
  282.             putbak(t);
  283.         } else if (cp==NULL) {
  284.             puttok();
  285.         } else if (t==LPAR) {
  286.             if (cp->plev)
  287.                 *op++ = t;
  288.             cp->plev++;
  289.             while ( (t=getchr())==' ' || t=='\t' || t=='\n')
  290.                 ;    /* skip leading white space during arg collection */
  291.             putbak(t);
  292. /*
  293.         } else if (t==' ' || t=='\t' || t=='\n') {
  294.             continue;
  295. */
  296.         } else if (t==RPAR) {
  297.             cp->plev--;
  298.             if (cp->plev==0) {
  299.                 *op++ = '\0';
  300.                 expand(cp->argp, ap-cp->argp-1);
  301.                 op = *cp->argp;
  302.                 ap = cp->argp-1;
  303.                 cp--;
  304.                 if (cp < callst)
  305.                     cp = NULL;
  306.             } else
  307.                 *op++ = t;
  308.         } else if (t==COMMA && cp->plev<=1) {
  309.             *op++ = '\0';
  310.             *ap++ = op;
  311.             while ((t=getchr())==' ' || t=='\t' || t=='\n')
  312.                 ;    /* skip leading white space during arg collection */
  313.             putbak(t);
  314.         } else
  315.             *op++ = t;
  316.     }
  317.     if (cp!=NULL) {
  318.         fprintf(stderr, "m4: unexpected EOF\n");
  319.         delexit();
  320.     }
  321.     okret = 1;
  322.     delexit();
  323. }
  324.  
  325. catchsig()
  326. {
  327.     okret = 0;
  328.     delexit();
  329. }
  330.  
  331. delexit()
  332. {
  333.     register FILE *fp;
  334.     register i, c;
  335.  
  336.     if (!okret) {
  337.         signal(SIGHUP, SIG_IGN);
  338.         signal(SIGINT, SIG_IGN);
  339.     }
  340.     for (i=1; i<10; i++) {
  341.         if (olist[i]==NULL)
  342.             continue;
  343.         fclose(olist[i]);
  344.         tempname[7] = 'a'+i;
  345.         if (okret) {
  346.             fp = fopen(tempname, READ);
  347.             while ((c = getc(fp)) > 0)
  348.                 putchar(c);
  349.             fclose(fp);
  350.         }
  351.         unlink(tempname);
  352.     }
  353.     tempname[7] = 'a';
  354.     unlink(tempname);
  355.     exit(1-okret);
  356. }
  357.  
  358. puttok()
  359. {
  360.     register char *tp;
  361.  
  362.     tp = token;
  363.     if (cp) {
  364.         if (op >= &obuf[SAVS]) {
  365.             fprintf(stderr, "m4: argument overflow\n");
  366.             delexit();
  367.         }
  368.         while (*tp)
  369.             *op++ = *tp++;
  370.     } else if (curfile)
  371.         while (*tp)
  372.             putc(*tp++, curfile);
  373. }
  374.  
  375. pbstr(str)
  376. register char *str;
  377. {
  378.     register char *p;
  379.  
  380.     p = str;
  381.     while (*p++);
  382.     --p;
  383.     if (ip >= &ibuf[SAVS]) {
  384.         fprintf(stderr, "m4: pushback overflow\n");
  385.         delexit();
  386.     }
  387.     while (p > str)
  388.         putbak(*--p);
  389. }
  390.  
  391. expand(a1, c)
  392. register char **a1;
  393. {
  394.     register char *dp;
  395.     register n;
  396.  
  397.     dp = a1[-1];
  398.     if (dp==defloc)
  399.         dodef(a1, c);
  400.     else if (dp==evaloc)
  401.         doeval(a1, c);
  402.     else if (dp==inclloc)
  403.         doincl(a1, c, 1);
  404.     else if (dp==sinclloc)
  405.         doincl(a1, c, 0);
  406.     else if (dp==makeloc)
  407.         domake(a1, c);
  408.     else if (dp==syscmdloc)
  409.         dosyscmd(a1, c);
  410.     else if (dp==incrloc)
  411.         doincr(a1, c);
  412.     else if (dp==substrloc)
  413.         dosubstr(a1, c);
  414.     else if (dp==indexloc)
  415.         doindex(a1, c);
  416.     else if (dp==transloc)
  417.         dotransl(a1, c);
  418.     else if (dp==ifloc)
  419.         doif(a1, c);
  420.     else if (dp==divloc)
  421.         dodiv(a1, c);
  422.     else if (dp==divnumloc)
  423.         dodivnum(a1, c);
  424.     else if (dp==undivloc)
  425.         doundiv(a1, c);
  426.     else if (dp==dnlloc)
  427.         dodnl(a1, c);
  428.     else if (dp==dumploc)
  429.         dodump(a1, c);
  430.     else if (dp==errploc)
  431.         doerrp(a1, c);
  432.     else if (dp==lenloc)
  433.         dolen(a1, c);
  434.     else if (dp==ifdefloc)
  435.         doifdef(a1, c);
  436.     else if (dp==undefloc)
  437.         doundef(a1, c);
  438.     else if (dp==shiftloc)
  439.         doshift(a1, c);
  440.     else if (dp==cqloc)
  441.         docq(a1, c);
  442.     else {
  443.         while (*dp++);
  444.         for (dp--; dp>a1[-1]; ) {
  445.             if (--dp>a1[-1] && dp[-1]=='$') {
  446.                 n = *dp-'0';
  447.                 if (n>=0 && n<=9) {
  448.                     if (n <= c)
  449.                         pbstr(a1[n]);
  450.                     dp--;
  451.                 } else
  452.                     putbak(*dp);
  453.             } else
  454.                 putbak(*dp);
  455.         }
  456.     }
  457. }
  458.  
  459. struct nlist *lookup(str)
  460. char *str;
  461. {
  462.     register char *s1, *s2;
  463.     register struct nlist *np;
  464.     static struct nlist nodef;
  465.  
  466.     s1 = str;
  467.     for (hshval = 0; *s1; )
  468.         hshval += *s1++;
  469.     hshval %= HSHSIZ;
  470.     for (np = hshtab[hshval]; np!=NULL; np = np->next) {
  471.         s1 = str;
  472.         s2 = np->name;
  473.         while (*s1++ == *s2)
  474.             if (*s2++ == EOS)
  475.                 return(np);
  476.     }
  477.     return(&nodef);
  478. }
  479.  
  480. char *install(nam, val)
  481. char *nam, *val;
  482. {
  483.     register struct nlist *np;
  484.  
  485.     if ((np = lookup(nam))->name == NULL) {
  486.         np = (struct nlist *)malloc(sizeof(*np));
  487.         if (np == NULL) {
  488.             fprintf(stderr, "m4: no space for alloc\n");
  489.             exit(1);
  490.         }
  491.         np->name = copy(nam);
  492.         np->def = copy(val);
  493.         np->next = hshtab[hshval];
  494.         hshtab[hshval] = np;
  495.         return(np->def);
  496.     }
  497.     free(np->def);
  498.     np->def = copy(val);
  499.     return(np->def);
  500. }
  501.  
  502. doundef(ap, c)
  503. char **ap;
  504. {
  505.     register struct nlist *np, *tnp;
  506.  
  507.     if (c < 1 || (np = lookup(ap[1]))->name == NULL)
  508.         return;
  509.     tnp = hshtab[hshval];    /* lookup sets hshval */
  510.     if (tnp == np)    /* it's in first place */
  511.         hshtab[hshval] = np->next;
  512.     else {
  513.         for ( ; tnp->next != np; tnp = tnp->next)
  514.             ;
  515.         tnp->next = np->next;
  516.     }
  517.     free(np->name);
  518.     free(np->def);
  519.     free((char *)np);
  520. }
  521.  
  522. char *copy(s)
  523. register char *s;
  524. {
  525.     register char *p, *s1;
  526.  
  527.     p = s1 = malloc((unsigned)strlen(s)+1);
  528.     if (p == NULL) {
  529.         fprintf(stderr, "m4: no space for alloc\n");
  530.         exit(1);
  531.     }
  532.     while (*s1++ = *s++);
  533.     return(p);
  534. }
  535.  
  536. dodef(ap, c)
  537. char **ap;
  538. {
  539.     if (c >= 2) {
  540.         if (strcmp(ap[1], ap[2]) == 0) {
  541.             fprintf(stderr, "m4: %s defined as itself\n", ap[1]);
  542.             delexit();
  543.         }
  544.         install(ap[1], ap[2]);
  545.     }
  546.     else if (c == 1)
  547.         install(ap[1], "");
  548. }
  549.  
  550. doifdef(ap, c)
  551. char **ap;
  552. {
  553.     register struct nlist *np;
  554.  
  555.     if (c < 2)
  556.         return;
  557.     if (lookup(ap[1])->name != NULL)
  558.         pbstr(ap[2]);
  559.     else if (c >= 3)
  560.         pbstr(ap[3]);
  561. }
  562.  
  563. dolen(ap, c)
  564. char **ap;
  565. {
  566.     putnum((long) strlen(ap[1]));
  567. }
  568.  
  569. docq(ap, c)
  570. char **ap;
  571. {
  572.     if (c > 1) {
  573.         lquote = *ap[1];
  574.         rquote = *ap[2];
  575.     } else if (c == 1) {
  576.         lquote = rquote = *ap[1];
  577.     } else {
  578. #ifndef M4
  579.         lquote = GRAVE;
  580.         rquote = ACUTE;
  581. #endif
  582. #ifdef M4
  583.         lquote = LBRAK;
  584.         rquote = RBRAK;
  585. #endif
  586.     }
  587. }
  588.  
  589. doshift(ap, c)
  590. char **ap;
  591. {
  592.     fprintf(stderr, "m4: shift not yet implemented\n");
  593. }
  594.  
  595. dodump(ap, c)
  596. char **ap;
  597. {
  598.     int i;
  599.     register struct nlist *np;
  600.  
  601.     if (c > 0)
  602.         while (c--) {
  603.             if ((np = lookup(*++ap))->name != NULL)
  604.                 fprintf(stderr, "`%s'    `%s'\n", np->name, np->def);
  605.         }
  606.     else
  607.         for (i=0; i<HSHSIZ; i++)
  608.             for (np=hshtab[i]; np!=NULL; np=np->next)
  609.                 fprintf(stderr, "`%s'    `%s'\n", np->name, np->def);
  610. }
  611.  
  612. doerrp(ap, c)
  613. char **ap;
  614. {
  615.     if (c > 0) {
  616.         fprintf(stderr, ap[1], ap[2], ap[3], ap[4], ap[5], ap[6]);
  617.         fprintf(stderr, "\n");
  618.     }
  619. }
  620.  
  621.  
  622. long    evalval;    /* return value from yacc stuff */
  623. char    *pe;    /* used by grammar */
  624.  
  625. doeval(ap, c)
  626. char **ap;
  627. {
  628.  
  629.     if (c > 0) {
  630.         pe = ap[1];
  631.         if (yyparse() == 0)
  632.             putnum(evalval);
  633.         else
  634.             fprintf(stderr, "m4: invalid expression in eval: %s\n", ap[1]);
  635.     }
  636. }
  637.  
  638. doincl(ap, c, noisy)
  639. char **ap;
  640. {
  641.     if (c > 0 && strlen(ap[1]) > 0) {
  642.         infptr++;
  643.         ip_stk[infptr] = cur_ip = ip;
  644.         if ((infile[infptr] = fopen(ap[1], READ))==ERROR) {
  645.             if (noisy) {
  646.                 fprintf(stderr, "m4: file not found: %s\n", ap[1]);
  647.                 delexit();
  648.             }
  649.             else
  650.                 infptr--;
  651.         }
  652.     }
  653. }
  654.  
  655. dosyscmd(ap, c)
  656. char **ap;
  657. {
  658.     if (c > 0)
  659.         system(ap[1]);
  660. }
  661.  
  662. domake(ap, c)
  663. char **ap;
  664. {
  665.     if (c > 0)
  666.         pbstr(mktemp(ap[1]));
  667. }
  668.  
  669. doincr(ap, c)
  670. char **ap;
  671. {
  672.     if (c >= 1)
  673.         putnum(ctol(ap[1])+1);
  674. }
  675.  
  676. putnum(num)
  677. long num;
  678. {
  679.     register sign;
  680.  
  681.     sign = (num < 0) ? '-' : '\0';
  682.     if (num < 0)
  683.         num = -num;
  684.     do {
  685.         putbak(num%10+'0');
  686.         num = num/10;
  687.     } while (num!=0);
  688.     if (sign == '-')
  689.         putbak('-');
  690. }
  691.  
  692. dosubstr(ap, c)
  693. char **ap;
  694. {
  695.     int nc;
  696.     register char *sp, *fc;
  697.  
  698.     if (c<2)
  699.         return;
  700.     if (c<3)
  701.         nc = TOKS;
  702.     else
  703.         nc = ctoi(ap[3]);
  704.     fc = ap[1] + max(0, min(ctoi(ap[2]), strlen(ap[1])));
  705.     sp = fc + min(nc, strlen(fc));
  706.     while (sp > fc)
  707.         putbak(*--sp);
  708. }
  709.  
  710. doindex(ap, c)
  711. char **ap;
  712. {
  713.     if (c >= 2)
  714.         putnum((long) strindex(ap[1], ap[2]));
  715. }
  716.  
  717. strindex(p1, p2)
  718. char *p1, *p2;
  719. {
  720.     register m;
  721.     register char *s, *t, *p;
  722.  
  723.     for (p=p1; *p; p++) {
  724.         s = p;
  725.         m = 1;
  726.         for (t=p2; *t; )
  727.             if (*t++ != *s++)
  728.                 m = 0;
  729.         if (m == 1)
  730.             return(p-p1);
  731.     }
  732.     return(-1);
  733. }
  734.  
  735. dotransl(ap, c)
  736. char **ap;
  737. {
  738.     register char *s, *fr, *to;
  739.  
  740.     if (c <= 1) return;
  741.  
  742.     if (c == 2) {
  743.         register int i;
  744.         to = ap[1];
  745.         for (s = ap[1]; *s; s++) {
  746.             i = 0;
  747.             for (fr = ap[2]; *fr; fr++)
  748.                 if (*s == *fr) {
  749.                     i++;
  750.                     break;
  751.                 }
  752.             if (i == 0)
  753.                 *to++ = *s;
  754.         }
  755.         *to = '\0';
  756.     }
  757.  
  758.     if (c >= 3) {
  759.         for (s = ap[1]; *s; s++)
  760.             for (fr = ap[2], to = ap[3]; *fr && *to; fr++, to++)
  761.                 if (*s == *fr)
  762.                     *s = *to;
  763.     }
  764.  
  765.     pbstr(ap[1]);
  766. }
  767.  
  768. doif(ap, c)
  769. register char **ap;
  770. {
  771.     if (c < 3)
  772.         return;
  773.     while (c >= 3) {
  774.         if (strcmp(ap[1], ap[2]) == 0) {
  775.             pbstr(ap[3]);
  776.             return;
  777.         }
  778.         c -= 3;
  779.         ap += 3;
  780.     }
  781.     if (c > 0)
  782.         pbstr(ap[1]);
  783. }
  784.  
  785. dodiv(ap, c)
  786. register char **ap;
  787. {
  788.     register int f;
  789.  
  790.     if (c<1)
  791.         f = 0;
  792.     else
  793.         f = ctoi(ap[1]);
  794.     if (f>=10 || f<0) {
  795.         curfile = NULL;
  796.         return;
  797.     }
  798.     tempname[7] = 'a' + f;
  799.     if (olist[f] || (olist[f]=fopen(tempname, WRITE))) {
  800.         curout = f;
  801.         curfile = olist[f];
  802.     }
  803. }
  804.  
  805. doundiv(ap, c)
  806. char **ap;
  807. {
  808.     register FILE *fp;
  809.     register int i, ch;
  810.     int j;
  811.  
  812.     if (c == 0) {
  813.         for (i=1; i<10; i++) {
  814.             if (i==curout || olist[i]==NULL)
  815.                 continue;
  816.             fclose(olist[i]);
  817.             tempname[7] = 'a'+i;
  818.             fp = fopen(tempname, READ);
  819.             if (curfile != NULL)
  820.                 while ((ch = getc(fp)) > 0)
  821.                     putc(ch, curfile);
  822.             fclose(fp);
  823.             unlink(tempname);
  824.             olist[i] = NULL;
  825.         }
  826.  
  827.     }
  828.     else {
  829.         for (j = 1; j <= c; j++) {
  830.             i = ctoi(*++ap);
  831.             if (i<1 || i>9 || i==curout || olist[i]==NULL)
  832.                 continue;
  833.             fclose(olist[i]);
  834.             tempname[7] = 'a'+i;
  835.             fp = fopen(tempname, READ);
  836.             if (curfile != NULL)
  837.                 while ((ch = getc(fp)) > 0)
  838.                     putc(ch, curfile);
  839.             fclose(fp);
  840.             unlink(tempname);
  841.             olist[i] = NULL;
  842.         }
  843.     }
  844. }
  845.  
  846. dodivnum(ap, c)
  847. char **ap;
  848. {
  849.     putnum((long) curout);
  850. }
  851.  
  852. dodnl(ap, c)
  853. char **ap;
  854. {
  855.     register t;
  856.  
  857.     while ((t=getchr())!='\n' && t>=0)
  858.         ;
  859. }
  860.  
  861. long ctol(str)
  862. register char *str;
  863. {
  864.     register sign;
  865.     long num;
  866.  
  867.     while (*str==' ' || *str=='\t' || *str=='\n')
  868.         str++;
  869.     num = 0;
  870.     if (*str == '-') {
  871.         sign = -1;
  872.         str++;
  873.     }
  874.     else
  875.         sign = 1;
  876.     while (*str>='0' && *str<='9')
  877.         num = num*10 + *str++ - '0';
  878.     return(sign * num);
  879. }
  880.  
  881. ctoi(s)
  882. char *s;
  883. {
  884.     return(ctol(s));
  885. }
  886.  
  887. min(a, b)
  888. {
  889.     if (a>b)
  890.         return(b);
  891.     return(a);
  892. }
  893.  
  894. max(a, b)
  895. {
  896.     if (a>b)
  897.         return(a);
  898.     return(b);
  899. }
  900.