xref: /plan9-contrib/sys/src/cmd/troff/n7.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
1 #include "tdef.h"
2 #include "fns.h"
3 #include "ext.h"
4 
5 #ifdef STRICT
6 	/* not in ANSI or POSIX */
7 #undef  isascii
8 #define	isascii(a) ((a) >= 0 && (a) <= 127)
9 #endif
10 
11 #define GETCH gettch
12 Tchar	gettch(void);
13 
14 
15 /*
16  * troff7.c
17  *
18  * text
19  */
20 
21 int	brflg;
22 
tbreak(void)23 void tbreak(void)
24 {
25 	int pad, k;
26 	Tchar *i, j;
27 	int resol;
28 	int un0 = un;
29 
30 	trap = 0;
31 	if (nb)
32 		return;
33 	if (dip == d && numtabp[NL].val == -1) {
34 		newline(1);
35 		return;
36 	}
37 	if (!nc) {
38 		setnel();
39 		if (!wch)
40 			return;
41 		if (pendw)
42 			getword(1);
43 		movword();
44 	} else if (pendw && !brflg) {
45 		getword(1);
46 		movword();
47 	}
48 	*linep = dip->nls = 0;
49 	if (NROFF && dip == d)
50 		horiz(po);
51 	if (lnmod)
52 		donum();
53 	lastl = ne;
54 	if (brflg != 1) {
55 		totout = 0;
56 	} else if (ad) {
57 		if ((lastl = ll - un) < ne)
58 			lastl = ne;
59 	}
60 	if (admod && ad && (brflg != 2)) {
61 		lastl = ne;
62 		adsp = adrem = 0;
63 		if (admod == 1)
64 			un +=  quant(nel / 2, HOR);
65 		else if (admod == 2)
66 			un += nel;
67 	}
68 	totout++;
69 	brflg = 0;
70 	if (lastl + un > dip->maxl)
71 		dip->maxl = lastl + un;
72 	horiz(un);
73 	if (NROFF) {
74 		if (adrem % t.Adj)
75 			resol = t.Hor;
76 		else
77 			resol = t.Adj;
78 	} else
79 		resol = HOR;
80 
81 	lastl = ne + (nwd-1) * adsp + adrem;
82 	for (i = line; nc > 0; ) {
83 		if ((cbits(j = *i++)) == ' ') {
84 			pad = 0;
85 			do {
86 				pad += width(j);
87 				nc--;
88 			} while ((cbits(j = *i++)) == ' ');
89 			i--;
90 			pad += adsp;
91 			--nwd;
92 			if (adrem) {
93 				if (adrem < 0) {
94 					pad -= resol;
95 					adrem += resol;
96 				} else if ((totout & 01) || adrem / resol >= nwd) {
97 					pad += resol;
98 					adrem -= resol;
99 				}
100 			}
101 			pchar((Tchar) WORDSP);
102 			horiz(pad);
103 		} else {
104 			pchar(j);
105 			nc--;
106 		}
107 	}
108 	if (ic) {
109 		if ((k = ll - un0 - lastl + ics) > 0)
110 			horiz(k);
111 		pchar(ic);
112 	}
113 	if (icf)
114 		icf++;
115 	else
116 		ic = 0;
117 	ne = nwd = 0;
118 	un = in;
119 	setnel();
120 	newline(0);
121 	if (dip != d) {
122 		if (dip->dnl > dip->hnl)
123 			dip->hnl = dip->dnl;
124 	} else {
125 		if (numtabp[NL].val > dip->hnl)
126 			dip->hnl = numtabp[NL].val;
127 	}
128 	for (k = ls - 1; k > 0 && !trap; k--)
129 		newline(0);
130 	spread = 0;
131 }
132 
donum(void)133 void donum(void)
134 {
135 	int i, nw;
136 	int lnv = numtabp[LN].val;
137 
138 	nrbits = nmbits;
139 	nw = width('1' | nrbits);
140 	if (nn) {
141 		nn--;
142 		goto d1;
143 	}
144 	if (lnv % ndf) {
145 		numtabp[LN].val++;
146 d1:
147 		un += nw * (nmwid + nms + ni);
148 		return;
149 	}
150 	i = 0;
151 	do {		/* count digits in numtabp[LN].val */
152 		i++;
153 	} while ((lnv /= 10) > 0);
154 	horiz(nw * (ni + max(nmwid-i, 0)));
155 	nform = 0;
156 	fnumb(numtabp[LN].val, pchar);
157 	un += nw * nms;
158 	numtabp[LN].val++;
159 }
160 
161 
text(void)162 void text(void)
163 {
164 	Tchar i;
165 	static int spcnt;
166 
167 	nflush++;
168 	numtabp[HP].val = 0;
169 	if ((dip == d) && (numtabp[NL].val == -1)) {
170 		newline(1);
171 		return;
172 	}
173 	setnel();
174 	if (ce || !fi) {
175 		nofill();
176 		return;
177 	}
178 	if (pendw)
179 		goto t4;
180 	if (pendt)
181 		if (spcnt)
182 			goto t2;
183 		else
184 			goto t3;
185 	pendt++;
186 	if (spcnt)
187 		goto t2;
188 	while ((cbits(i = GETCH())) == ' ') {
189 		spcnt++;
190 		numtabp[HP].val += sps;
191 		widthp = sps;
192 	}
193 	if (nlflg) {
194 t1:
195 		nflush = pendt = ch = spcnt = 0;
196 		callsp();
197 		return;
198 	}
199 	ch = i;
200 	if (spcnt) {
201 t2:
202 		tbreak();
203 		if (nc || wch)
204 			goto rtn;
205 		un += spcnt * sps;
206 		spcnt = 0;
207 		setnel();
208 		if (trap)
209 			goto rtn;
210 		if (nlflg)
211 			goto t1;
212 	}
213 t3:
214 	if (spread)
215 		goto t5;
216 	if (pendw || !wch)
217 t4:
218 		if (getword(0))
219 			goto t6;
220 	if (!movword())
221 		goto t3;
222 t5:
223 	if (nlflg)
224 		pendt = 0;
225 	adsp = adrem = 0;
226 	if (ad) {
227 		if (nwd == 1)
228 			adsp = nel;
229 		else
230 			adsp = nel / (nwd - 1);
231 		adsp = (adsp / HOR) * HOR;
232 		adrem = nel - adsp*(nwd-1);
233 	}
234 	brflg = 1;
235 	tbreak();
236 	spread = 0;
237 	if (!trap)
238 		goto t3;
239 	if (!nlflg)
240 		goto rtn;
241 t6:
242 	pendt = 0;
243 	ckul();
244 rtn:
245 	nflush = 0;
246 }
247 
248 
nofill(void)249 void nofill(void)
250 {
251 	int j;
252 	Tchar i;
253 
254 	if (!pendnf) {
255 		over = 0;
256 		tbreak();
257 		if (trap)
258 			goto rtn;
259 		if (nlflg) {
260 			ch = nflush = 0;
261 			callsp();
262 			return;
263 		}
264 		adsp = adrem = 0;
265 		nwd = 10000;
266 	}
267 	while ((j = (cbits(i = GETCH()))) != '\n') {
268 		if (j == ohc)
269 			continue;
270 		if (j == CONT) {
271 			pendnf++;
272 			nflush = 0;
273 			flushi();
274 			ckul();
275 			return;
276 		}
277 		j = width(i);
278 		widthp = j;
279 		numtabp[HP].val += j;
280 		storeline(i, j);
281 	}
282 	if (ce) {
283 		ce--;
284 		if ((i = quant(nel / 2, HOR)) > 0)
285 			un += i;
286 	}
287 	if (!nc)
288 		storeline((Tchar)FILLER, 0);
289 	brflg = 2;
290 	tbreak();
291 	ckul();
292 rtn:
293 	pendnf = nflush = 0;
294 }
295 
296 
callsp(void)297 void callsp(void)
298 {
299 	int i;
300 
301 	if (flss)
302 		i = flss;
303 	else
304 		i = lss;
305 	flss = 0;
306 	casesp1(i);
307 }
308 
309 
ckul(void)310 void ckul(void)
311 {
312 	if (ul && (--ul == 0)) {
313 		cu = 0;
314 		font = sfont;
315 		mchbits();
316 	}
317 	if (it && --it == 0 && itmac)
318 		control(itmac, 0);
319 }
320 
321 
storeline(Tchar c,int w)322 void storeline(Tchar c, int w)
323 {
324 	int diff;
325 
326 	if (linep >= line + lnsize - 2) {
327 		lnsize += LNSIZE;
328 		diff = linep - line;
329 		if (( line = (Tchar *)realloc((char *)line, lnsize * sizeof(Tchar))) != NULL) {
330 			if (linep && diff)
331 				linep = line + diff;
332 		} else {
333 			if (over) {
334 				return;
335 			} else {
336 				flusho();
337 				ERROR "Line overflow." WARN;
338 				over++;
339 				*linep++ = LEFTHAND;
340 				w = width(LEFTHAND);
341 				nc++;
342 				c = '\n';
343 			}
344 		}
345 	}
346 	*linep++ = c;
347 	ne += w;
348 	nel -= w;
349 	nc++;
350 }
351 
352 
newline(int a)353 void newline(int a)
354 {
355 	int i, j, nlss;
356 	int opn;
357 
358 	nlss = 0;
359 	if (a)
360 		goto nl1;
361 	if (dip != d) {
362 		j = lss;
363 		pchar1((Tchar)FLSS);
364 		if (flss)
365 			lss = flss;
366 		i = lss + dip->blss;
367 		dip->dnl += i;
368 		pchar1((Tchar)i);
369 		pchar1((Tchar)'\n');
370 		lss = j;
371 		dip->blss = flss = 0;
372 		if (dip->alss) {
373 			pchar1((Tchar)FLSS);
374 			pchar1((Tchar)dip->alss);
375 			pchar1((Tchar)'\n');
376 			dip->dnl += dip->alss;
377 			dip->alss = 0;
378 		}
379 		if (dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && dip->dimac)
380 			if (control(dip->dimac, 0)) {
381 				trap++;
382 				dip->ditf++;
383 			}
384 		return;
385 	}
386 	j = lss;
387 	if (flss)
388 		lss = flss;
389 	nlss = dip->alss + dip->blss + lss;
390 	numtabp[NL].val += nlss;
391 	if (TROFF && ascii) {
392 		dip->alss = dip->blss = 0;
393 	}
394 	pchar1((Tchar)'\n');
395 	flss = 0;
396 	lss = j;
397 	if (numtabp[NL].val < pl)
398 		goto nl2;
399 nl1:
400 	ejf = dip->hnl = numtabp[NL].val = 0;
401 	ejl = frame;
402 	if (donef) {
403 		if ((!nc && !wch) || ndone)
404 			done1(0);
405 		ndone++;
406 		donef = 0;
407 		if (frame == stk)
408 			nflush++;
409 	}
410 	opn = numtabp[PN].val;
411 	numtabp[PN].val++;
412 	if (npnflg) {
413 		numtabp[PN].val = npn;
414 		npn = npnflg = 0;
415 	}
416 nlpn:
417 	if (numtabp[PN].val == pfrom) {
418 		print++;
419 		pfrom = -1;
420 	} else if (opn == pto) {
421 		print = 0;
422 		opn = -1;
423 		chkpn();
424 		goto nlpn;
425 	}
426 	if (print)
427 		ptpage(numtabp[PN].val);	/* supposedly in a clean state so can pause */
428 	if (stop && print) {
429 		dpn++;
430 		if (dpn >= stop) {
431 			dpn = 0;
432 			ptpause();
433 		}
434 	}
435 nl2:
436 	trap = 0;
437 	if (numtabp[NL].val == 0) {
438 		if ((j = findn(0)) != NTRAP)
439 			trap = control(mlist[j], 0);
440 	} else if ((i = findt(numtabp[NL].val - nlss)) <= nlss) {
441 		if ((j = findn1(numtabp[NL].val - nlss + i)) == NTRAP) {
442 			flusho();
443 			ERROR "Trap botch." WARN;
444 			done2(-5);
445 		}
446 		trap = control(mlist[j], 0);
447 	}
448 }
449 
450 
findn1(int a)451 findn1(int a)
452 {
453 	int i, j;
454 
455 	for (i = 0; i < NTRAP; i++) {
456 		if (mlist[i]) {
457 			if ((j = nlist[i]) < 0)
458 				j += pl;
459 			if (j == a)
460 				break;
461 		}
462 	}
463 	return(i);
464 }
465 
466 
chkpn(void)467 void chkpn(void)
468 {
469 	pto = *(pnp++);
470 	pfrom = pto>=0 ? pto : -pto;
471 	if (pto == -INT_MAX) {
472 		flusho();
473 		done1(0);
474 	}
475 	if (pto < 0) {
476 		pto = -pto;
477 		print++;
478 		pfrom = 0;
479 	}
480 }
481 
482 
findt(int a)483 findt(int a)
484 {
485 	int i, j, k;
486 
487 	k = INT_MAX;
488 	if (dip != d) {
489 		if (dip->dimac && (i = dip->ditrap - a) > 0)
490 			k = i;
491 		return(k);
492 	}
493 	for (i = 0; i < NTRAP; i++) {
494 		if (mlist[i]) {
495 			if ((j = nlist[i]) < 0)
496 				j += pl;
497 			if ((j -= a) <= 0)
498 				continue;
499 			if (j < k)
500 				k = j;
501 		}
502 	}
503 	i = pl - a;
504 	if (k > i)
505 		k = i;
506 	return(k);
507 }
508 
509 
findt1(void)510 findt1(void)
511 {
512 	int i;
513 
514 	if (dip != d)
515 		i = dip->dnl;
516 	else
517 		i = numtabp[NL].val;
518 	return(findt(i));
519 }
520 
521 
eject(Stack * a)522 void eject(Stack *a)
523 {
524 	int savlss;
525 
526 	if (dip != d)
527 		return;
528 	ejf++;
529 	if (a)
530 		ejl = a;
531 	else
532 		ejl = frame;
533 	if (trap)
534 		return;
535 e1:
536 	savlss = lss;
537 	lss = findt(numtabp[NL].val);
538 	newline(0);
539 	lss = savlss;
540 	if (numtabp[NL].val && !trap)
541 		goto e1;
542 }
543 
544 
movword(void)545 movword(void)
546 {
547 	int w;
548 	Tchar i, *wp;
549 	int savwch, hys;
550 
551 	over = 0;
552 	wp = wordp;
553 	if (!nwd) {
554 		while (cbits(*wp++) == ' ') {
555 			wch--;
556 			wne -= sps;
557 		}
558 		wp--;
559 	}
560 	if (wne > nel && !hyoff && hyf && (!nwd || nel > 3 * sps) &&
561 	   (!(hyf & 02) || (findt1() > lss)))
562 		hyphen(wp);
563 	savwch = wch;
564 	hyp = hyptr;
565 	nhyp = 0;
566 	while (*hyp && *hyp <= wp)
567 		hyp++;
568 	while (wch) {
569 		if (hyoff != 1 && *hyp == wp) {
570 			hyp++;
571 			if (!wdstart || (wp > wdstart + 1 && wp < wdend &&
572 			   (!(hyf & 04) || wp < wdend - 1) &&		/* 04 => last 2 */
573 			   (!(hyf & 010) || wp > wdstart + 2))) {	/* 010 => 1st 2 */
574 				nhyp++;
575 				storeline((Tchar)IMP, 0);
576 			}
577 		}
578 		i = *wp++;
579 		w = width(i);
580 		wne -= w;
581 		wch--;
582 		storeline(i, w);
583 	}
584 	if (nel >= 0) {
585 		nwd++;
586 		return(0);	/* line didn't fill up */
587 	}
588 	if (TROFF)
589 		xbits((Tchar)HYPHEN, 1);
590 	hys = width((Tchar)HYPHEN);
591 m1:
592 	if (!nhyp) {
593 		if (!nwd)
594 			goto m3;
595 		if (wch == savwch)
596 			goto m4;
597 	}
598 	if (*--linep != IMP)
599 		goto m5;
600 	if (!(--nhyp))
601 		if (!nwd)
602 			goto m2;
603 	if (nel < hys) {
604 		nc--;
605 		goto m1;
606 	}
607 m2:
608 	if ((i = cbits(*(linep - 1))) != '-' && i != EMDASH) {
609 		*linep = (*(linep - 1) & SFMASK) | HYPHEN;
610 		w = width(*linep);
611 		nel -= w;
612 		ne += w;
613 		linep++;
614 	}
615 m3:
616 	nwd++;
617 m4:
618 	wordp = wp;
619 	return(1);	/* line filled up */
620 m5:
621 	nc--;
622 	w = width(*linep);
623 	ne -= w;
624 	nel += w;
625 	wne += w;
626 	wch++;
627 	wp--;
628 	goto m1;
629 }
630 
631 
horiz(int i)632 void horiz(int i)
633 {
634 	vflag = 0;
635 	if (i)
636 		pchar(makem(i));
637 }
638 
639 
setnel(void)640 void setnel(void)
641 {
642 	if (!nc) {
643 		linep = line;
644 		if (un1 >= 0) {
645 			un = un1;
646 			un1 = -1;
647 		}
648 		nel = ll - un;
649 		ne = adsp = adrem = 0;
650 	}
651 }
652 
653 
getword(int x)654 getword(int x)
655 {
656 	int j, k;
657 	Tchar i, *wp;
658 	int noword;
659 	int obits;
660 
661 	j = noword = 0;
662 	if (x)
663 		if (pendw) {
664 			*pendw = 0;
665 			goto rtn;
666 		}
667 	if (wordp = pendw)
668 		goto g1;
669 	hyp = hyptr;
670 	wordp = word;
671 	over = wne = wch = 0;
672 	hyoff = 0;
673 	obits = chbits;
674 	while (1) {	/* picks up 1st char of word */
675 		j = cbits(i = GETCH());
676 		if (j == '\n') {
677 			wne = wch = 0;
678 			noword = 1;
679 			goto rtn;
680 		}
681 		if (j == ohc) {
682 			hyoff = 1;	/* 1 => don't hyphenate */
683 			continue;
684 		}
685 		if (j == ' ') {
686 			numtabp[HP].val += sps;
687 			widthp = sps;
688 			storeword(i, sps);
689 			continue;
690 		}
691 		break;
692 	}
693 	storeword(' ' | obits, sps);
694 	if (spflg) {
695 		storeword(' ' | obits, sps);
696 		spflg = 0;
697 	}
698 g0:
699 	if (j == CONT) {
700 		pendw = wordp;
701 		nflush = 0;
702 		flushi();
703 		return(1);
704 	}
705 	if (hyoff != 1) {
706 		if (j == ohc) {
707 			hyoff = 2;
708 			*hyp++ = wordp;
709 			if (hyp > hyptr + NHYP - 1)
710 				hyp = hyptr + NHYP - 1;
711 			goto g1;
712 		}
713 		if (((j == '-' || j == EMDASH)) && !(i & ZBIT))	/* zbit avoids \X */
714 			if (wordp > word + 1) {
715 				hyoff = 2;
716 				*hyp++ = wordp + 1;
717 				if (hyp > hyptr + NHYP - 1)
718 					hyp = hyptr + NHYP - 1;
719 			}
720 	}
721 	j = width(i);
722 	numtabp[HP].val += j;
723 	storeword(i, j);
724 g1:
725 	j = cbits(i = GETCH());
726 	if (j != ' ') {
727 		static char *sentchar = ".?!";	/* sentence terminators */
728 		if (j != '\n')
729 			goto g0;
730 		wp = wordp-1;	/* handle extra space at end of sentence */
731 		while (wp >= word) {
732 			j = cbits(*wp--);
733 			if (j=='"' || j=='\'' || j==')' || j==']' || j=='*' || j==DAGGER)
734 				continue;
735 			for (k = 0; sentchar[k]; k++)
736 				if (j == sentchar[k]) {
737 					spflg++;
738 					break;
739 				}
740 			break;
741 		}
742 	}
743 	*wordp = 0;
744 	numtabp[HP].val += sps;
745 rtn:
746 	for (wp = word; *wp; wp++) {
747 		if (ismot(j))
748 			break;	/* drechsler */
749 		j = cbits(*wp);
750 		if (j == ' ')
751 			continue;
752 		if (!(isascii(j) && isdigit(j)) && j != '-')
753 			break;
754 	}
755 	if (*wp == 0)	/* all numbers, so don't hyphenate */
756 		hyoff = 1;
757 	wdstart = 0;
758 	wordp = word;
759 	pendw = 0;
760 	*hyp++ = 0;
761 	setnel();
762 	return(noword);
763 }
764 
765 
storeword(Tchar c,int w)766 void storeword(Tchar c, int w)
767 {
768 	Tchar *savp;
769 	int i;
770 
771 	if (wordp >= word + wdsize - 2) {
772 		wdsize += WDSIZE;
773 		savp = word;
774 		if (( word = (Tchar *)realloc((char *)word, wdsize * sizeof(Tchar))) != NULL) {
775 			if (wordp)
776 				wordp = word + (wordp - savp);
777 			if (pendw)
778 				pendw = word + (pendw - savp);
779 			if (wdstart)
780 				wdstart = word + (wdstart - savp);
781 			if (wdend)
782 				wdend = word + (wdend - savp);
783 			for (i = 0; i < NHYP; i++)
784 				if (hyptr[i])
785 					hyptr[i] = word + (hyptr[i] - savp);
786 		} else {
787 			if (over) {
788 				return;
789 			} else {
790 				flusho();
791 				ERROR "Word overflow." WARN;
792 				over++;
793 				c = LEFTHAND;
794 				w = width(LEFTHAND);
795 			}
796 		}
797 	}
798 	widthp = w;
799 	wne += w;
800 	*wordp++ = c;
801 	wch++;
802 }
803 
804 
gettch(void)805 Tchar gettch(void)
806 {
807 	extern int c_isalnum;
808 	Tchar i;
809 	int j;
810 
811 	if (TROFF)
812 		return getch();
813 
814 	i = getch();
815 	j = cbits(i);
816 	if (ismot(i) || fbits(i) != ulfont)
817 		return(i);
818 	if (cu) {
819 		if (trtab[j] == ' ') {
820 			setcbits(i, '_');
821 			setfbits(i, FT);	/* default */
822 		}
823 		return(i);
824 	}
825 	/* should test here for characters that ought to be underlined */
826 	/* in the old nroff, that was the 200 bit on the width! */
827 	/* for now, just do letters, digits and certain special chars */
828 	if (j <= 127) {
829 		if (!isalnum(j))
830 			setfbits(i, FT);
831 	} else {
832 		if (j < c_isalnum)
833 			setfbits(i, FT);
834 	}
835 	return(i);
836 }
837