842 lines
20 KiB
C
842 lines
20 KiB
C
/*
|
|
* pass2.c - cawf(1) pass 2 function
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1991 Purdue University Research Foundation,
|
|
* West Lafayette, Indiana 47907. All rights reserved.
|
|
*
|
|
* Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
|
|
* University Computing Center. Not derived from licensed software;
|
|
* derived from awf(1) by Henry Spencer of the University of Toronto.
|
|
*
|
|
* Permission is granted to anyone to use this software for any
|
|
* purpose on any computer system, and to alter it and redistribute
|
|
* it freely, subject to the following restrictions:
|
|
*
|
|
* 1. The author is not responsible for any consequences of use of
|
|
* this software, even if they arise from flaws in it.
|
|
*
|
|
* 2. The origin of this software must not be misrepresented, either
|
|
* by explicit claim or by omission. Credits must appear in the
|
|
* documentation.
|
|
*
|
|
* 3. Altered versions must be plainly marked as such, and must not
|
|
* be misrepresented as being the original software. Credits must
|
|
* appear in the documentation.
|
|
*
|
|
* 4. This notice may not be removed or altered.
|
|
*/
|
|
|
|
#include "cawf.h"
|
|
#include <ctype.h>
|
|
|
|
/*
|
|
* Pass2(line) - process the nroff requests in a line and break
|
|
* text into words for pass 3
|
|
*/
|
|
|
|
void
|
|
Pass2(line)
|
|
unsigned char *line;
|
|
{
|
|
int brk; /* request break status */
|
|
unsigned char buf[MAXLINE]; /* working buffer */
|
|
unsigned char c; /* character buffer */
|
|
double d; /* temporary double */
|
|
double exscale; /* expression scaling factor */
|
|
double expr[MAXEXP]; /* expressions */
|
|
unsigned char exsign[MAXEXP]; /* expression signs */
|
|
int i, j; /* temporary indexes */
|
|
int inword; /* word processing status */
|
|
int nexpr; /* number of expressions */
|
|
unsigned char nm[4], nm1[4]; /* names */
|
|
int nsp; /* number of spaces */
|
|
unsigned char op; /* expression term operator */
|
|
unsigned char opstack[MAXSP]; /* expression operation stack */
|
|
unsigned char period; /* end of word status */
|
|
unsigned char *s1, *s2, *s3; /* temporary string pointers */
|
|
double sexpr[MAXEXP]; /* signed expressions */
|
|
int sp; /* expression stack pointer */
|
|
unsigned char ssign; /* expression's starting sign */
|
|
int tabpos; /* tab position */
|
|
double tscale; /* term scaling factor */
|
|
double tval; /* term value */
|
|
double val; /* term value */
|
|
double valstack[MAXSP]; /* expression value stack */
|
|
unsigned char xbuf[MAXLINE]; /* expansion buffer */
|
|
|
|
if (line == NULL) {
|
|
/*
|
|
* End of macro expansion.
|
|
*/
|
|
Pass3(DOBREAK, (unsigned char *)"need", NULL, 999);
|
|
return;
|
|
}
|
|
/*
|
|
* Adjust line number.
|
|
*/
|
|
if (Lockil == 0)
|
|
P2il++;
|
|
/*
|
|
* Empty line - "^[ \t]*$" or "^\\\"".
|
|
*/
|
|
if (regexec(Pat[6].pat, line)
|
|
|| strncmp((char *)line, "\\\"", 2) == 0) {
|
|
Pass3(DOBREAK, (unsigned char *)"space", NULL, 0);
|
|
return;
|
|
}
|
|
/*
|
|
* Line begins with white space.
|
|
*/
|
|
if (*line == ' ' || *line == '\t') {
|
|
Pass3(DOBREAK, (unsigned char *)"flush", NULL, 0);
|
|
Pass3(0, (unsigned char *)"", NULL, 0);
|
|
}
|
|
if (*line != '.' && *line != '\'') {
|
|
/*
|
|
* Line contains text (not an nroff request).
|
|
*/
|
|
if (Font[0] == 'R' && Backc == 0 && Aftnxt == NULL
|
|
&& regexec(Pat[7].pat, line) == 0) {
|
|
/*
|
|
* The font is Roman, there is no "\\c" or "after next"
|
|
* trap pending and and the line has no '\\', '\t', '-',
|
|
* or " " (regular expression "\\|\t|-| ").
|
|
*
|
|
* Output each word of the line as "<length> <word>".
|
|
*/
|
|
for (s1 = line;;) {
|
|
while (*s1 && *s1 == ' ')
|
|
s1++;
|
|
if (*s1 == '\0')
|
|
break;
|
|
for (s2 = s1, s3 = buf; *s2 && *s2 != ' ';)
|
|
*s3++ = Trtbl[(int)*s2++];
|
|
*s3 = '\0';
|
|
Pass3((s2 - s1), buf, NULL, 0);
|
|
s1 = *s2 ? ++s2 : s2;
|
|
}
|
|
/*
|
|
* Line terminates with punctuation and optional
|
|
* bracketing (regular expression "[.!?:][\])'\"*]*$").
|
|
*/
|
|
if (regexec(Pat[8].pat, line))
|
|
Pass3(NOBREAK, (unsigned char *)"gap", NULL, 2);
|
|
if (Centering > 0) {
|
|
Pass3(DOBREAK,(unsigned char *)"center", NULL,
|
|
0);
|
|
Centering--;
|
|
} else if (Fill == 0)
|
|
Pass3(DOBREAK, (unsigned char *)"flush", NULL,
|
|
0);
|
|
return;
|
|
}
|
|
/*
|
|
* Line must be scanned a character at a time.
|
|
*/
|
|
inword = nsp = tabpos = 0;
|
|
period = '\0';
|
|
for (s1 = line;; s1++) {
|
|
/*
|
|
* Space or TAB causes state transition.
|
|
*/
|
|
if (*s1 == '\0' || *s1 == ' ' || *s1 == '\t') {
|
|
if (inword) {
|
|
if (!Backc) {
|
|
Endword();
|
|
Pass3(Wordl, Word, NULL, 0);
|
|
if (Uhyph) {
|
|
Pass3(NOBREAK,
|
|
(unsigned char *)"nohyphen",
|
|
NULL, 0);
|
|
}
|
|
}
|
|
inword = 0;
|
|
nsp = 0;
|
|
}
|
|
if (*s1 == '\0')
|
|
break;
|
|
} else {
|
|
if (inword == 0) {
|
|
if (Backc == 0) {
|
|
Wordl = Wordx = 0;
|
|
Uhyph = 0;
|
|
}
|
|
Backc = 0;
|
|
inword = 1;
|
|
if (nsp > 1) {
|
|
Pass3(NOBREAK,
|
|
(unsigned char *)"gap",
|
|
NULL, nsp);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Process a character.
|
|
*/
|
|
switch (*s1) {
|
|
/*
|
|
* Space
|
|
*/
|
|
case ' ':
|
|
nsp++;
|
|
period = '\0';
|
|
break;
|
|
/*
|
|
* TAB
|
|
*/
|
|
case '\t':
|
|
tabpos++;
|
|
if (tabpos <= Ntabs) {
|
|
Pass3(NOBREAK,
|
|
(unsigned char *)"tabto", NULL,
|
|
Tabs[tabpos-1]);
|
|
}
|
|
nsp = 0;
|
|
period = '\0';
|
|
break;
|
|
/*
|
|
* Hyphen if word is being assembled
|
|
*/
|
|
case '-':
|
|
if (Wordl <= 0)
|
|
goto ordinary_char;
|
|
if ((i = Findhy(NULL, 0, 0)) < 0) {
|
|
Error(WARN, LINE, " no hyphen for font ",
|
|
(char *)Font);
|
|
return;
|
|
}
|
|
Endword();
|
|
Pass3(Wordl, Word, NULL, Hychar[i].len);
|
|
Pass3(NOBREAK, (unsigned char *)"userhyphen",
|
|
Hychar[i].str, Hychar[i].len);
|
|
Wordl = Wordx = 0;
|
|
period = '\0';
|
|
Uhyph = 1;
|
|
break;
|
|
/*
|
|
* Backslash
|
|
*/
|
|
case '\\':
|
|
s1++;
|
|
switch(*s1) {
|
|
/*
|
|
* Comment - "\\\""
|
|
*/
|
|
case '"':
|
|
while (*(s1+1))
|
|
s1++;
|
|
break;
|
|
/*
|
|
* Change font - "\\fN"
|
|
*/
|
|
case 'f':
|
|
s1 = Asmcode(&s1, nm);
|
|
if (nm[0] == 'P') {
|
|
Font[0] = Prevfont;
|
|
break;
|
|
}
|
|
for (i = 0; Fcode[i].nm; i++) {
|
|
if (Fcode[i].nm == nm[0])
|
|
break;
|
|
}
|
|
if (Fcode[i].nm == '\0'
|
|
|| nm[1] != '\0') {
|
|
Error(WARN, LINE, " unknown font ",
|
|
(char *)nm);
|
|
break;
|
|
}
|
|
if (Fcode[i].status != '1') {
|
|
Error(WARN, LINE,
|
|
" font undefined ", (char *)nm);
|
|
break;
|
|
} else {
|
|
Prevfont = Font[0];
|
|
Font[0] = nm[0];
|
|
}
|
|
break;
|
|
/*
|
|
* Positive horizontal motion - "\\h\\n(NN" or
|
|
* "\\h\\nN"
|
|
*/
|
|
case 'h':
|
|
if (s1[1] != '\\' || s1[2] != 'n') {
|
|
Error(WARN, LINE,
|
|
" no \\n after \\h", NULL);
|
|
break;
|
|
}
|
|
s1 +=2;
|
|
s1 = Asmcode(&s1, nm);
|
|
if ((i = Findnum(nm, 0, 0)) < 0)
|
|
goto unknown_num;
|
|
if ((j = Numb[i].val) < 0) {
|
|
Error(WARN, LINE, " \\h < 0 ",
|
|
NULL);
|
|
break;
|
|
}
|
|
if (j == 0)
|
|
break;
|
|
if ((strlen((char *)s1+1) + j + 1)
|
|
>= MAXLINE)
|
|
goto line_too_long;
|
|
for (s2 = &xbuf[1]; j; j--)
|
|
*s2++ = ' ';
|
|
(void) strcpy((char *)s2, (char *)s1+1);
|
|
s1 = xbuf;
|
|
break;
|
|
/*
|
|
* Save current position in register if "\\k<reg>"
|
|
*/
|
|
case 'k':
|
|
s1 = Asmcode(&s1, nm);
|
|
if ((i = Findnum(nm, 0, 0)) < 0)
|
|
i = Findnum(nm, 0, 1);
|
|
Numb[i].val =
|
|
(int)((double)Outll * Scalen);
|
|
break;
|
|
/*
|
|
* Interpolate number - "\\n(NN" or "\\nN"
|
|
*/
|
|
case 'n':
|
|
s1 = Asmcode(&s1, nm);
|
|
if ((i = Findnum(nm, 0, 0)) < 0) {
|
|
unknown_num:
|
|
Error(WARN, LINE,
|
|
" unknown number register ",
|
|
(char *)nm);
|
|
break;
|
|
}
|
|
(void) sprintf((char *)buf, "%d",
|
|
Numb[i].val);
|
|
if ((strlen((char *)buf)
|
|
+ strlen((char *)s1+1) + 1)
|
|
>= MAXLINE) {
|
|
line_too_long:
|
|
Error(WARN, LINE, " line too long",
|
|
NULL);
|
|
break;
|
|
}
|
|
(void) sprintf((char *)buf, "%d%s",
|
|
Numb[i].val, (char *)s1+1);
|
|
(void) strcpy((char *)&xbuf[1],
|
|
(char *)buf);
|
|
s1 = xbuf;
|
|
break;
|
|
/*
|
|
* Change size - "\\s[+-][0-9]" - NOP
|
|
*/
|
|
case 's':
|
|
s1++;
|
|
if (*s1 == '+' || *s1 == '-')
|
|
s1++;
|
|
while (*s1 && isdigit(*s1))
|
|
s1++;
|
|
s1--;
|
|
break;
|
|
/*
|
|
* Continue - "\\c"
|
|
*/
|
|
case 'c':
|
|
Backc = 1;
|
|
break;
|
|
/*
|
|
* Interpolate string - "\\*(NN" or "\\*N"
|
|
*/
|
|
case '*':
|
|
s1 = Asmcode(&s1, nm);
|
|
s2 = Findstr(nm, NULL, 0);
|
|
if (*s2 != '\0') {
|
|
if ((strlen((char *)s2)
|
|
+ strlen((char *)s1+1) + 1)
|
|
>= MAXLINE)
|
|
goto line_too_long;
|
|
(void) sprintf((char *)buf, "%s%s",
|
|
(char *)s2, (char *)s1+1);
|
|
(void) strcpy((char *)&xbuf[1],
|
|
(char *)buf);
|
|
s1 = xbuf;
|
|
}
|
|
break;
|
|
/*
|
|
* Discretionary hyphen - "\\%"
|
|
*/
|
|
case '%':
|
|
if (Wordl <= 0)
|
|
break;
|
|
if ((i = Findhy(NULL, 0, 0)) < 0) {
|
|
Error(WARN, LINE,
|
|
" no hyphen for font ",
|
|
(char *)Font);
|
|
break;
|
|
}
|
|
Endword();
|
|
Pass3(Wordl, Word, NULL, Hychar[i].len);
|
|
Pass3(NOBREAK,
|
|
(unsigned char *) "hyphen",
|
|
Hychar[i].str, Hychar[i].len);
|
|
Wordl = Wordx = 0;
|
|
Uhyph = 1;
|
|
break;
|
|
/*
|
|
* None of the above - may be special character
|
|
* name.
|
|
*/
|
|
default:
|
|
s2 = s1--;
|
|
s1 = Asmcode(&s1, nm);
|
|
if ((i = Findchar(nm, 0, NULL, 0)) < 0){
|
|
s1 = s2;
|
|
goto ordinary_char;
|
|
}
|
|
if (strcmp((char *)nm, "em") == 0
|
|
&& Wordx > 0) {
|
|
/*
|
|
* "\\(em" is a special case when a word
|
|
* has been assembled, because of
|
|
* hyphenation.
|
|
*/
|
|
Endword();
|
|
Pass3(Wordl, Word, NULL,
|
|
Schar[i].len);
|
|
Pass3(NOBREAK,
|
|
(unsigned char *)"userhyphen",
|
|
Schar[i].str, Schar[i].len);
|
|
Wordl = Wordx = 0;
|
|
period = '\0';
|
|
Uhyph = 1;
|
|
}
|
|
/*
|
|
* Interpolate a special character
|
|
*/
|
|
if (Str2word(Schar[i].str,
|
|
strlen((char *)Schar[i].str)) != 0)
|
|
return;
|
|
Wordl += Schar[i].len;
|
|
period = '\0';
|
|
}
|
|
break;
|
|
/*
|
|
* Ordinary character
|
|
*/
|
|
default:
|
|
ordinary_char:
|
|
if (Str2word(s1, 1) != 0)
|
|
return;
|
|
Wordl++;
|
|
if (*s1 == '.' || *s1 == '!'
|
|
|| *s1 == '?' || *s1 == ':')
|
|
period = '.';
|
|
else if (period == '.') {
|
|
nm[0] = *s1;
|
|
nm[1] = '\0';
|
|
if (regexec(Pat[13].pat, nm) == 0)
|
|
period = '\0';
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* End of line processing
|
|
*/
|
|
if (!Backc) {
|
|
if (period == '.')
|
|
Pass3(NOBREAK, (unsigned char *)"gap", NULL, 2);
|
|
if (Centering > 0) {
|
|
Pass3(DOBREAK, (unsigned char *)"center", NULL,
|
|
0);
|
|
Centering--;
|
|
} else if (!Fill)
|
|
Pass3(DOBREAK, (unsigned char *)"flush", NULL,
|
|
0);
|
|
}
|
|
if (Aftnxt == NULL)
|
|
return;
|
|
/* else fall through to process an "after next trap */
|
|
}
|
|
/*
|
|
* Special -man macro handling.
|
|
*/
|
|
if (Marg == MANMACROS) {
|
|
/*
|
|
* A text line - "^[^.]" - is only processed when there is an
|
|
* "after next" directive.
|
|
*/
|
|
if (*line != '.' && *line != '\'') {
|
|
if (Aftnxt != NULL) {
|
|
if (regexec(Pat[9].pat, Aftnxt)) /* ",fP" */
|
|
Font[0] = Prevfont;
|
|
if (regexec(Pat[16].pat, Aftnxt)) /* ",fR" */
|
|
Font[0] = 'R';
|
|
if (regexec(Pat[10].pat, Aftnxt)) /* ",tP" */
|
|
Pass3(DOBREAK,
|
|
(unsigned char *)"toindent",
|
|
NULL, 0);
|
|
Free(&Aftnxt);
|
|
}
|
|
return;
|
|
}
|
|
/*
|
|
* Special footer handling - "^.lF"
|
|
*/
|
|
if (line[1] == 'l' && line[2] == 'F') {
|
|
s1 = Findstr((unsigned char *)"by", NULL, 0);
|
|
s2 = Findstr((unsigned char *)"nb", NULL, 0);
|
|
if (*s1 == '\0' || *s2 == '\0')
|
|
(void) sprintf((char *)buf, "%s%s",
|
|
(char *)s1, (char *)s2);
|
|
else
|
|
(void) sprintf((char *)buf, "%s; %s",
|
|
(char *)s1, (char *)s2);
|
|
Pass3(NOBREAK, (unsigned char *)"LF", buf, 0);
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* Special -ms macro handling.
|
|
*/
|
|
if (Marg == MSMACROS) {
|
|
/*
|
|
* A text line - "^[^.]" - is only processed when there is an
|
|
* "after next" directive.
|
|
*/
|
|
if (*line != '.' && *line != '\'') {
|
|
if (Aftnxt != NULL) {
|
|
if (regexec(Pat[10].pat, Aftnxt)) /* ",tP" */
|
|
Pass3(DOBREAK,
|
|
(unsigned char *)"toindent",
|
|
NULL, 0);
|
|
Free(&Aftnxt);
|
|
}
|
|
return;
|
|
}
|
|
/*
|
|
* Numbered headings - "^[.']nH"
|
|
*/
|
|
if (line[1] == 'n' && line[2] == 'H') {
|
|
s1 = Field(2, line, 0);
|
|
if (s1 != NULL) {
|
|
i = atoi((char *)s1) - 1;
|
|
if (i < 0) {
|
|
for (j = 0; j < MAXNHNR; j++) {
|
|
Nhnr[j] = 0;
|
|
}
|
|
i = 0;
|
|
} else if (i >= MAXNHNR) {
|
|
(void) sprintf((char *)buf,
|
|
" over NH limit (%d)", MAXNHNR);
|
|
Error(WARN, LINE, (char *)buf, NULL);
|
|
}
|
|
} else
|
|
i = 0;
|
|
Nhnr[i]++;
|
|
for (j = i + 1; j < MAXNHNR; j++) {
|
|
Nhnr[j] = 0;
|
|
}
|
|
s1 = buf;
|
|
for (j = 0; j <= i; j++) {
|
|
(void) sprintf((char *)s1, "%d.", Nhnr[j]);
|
|
s1 = buf + strlen((char *)buf);
|
|
}
|
|
(void) Findstr((unsigned char *)"Nh", buf, 1);
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* Remaining lines should begin with a '.' or '\'' unless an "after next"
|
|
* trap has failed.
|
|
*/
|
|
if (*line != '.' && *line != '\'') {
|
|
if (Aftnxt != NULL)
|
|
Error(WARN, LINE, " failed .it: ", (char *)Aftnxt);
|
|
else
|
|
Error(WARN, LINE, " unrecognized line ", NULL);
|
|
return;
|
|
}
|
|
brk = (*line == '.') ? DOBREAK : NOBREAK;
|
|
/*
|
|
* Evaluate expressions for "^[.'](ta|ll|ls|in|ti|po|ne|sp|pl|nr)"
|
|
* Then process the requests.
|
|
*/
|
|
if (regexec(Pat[11].pat, &line[1])) {
|
|
/*
|
|
* Establish default scale factor.
|
|
*/
|
|
if ((line[1] == 'n' && line[2] == 'e')
|
|
|| (line[1] == 's' && line[2] == 'p')
|
|
|| (line[1] == 'p' && line[2] == 'l'))
|
|
exscale = Scalev;
|
|
else if (line[1] == 'n' && line[2] == 'r')
|
|
exscale = Scaleu;
|
|
else
|
|
exscale = Scalen;
|
|
/*
|
|
* Determine starting argument.
|
|
*/
|
|
if (line[1] == 'n' && line[2] == 'r')
|
|
s1 = Field(2, &line[3], 0);
|
|
else
|
|
s1 = Field(1, &line[3], 0);
|
|
/*
|
|
* Evaluate expressions.
|
|
*/
|
|
for (nexpr = 0; s1 != NULL &&*s1 != '\0'; ) {
|
|
while (*s1 == ' ' || *s1 == '\t')
|
|
s1++;
|
|
if (*s1 == '+' || *s1 == '-')
|
|
ssign = *s1++;
|
|
else
|
|
ssign = '\0';
|
|
/*
|
|
* Process terms.
|
|
*/
|
|
val = 0.0;
|
|
sp = -1;
|
|
c = '+';
|
|
s1--;
|
|
while (c == '+' || c == '*' || c == '%'
|
|
|| c == ')' || c == '-' || c == '/') {
|
|
op = c;
|
|
s1++;
|
|
tscale = exscale;
|
|
tval = 0.0;
|
|
/*
|
|
* Pop stack on right parenthesis.
|
|
*/
|
|
if (op == ')') {
|
|
tval = val;
|
|
if (sp >= 0) {
|
|
val = valstack[sp];
|
|
op = opstack[sp];
|
|
sp--;
|
|
} else {
|
|
Error(WARN, LINE,
|
|
" expression stack underflow", NULL);
|
|
return;
|
|
}
|
|
tscale = Scaleu;
|
|
/*
|
|
* Push stack on left parenthesis.
|
|
*/
|
|
} else if (*s1 == '(') {
|
|
sp++;
|
|
if (sp >= MAXSP) {
|
|
Error(WARN, LINE,
|
|
" expression stack overflow", NULL);
|
|
return;
|
|
}
|
|
valstack[sp] = val;
|
|
opstack[sp] = op;
|
|
val = 0.0;
|
|
c = '+';
|
|
continue;
|
|
} else if (*s1 == '\\') {
|
|
s1++;
|
|
switch(*s1) {
|
|
/*
|
|
* "\\"" begins a comment.
|
|
*/
|
|
case '"':
|
|
while (*s1)
|
|
s1++;
|
|
break;
|
|
/*
|
|
* Crude width calculation for "\\w"
|
|
*/
|
|
case 'w':
|
|
s2 = ++s1;
|
|
if (*s1) {
|
|
s1++;
|
|
while (*s1 && *s1 != *s2)
|
|
s1++;
|
|
tval = (double) (s1 - s2 - 1) * Scalen;
|
|
if (*s1)
|
|
s1++;
|
|
}
|
|
break;
|
|
/*
|
|
* Interpolate number register if "\\n".
|
|
*/
|
|
case 'n':
|
|
s1 = Asmcode(&s1, nm);
|
|
if ((i = Findnum(nm, 0, 0)) >= 0)
|
|
tval = Numb[i].val;
|
|
s1++;
|
|
}
|
|
/*
|
|
* Assemble numeric value.
|
|
*/
|
|
} else if (*s1 == '.' || isdigit(*s1)) {
|
|
for (i = 0; isdigit(*s1) || *s1 == '.'; s1++) {
|
|
if (*s1 == '.') {
|
|
i = 10;
|
|
continue;
|
|
}
|
|
d = (double) (*s1 - '0');
|
|
if (i) {
|
|
tval = tval + (d / (double) i);
|
|
i = i * 10;
|
|
} else
|
|
tval = (tval * 10.0) + d;
|
|
}
|
|
} else {
|
|
/*
|
|
* It's not an expression. Ignore extra scale.
|
|
*/
|
|
if ((i = Findscale((int)*s1, 0.0, 0)) < 0) {
|
|
(void) sprintf((char *)buf,
|
|
" \"%s\" isn't an expression",
|
|
(char *)s1);
|
|
Error(WARN, LINE, (char *)buf, NULL);
|
|
}
|
|
s1++;
|
|
}
|
|
/*
|
|
* Add term to expression value.
|
|
*/
|
|
if ((i = Findscale((int)*s1, 0.0, 0)) >= 0) {
|
|
tval *= Scale[i].val;
|
|
s1++;
|
|
} else
|
|
tval *= tscale;
|
|
switch (op) {
|
|
case '+':
|
|
val += tval;
|
|
break;
|
|
case '-':
|
|
val -= tval;
|
|
break;
|
|
case '*':
|
|
val *= tval;
|
|
break;
|
|
case '/':
|
|
case '%':
|
|
i = (int) val;
|
|
j = (int) tval;
|
|
if (j == 0) {
|
|
Error(WARN, LINE,
|
|
(*s1 == '/') ? "div" : "mod",
|
|
" by 0");
|
|
return;
|
|
}
|
|
if (op == '/')
|
|
val = (double) (i / j);
|
|
else
|
|
val = (double) (i % j);
|
|
break;
|
|
}
|
|
c = *s1;
|
|
}
|
|
/*
|
|
* Save expression value and sign.
|
|
*/
|
|
if (nexpr >= MAXEXP) {
|
|
(void) sprintf((char *)buf,
|
|
" at expression limit of %d", MAXEXP);
|
|
Error(WARN, LINE, (char *)buf, NULL);
|
|
return;
|
|
}
|
|
exsign[nexpr] = ssign;
|
|
expr[nexpr] = val;
|
|
if (ssign == '-')
|
|
sexpr[nexpr] = -1.0 * val;
|
|
else
|
|
sexpr[nexpr] = val;
|
|
nexpr++;
|
|
while (*s1 == ' ' || *s1 == '\t')
|
|
s1++;
|
|
}
|
|
/*
|
|
* Set parameters "(ll|ls|in|ti|po|pl)"
|
|
*/
|
|
if (regexec(Pat[12].pat, &line[1])) {
|
|
nm[0] = line[1];
|
|
nm[1] = line[2];
|
|
if ((i = Findparms(nm)) < 0) {
|
|
Error(WARN, LINE,
|
|
" can't find parameter register ",
|
|
(char *)nm);
|
|
return;
|
|
}
|
|
if (nexpr == 0 || exscale == 0.0)
|
|
j = Parms[i].prev;
|
|
else if (exsign[0] == '\0'
|
|
|| (nm[0] == 't' && nm[1] == 'i'))
|
|
j = (int)(sexpr[0] / exscale);
|
|
else
|
|
j = Parms[i].val + (int)(sexpr[0] / exscale);
|
|
Parms[i].prev = Parms[i].val;
|
|
Parms[i].val = j;
|
|
nm[0] = (nexpr) ? exsign[0] : '\0'; /* for .ti */
|
|
nm[1] = '\0';
|
|
Pass3(brk, (unsigned char *)Parms[i].cmd, nm, j);
|
|
return;
|
|
}
|
|
if (line[1] == 'n') {
|
|
switch(line[2]) {
|
|
/*
|
|
* Need - "^[.']ne <expression>"
|
|
*/
|
|
case 'e':
|
|
if (nexpr && Scalev > 0.0)
|
|
i = (int) ((expr[0]/Scalev) + 0.99);
|
|
else
|
|
i = 0;
|
|
Pass3(DOBREAK, (unsigned char *)"need", NULL,
|
|
i);
|
|
return;
|
|
/*
|
|
* Number - "^[.']nr <name> <expression>"
|
|
*/
|
|
case 'r':
|
|
if ((s1 = Field(2, line, 0)) == NULL) {
|
|
Error(WARN, LINE, " bad number register",
|
|
NULL);
|
|
return;
|
|
}
|
|
if ((i = Findnum(s1, 0, 0)) < 0)
|
|
i = Findnum(s1, 0, 1);
|
|
if (nexpr < 1) {
|
|
Numb[i].val = 0;
|
|
return;
|
|
}
|
|
if (exsign[0] == '\0')
|
|
Numb[i].val = (int) expr[0];
|
|
else
|
|
Numb[i].val += (int) sexpr[0];
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* Space - "^[.']sp <expression>"
|
|
*/
|
|
if (line[1] == 's' && line[2] == 'p') {
|
|
if (nexpr == 0)
|
|
i = 1;
|
|
else
|
|
i = (int)((expr[0] / Scalev) + 0.99);
|
|
while (i--)
|
|
Pass3(brk, (unsigned char *)"space", NULL, 0);
|
|
return;
|
|
}
|
|
/*
|
|
* Tab positions - "^[.']ta <pos1> <pos2> . . ."
|
|
*/
|
|
if (line[1] == 't' && line[2] == 'a') {
|
|
tval = 0.0;
|
|
for (j = 0; j < nexpr; j++) {
|
|
if (exsign[j] == '\0')
|
|
tval = expr[j];
|
|
else
|
|
tval += sexpr[j];
|
|
Tabs[j] = (int) (tval / Scalen);
|
|
}
|
|
Ntabs = nexpr;
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* Process all other nroff requests via Nreq().
|
|
*/
|
|
(void) Nreq(line, brk);
|
|
return;
|
|
}
|