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