home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / gawk / cawf2st.zoo / pass2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-12  |  51.7 KB  |  1,266 lines

  1. /*
  2.  *      pass2.c - cawf(1) pass 2 function
  3.  */
  4.  
  5. /*
  6.  *      Copyright (c) 1991 Purdue University Research Foundation,
  7.  *      West Lafayette, Indiana 47907.  All rights reserved.
  8.  *
  9.  *      Written by Victor A. Abell <abe@mace.cc.purdue.edu>,  Purdue
  10.  *      University Computing Center.  Not derived from licensed software;
  11.  *      derived from awf(1) by Henry Spencer of the University of Toronto.
  12.  *
  13.  *      Permission is granted to anyone to use this software for any
  14.  *      purpose on any computer system, and to alter it and redistribute
  15.  *      it freely, subject to the following restrictions:
  16.  *
  17.  *      1. The author is not responsible for any consequences of use of
  18.  *         this software, even if they arise from flaws in it.
  19.  *
  20.  *      2. The origin of this software must not be misrepresented, either
  21.  *         by explicit claim or by omission.  Credits must appear in the
  22.  *         documentation.
  23.  *
  24.  *      3. Altered versions must be plainly marked as such, and must not
  25.  *         be misrepresented as being the original software.  Credits must
  26.  *         appear in the documentation.
  27.  *
  28.  *      4. This notice may not be removed or altered.
  29.  */
  30.  
  31. #include "cawf.h"
  32. #ifdef  UNIX
  33. #ifdef  USG
  34. #include <string.h>
  35. #else
  36. #include <strings.h>
  37. #endif
  38. #else
  39. #include <string.h>
  40. #endif
  41. #include <ctype.h>
  42.  
  43. /*
  44.  * Pass2(line) - process the nroff commands in a line and break
  45.  *               text into words for pass 3
  46.  */
  47.  
  48. void
  49. Pass2(line)
  50.         char *line;
  51. {
  52.         char buf[MAXLINE];              /* working buffer */
  53.         char c;                         /* character buffer */
  54.         double d;                       /* temporary double */
  55.         double exscale;                 /* expression scaling factor */
  56.         double expr[MAXEXP];            /* expressions */
  57.         char exsign[MAXEXP];            /* expression signs */
  58.         int i, j, k;                    /* temporary indexes */
  59.         int inword;                     /* word processing status */
  60.         int nexpr;                      /* number of expressions */
  61.         char nm[4];                     /* name */
  62.         int nsp;                        /* number of spaces */
  63.         char op;                        /* expression term operator */
  64.         char opstack[MAXSP];            /* expression operation stack */
  65.         char period;                    /* end of word status */
  66.         char *s1, *s2, *s3, *s4, *s5;   /* temporary string pointers */
  67.         double sexpr[MAXEXP];           /* signed expressions */
  68.         int sp;                         /* expression stack pointer */
  69.         char ssign;                     /* expression's starting sign */
  70.         int tabpos;                     /* tab position */
  71.         double tscale;                  /* term scaling factor */
  72.         double tval;                    /* term value */
  73.         double val;                     /* term value */
  74.         double valstack[MAXSP];         /* expression value stack */
  75.         char xbuf[MAXLINE];             /* expansion buffer */
  76.  
  77.         if (line == NULL) {
  78.     /*
  79.      * End of macro expansion.
  80.      */
  81.                 Pass3(DOBREAK, "need", NULL, 999);      /* flush page */
  82.                 return;
  83.         }
  84.     /*
  85.      * Adjust line number.
  86.      */
  87.         if (Lockil == 0)
  88.                 P2il++;
  89.     /*
  90.      * Empty line - "^[ \t]*$".
  91.      */
  92.         if (regexec(Pat[6].pat, line)) {
  93.                 Pass3(DOBREAK, "space", NULL, 0);
  94.                 return;
  95.         }
  96.     /*
  97.      * Line begins with white space.
  98.      */
  99.         if (*line == ' ' || *line == '\t') {
  100.                 Pass3(DOBREAK, "flush", NULL, 0);
  101.                 Pass3(0, "", NULL, 0);
  102.         }
  103.     /*
  104.      * Line contains text (not an nroff command).
  105.      */
  106.         if (*line != '.') {
  107.                 if (Font[0] == 'R' && Backc == 0 && Aftnxt == NULL
  108.                 &&  regexec(Pat[7].pat, line) == 0) {
  109.                     /*
  110.                      * The font is Roman, there is no "\\c" or "after next"
  111.                      * trap pending and and the line has no '\\', '\t', '-',
  112.                      * or "  "  (regular expression "\\|\t|-|  ").
  113.                      *
  114.                      * Output each word of the line as "<length> <word>".
  115.                      */
  116.                         for (s1 = line;;) {
  117.                                 while (*s1 && *s1 == ' ')
  118.                                         s1++;
  119.                                 if (*s1 == '\0')
  120.                                         break;
  121.                                 for (s2 = s1, s3 = buf; *s2 && *s2 != ' ';)
  122.                                         *s3++ = Trtbl[(int)*s2++];
  123.                                 *s3 = '\0';
  124.                                 Pass3((s2 - s1), buf, NULL, 0);
  125.                                 s1 = *s2 ? ++s2 : s2;
  126.                         }
  127.                     /*
  128.                      * Line terminates with punctuation and optional
  129.                      * bracketing (regular expression "[.!?:][\])'\"*]*$").
  130.                      */
  131.                         if (regexec(Pat[8].pat, line))
  132.                                 Pass3(NOBREAK, "gap", NULL, 2);
  133.                         if (Centering > 0) {
  134.                                 Pass3(DOBREAK,"center", NULL, 0);
  135.                                 Centering--;
  136.                         } else if (Fill == 0)
  137.                                 Pass3(DOBREAK, "flush", NULL, 0);
  138.                         return;
  139.                 }
  140.             /*
  141.              * Line must be scanned a character at a time.
  142.              */
  143.                 inword = nsp = tabpos = 0;
  144.                 period = '\0';
  145.                 for (s1 = line;; s1++) {
  146.                     /*
  147.                      * Space or TAB causes state transition.
  148.                      */
  149.                         if (*s1 == '\0' || *s1 == ' ' || *s1 == '\t') {
  150.                                 if (inword) {
  151.                                         if (!Backc) {
  152.                                                 Word[Wordx] = '\0';
  153.                                                 Pass3(Wordl, Word, NULL, 0);
  154.                                                 if (Uhyph) {
  155.                                                     Pass3(NOBREAK, "nohyphen",
  156.                                                         NULL, 0);
  157.                                                 }
  158.                                         }
  159.                                         inword = 0;
  160.                                         nsp = 0;
  161.                                 }
  162.                                 if (*s1 == '\0')
  163.                                         break;
  164.                         } else {
  165.                                 if (inword == 0) {
  166.                                         if (Backc == 0) {
  167.                                                 Wordl = Wordx = 0;
  168.                                                 Uhyph = 0;
  169.                                         }
  170.                                         Backc = 0;
  171.                                         inword = 1;
  172.                                         if (nsp > 1) {
  173.                                                 Pass3(NOBREAK, "gap", NULL,
  174.                                                     nsp);
  175.                                         }
  176.                                 }
  177.                         }
  178.                     /*
  179.                      * Process a character.
  180.                      */
  181.                         switch (*s1) {
  182.                     /*
  183.                      * Space
  184.                      */
  185.                         case ' ':
  186.                                 nsp++;
  187.                                 period = '\0';
  188.                                 break;
  189.                     /*
  190.                      * TAB
  191.                      */
  192.                         case '\t':
  193.                                 tabpos++;
  194.                                 if (tabpos <= Ntabs) {
  195.                                         Pass3(NOBREAK, "tabto", NULL,
  196.                                             Tabs[tabpos-1]);
  197.                                 }
  198.                                 nsp = 0;
  199.                                 period = '\0';
  200.                                 break;
  201.                     /*
  202.                      * Hyphen if word is being assembled
  203.                      */
  204.                         case '-':
  205.                                 if (Wordl <= 0)
  206.                                     goto ordinary_char;
  207.                                 if ((i = Findhy(NULL, 0, 0)) < 0) {
  208.                                     Error(WARN, LINE, " no hyphen for font ",
  209.                                         Font);
  210.                                     return;
  211.                                 }
  212.                                 Word[Wordx] = '\0';
  213.                                 Pass3(Wordl, Word, NULL, Hychar[i].len);
  214.                                 Pass3(NOBREAK, "userhyphen", Hychar[i].str,
  215.                                     Hychar[i].len);
  216.                                 Wordl = Wordx = 0;
  217.                                 period = '\0';
  218.                                 Uhyph = 1;
  219.                                 break;
  220.                     /*
  221.                      * Backslash
  222.                      */
  223.                         case '\\':
  224.                                 s1++;
  225.                                 switch(*s1) {
  226.                             /*
  227.                              * Change font - "\\fN"
  228.                              */
  229.                                 case 'f':
  230.                                         s1 = Asmcode(&s1, nm);
  231.                                         if (nm[0] == 'P') {
  232.                                             Font[0] = Prevfont;
  233.                                             break;
  234.                                         }
  235.                                         for (i = 0; Fcode[i].nm; i++) {
  236.                                             if (Fcode[i].nm == nm[0])
  237.                                                 break;
  238.                                         }
  239.                                         if (Fcode[i].nm == '\0'
  240.                                         ||  nm[1] != '\0') {
  241.                                             Error(WARN, LINE, " unknown font ",
  242.                                                 nm);
  243.                                             break;
  244.                                         }
  245.                                         if (Fcode[i].status != '1') {
  246.                                             Error(WARN, LINE,
  247.                                                 " font undefined ", nm);
  248.                                             break;
  249.                                         } else {
  250.                                             Prevfont = Font[0];
  251.                                             Font[0] = nm[0];
  252.                                         }
  253.                                         break;
  254.                             /*
  255.                              * Positive horizontal motion - "\\h\\n(NN" or
  256.                              * "\\h\\nN"
  257.                              */
  258.                                 case 'h':
  259.                                         if (s1[1] != '\\' || s1[2] != 'n') {
  260.                                             Error(WARN, LINE,
  261.                                                 " no \\n after \\h", NULL);
  262.                                             break;
  263.                                         }
  264.                                         s1 +=2;
  265.                                         s1 = Asmcode(&s1, nm);
  266.                                         if ((i = Findnum(nm, 0, 0)) < 0)
  267.                                                 goto unknown_num;
  268.                                         if ((j = Numb[i].val) < 0) {
  269.                                             Error(WARN, LINE, " \\h < 0 ",
  270.                                             NULL);
  271.                                             break;
  272.                                         }
  273.                                         if (j == 0)
  274.                                                 break;
  275.                                         if ((strlen(s1+1) + j + 1) >=  MAXLINE)
  276.                                                 goto line_too_long;
  277.                                         for (s2 = &xbuf[1]; j; j--)
  278.                                                 *s2++ = ' ';
  279.                                         (void) strcpy(s2, s1+1);
  280.                                         s1 = xbuf;
  281.                                         break;
  282.                             /*
  283.                              * Save current position in register if "\\k<reg>"
  284.                              */
  285.                                 case 'k':
  286.                                         s1 = Asmcode(&s1, nm);
  287.                                         if ((i = Findnum(nm, 0, 0)) < 0)
  288.                                             i = Findnum(nm, 0, 1);
  289.                                         Numb[i].val =
  290.                                                 (int)((double)Outll * Scalen);
  291.                                         break;
  292.                             /*
  293.                              * Interpolate number - "\\n(NN" or "\\nN"
  294.                              */
  295.                                 case 'n':
  296.                                         s1 = Asmcode(&s1, nm);
  297.                                         if ((i = Findnum(nm, 0, 0)) < 0) {
  298. unknown_num:
  299.                                             Error(WARN, LINE,
  300.                                                 " unknown number register ",
  301.                                                 nm);
  302.                                             break;
  303.                                         }
  304.                                         (void) sprintf(buf, "%d",
  305.                                             Numb[i].val);
  306.                                         if ((strlen(buf) + strlen(s1+1) + 1)
  307.                                         >=  MAXLINE) {
  308. line_too_long:
  309.                                             Error(WARN, LINE, " line too long",
  310.                                                 NULL);
  311.                                             break;
  312.                                         }
  313.                                         (void) sprintf(buf, "%d%s",
  314.                                             Numb[i].val, s1+1);
  315.                                         (void) strcpy(&xbuf[1], buf);
  316.                                         s1 = xbuf;
  317.                                         break;
  318.                             /*
  319.                              * Change size - "\\s[+-][0-9]" - NOP
  320.                              */
  321.                                 case 's':
  322.                                         s1++;
  323.                                         if (*s1 == '+' || *s1 == '-')
  324.                                                 s1++;
  325.                                         while (*s1 && isdigit(*s1))
  326.                                                 s1++;
  327.                                         s1--;
  328.                                         break;
  329.                             /*
  330.                              * Continue - "\\c"
  331.                              */
  332.                                 case 'c':
  333.                                         Backc = 1;
  334.                                         break;
  335.                             /*
  336.                              * Interpolate string - "\\*(NN" or "\\*N"
  337.                              */
  338.                                 case '*':
  339.                                         s1 = Asmcode(&s1, nm);
  340.                                         s2 = Findstr(nm, NULL, 0);
  341.                                         if (*s2 != '\0') {
  342.                                             if ((strlen(s2) + strlen(s1+1) + 1)
  343.                                             >=  MAXLINE)
  344.                                                 goto line_too_long;
  345.                                             (void) sprintf(buf, "%s%s",
  346.                                                 s2, s1+1);
  347.                                             (void) strcpy(&xbuf[1], buf);
  348.                                             s1 = xbuf;
  349.                                         }
  350.                                         break;
  351.                             /*
  352.                              * Discretionary hyphen - "\\%"
  353.                              */
  354.                                 case '%':
  355.                                         if (Wordl <= 0)
  356.                                             break;
  357.                                         if ((i = Findhy(NULL, 0, 0)) < 0) {
  358.                                             Error(WARN, LINE,
  359.                                                 " np hyphen for font ", Font);
  360.                                             break;
  361.                                         }
  362.                                         Word[Wordx] = '\0';
  363.                                         Pass3(Wordl, Word, NULL, Hychar[i].len);
  364.                                         Pass3(NOBREAK, "hyphen", Hychar[i].str,
  365.                                             Hychar[i].len);
  366.                                         Wordl = Wordx = 0;
  367.                                         Uhyph = 1;
  368.                                         break;
  369.                             /*
  370.                              * None of the above - may be special character
  371.                              * name.
  372.                              */
  373.                                 default:
  374.                                         s2 = --s1;
  375.                                         s1 = Asmcode(&s1, nm);
  376.                                         if ((i = Findchar(nm, 0, 0, 0)) < 0) {
  377.                                             s1 = s2;
  378.                                             goto ordinary_char;
  379.                                         }
  380.                                         if (strcmp(nm, "em") == 0
  381.                                         && Wordx > 0) {
  382.                                     /*
  383.                                      * "\\(em" is a special case when a word
  384.                                      * has been assembled, because of
  385.                                      * hyphenation.
  386.                                      */
  387.                                             Word[Wordx] = '\0';
  388.                                             Pass3(Wordl, Word, NULL,
  389.                                                 Schar[i].len);
  390.                                             Pass3(NOBREAK, "userhyphen",
  391.                                                 Schar[i].str, Schar[i].len);
  392.                                             Wordl = Wordx = 0;
  393.                                             period = '\0';
  394.                                             Uhyph = 1;
  395.                                         }
  396.                                     /*
  397.                                      * Interpolate a special character
  398.                                      */
  399.                                         if (Str2word(Schar[i].str,
  400.                                             strlen(Schar[i].str)) != 0)
  401.                                                 return;
  402.                                         Wordl += Schar[i].len;
  403.                                         period = '\0';
  404.                                 }
  405.                                 break;
  406.                     /*
  407.                      * Ordinary character
  408.                      */
  409.                         default:
  410. ordinary_char:
  411.                                 if (Str2word(s1, 1) != 0)
  412.                                         return;
  413.                                 Wordl++;
  414.                                 if (*s1 == '.' || *s1 == '!'
  415.                                 ||  *s1 == '?' || *s1 == ':')
  416.                                     period = '.';
  417.                                 else if (period == '.') {
  418.                                     nm[0] = *s1;
  419.                                     nm[1] = '\0';
  420.                                     if (regexec(Pat[13].pat, nm) == 0)
  421.                                          period = '\0';
  422.                                 }
  423.                         }
  424.                 }
  425.             /*
  426.              * End of line processing
  427.              */
  428.                 if (!Backc) {
  429.                         if (period == '.')
  430.                                 Pass3(NOBREAK, "gap", NULL, 2);
  431.                         if (Centering > 0) {
  432.                                 Pass3(DOBREAK, "center", NULL, 0);
  433.                                 Centering--;
  434.                         } else if (!Fill)
  435.                                 Pass3(DOBREAK, "flush", NULL, 0);
  436.                 }
  437.                 if (Aftnxt == NULL)
  438.                         return;
  439.                 /* else fall through to process an "after next trap */
  440.         }
  441.     /*
  442.      * Special -man macro handling.
  443.      */
  444.         if (Marg == MANMACROS) {
  445.             /*
  446.              * A text line - "^[^.]" - is only processed when there is an
  447.              * "after next" directive.
  448.              */
  449.                 if (*line != '.') {
  450.                         if (Aftnxt != NULL) {
  451.                                 if (regexec(Pat[9].pat, Aftnxt))  /* ",fP" */
  452.                                         Font[0] = Prevfont;
  453.                                 if (regexec(Pat[10].pat, Aftnxt))  /* ",tP" */
  454.                                         Pass3(DOBREAK, "toindent", NULL, 0);
  455.                                 Free(&Aftnxt);
  456.                         }
  457.                         return;
  458.                 }
  459.             /*
  460.              * Special footer handling - "^.lF"
  461.              */
  462.                 if (line[1] == 'l' && line[2] == 'F') {
  463.                         s1 = Findstr("by", NULL, 0);
  464.                         s2 = Findstr("nb", NULL, 0);
  465.                         if (*s1 == '\0' || *s2 == '\0')
  466.                                 (void) sprintf(buf, "%s%s", s1, s2);
  467.                         else
  468.                                 (void) sprintf(buf, "%s; %s", s1, s2);
  469.                         Pass3(NOBREAK, "LF", buf, 0);
  470.                         return;
  471.                 }
  472.         }
  473.     /*
  474.      * Special -ms macro handling.
  475.      */
  476.         if (Marg == MSMACROS) {
  477.             /*
  478.              * A text line - "^[^.]" - is only processed when there is an
  479.              * "after next" directive.
  480.              */
  481.                 if (*line != '.') {
  482.                         if (Aftnxt != NULL) {
  483.                                 if (regexec(Pat[10].pat, Aftnxt))  /* ",tP" */
  484.                                         Pass3(DOBREAK, "toindent", NULL, 0);
  485.                                 Free(&Aftnxt);
  486.                         }
  487.                         return;
  488.                 }
  489.             /*
  490.              * Numbered headings - "^\.nH"
  491.              */
  492.                 if (line[1] == 'n' && line[2] == 'H') {
  493.                         s1 = Field(2, line, 0);
  494.                         if (s1 != NULL) {
  495.                                 i = atoi(s1) - 1;       
  496.                                 if (i < 0) {
  497.                                         for (j = 0; j < MAXNHNR; j++) {
  498.                                                 Nhnr[j] = 0;
  499.                                         }
  500.                                         i = 0;
  501.                                 } else if (i >= MAXNHNR) {
  502.                                     (void) sprintf(buf, " over NH limit (%d)",
  503.                                         MAXNHNR);
  504.                                     Error(WARN, LINE, buf, NULL);
  505.                                 }
  506.                         } else
  507.                                 i = 0;
  508.                         Nhnr[i]++;
  509.                         for (j = i + 1; j < MAXNHNR; j++) {
  510.                                 Nhnr[j] = 0;
  511.                         }
  512.                         s1 = buf;
  513.                         for (j = 0; j <= i; j++) {
  514.                                 (void) sprintf(s1, "%d.", Nhnr[j]);
  515.                                 s1 = buf + strlen(buf);
  516.                         }
  517.                         (void) Findstr("Nh", buf, 1);
  518.                         return;
  519.                 }
  520.         }
  521.     /*
  522.      * Remaining lines should begin with a '.' unless an "after next"
  523.      * trap has failed.
  524.      */
  525.         if (line[0] != '.') {
  526.                 if (Aftnxt != NULL)
  527.                         Error(WARN, LINE, " failed .it: ", Aftnxt);
  528.                 else
  529.                         Error(WARN, LINE, " unrecognized line ", NULL);
  530.                 return;
  531.         }
  532.     /*
  533.      * Evaluate expressions for "^\.(ta|ll|ls|in|ti|po|ne|sp|pl|nr)"
  534.      * Then process the commands.
  535.      */
  536.         if (regexec(Pat[11].pat, &line[1])) {
  537.             /*
  538.              * Establish default scale factor.
  539.              */
  540.                 if ((line[1] == 'n' && line[2] == 'e')
  541.                 ||  (line[1] == 's' && line[2] == 'p')
  542.                 ||  (line[1] == 'p' && line[2] == 'l'))
  543.                         exscale = Scalev;
  544.                 else if (line[1] == 'n' && line[2] == 'r')
  545.                         exscale = Scaleu;
  546.                 else
  547.                         exscale = Scalen;
  548.             /*
  549.              * Determine starting argument.
  550.              */
  551.                 if (line[1] == 'n' && line[2] == 'r')
  552.                         s1 = Field(2, &line[3], 0);
  553.                 else
  554.                         s1 = Field(1, &line[3], 0);
  555.             /*
  556.              * Evaluate expressions.
  557.              */
  558.                 for (nexpr = 0; s1 != NULL &&*s1 != '\0'; ) {
  559.                         while (*s1 == ' ' || *s1 == '\t')
  560.                                 s1++;
  561.                         if (*s1 == '+' || *s1 == '-')
  562.                                 ssign = *s1++;
  563.                         else
  564.                                 ssign = '\0';
  565.                     /*
  566.                      * Process terms.
  567.                      */
  568.                         val = 0.0;
  569.                         sp = -1;
  570.                         c = '+';
  571.                         s1--;
  572.                         while (c == '+' || c == '*' || c == '%'
  573.                         ||  c == ')' || c == '-' || c == '/') {
  574.                             op = c;
  575.                             s1++;
  576.                             tscale = exscale;
  577.                             tval = 0.0;
  578.                         /*
  579.                          * Pop stack on right parenthesis.
  580.                          */
  581.                             if (op == ')') {
  582.                                 tval = val;
  583.                                 if (sp >= 0) {
  584.                                     val = valstack[sp];
  585.                                     op = opstack[sp];
  586.                                     sp--;
  587.                                 } else {
  588.                                     Error(WARN, LINE,
  589.                                         " expression stack underflow", NULL);
  590.                                     return;
  591.                                 }
  592.                                 tscale = Scaleu;
  593.                         /*
  594.                          * Push stack on left parenthesis.
  595.                          */
  596.                             } else if (*s1 == '(') {
  597.                                 sp++;
  598.                                 if (sp >= MAXSP) {
  599.                                     Error(WARN, LINE,
  600.                                        " expression stack overflow", NULL);
  601.                                     return;
  602.                                 }
  603.                                 valstack[sp] = val;
  604.                                 opstack[sp] = op;
  605.                                 val = 0.0;
  606.                                 c = '+';
  607.                                 continue;
  608.                             } else if (*s1 == '\\') {
  609.                               s1++;
  610.                               switch(*s1) {
  611.                         /*
  612.                          * "\\"" begins a comment.
  613.                          */
  614.                               case '"':
  615.                                 while (*s1)
  616.                                         s1++;
  617.                                 break;
  618.                         /*
  619.                          * Crude width calculation for "\\w"
  620.                          */
  621.                               case 'w':
  622.                                 s2 = ++s1;
  623.                                 if (*s1) {
  624.                                     s1++;
  625.                                     while (*s1 && *s1 != *s2)
  626.                                         s1++;
  627.                                     tval = (double) (s1 - s2 - 1) * Scalen;
  628.                                     if (*s1)
  629.                                         s1++;
  630.                                 }
  631.                                 break;
  632.                         /*
  633.                          * Interpolate number register if "\\n".
  634.                          */
  635.                               case 'n':
  636.                                 s1 = Asmcode(&s1, nm);
  637.                                 if ((i = Findnum(nm, 0, 0)) >= 0)
  638.                                     tval = Numb[i].val;
  639.                                 s1++;
  640.                              }
  641.                         /*
  642.                          * Assemble numeric value.
  643.                          */
  644.                             } else if (*s1 == '.' || isdigit(*s1)) {
  645.                                 for (i = 0; isdigit(*s1) || *s1 == '.'; s1++) {
  646.                                     if (*s1 == '.') {
  647.                                         i = 10;
  648.                                         continue;
  649.                                     }
  650.                                     d = (double) (*s1 - '0');
  651.                                     if (i) {
  652.                                         tval = tval + (d / (double) i);
  653.                                         i = i * 10;
  654.                                     } else
  655.                                         tval = (tval * 10.0) + d;
  656.                                 }
  657.                             } else {
  658.                         /*
  659.                          * It's not an expression.  Ignore extra scale.
  660.                          */
  661.                                 if ((i = Findscale(*s1, 0.0, 0)) < 0) {
  662.                                     (void) sprintf(buf,
  663.                                         " \"%s\" isn't an expression", s1);
  664.                                     Error(WARN, LINE, buf, NULL);
  665.                                 }
  666.                                 s1++;
  667.                             }
  668.                         /*
  669.                          * Add term to expression value.
  670.                          */
  671.                             if ((i = Findscale(*s1, 0.0, 0)) >= 0) {
  672.                                 tval *= Scale[i].val;
  673.                                 s1++;
  674.                             } else
  675.                                 tval *= tscale;
  676.                             switch (op) {
  677.                             case '+':
  678.                                 val += tval;
  679.                                 break;
  680.                             case '-':
  681.                                 val -= tval;
  682.                                 break;
  683.                             case '*':
  684.                                 val *= tval;
  685.                                 break;
  686.                             case '/':
  687.                             case '%':
  688.                                 i = (int) val;
  689.                                 j = (int) tval;
  690.                                 if (j == 0) {
  691.                                     Error(WARN, LINE,
  692.                                         (*s1 == '/') ? "div" : "mod",
  693.                                         " by 0");
  694.                                     return;
  695.                                 }
  696.                                 if (op == '/')
  697.                                         val = (double) (i / j);
  698.                                 else
  699.                                         val = (double) (i % j);
  700.                                 break;
  701.                             }
  702.                             c = *s1;
  703.                         }
  704.                     /*
  705.                      * Save expression value and sign.
  706.                      */
  707.                         if (nexpr >= MAXEXP) {
  708.                                 (void) sprintf(buf,
  709.                                     " at expression limit of %d", MAXEXP);
  710.                                 Error(WARN, LINE, buf, NULL);
  711.                                 return;
  712.                         }
  713.                         exsign[nexpr] = ssign;
  714.                         expr[nexpr] = val;
  715.                         if (ssign == '-')
  716.                                 sexpr[nexpr] = -1.0 * val;
  717.                         else
  718.                                 sexpr[nexpr] = val;
  719.                         nexpr++;
  720.                         while (*s1 == ' ' || *s1 == '\t')
  721.                                 s1++;
  722.                 }
  723.             /*
  724.              * Set parameters "(ll|ls|in|ti|po|pl)"
  725.              */
  726.                 if (regexec(Pat[12].pat, &line[1])) {
  727.                         nm[0] = line[1];
  728.                         nm[1] = line[2];
  729.                         if ((i = Findparms(nm)) < 0) {
  730.                                 Error(WARN, LINE,
  731.                                     " can't find parameter register ", nm);
  732.                                 return;
  733.                         }
  734.                         if (nexpr == 0 || exscale == 0.0)
  735.                                 j = Parms[i].prev;
  736.                         else if (exsign[0] == '\0'
  737.                              ||  (nm[0] == 't' && nm[1] == 'i'))
  738.                                  j = (int)(sexpr[0] / exscale);
  739.                         else
  740.                                 j = Parms[i].val + (int)(sexpr[0] / exscale);
  741.                         Parms[i].prev = Parms[i].val;
  742.                         Parms[i].val = j;
  743.                         nm[0] = (nexpr) ? exsign[0] : '\0';     /* for .ti */
  744.                         nm[1] = '\0';
  745.                         Pass3(DOBREAK, Parms[i].cmd, nm, j);
  746.                         return;
  747.                 }
  748.                 if (line[1] == 'n') {
  749.                         switch(line[2]) {
  750.             /*
  751.              * Need - "^\.ne <expression>"
  752.              */
  753.                         case 'e':
  754.                                 if (nexpr && Scalev > 0.0)
  755.                                         i = (int) ((expr[0]/Scalev) + 0.99);
  756.                                 else
  757.                                         i = 0;
  758.                                 Pass3(DOBREAK, "need", NULL, i);
  759.                                 return;
  760.             /*
  761.              * Number - "^\.nr <name> <expression>"
  762.              */
  763.                         case 'r':
  764.                                 if ((s1 = Field(2, line, 0)) == NULL) {
  765.                                     Error(WARN, LINE, " bad number register",
  766.                                         NULL);
  767.                                     return;
  768.                                 }
  769.                                 if ((i = Findnum(s1, 0, 0)) < 0)
  770.                                     i = Findnum(s1, 0, 1);
  771.                                 if (nexpr < 1) {
  772.                                     Numb[i].val = 0;
  773.                                     return;
  774.                                 }
  775.                                 if (exsign[0] == '\0')
  776.                                     Numb[i].val = (int) expr[0];
  777.                                 else
  778.                                     Numb[i].val += (int) sexpr[0];
  779.                                 return;
  780.                         }
  781.                 }
  782.             /*
  783.              * Space - "^\.sp <expression>"
  784.              */
  785.                 if (line[1] == 's' && line[2] == 'p') {
  786.                         if (nexpr == 0)
  787.                                 i = 1;
  788.                         else
  789.                                 i = (int)((expr[0] / Scalev) + 0.99);
  790.                         while (i--)
  791.                                 Pass3(DOBREAK, "space", NULL, 0);
  792.                         return;
  793.                 }
  794.             /*
  795.              * Tab positions - "^\.ta <pos1> <pos2> . . ."
  796.              */
  797.                 if (line[1] == 't' && line[2] == 'a') {
  798.                         tval = 0.0;
  799.                         for (j = 0; j < nexpr; j++) {
  800.                                 if (exsign[j] == '\0')
  801.                                         tval = expr[j];
  802.                                 else
  803.                                         tval += sexpr[j];
  804.                                 Tabs[j] = (int) (tval / Scalen);
  805.                         }
  806.                         Ntabs = nexpr;
  807.                         return;
  808.                 }
  809.         }
  810.     /*
  811.      * Remaining lines begin with a '.'.
  812.      */
  813.  
  814.     /*
  815.      * Adjust - "^\.ad"
  816.      */
  817.         if (line[1] == 'a' && line[2] == 'd') {
  818.                 Pass3(NOBREAK, "both", NULL, 0);
  819.                 return;
  820.         }
  821.         if (line[1] == 'b') {
  822.                 switch (line[2]) {
  823.     /*
  824.      * Break - "^\.br"
  825.      */
  826.                 case 'r':
  827.                         Pass3(DOBREAK, "flush", NULL, 0);
  828.                         return;
  829.     /*
  830.      * Begin new page - "^\.bp"
  831.      */
  832.                 case 'p':
  833.                         Pass3(DOBREAK, "need", NULL, 999);
  834.                         return;
  835.                 }
  836.         }
  837.     /*
  838.      * Center - "^\.ce"
  839.      */
  840.         if (line[1] == 'c' && line[2] == 'e') {
  841.                 if ((s2 = Field(2, line, 0)) != NULL)
  842.                         Centering = atoi(s2);
  843.                 else
  844.                         Centering = 1;
  845.                 return;
  846.         }
  847.         if (line[1] == 'd') {
  848.                 switch (line[2]) {
  849.     /*
  850.      * Diversion on and off - "^\.di"
  851.      */
  852.                 case 'i':
  853.                         Pass3(DOBREAK, "flush", NULL, 0);
  854.                         Divert ^= 1;
  855.                         return;
  856.     /*
  857.      * Define string - "^\.ds"
  858.      */
  859.                 case 's':
  860.  
  861. common_ds:
  862.  
  863.                         if (Asmname(&line[3], nm) == 0) {
  864. no_name:
  865.                                 Error(WARN, LINE, " no name", NULL);
  866.                                 return;
  867.                         }
  868.                         s3 = Field(3, line, 0);
  869.                         s4 = Findstr(nm, s3, 1);
  870.                         if (Hdft) {
  871.                             /*
  872.                              * Look for names LH, LF, CH, CF, RH, RF.
  873.                              */
  874.                                 if ((nm[0]=='L' || nm[0]=='C' || nm[0]=='R')
  875.                                 &&  (nm[1]=='F' || nm[1]=='H')) {
  876.                                         (void) sprintf(buf, "%s", nm);
  877.                                         Pass3(NOBREAK, buf, s4, 0);
  878.                                 }
  879.                         }
  880.                         return;
  881.                 }
  882.         }
  883.         if (line[1] == 'f') {
  884.     /*
  885.      * Fill - "^\.fi"
  886.      */
  887.                 if (line[2] == 'i') {
  888.                         Fill = 1;
  889.                         Pass3(DOBREAK, "flush", NULL, 0);
  890.                         return;
  891.                 }
  892.     /*
  893.      * Font - "^\.ft <font_name>"
  894.      */
  895.                 if (line[2] == 't') {
  896.                         if (line[3] == '\0' || line[4] == '\0')
  897.                                 line[4] = 'P';
  898.                         if (line[4] == 'P') {
  899.                                 Font[0] = Prevfont;
  900.                                 return;
  901.                         }
  902.                         for (i = 0; Fcode[i].nm; i++) {
  903.                                 if (Fcode[i].nm == line[4])
  904.                                         break;
  905.                         }
  906.                         if (Fcode[i].status == '\0') {
  907.                                 Error(WARN, LINE, " bad font code", NULL);
  908.                                 return;
  909.                         }
  910.                         Prevfont = Font[0];
  911.                         Font[0] = line[4];
  912.                         return;
  913.                 }
  914.         }
  915.     /*
  916.      * Input trap - "^\.it [1 <command>]"
  917.      */
  918.         if (line[1] == 'i' && line[2] == 't') {
  919.                 if ((s2 = Field(2, line, 0)) == NULL) {
  920.                         Free(&Aftnxt);
  921.                         return;
  922.                 }
  923.                 if ((i = atoi(s2)) != 1) {
  924.                         Error(WARN, LINE, " first .it arg must be 1", NULL);
  925.                         return;
  926.                 }
  927.                 if ((s3 = Field(3, line, 0)) == NULL)
  928.                         Free(&Aftnxt);
  929.                 else {
  930.                         (void) sprintf(buf, "%s,%s",
  931.                                 (Aftnxt == NULL) ? "" : Aftnxt, s3);
  932.                         Free(&Aftnxt);
  933.                         Aftnxt = Newstr(buf);
  934.                 }
  935.                 return;
  936.         }
  937.     /*
  938.      * "^\.i0", "^\.lg" and "^\.li" - do nothing
  939.      */
  940.         if ((line[1] == 'i' && line[2] == '0')
  941.         ||  (line[1] == 'l' && line[2] == 'g')
  942.         ||  (line[1] == 'l' && line[2] == 'i'))
  943.                 return;
  944.         if (line[1] == 'n') {
  945.                 switch (line[2]) {
  946.     /*
  947.      * No adjust "^\.na"
  948.      */
  949.                 case 'a':
  950.                         Pass3(NOBREAK, "left", NULL, 0);
  951.                         return;
  952.     /*
  953.      * No fill - "^\.nf"
  954.      */
  955.                 case 'f':
  956.                         Fill = 0;
  957.                         Pass3(DOBREAK, "flush", NULL, 0);
  958.                         return;
  959.     /*
  960.      * No space - "^\.ns"
  961.      */
  962.                 case 's':
  963.                         Pass3(NOBREAK, "nospace", NULL, 0);
  964.                         return;
  965.                 }
  966.         }
  967.     /*
  968.      * Point size - "^\.ps"
  969.      */
  970.         if (line[1] == 'p' && line[2] == 's')
  971.                 return;
  972.         if (line[1] == 'r') {
  973.                 switch (line[2]) {
  974.     /*
  975.      * Remove macro or string - "^\.rm"
  976.      */
  977.                 case 'm':
  978.                         if (Asmname(&line[3], nm) == 0)
  979.                                 goto no_name;
  980.                         if ((i = Findmacro(nm, 0)) >= 0) {
  981.                                 Delmacro(i);
  982.                                 return;
  983.                         }
  984.                         (void) Findstr(nm, NULL, 0);
  985.                         if (Sx < 0) {
  986.                                 Error(WARN, LINE, " no macro/string", NULL);
  987.                                 return;
  988.                         }
  989.                         Delstr(Sx);
  990.                         return;
  991.     /*
  992.      * Remove register - "^\.rr"
  993.      */
  994.                 case 'r':
  995.                         if (Asmname(&line[3], nm) == 0)
  996.                                 goto no_name;
  997.                         if ((i = Findnum(nm, 0, 0)) < 0) {
  998.                                 Error(WARN, LINE, " no register", NULL);
  999.                                 return;
  1000.                         }
  1001.                         Delnum(i);
  1002.                         return;
  1003.     /*
  1004.      * Resume space - "^\.rs"
  1005.      */
  1006.                 case 's':
  1007.                         Pass3(NOBREAK, "yesspace", NULL, 0);
  1008.                         return;
  1009.                 }
  1010.         }
  1011.         if (line[1] == 't') {
  1012.                 switch (line[2]) {
  1013.     /*
  1014.      * Message - "^\.tm"
  1015.      */
  1016.                 case 'm':
  1017.                         Pass3(MESSAGE, Inname,
  1018.                                 (line[3] == ' ') ? &line[4] : &line[3], NR);
  1019.                         return;
  1020.     /*
  1021.      * Translate - "^\.tr abcd..."
  1022.      */
  1023.                 case 'r':
  1024.                         if (line[3] != ' ') {
  1025.                                 Error(WARN, LINE, " unknown translation",
  1026.                                         NULL);
  1027.                                 return;
  1028.                         }
  1029.                         for (s1 = &line[4]; *s1; s1 += 2)
  1030.                                 Trtbl[(int)*s1] = (*(s1+1)) ? *(s1+1) : ' ';
  1031.                         return;
  1032.                 }
  1033.         }
  1034.     /*
  1035.      * Vertical spacing - "^\.vs" (do nothing)
  1036.      */
  1037.         if (line[1] == 'v' && line[2] == 's')
  1038.                 return;
  1039.         if (line[1] == '^') {
  1040.                 switch(line[2]) {
  1041.     /*
  1042.      * Initialization - "^\.\^b (fh|HF|NH) [01]"
  1043.      *
  1044.      * fh = first page header status
  1045.      * HF = header/footer status
  1046.      * NH = initialize number headers
  1047.      */
  1048.                 case 'b':
  1049.                         if ((s1 = Field(2, line, 0)) == NULL)
  1050.                                 return;
  1051.                         if ((s2 = Field(3, line, 0)) == NULL)
  1052.                                 i = 0;
  1053.                         else
  1054.                                 i = atoi(s2);
  1055.                         if (s1[0] == 'f' && s1[1] == 'h')
  1056.                                 Pass3(NOBREAK, "fph", NULL, i);
  1057.                         else if (s1[0] == 'H' && s1[1] == 'F')
  1058.                                 Hdft = i;
  1059.                         else if (s1[0] == 'N' && s1[1] == 'H') {
  1060.                                 for (i = 0; i < MAXNHNR; i++)
  1061.                                         Nhnr[i] = 0;
  1062.                         } else
  1063.                                 Error(WARN, LINE, " unknown initialization",
  1064.                                         NULL);
  1065.                         return;
  1066.     /*
  1067.      * Character definitions - "^\.\^c"
  1068.      */
  1069.                 case 'c':
  1070.  
  1071.                         s2 = Field(2, line, 0);
  1072.                         i = atoi(Field(3, line, 0));
  1073.                         s4 = Field(4, line, 0);
  1074.                         if (i < 0 || i > MAXLINE/2 || *s2 == '\0') {
  1075.                                 Error(WARN, LINE, " bad character definition",
  1076.                                         NULL);
  1077.                                 return;
  1078.                         }
  1079.                         if (s4 == NULL)
  1080.                                 s4 = "";
  1081.                         else if (*s4 == '"')
  1082.                                 s4++;
  1083.                         s1 = buf;
  1084.                         while ((s5 = strchr(s4, '\\')) != NULL) {
  1085.                                 while (s5 > s4)
  1086.                                         *s1++ = *s4++;
  1087.                                 s4 = ++s5;
  1088.                                 if (*s5 == '\\')
  1089.                                         *s1++ = '\\';
  1090.                                 else if (*s5 == 'b')
  1091.                                         *s1++ = '\b';
  1092.                                 if (*s4)
  1093.                                         s4++;
  1094.                         }
  1095.                         while (*s1++ = *s4++)
  1096.                                 ;
  1097.                         if (*s2 == 'h' && *(s2+1) == 'y')
  1098.                                 (void) Findhy(buf, i, 1);
  1099.                         else
  1100.                                 (void) Findchar(s2, i, buf, 1);
  1101.                         return;
  1102.     /*
  1103.      * Debug - "^\.\^d"
  1104.      */
  1105.                 case 'd':
  1106.                         return;
  1107.     /*
  1108.      * Finalization - "\.\^e"
  1109.      */
  1110.                 case 'e':
  1111.                         return;
  1112.     /*
  1113.      * Font is OK - "\.\^f <font_name_character>"
  1114.      */
  1115.                 case 'f':
  1116.                         if (line[3] != '\0' && line[4] != '\0') {
  1117.                                 for (i = 0; Fcode[i].nm; i++) {
  1118.                                         if (line[4] == Fcode[i].nm) {
  1119.                                                 Fcode[i].status = '1';
  1120.                                                 return;
  1121.                                         }
  1122.                                 }
  1123.                         }
  1124.                         Error(WARN, LINE, " unknown font", NULL);
  1125.                         return;
  1126.     /*
  1127.      * Resolutions - "\.\^r cpi horizontal vertical"
  1128.      */
  1129.                 case 'r':
  1130.                         if ((i = atoi(Field(3, line, 0))) <= 0
  1131.                         ||  (j = atoi(Field(4, line, 0))) <= 0) {
  1132.                                 Error(WARN, LINE, " bad cpi resolutions",
  1133.                                         NULL);
  1134.                                 return;
  1135.                         }
  1136.                         tval = (double) (240.0 / (double) i);
  1137.                         if (Findscale('m', tval, 1) < 0)
  1138.                                 Error(FATAL, LINE, " missing Scal['m']",
  1139.                                         NULL);
  1140.                         Scalen = tval;
  1141.                         if (Scalen <= 0.0) {
  1142.                                 (void) sprintf(buf, " bad Scale['n'] (%f)",
  1143.                                         Scalen);
  1144.                                 Error(FATAL, LINE, buf, NULL);
  1145.                         }
  1146.                         if (Findscale('n', tval, 1) < 0)
  1147.                                 Error(FATAL, LINE, " missing Scale['n']",
  1148.                                         NULL);
  1149.                         Scalev = (double) (240.0 / (double) j);
  1150.                         if (Scalev <= 0.0) {
  1151.                                 (void) sprintf(buf, " bad Scale['v'] (%f)",
  1152.                                         Scalen);
  1153.                                 Error(FATAL, LINE, buf, NULL);
  1154.                         }
  1155.                         if (Findscale('v', Scalev, 1) < 0)
  1156.                                 Error(FATAL, LINE, " missing Scale['v']",
  1157.                                         NULL);
  1158.                         return;
  1159.     /*
  1160.      * Error file - "^\.\^x <name>"
  1161.      */
  1162.                 case 'x':
  1163.                         return;
  1164.     /*
  1165.      * Set line number and file name - "^\.\^# <number> <file>"
  1166.      *
  1167.      * Lock line number and file name - "^\.\^= <number> <file>"
  1168.      */
  1169.                 case '#':
  1170.                 case '=':
  1171.                         if ((s1 = Field(2, line, 0)) != NULL)
  1172.                                 P2il = atoi(s1) - 1;
  1173.                         else
  1174.                                 P2il = 0;
  1175.                         Lockil = (line[2] == '#') ? 0 : 1;
  1176.                         Free(&P2name);
  1177.                         if (Field(3, line, 1) != NULL) {
  1178.                                 P2name = F;
  1179.                                 F = NULL;
  1180.                         } else
  1181.                                 P2name = NULL;
  1182.                         return;
  1183.                 }
  1184.         }
  1185.     /*
  1186.      * Comment - "^\.\\"
  1187.      */
  1188.         if (line[1] == '\\')
  1189.                 return;
  1190.     /*
  1191.      * Unknown command starting with a '.'.
  1192.      */
  1193.         Error(WARN, LINE, " unknown command", NULL);
  1194.         return;
  1195. }
  1196.  
  1197.  
  1198. /*
  1199.  * Str2word(s, len) - copy len characters from string to Word[]
  1200.  *
  1201.  * entry:
  1202.  *      s   = pointer to string
  1203.  *      len = number of characters to copy
  1204.  *
  1205.  * exit:
  1206.  *      return = 0 if characters copied
  1207.  *               1 if error detected (warning message issued)
  1208.  */
  1209.  
  1210. Str2word(s, len)
  1211.         char *s;
  1212.         int len;
  1213. {
  1214.         for (; len > 0; len--, s++) {
  1215.                 switch (Font[0]) {
  1216.                 case 'B':
  1217.                         if (Fontout == 'e') {
  1218.                                 if ((Wordx + 2) >= MAXLINE) {
  1219. word_too_long:
  1220.                                         Error(WARN, LINE, " word too long",
  1221.                                                 NULL);
  1222.                                         return(1);
  1223.                                 }
  1224.                                 Word[Wordx++] = ESC;
  1225.                                 Word[Wordx++] = 'B';
  1226.                         }
  1227.                         if ((Wordx + 1) >= MAXLINE)
  1228.                                 goto word_too_long;
  1229.                         Word[Wordx++] = Trtbl[(int)*s];
  1230.                         if (Fontout == 'b') {
  1231.                                 if ((Wordx + 4) >= MAXLINE)
  1232.                                         goto word_too_long;
  1233.                                 Word[Wordx++] = '\b';
  1234.                                 Word[Wordx++] = Trtbl[(int)*s];
  1235.                                 Word[Wordx++] = '\b';
  1236.                                 Word[Wordx++] = Trtbl[(int)*s];
  1237.                         }
  1238.                         break;
  1239.                 case 'I':
  1240.                         if (isalnum(*s)) {
  1241.                                 if (Fontout == 'e') {
  1242.                                         if ((Wordx + 2) >= MAXLINE)
  1243.                                                 goto word_too_long;
  1244.                                         Word[Wordx++] = ESC;
  1245.                                         Word[Wordx++] = 'I';
  1246.                                 } else if (Fontout == 'b') {
  1247.                                         if ((Wordx + 2) >= MAXLINE)
  1248.                                                 goto word_too_long;
  1249.                                         Word[Wordx++] = '_';
  1250.                                         Word[Wordx++] = '\b';
  1251.                                 }
  1252.                                 if ((Wordx + 1) >= MAXLINE)
  1253.                                         goto word_too_long;
  1254.                                 Word[Wordx++] = Trtbl[(int)*s];
  1255.                                 break;
  1256.                         }
  1257.                         /* else fall through */
  1258.                 default:
  1259.                         if ((Wordx + 1) >= MAXLINE)
  1260.                                 goto word_too_long;
  1261.                         Word[Wordx++] = Trtbl[(int)*s];
  1262.                 }
  1263.         }
  1264.         return(0);
  1265. }
  1266.