1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /*	from OpenSolaris "n7.c	1.10	05/06/08 SMI"	*/
32 
33 /*
34  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
35  *
36  * Sccsid @(#)n7.c	1.181 (gritter) 6/19/11
37  *
38  * Portions Copyright (c) 2014, 2015 Carsten Kunze
39  */
40 
41 /*
42  * University Copyright- Copyright (c) 1982, 1986, 1988
43  * The Regents of the University of California
44  * All Rights Reserved
45  *
46  * University Acknowledgment- Portions of this document are derived from
47  * software developed by the University of California, Berkeley, and its
48  * contributors.
49  */
50 
51 #include <stddef.h>
52 #include <stdlib.h>
53 #include <limits.h>
54 #include "tdef.h"
55 #ifdef NROFF
56 #include "tw.h"
57 #include "draw.h"
58 #endif
59 #include "pt.h"
60 #ifdef NROFF
61 #define GETCH gettch
62 tchar	gettch(void);
63 #endif
64 #ifndef NROFF
65 #define GETCH getch
66 #endif
67 
68 /*
69  * troff7.c
70  *
71  * text
72  */
73 
74 #include <math.h>
75 #include <string.h>
76 #include <ctype.h>
77 #include "ext.h"
78 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
79 wchar_t	cwc, owc, wceoll;
80 #endif /* EUC && NROFF && ZWDELIMS */
81 int	brflg;
82 
83 #undef	iswascii
84 #define	iswascii(c)	(((c) & ~(wchar_t)0177) == 0)
85 
86 static int	_findt(struct d *, int, int);
87 static tchar	adjbit(tchar);
88 static void	sethtdp(void);
89 static void	leftend(tchar, int, int);
90 static void	parword(void);
91 static void	parfmt(void);
92 #ifndef	NROFF
93 #define	nroff		0
94 extern int	lastrst;
95 extern int	lastrsb;
96 static void	setlhang(tchar);
97 static void	setrhang(void);
98 static void	letshrink(void);
99 static int	letgrow(void);
100 static int	lspcomp(int);
101 #else	/* NROFF */
102 #define	nroff		1
103 #define	lastrst		0
104 #define	lastrsb		0
105 #define	setlhang(a)
106 #define	setrhang()
107 #define	getlsp(c)	0
108 #define	storelsp(a, b)
109 #define	getlsh(c, w)	0
110 #define	storelsh(a, b)
111 #define	letshrink()
112 #define	letgrow()	0
113 #define	lspcomp(a)	0
114 #endif	/* NROFF */
115 
116 void
tbreak(void)117 tbreak(void)
118 {
119 	register int pad, k;
120 	register tchar	*i, j, c;
121 	register int resol = 0;
122 	int _minflg;
123 
124 restart:
125 	trap = 0;
126 	if (nb)
127 		return;
128 	if (dip == d && numtab[NL].val == -1) {
129 		newline(1);
130 		return;
131 	}
132 	if (!nc && !pgchars) {
133 		setnel();
134 		if (!wch)
135 			return;
136 		if (pendw)
137 			getword(1);
138 		movword();
139 	} else if (pendw && !brflg) {
140 		getword(1);
141 		movword();
142 	} else if (!brflg && adflg & 1) {
143 		adflg |= 2;
144 		text();
145 		return;
146 	}
147 	if ((pa || padj) && pglines == 0 && pgchars) {
148 		parfmt();
149 		goto restart;
150 	}
151 	if (minspsz && !brflg && ad && !admod)
152 		ne += adspc;
153 	*linep = dip->nls = 0;
154 #ifdef NROFF
155 	if (dip == d)
156 		horiz(po);
157 #endif
158 	if (lnmod)
159 		donum();
160 	lastl = ne;
161 	if (brflg != 1) {
162 		totout = 0;
163 		hlc = 0;
164 	} else if (ad) {
165 		if ((lastl = ll - un + rhang + lsplast) < ne)
166 			lastl = ne;
167 	}
168 	if (admod && ad && (brflg != 2)) {
169 		lastl = ne;
170 		adsp = adrem = 0;
171 		if (admod == 1)
172 			un +=  quant(nel / 2, HOR);
173 		else if (admod == 2)
174 			un += nel;
175 	}
176 	_minflg = minspsz && admod == 0 && ad && brflg == 1 && adflg & 4;
177 	totout++;
178 	brflg = 0;
179 	if (lastl + un > dip->maxl)
180 		dip->maxl = lastl + un;
181 	horiz(un);
182 	if (un != 0)
183 		pchar(mkxfunc(INDENT, un));
184 #ifdef NROFF
185 	if (adrem % t.Adj)
186 		resol = t.Hor;
187 	else
188 		resol = t.Adj;
189 #else
190 	resol = HOR;
191 #endif
192 	adrem = (adrem / resol) * resol;
193 	for (i = line; nc > 0; ) {
194 		if ((c = cbits(j = *i++)) == ' ' || c == STRETCH) {
195 			if ((xflag && !fi && dilev) || iszbit(j) || isadjspc(j))
196 				goto std;
197 			pad = 0;
198 			if (i > &line[1])
199 				pad += kernadjust(i[-2], i[-1]);
200 			do {
201 				if (xflag)
202 					pchar(adjbit(j));
203 				minflg = _minflg;
204 				pad += width(j);
205 				nc--;
206 			} while ((c = cbits(j = *i++)) == ' ' || c == STRETCH);
207 			pad += kernadjust(i[-2], i[-1]);
208 			i--;
209 			pad += adsp;
210 			--nwd;
211 			if (adrem) {
212 				if (adrem < 0) {
213 					pad -= resol;
214 					adrem += resol;
215 				} else if ((totout & 01) || adrem / resol >= nwd) {
216 					pad += resol;
217 					adrem -= resol;
218 				}
219 			}
220 			pchar((tchar) WORDSP);
221 			horiz(pad);
222 		} else {
223 		std:
224 			if (!ismot(j) && isxfunc(j, FLDMARK))
225 				fldcnt--;
226 			else if (fldcnt == 0 && nc && !ismot(j) &&
227 					!iszbit(j)) {
228 				if (lspcur && (cbits(j) > ' ' ||
229 							isxfunc(j, CHAR))) {
230 					for (c = j; isxfunc(c, CHAR);
231 						c = charout[sbits(c)].ch);
232 					k = (int)sbits(c) / 2 * lspcur / LAFACT;
233 					if (k >= 0)
234 						c = mkxfunc(LETSP, k);
235 					else
236 						c = mkxfunc(NLETSP, -k);
237 					pchar(c);
238 				}
239 				if (lshcur && cbits(j) > ' ') {
240 					k = lshcur;
241 					if (k >= 0)
242 						c = mkxfunc(LETSH, k);
243 					else
244 						c = mkxfunc(NLETSH, -k);
245 					pchar(c);
246 				}
247 			}
248 			pchar(j);
249 			nc--;
250 		}
251 	}
252 	if (hlc)
253 		pchar(mkxfunc(HYPHED, 0));
254 	if (ic) {
255 		if ((k = ll - un - lastl + ics) > 0)
256 			horiz(k);
257 		pchar(ic);
258 	}
259 	if (icf)
260 		icf++;
261 	else
262 		ic = 0;
263 	ne = nwd = 0;
264 	un = in;
265 	setnel();
266 	newline(0);
267 	if (dip != d) {
268 		if (dip->dnl > dip->hnl)
269 			dip->hnl = dip->dnl;
270 	} else {
271 		if (numtab[NL].val > dip->hnl)
272 			dip->hnl = numtab[NL].val;
273 	}
274 	for (k = ls - 1; k > 0 && !trap; k--)
275 		newline(0);
276 	spread = 0;
277 	spbits = 0;
278 }
279 
280 void
donum(void)281 donum(void)
282 {
283 	register int i, nw;
284 
285 	nrbits = nmbits;
286 	nw = width('1' | nrbits);
287 	if (nn) {
288 		nn--;
289 		goto d1;
290 	}
291 	if (numtab[LN].val % ndf) {
292 		numtab[LN].val++;
293 d1:
294 		un += nw * (3 + nms + ni);
295 		return;
296 	}
297 	i = 0;
298 	if (numtab[LN].val < 100)
299 		i++;
300 	if (numtab[LN].val < 10)
301 		i++;
302 	horiz(nw * (ni + i));
303 	nform = 0;
304 	fnumb(numtab[LN].val, pchar);
305 	un += nw * nms;
306 	numtab[LN].val++;
307 }
308 
309 void
text(void)310 text(void)
311 {
312 	register tchar i, c, lasti = 0;
313 	int	k = 0;
314 	static int	spcnt;
315 	int	recadj = 0;
316 
317 	if (adflg & 2) {
318 		adflg &= ~3;
319 		recadj = 1;
320 		goto adj;
321 	}
322 	adflg = 0;
323 	nflush++;
324 	numtab[HP].val = 0;
325 	if ((dip == d) && (numtab[NL].val == -1)) {
326 		newline(1);
327 		goto r;
328 	}
329 	setnel();
330 	if (ce || rj || !fi) {
331 		nofill();
332 		goto r;
333 	}
334 	if (pendw)
335 		goto t4;
336 	if (pendt) {
337 		if (spcnt)
338 			goto t2;
339 		else
340 			goto t3;
341 	}
342 	pendt++;
343 	if (spcnt)
344 		goto t2;
345 	while ((c = cbits(i = GETCH())) == ' ' || c == STRETCH) {
346 		if (iszbit(i))
347 			break;
348 		if (isadjspc(i))
349 			continue;
350 		spcnt++;
351 		widthp = xflag ? width(i) : sps;
352 		sethtdp();
353 		numtab[HP].val += widthp;
354 		lasti = i;
355 	}
356 	if (lasti) {
357 		k = kernadjust(lasti, i);
358 		numtab[HP].val += k;
359 		widthp += k;
360 	}
361 	if (nlflg) {
362 t1:
363 		nflush = pendt = ch = spcnt = 0;
364 		callsp();
365 		goto r;
366 	}
367 	ch = i;
368 	if (spcnt) {
369 t2:
370 		lsn = spcnt;
371 		glss = spcnt * sps + k;
372 		if (lsmac) {
373 			spcnt = 0;
374 			control(lsmac, 0);
375 			goto rtn;
376 		} else {
377 		tbreak();
378 		if (nc || wch)
379 			goto rtn;
380 		un += glss;
381 		spcnt = 0;
382 		setnel();
383 		if (trap)
384 			goto rtn;
385 		if (nlflg)
386 			goto t1;
387 		}
388 	}
389 t3:
390 	if (spread && !brpnl)
391 		goto t5;
392 	if (pendw || !wch)
393 t4:
394 		if (getword(0)) {
395 			if (!pendw) {
396 				if (brnl || (brpnl && spread))
397 					goto tb;
398 				if (brpnl)
399 					goto t5;
400 			}
401 			goto t6;
402 		}
403 	if (!movword())
404 		goto t3;
405 t5:
406 	if (nlflg)
407 		pendt = 0;
408 adj:
409 	adsp = adrem = 0;
410 	if (ad) {
411 		setrhang();
412 		if (admod == 0 && lspcur == 0 && lshcur == 0 &&
413 				nel < 0 && lspnc)
414 			letshrink();
415 	jst:	if (nwd == 1)
416 			adsp = nel;
417 		else
418 			adsp = nel / (nwd - 1);
419 		adsp = (adsp / HOR) * HOR;
420 		if (admod == 0 && lspcur == 0 && lshcur == 0 &&
421 				adsp > letsps - sps)
422 			if (letgrow())
423 				goto jst;
424 		adrem = nel - adsp*(nwd-1);
425 		if (admod == 0 && nwd == 1 && warn & WARN_BREAK)
426 			errprint("can't break line");
427 		else if (admod == 0 && spreadwarn && adsp >= spreadlimit)
428 			errprint("spreadlimit exceeded, %gm", (double)adsp/EM);
429 	}
430 	brflg = 1;
431 tb:
432 	tbreak();
433 	spread = 0;
434 	if (!trap && !recadj && !brnl && !brpnl)
435 		goto t3;
436 	if (brnl > 0 && brnl < INT_MAX)
437 		brnl--;
438 	if (brpnl > 0 && brpnl < INT_MAX)
439 		brpnl--;
440 	if (!nlflg)
441 		goto rtn;
442 t6:
443 	pendt = 0;
444 	ckul();
445 rtn:
446 	nflush = 0;
447 r:
448 	if (chomp) {
449 		chomp = 0;
450 		chompend = 1;
451 	}
452 }
453 
454 
455 void
nofill(void)456 nofill(void)
457 {
458 	register int j;
459 	register tchar i, nexti;
460 	int k, oev;
461 
462 	if (chompend) {
463 		chompend = 0;
464 	} else if (!pendnf && !chomp) {
465 		over = 0;
466 		tbreak();
467 		if (trap)
468 			goto rtn;
469 		if (nlflg) {
470 			ch = nflush = 0;
471 			callsp();
472 			return;
473 		}
474 		adsp = adrem = 0;
475 		nwd = 10000;
476 	}
477 	nexti = GETCH();
478 	leftend(nexti, !ce && !rj && !pendnf, !isdi(nexti));
479 	while ((j = (cbits(i = nexti))) != '\n') {
480 		if (stopch && issame(i, stopch))
481 			break;
482 		if (j == ohc) {
483 			nexti = GETCH();
484 			continue;
485 		}
486 		if (j == CONT) {
487 			pendnf++;
488 			nflush = 0;
489 			flushi();
490 			ckul();
491 			return;
492 		}
493 		j = width(i);
494 		widthp = j;
495 		sethtdp();
496 		numtab[HP].val += j;
497 		storeline(i, j);
498 		oev = ev;
499 		nexti = GETCH();
500 		if (ev == oev) {
501 			k = kernadjust(i, nexti);
502 			ne += k;
503 			nel -= k;
504 			numtab[HP].val += k;
505 		}
506 	}
507 	if (chomp) {
508 		return;
509 	}
510 	if (ce) {
511 		ce--;
512 		if ((i = quant(nel / 2, HOR)) > 0)
513 			un += i;
514 	}
515 	if (rj) {
516 		rj--;
517 		setrhang();
518 		if (nel > 0)
519 			un += nel;
520 	}
521 	if (!nc)
522 		storeline((tchar)FILLER, 0);
523 	brflg = 2;
524 	tbreak();
525 	ckul();
526 rtn:
527 	pendnf = nflush = 0;
528 }
529 
530 
531 void
callsp(void)532 callsp(void)
533 {
534 	register int i;
535 
536 	if (flss)
537 		i = flss;
538 	else
539 		i = lss;
540 	flss = 0;
541 	if (blmac && (fi || (frame->flags & FLAG_DIVERSION) == 0))
542 		control(blmac, 0);
543 	else
544 		casesp(i);
545 }
546 
547 
548 void
ckul(void)549 ckul(void)
550 {
551 	if (ul && (--ul == 0)) {
552 		cu = 0;
553 		font = sfont;
554 		mchbits();
555 	}
556 	if (it && !pglines && (!itc || (!pendw && !pendnf)) &&
557 			(--it == 0) && itmac)
558 		control(itmac, 0);
559 }
560 
561 
562 int
storeline(register tchar c,int w)563 storeline(register tchar c, int w)
564 {
565 #ifdef NROFF
566 	if (ismot(c)) {
567 		if (isvmot(c)) {
568 			if (isnmot(c))
569 				lvmot -= c & BMBITS;
570 			else
571 				lvmot += c & BMBITS;
572 		}
573 	} else if (ndraw && !(cbits(c) & ~0xffff)) {
574 		storechar(c, numtab[NL].val+lvmot, po + in + ne);
575 	}
576 #endif
577 	if (linep == NULL || linep >= line + lnsize - 4) {
578 		tchar	*k;
579 		if (over)
580 			return 0;
581 		lnsize += lnsize ? 100 : LNSIZE;
582 		if ((k = realloc(line, lnsize * sizeof *line)) == NULL) {
583 			flusho();
584 			errprint("Line overflow.");
585 			over++;
586 			c = LEFTHAND;
587 			w = -1;
588 			goto s1;
589 		}
590 		linep = (tchar *)((char *)linep + ((char *)k - (char *)line));
591 		line = k;
592 	}
593 s1:
594 	if (w == -1) {
595 		minflg = minspsz && ad && !admod;
596 		w = width(c);
597 	}
598 	ne += w;
599 	nel -= w;
600 	*linep++ = c;
601 	nc++;
602 	return 1;
603 }
604 
605 
606 #ifndef	NROFF
607 static int
getlsp(tchar c)608 getlsp(tchar c)
609 {
610 	int	s;
611 
612 	if (!ad || admod || ismot(c))
613 		return 0;
614 	if (iszbit(c) || (cbits(c) <= ' ' && !isxfunc(c, CHAR)))
615 		return 0;
616 	while (isxfunc(c, CHAR))
617 		c = charout[sbits(c)].ch;
618 	s = sbits(c) / 2;
619 	return s;
620 }
621 
622 static void
storelsp(tchar c,int neg)623 storelsp(tchar c, int neg)
624 {
625 	int	s;
626 
627 	if (isxfunc(c, FLDMARK)) {
628 		lsplow = lsphigh = lspnc = 0;
629 		fldcnt += neg ? -1 : 1;
630 		return;
631 	}
632 	if ((s = getlsp(c)) != 0) {
633 		if (neg)
634 			s = -s;
635 		lsplow += s * lspmin / LAFACT;
636 		lsphigh += s * lspmax / LAFACT;
637 		lspnc += neg ? -1 : 1;
638 	}
639 }
640 
641 static int
getlsh(tchar c,int w)642 getlsh(tchar c, int w)
643 {
644 	if (!ad || admod || ismot(c))
645 		return 0;
646 	if (iszbit(c) || cbits(c) <= ' ')
647 		return 0;
648 	return w;
649 }
650 
651 static void
storelsh(tchar c,int w)652 storelsh(tchar c, int w)
653 {
654 	int	s;
655 
656 	if (isxfunc(c, FLDMARK)) {
657 		lshlow = lshhigh = lshwid = 0;
658 		return;
659 	}
660 	if ((s = getlsh(c, w)) != 0) {
661 		lshwid += s;
662 		lshlow = lshwid * lshmin / LAFACT;
663 		lshhigh = lshwid * lshmax / LAFACT;
664 	}
665 }
666 #endif	/* !NROFF */
667 
668 void
newline(int a)669 newline(int a)
670 {
671 	register int i, j, nlss = 0, nl;
672 	int	opn;
673 
674 #ifdef NROFF
675 	if (lvmot) {
676 		tchar c;
677 		c = MOT | VMOT | (lvmot < 0 ? -lvmot : lvmot | NMOT);
678 		pchar1(c);
679 		lvmot = 0;
680 	}
681 #endif
682 	if (a)
683 		goto nl1;
684 	if (dip != d) {
685 		j = lss;
686 		pchar1((tchar)FLSS);
687 		if (flss)
688 			lss = flss;
689 		i = nlss = lss + dip->blss;
690 		dip->dnl += i;
691 		pchar1((tchar)i);
692 		pchar1((tchar)'\n');
693 		lss = j;
694 		dip->blss = flss = 0;
695 		if (dip->alss) {
696 			pchar1((tchar)FLSS);
697 			pchar1((tchar)dip->alss);
698 			pchar1((tchar)'\n');
699 			dip->dnl += dip->alss;
700 			nlss += dip->alss;
701 			dip->alss = 0;
702 		}
703 		if (vpt > 0 && dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && dip->dimac)
704 			if (control(dip->dimac, 0)) {
705 				trap++;
706 				dip->ditf++;
707 			}
708 		goto nlt;
709 	}
710 	j = lss;
711 	if (flss)
712 		lss = flss;
713 	nlss = dip->alss + dip->blss + lss;
714 	numtab[NL].val += nlss;
715 #ifndef NROFF
716 	if (ascii) {
717 		dip->alss = dip->blss = 0;
718 	}
719 #endif
720 	pchar1((tchar)'\n');
721 	flss = 0;
722 	lss = j;
723 	if (vpt == 0 || numtab[NL].val < pl)
724 		goto nl2;
725 nl1:
726 	ejf = dip->hnl = numtab[NL].val = 0;
727 	ejl = frame->tail_cnt;
728 	if (donef || (ndone && pgchars && !pglines)) {
729 		if ((!nc && !wch && !pglines) || ndone)
730 			done1(0);
731 		ndone++;
732 		donef = 0;
733 		if (frame == stk)
734 			nflush++;
735 	}
736 	opn = numtab[PN].val;
737 	numtab[PN].val++;
738 	if (npnflg) {
739 		numtab[PN].val = npn;
740 		npn = npnflg = 0;
741 	}
742 	prwatchn(&numtab[PN]);
743 nlpn:
744 	if (numtab[PN].val == pfrom) {
745 		print++;
746 		pfrom = -1;
747 	} else if (opn == pto) {
748 		print = 0;
749 		opn = -1;
750 		chkpn();
751 		goto nlpn;
752 	}
753 	if (print)
754 		newpage(numtab[PN].val);	/* supposedly in a clean state so can pause */
755 	if (stop && print) {
756 		dpn++;
757 		if (dpn >= stop) {
758 			dpn = 0;
759 			dostop();
760 		}
761 	}
762 nl2:
763 	trap = 0;
764 nlt:
765 	if (dip != d)
766 		nl = dip->dnl;
767 	else
768 		nl = numtab[NL].val;
769 	if (vpt <= 0)
770 		/*EMPTY*/;
771 	else if (nl == 0) {
772 		if ((j = findn(dip, 0)) != NTRAP)
773 			trap |= control(dip->mlist[j], 0);
774 	} else if ((i = _findt(dip, nl - nlss, 0)) <= nlss) {
775 		if ((j = findn1(dip, nl - nlss + i)) == NTRAP) {
776 			flusho();
777 			errprint("Trap botch.");
778 			done2(-5);
779 		}
780 		trap |= control(dip->mlist[j], 0);
781 	}
782 	if (nolt && dip == d) {
783 		for (i = nolt - 1; i >= 0; i--)
784 			trap |= control(olt[i], 0);
785 		nolt = 0;
786 		free(olt);
787 		olt = NULL;
788 	}
789 }
790 
791 
792 int
findn1(struct d * dp,int a)793 findn1(struct d *dp, int a)
794 {
795 	register int i, j;
796 
797 	for (i = 0; i < NTRAP; i++) {
798 		if (dp->mlist[i]) {
799 			if ((j = dp->nlist[i]) < 0 && dp == d)
800 				j += pl;
801 			if (j == a)
802 				break;
803 		}
804 	}
805 	return(i);
806 }
807 
808 
809 void
chkpn(void)810 chkpn(void)
811 {
812 	pto = *(pnp++);
813 	pfrom = pto>=0 ? pto : -pto;
814 	if (pto == -32767) {
815 		flusho();
816 		done1(0);
817 	}
818 	if (pto < 0) {
819 		pto = -pto;
820 		print++;
821 		pfrom = 0;
822 	}
823 }
824 
825 
826 int
findt(struct d * dp,int a)827 findt(struct d *dp, int a)
828 {
829 	return _findt(dp, a, 1);
830 }
831 
832 static int
_findt(struct d * dp,int a,int maydi)833 _findt(struct d *dp, int a, int maydi)
834 {
835 	register int i, j, k;
836 
837 	k = INT_MAX;
838 	if (dip != d && maydi) {
839 		if (dip->dimac && (i = dip->ditrap - a) > 0)
840 			k = i;
841 	}
842 	for (i = 0; i < NTRAP; i++) {
843 		if (dp->mlist[i]) {
844 			if ((j = dp->nlist[i]) < 0 && dp == d)
845 				j += pl;
846 			if ((j -= a) <= 0)
847 				continue;
848 			if (j < k)
849 				k = j;
850 		}
851 	}
852 	if (dp == d) {
853 		i = pl - a;
854 		if (k > i)
855 			k = i;
856 	}
857 	return(k);
858 }
859 
860 
861 int
findt1(void)862 findt1(void)
863 {
864 	register int i;
865 
866 	if (dip != d)
867 		i = dip->dnl;
868 	else
869 		i = numtab[NL].val;
870 	return(findt(dip, i));
871 }
872 
873 
874 void
eject(struct s * a)875 eject(struct s *a)
876 {
877 	register int savlss;
878 
879 #ifdef NROFF
880 	if (ndraw) npic(0);
881 #endif
882 	if (dip != d)
883 		return;
884 	if (vpt == 0) {
885 		if (donef == 0) {
886 			errprint("page not ejected because traps are disabled");
887 			return;
888 		}
889 		errprint("page forcefully ejected although traps are disabled");
890 		vpt = -1;
891 	}
892 	ejf++;
893 	if (a)
894 		ejl = a->tail_cnt;
895 	else
896 		ejl = frame->tail_cnt;
897 	if (trap)
898 		return;
899 e1:
900 	savlss = lss;
901 	lss = findt(d, numtab[NL].val);
902 	newline(0);
903 	lss = savlss;
904 	if (numtab[NL].val && !trap)
905 		goto e1;
906 }
907 
908 
909 static int
maybreak(tchar c,int dv)910 maybreak(tchar c, int dv)
911 {
912 	int	i, k = cbits(c);
913 
914 	if (c & BLBIT)
915 		return 1;
916 	if (iszbit(c))
917 		return 0;
918 	switch (breakch[0]) {
919 	case IMP:
920 		return 0;
921 	case 0:
922 		return (!gemu || dv) && (k == '-' || k == EMDASH);
923 	default:
924 		for (i = 0; breakch[i] && i < NSENT; i++)
925 			if (breakch[i] == k)
926 				return 1;
927 		return 0;
928 	}
929 }
930 
931 static int
nhychar(tchar c)932 nhychar(tchar c)
933 {
934 	int	i, k = cbits(c);
935 
936 	switch (nhych[0]) {
937 	case IMP:
938 		return 0;
939 	case 0:
940 		if (hyext)
941 			return 0;
942 		return k == '-' || k == EMDASH;
943 	default:
944 		for (i = 0; nhych[i] && i < NSENT; i++)
945 			if (nhych[i] == k)
946 				return 1;
947 		return 0;
948 	}
949 }
950 
951 static int
ishyp(tchar * wp)952 ishyp(tchar *wp)
953 {
954 	tchar	*tp;
955 	int	yes = 0;
956 
957 	tp = (tchar *)((intptr_t)*hyp & ~(intptr_t)03);
958 	if (hyoff != 1 && tp == wp && !iszbit(*wp)) {
959 		if (!wdstart || (wp > wdstart + 1 && wp < wdend &&
960 		   (!(wdhyf & 04) || wp < wdend - 1) &&		/* 04 => last 2 */
961 		   (!(wdhyf & 010) || wp > wdstart + 2)) ||	/* 010 => 1st 2 */
962 		   (wdhyf & 020 && wp == wdend) ||		/* 020 = allow last */
963 		   (wdhyf & 040 && wp == wdstart + 1))		/* 040 = allow first */
964 			yes = 1;
965 		hyp++;
966 	}
967 	return yes;
968 }
969 
970 
971 int
movword(void)972 movword(void)
973 {
974 	register int w;
975 	register tchar i, *wp, c, *lp, *lastlp, lasti = 0;
976 	int	savwch, hys, stretches = 0, wholewd = 0, mnel, hyphenated = 0;
977 	int	hc;
978 #ifndef	NROFF
979 	tchar	lgs = 0, lge = 0, optlgs = 0, optlge = 0;
980 	int	*ip, s, lgw = 0, optlgw = 0, lgr = 0, optlgr = 0;
981 	tchar	*optlinep = NULL, *optwp = NULL;
982 	int	optnc = 0, optnel = 0, optne = 0, optadspc = 0, optwne = 0,
983 		optwch = 0, optwholewd = 0,
984 		optlsplow = 0, optlsphigh = 0, optlspnc = 0, optfldcnt = 0,
985 		optlshwid = 0, optlshlow = 0, optlshhigh = 0;
986 #else	/* NROFF */
987 #define	lgw	0
988 #define	optlinep	0
989 #endif	/* NROFF */
990 
991 	if (pa || padj) {
992 		parword();
993 		return(0);
994 	}
995 	over = 0;
996 	wp = wordp;
997 	if (!nwd) {
998 		while ((c = cbits(i = *wp++)) == ' ') {
999 			if (iszbit(i))
1000 				break;
1001 			wch--;
1002 			wne -= xflag ? width(i) : sps;
1003 			if (xflag && linep > line)
1004 				storeline(adjbit(i), 0);
1005 		}
1006 		wp--;
1007 		if (wp > wordp)
1008 			wne -= kernadjust(wp[-1], wp[0]);
1009 		leftend(*wp, admod != 1 && admod != 2, 1);
1010 	}
1011 	if (wdhyf == -1)
1012 		wdhyf = hyf;
1013 	wsp = 0;
1014 	if (wne > nel - adspc && !hyoff && wdhyf && (hlm < 0 || hlc < hlm) &&
1015 	   (!nwd || nel + lsplow + lshlow - adspc >
1016 	    3 * (minsps && ad && !admod ? minsps : sps)) &&
1017 	   (!(wdhyf & 02) || (findt1() > lss)))
1018 		hyphen(wp);
1019 	savwch = wch;
1020 	hyp = hyptr;
1021 	nhyp = 0;
1022 	while (*hyp && *hyp <= wp)
1023 		hyp++;
1024 	while (wch) {
1025 		if (ishyp(wp)) {
1026 			i = IMP;
1027 			setsbits(i, (intptr_t)(hyp[-1]) & 03);
1028 			if (storeline(i, 0))
1029 				nhyp++;
1030 		}
1031 		i = *wp++;
1032 		minflg = minspsz && ad && !admod;
1033 		w = width(i);
1034 		storelsh(i, rawwidth);
1035 		adspc += minspc;
1036 		w += kernadjust(i, *wp);
1037 		wne -= w;
1038 		wch--;
1039 		if (cbits(i) == STRETCH && cbits(lasti) != STRETCH)
1040 			stretches++;
1041 		lasti = i;
1042 		storeline(i, w);
1043 		if (letsps)
1044 			storelsp(i, 0);
1045 	}
1046 	*linep = *wp;
1047 	lastlp = linep;
1048 	mnel = ad && !admod ? (sps - minsps) * nwd : 0;
1049 	if (nel >= 0 || (nel + lsplow + lshlow >= 0 &&
1050 			lspnc - (nwd ? nwd : 1) > 0)) {
1051 		if ((nel >= 0 && nwd && nel - adspc < 0 && nel / nwd < sps) ||
1052 				(nel < 0 && nel + lsplow + lshlow >= 0)) {
1053 			wholewd = 1;
1054 			goto m0;
1055 		}
1056 		nwd += stretches + 1;
1057 		if (nel - adspc < 0 && nwd > 1)
1058 			adflg |= 5;
1059 		w = kernadjust(lasti,  ' ' | (spbits?spbits:sfmask(lasti)));
1060 		ne += w;
1061 		nel -= w;
1062 		return(0);	/* line didn't fill up */
1063 	}
1064 m0:
1065 	hc = shc ? shc : HYPHEN;
1066 #ifndef NROFF
1067 	xbits((tchar)hc, 1);
1068 #endif
1069 	hys = width((tchar)hc);
1070 	if (wholewd)
1071 		goto m1a;
1072 m1:
1073 	if (!nhyp) {
1074 		if (!nwd)
1075 			goto m3;
1076 		if (wch == savwch) {
1077 			if (optlinep)
1078 				goto m2;
1079 			goto m4;
1080 		}
1081 	}
1082 	if ((*--linep & ~SMASK) != IMP)
1083 		goto m5;
1084 #ifndef	NROFF
1085 	i = *(linep + 1);
1086 	if ((s = sbits(*linep)) != 0 &&
1087 			(ip = lgrevtab[fbits(i)][cbits(i)]) != NULL) {
1088 		lgs = strlg(fbits(i), ip, s) | sfmask(i) | AUTOLIG;
1089 		for (w = 0; ip[s+w]; w++);
1090 		lge = strlg(fbits(i), &ip[s], w) | sfmask(i) | AUTOLIG;
1091 		lgw = width(lgs);
1092 		lgr = rawwidth;
1093 		if (linep - 1 >= wordp) {
1094 			lgw += kernadjust(i, *(linep - 1));
1095 			lgw -= kernadjust(*(linep + 1), *(linep - 1));
1096 		}
1097 	} else {
1098 		lgs = 0;
1099 		lge = 0;
1100 		lgw = 0;
1101 	}
1102 #endif	/* !NROFF */
1103 	if (!(--nhyp))
1104 		if (!nwd)
1105 			goto m2;
1106 	if (nel + lsplow + lshlow < hys + lgw) {
1107 		nc--;
1108 		goto m1;
1109 	}
1110 	if (nel >= mnel + hys + lgw)
1111 		goto m2;
1112 	wholewd = 0;
1113 m1a:
1114 #ifndef	NROFF
1115 	if ((minspsz && ad && !admod &&
1116 			wch < savwch && nwd && nel / nwd > 0 && nel < mnel) ||
1117 			(nel + lsplow + lshlow >= (wholewd ? 0 : hys + lgw) &&
1118 			nel < (wholewd ? 0 : hys + lgw))) {
1119 		optlgs = lgs, optlge = lge, optlgw = lgw, optlgr = lgr;
1120 		optlinep = linep, optwp = wp, optnc = nc, optnel = nel,
1121 		optne = ne, optadspc = adspc, optwne = wne, optwch = wch;
1122 		optlsplow = lsplow, optlsphigh = lsphigh, optlspnc = lspnc;
1123 		optfldcnt = fldcnt;
1124 		optlshwid = lshwid, optlshlow = lshlow, optlshhigh = lshhigh;
1125 		optwholewd = wholewd;
1126 		nc -= !wholewd;
1127 		goto m1;
1128 	} else if (wholewd) {
1129 		wholewd = 0;
1130 		goto m1;
1131 	}
1132 #endif
1133 m2:
1134 #ifndef	NROFF
1135 	if (optlinep && 3*abs(optnel - mnel) < 5*abs(nel - mnel)) {
1136 		lgs = optlgs, lge = optlge, lgw = optlgw, lgr = optlgr;
1137 		linep = optlinep, wp = optwp, nc = optnc, nel = optnel,
1138 		ne = optne, adspc = optadspc, wne = optwne, wch = optwch;
1139 		lsplow = optlsplow, lsphigh = optlsphigh, lspnc = optlspnc;
1140 		fldcnt = optfldcnt;
1141 		lshwid = optlshwid, lshlow = optlshlow, lshhigh = optlshhigh;
1142 		if ((wholewd = optwholewd))
1143 			goto m3;
1144 	} else if (optlinep && wch == savwch && !nhyp)
1145 		goto m4;
1146 	if (lgs != 0) {
1147 		*wp = lge;
1148 		storeline(lgs, lgw);
1149 		storelsh(lgs, lgr);
1150 	}
1151 #endif	/* !NROFF */
1152 	if (!maybreak(*(linep - 1), 1)) {
1153 		*linep = sfmask(*(linep - 1)) | hc;
1154 		w = -kernadjust(*(linep - 1), *(linep + 1));
1155 		w += kernadjust(*(linep - 1), *linep);
1156 		w += width(*linep);
1157 		storelsh(*linep, rawwidth);
1158 		w += kernadjust(*linep, ' ' | sfmask(*linep));
1159 		nel -= w;
1160 		ne += w;
1161 		if (letsps)
1162 			storelsp(*linep, 0);
1163 		linep++;
1164 		hyphenated++;
1165 	}
1166 m3:
1167 	nwd++;
1168 m4:
1169 	if (letsps && linep > line)
1170 		storelsp(linep[-1], 1);
1171 	adflg &= ~1;
1172 	adflg |= 4;
1173 	wordp = wp;
1174 	if (hyphenated)
1175 		hlc++;
1176 	else
1177 		hlc = 0;
1178 	return(1);	/* line filled up */
1179 m5:
1180 	nc--;
1181 	minflg = minspsz && ad && !admod;
1182 	w = width(*linep);
1183 	storelsh(*linep, -rawwidth);
1184 	adspc -= minspc;
1185 	for (lp = &linep[1]; lp < lastlp && cbits(*lp) == IMP; lp++);
1186 	w += kernadjust(*linep, *lp ? *lp : ' ' | sfmask(*linep));
1187 	ne -= w;
1188 	nel += w;
1189 	wne += w;
1190 	wch++;
1191 	wp--;
1192 	if (letsps)
1193 		storelsp(*linep, 1);
1194 	goto m1;
1195 }
1196 
1197 
1198 void
horiz(int i)1199 horiz(int i)
1200 {
1201 	vflag = 0;
1202 	if (i)
1203 		pchar(makem(i));
1204 }
1205 
1206 
1207 void
setnel(void)1208 setnel(void)
1209 {
1210 	if (!nc) {
1211 		linep = line;
1212 		if (un1 >= 0 && (!pgwords || pglines)) {
1213 			un = un1;
1214 			un1 = -1;
1215 		}
1216 		nel = ll - un;
1217 		rhang = ne = adsp = adrem = adspc = 0;
1218 #ifndef	NROFF
1219 		lsplow = lsphigh = lspcur = lsplast = lspnc = fldcnt = 0;
1220 		lshwid = lshhigh = lshlow = lshcur = 0;
1221 #endif	/* !NROFF */
1222 		cht = cdp = 0;
1223 	}
1224 }
1225 
1226 
1227 int
getword(int x)1228 getword(int x)
1229 {
1230 	register int j, k = 0, w;
1231 	register tchar i = 0, *wp, nexti, gotspc = 0, t;
1232 	int noword, n, inword = 0;
1233 	int lastsp = ' ';
1234 	static int dv;
1235 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1236 	wchar_t *wddelim;
1237 	char mbbuf3[MB_LEN_MAX + 1];
1238 	char *mbbuf3p;
1239 	int wbf;
1240 	tchar m;
1241 #endif /* EUC && NROFF && ZWDELIMS */
1242 
1243 	dv = 0;
1244 	noword = 0;
1245 	if (x)
1246 		if (pendw) {
1247 			*pendw = 0;
1248 			goto rtn;
1249 		}
1250 	if ((wordp = pendw))
1251 		goto g1;
1252 	hyp = hyptr;
1253 	wordp = word;
1254 	over = wne = wch = 0;
1255 	hyoff = 0;
1256 	wdhyf = -1;
1257 	memset(wdpenal, 0, wdsize * sizeof *wdpenal);
1258 	n = 0;
1259 	while (1) {	/* picks up 1st char of word */
1260 		j = cbits(i = GETCH());
1261 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1262 		if (multi_locale)
1263 			collectmb(i);
1264 #endif /* EUC && NROFF && ZWDELIMS */
1265 		if (j == '\n') {
1266 			wne = wch = 0;
1267 			noword = 1;
1268 			goto rtn;
1269 		}
1270 		if (j == ohc) {
1271 			hyoff = 1;	/* 1 => don't hyphenate */
1272 			continue;
1273 		}
1274 		if ((j == ' ' || (padj && j == STRETCH)) && !iszbit(i)) {
1275 			lastsp = j;
1276 			n++;
1277 			if (isadjspc(i))
1278 				w = 0;
1279 			else if (xflag && seflg && sesspsz == 0) {
1280 				i |= ZBIT;
1281 				w = 0;
1282 			} else if (xflag && seflg && sesspsz && n == 1) {
1283 				if (spbits) {
1284 					i = lastsp | SENTSP | spbits;
1285 					w = width(i);
1286 				} else
1287 					w = ses;
1288 			} else if (spbits && xflag) {
1289 				i = lastsp | spbits;
1290 				w = width(i);
1291 			} else
1292 				w = sps;
1293 			cht = cdp = 0;
1294 			storeword(i, w);
1295 			numtab[HP].val += w;
1296 			if (!isadjspc(j)) {
1297 				widthp = w;
1298 				gotspc = i;
1299 				spbits = sfmask(i);
1300 			}
1301 			continue;
1302 		}
1303 		if (gotspc) {
1304 			k = kernadjust(gotspc, i);
1305 			numtab[HP].val += k;
1306 			wne += k;
1307 			widthp += k;
1308 		}
1309 		break;
1310 	}
1311 	seflg = 0;
1312 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1313 	if (!multi_locale)
1314 		goto a0;
1315 	if (wddlm && iswprint(wceoll) && iswprint(cwc) &&
1316 	    (!iswascii(wceoll) || !iswascii(cwc)) &&
1317 	    !iswspace(wceoll) && !iswspace(cwc)) {
1318 		wddelim = (*wddlm)(wceoll, cwc, 1);
1319 		wceoll = 0;
1320 		if (*wddelim != ' ') {
1321 			if (!*wddelim) {
1322 				storeword(((*wdbdg)(wceoll, cwc, 1) < 3) ?
1323 					  ZWDELIM(1) : ZWDELIM(2), 0);
1324 			} else {
1325 				while (*wddelim) {
1326 					if ((n = wctomb(mbbuf3, *wddelim++))
1327 					    > 0) {
1328 						m = setuc0(wddelim[-1]);
1329 						storeword(m, -1);
1330 					} else {
1331 						storeword(' ' | chbits, sps);
1332 						break;
1333 					}
1334 				}
1335 			}
1336 			spflg = 0;
1337 			goto g0;
1338 		}
1339 	}
1340 a0:
1341 #endif /* EUC && NROFF && ZWDELIMS */
1342 	if (spbits && xflag) {
1343 		t = lastsp | spbits;
1344 		w = width(t);
1345 	} else {
1346 		t = lastsp | chbits;
1347 		w = sps;
1348 	}
1349 	cdp = cht = 0;
1350 	if (chompend) {
1351 		chompend = 0;
1352 	} else {
1353 		storeword(t, w + k);
1354 	}
1355 	if (spflg) {
1356 		if (xflag == 0 || ses != 0)
1357 			storeword(t | SENTSP, ses);
1358 		spflg = 0;
1359 	}
1360 	if (!nwd)
1361 		wsp = wne;
1362 g0:
1363 	if (ninlev)
1364 		wdhyf = hyf;
1365 	if (j == CONT) {
1366 		pendw = wordp;
1367 		nflush = 0;
1368 		flushi();
1369 		return(1);
1370 	}
1371 	if (hyoff != 1) {
1372 		if (j == ohc) {
1373 			if (!inword && xflag) {
1374 				hyoff = 1;
1375 				goto g1;
1376 			}
1377 			hyoff = 2;
1378 			*hyp++ = wordp;
1379 			if (hyp > (hyptr + NHYP - 1))
1380 				hyp = hyptr + NHYP - 1;
1381 			if (isblbit(i) && wordp > word)
1382 				wordp[-1] |= BLBIT;
1383 			goto g1;
1384 		}
1385 		if (maybreak(j, dv)) {
1386 			if (wordp > word + 1) {
1387 				int i;
1388 				if (!xflag)
1389 					hyoff = 2;
1390 				if (gemu && hyp > hyptr && wordp > word
1391 				    && hyp[-1] == wordp && (
1392 				    (i = cbits(wordp[-1])) == '-'
1393 				    || i == EMDASH))
1394 					hyp--;
1395 				*hyp++ = wordp + 1;
1396 				if (hyp > (hyptr + NHYP - 1))
1397 					hyp = hyptr + NHYP - 1;
1398 			}
1399 		} else {
1400 			int i = cbits(j);
1401 			dv = alph(j) || (i >= '0' && i <= '9');
1402 		}
1403 		if (xflag && nhychar(j))
1404 			hyoff = 2;
1405 	}
1406 	j = width(i);
1407 	numtab[HP].val += j;
1408 	storeword(i, j);
1409 	if (1) {
1410 		int	oev = ev;
1411 		nexti = GETCH();
1412 		if (ev == oev) {
1413 			if (cbits(nexti) == '\n')
1414 				t = ' ' | chbits;
1415 			else
1416 				t = nexti;
1417 			k = kernadjust(i, t);
1418 			wne += k;
1419 			widthp += k;
1420 			numtab[HP].val += k;
1421 		}
1422 	} else
1423 g1:		nexti = GETCH();
1424 	j = cbits(i = nexti);
1425 	if (gemu && (j == FILLER || j == UNPAD))
1426 		inword = 0;
1427 	else
1428 	if (!ismot(i) && j != ohc)
1429 		inword = 1;
1430 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1431 	if (multi_locale)
1432 		collectmb(i);
1433 #endif /* EUC && NROFF && ZWDELIMS */
1434 	{
1435 		static int sentchar[] =
1436 			{ '.', '?', '!', ':', 0 }; /* sentence terminators */
1437 		int	*sp, *tp;
1438 		static int transchar[] =
1439 			{ '"', '\'', ')', ']', '*', 0, 0 };
1440 		transchar[5] = DAGGER;
1441 		if ((j != '\n' && j != ' ' && (!padj || j != STRETCH)) ||
1442 				ismot(i) || iszbit(i) ||
1443 				isadjspc(i))
1444 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1445 			if (!multi_locale)
1446 #endif /* EUC && NROFF && ZWDELIMS */
1447 			goto g0;
1448 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1449 			else {
1450 				if (!wdbdg || (iswascii(cwc) && iswascii(owc)))
1451 					goto g0;
1452 				if ((wbf = (*wdbdg)(owc, cwc, 1)) < 5) {
1453 					storeword((wbf < 3) ? ZWDELIM(1) :
1454 						  ZWDELIM(2), 0);
1455 					*wordp = 0;
1456 					goto rtn;
1457 				} else goto g0;
1458 			}
1459 #endif /* EUC && NROFF && ZWDELIMS */
1460 		if (j == STRETCH && padj)
1461 			storeword(mkxfunc(PENALTY, INFPENALTY), 0);
1462 		wp = wordp-1;	/* handle extra space at end of sentence */
1463 		sp = *sentch ? sentch : sentchar;
1464 		tp = *transch ? transch : transchar;
1465 		while (sp[0] != IMP && wp >= word) {
1466 			j = cbits(*wp--);
1467 			if (istrans(wp[1]))
1468 				goto cont;
1469 			for (k = 0; tp[0] != IMP && tp[k] && k < NSENT; k++)
1470 				if (j == tp[k])
1471 					goto cont;
1472 			for (k = 0; sp[k] && k < NSENT; k++)
1473 				if (j == sp[k]) {
1474 					if (nlflg)
1475 						spflg++;
1476 					else
1477 						seflg++;
1478 					break;
1479 				}
1480 			break;
1481 		cont:;
1482 		}
1483 	}
1484 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1485 	wceoll = owc;
1486 #endif /* EUC && NROFF && ZWDELIMS */
1487 	*wordp = 0;
1488 	numtab[HP].val += xflag ? width(i) : sps;
1489 rtn:
1490 	if (i & SFMASK)
1491 		spbits = sfmask(i);
1492 	else if (i == '\n')
1493 		spbits = chbits;
1494 	for (wp = word; *wp; wp++) {
1495 		j = cbits(*wp);
1496 		if ((j == ' ' || j == STRETCH) && !iszbit(j) && !isadjspc(j))
1497 			continue;
1498 		if (!ischar(j) || (!isdigit(j) && j != '-'))
1499 			break;
1500 	}
1501 	if (*wp == 0)	/* all numbers, so don't hyphenate */
1502 		hyoff = 1;
1503 	wdstart = 0;
1504 	wordp = word;
1505 	pendw = 0;
1506 	*hyp++ = 0;
1507 	setnel();
1508 	return(noword);
1509 }
1510 
1511 
1512 void
storeword(register tchar c,register int w)1513 storeword(register tchar c, register int w)
1514 {
1515 
1516 	if (wordp == NULL || wordp >= &word[wdsize - 3]) {
1517 		tchar	*k, **h;
1518 		ptrdiff_t	j;
1519 		int	*pp, owdsize;
1520 		if (over)
1521 			return;
1522 		owdsize = wdsize;
1523 		wdsize += wdsize ? 100 : WDSIZE;
1524 		if ((k = realloc(word, wdsize * sizeof *word)) == NULL ||
1525 				(pp = realloc(wdpenal,
1526 				    wdsize * sizeof *wdpenal)) == NULL) {
1527 			flusho();
1528 			errprint("Word overflow.");
1529 			over++;
1530 			c = LEFTHAND;
1531 			w = -1;
1532 			wdsize = owdsize;
1533 			goto s1;
1534 		}
1535 		j = (char *)k - (char *)word;
1536 		wordp = (tchar *)((char *)wordp + j);
1537 		for (h = hyptr; h < hyp; h++)
1538 			if (*h)
1539 				*h = (tchar *)((char *)*h + j);
1540 		word = k;
1541 		wdpenal = pp;
1542 		memset(&wdpenal[owdsize], 0,
1543 				(wdsize - owdsize) * sizeof *wdpenal);
1544 	}
1545 s1:
1546 	if (isxfunc(c, PENALTY)) {
1547 		wdpenal[max(0, wordp - word - 1)] = sbits(c) | 0x80000000;
1548 		return;
1549 	}
1550 	if (isxfunc(c, DPENAL)) {
1551 		if ((wdpenal[max(0, wordp - word - 1)]&0x80000000) == 0)
1552 			wdpenal[max(0, wordp - word - 1)] = sbits(c);
1553 		return;
1554 	}
1555 	if (w == -1)
1556 		w = width(c);
1557 	widthp = w;
1558 	sethtdp();
1559 	wne += w;
1560 	*wordp++ = c;
1561 	wch++;
1562 	if (dpenal)
1563 		wdpenal[max(0, wordp - word - 1)] = dpenal;
1564 }
1565 
1566 
1567 #ifdef NROFF
gettch(void)1568 tchar gettch(void)
1569 {
1570 	extern int c_isalnum;
1571 	tchar i;
1572 	int j;
1573 
1574 	i = getch();
1575 	j = cbits(i);
1576 	if (ismot(i) || fbits(i) != ulfont)
1577 		return(i);
1578 	if (cu) {
1579 		if (trtab[j] == ' ') {
1580 			setcbits(i, '_');
1581 			setfbits(i, FT);	/* default */
1582 		}
1583 		return(i);
1584 	}
1585 	/* should test here for characters that ought to be underlined */
1586 	/* in the old nroff, that was the 200 bit on the width! */
1587 	/* for now, just do letters, digits and certain special chars */
1588 	if (j <= 127) {
1589 		if (!isalnum(j))
1590 			setfbits(i, FT);
1591 	} else {
1592 		if (j < c_isalnum)
1593 			setfbits(i, FT);
1594 	}
1595 	return(i);
1596 }
1597 
1598 
1599 #endif
1600 #if defined (EUC) && defined (NROFF) && defined (ZWDELIMS)
1601 int
collectmb(tchar i)1602 collectmb(tchar i)
1603 {
1604 	owc = cwc;
1605 	cwc = tr2un(cbits(i), fbits(i));
1606 	return(0);
1607 }
1608 
1609 
1610 #endif /* EUC && NROFF && ZWDELIMS */
1611 
1612 static tchar
adjbit(tchar c)1613 adjbit(tchar c)
1614 {
1615 	if (cbits(c) == ' ')
1616 		setcbits(c, WORDSP);
1617 	return(c | ADJBIT);
1618 }
1619 
1620 static void
sethtdp(void)1621 sethtdp(void)
1622 {
1623 	if ((cht = lastrst) > maxcht)
1624 		maxcht = cht;
1625 	if ((cdp = -lastrsb) > maxcdp)
1626 		maxcdp = cdp;
1627 }
1628 
1629 static void
leftend(tchar c,int hang,int dolpfx)1630 leftend(tchar c, int hang, int dolpfx)
1631 {
1632 	int	k, w;
1633 
1634 	if (dolpfx && lpfx) {
1635 		if (hang)
1636 			setlhang(lpfx[0]);
1637 		for (k = 0; lpfx[k]; k++) {
1638 			w = width(lpfx[k]);
1639 			w += k ? kernadjust(lpfx[k-1], lpfx[k]) : 0;
1640 			storeline(lpfx[k], w);
1641 		}
1642 		if (k) {
1643 			w = kernadjust(lpfx[k-1], c);
1644 			nel -= w;
1645 			ne += w;
1646 		}
1647 	} else if (hang)
1648 		setlhang(c);
1649 }
1650 
1651 #ifndef	NROFF
1652 static void
setlhang(tchar c)1653 setlhang(tchar c)
1654 {
1655 	int	k;
1656 
1657 	if (lhangtab != NULL && !ismot(c) && cbits(c) != SLANT &&
1658 			cbits(c) != XFUNC &&
1659 			lhangtab[fbits(c)] != NULL &&
1660 			(k = lhangtab[fbits(c)][cbits(c)]) != 0) {
1661 		width(c);	/* set xpts */
1662 		k = (k * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth;
1663 		nel -= k;
1664 		storeline(makem(k), 0);
1665 	}
1666 }
1667 
1668 static void
setrhang(void)1669 setrhang(void)
1670 {
1671 	int	j, k;
1672 	tchar	c;
1673 
1674 	if (nc > 0) {
1675 		c = 0;
1676 		for (j = nc - 1; j >= 0; j--)
1677 			if ((c = line[j]) != IMP)
1678 				break;
1679 		width(c);
1680 		j = lasttrack;
1681 		j += kernadjust(c, ' ' | sfmask(c));
1682 		if (admod != 1 && rhangtab != NULL && !ismot(c) &&
1683 				rhangtab[xfont] != NULL &&
1684 				(k = rhangtab[xfont][cbits(c)]) != 0) {
1685 			rhang = (k * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth;
1686 			j += rhang;
1687 		}
1688 		ne -= j;
1689 		nel += j;
1690 	}
1691 }
1692 
1693 static void
letshrink(void)1694 letshrink(void)
1695 {
1696 	int	diff, nsp, lshdiff;
1697 
1698 	nsp = nwd == 1 ? nwd : nwd - 1;
1699 	diff = nel;
1700 	if (lspnc && lsplow)
1701 		diff += nel * nsp / lspnc;
1702 	if (lshwid) {
1703 		if (lshlow < -diff / 2)
1704 			lshcur = -lshmin;
1705 		else if (lsplow < -diff / 2)
1706 			lshcur = (double)(diff - lsplow) / lshwid * LAFACT;
1707 		else
1708 			lshcur = (double)diff / 2 / lshwid * LAFACT;
1709 		lshdiff = (double)lshcur / LAFACT * lshwid;
1710 		nel -= lshdiff;
1711 		ne += lshdiff;
1712 	} else
1713 		lshdiff = 0;
1714 	diff -= lshdiff;
1715 	if (lsplow)
1716 		lspcur = lspmin * diff / lsplow;
1717 	else
1718 		lspcur = 0;
1719 	ne += lspcomp(lshdiff);
1720 }
1721 
1722 static int
letgrow(void)1723 letgrow(void)
1724 {
1725 	int	diff, n, nsp, lshdiff;
1726 
1727 	nsp = nwd == 1 ? nwd : nwd - 1;
1728 	if ((lspnc - nsp <= 0 || lsphigh <= 0) && lshhigh <= 0)
1729 		return 0;
1730 	n = (letsps - (minsps && ad && !admod ? minsps : sps)) * nsp;
1731 	diff = nel;
1732 	if (lspnc && lsphigh)
1733 		diff += nel * nsp / lspnc - n;
1734 	if (lshwid) {
1735 		if (lshhigh < diff / 2)
1736 			lshcur = lshmax;
1737 		else if (lsphigh < diff / 2)
1738 			lshcur = (double)(diff - lsphigh) / lshwid * LAFACT;
1739 		else
1740 			lshcur = (double)diff / 2 / lshwid * LAFACT;
1741 		lshdiff = (double)lshcur / LAFACT * lshwid;
1742 		nel -= lshdiff;
1743 		ne += lshdiff;
1744 	} else
1745 		lshdiff = 0;
1746 	diff -= lshdiff;
1747 	if (diff > lsphigh)
1748 		diff = lsphigh;
1749 	if (lsphigh)
1750 		lspcur = lspmax * diff / lsphigh;
1751 	else
1752 		lspcur = 0;
1753 	return lspcomp(lshdiff);
1754 }
1755 
1756 static int
lspcomp(int idiff)1757 lspcomp(int idiff)
1758 {
1759 	int	diff = 0, i;
1760 	tchar	c;
1761 
1762 	diff = 0;
1763 	for (i = 0; i < nc; i++)
1764 		if (!ismot(c = line[i])) {
1765 			if (isxfunc(c, FLDMARK))
1766 				diff = lsplast = 0;
1767 			else if (cbits(c) > ' ' || isxfunc(c, CHAR)) {
1768 				while (isxfunc(c, CHAR))
1769 					c = charout[sbits(c)].ch;
1770 				lsplast = (int)sbits(c) / 2 * lspcur / LAFACT;
1771 				diff += lsplast;
1772 			}
1773 		}
1774 	diff -= lsplast;
1775 	nel -= diff;
1776 	ne += lsplast;
1777 	return idiff + diff;
1778 }
1779 #endif	/* !NROFF */
1780 
1781 /*
1782  * A dynamic programming approach to line breaking over
1783  * a paragraph as introduced by D. E. Knuth & M. F. Plass,
1784  * "Breaking paragraphs into lines", Software - Practice
1785  * and Experience, Vol. 11, Issue 12 (1981), pp. 1119-1184.
1786  */
1787 
1788 static double
penalty(int k,int s,int h,int h2,int h3)1789 penalty(int k, int s, int h, int h2, int h3)
1790 {
1791 	double	t, d;
1792 
1793 	t = nel - k;
1794 	t = t >= 0 ? t * 5 / 3 : -t;
1795 	if (ad && !admod) {
1796 		d = s;
1797 		if (k - s && (letsps || lshmin || lshmax))
1798 			d += (double)(k - s) / 100;
1799 		if (d)
1800 			t /= d;
1801 	} else
1802 		t /= nel / 10;
1803 	if (h && hypp)
1804 		t += hypp;
1805 	if (h2 && hypp2)
1806 		t += hypp2;
1807 	if (h3 && hypp3)
1808 		t += hypp3;
1809 	t = t * t * t;
1810 	if (t > MAXPENALTY)
1811 		t = MAXPENALTY;
1812 	return t;
1813 }
1814 
1815 static void
parcomp(int start)1816 parcomp(int start)
1817 {
1818 	double	*cost, *_cost;
1819 	long double	t;
1820 	int	*prevbreak, *hypc, *_hypc, *brcnt, *_brcnt;
1821 	int	i, j, k, m, h, v, s;
1822 
1823 	_cost = malloc((pgsize + 1) * sizeof *_cost);
1824 	cost = &_cost[1];
1825 	_hypc = calloc(pgsize + 1, sizeof *_hypc);
1826 	hypc = &_hypc[1];
1827 	_brcnt = calloc(pgsize + 1, sizeof *_brcnt);
1828 	brcnt = &_brcnt[1];
1829 	prevbreak = calloc(pgsize, sizeof *prevbreak);
1830 	for (i = -1; i < start; i++)
1831 		cost[i] = 0;
1832 	for (i = start; i < pgwords; i++)
1833 		cost[i] = HUGE_VAL;
1834 	for (i = start; i < pgwords; i++) {
1835 		if (pshapes) {
1836 			j = brcnt[i-1];
1837 			if (j < pshapes)
1838 				nel = pgll[j] - pgin[j];
1839 			else
1840 				nel = pgll[pshapes-1] - pgin[pshapes-1];
1841 		} else if (un != in) {
1842 			nel = ll;
1843 			nel -= i > start ? in : un;
1844 		}
1845 		k = pgwordw[i] + pglgsw[i];
1846 		m = pglsphc[i] + pglgsh[i];
1847 		s = 0;
1848 		for (j = i; j < pgwords; j++) {
1849 			if (j > i) {
1850 				k += pgspacw[j] + pgwordw[j];
1851 				m += pgadspc[j] + pglsphc[j];
1852 				s += pgspacw[j];
1853 			}
1854 			v = k + pghyphw[j] + pglgew[j];
1855 			if (v - m - pglgeh[j] <= nel) {
1856 				if (!spread && j == pgwords - 1 &&
1857 						pgpenal[j] == 0)
1858 					t = 0;
1859 				else
1860 					t = penalty(v, s, pghyphw[j],
1861 						pghyphw[j] && hypc[i-1],
1862 						pghyphw[j] && j >= pglastw);
1863 				t += pgpenal[j];
1864 				t += cost[i-1];
1865 				/*fprintf(stderr, "%c%c%c%c to %c%c%c%c "
1866 				                 "t=%g cost[%d]=%g "
1867 						 "brcnt=%d oldbrcnt=%d\n",
1868 						(char)para[pgwordp[i]],
1869 						(char)para[pgwordp[i]+1],
1870 						(char)para[pgwordp[i]+2],
1871 						(char)para[pgwordp[i]+3],
1872 						(char)para[pgwordp[j+1]-4],
1873 						(char)para[pgwordp[j+1]-3],
1874 						(char)para[pgwordp[j+1]-2],
1875 						(char)para[pgwordp[j+1]-1],
1876 						t, j, cost[j],
1877 						1 + brcnt[i-1],
1878 						brcnt[j]
1879 					);*/
1880 				if ((double)t <= cost[j]) {
1881 					if (pghyphw[j])
1882 						h = hypc[i-1] + 1;
1883 					else
1884 						h = 0;
1885 					/*
1886 					 * This is not completely
1887 					 * correct: It might be
1888 					 * preferable to disallow
1889 					 * an earlier hyphenation
1890 					 * point. But it seems
1891 					 * good enough.
1892 					 */
1893 					if (hlm < 0 || h <= hlm) {
1894 						hypc[j] = h;
1895 						cost[j] = t;
1896 						prevbreak[j] = i;
1897 						brcnt[j] = 1 + brcnt[i-1];
1898 					}
1899 				}
1900 			} else {
1901 				if (j == i) {
1902 					t = 1 + cost[i-1];
1903 					cost[j] = t;
1904 					prevbreak[j] = i;
1905 					brcnt[j] = 1 + brcnt[i-1];
1906 				}
1907 				break;
1908 			}
1909 		}
1910 	}
1911 	/*for (i = 0; i < pgwords; i++)
1912 		fprintf(stderr, "cost[%d] = %g %c%c%c%c to %c%c%c%c\n",
1913 				i, cost[i],
1914 				(char)para[pgwordp[prevbreak[i]]],
1915 				(char)para[pgwordp[prevbreak[i]]+1],
1916 				(char)para[pgwordp[prevbreak[i]]+2],
1917 				(char)para[pgwordp[prevbreak[i]]+3],
1918 				(char)para[pgwordp[i]],
1919 				(char)para[pgwordp[i]+1],
1920 				(char)para[pgwordp[i]+2],
1921 				(char)para[pgwordp[i]+3]
1922 			);*/
1923 	pglines = 0;
1924 	memset(&pgopt[pglnout], 0, (pgsize - pglnout) * sizeof *pgopt);
1925 	i = j = pgwords - 1;
1926 	do {
1927 		pglines++;
1928 		j = prevbreak[j];
1929 		pgopt[i--] = j--;
1930 	} while (j >= start && i >= pglnout);
1931 	memmove(&pgopt[pglnout+1], &pgopt[i+2], pglines * sizeof *pgopt);
1932 	pgopt[pglnout] = start;
1933 	free(_cost);
1934 	free(_hypc);
1935 	free(_brcnt);
1936 	free(prevbreak);
1937 }
1938 
1939 void
growpgsize(void)1940 growpgsize(void)
1941 {
1942 	pgsize += 20;
1943 	pgwordp = realloc(pgwordp, pgsize * sizeof *pgwordp);
1944 	pgwordw = realloc(pgwordw, pgsize * sizeof *pgwordw);
1945 	pghyphw = realloc(pghyphw, pgsize * sizeof *pghyphw);
1946 	pgadspc = realloc(pgadspc, pgsize * sizeof *pgadspc);
1947 	pglsphc = realloc(pglsphc, pgsize * sizeof *pglsphc);
1948 	pgopt = realloc(pgopt, pgsize * sizeof *pgopt);
1949 	pgspacp = realloc(pgspacp, pgsize * sizeof *pgspacp);
1950 	pgspacw = realloc(pgspacw, pgsize * sizeof *pgspacw);
1951 	pglgsc = realloc(pglgsc, pgsize * sizeof *pglgsc);
1952 	pglgec = realloc(pglgec, pgsize * sizeof *pglgec);
1953 	pglgsw = realloc(pglgsw, pgsize * sizeof *pglgsw);
1954 	pglgew = realloc(pglgew, pgsize * sizeof *pglgew);
1955 	pglgsh = realloc(pglgsh, pgsize * sizeof *pglgsh);
1956 	pglgeh = realloc(pglgeh, pgsize * sizeof *pglgeh);
1957 	pgin = realloc(pgin, pgsize * sizeof *pgin);
1958 	pgll = realloc(pgll, pgsize * sizeof *pgll);
1959 	pgwdin = realloc(pgwdin, pgsize * sizeof *pgwdin);
1960 	pgwdll = realloc(pgwdll, pgsize * sizeof *pgwdll);
1961 	pgflags = realloc(pgflags, pgsize * sizeof *pgflags);
1962 	pglno = realloc(pglno, pgsize * sizeof *pglno);
1963 	pgpenal = realloc(pgpenal, pgsize * sizeof *pgpenal);
1964 	if (pgwordp == NULL || pgwordw == NULL || pghyphw == NULL ||
1965 			pgopt == NULL || pgspacw == NULL ||
1966 			pgadspc == NULL || pglsphc == NULL ||
1967 			pglgsc == NULL || pglgec == NULL ||
1968 			pglgsw == NULL || pglgew == NULL ||
1969 			pglgsh == NULL || pglgeh == NULL ||
1970 			pgin == NULL || pgll == NULL ||
1971 			pgwdin == NULL || pgwdll == NULL ||
1972 			pgflags == NULL || pglno == NULL ||
1973 			pgpenal == NULL || pgwdin == NULL || pgwdin == NULL) {
1974 		errprint("out of memory justifying paragraphs");
1975 		done(02);
1976 	}
1977 }
1978 
1979 static void
parlgzero(int i)1980 parlgzero(int i)
1981 {
1982 	pglgsc[i] = 0;
1983 	pglgec[i] = 0;
1984 	pglgsw[i] = 0;
1985 	pglgew[i] = 0;
1986 	pglgsh[i] = 0;
1987 	pglgeh[i] = 0;
1988 }
1989 
1990 static float
makepgpenal(int p)1991 makepgpenal(int p)
1992 {
1993 	p &= ~0x80000000;
1994 	p -= INFPENALTY0 + 1;
1995 	if (p >= INFPENALTY0)
1996 		return INFPENALTY;
1997 	else if (p <= -INFPENALTY0)
1998 		return -INFPENALTY;
1999 	else
2000 		return p * PENALSCALE;
2001 }
2002 
2003 static void
parword(void)2004 parword(void)
2005 {
2006 	int	a, c, w, hc;
2007 	tchar	i, *wp;
2008 
2009 	if (pgwords + 1 >= pgsize)
2010 		growpgsize();
2011 	hc = shc ? shc : HYPHEN;
2012 	pglastw = pgwords;
2013 	wp = wordp;
2014 	a = w = 0;
2015 	pglno[pgwords] = numtab[CD].val;
2016 	pgspacp[pgwords] = pgspacs;
2017 	pgpenal[pgwords] = 0;
2018 	pgwdin[pgwords] = in;
2019 	pgwdll[pgwords] = ll;
2020 	if (pgwords == 0)
2021 		pgflags[pgwords] = 0;
2022 	un1 = -1;
2023 	while ((c = cbits(i = *wp++)) == ' ' || c == STRETCH) {
2024 		if (iszbit(i))
2025 			break;
2026 		wch--;
2027 		minflg = minspsz && ad && !admod;
2028 		w += width(i);
2029 		a += minspc;
2030 		w += kernadjust(wp[-1], wp[0]);
2031 		if (pgspacs >= pgssize) {
2032 			pgssize += 60;
2033 			parsp = realloc(parsp, pgssize * sizeof *parsp);
2034 			if (parsp == NULL) {
2035 				errprint("no memory for spaces in paragraph");
2036 				done(02);
2037 			}
2038 		}
2039 		parsp[pgspacs++] = i;
2040 		if (c == STRETCH)
2041 			pgpenal[pgwords] = INFPENALTY;
2042 		else if (wdpenal[wp-word-1])
2043 			pgpenal[pgwords] = makepgpenal(wdpenal[wp-word-1]);
2044 	}
2045 	if (wch == 0)
2046 		return;
2047 	pgspacp[pgwords+1] = pgspacs;
2048 	if (--wp > wordp && pgchars > 0)
2049 		w += kernadjust(para[pgchars-1], wordp[0]);
2050 	wne -= w;
2051 	pgspacw[pgwords] = pgwords ? w + a : 0;
2052 	pghyphw[pgwords] = 0;
2053 	pgadspc[pgwords] = pgwords ? a : 0;
2054 	pglsphc[pgwords] = 0;
2055 	pgwordw[pgwords] = 0;
2056 	pgwordp[pgwords] = pgchars;
2057 	pgne += pgspacw[pgwords];
2058 	parlgzero(pgwords);
2059 	parlgzero(pgwords+1);
2060 	if (wdhyf == -1)
2061 		wdhyf = hyf;
2062 	if (!hyoff && wdhyf && hlm)
2063 		hyphen(wp);
2064 	hyp = hyptr;
2065 	nhyp = 0;
2066 	while (*hyp && *hyp <= wp)
2067 		hyp++;
2068 	while (wch) {
2069 		if (ishyp(wp) && !maybreak(wp[-1], 1)) {
2070 			i = sfmask(wp[-1]) | hc;
2071 			w = width(i);
2072 			w += kernadjust(wp[-1], i);
2073 			pghyphw[pgwords] = w;
2074 #ifndef	NROFF
2075 			{
2076 			int		*ip;
2077 			intptr_t	n;
2078 			tchar		e, s;
2079 
2080 			n = (intptr_t)hyp[-1] & 03;
2081 			ip = n ? lgrevtab[fbits(*wp)][cbits(*wp)] : NULL;
2082 			if (n != 0 && ip != NULL) {
2083 				pglgec[pgwords] = e =
2084 					strlg(fbits(*wp), ip, n) |
2085 						sfmask(*wp) | AUTOLIG;
2086 				for (w = 0; ip[n+w]; w++);
2087 				pglgsc[pgwords+1] = s =
2088 					strlg(fbits(*wp), &ip[n], w) |
2089 						sfmask(*wp) | AUTOLIG;
2090 				pglgew[pgwords] = width(e);
2091 				pglgeh[pgwords] = getlsh(e, rawwidth) *
2092 					lshmin / LAFACT;
2093 				pglgew[pgwords] += kernadjust(wp[-1], e);
2094 				pghyphw[pgwords] += kernadjust(e, i);
2095 				pghyphw[pgwords] -= kernadjust(wp[-1], i);
2096 				pglgsw[pgwords+1] = width(s);
2097 				pglgsh[pgwords+1] = getlsh(s, rawwidth) *
2098 					lshmin / LAFACT;
2099 				pglgsw[pgwords+1] -= width(*wp);
2100 				pglgsh[pgwords+1] -= getlsh(*wp, rawwidth) *
2101 					lshmin / LAFACT;
2102 				pglgsw[pgwords+1] += kernadjust(s, wp[1]);
2103 				pglgsw[pgwords+1] -= kernadjust(wp[0], wp[1]);
2104 			} }
2105 #endif	/* !NROFF */
2106 		}
2107 		if (pghyphw[pgwords] || (wp > word && maybreak(wp[-1], 1))) {
2108 			if (pghyphw[pgwords])
2109 				pghyphw[pgwords] -= kernadjust(wp[-1], wp[0]);
2110 			pgne += pgwordw[pgwords];
2111 			pgwordp[++pgwords] = pgchars;
2112 			if (pgwords + 1 >= pgsize)
2113 				growpgsize();
2114 			pglno[pgwords] = numtab[CD].val;
2115 			pgspacp[pgwords] = pgspacs;
2116 			pgspacp[pgwords+1] = pgspacs;
2117 			pgspacw[pgwords] = 0;
2118 			pgwordw[pgwords] = 0;
2119 			pghyphw[pgwords] = 0;
2120 			pgadspc[pgwords] = 0;
2121 			pglsphc[pgwords] = 0;
2122 			pgpenal[pgwords] = 0;
2123 			pgwdin[pgwords] = in;
2124 			pgwdll[pgwords] = ll;
2125 			pgflags[pgwords] = 0;
2126 			parlgzero(pgwords+1);
2127 		}
2128 		i = *wp++;
2129 		w = width(i);
2130 		pglsphc[pgwords] += getlsh(i, rawwidth) * lshmin / LAFACT;
2131 		w += kernadjust(i, *wp);
2132 		wne -= w;
2133 		wch--;
2134 		pgwordw[pgwords] += w;
2135 		if (letsps)
2136 			pglsphc[pgwords] += getlsp(i) * lspmin / LAFACT;
2137 		if (pgchars + 1 >= pgcsize) {
2138 			pgcsize += 600;
2139 			para = realloc(para, pgcsize * sizeof *para);
2140 			if (para == NULL) {
2141 				errprint("no memory for characters "
2142 				         "in paragraph");
2143 				done(02);
2144 			}
2145 		}
2146 		para[pgchars++] = i;
2147 		if (wdpenal[wp-word-1])
2148 			pgpenal[pgwords] = makepgpenal(wdpenal[wp-word-1]);
2149 	}
2150 	pgne += pgwordw[pgwords];
2151 	pgwordp[++pgwords] = pgchars;
2152 	pgspacw[pgwords] = 0;
2153 	pgwordw[pgwords] = 0;
2154 	pghyphw[pgwords] = 0;
2155 	pgadspc[pgwords] = 0;
2156 	pglsphc[pgwords] = 0;
2157 	pgpenal[pgwords] = 0;
2158 	pgwdin[pgwords] = in;
2159 	pgwdll[pgwords] = ll;
2160 	pgflags[pgwords] = 0;
2161 	parlgzero(pgwords);
2162 	if (spread)
2163 		tbreak();
2164 }
2165 
2166 static void
pbreak(int sprd,int lastf,struct s * s)2167 pbreak(int sprd, int lastf, struct s *s)
2168 {
2169 	int	j;
2170 
2171 	if (sprd)
2172 		adflg |= 5;
2173 	if (pshapes) {
2174 		j = pglnout < pshapes ? pglnout : pshapes - 1;
2175 		un = pgin[j];
2176 	}
2177 	nlflg = 1;
2178 	tbreak();
2179 	pglnout++;
2180 	if (trap) {
2181 		extern jmp_buf	sjbuf;
2182 		jmp_buf	savsjbuf;
2183 		if (setjmp(*s->jmp) == 0) {
2184 			nlflg = 1;
2185 			memcpy(&savsjbuf, &sjbuf, sizeof sjbuf);
2186 			if (donep && lastf)
2187 				donef = -1;
2188 			mainloop();
2189 		}
2190 		memcpy(&sjbuf, &savsjbuf, sizeof sjbuf);
2191 	}
2192 }
2193 
2194 void
parpr(struct s * s)2195 parpr(struct s *s)
2196 {
2197 	int	i, j, k = 0, nw = 0, w, stretches, _spread = spread, hc;
2198 	int	savll, savin, savcd, lastin, lastll, curin, curll;
2199 	tchar	c, e, lastc, lgs;
2200 
2201 	savll = ll;
2202 	savin = in;
2203 	curin = 0;
2204 	lastin = 0;
2205 	curll = -1;
2206 	lastll = 0;
2207 	savcd = numtab[CD].val;
2208 	hc = shc ? shc : HYPHEN;
2209 	nw = 0;
2210 	for (i = 0; i < pgwords; i++) {
2211 		lgs = 0;
2212 		numtab[CD].val = pglno[i];
2213 		if (i == 0 || pgflags[i] & PG_NEWIN)
2214 			lastin = pgwdin[i];
2215 		if (i == 0 || pgflags[i] & PG_NEWLL)
2216 			lastll = pgwdll[i];
2217 		if (k == 0 || pgopt[k] == i) {
2218 			if (k++ > 0) {
2219 				if (pghyphw[i-1]) {
2220 #ifndef	NROFF
2221 					if ((e = pglgec[i-1]) != 0) {
2222 						w = width(e);
2223 						storelsh(e, rawwidth);
2224 						w += kernadjust(para[pgwordp[i]-1], e);
2225 						storeline(e, w);
2226 						if (letsps)
2227 							storelsp(e, 0);
2228 						lgs = pglgsc[i];
2229 					} else
2230 #endif
2231 						e = para[pgwordp[i]-1];
2232 					c = sfmask(e) | hc;
2233 					w = width(c);
2234 					storelsh(c, rawwidth);
2235 					w += kernadjust(e, c);
2236 					storeline(c, w);
2237 					if (letsps)
2238 						storelsp(c, 0);
2239 				}
2240 				pbreak(1, i >= pgwords, s);
2241 				if (i >= pgwords)
2242 					break;
2243 			}
2244 			if (pshapes) {
2245 				if (k == 1)
2246 					parcomp(0);
2247 				j = k-1 < pshapes ? k-1 : pshapes - 1;
2248 				ll = pgll[j];
2249 				un = pgin[j];
2250 				nel = ll - un;
2251 			} else if (k > 1 && (in != curin || ll != curll)) {
2252 				savin = curin = lastin = in;
2253 				savll = curll = lastll = ll;
2254 				un = in;
2255 				nel = ll - un;
2256 				parcomp(i);
2257 			} else if (lastin != curin || lastll != curll) {
2258 				savin = in = curin = lastin;
2259 				savll = ll = curll = lastll;
2260 				if (k > 1)
2261 					un = in;
2262 				nel = ll - un;
2263 				parcomp(i);
2264 			}
2265 			nel = ll - un;
2266 			nw = nwd = 1;
2267 			leftend(para[pgwordp[i]], admod != 1 && admod != 2, 1);
2268 		} else {
2269 			for (j = pgspacp[i]; j < pgspacp[i+1]; j++) {
2270 				c = parsp[j];
2271 				minflg = minspsz && ad && !admod;
2272 				w = width(c);
2273 				adspc += minspc;
2274 				if (j == pgspacp[i] && i > 0)
2275 					w += kernadjust(para[pgwordp[i]-1], c);
2276 				if (j == pgspacp[i+1]-1)
2277 					w += kernadjust(c, para[pgwordp[i]]);
2278 				storeline(c, w);
2279 				spbits = sfmask(c);
2280 			}
2281 			nwd += pgspacp[i] != pgspacp[i+1];
2282 		}
2283 		stretches = 0;
2284 		lastc = 0;
2285 		for (j = pgwordp[i]; j < pgwordp[i+1]; j++) {
2286 			c = lgs ? lgs : para[j];
2287 			lgs = 0;
2288 			w = width(c);
2289 			storelsh(c, rawwidth);
2290 			if (j == pgwordp[i] && i > 0 && nw > 1 &&
2291 					pgspacp[i] == pgspacp[i+1])
2292 				w += kernadjust(para[j-1], c);
2293 			if (j < pgwordp[i+1]-1)
2294 				w += kernadjust(c, para[j+1]);
2295 			storeline(c, w);
2296 			if (cbits(c) == STRETCH && cbits(lastc) != STRETCH)
2297 				stretches++;
2298 			lastc = c;
2299 			if (letsps)
2300 				storelsp(c, 0);
2301 		}
2302 		nwd += stretches;
2303 		nw++;
2304 	}
2305 	pbreak((nel - adspc < 0 && nwd > 1) || _spread, 1, s);
2306 	if (pgflags[pgwords] & PG_NEWIN)
2307 		savin = pgwdin[pgwords];
2308 	if (pgflags[pgwords] & PG_NEWLL)
2309 		savll = pgwdll[pgwords];
2310 	pgwords = pgchars = pgspacs = pglines = pgne = pglastw = 0;
2311 	ll = savll;
2312 	in = un = savin;
2313 	numtab[CD].val = savcd;
2314 }
2315 
2316 static void
parfmt(void)2317 parfmt(void)
2318 {
2319 	int	_nlflg = nlflg;
2320 	int	_spread = spread;
2321 	struct s	*s;
2322 
2323 	if (pgchars == 0)
2324 		return;
2325 	setnel();
2326 	pglnout = 0;
2327 	s = frame;
2328 	nxf->jmp = malloc(sizeof *nxf->jmp);
2329 	pushi(-2, 0, FLAG_PARAGRAPH);
2330 	parpr(frame);
2331 	while (frame != s)
2332 		ch = popi();
2333 	nlflg = _nlflg;
2334 	if (_spread == 1 && pshapes > pglnout) {
2335 		memmove(&pgin[0], &pgin[pglnout],
2336 			(pshapes - pglnout) * sizeof *pgin);
2337 		memmove(&pgll[0], &pgll[pglnout],
2338 			(pshapes - pglnout) * sizeof *pgll);
2339 		pshapes -= pglnout;
2340 	} else
2341 		pshapes = 0;
2342 }
2343