home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 264_01 / nrocmd.c < prev    next >
Text File  |  1979-12-31  |  12KB  |  735 lines

  1. /*
  2.  *    Command processor for NRO text processor
  3.  *
  4.  *    Stephen L. Browning
  5.  *    5723 North Parker Avenue
  6.  *    Indianapolis, Indiana 46220
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <ctype.h>
  11. #include "nro.h"
  12. #include "nrocom.c"
  13.  
  14. comand(p)
  15. char *p;
  16. {
  17.     int ct, val;
  18.     int spval;
  19.     int index;
  20.     char argtyp;
  21.     char name[MAXLINE];
  22.     char macexp[MXMLEN];
  23.     char *skipwd(), *skipbl();
  24.  
  25.     ct = comtyp(p,macexp);
  26.     if (ct == UNKNOWN)
  27.     {
  28.         fprintf(stderr, "nro: unrecognized command %s\n",p);
  29.         return;
  30.     }
  31.     expesc(p,name);
  32.     val = getval(p,&argtyp);
  33.     switch (ct)
  34.     {
  35.     case BO: /* bold face */
  36.         set(&dc.boval,val,argtyp,1,0,HUGE);
  37.         dc.cuval = dc.ulval = 0;
  38.         break;
  39.  
  40.     case BP: /* begin page */
  41.         if(pg.lineno > 0)
  42.             space(HUGE);
  43.         set(&pg.curpag,val,argtyp,pg.curpag+1,-HUGE,HUGE);
  44.         pg.newpag = pg.curpag;
  45.         break;
  46.  
  47.     case BR: /* break */
  48.         brk();
  49.         break;
  50.  
  51.     case BS: /* backspaces in output */
  52.         set(&dc.bsflg,val,argtyp,1,0,1);
  53.         break;
  54.  
  55.     case CC: /* command character */
  56.         if (argtyp == '\r' || argtyp == '\n')
  57.             dc.cmdchr = '.';
  58.         else
  59.             dc.cmdchr = argtyp;
  60.         break;
  61.  
  62.     case CE: /* center */
  63.         brk();
  64.         set(&dc.ceval,val,argtyp,1,0,HUGE);
  65.         break;
  66.  
  67.     case CU: /* continuous underline */
  68.         set(&dc.cuval,val,argtyp,1,0,HUGE);
  69.         dc.ulval = dc.boval = 0;
  70.         break;
  71.  
  72.     case DE: /* define macro */
  73.         defmac(p,sofile[dc.flevel]);
  74.         break;
  75.  
  76.     case EF: /* even footer */
  77.         gettl(p,pg.efoot,&pg.eflim[0]);
  78.         break;
  79.  
  80.     case EH: /* even header */
  81.         gettl(p,pg.ehead,&pg.ehlim[0]);
  82.         break;
  83.  
  84.     case EN: /* end macro definition */
  85.         fprintf(stderr, "***nro: missing .de command\n");
  86.         break;
  87.  
  88.     case FI: /* fill */
  89.         brk();
  90.         dc.fill = YES;
  91.         break;
  92.  
  93.     case FO: /* footer */
  94.         gettl(p,pg.efoot,&pg.eflim[0]);
  95.         gettl(p,pg.ofoot,&pg.oflim[0]);
  96.         break;
  97.  
  98.     case HE: /* header */
  99.         gettl(p,pg.ehead,&pg.ehlim[0]);
  100.         gettl(p,pg.ohead,&pg.ohlim[0]);
  101.         break;
  102.  
  103.     case IN: /* indenting */
  104.         set(&dc.inval,val,argtyp,0,0,dc.rmval-1);
  105.         dc.tival = dc.inval;
  106.         break;
  107.  
  108.     case JU: /* justify */
  109.         dc.juval = YES;
  110.         break;
  111.  
  112.     case LS: /* line spacing */
  113.         set(&dc.lsval,val,argtyp,1,1,HUGE);
  114.         break;
  115.  
  116.     case M1: /* set topmost margin */
  117.         set(&pg.m1val,val,argtyp,2,0,HUGE);
  118.         break;
  119.  
  120.     case M2: /* set second top margin */
  121.         set(&pg.m2val,val,argtyp,2,0,HUGE);
  122.         break;
  123.  
  124.     case M3: /* set first bottom margin */
  125.         set(&pg.m3val,val,argtyp,2,0,HUGE);
  126.         pg.bottom = pg.plval - pg.m4val - pg.m3val;
  127.         break;
  128.  
  129.     case M4: /* set bottom-most margin */
  130.         set(&pg.m4val,val,argtyp,2,0,HUGE);
  131.         pg.bottom = pg.plval - pg.m4val - pg.m3val;
  132.         break;
  133.  
  134.     case MACRO: /* macro expansion */
  135.         maceval(p,macexp);
  136.         break;
  137.  
  138.     case NE: /* need n lines */
  139.         brk();
  140.         if ((pg.bottom-pg.lineno+1) < (val*dc.lsval))
  141.         {
  142.             space(HUGE);
  143.         }
  144.         break;
  145.  
  146.     case NF: /* no fill */
  147.         brk();
  148.         dc.fill = NO;
  149.         break;
  150.  
  151.     case NJ: /* no justify */
  152.         dc.juval = NO;
  153.         break;
  154.  
  155.     case NR: /* set number register */
  156.         p = skipwd(p);
  157.         p = skipbl(p);
  158.         if (!isalpha(*p))
  159.         {
  160.             fprintf(stderr, "nro: invalid or missing number register name\n");
  161.         }
  162.         else
  163.         {
  164.             index = tolower(*p) - 'a';
  165.             p = skipwd(p);
  166.             val = getval(p,&argtyp);
  167.             set(&dc.nr[index],val,argtyp,0,-HUGE,HUGE);
  168.         }
  169.         break;
  170.  
  171.     case OF: /* odd footer */
  172.         gettl(p,pg.ofoot,&pg.oflim[0]);
  173.         break;
  174.  
  175.     case OH: /* odd header */
  176.         gettl(p,pg.ohead,&pg.ohlim[0]);
  177.         break;
  178.  
  179.     case PC: /* page number character */
  180.         if (argtyp == '\r' || argtyp == '\n')
  181.             dc.pgchr = '\0';
  182.         else
  183.             dc.pgchr = argtyp;
  184.         break;
  185.  
  186.     case PL: /* page length */
  187.         set(&pg.plval,val,argtyp,PAGELEN,
  188.             pg.m1val+pg.m2val+pg.m3val+pg.m4val+1,HUGE);
  189.         pg.bottom = pg.plval - pg.m3val - pg.m4val;
  190.         break;
  191.  
  192.     case PO: /* page offset */
  193.         set(&pg.offset,val,argtyp,0,0,HUGE);
  194.         break;
  195.  
  196.     case RM: /* right margin */
  197.         set(&dc.rmval,val,argtyp,PAGEWIDTH,dc.tival+1,HUGE);
  198.         break;
  199.  
  200.     case SO: /* source file */
  201.         p = skipwd(p);
  202.         p = skipbl(p);
  203.         if (getwrd(p,name) == 0) break;
  204.         if (dc.flevel+1 >= NFILES)
  205.         {
  206.             fprintf(stderr, "nro: .so commands nested too deeply\n");
  207.             exit(-1);
  208.         }
  209.         if((sofile[dc.flevel+1] = fopen(name, "r")) == (FILE *)0)
  210.         {
  211.             printf("***nro: unable to open %s\n",name);
  212.             exit(-1);
  213.         }
  214.         ++dc.flevel;
  215.         break;
  216.  
  217.     case SP: /* space */
  218.         set(&spval,val,argtyp,1,0,HUGE);
  219.         space(spval);
  220.         break;
  221.  
  222.     case TI: /* temporary indent */
  223.         brk();
  224.         set(&dc.tival,val,argtyp,0,0,dc.rmval);
  225.         break;
  226.  
  227.     case UL: /* underline */
  228.         set(&dc.ulval,val,argtyp,0,1,HUGE);
  229.         dc.cuval = dc.boval = 0;
  230.         break;
  231.     }
  232. }
  233.  
  234.  
  235.  
  236. /*
  237.  *    convert ascii character to decimal.
  238.  */
  239.  
  240. atod(c)
  241. char c;
  242. {
  243.     return(((c < '0') || (c > '9')) ? -1 : c-'0');
  244. }
  245.  
  246.  
  247.  
  248. /*
  249.  *    end current filled line
  250.  */
  251.  
  252. brk()
  253. {
  254.     if(co.outp > 0)
  255.     {
  256.         co.outbuf[co.outp] = '\r';
  257.         co.outbuf[co.outp + 1] = '\n';
  258.         co.outbuf[co.outp + 2] = '\0';
  259.         put(co.outbuf);
  260.     }
  261.     co.outp = 0;
  262.     co.outw = 0;
  263.     co.outwds = 0;
  264. }
  265.  
  266.  
  267. /*
  268.  *    Collect macro definition from input stream
  269.  */
  270.  
  271. colmac(p,d,i)
  272. char *p, d[];
  273. int i;
  274. {
  275.     while (*p != '\0')
  276.     {
  277.         if (i >= MXMLEN-1)
  278.         {
  279.             d[i-1] = '\0';
  280.             return(ERR);
  281.         }
  282.         d[i++] = *p++;
  283.     }
  284.     d[i] = '\0';
  285.     return(i);
  286. }
  287.  
  288.  
  289.  
  290.  
  291. /*
  292.  *    decodes nro command and returns its associated
  293.  *    value.
  294.  */
  295.  
  296. comtyp(p,m)
  297. char *p;
  298. char *m;
  299. {
  300.     char c1, c2;
  301.     char macnam[MNLEN];
  302.     char *s;
  303.  
  304.     p++;
  305.     /*
  306.     *    First check to see if the command is a macro.
  307.     *    If it is, truncate to two characters and return
  308.     *    expansion in m.  Note that upper and lower case
  309.     *    characters are handled differently for macro names,
  310.     *    but not for normal command names.
  311.     */
  312.     getwrd(p,macnam);
  313.     macnam[2] = '\0';
  314.     if ((s = getmac(macnam)) != NULL)
  315.     {
  316.         strcpy(m,s);
  317.         return(MACRO);
  318.     }
  319.     c1 = tolower(*p);
  320.     p++;
  321.     c2 = tolower(*p);
  322.     if (c1 == 'b' && c2 == 'o') return(BO);
  323.     if (c1 == 'b' && c2 == 'p') return(BP);
  324.     if (c1 == 'b' && c2 == 'r') return(BR);
  325.     if (c1 == 'b' && c2 == 's') return(BS);
  326.     if (c1 == 'c' && c2 == 'c') return(CC);
  327.     if (c1 == 'c' && c2 == 'e') return(CE);
  328.     if (c1 == 'c' && c2 == 'u') return(CU);
  329.     if (c1 == 'd' && c2 == 'e') return(DE);
  330.     if (c1 == 'e' && c2 == 'f') return(EF);
  331.     if (c1 == 'e' && c2 == 'h') return(EH);
  332.     if (c1 == 'e' && c2 == 'n') return(EN);
  333.     if (c1 == 'f' && c2 == 'i') return(FI);
  334.     if (c1 == 'f' && c2 == 'o') return(FO);
  335.     if (c1 == 'h' && c2 == 'e') return(HE);
  336.     if (c1 == 'i' && c2 == 'n') return(IN);
  337.     if (c1 == 'j' && c2 == 'u') return(JU);
  338.     if (c1 == 'l' && c2 == 's') return(LS);
  339.     if (c1 == 'm' && c2 == '1') return(M1);
  340.     if (c1 == 'm' && c2 == '2') return(M2);
  341.     if (c1 == 'm' && c2 == '3') return(M3);
  342.     if (c1 == 'm' && c2 == '4') return(M4);
  343.     if (c1 == 'n' && c2 == 'e') return(NE);
  344.     if (c1 == 'n' && c2 == 'f') return(NF);
  345.     if (c1 == 'n' && c2 == 'j') return(NJ);
  346.     if (c1 == 'n' && c2 == 'r') return(NR);
  347.     if (c1 == 'o' && c2 == 'f') return(OF);
  348.     if (c1 == 'o' && c2 == 'h') return(OH);
  349.     if (c1 == 'p' && c2 == 'c') return(PC);
  350.     if (c1 == 'p' && c2 == 'l') return(PL);
  351.     if (c1 == 'p' && c2 == 'o') return(PO);
  352.     if (c1 == 'r' && c2 == 'm') return(RM);
  353.     if (c1 == 's' && c2 == 'o') return(SO);
  354.     if (c1 == 's' && c2 == 'p') return(SP);
  355.     if (c1 == 't' && c2 == 'i') return(TI);
  356.     if (c1 == 'u' && c2 == 'l') return(UL);
  357.     return(UNKNOWN);
  358. }
  359.  
  360.  
  361.  
  362. /*
  363.  *    convert string to decimal.
  364.  *    processes only positive values.
  365.  */
  366.  
  367. ctod(p)
  368. char *p;
  369. {
  370.     int val, d;
  371.  
  372.     val = 0;
  373.     while(*p != '\0')
  374.     {
  375.         d = atod(*p++);
  376.         if(d == -1) return(val);
  377.         val = 10 * val + d;
  378.     }
  379.     return(val);
  380. }
  381.  
  382.  
  383. /*
  384.  *    Define a macro
  385.  */
  386.  
  387. defmac(p,infp)
  388. char *p;
  389. FILE *infp;
  390. {
  391.     int i;
  392.     char name[MNLEN];
  393.     char defn[MXMLEN];
  394.     char *q;
  395.  
  396.     q = skipwd(p);
  397.     q = skipbl(q);
  398.     i = getwrd(q,name);
  399.     if (!isalpha(*name))
  400.     {
  401.         fprintf("nro: missing or illegal macro definition name\n");
  402.         exit(-1);
  403.     }
  404.     if (i > 2) name[2] = '\0';
  405.     i = 0;
  406.     while (getlin(p,infp) != EOF)
  407.     {
  408.         if (p[0] == dc.cmdchr && tolower(p[1]) == 'e' && tolower(p[2]) == 'n')
  409.         {
  410.             break;
  411.         }
  412.         if ((i = colmac(p,defn,i)) == ERR)
  413.         {
  414.             fprintf("nro: macro definition too long\n");
  415.             exit(-1);
  416.         }
  417.     }
  418.     if (putmac(name,defn) == ERR)
  419.     {
  420.         fprintf("nro: macro definition table full\n");
  421.         exit(-1);
  422.     }
  423. }
  424.  
  425.  
  426. /*
  427.  *    Expand escape sequences
  428.  */
  429.  
  430. expesc(p,q)
  431. char *p;
  432. char *q;
  433. {
  434.     char *s, *t;
  435.  
  436.     s = p;
  437.     t = q;
  438.     while (*s != '\0')
  439.     {
  440.         if (*s != '@')
  441.         {
  442.             *t++ = *s++;
  443.         }
  444.         else if (*(s+1) == '@')
  445.         {
  446.             *t++ = *s++;
  447.             ++s;
  448.         }
  449.         else if (tolower(*(s+1)) == 'n' && isalpha(*(s+2)))
  450.         {
  451.             s += 2;
  452.             t += itoda(dc.nr[tolower(*s)-'a'],t,6) - 1;
  453.             ++s;
  454.         }
  455.         else
  456.         {
  457.             *t++ = *s++;
  458.         }
  459.     }
  460.     *t = '\0';
  461.     strcpy(p,q);
  462. }
  463.  
  464.  
  465.  
  466. /*
  467.  *    Get macro definition from table
  468.  */
  469.  
  470. char *getmac(name)
  471. char *name;
  472. {
  473.     int i;
  474.  
  475.     for (i = mac.lastp; i >= 0; --i)
  476.     {
  477.         if (!strcmp(name,mac.mnames[i]))
  478.         {
  479.             return(mac.mnames[i] + 3);
  480.         }
  481.     }
  482.     return(NULL);
  483. }
  484.  
  485.  
  486.  
  487.  
  488. /*
  489.  *    get header or footer title
  490.  */
  491.  
  492. gettl(p,q,limit)
  493. char *p;
  494. char *q;
  495. int limit[];
  496. {
  497.     p = skipwd(p);
  498.     p = skipbl(p);
  499.     strcpy(q,p);
  500.     limit[LEFT] = dc.inval;
  501.     limit[RIGHT] = dc.rmval;
  502. }
  503.  
  504.  
  505.  
  506. /*
  507.  *    retrieves optional argument following nro command.
  508.  *    returns positive integer value with sign (if any)
  509.  *    saved in character addressed by p_argt.
  510.  */
  511.  
  512. getval(p,p_argt)
  513. char *p;
  514. char *p_argt;
  515. {
  516.     p = skipwd(p);
  517.     p = skipbl(p);
  518.     *p_argt = *p;
  519.     if((*p == '+') || (*p == '-'))
  520.         ++p;
  521.     return(ctod(p));
  522. }
  523.  
  524.  
  525. /*
  526.  *    Evaluate macro expansion
  527.  */
  528.  
  529. maceval(p,m)
  530. char *p;
  531. char m[];
  532. {
  533.     int i, j;
  534.     char *argp[10];
  535.     char c;
  536.  
  537.     *p++ = '\0';        /* replace command char with '\0' */
  538.     /*
  539.     *    initialize argp array to substitute command
  540.     *    string for any undefined argument
  541.     */
  542.     for (i=0; i<10; ++i)
  543.         argp[i] = p;
  544.     p = skipwd(p);
  545.     *p++ = '\0';
  546.     for (i=0; i<10; ++i)
  547.     {
  548.         p = skipbl(p);
  549.         if (*p == '\r' || *p == '\n' || *p == '\0')
  550.             break;
  551.         if (*p == '\'' || *p == '"')
  552.         {
  553.             c = *p++;
  554.             argp[i] = p;
  555.             while (*p != c && *p != '\r' && *p != '\n' && *p != '\0')
  556.                 ++p;
  557.             *p++ = '\0';
  558.         }
  559.         else
  560.         {
  561.             argp[i] = p;
  562.             p = skipwd(p);
  563.             *p++ = '\0';
  564.         }
  565.     }
  566.     for (i=strlen(m)-1; i>=0; --i)
  567.     {
  568.         if (i > 0 && m[i-1] == '$')
  569.         {
  570.             if (!isdigit(m[i]))
  571.             {
  572.                 putbak(m[i]);
  573.             }
  574.             else
  575.             {
  576.                 pbstr(argp[m[i]-'0']);
  577.                 --i;
  578.             }
  579.         }
  580.         else
  581.         {
  582.             putbak(m[i]);
  583.         }
  584.     }
  585. }
  586.  
  587.  
  588. /*
  589.  *    Push back string into input stream
  590.  */
  591.  
  592. pbstr(p)
  593. char p[];
  594. {
  595.     int i;
  596.  
  597.     for (i=strlen(p)-1; i>=0; --i)
  598.     {
  599.         putbak(p[i]);
  600.     }
  601. }
  602.  
  603.  
  604.  
  605. /*
  606.  *    Push character back into input stream
  607.  */
  608.  
  609. putbak(c)
  610. char c;
  611. {
  612.     if (mac.ppb < &mac.pbb[0]) {
  613.         mac.ppb = &mac.pbb[0];
  614.         *mac.ppb = c;
  615.     }
  616.     else
  617.     {
  618.         if (mac.ppb >= &mac.pbb[MAXLINE-1])
  619.         {
  620.             puts("nro: push back buffer overflow\n");
  621.             exit(-1);
  622.         }
  623.         *++mac.ppb = c;
  624.     }
  625. }
  626.  
  627.  
  628.  
  629.  
  630. /*
  631.  *    Put macro definition into table
  632.  */
  633.  
  634. putmac(name,p)
  635. char *name;
  636. char *p;
  637. {
  638.     if (mac.lastp >= MXMDEF)
  639.         return(ERR);
  640.     if (mac.emb + strlen(name) + strlen(p) + 1 > &mac.mb[MACBUF])
  641.     {
  642.         return(ERR);
  643.     }
  644.     ++mac.lastp;
  645.     mac.mnames[mac.lastp] = mac.emb;
  646.     strcpy(mac.emb,name);
  647.     strcpy(mac.emb + strlen(name) + 1,p);
  648.     mac.emb += strlen(name) + strlen(p) + 2;
  649.     return(OK);
  650. }
  651.  
  652.  
  653.  
  654.  
  655. /*
  656.  *    set parameter and check range
  657.  */
  658.  
  659. set(param,val,type,defval,minval,maxval)
  660. int *param;
  661. int val;
  662. char type;
  663. int defval,minval,maxval;
  664. {
  665.     switch(type)
  666.     {
  667.     case '\r':
  668.     case '\n':
  669.         *param = defval;
  670.         break;
  671.  
  672.     case '+':
  673.         *param += val;
  674.         break;
  675.  
  676.     case '-':
  677.         *param -= val;
  678.         break;
  679.  
  680.     default:
  681.         *param = val;
  682.         break;
  683.     }
  684.     *param = min(*param,maxval);
  685.     *param = max(*param,minval);
  686. }
  687.  
  688.  
  689.  
  690. /*
  691.  *    skip blanks and tabs in character buffer.
  692.  *    return number of characters skipped.
  693.  */
  694.  
  695. char *skipbl(p)
  696. char *p;
  697. {
  698.     while (*p == ' ' || *p == '\t')
  699.         ++p;
  700.     return(p);
  701. }
  702.  
  703.  
  704. /*
  705.  *    skip over word and punctuation
  706.  */
  707.  
  708. char *skipwd(p)
  709. char *p;
  710. {
  711.     while (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
  712.         ++p;
  713.     return(p);
  714. }
  715.  
  716.  
  717.  
  718. /*
  719.  *    space vertically n lines
  720.  */
  721.  
  722. space(n)
  723. int n;
  724. {
  725.     brk();
  726.     if (pg.lineno > pg.bottom)
  727.         return;
  728.     if (pg.lineno == 0)
  729.         phead();
  730.     skip(min(n,pg.bottom+1-pg.lineno));
  731.     pg.lineno += n;
  732.     if (pg.lineno > pg.bottom) pfoot();
  733. }
  734.  
  735.