tbl: use \s(NN instead of \sNN
[troff.git] / troff / n5.c
blobf9662f1fb33ae8a61d09dba12bda7165ff0331dc
1 /*
2 * troff5.c
3 *
4 * misc processing requests
5 */
7 #include "tdef.h"
8 #include "fns.h"
9 #include "ext.h"
11 int iflist[NIF];
12 int ifx;
13 int ifnum = 0; /* trying numeric expression for .if or .ie condition */
15 void casead(void)
17 int i;
19 ad = 1;
20 /* leave admod alone */
21 if (skip())
22 return;
23 switch (i = cbits(getch())) {
24 case 'r': /* right adj, left ragged */
25 admod = 2;
26 break;
27 case 'l': /* left adj, right ragged */
28 admod = ad = 0; /* same as casena */
29 break;
30 case 'c': /*centered adj*/
31 admod = 1;
32 break;
33 case 'b':
34 case 'n':
35 admod = 0;
36 break;
37 case '0':
38 case '2':
39 case '4':
40 ad = 0;
41 case '1':
42 case '3':
43 case '5':
44 admod = (i - '0') / 2;
49 void casena(void)
51 ad = 0;
55 void casefi(void)
57 tbreak();
58 fi = 1;
59 pendnf = 0;
63 void casenf(void)
65 tbreak();
66 fi = 0;
70 void casers(void)
72 dip->nls = 0;
76 void casens(void)
78 dip->nls++;
82 int chget(int c)
84 Tchar i;
85 i = 0;
86 if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n') {
87 ch = i;
88 return c;
89 } else
90 return cbits(i); /* was (i & BYTEMASK) */
94 void casecc(void)
96 cc = chget('.');
100 void casec2(void)
102 c2 = chget('\'');
106 void casehc(void)
108 ohc = chget(OHC);
112 void casetc(void)
114 tabc = chget(0);
118 void caselc(void)
120 dotc = chget(0);
124 void casehy(void)
126 int i;
128 hyf = 1;
129 if (skip())
130 return;
131 noscale++;
132 i = atoi0();
133 noscale = 0;
134 if (nonumb)
135 return;
136 hyf = max(i, 0);
140 void casenh(void)
142 hyf = 0;
146 int max(int aa, int bb)
148 if (aa > bb)
149 return aa;
150 else
151 return bb;
155 void casece(void)
157 int i;
159 noscale++;
160 skip();
161 i = max(atoi0(), 0);
162 if (nonumb)
163 i = 1;
164 tbreak();
165 ce = i;
166 noscale = 0;
170 void casein(void)
172 int i;
174 if (skip())
175 i = in1;
176 else {
177 i = max(hnumb(&in), 0);
178 if (nonumb)
179 i = in1;
181 tbreak();
182 in1 = in;
183 in = i;
184 if (!nc) {
185 un = in;
186 setnel();
191 void casell(void)
193 int i;
195 if (skip())
196 i = ll1;
197 else {
198 i = max(hnumb(&ll), INCH / 10);
199 if (nonumb)
200 i = ll1;
202 ll1 = ll;
203 ll = i;
204 setnel();
208 void caselt(void)
210 int i;
212 if (skip())
213 i = lt1;
214 else {
215 i = max(hnumb(&lt), 0);
216 if (nonumb)
217 i = lt1;
219 lt1 = lt;
220 lt = i;
224 void caseti(void)
226 int i;
228 if (skip())
229 return;
230 i = max(hnumb(&in), 0);
231 tbreak();
232 un1 = i;
233 setnel();
237 void casels(void)
239 int i;
241 noscale++;
242 if (skip())
243 i = ls1;
244 else {
245 i = max(inumb(&ls), 1);
246 if (nonumb)
247 i = ls1;
249 ls1 = ls;
250 ls = i;
251 noscale = 0;
255 void casepo(void)
257 int i;
259 if (skip())
260 i = po1;
261 else {
262 i = max(hnumb(&po), 0);
263 if (nonumb)
264 i = po1;
266 po1 = po;
267 po = i;
268 if (TROFF & !ascii)
269 esc += po - po1;
273 void casepl(void)
275 int i;
277 skip();
278 if ((i = vnumb(&pl)) == 0)
279 pl = 11 * INCH; /*11in*/
280 else
281 pl = i;
282 if (numtabp[NL].val > pl)
283 numtabp[NL].val = pl;
287 void casewh(void)
289 int i, j, k;
291 lgf++;
292 skip();
293 i = vnumb((int *)0);
294 if (nonumb)
295 return;
296 skip();
297 j = getrq();
298 if ((k = findn(i)) != NTRAP) {
299 mlist[k] = j;
300 return;
302 for (k = 0; k < NTRAP; k++)
303 if (mlist[k] == 0)
304 break;
305 if (k == NTRAP) {
306 flusho();
307 ERROR "cannot plant trap." WARN;
308 return;
310 mlist[k] = j;
311 nlist[k] = i;
315 void casech(void)
317 int i, j, k;
319 lgf++;
320 skip();
321 if (!(j = getrq()))
322 return;
323 else
324 for (k = 0; k < NTRAP; k++)
325 if (mlist[k] == j)
326 break;
327 if (k == NTRAP)
328 return;
329 skip();
330 i = vnumb((int *)0);
331 if (nonumb)
332 mlist[k] = 0;
333 nlist[k] = i;
337 int findn(int i)
339 int k;
341 for (k = 0; k < NTRAP; k++)
342 if ((nlist[k] == i) && (mlist[k] != 0))
343 break;
344 return k;
348 void casepn(void)
350 int i;
352 skip();
353 noscale++;
354 i = max(inumb(&numtabp[PN].val), 0);
355 noscale = 0;
356 if (!nonumb) {
357 npn = i;
358 npnflg++;
363 void casebp(void)
365 int i;
366 Stack *savframe;
368 if (dip != d)
369 return;
370 savframe = frame;
371 skip();
372 if ((i = inumb(&numtabp[PN].val)) < 0)
373 i = 0;
374 tbreak();
375 if (!nonumb) {
376 npn = i;
377 npnflg++;
378 } else if (dip->nls)
379 return;
380 eject(savframe);
383 void casetm(void)
385 casetm1(0, stderr);
389 void casefm(void)
391 static struct fcache {
392 char *name;
393 FILE *fp;
394 } fcache[15];
395 int i;
397 if ( skip() || !getname()) {
398 ERROR "fm: missing filename" WARN;
399 return;
402 for (i = 0; i < 15 && fcache[i].fp != NULL; i++) {
403 if (strcmp(nextf, fcache[i].name) == 0)
404 break;
406 if (i >= 15) {
407 ERROR "fm: too many streams" WARN;
408 return;
410 if (fcache[i].fp == NULL) {
411 if( (fcache[i].fp = fopen(nextf, "w")) == NULL) {
412 ERROR "fm: cannot open %s", nextf WARN;
413 return;
415 fcache[i].name = strdupl(nextf);
417 casetm1(0, fcache[i].fp);
420 void casetm1(int ab, FILE *out)
422 int i, j, c;
423 char *p;
424 char tmbuf[NTM];
426 lgf++;
427 copyf++;
428 if (ab) {
429 if (skip())
430 ERROR "User Abort" WARN;
431 else {
432 extern int error;
433 int savtrac = trace;
434 i = trace = 0;
435 noscale++;
436 i = inumb(&trace);
437 noscale--;
438 if (i) {
439 error = i;
440 if (nlflg || skip())
441 ERROR "User Abort, exit code %d", i WARN;
443 trace = savtrac;
445 } else
446 skip();
447 for (i = 0; i < NTM - 2; ) {
448 if ((c = cbits(getch())) == '\n' || c == RIGHT)
449 break;
450 else if (c == MINUS) { /* special pleading for strange encodings */
451 tmbuf[i++] = '\\';
452 tmbuf[i++] = '-';
453 } else if (c == PRESC) {
454 tmbuf[i++] = '\\';
455 tmbuf[i++] = 'e';
456 } else if (c == FILLER) {
457 tmbuf[i++] = '\\';
458 tmbuf[i++] = '&';
459 } else if (c == UNPAD) {
460 tmbuf[i++] = '\\';
461 tmbuf[i++] = ' ';
462 } else if (c == OHC) {
463 tmbuf[i++] = '\\';
464 tmbuf[i++] = '%';
465 } else if (c >= ALPHABET) {
466 p = chname(c);
467 switch (*p) {
468 case MBchar:
469 sprintf(&tmbuf[i], p+1);
470 break;
471 case Number:
472 sprintf(&tmbuf[i], "\\N'%s'", p+1);
473 break;
474 case Troffchar:
475 if ((j = strlen(p+1)) == 2)
476 sprintf(&tmbuf[i], "\\(%s", p+1);
477 else
478 sprintf(&tmbuf[i], "\\C'%s'", p+1);
479 break;
480 default:
481 sprintf(&tmbuf[i]," %s? ", p);
482 break;
484 j = strlen(&tmbuf[i]);
485 i += j;
486 } else
487 tmbuf[i++] = c;
489 tmbuf[i] = 0;
490 if (ab) /* truncate output */
491 obufp = obuf; /* should be a function in n2.c */
492 flusho();
493 if (i)
494 fprintf(out, "%s\n", tmbuf);
495 fflush(out);
496 copyf--;
497 lgf--;
501 void casesp(void)
503 casesp1(0);
506 void casesp1(int a)
508 int i, j, savlss;
510 tbreak();
511 if (dip->nls || trap)
512 return;
513 i = findt1();
514 if (!a) {
515 skip();
516 j = vnumb((int *)0);
517 if (nonumb)
518 j = lss;
519 } else
520 j = a;
521 if (j == 0)
522 return;
523 if (i < j)
524 j = i;
525 savlss = lss;
526 if (dip != d)
527 i = dip->dnl;
528 else
529 i = numtabp[NL].val;
530 if ((i + j) < 0)
531 j = -i;
532 lss = j;
533 newline(0);
534 lss = savlss;
538 void casert(void)
540 int a, *p;
542 skip();
543 if (dip != d)
544 p = &dip->dnl;
545 else
546 p = &numtabp[NL].val;
547 a = vnumb(p);
548 if (nonumb)
549 a = dip->mkline;
550 if ((a < 0) || (a >= *p))
551 return;
552 nb++;
553 casesp1(a - *p);
557 void caseem(void)
559 lgf++;
560 skip();
561 em = getrq();
565 void casefl(void)
567 tbreak();
568 if (!ascii)
569 ptflush();
570 flusho();
574 void caseev(void)
576 int nxev;
578 if (skip()) {
580 if (evi == 0)
581 return;
582 nxev = evlist[--evi];
583 goto e1;
585 noscale++;
586 nxev = atoi0();
587 noscale = 0;
588 if (nonumb)
589 goto e0;
590 flushi();
591 if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) {
592 flusho();
593 ERROR "cannot do .ev %d", nxev WARN;
594 if (error)
595 done2(040);
596 else
597 edone(040);
598 return;
600 evlist[evi++] = ev;
602 if (ev == nxev)
603 return;
604 ev = nxev;
605 envp = &env[ev];
608 void envcopy(Env *e1, Env *e2) /* copy env e2 to e1 */
610 *e1 = *e2; /* rumor hath that this fails on some machines */
614 void caseel(void)
616 if (--ifx < 0) {
617 ifx = 0;
618 iflist[0] = 0;
620 caseif1(2);
624 void caseie(void)
626 if (ifx >= NIF) {
627 ERROR "if-else overflow." WARN;
628 ifx = 0;
629 edone(040);
631 caseif1(1);
632 ifx++;
636 void caseif(void)
638 caseif1(0);
641 void caseif1(int x)
643 extern int falsef;
644 int notflag, true;
645 Tchar i;
647 if (x == 2) {
648 notflag = 0;
649 true = iflist[ifx];
650 goto i1;
652 true = 0;
653 skip();
654 if ((cbits(i = getch())) == '!') {
655 notflag = 1;
656 } else {
657 notflag = 0;
658 ch = i;
660 ifnum++;
661 i = atoi0();
662 ifnum = 0;
663 if (!nonumb) {
664 if (i > 0)
665 true++;
666 goto i1;
668 i = getch();
669 switch (cbits(i)) {
670 case 'e':
671 if (!(numtabp[PN].val & 01))
672 true++;
673 break;
674 case 'o':
675 if (numtabp[PN].val & 01)
676 true++;
677 break;
678 case 'n':
679 if (NROFF)
680 true++;
681 break;
682 case 't':
683 if (TROFF)
684 true++;
685 break;
686 case ' ':
687 break;
688 default:
689 true = cmpstr(i);
692 true ^= notflag;
693 if (x == 1)
694 iflist[ifx] = !true;
695 if (true) {
697 while ((cbits(i = getch())) == ' ')
699 if (cbits(i) == LEFT)
700 goto i2;
701 ch = i;
702 nflush++;
703 } else {
704 if (!nlflg) {
705 copyf++;
706 falsef++;
707 eatblk(0);
708 copyf--;
709 falsef--;
714 void eatblk(int inblk)
716 int cnt, i;
718 cnt = 0;
719 do {
720 if (ch) {
721 i = cbits(ch);
722 ch = 0;
723 } else
724 i = cbits(getch0());
725 if (i == ESC)
726 cnt++;
727 else {
728 if (cnt == 1)
729 switch (i) {
730 case '{': i = LEFT; break;
731 case '}': i = RIGHT; break;
732 case '\n': i = 'x'; break;
734 cnt = 0;
736 if (i == LEFT) eatblk(1);
737 } while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT)));
738 if (i == '\n') {
739 nlflg++;
740 if (ip == 0)
741 numtabp[CD].val++;
746 int cmpstr(Tchar c)
748 int j, delim;
749 Tchar i;
750 int val;
751 int savapts, savapts1, savfont, savfont1, savpts, savpts1;
752 Tchar string[1280];
753 Tchar *sp;
755 if (ismot(c))
756 return 0;
757 delim = cbits(c);
758 savapts = apts;
759 savapts1 = apts1;
760 savfont = font;
761 savfont1 = font1;
762 savpts = pts;
763 savpts1 = pts1;
764 sp = string;
765 while ((j = cbits(i = getch())) != delim && j != '\n' && sp < &string[1280 - 1])
766 *sp++ = i;
767 if (sp >= string + 1280) {
768 ERROR "too-long string compare." WARN;
769 edone(0100);
771 if (nlflg) {
772 val = sp==string;
773 goto rtn;
775 *sp = 0;
776 apts = savapts;
777 apts1 = savapts1;
778 font = savfont;
779 font1 = savfont1;
780 pts = savpts;
781 pts1 = savpts1;
782 mchbits();
783 val = 1;
784 sp = string;
785 while ((j = cbits(i = getch())) != delim && j != '\n') {
786 if (*sp != i) {
787 eat(delim);
788 val = 0;
789 goto rtn;
791 sp++;
793 if (*sp)
794 val = 0;
795 rtn:
796 apts = savapts;
797 apts1 = savapts1;
798 font = savfont;
799 font1 = savfont1;
800 pts = savpts;
801 pts1 = savpts1;
802 mchbits();
803 return(val);
807 void caserd(void)
810 lgf++;
811 skip();
812 getname();
813 if (!iflg) {
814 if (quiet) {
815 if (NROFF) {
816 echo_off();
817 flusho();
819 fprintf(stderr, "\007"); /*bell*/
820 } else {
821 if (nextf[0]) {
822 fprintf(stderr, "%s:", nextf);
823 } else {
824 fprintf(stderr, "\007"); /*bell*/
828 collect();
829 tty++;
830 pushi(RD_OFFSET, PAIR('r','d'));
834 int rdtty(void)
836 char onechar;
838 onechar = 0;
839 if (read(0, &onechar, 1) == 1) {
840 if (onechar == '\n')
841 tty++;
842 else
843 tty = 1;
844 if (tty != 3)
845 return onechar;
847 tty = 0;
848 if (NROFF && quiet)
849 echo_on();
850 return 0;
854 void caseec(void)
856 eschar = chget('\\');
860 void caseeo(void)
862 eschar = 0;
866 void caseta(void)
868 int i, j, k;
870 tabtab[0] = nonumb = 0;
871 for (i = 0; ((i < (NTAB - 1)) && !nonumb); i++) {
872 if (skip())
873 break;
874 k = tabtab[max(i-1, 0)] & TABMASK;
875 if ((j = max(hnumb(&k), 0)) > TABMASK) {
876 ERROR "Tab too far away" WARN;
877 j = TABMASK;
879 tabtab[i] = j & TABMASK;
880 if (!nonumb)
881 switch (cbits(ch)) {
882 case 'C':
883 tabtab[i] |= CTAB;
884 break;
885 case 'R':
886 tabtab[i] |= RTAB;
887 break;
888 default: /*includes L*/
889 break;
891 nonumb = ch = 0;
893 if (!skip())
894 ERROR "Too many tab stops" WARN;
895 tabtab[i] = 0;
899 void casene(void)
901 int i, j;
903 skip();
904 i = vnumb((int *)0);
905 if (nonumb)
906 i = lss;
907 if (dip == d && numtabp[NL].val == -1) {
908 newline(1);
909 return;
911 if (i > (j = findt1())) {
912 i = lss;
913 lss = j;
914 dip->nls = 0;
915 newline(0);
916 lss = i;
921 void casetr(void)
923 int i, j;
924 Tchar k;
926 lgf++;
927 skip();
928 while ((i = cbits(k=getch())) != '\n') {
929 if (ismot(k))
930 return;
931 if (ismot(k = getch()))
932 return;
933 if ((j = cbits(k)) == '\n')
934 j = ' ';
935 trtab[i] = j;
940 void casecu(void)
942 cu++;
943 caseul();
947 void caseul(void)
949 int i;
951 noscale++;
952 skip();
953 i = max(atoi0(), 0);
954 if (nonumb)
955 i = 1;
956 if (ul && (i == 0)) {
957 font = sfont;
958 ul = cu = 0;
960 if (i) {
961 if (!ul) {
962 sfont = font;
963 font = ulfont;
965 ul = i;
967 noscale = 0;
968 mchbits();
972 void caseuf(void)
974 int i, j;
976 if (skip() || !(i = getrq()) || i == 'S' || (j = findft(i)) == -1)
977 ulfont = ULFONT; /*default underline position*/
978 else
979 ulfont = j;
980 if (NROFF && ulfont == FT)
981 ulfont = ULFONT;
985 void caseit(void)
987 int i;
989 lgf++;
990 it = itmac = 0;
991 noscale++;
992 skip();
993 i = atoi0();
994 skip();
995 if (!nonumb && (itmac = getrq()))
996 it = i;
997 noscale = 0;
1001 void casemc(void)
1003 int i;
1005 if (icf > 1)
1006 ic = 0;
1007 icf = 0;
1008 if (skip())
1009 return;
1010 ic = getch();
1011 icf = 1;
1012 skip();
1013 i = max(hnumb((int *)0), 0);
1014 if (!nonumb)
1015 ics = i;
1019 void casemk(void)
1021 int i, j;
1023 if (dip != d)
1024 j = dip->dnl;
1025 else
1026 j = numtabp[NL].val;
1027 if (skip()) {
1028 dip->mkline = j;
1029 return;
1031 if ((i = getrq()) == 0)
1032 return;
1033 numtabp[findr(i)].val = j;
1037 void casesv(void)
1039 int i;
1041 skip();
1042 if ((i = vnumb((int *)0)) < 0)
1043 return;
1044 if (nonumb)
1045 i = 1;
1046 sv += i;
1047 caseos();
1051 void caseos(void)
1053 int savlss;
1055 if (sv <= findt1()) {
1056 savlss = lss;
1057 lss = sv;
1058 newline(0);
1059 lss = savlss;
1060 sv = 0;
1065 void casenm(void)
1067 int i;
1069 lnmod = nn = 0;
1070 if (skip())
1071 return;
1072 lnmod++;
1073 noscale++;
1074 i = inumb(&numtabp[LN].val);
1075 if (!nonumb)
1076 numtabp[LN].val = max(i, 0);
1077 getnm(&ndf, 1);
1078 getnm(&nms, 0);
1079 getnm(&ni, 0);
1080 getnm(&nmwid, 3); /* really kludgy! */
1081 noscale = 0;
1082 nmbits = chbits;
1086 * .nm relies on the fact that illegal args are skipped; don't warn
1087 * for illegality of these
1089 void getnm(int *p, int min)
1091 int i;
1092 int savtr = trace;
1094 eat(' ');
1095 if (skip())
1096 return;
1097 trace = 0;
1098 i = atoi0();
1099 if (nonumb)
1100 return;
1101 *p = max(i, min);
1102 trace = savtr;
1106 void casenn(void)
1108 noscale++;
1109 skip();
1110 nn = max(atoi0(), 1);
1111 noscale = 0;
1115 void caseab(void)
1117 casetm1(1, stderr);
1118 done3(0);
1122 /* nroff terminal handling has been pretty well excised */
1123 /* as part of the merge with troff. these are ghostly remnants, */
1124 /* called, but doing nothing. restore them at your peril. */
1127 void save_tty(void) /*save any tty settings that may be changed*/
1132 void restore_tty(void) /*restore tty settings from beginning*/
1137 void set_tty(void)
1142 void echo_off(void) /*turn off ECHO for .rd in "-q" mode*/
1147 void echo_on(void) /*restore ECHO after .rd in "-q" mode*/