Remove building with NOCRYPTO option
[minix3.git] / minix / commands / cawf / pass2.c
blobb5bedc56c4ce4bbdb5c7553ac294eb1db9279686
1 /*
2 * pass2.c - cawf(1) pass 2 function
3 */
5 /*
6 * Copyright (c) 1991 Purdue University Research Foundation,
7 * West Lafayette, Indiana 47907. All rights reserved.
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.
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:
17 * 1. The author is not responsible for any consequences of use of
18 * this software, even if they arise from flaws in it.
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.
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.
28 * 4. This notice may not be removed or altered.
31 #include "cawf.h"
32 #include <ctype.h>
35 * Pass2(line) - process the nroff requests in a line and break
36 * text into words for pass 3
39 void Pass2(unsigned char *line) {
40 int brk; /* request break status */
41 unsigned char buf[MAXLINE]; /* working buffer */
42 unsigned char c; /* character buffer */
43 double d; /* temporary double */
44 double exscale; /* expression scaling factor */
45 double expr[MAXEXP]; /* expressions */
46 unsigned char exsign[MAXEXP]; /* expression signs */
47 int i, j; /* temporary indexes */
48 int inword; /* word processing status */
49 int nexpr; /* number of expressions */
50 unsigned char nm[4], nm1[4]; /* names */
51 int nsp; /* number of spaces */
52 unsigned char op; /* expression term operator */
53 unsigned char opstack[MAXSP]; /* expression operation stack */
54 unsigned char period; /* end of word status */
55 unsigned char *s1, *s2, *s3; /* temporary string pointers */
56 double sexpr[MAXEXP]; /* signed expressions */
57 int sp; /* expression stack pointer */
58 unsigned char ssign; /* expression's starting sign */
59 int tabpos; /* tab position */
60 double tscale; /* term scaling factor */
61 double tval; /* term value */
62 double val; /* term value */
63 double valstack[MAXSP]; /* expression value stack */
64 unsigned char xbuf[MAXLINE]; /* expansion buffer */
66 if (line == NULL) {
68 * End of macro expansion.
70 Pass3(DOBREAK, (unsigned char *)"need", NULL, 999);
71 return;
74 * Adjust line number.
76 if (Lockil == 0)
77 P2il++;
79 * Empty line - "^[ \t]*$" or "^\\\"".
81 if (regexec(Pat[6].pat, line)
82 || strncmp((char *)line, "\\\"", 2) == 0) {
83 Pass3(DOBREAK, (unsigned char *)"space", NULL, 0);
84 return;
87 * Line begins with white space.
89 if (*line == ' ' || *line == '\t') {
90 Pass3(DOBREAK, (unsigned char *)"flush", NULL, 0);
91 Pass3(0, (unsigned char *)"", NULL, 0);
93 if (*line != '.' && *line != '\'') {
95 * Line contains text (not an nroff request).
97 if (Font[0] == 'R' && Backc == 0 && Aftnxt == NULL
98 && regexec(Pat[7].pat, line) == 0) {
100 * The font is Roman, there is no "\\c" or "after next"
101 * trap pending and and the line has no '\\', '\t', '-',
102 * or " " (regular expression "\\|\t|-| ").
104 * Output each word of the line as "<length> <word>".
106 for (s1 = line;;) {
107 while (*s1 == ' ')
108 s1++;
109 if (*s1 == '\0')
110 break;
111 for (s2 = s1, s3 = buf; *s2 && *s2 != ' ';)
112 *s3++ = Trtbl[(int)*s2++];
113 *s3 = '\0';
114 Pass3((s2 - s1), buf, NULL, 0);
115 s1 = *s2 ? ++s2 : s2;
118 * Line terminates with punctuation and optional
119 * bracketing (regular expression "[.!?:][\])'\"*]*$").
121 if (regexec(Pat[8].pat, line))
122 Pass3(NOBREAK, (unsigned char *)"gap", NULL, 2);
123 if (Centering > 0) {
124 Pass3(DOBREAK,(unsigned char *)"center", NULL,
126 Centering--;
127 } else if (Fill == 0)
128 Pass3(DOBREAK, (unsigned char *)"flush", NULL,
130 return;
133 * Line must be scanned a character at a time.
135 inword = nsp = tabpos = 0;
136 period = '\0';
137 for (s1 = line;; s1++) {
139 * Space or TAB causes state transition.
141 if (*s1 == '\0' || *s1 == ' ' || *s1 == '\t') {
142 if (inword) {
143 if (!Backc) {
144 Endword();
145 Pass3(Wordl, Word, NULL, 0);
146 if (Uhyph) {
147 Pass3(NOBREAK,
148 (unsigned char *)"nohyphen",
149 NULL, 0);
152 inword = 0;
153 nsp = 0;
155 if (*s1 == '\0')
156 break;
157 } else {
158 if (inword == 0) {
159 if (Backc == 0) {
160 Wordl = Wordx = 0;
161 Uhyph = 0;
163 Backc = 0;
164 inword = 1;
165 if (nsp > 1) {
166 Pass3(NOBREAK,
167 (unsigned char *)"gap",
168 NULL, nsp);
173 * Process a character.
175 switch (*s1) {
177 * Space
179 case ' ':
180 nsp++;
181 period = '\0';
182 break;
184 * TAB
186 case '\t':
187 tabpos++;
188 if (tabpos <= Ntabs) {
189 Pass3(NOBREAK,
190 (unsigned char *)"tabto", NULL,
191 Tabs[tabpos-1]);
193 nsp = 0;
194 period = '\0';
195 break;
197 * Hyphen if word is being assembled
199 case '-':
200 if (Wordl <= 0)
201 goto ordinary_char;
202 if ((i = Findhy(NULL, 0, 0)) < 0) {
203 Error(WARN, LINE, " no hyphen for font ",
204 (char *)Font);
205 return;
207 Endword();
208 Pass3(Wordl, Word, NULL, Hychar[i].len);
209 Pass3(NOBREAK, (unsigned char *)"userhyphen",
210 Hychar[i].str, Hychar[i].len);
211 Wordl = Wordx = 0;
212 period = '\0';
213 Uhyph = 1;
214 break;
216 * Backslash
218 case '\\':
219 s1++;
220 switch(*s1) {
222 * Comment - "\\\""
224 case '"':
225 while (*(s1+1))
226 s1++;
227 break;
229 * Change font - "\\fN"
231 case 'f':
232 s1 = Asmcode(&s1, nm);
233 if (nm[0] == 'P') {
234 Font[0] = Prevfont;
235 break;
237 for (i = 0; Fcode[i].nm; i++) {
238 if (Fcode[i].nm == nm[0])
239 break;
241 if (Fcode[i].nm == '\0'
242 || nm[1] != '\0') {
243 Error(WARN, LINE, " unknown font ",
244 (char *)nm);
245 break;
247 if (Fcode[i].status != '1') {
248 Error(WARN, LINE,
249 " font undefined ", (char *)nm);
250 break;
251 } else {
252 Prevfont = Font[0];
253 Font[0] = nm[0];
255 break;
257 * Positive horizontal motion - "\\h\\n(NN" or
258 * "\\h\\nN"
260 case 'h':
261 if (s1[1] != '\\' || s1[2] != 'n') {
262 Error(WARN, LINE,
263 " no \\n after \\h", NULL);
264 break;
266 s1 +=2;
267 s1 = Asmcode(&s1, nm);
268 if ((i = Findnum(nm, 0, 0)) < 0)
269 goto unknown_num;
270 if ((j = Numb[i].val) < 0) {
271 Error(WARN, LINE, " \\h < 0 ",
272 NULL);
273 break;
275 if (j == 0)
276 break;
277 if ((strlen((char *)s1+1) + j + 1)
278 >= MAXLINE)
279 goto line_too_long;
280 for (s2 = &xbuf[1]; j; j--)
281 *s2++ = ' ';
282 (void) strcpy((char *)s2, (char *)s1+1);
283 s1 = xbuf;
284 break;
286 * Save current position in register if "\\k<reg>"
288 case 'k':
289 s1 = Asmcode(&s1, nm);
290 if ((i = Findnum(nm, 0, 0)) < 0)
291 i = Findnum(nm, 0, 1);
292 Numb[i].val =
293 (int)((double)Outll * Scalen);
294 break;
296 * Interpolate number - "\\n(NN" or "\\nN"
298 case 'n':
299 s1 = Asmcode(&s1, nm);
300 if ((i = Findnum(nm, 0, 0)) < 0) {
301 unknown_num:
302 Error(WARN, LINE,
303 " unknown number register ",
304 (char *)nm);
305 break;
307 (void) sprintf((char *)buf, "%d",
308 Numb[i].val);
309 if ((strlen((char *)buf)
310 + strlen((char *)s1+1) + 1)
311 >= MAXLINE) {
312 line_too_long:
313 Error(WARN, LINE, " line too long",
314 NULL);
315 break;
317 (void) sprintf((char *)buf, "%d%s",
318 Numb[i].val, (char *)s1+1);
319 (void) strcpy((char *)&xbuf[1],
320 (char *)buf);
321 s1 = xbuf;
322 break;
324 * Change size - "\\s[+-][0-9]" - NOP
326 case 's':
327 s1++;
328 if (*s1 == '+' || *s1 == '-')
329 s1++;
330 while (*s1 && isdigit(*s1))
331 s1++;
332 s1--;
333 break;
335 * Continue - "\\c"
337 case 'c':
338 Backc = 1;
339 break;
341 * Interpolate string - "\\*(NN" or "\\*N"
343 case '*':
344 s1 = Asmcode(&s1, nm);
345 s2 = Findstr(nm, NULL, 0);
346 if (*s2 != '\0') {
347 if ((strlen((char *)s2)
348 + strlen((char *)s1+1) + 1)
349 >= MAXLINE)
350 goto line_too_long;
351 (void) sprintf((char *)buf, "%s%s",
352 (char *)s2, (char *)s1+1);
353 (void) strcpy((char *)&xbuf[1],
354 (char *)buf);
355 s1 = xbuf;
357 break;
359 * Discretionary hyphen - "\\%"
361 case '%':
362 if (Wordl <= 0)
363 break;
364 if ((i = Findhy(NULL, 0, 0)) < 0) {
365 Error(WARN, LINE,
366 " no hyphen for font ",
367 (char *)Font);
368 break;
370 Endword();
371 Pass3(Wordl, Word, NULL, Hychar[i].len);
372 Pass3(NOBREAK,
373 (unsigned char *) "hyphen",
374 Hychar[i].str, Hychar[i].len);
375 Wordl = Wordx = 0;
376 Uhyph = 1;
377 break;
379 * None of the above - may be special character
380 * name.
382 default:
383 s2 = s1--;
384 s1 = Asmcode(&s1, nm);
385 if ((i = Findchar(nm, 0, NULL, 0)) < 0){
386 s1 = s2;
387 goto ordinary_char;
389 if (strcmp((char *)nm, "em") == 0
390 && Wordx > 0) {
392 * "\\(em" is a special case when a word
393 * has been assembled, because of
394 * hyphenation.
396 Endword();
397 Pass3(Wordl, Word, NULL,
398 Schar[i].len);
399 Pass3(NOBREAK,
400 (unsigned char *)"userhyphen",
401 Schar[i].str, Schar[i].len);
402 Wordl = Wordx = 0;
403 period = '\0';
404 Uhyph = 1;
407 * Interpolate a special character
409 if (Str2word(Schar[i].str,
410 strlen((char *)Schar[i].str)) != 0)
411 return;
412 Wordl += Schar[i].len;
413 period = '\0';
415 break;
417 * Ordinary character
419 default:
420 ordinary_char:
421 if (Str2word(s1, 1) != 0)
422 return;
423 Wordl++;
424 if (*s1 == '.' || *s1 == '!'
425 || *s1 == '?' || *s1 == ':')
426 period = '.';
427 else if (period == '.') {
428 nm[0] = *s1;
429 nm[1] = '\0';
430 if (regexec(Pat[13].pat, nm) == 0)
431 period = '\0';
436 * End of line processing
438 if (!Backc) {
439 if (period == '.')
440 Pass3(NOBREAK, (unsigned char *)"gap", NULL, 2);
441 if (Centering > 0) {
442 Pass3(DOBREAK, (unsigned char *)"center", NULL,
444 Centering--;
445 } else if (!Fill)
446 Pass3(DOBREAK, (unsigned char *)"flush", NULL,
449 if (Aftnxt == NULL)
450 return;
451 /* else fall through to process an "after next trap */
454 * Special -man macro handling.
456 if (Marg == MANMACROS) {
458 * A text line - "^[^.]" - is only processed when there is an
459 * "after next" directive.
461 if (*line != '.' && *line != '\'') {
462 if (Aftnxt != NULL) {
463 if (regexec(Pat[9].pat, Aftnxt)) /* ",fP" */
464 Font[0] = Prevfont;
465 if (regexec(Pat[16].pat, Aftnxt)) /* ",fR" */
466 Font[0] = 'R';
467 if (regexec(Pat[10].pat, Aftnxt)) /* ",tP" */
468 Pass3(DOBREAK,
469 (unsigned char *)"toindent",
470 NULL, 0);
471 Free(&Aftnxt);
473 return;
476 * Special footer handling - "^.lF"
478 if (line[1] == 'l' && line[2] == 'F') {
479 s1 = Findstr((unsigned char *)"by", NULL, 0);
480 s2 = Findstr((unsigned char *)"nb", NULL, 0);
481 if (*s1 == '\0' || *s2 == '\0')
482 (void) sprintf((char *)buf, "%s%s",
483 (char *)s1, (char *)s2);
484 else
485 (void) sprintf((char *)buf, "%s; %s",
486 (char *)s1, (char *)s2);
487 Pass3(NOBREAK, (unsigned char *)"LF", buf, 0);
488 return;
492 * Special -ms macro handling.
494 if (Marg == MSMACROS) {
496 * A text line - "^[^.]" - is only processed when there is an
497 * "after next" directive.
499 if (*line != '.' && *line != '\'') {
500 if (Aftnxt != NULL) {
501 if (regexec(Pat[10].pat, Aftnxt)) /* ",tP" */
502 Pass3(DOBREAK,
503 (unsigned char *)"toindent",
504 NULL, 0);
505 Free(&Aftnxt);
507 return;
510 * Numbered headings - "^[.']nH"
512 if (line[1] == 'n' && line[2] == 'H') {
513 s1 = Field(2, line, 0);
514 if (s1 != NULL) {
515 i = atoi((char *)s1) - 1;
516 if (i < 0) {
517 for (j = 0; j < MAXNHNR; j++) {
518 Nhnr[j] = 0;
520 i = 0;
521 } else if (i >= MAXNHNR) {
522 (void) sprintf((char *)buf,
523 " over NH limit (%d)", MAXNHNR);
524 Error(WARN, LINE, (char *)buf, NULL);
526 } else
527 i = 0;
528 Nhnr[i]++;
529 for (j = i + 1; j < MAXNHNR; j++) {
530 Nhnr[j] = 0;
532 s1 = buf;
533 for (j = 0; j <= i; j++) {
534 (void) sprintf((char *)s1, "%d.", Nhnr[j]);
535 s1 = buf + strlen((char *)buf);
537 (void) Findstr((unsigned char *)"Nh", buf, 1);
538 return;
542 * Remaining lines should begin with a '.' or '\'' unless an "after next"
543 * trap has failed.
545 if (*line != '.' && *line != '\'') {
546 if (Aftnxt != NULL)
547 Error(WARN, LINE, " failed .it: ", (char *)Aftnxt);
548 else
549 Error(WARN, LINE, " unrecognized line ", NULL);
550 return;
552 brk = (*line == '.') ? DOBREAK : NOBREAK;
554 * Evaluate expressions for "^[.'](ta|ll|ls|in|ti|po|ne|sp|pl|nr)"
555 * Then process the requests.
557 if (regexec(Pat[11].pat, &line[1])) {
559 * Establish default scale factor.
561 if ((line[1] == 'n' && line[2] == 'e')
562 || (line[1] == 's' && line[2] == 'p')
563 || (line[1] == 'p' && line[2] == 'l'))
564 exscale = Scalev;
565 else if (line[1] == 'n' && line[2] == 'r')
566 exscale = Scaleu;
567 else
568 exscale = Scalen;
570 * Determine starting argument.
572 if (line[1] == 'n' && line[2] == 'r')
573 s1 = Field(2, &line[3], 0);
574 else
575 s1 = Field(1, &line[3], 0);
577 * Evaluate expressions.
579 for (nexpr = 0; s1 != NULL &&*s1 != '\0'; ) {
580 while (*s1 == ' ' || *s1 == '\t')
581 s1++;
582 if (*s1 == '+' || *s1 == '-')
583 ssign = *s1++;
584 else
585 ssign = '\0';
587 * Process terms.
589 val = 0.0;
590 sp = -1;
591 c = '+';
592 s1--;
593 while (c == '+' || c == '*' || c == '%'
594 || c == ')' || c == '-' || c == '/') {
595 op = c;
596 s1++;
597 tscale = exscale;
598 tval = 0.0;
600 * Pop stack on right parenthesis.
602 if (op == ')') {
603 tval = val;
604 if (sp >= 0) {
605 val = valstack[sp];
606 op = opstack[sp];
607 sp--;
608 } else {
609 Error(WARN, LINE,
610 " expression stack underflow", NULL);
611 return;
613 tscale = Scaleu;
615 * Push stack on left parenthesis.
617 } else if (*s1 == '(') {
618 sp++;
619 if (sp >= MAXSP) {
620 Error(WARN, LINE,
621 " expression stack overflow", NULL);
622 return;
624 valstack[sp] = val;
625 opstack[sp] = op;
626 val = 0.0;
627 c = '+';
628 continue;
629 } else if (*s1 == '\\') {
630 s1++;
631 switch(*s1) {
633 * "\\"" begins a comment.
635 case '"':
636 while (*s1)
637 s1++;
638 break;
640 * Crude width calculation for "\\w"
642 case 'w':
643 s2 = ++s1;
644 if (*s1) {
645 s1++;
646 while (*s1 && *s1 != *s2)
647 s1++;
648 tval = (double) (s1 - s2 - 1) * Scalen;
649 if (*s1)
650 s1++;
652 break;
654 * Interpolate number register if "\\n".
656 case 'n':
657 s1 = Asmcode(&s1, nm);
658 if ((i = Findnum(nm, 0, 0)) >= 0)
659 tval = Numb[i].val;
660 s1++;
663 * Assemble numeric value.
665 } else if (*s1 == '.' || isdigit(*s1)) {
666 for (i = 0; isdigit(*s1) || *s1 == '.'; s1++) {
667 if (*s1 == '.') {
668 i = 10;
669 continue;
671 d = (double) (*s1 - '0');
672 if (i) {
673 tval = tval + (d / (double) i);
674 i = i * 10;
675 } else
676 tval = (tval * 10.0) + d;
678 } else {
680 * It's not an expression. Ignore extra scale.
682 if ((i = Findscale((int)*s1, 0.0, 0)) < 0) {
683 (void) sprintf((char *)buf,
684 " \"%s\" isn't an expression",
685 (char *)s1);
686 Error(WARN, LINE, (char *)buf, NULL);
688 s1++;
691 * Add term to expression value.
693 if ((i = Findscale((int)*s1, 0.0, 0)) >= 0) {
694 tval *= Scale[i].val;
695 s1++;
696 } else
697 tval *= tscale;
698 switch (op) {
699 case '+':
700 val += tval;
701 break;
702 case '-':
703 val -= tval;
704 break;
705 case '*':
706 val *= tval;
707 break;
708 case '/':
709 case '%':
710 i = (int) val;
711 j = (int) tval;
712 if (j == 0) {
713 Error(WARN, LINE,
714 (*s1 == '/') ? "div" : "mod",
715 " by 0");
716 return;
718 if (op == '/')
719 val = (double) (i / j);
720 else
721 val = (double) (i % j);
722 break;
724 c = *s1;
727 * Save expression value and sign.
729 if (nexpr >= MAXEXP) {
730 (void) sprintf((char *)buf,
731 " at expression limit of %d", MAXEXP);
732 Error(WARN, LINE, (char *)buf, NULL);
733 return;
735 exsign[nexpr] = ssign;
736 expr[nexpr] = val;
737 if (ssign == '-')
738 sexpr[nexpr] = -1.0 * val;
739 else
740 sexpr[nexpr] = val;
741 nexpr++;
742 while (*s1 == ' ' || *s1 == '\t')
743 s1++;
746 * Set parameters "(ll|ls|in|ti|po|pl)"
748 if (regexec(Pat[12].pat, &line[1])) {
749 nm[0] = line[1];
750 nm[1] = line[2];
751 if ((i = Findparms(nm)) < 0) {
752 Error(WARN, LINE,
753 " can't find parameter register ",
754 (char *)nm);
755 return;
757 if (nexpr == 0 || exscale == 0.0)
758 j = Parms[i].prev;
759 else if (exsign[0] == '\0'
760 || (nm[0] == 't' && nm[1] == 'i'))
761 j = (int)(sexpr[0] / exscale);
762 else
763 j = Parms[i].val + (int)(sexpr[0] / exscale);
764 Parms[i].prev = Parms[i].val;
765 Parms[i].val = j;
766 nm[0] = (nexpr) ? exsign[0] : '\0'; /* for .ti */
767 nm[1] = '\0';
768 Pass3(brk, (unsigned char *)Parms[i].cmd, nm, j);
769 return;
771 if (line[1] == 'n') {
772 switch(line[2]) {
774 * Need - "^[.']ne <expression>"
776 case 'e':
777 if (nexpr && Scalev > 0.0)
778 i = (int) ((expr[0]/Scalev) + 0.99);
779 else
780 i = 0;
781 Pass3(DOBREAK, (unsigned char *)"need", NULL,
783 return;
785 * Number - "^[.']nr <name> <expression>"
787 case 'r':
788 if ((s1 = Field(2, line, 0)) == NULL) {
789 Error(WARN, LINE, " bad number register",
790 NULL);
791 return;
793 if ((i = Findnum(s1, 0, 0)) < 0)
794 i = Findnum(s1, 0, 1);
795 if (nexpr < 1) {
796 Numb[i].val = 0;
797 return;
799 if (exsign[0] == '\0')
800 Numb[i].val = (int) expr[0];
801 else
802 Numb[i].val += (int) sexpr[0];
803 return;
807 * Space - "^[.']sp <expression>"
809 if (line[1] == 's' && line[2] == 'p') {
810 if (nexpr == 0)
811 i = 1;
812 else
813 i = (int)((expr[0] / Scalev) + 0.99);
814 while (i--)
815 Pass3(brk, (unsigned char *)"space", NULL, 0);
816 return;
819 * Tab positions - "^[.']ta <pos1> <pos2> . . ."
821 if (line[1] == 't' && line[2] == 'a') {
822 tval = 0.0;
823 for (j = 0; j < nexpr; j++) {
824 if (exsign[j] == '\0')
825 tval = expr[j];
826 else
827 tval += sexpr[j];
828 Tabs[j] = (int) (tval / Scalen);
830 Ntabs = nexpr;
831 return;
835 * Process all other nroff requests via Nreq().
837 (void) Nreq(line, brk);
838 return;