Blob


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)
16 {
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;
45 }
46 }
49 void casena(void)
50 {
51 ad = 0;
52 }
55 void casefi(void)
56 {
57 tbreak();
58 fi = 1;
59 pendnf = 0;
60 }
63 void casenf(void)
64 {
65 tbreak();
66 fi = 0;
67 }
70 void casers(void)
71 {
72 dip->nls = 0;
73 }
76 void casens(void)
77 {
78 dip->nls++;
79 }
81 int
82 chget(int c)
83 {
84 Tchar i;
86 i = 0;
87 if (skip() || ismot(i = getch()) || cbits(i) == ' ' || cbits(i) == '\n') {
88 ch = i;
89 return(c);
90 } else
91 return cbits(i); /* was (i & BYTEMASK) */
92 }
95 void casecc(void)
96 {
97 cc = chget('.');
98 }
101 void casec2(void)
103 c2 = chget('\'');
107 void casehc(void)
109 ohc = chget(OHC);
113 void casetc(void)
115 tabc = chget(0);
119 void caselc(void)
121 dotc = chget(0);
125 void casehy(void)
127 int i;
129 hyf = 1;
130 if (skip())
131 return;
132 noscale++;
133 i = atoi0();
134 noscale = 0;
135 if (nonumb)
136 return;
137 hyf = max(i, 0);
141 void casenh(void)
143 hyf = 0;
146 int
147 max(int aa, int bb)
149 if (aa > bb)
150 return(aa);
151 else
152 return(bb);
156 void casece(void)
158 int i;
160 noscale++;
161 skip();
162 i = max(atoi0(), 0);
163 if (nonumb)
164 i = 1;
165 tbreak();
166 ce = i;
167 noscale = 0;
171 void casein(void)
173 int i;
175 if (skip())
176 i = in1;
177 else {
178 i = max(hnumb(&in), 0);
179 if (nonumb)
180 i = in1;
182 tbreak();
183 in1 = in;
184 in = i;
185 if (!nc) {
186 un = in;
187 setnel();
192 void casell(void)
194 int i;
196 if (skip())
197 i = ll1;
198 else {
199 i = max(hnumb(&ll), INCH / 10);
200 if (nonumb)
201 i = ll1;
203 ll1 = ll;
204 ll = i;
205 setnel();
209 void caselt(void)
211 int i;
213 if (skip())
214 i = lt1;
215 else {
216 i = max(hnumb(&lt), 0);
217 if (nonumb)
218 i = lt1;
220 lt1 = lt;
221 lt = i;
225 void caseti(void)
227 int i;
229 if (skip())
230 return;
231 i = max(hnumb(&in), 0);
232 tbreak();
233 un1 = i;
234 setnel();
238 void casels(void)
240 int i;
242 noscale++;
243 if (skip())
244 i = ls1;
245 else {
246 i = max(inumb(&ls), 1);
247 if (nonumb)
248 i = ls1;
250 ls1 = ls;
251 ls = i;
252 noscale = 0;
256 void casepo(void)
258 int i;
260 if (skip())
261 i = po1;
262 else {
263 i = max(hnumb(&po), 0);
264 if (nonumb)
265 i = po1;
267 po1 = po;
268 po = i;
269 if (TROFF & !ascii)
270 esc += po - po1;
274 void casepl(void)
276 int i;
278 skip();
279 if ((i = vnumb(&pl)) == 0)
280 pl = 11 * INCH; /*11in*/
281 else
282 pl = i;
283 if (numtabp[NL].val > pl)
284 numtabp[NL].val = pl;
288 void casewh(void)
290 int i, j, k;
292 lgf++;
293 skip();
294 i = vnumb((int *)0);
295 if (nonumb)
296 return;
297 skip();
298 j = getrq();
299 if ((k = findn(i)) != NTRAP) {
300 mlist[k] = j;
301 return;
303 for (k = 0; k < NTRAP; k++)
304 if (mlist[k] == 0)
305 break;
306 if (k == NTRAP) {
307 flusho();
308 ERROR "cannot plant trap." WARN;
309 return;
311 mlist[k] = j;
312 nlist[k] = i;
316 void casech(void)
318 int i, j, k;
320 lgf++;
321 skip();
322 if (!(j = getrq()))
323 return;
324 else
325 for (k = 0; k < NTRAP; k++)
326 if (mlist[k] == j)
327 break;
328 if (k == NTRAP)
329 return;
330 skip();
331 i = vnumb((int *)0);
332 if (nonumb)
333 mlist[k] = 0;
334 nlist[k] = i;
337 int
338 findn(int i)
340 int k;
342 for (k = 0; k < NTRAP; k++)
343 if ((nlist[k] == i) && (mlist[k] != 0))
344 break;
345 return(k);
349 void casepn(void)
351 int i;
353 skip();
354 noscale++;
355 i = max(inumb(&numtabp[PN].val), 0);
356 noscale = 0;
357 if (!nonumb) {
358 npn = i;
359 npnflg++;
364 void casebp(void)
366 int i;
367 Stack *savframe;
369 if (dip != d)
370 return;
371 savframe = frame;
372 skip();
373 if ((i = inumb(&numtabp[PN].val)) < 0)
374 i = 0;
375 tbreak();
376 if (!nonumb) {
377 npn = i;
378 npnflg++;
379 } else if (dip->nls)
380 return;
381 eject(savframe);
384 void casetm(void)
386 casetm1(0, stderr);
390 void casefm(void)
392 static struct fcache {
393 char *name;
394 FILE *fp;
395 } fcache[15];
396 int i;
398 if ( skip() || !getname()) {
399 ERROR "fm: missing filename" WARN;
400 return;
403 for (i = 0; i < 15 && fcache[i].fp != NULL; i++) {
404 if (strcmp(nextf, fcache[i].name) == 0)
405 break;
407 if (i >= 15) {
408 ERROR "fm: too many streams" WARN;
409 return;
411 if (fcache[i].fp == NULL) {
412 if( (fcache[i].fp = fopen(unsharp(nextf), "w")) == NULL) {
413 ERROR "fm: cannot open %s", nextf WARN;
414 return;
416 fcache[i].name = strdupl(nextf);
418 casetm1(0, fcache[i].fp);
421 void casetm1(int ab, FILE *out)
423 int i, j, c;
424 char *p;
425 char tmbuf[NTM];
427 lgf++;
428 copyf++;
429 if (ab) {
430 if (skip())
431 ERROR "User Abort" WARN;
432 else {
433 extern int error;
434 int savtrac = trace;
435 i = trace = 0;
436 noscale++;
437 i = inumb(&trace);
438 noscale--;
439 if (i) {
440 error = i;
441 if (nlflg || skip())
442 ERROR "User Abort, exit code %d", i WARN;
444 trace = savtrac;
446 } else
447 skip();
448 for (i = 0; i < NTM - 2; ) {
449 if ((c = cbits(getch())) == '\n' || c == RIGHT)
450 break;
451 else if (c == MINUS) { /* special pleading for strange encodings */
452 tmbuf[i++] = '\\';
453 tmbuf[i++] = '-';
454 } else if (c == PRESC) {
455 tmbuf[i++] = '\\';
456 tmbuf[i++] = 'e';
457 } else if (c == FILLER) {
458 tmbuf[i++] = '\\';
459 tmbuf[i++] = '&';
460 } else if (c == UNPAD) {
461 tmbuf[i++] = '\\';
462 tmbuf[i++] = ' ';
463 } else if (c == OHC) {
464 tmbuf[i++] = '\\';
465 tmbuf[i++] = '%';
466 } else if (c >= ALPHABET) {
467 p = chname(c);
468 switch (*p) {
469 case MBchar:
470 strcpy(&tmbuf[i], p+1);
471 break;
472 case Number:
473 sprintf(&tmbuf[i], "\\N'%s'", p+1);
474 break;
475 case Troffchar:
476 if ((j = strlen(p+1)) == 2)
477 sprintf(&tmbuf[i], "\\(%s", p+1);
478 else
479 sprintf(&tmbuf[i], "\\C'%s'", p+1);
480 break;
481 default:
482 sprintf(&tmbuf[i]," %s? ", p);
483 break;
485 j = strlen(&tmbuf[i]);
486 i += j;
487 } else
488 tmbuf[i++] = c;
490 tmbuf[i] = 0;
491 if (ab) /* truncate output */
492 obufp = obuf; /* should be a function in n2.c */
493 flusho();
494 if (i)
495 fprintf(out, "%s\n", tmbuf);
496 fflush(out);
497 copyf--;
498 lgf--;
502 void casesp(void)
504 casesp1(0);
507 void casesp1(int a)
509 int i, j, savlss;
511 tbreak();
512 if (dip->nls || trap)
513 return;
514 i = findt1();
515 if (!a) {
516 skip();
517 j = vnumb((int *)0);
518 if (nonumb)
519 j = lss;
520 } else
521 j = a;
522 if (j == 0)
523 return;
524 if (i < j)
525 j = i;
526 savlss = lss;
527 if (dip != d)
528 i = dip->dnl;
529 else
530 i = numtabp[NL].val;
531 if ((i + j) < 0)
532 j = -i;
533 lss = j;
534 newline(0);
535 lss = savlss;
539 void casert(void)
541 int a, *p;
543 skip();
544 if (dip != d)
545 p = &dip->dnl;
546 else
547 p = &numtabp[NL].val;
548 a = vnumb(p);
549 if (nonumb)
550 a = dip->mkline;
551 if ((a < 0) || (a >= *p))
552 return;
553 nb++;
554 casesp1(a - *p);
558 void caseem(void)
560 lgf++;
561 skip();
562 em = getrq();
566 void casefl(void)
568 tbreak();
569 if (!ascii)
570 ptflush();
571 flusho();
575 void caseev(void)
577 int nxev;
579 if (skip()) {
580 e0:
581 if (evi == 0)
582 return;
583 nxev = evlist[--evi];
584 goto e1;
586 noscale++;
587 nxev = atoi0();
588 noscale = 0;
589 if (nonumb)
590 goto e0;
591 flushi();
592 if (nxev >= NEV || nxev < 0 || evi >= EVLSZ) {
593 flusho();
594 ERROR "cannot do .ev %d", nxev WARN;
595 if (error)
596 done2(040);
597 else
598 edone(040);
599 return;
601 evlist[evi++] = ev;
602 e1:
603 if (ev == nxev)
604 return;
605 ev = nxev;
606 envp = &env[ev];
609 void envcopy(Env *e1, Env *e2) /* copy env e2 to e1 */
611 *e1 = *e2; /* rumor hath that this fails on some machines */
615 void caseel(void)
617 if (--ifx < 0) {
618 ifx = 0;
619 iflist[0] = 0;
621 caseif1(2);
625 void caseie(void)
627 if (ifx >= NIF) {
628 ERROR "if-else overflow." WARN;
629 ifx = 0;
630 edone(040);
632 caseif1(1);
633 ifx++;
637 void caseif(void)
639 caseif1(0);
642 void caseif1(int x)
644 extern int falsef;
645 int notflag, true;
646 Tchar i;
648 if (x == 2) {
649 notflag = 0;
650 true = iflist[ifx];
651 goto i1;
653 true = 0;
654 skip();
655 if ((cbits(i = getch())) == '!') {
656 notflag = 1;
657 } else {
658 notflag = 0;
659 ch = i;
661 ifnum++;
662 i = atoi0();
663 ifnum = 0;
664 if (!nonumb) {
665 if (i > 0)
666 true++;
667 goto i1;
669 i = getch();
670 switch (cbits(i)) {
671 case 'e':
672 if (!(numtabp[PN].val & 01))
673 true++;
674 break;
675 case 'o':
676 if (numtabp[PN].val & 01)
677 true++;
678 break;
679 case 'n':
680 if (NROFF)
681 true++;
682 break;
683 case 't':
684 if (TROFF)
685 true++;
686 break;
687 case ' ':
688 break;
689 default:
690 true = cmpstr(i);
692 i1:
693 true ^= notflag;
694 if (x == 1)
695 iflist[ifx] = !true;
696 if (true) {
697 i2:
698 while ((cbits(i = getch())) == ' ')
700 if (cbits(i) == LEFT)
701 goto i2;
702 ch = i;
703 nflush++;
704 } else {
705 if (!nlflg) {
706 copyf++;
707 falsef++;
708 eatblk(0);
709 copyf--;
710 falsef--;
715 void eatblk(int inblk)
717 int cnt, i;
719 cnt = 0;
720 do {
721 if (ch) {
722 i = cbits(ch);
723 ch = 0;
724 } else
725 i = cbits(getch0());
726 if (i == ESC)
727 cnt++;
728 else {
729 if (cnt == 1)
730 switch (i) {
731 case '{': i = LEFT; break;
732 case '}': i = RIGHT; break;
733 case '\n': i = 'x'; break;
735 cnt = 0;
737 if (i == LEFT) eatblk(1);
738 } while ((!inblk && (i != '\n')) || (inblk && (i != RIGHT)));
739 if (i == '\n') {
740 nlflg++;
741 if (ip == 0)
742 numtabp[CD].val++;
746 int
747 cmpstr(Tchar c)
749 int j, delim;
750 Tchar i;
751 int val;
752 int savapts, savapts1, savfont, savfont1, savpts, savpts1;
753 Tchar string[1280];
754 Tchar *sp;
756 if (ismot(c))
757 return(0);
758 delim = cbits(c);
759 savapts = apts;
760 savapts1 = apts1;
761 savfont = font;
762 savfont1 = font1;
763 savpts = pts;
764 savpts1 = pts1;
765 sp = string;
766 while ((j = cbits(i = getch()))!=delim && j!='\n' && sp<&string[1280-1])
767 *sp++ = i;
768 if (sp >= string + 1280) {
769 ERROR "too-long string compare." WARN;
770 edone(0100);
772 if (nlflg) {
773 val = sp==string;
774 goto rtn;
776 *sp = 0;
777 apts = savapts;
778 apts1 = savapts1;
779 font = savfont;
780 font1 = savfont1;
781 pts = savpts;
782 pts1 = savpts1;
783 mchbits();
784 val = 1;
785 sp = string;
786 while ((j = cbits(i = getch())) != delim && j != '\n') {
787 if (*sp != i) {
788 eat(delim);
789 val = 0;
790 goto rtn;
792 sp++;
794 if (*sp)
795 val = 0;
796 rtn:
797 apts = savapts;
798 apts1 = savapts1;
799 font = savfont;
800 font1 = savfont1;
801 pts = savpts;
802 pts1 = savpts1;
803 mchbits();
804 return(val);
808 void caserd(void)
811 lgf++;
812 skip();
813 getname();
814 if (!iflg) {
815 if (quiet) {
816 if (NROFF) {
817 echo_off();
818 flusho();
820 fprintf(stderr, "\007"); /*bell*/
821 } else {
822 if (nextf[0]) {
823 fprintf(stderr, "%s:", nextf);
824 } else {
825 fprintf(stderr, "\007"); /*bell*/
829 collect();
830 tty++;
831 pushi(RD_OFFSET, PAIR('r','d'));
834 int
835 rdtty(void)
837 char onechar;
839 onechar = 0;
840 if (read(0, &onechar, 1) == 1) {
841 if (onechar == '\n')
842 tty++;
843 else
844 tty = 1;
845 if (tty != 3)
846 return(onechar);
848 tty = 0;
849 if (NROFF && quiet)
850 echo_on();
851 return(0);
855 void caseec(void)
857 eschar = chget('\\');
861 void caseeo(void)
863 eschar = 0;
867 void caseta(void)
869 int i, j, k;
871 tabtab[0] = nonumb = 0;
872 for (i = 0; ((i < (NTAB - 1)) && !nonumb); i++) {
873 if (skip())
874 break;
875 k = tabtab[max(i-1, 0)] & TABMASK;
876 if ((j = max(hnumb(&k), 0)) > TABMASK) {
877 ERROR "Tab too far away" WARN;
878 j = TABMASK;
880 tabtab[i] = j & TABMASK;
881 if (!nonumb)
882 switch (cbits(ch)) {
883 case 'C':
884 tabtab[i] |= CTAB;
885 break;
886 case 'R':
887 tabtab[i] |= RTAB;
888 break;
889 default: /*includes L*/
890 break;
892 nonumb = ch = 0;
894 if (!skip())
895 ERROR "Too many tab stops" WARN;
896 tabtab[i] = 0;
900 void casene(void)
902 int i, j;
904 skip();
905 i = vnumb((int *)0);
906 if (nonumb)
907 i = lss;
908 if (dip == d && numtabp[NL].val == -1) {
909 newline(1);
910 return;
912 if (i > (j = findt1())) {
913 i = lss;
914 lss = j;
915 dip->nls = 0;
916 newline(0);
917 lss = i;
922 void casetr(void)
924 int i, j;
925 Tchar k;
927 lgf++;
928 skip();
929 while ((i = cbits(k=getch())) != '\n') {
930 if (ismot(k))
931 return;
932 if (ismot(k = getch()))
933 return;
934 if ((j = cbits(k)) == '\n')
935 j = ' ';
936 trtab[i] = j;
941 void casecu(void)
943 cu++;
944 caseul();
948 void caseul(void)
950 int i;
952 noscale++;
953 skip();
954 i = max(atoi0(), 0);
955 if (nonumb)
956 i = 1;
957 if (ul && (i == 0)) {
958 font = sfont;
959 ul = cu = 0;
961 if (i) {
962 if (!ul) {
963 sfont = font;
964 font = ulfont;
966 ul = i;
968 noscale = 0;
969 mchbits();
973 void caseuf(void)
975 int i, j;
977 if (skip() || !(i = getrq()) || i == 'S' || (j = findft(i)) == -1)
978 ulfont = ULFONT; /*default underline position*/
979 else
980 ulfont = j;
981 if (NROFF && ulfont == FT)
982 ulfont = ULFONT;
986 void caseit(void)
988 int i;
990 lgf++;
991 it = itmac = 0;
992 noscale++;
993 skip();
994 i = atoi0();
995 skip();
996 if (!nonumb && (itmac = getrq()))
997 it = i;
998 noscale = 0;
1002 void casemc(void)
1004 int i;
1006 if (icf > 1)
1007 ic = 0;
1008 icf = 0;
1009 if (skip())
1010 return;
1011 ic = getch();
1012 icf = 1;
1013 skip();
1014 i = max(hnumb((int *)0), 0);
1015 if (!nonumb)
1016 ics = i;
1020 void casemk(void)
1022 int i, j;
1024 if (dip != d)
1025 j = dip->dnl;
1026 else
1027 j = numtabp[NL].val;
1028 if (skip()) {
1029 dip->mkline = j;
1030 return;
1032 if ((i = getrq()) == 0)
1033 return;
1034 numtabp[findr(i)].val = j;
1038 void casesv(void)
1040 int i;
1042 skip();
1043 if ((i = vnumb((int *)0)) < 0)
1044 return;
1045 if (nonumb)
1046 i = 1;
1047 sv += i;
1048 caseos();
1052 void caseos(void)
1054 int savlss;
1056 if (sv <= findt1()) {
1057 savlss = lss;
1058 lss = sv;
1059 newline(0);
1060 lss = savlss;
1061 sv = 0;
1066 void casenm(void)
1068 int i;
1070 lnmod = nn = 0;
1071 if (skip())
1072 return;
1073 lnmod++;
1074 noscale++;
1075 i = inumb(&numtabp[LN].val);
1076 if (!nonumb)
1077 numtabp[LN].val = max(i, 0);
1078 getnm(&ndf, 1);
1079 getnm(&nms, 0);
1080 getnm(&ni, 0);
1081 getnm(&nmwid, 3); /* really kludgy! */
1082 noscale = 0;
1083 nmbits = chbits;
1087 * .nm relies on the fact that illegal args are skipped; don't warn
1088 * for illegality of these
1090 void getnm(int *p, int min)
1092 int i;
1093 int savtr = trace;
1095 eat(' ');
1096 if (skip())
1097 return;
1098 trace = 0;
1099 i = atoi0();
1100 if (nonumb)
1101 return;
1102 *p = max(i, min);
1103 trace = savtr;
1107 void casenn(void)
1109 noscale++;
1110 skip();
1111 nn = max(atoi0(), 1);
1112 noscale = 0;
1116 void caseab(void)
1118 casetm1(1, stderr);
1119 done3(0);
1123 /* nroff terminal handling has been pretty well excised */
1124 /* as part of the merge with troff. these are ghostly remnants, */
1125 /* called, but doing nothing. restore them at your peril. */
1128 void save_tty(void) /*save any tty settings that may be changed*/
1133 void restore_tty(void) /*restore tty settings from beginning*/
1138 void set_tty(void)
1143 void echo_off(void) /*turn off ECHO for .rd in "-q" mode*/
1148 void echo_on(void) /*restore ECHO after .rd in "-q" mode*/