diff options
Diffstat (limited to 'troff/n7.c')
| -rw-r--r-- | troff/n7.c | 2342 |
1 files changed, 2342 insertions, 0 deletions
diff --git a/troff/n7.c b/troff/n7.c new file mode 100644 index 000000000000..89c6a4e2755a --- /dev/null +++ b/troff/n7.c @@ -0,0 +1,2342 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* from OpenSolaris "n7.c 1.10 05/06/08 SMI" */ + +/* + * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany + * + * Sccsid @(#)n7.c 1.181 (gritter) 6/19/11 + * + * Portions Copyright (c) 2014, 2015 Carsten Kunze + */ + +/* + * University Copyright- Copyright (c) 1982, 1986, 1988 + * The Regents of the University of California + * All Rights Reserved + * + * University Acknowledgment- Portions of this document are derived from + * software developed by the University of California, Berkeley, and its + * contributors. + */ + +#include <stddef.h> +#include <stdlib.h> +#include <limits.h> +#include "tdef.h" +#ifdef NROFF +#include "tw.h" +#include "draw.h" +#endif +#include "pt.h" +#ifdef NROFF +#define GETCH gettch +tchar gettch(void); +#endif +#ifndef NROFF +#define GETCH getch +#endif + +/* + * troff7.c + * + * text + */ + +#include <math.h> +#include <string.h> +#include <ctype.h> +#include "ext.h" +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) +wchar_t cwc, owc, wceoll; +#endif /* EUC && NROFF && ZWDELIMS */ +int brflg; + +#undef iswascii +#define iswascii(c) (((c) & ~(wchar_t)0177) == 0) + +static int _findt(struct d *, int, int); +static tchar adjbit(tchar); +static void sethtdp(void); +static void leftend(tchar, int, int); +static void parword(void); +static void parfmt(void); +#ifndef NROFF +#define nroff 0 +extern int lastrst; +extern int lastrsb; +static void setlhang(tchar); +static void setrhang(void); +static void letshrink(void); +static int letgrow(void); +static int lspcomp(int); +#else /* NROFF */ +#define nroff 1 +#define lastrst 0 +#define lastrsb 0 +#define setlhang(a) +#define setrhang() +#define getlsp(c) 0 +#define storelsp(a, b) +#define getlsh(c, w) 0 +#define storelsh(a, b) +#define letshrink() +#define letgrow() 0 +#define lspcomp(a) 0 +#endif /* NROFF */ + +void +tbreak(void) +{ + register int pad, k; + register tchar *i, j, c; + register int resol = 0; + int _minflg; + +restart: + trap = 0; + if (nb) + return; + if (dip == d && numtab[NL].val == -1) { + newline(1); + return; + } + if (!nc && !pgchars) { + setnel(); + if (!wch) + return; + if (pendw) + getword(1); + movword(); + } else if (pendw && !brflg) { + getword(1); + movword(); + } else if (!brflg && adflg & 1) { + adflg |= 2; + text(); + return; + } + if ((pa || padj) && pglines == 0 && pgchars) { + parfmt(); + goto restart; + } + if (minspsz && !brflg && ad && !admod) + ne += adspc; + *linep = dip->nls = 0; +#ifdef NROFF + if (dip == d) + horiz(po); +#endif + if (lnmod) + donum(); + lastl = ne; + if (brflg != 1) { + totout = 0; + hlc = 0; + } else if (ad) { + if ((lastl = ll - un + rhang + lsplast) < ne) + lastl = ne; + } + if (admod && ad && (brflg != 2)) { + lastl = ne; + adsp = adrem = 0; + if (admod == 1) + un += quant(nel / 2, HOR); + else if (admod == 2) + un += nel; + } + _minflg = minspsz && admod == 0 && ad && brflg == 1 && adflg & 4; + totout++; + brflg = 0; + if (lastl + un > dip->maxl) + dip->maxl = lastl + un; + horiz(un); + if (un != 0) + pchar(mkxfunc(INDENT, un)); +#ifdef NROFF + if (adrem % t.Adj) + resol = t.Hor; + else + resol = t.Adj; +#else + resol = HOR; +#endif + adrem = (adrem / resol) * resol; + for (i = line; nc > 0; ) { + if ((c = cbits(j = *i++)) == ' ' || c == STRETCH) { + if ((xflag && !fi && dilev) || iszbit(j) || isadjspc(j)) + goto std; + pad = 0; + if (i > &line[1]) + pad += kernadjust(i[-2], i[-1]); + do { + if (xflag) + pchar(adjbit(j)); + minflg = _minflg; + pad += width(j); + nc--; + } while ((c = cbits(j = *i++)) == ' ' || c == STRETCH); + pad += kernadjust(i[-2], i[-1]); + i--; + pad += adsp; + --nwd; + if (adrem) { + if (adrem < 0) { + pad -= resol; + adrem += resol; + } else if ((totout & 01) || adrem / resol >= nwd) { + pad += resol; + adrem -= resol; + } + } + pchar((tchar) WORDSP); + horiz(pad); + } else { + std: + if (!ismot(j) && isxfunc(j, FLDMARK)) + fldcnt--; + else if (fldcnt == 0 && nc && !ismot(j) && + !iszbit(j)) { + if (lspcur && (cbits(j) > ' ' || + isxfunc(j, CHAR))) { + for (c = j; isxfunc(c, CHAR); + c = charout[sbits(c)].ch); + k = (int)sbits(c) / 2 * lspcur / LAFACT; + if (k >= 0) + c = mkxfunc(LETSP, k); + else + c = mkxfunc(NLETSP, -k); + pchar(c); + } + if (lshcur && cbits(j) > ' ') { + k = lshcur; + if (k >= 0) + c = mkxfunc(LETSH, k); + else + c = mkxfunc(NLETSH, -k); + pchar(c); + } + } + pchar(j); + nc--; + } + } + if (hlc) + pchar(mkxfunc(HYPHED, 0)); + if (ic) { + if ((k = ll - un - lastl + ics) > 0) + horiz(k); + pchar(ic); + } + if (icf) + icf++; + else + ic = 0; + ne = nwd = 0; + un = in; + setnel(); + newline(0); + if (dip != d) { + if (dip->dnl > dip->hnl) + dip->hnl = dip->dnl; + } else { + if (numtab[NL].val > dip->hnl) + dip->hnl = numtab[NL].val; + } + for (k = ls - 1; k > 0 && !trap; k--) + newline(0); + spread = 0; + spbits = 0; +} + +void +donum(void) +{ + register int i, nw; + + nrbits = nmbits; + nw = width('1' | nrbits); + if (nn) { + nn--; + goto d1; + } + if (numtab[LN].val % ndf) { + numtab[LN].val++; +d1: + un += nw * (3 + nms + ni); + return; + } + i = 0; + if (numtab[LN].val < 100) + i++; + if (numtab[LN].val < 10) + i++; + horiz(nw * (ni + i)); + nform = 0; + fnumb(numtab[LN].val, pchar); + un += nw * nms; + numtab[LN].val++; +} + +void +text(void) +{ + register tchar i, c, lasti = 0; + int k = 0; + static int spcnt; + int recadj = 0; + + if (adflg & 2) { + adflg &= ~3; + recadj = 1; + goto adj; + } + adflg = 0; + nflush++; + numtab[HP].val = 0; + if ((dip == d) && (numtab[NL].val == -1)) { + newline(1); + goto r; + } + setnel(); + if (ce || rj || !fi) { + nofill(); + goto r; + } + if (pendw) + goto t4; + if (pendt) { + if (spcnt) + goto t2; + else + goto t3; + } + pendt++; + if (spcnt) + goto t2; + while ((c = cbits(i = GETCH())) == ' ' || c == STRETCH) { + if (iszbit(i)) + break; + if (isadjspc(i)) + continue; + spcnt++; + widthp = xflag ? width(i) : sps; + sethtdp(); + numtab[HP].val += widthp; + lasti = i; + } + if (lasti) { + k = kernadjust(lasti, i); + numtab[HP].val += k; + widthp += k; + } + if (nlflg) { +t1: + nflush = pendt = ch = spcnt = 0; + callsp(); + goto r; + } + ch = i; + if (spcnt) { +t2: + lsn = spcnt; + glss = spcnt * sps + k; + if (lsmac) { + spcnt = 0; + control(lsmac, 0); + goto rtn; + } else { + tbreak(); + if (nc || wch) + goto rtn; + un += glss; + spcnt = 0; + setnel(); + if (trap) + goto rtn; + if (nlflg) + goto t1; + } + } +t3: + if (spread && !brpnl) + goto t5; + if (pendw || !wch) +t4: + if (getword(0)) { + if (!pendw) { + if (brnl || (brpnl && spread)) + goto tb; + if (brpnl) + goto t5; + } + goto t6; + } + if (!movword()) + goto t3; +t5: + if (nlflg) + pendt = 0; +adj: + adsp = adrem = 0; + if (ad) { + setrhang(); + if (admod == 0 && lspcur == 0 && lshcur == 0 && + nel < 0 && lspnc) + letshrink(); + jst: if (nwd == 1) + adsp = nel; + else + adsp = nel / (nwd - 1); + adsp = (adsp / HOR) * HOR; + if (admod == 0 && lspcur == 0 && lshcur == 0 && + adsp > letsps - sps) + if (letgrow()) + goto jst; + adrem = nel - adsp*(nwd-1); + if (admod == 0 && nwd == 1 && warn & WARN_BREAK) + errprint("can't break line"); + else if (admod == 0 && spreadwarn && adsp >= spreadlimit) + errprint("spreadlimit exceeded, %gm", (double)adsp/EM); + } + brflg = 1; +tb: + tbreak(); + spread = 0; + if (!trap && !recadj && !brnl && !brpnl) + goto t3; + if (brnl > 0 && brnl < INT_MAX) + brnl--; + if (brpnl > 0 && brpnl < INT_MAX) + brpnl--; + if (!nlflg) + goto rtn; +t6: + pendt = 0; + ckul(); +rtn: + nflush = 0; +r: + if (chomp) { + chomp = 0; + chompend = 1; + } +} + + +void +nofill(void) +{ + register int j; + register tchar i, nexti; + int k, oev; + + if (chompend) { + chompend = 0; + } else if (!pendnf && !chomp) { + over = 0; + tbreak(); + if (trap) + goto rtn; + if (nlflg) { + ch = nflush = 0; + callsp(); + return; + } + adsp = adrem = 0; + nwd = 10000; + } + nexti = GETCH(); + leftend(nexti, !ce && !rj && !pendnf, !isdi(nexti)); + while ((j = (cbits(i = nexti))) != '\n') { + if (stopch && issame(i, stopch)) + break; + if (j == ohc) { + nexti = GETCH(); + continue; + } + if (j == CONT) { + pendnf++; + nflush = 0; + flushi(); + ckul(); + return; + } + j = width(i); + widthp = j; + sethtdp(); + numtab[HP].val += j; + storeline(i, j); + oev = ev; + nexti = GETCH(); + if (ev == oev) { + k = kernadjust(i, nexti); + ne += k; + nel -= k; + numtab[HP].val += k; + } + } + if (chomp) { + return; + } + if (ce) { + ce--; + if ((i = quant(nel / 2, HOR)) > 0) + un += i; + } + if (rj) { + rj--; + setrhang(); + if (nel > 0) + un += nel; + } + if (!nc) + storeline((tchar)FILLER, 0); + brflg = 2; + tbreak(); + ckul(); +rtn: + pendnf = nflush = 0; +} + + +void +callsp(void) +{ + register int i; + + if (flss) + i = flss; + else + i = lss; + flss = 0; + if (blmac && (fi || (frame->flags & FLAG_DIVERSION) == 0)) + control(blmac, 0); + else + casesp(i); +} + + +void +ckul(void) +{ + if (ul && (--ul == 0)) { + cu = 0; + font = sfont; + mchbits(); + } + if (it && !pglines && (!itc || (!pendw && !pendnf)) && + (--it == 0) && itmac) + control(itmac, 0); +} + + +int +storeline(register tchar c, int w) +{ +#ifdef NROFF + if (ismot(c)) { + if (isvmot(c)) { + if (isnmot(c)) + lvmot -= c & BMBITS; + else + lvmot += c & BMBITS; + } + } else if (ndraw && !(cbits(c) & ~0xffff)) { + storechar(c, numtab[NL].val+lvmot, po + in + ne); + } +#endif + if (linep == NULL || linep >= line + lnsize - 4) { + tchar *k; + if (over) + return 0; + lnsize += lnsize ? 100 : LNSIZE; + if ((k = realloc(line, lnsize * sizeof *line)) == NULL) { + flusho(); + errprint("Line overflow."); + over++; + c = LEFTHAND; + w = -1; + goto s1; + } + linep = (tchar *)((char *)linep + ((char *)k - (char *)line)); + line = k; + } +s1: + if (w == -1) { + minflg = minspsz && ad && !admod; + w = width(c); + } + ne += w; + nel -= w; + *linep++ = c; + nc++; + return 1; +} + + +#ifndef NROFF +static int +getlsp(tchar c) +{ + int s; + + if (!ad || admod || ismot(c)) + return 0; + if (iszbit(c) || (cbits(c) <= ' ' && !isxfunc(c, CHAR))) + return 0; + while (isxfunc(c, CHAR)) + c = charout[sbits(c)].ch; + s = sbits(c) / 2; + return s; +} + +static void +storelsp(tchar c, int neg) +{ + int s; + + if (isxfunc(c, FLDMARK)) { + lsplow = lsphigh = lspnc = 0; + fldcnt += neg ? -1 : 1; + return; + } + if ((s = getlsp(c)) != 0) { + if (neg) + s = -s; + lsplow += s * lspmin / LAFACT; + lsphigh += s * lspmax / LAFACT; + lspnc += neg ? -1 : 1; + } +} + +static int +getlsh(tchar c, int w) +{ + if (!ad || admod || ismot(c)) + return 0; + if (iszbit(c) || cbits(c) <= ' ') + return 0; + return w; +} + +static void +storelsh(tchar c, int w) +{ + int s; + + if (isxfunc(c, FLDMARK)) { + lshlow = lshhigh = lshwid = 0; + return; + } + if ((s = getlsh(c, w)) != 0) { + lshwid += s; + lshlow = lshwid * lshmin / LAFACT; + lshhigh = lshwid * lshmax / LAFACT; + } +} +#endif /* !NROFF */ + +void +newline(int a) +{ + register int i, j, nlss = 0, nl; + int opn; + +#ifdef NROFF + if (lvmot) { + tchar c; + c = MOT | VMOT | (lvmot < 0 ? -lvmot : lvmot | NMOT); + pchar1(c); + lvmot = 0; + } +#endif + if (a) + goto nl1; + if (dip != d) { + j = lss; + pchar1((tchar)FLSS); + if (flss) + lss = flss; + i = nlss = lss + dip->blss; + dip->dnl += i; + pchar1((tchar)i); + pchar1((tchar)'\n'); + lss = j; + dip->blss = flss = 0; + if (dip->alss) { + pchar1((tchar)FLSS); + pchar1((tchar)dip->alss); + pchar1((tchar)'\n'); + dip->dnl += dip->alss; + nlss += dip->alss; + dip->alss = 0; + } + if (vpt > 0 && dip->ditrap && !dip->ditf && dip->dnl >= dip->ditrap && dip->dimac) + if (control(dip->dimac, 0)) { + trap++; + dip->ditf++; + } + goto nlt; + } + j = lss; + if (flss) + lss = flss; + nlss = dip->alss + dip->blss + lss; + numtab[NL].val += nlss; +#ifndef NROFF + if (ascii) { + dip->alss = dip->blss = 0; + } +#endif + pchar1((tchar)'\n'); + flss = 0; + lss = j; + if (vpt == 0 || numtab[NL].val < pl) + goto nl2; +nl1: + ejf = dip->hnl = numtab[NL].val = 0; + ejl = frame->tail_cnt; + if (donef || (ndone && pgchars && !pglines)) { + if ((!nc && !wch && !pglines) || ndone) + done1(0); + ndone++; + donef = 0; + if (frame == stk) + nflush++; + } + opn = numtab[PN].val; + numtab[PN].val++; + if (npnflg) { + numtab[PN].val = npn; + npn = npnflg = 0; + } + prwatchn(&numtab[PN]); +nlpn: + if (numtab[PN].val == pfrom) { + print++; + pfrom = -1; + } else if (opn == pto) { + print = 0; + opn = -1; + chkpn(); + goto nlpn; + } + if (print) + newpage(numtab[PN].val); /* supposedly in a clean state so can pause */ + if (stop && print) { + dpn++; + if (dpn >= stop) { + dpn = 0; + dostop(); + } + } +nl2: + trap = 0; +nlt: + if (dip != d) + nl = dip->dnl; + else + nl = numtab[NL].val; + if (vpt <= 0) + /*EMPTY*/; + else if (nl == 0) { + if ((j = findn(dip, 0)) != NTRAP) + trap |= control(dip->mlist[j], 0); + } else if ((i = _findt(dip, nl - nlss, 0)) <= nlss) { + if ((j = findn1(dip, nl - nlss + i)) == NTRAP) { + flusho(); + errprint("Trap botch."); + done2(-5); + } + trap |= control(dip->mlist[j], 0); + } + if (nolt && dip == d) { + for (i = nolt - 1; i >= 0; i--) + trap |= control(olt[i], 0); + nolt = 0; + free(olt); + olt = NULL; + } +} + + +int +findn1(struct d *dp, int a) +{ + register int i, j; + + for (i = 0; i < NTRAP; i++) { + if (dp->mlist[i]) { + if ((j = dp->nlist[i]) < 0 && dp == d) + j += pl; + if (j == a) + break; + } + } + return(i); +} + + +void +chkpn(void) +{ + pto = *(pnp++); + pfrom = pto>=0 ? pto : -pto; + if (pto == -32767) { + flusho(); + done1(0); + } + if (pto < 0) { + pto = -pto; + print++; + pfrom = 0; + } +} + + +int +findt(struct d *dp, int a) +{ + return _findt(dp, a, 1); +} + +static int +_findt(struct d *dp, int a, int maydi) +{ + register int i, j, k; + + k = INT_MAX; + if (dip != d && maydi) { + if (dip->dimac && (i = dip->ditrap - a) > 0) + k = i; + } + for (i = 0; i < NTRAP; i++) { + if (dp->mlist[i]) { + if ((j = dp->nlist[i]) < 0 && dp == d) + j += pl; + if ((j -= a) <= 0) + continue; + if (j < k) + k = j; + } + } + if (dp == d) { + i = pl - a; + if (k > i) + k = i; + } + return(k); +} + + +int +findt1(void) +{ + register int i; + + if (dip != d) + i = dip->dnl; + else + i = numtab[NL].val; + return(findt(dip, i)); +} + + +void +eject(struct s *a) +{ + register int savlss; + +#ifdef NROFF + if (ndraw) npic(0); +#endif + if (dip != d) + return; + if (vpt == 0) { + if (donef == 0) { + errprint("page not ejected because traps are disabled"); + return; + } + errprint("page forcefully ejected although traps are disabled"); + vpt = -1; + } + ejf++; + if (a) + ejl = a->tail_cnt; + else + ejl = frame->tail_cnt; + if (trap) + return; +e1: + savlss = lss; + lss = findt(d, numtab[NL].val); + newline(0); + lss = savlss; + if (numtab[NL].val && !trap) + goto e1; +} + + +static int +maybreak(tchar c, int dv) +{ + int i, k = cbits(c); + + if (c & BLBIT) + return 1; + if (iszbit(c)) + return 0; + switch (breakch[0]) { + case IMP: + return 0; + case 0: + return (!gemu || dv) && (k == '-' || k == EMDASH); + default: + for (i = 0; breakch[i] && i < NSENT; i++) + if (breakch[i] == k) + return 1; + return 0; + } +} + +static int +nhychar(tchar c) +{ + int i, k = cbits(c); + + switch (nhych[0]) { + case IMP: + return 0; + case 0: + if (hyext) + return 0; + return k == '-' || k == EMDASH; + default: + for (i = 0; nhych[i] && i < NSENT; i++) + if (nhych[i] == k) + return 1; + return 0; + } +} + +static int +ishyp(tchar *wp) +{ + tchar *tp; + int yes = 0; + + tp = (tchar *)((intptr_t)*hyp & ~(intptr_t)03); + if (hyoff != 1 && tp == wp && !iszbit(*wp)) { + if (!wdstart || (wp > wdstart + 1 && wp < wdend && + (!(wdhyf & 04) || wp < wdend - 1) && /* 04 => last 2 */ + (!(wdhyf & 010) || wp > wdstart + 2)) || /* 010 => 1st 2 */ + (wdhyf & 020 && wp == wdend) || /* 020 = allow last */ + (wdhyf & 040 && wp == wdstart + 1)) /* 040 = allow first */ + yes = 1; + hyp++; + } + return yes; +} + + +int +movword(void) +{ + register int w; + register tchar i, *wp, c, *lp, *lastlp, lasti = 0; + int savwch, hys, stretches = 0, wholewd = 0, mnel, hyphenated = 0; + int hc; +#ifndef NROFF + tchar lgs = 0, lge = 0, optlgs = 0, optlge = 0; + int *ip, s, lgw = 0, optlgw = 0, lgr = 0, optlgr = 0; + tchar *optlinep = NULL, *optwp = NULL; + int optnc = 0, optnel = 0, optne = 0, optadspc = 0, optwne = 0, + optwch = 0, optwholewd = 0, + optlsplow = 0, optlsphigh = 0, optlspnc = 0, optfldcnt = 0, + optlshwid = 0, optlshlow = 0, optlshhigh = 0; +#else /* NROFF */ +#define lgw 0 +#define optlinep 0 +#endif /* NROFF */ + + if (pa || padj) { + parword(); + return(0); + } + over = 0; + wp = wordp; + if (!nwd) { + while ((c = cbits(i = *wp++)) == ' ') { + if (iszbit(i)) + break; + wch--; + wne -= xflag ? width(i) : sps; + if (xflag && linep > line) + storeline(adjbit(i), 0); + } + wp--; + if (wp > wordp) + wne -= kernadjust(wp[-1], wp[0]); + leftend(*wp, admod != 1 && admod != 2, 1); + } + if (wdhyf == -1) + wdhyf = hyf; + wsp = 0; + if (wne > nel - adspc && !hyoff && wdhyf && (hlm < 0 || hlc < hlm) && + (!nwd || nel + lsplow + lshlow - adspc > + 3 * (minsps && ad && !admod ? minsps : sps)) && + (!(wdhyf & 02) || (findt1() > lss))) + hyphen(wp); + savwch = wch; + hyp = hyptr; + nhyp = 0; + while (*hyp && *hyp <= wp) + hyp++; + while (wch) { + if (ishyp(wp)) { + i = IMP; + setsbits(i, (intptr_t)(hyp[-1]) & 03); + if (storeline(i, 0)) + nhyp++; + } + i = *wp++; + minflg = minspsz && ad && !admod; + w = width(i); + storelsh(i, rawwidth); + adspc += minspc; + w += kernadjust(i, *wp); + wne -= w; + wch--; + if (cbits(i) == STRETCH && cbits(lasti) != STRETCH) + stretches++; + lasti = i; + storeline(i, w); + if (letsps) + storelsp(i, 0); + } + *linep = *wp; + lastlp = linep; + mnel = ad && !admod ? (sps - minsps) * nwd : 0; + if (nel >= 0 || (nel + lsplow + lshlow >= 0 && + lspnc - (nwd ? nwd : 1) > 0)) { + if ((nel >= 0 && nwd && nel - adspc < 0 && nel / nwd < sps) || + (nel < 0 && nel + lsplow + lshlow >= 0)) { + wholewd = 1; + goto m0; + } + nwd += stretches + 1; + if (nel - adspc < 0 && nwd > 1) + adflg |= 5; + w = kernadjust(lasti, ' ' | (spbits?spbits:sfmask(lasti))); + ne += w; + nel -= w; + return(0); /* line didn't fill up */ + } +m0: + hc = shc ? shc : HYPHEN; +#ifndef NROFF + xbits((tchar)hc, 1); +#endif + hys = width((tchar)hc); + if (wholewd) + goto m1a; +m1: + if (!nhyp) { + if (!nwd) + goto m3; + if (wch == savwch) { + if (optlinep) + goto m2; + goto m4; + } + } + if ((*--linep & ~SMASK) != IMP) + goto m5; +#ifndef NROFF + i = *(linep + 1); + if ((s = sbits(*linep)) != 0 && + (ip = lgrevtab[fbits(i)][cbits(i)]) != NULL) { + lgs = strlg(fbits(i), ip, s) | sfmask(i) | AUTOLIG; + for (w = 0; ip[s+w]; w++); + lge = strlg(fbits(i), &ip[s], w) | sfmask(i) | AUTOLIG; + lgw = width(lgs); + lgr = rawwidth; + if (linep - 1 >= wordp) { + lgw += kernadjust(i, *(linep - 1)); + lgw -= kernadjust(*(linep + 1), *(linep - 1)); + } + } else { + lgs = 0; + lge = 0; + lgw = 0; + } +#endif /* !NROFF */ + if (!(--nhyp)) + if (!nwd) + goto m2; + if (nel + lsplow + lshlow < hys + lgw) { + nc--; + goto m1; + } + if (nel >= mnel + hys + lgw) + goto m2; + wholewd = 0; +m1a: +#ifndef NROFF + if ((minspsz && ad && !admod && + wch < savwch && nwd && nel / nwd > 0 && nel < mnel) || + (nel + lsplow + lshlow >= (wholewd ? 0 : hys + lgw) && + nel < (wholewd ? 0 : hys + lgw))) { + optlgs = lgs, optlge = lge, optlgw = lgw, optlgr = lgr; + optlinep = linep, optwp = wp, optnc = nc, optnel = nel, + optne = ne, optadspc = adspc, optwne = wne, optwch = wch; + optlsplow = lsplow, optlsphigh = lsphigh, optlspnc = lspnc; + optfldcnt = fldcnt; + optlshwid = lshwid, optlshlow = lshlow, optlshhigh = lshhigh; + optwholewd = wholewd; + nc -= !wholewd; + goto m1; + } else if (wholewd) { + wholewd = 0; + goto m1; + } +#endif +m2: +#ifndef NROFF + if (optlinep && 3*abs(optnel - mnel) < 5*abs(nel - mnel)) { + lgs = optlgs, lge = optlge, lgw = optlgw, lgr = optlgr; + linep = optlinep, wp = optwp, nc = optnc, nel = optnel, + ne = optne, adspc = optadspc, wne = optwne, wch = optwch; + lsplow = optlsplow, lsphigh = optlsphigh, lspnc = optlspnc; + fldcnt = optfldcnt; + lshwid = optlshwid, lshlow = optlshlow, lshhigh = optlshhigh; + if ((wholewd = optwholewd)) + goto m3; + } else if (optlinep && wch == savwch && !nhyp) + goto m4; + if (lgs != 0) { + *wp = lge; + storeline(lgs, lgw); + storelsh(lgs, lgr); + } +#endif /* !NROFF */ + if (!maybreak(*(linep - 1), 1)) { + *linep = sfmask(*(linep - 1)) | hc; + w = -kernadjust(*(linep - 1), *(linep + 1)); + w += kernadjust(*(linep - 1), *linep); + w += width(*linep); + storelsh(*linep, rawwidth); + w += kernadjust(*linep, ' ' | sfmask(*linep)); + nel -= w; + ne += w; + if (letsps) + storelsp(*linep, 0); + linep++; + hyphenated++; + } +m3: + nwd++; +m4: + if (letsps && linep > line) + storelsp(linep[-1], 1); + adflg &= ~1; + adflg |= 4; + wordp = wp; + if (hyphenated) + hlc++; + else + hlc = 0; + return(1); /* line filled up */ +m5: + nc--; + minflg = minspsz && ad && !admod; + w = width(*linep); + storelsh(*linep, -rawwidth); + adspc -= minspc; + for (lp = &linep[1]; lp < lastlp && cbits(*lp) == IMP; lp++); + w += kernadjust(*linep, *lp ? *lp : ' ' | sfmask(*linep)); + ne -= w; + nel += w; + wne += w; + wch++; + wp--; + if (letsps) + storelsp(*linep, 1); + goto m1; +} + + +void +horiz(int i) +{ + vflag = 0; + if (i) + pchar(makem(i)); +} + + +void +setnel(void) +{ + if (!nc) { + linep = line; + if (un1 >= 0 && (!pgwords || pglines)) { + un = un1; + un1 = -1; + } + nel = ll - un; + rhang = ne = adsp = adrem = adspc = 0; +#ifndef NROFF + lsplow = lsphigh = lspcur = lsplast = lspnc = fldcnt = 0; + lshwid = lshhigh = lshlow = lshcur = 0; +#endif /* !NROFF */ + cht = cdp = 0; + } +} + + +int +getword(int x) +{ + register int j, k = 0, w; + register tchar i = 0, *wp, nexti, gotspc = 0, t; + int noword, n, inword = 0; + int lastsp = ' '; + static int dv; +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + wchar_t *wddelim; + char mbbuf3[MB_LEN_MAX + 1]; + char *mbbuf3p; + int wbf; + tchar m; +#endif /* EUC && NROFF && ZWDELIMS */ + + dv = 0; + noword = 0; + if (x) + if (pendw) { + *pendw = 0; + goto rtn; + } + if ((wordp = pendw)) + goto g1; + hyp = hyptr; + wordp = word; + over = wne = wch = 0; + hyoff = 0; + wdhyf = -1; + memset(wdpenal, 0, wdsize * sizeof *wdpenal); + n = 0; + while (1) { /* picks up 1st char of word */ + j = cbits(i = GETCH()); +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + if (multi_locale) + collectmb(i); +#endif /* EUC && NROFF && ZWDELIMS */ + if (j == '\n') { + wne = wch = 0; + noword = 1; + goto rtn; + } + if (j == ohc) { + hyoff = 1; /* 1 => don't hyphenate */ + continue; + } + if ((j == ' ' || (padj && j == STRETCH)) && !iszbit(i)) { + lastsp = j; + n++; + if (isadjspc(i)) + w = 0; + else if (xflag && seflg && sesspsz == 0) { + i |= ZBIT; + w = 0; + } else if (xflag && seflg && sesspsz && n == 1) { + if (spbits) { + i = lastsp | SENTSP | spbits; + w = width(i); + } else + w = ses; + } else if (spbits && xflag) { + i = lastsp | spbits; + w = width(i); + } else + w = sps; + cht = cdp = 0; + storeword(i, w); + numtab[HP].val += w; + if (!isadjspc(j)) { + widthp = w; + gotspc = i; + spbits = sfmask(i); + } + continue; + } + if (gotspc) { + k = kernadjust(gotspc, i); + numtab[HP].val += k; + wne += k; + widthp += k; + } + break; + } + seflg = 0; +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + if (!multi_locale) + goto a0; + if (wddlm && iswprint(wceoll) && iswprint(cwc) && + (!iswascii(wceoll) || !iswascii(cwc)) && + !iswspace(wceoll) && !iswspace(cwc)) { + wddelim = (*wddlm)(wceoll, cwc, 1); + wceoll = 0; + if (*wddelim != ' ') { + if (!*wddelim) { + storeword(((*wdbdg)(wceoll, cwc, 1) < 3) ? + ZWDELIM(1) : ZWDELIM(2), 0); + } else { + while (*wddelim) { + if ((n = wctomb(mbbuf3, *wddelim++)) + > 0) { + m = setuc0(wddelim[-1]); + storeword(m, -1); + } else { + storeword(' ' | chbits, sps); + break; + } + } + } + spflg = 0; + goto g0; + } + } +a0: +#endif /* EUC && NROFF && ZWDELIMS */ + if (spbits && xflag) { + t = lastsp | spbits; + w = width(t); + } else { + t = lastsp | chbits; + w = sps; + } + cdp = cht = 0; + if (chompend) { + chompend = 0; + } else { + storeword(t, w + k); + } + if (spflg) { + if (xflag == 0 || ses != 0) + storeword(t | SENTSP, ses); + spflg = 0; + } + if (!nwd) + wsp = wne; +g0: + if (ninlev) + wdhyf = hyf; + if (j == CONT) { + pendw = wordp; + nflush = 0; + flushi(); + return(1); + } + if (hyoff != 1) { + if (j == ohc) { + if (!inword && xflag) { + hyoff = 1; + goto g1; + } + hyoff = 2; + *hyp++ = wordp; + if (hyp > (hyptr + NHYP - 1)) + hyp = hyptr + NHYP - 1; + if (isblbit(i) && wordp > word) + wordp[-1] |= BLBIT; + goto g1; + } + if (maybreak(j, dv)) { + if (wordp > word + 1) { + int i; + if (!xflag) + hyoff = 2; + if (gemu && hyp > hyptr && wordp > word + && hyp[-1] == wordp && ( + (i = cbits(wordp[-1])) == '-' + || i == EMDASH)) + hyp--; + *hyp++ = wordp + 1; + if (hyp > (hyptr + NHYP - 1)) + hyp = hyptr + NHYP - 1; + } + } else { + int i = cbits(j); + dv = alph(j) || (i >= '0' && i <= '9'); + } + if (xflag && nhychar(j)) + hyoff = 2; + } + j = width(i); + numtab[HP].val += j; + storeword(i, j); + if (1) { + int oev = ev; + nexti = GETCH(); + if (ev == oev) { + if (cbits(nexti) == '\n') + t = ' ' | chbits; + else + t = nexti; + k = kernadjust(i, t); + wne += k; + widthp += k; + numtab[HP].val += k; + } + } else +g1: nexti = GETCH(); + j = cbits(i = nexti); + if (gemu && (j == FILLER || j == UNPAD)) + inword = 0; + else + if (!ismot(i) && j != ohc) + inword = 1; +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + if (multi_locale) + collectmb(i); +#endif /* EUC && NROFF && ZWDELIMS */ + { + static int sentchar[] = + { '.', '?', '!', ':', 0 }; /* sentence terminators */ + int *sp, *tp; + static int transchar[] = + { '"', '\'', ')', ']', '*', 0, 0 }; + transchar[5] = DAGGER; + if ((j != '\n' && j != ' ' && (!padj || j != STRETCH)) || + ismot(i) || iszbit(i) || + isadjspc(i)) +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + if (!multi_locale) +#endif /* EUC && NROFF && ZWDELIMS */ + goto g0; +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + else { + if (!wdbdg || (iswascii(cwc) && iswascii(owc))) + goto g0; + if ((wbf = (*wdbdg)(owc, cwc, 1)) < 5) { + storeword((wbf < 3) ? ZWDELIM(1) : + ZWDELIM(2), 0); + *wordp = 0; + goto rtn; + } else goto g0; + } +#endif /* EUC && NROFF && ZWDELIMS */ + if (j == STRETCH && padj) + storeword(mkxfunc(PENALTY, INFPENALTY), 0); + wp = wordp-1; /* handle extra space at end of sentence */ + sp = *sentch ? sentch : sentchar; + tp = *transch ? transch : transchar; + while (sp[0] != IMP && wp >= word) { + j = cbits(*wp--); + if (istrans(wp[1])) + goto cont; + for (k = 0; tp[0] != IMP && tp[k] && k < NSENT; k++) + if (j == tp[k]) + goto cont; + for (k = 0; sp[k] && k < NSENT; k++) + if (j == sp[k]) { + if (nlflg) + spflg++; + else + seflg++; + break; + } + break; + cont:; + } + } +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) + wceoll = owc; +#endif /* EUC && NROFF && ZWDELIMS */ + *wordp = 0; + numtab[HP].val += xflag ? width(i) : sps; +rtn: + if (i & SFMASK) + spbits = sfmask(i); + else if (i == '\n') + spbits = chbits; + for (wp = word; *wp; wp++) { + j = cbits(*wp); + if ((j == ' ' || j == STRETCH) && !iszbit(j) && !isadjspc(j)) + continue; + if (!ischar(j) || (!isdigit(j) && j != '-')) + break; + } + if (*wp == 0) /* all numbers, so don't hyphenate */ + hyoff = 1; + wdstart = 0; + wordp = word; + pendw = 0; + *hyp++ = 0; + setnel(); + return(noword); +} + + +void +storeword(register tchar c, register int w) +{ + + if (wordp == NULL || wordp >= &word[wdsize - 3]) { + tchar *k, **h; + ptrdiff_t j; + int *pp, owdsize; + if (over) + return; + owdsize = wdsize; + wdsize += wdsize ? 100 : WDSIZE; + if ((k = realloc(word, wdsize * sizeof *word)) == NULL || + (pp = realloc(wdpenal, + wdsize * sizeof *wdpenal)) == NULL) { + flusho(); + errprint("Word overflow."); + over++; + c = LEFTHAND; + w = -1; + wdsize = owdsize; + goto s1; + } + j = (char *)k - (char *)word; + wordp = (tchar *)((char *)wordp + j); + for (h = hyptr; h < hyp; h++) + if (*h) + *h = (tchar *)((char *)*h + j); + word = k; + wdpenal = pp; + memset(&wdpenal[owdsize], 0, + (wdsize - owdsize) * sizeof *wdpenal); + } +s1: + if (isxfunc(c, PENALTY)) { + wdpenal[max(0, wordp - word - 1)] = sbits(c) | 0x80000000; + return; + } + if (isxfunc(c, DPENAL)) { + if ((wdpenal[max(0, wordp - word - 1)]&0x80000000) == 0) + wdpenal[max(0, wordp - word - 1)] = sbits(c); + return; + } + if (w == -1) + w = width(c); + widthp = w; + sethtdp(); + wne += w; + *wordp++ = c; + wch++; + if (dpenal) + wdpenal[max(0, wordp - word - 1)] = dpenal; +} + + +#ifdef NROFF +tchar gettch(void) +{ + extern int c_isalnum; + tchar i; + int j; + + i = getch(); + j = cbits(i); + if (ismot(i) || fbits(i) != ulfont) + return(i); + if (cu) { + if (trtab[j] == ' ') { + setcbits(i, '_'); + setfbits(i, FT); /* default */ + } + return(i); + } + /* should test here for characters that ought to be underlined */ + /* in the old nroff, that was the 200 bit on the width! */ + /* for now, just do letters, digits and certain special chars */ + if (j <= 127) { + if (!isalnum(j)) + setfbits(i, FT); + } else { + if (j < c_isalnum) + setfbits(i, FT); + } + return(i); +} + + +#endif +#if defined (EUC) && defined (NROFF) && defined (ZWDELIMS) +int +collectmb(tchar i) +{ + owc = cwc; + cwc = tr2un(cbits(i), fbits(i)); + return(0); +} + + +#endif /* EUC && NROFF && ZWDELIMS */ + +static tchar +adjbit(tchar c) +{ + if (cbits(c) == ' ') + setcbits(c, WORDSP); + return(c | ADJBIT); +} + +static void +sethtdp(void) +{ + if ((cht = lastrst) > maxcht) + maxcht = cht; + if ((cdp = -lastrsb) > maxcdp) + maxcdp = cdp; +} + +static void +leftend(tchar c, int hang, int dolpfx) +{ + int k, w; + + if (dolpfx && lpfx) { + if (hang) + setlhang(lpfx[0]); + for (k = 0; lpfx[k]; k++) { + w = width(lpfx[k]); + w += k ? kernadjust(lpfx[k-1], lpfx[k]) : 0; + storeline(lpfx[k], w); + } + if (k) { + w = kernadjust(lpfx[k-1], c); + nel -= w; + ne += w; + } + } else if (hang) + setlhang(c); +} + +#ifndef NROFF +static void +setlhang(tchar c) +{ + int k; + + if (lhangtab != NULL && !ismot(c) && cbits(c) != SLANT && + cbits(c) != XFUNC && + lhangtab[fbits(c)] != NULL && + (k = lhangtab[fbits(c)][cbits(c)]) != 0) { + width(c); /* set xpts */ + k = (k * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth; + nel -= k; + storeline(makem(k), 0); + } +} + +static void +setrhang(void) +{ + int j, k; + tchar c; + + if (nc > 0) { + c = 0; + for (j = nc - 1; j >= 0; j--) + if ((c = line[j]) != IMP) + break; + width(c); + j = lasttrack; + j += kernadjust(c, ' ' | sfmask(c)); + if (admod != 1 && rhangtab != NULL && !ismot(c) && + rhangtab[xfont] != NULL && + (k = rhangtab[xfont][cbits(c)]) != 0) { + rhang = (k * u2pts(xpts) + (Unitwidth / 2)) / Unitwidth; + j += rhang; + } + ne -= j; + nel += j; + } +} + +static void +letshrink(void) +{ + int diff, nsp, lshdiff; + + nsp = nwd == 1 ? nwd : nwd - 1; + diff = nel; + if (lspnc && lsplow) + diff += nel * nsp / lspnc; + if (lshwid) { + if (lshlow < -diff / 2) + lshcur = -lshmin; + else if (lsplow < -diff / 2) + lshcur = (double)(diff - lsplow) / lshwid * LAFACT; + else + lshcur = (double)diff / 2 / lshwid * LAFACT; + lshdiff = (double)lshcur / LAFACT * lshwid; + nel -= lshdiff; + ne += lshdiff; + } else + lshdiff = 0; + diff -= lshdiff; + if (lsplow) + lspcur = lspmin * diff / lsplow; + else + lspcur = 0; + ne += lspcomp(lshdiff); +} + +static int +letgrow(void) +{ + int diff, n, nsp, lshdiff; + + nsp = nwd == 1 ? nwd : nwd - 1; + if ((lspnc - nsp <= 0 || lsphigh <= 0) && lshhigh <= 0) + return 0; + n = (letsps - (minsps && ad && !admod ? minsps : sps)) * nsp; + diff = nel; + if (lspnc && lsphigh) + diff += nel * nsp / lspnc - n; + if (lshwid) { + if (lshhigh < diff / 2) + lshcur = lshmax; + else if (lsphigh < diff / 2) + lshcur = (double)(diff - lsphigh) / lshwid * LAFACT; + else + lshcur = (double)diff / 2 / lshwid * LAFACT; + lshdiff = (double)lshcur / LAFACT * lshwid; + nel -= lshdiff; + ne += lshdiff; + } else + lshdiff = 0; + diff -= lshdiff; + if (diff > lsphigh) + diff = lsphigh; + if (lsphigh) + lspcur = lspmax * diff / lsphigh; + else + lspcur = 0; + return lspcomp(lshdiff); +} + +static int +lspcomp(int idiff) +{ + int diff = 0, i; + tchar c; + + diff = 0; + for (i = 0; i < nc; i++) + if (!ismot(c = line[i])) { + if (isxfunc(c, FLDMARK)) + diff = lsplast = 0; + else if (cbits(c) > ' ' || isxfunc(c, CHAR)) { + while (isxfunc(c, CHAR)) + c = charout[sbits(c)].ch; + lsplast = (int)sbits(c) / 2 * lspcur / LAFACT; + diff += lsplast; + } + } + diff -= lsplast; + nel -= diff; + ne += lsplast; + return idiff + diff; +} +#endif /* !NROFF */ + +/* + * A dynamic programming approach to line breaking over + * a paragraph as introduced by D. E. Knuth & M. F. Plass, + * "Breaking paragraphs into lines", Software - Practice + * and Experience, Vol. 11, Issue 12 (1981), pp. 1119-1184. + */ + +static double +penalty(int k, int s, int h, int h2, int h3) +{ + double t, d; + + t = nel - k; + t = t >= 0 ? t * 5 / 3 : -t; + if (ad && !admod) { + d = s; + if (k - s && (letsps || lshmin || lshmax)) + d += (double)(k - s) / 100; + if (d) + t /= d; + } else + t /= nel / 10; + if (h && hypp) + t += hypp; + if (h2 && hypp2) + t += hypp2; + if (h3 && hypp3) + t += hypp3; + t = t * t * t; + if (t > MAXPENALTY) + t = MAXPENALTY; + return t; +} + +static void +parcomp(int start) +{ + double *cost, *_cost; + long double t; + int *prevbreak, *hypc, *_hypc, *brcnt, *_brcnt; + int i, j, k, m, h, v, s; + + _cost = malloc((pgsize + 1) * sizeof *_cost); + cost = &_cost[1]; + _hypc = calloc(pgsize + 1, sizeof *_hypc); + hypc = &_hypc[1]; + _brcnt = calloc(pgsize + 1, sizeof *_brcnt); + brcnt = &_brcnt[1]; + prevbreak = calloc(pgsize, sizeof *prevbreak); + for (i = -1; i < start; i++) + cost[i] = 0; + for (i = start; i < pgwords; i++) + cost[i] = HUGE_VAL; + for (i = start; i < pgwords; i++) { + if (pshapes) { + j = brcnt[i-1]; + if (j < pshapes) + nel = pgll[j] - pgin[j]; + else + nel = pgll[pshapes-1] - pgin[pshapes-1]; + } else if (un != in) { + nel = ll; + nel -= i > start ? in : un; + } + k = pgwordw[i] + pglgsw[i]; + m = pglsphc[i] + pglgsh[i]; + s = 0; + for (j = i; j < pgwords; j++) { + if (j > i) { + k += pgspacw[j] + pgwordw[j]; + m += pgadspc[j] + pglsphc[j]; + s += pgspacw[j]; + } + v = k + pghyphw[j] + pglgew[j]; + if (v - m - pglgeh[j] <= nel) { + if (!spread && j == pgwords - 1 && + pgpenal[j] == 0) + t = 0; + else + t = penalty(v, s, pghyphw[j], + pghyphw[j] && hypc[i-1], + pghyphw[j] && j >= pglastw); + t += pgpenal[j]; + t += cost[i-1]; + /*fprintf(stderr, "%c%c%c%c to %c%c%c%c " + "t=%g cost[%d]=%g " + "brcnt=%d oldbrcnt=%d\n", + (char)para[pgwordp[i]], + (char)para[pgwordp[i]+1], + (char)para[pgwordp[i]+2], + (char)para[pgwordp[i]+3], + (char)para[pgwordp[j+1]-4], + (char)para[pgwordp[j+1]-3], + (char)para[pgwordp[j+1]-2], + (char)para[pgwordp[j+1]-1], + t, j, cost[j], + 1 + brcnt[i-1], + brcnt[j] + );*/ + if ((double)t <= cost[j]) { + if (pghyphw[j]) + h = hypc[i-1] + 1; + else + h = 0; + /* + * This is not completely + * correct: It might be + * preferable to disallow + * an earlier hyphenation + * point. But it seems + * good enough. + */ + if (hlm < 0 || h <= hlm) { + hypc[j] = h; + cost[j] = t; + prevbreak[j] = i; + brcnt[j] = 1 + brcnt[i-1]; + } + } + } else { + if (j == i) { + t = 1 + cost[i-1]; + cost[j] = t; + prevbreak[j] = i; + brcnt[j] = 1 + brcnt[i-1]; + } + break; + } + } + } + /*for (i = 0; i < pgwords; i++) + fprintf(stderr, "cost[%d] = %g %c%c%c%c to %c%c%c%c\n", + i, cost[i], + (char)para[pgwordp[prevbreak[i]]], + (char)para[pgwordp[prevbreak[i]]+1], + (char)para[pgwordp[prevbreak[i]]+2], + (char)para[pgwordp[prevbreak[i]]+3], + (char)para[pgwordp[i]], + (char)para[pgwordp[i]+1], + (char)para[pgwordp[i]+2], + (char)para[pgwordp[i]+3] + );*/ + pglines = 0; + memset(&pgopt[pglnout], 0, (pgsize - pglnout) * sizeof *pgopt); + i = j = pgwords - 1; + do { + pglines++; + j = prevbreak[j]; + pgopt[i--] = j--; + } while (j >= start && i >= pglnout); + memmove(&pgopt[pglnout+1], &pgopt[i+2], pglines * sizeof *pgopt); + pgopt[pglnout] = start; + free(_cost); + free(_hypc); + free(_brcnt); + free(prevbreak); +} + +void +growpgsize(void) +{ + pgsize += 20; + pgwordp = realloc(pgwordp, pgsize * sizeof *pgwordp); + pgwordw = realloc(pgwordw, pgsize * sizeof *pgwordw); + pghyphw = realloc(pghyphw, pgsize * sizeof *pghyphw); + pgadspc = realloc(pgadspc, pgsize * sizeof *pgadspc); + pglsphc = realloc(pglsphc, pgsize * sizeof *pglsphc); + pgopt = realloc(pgopt, pgsize * sizeof *pgopt); + pgspacp = realloc(pgspacp, pgsize * sizeof *pgspacp); + pgspacw = realloc(pgspacw, pgsize * sizeof *pgspacw); + pglgsc = realloc(pglgsc, pgsize * sizeof *pglgsc); + pglgec = realloc(pglgec, pgsize * sizeof *pglgec); + pglgsw = realloc(pglgsw, pgsize * sizeof *pglgsw); + pglgew = realloc(pglgew, pgsize * sizeof *pglgew); + pglgsh = realloc(pglgsh, pgsize * sizeof *pglgsh); + pglgeh = realloc(pglgeh, pgsize * sizeof *pglgeh); + pgin = realloc(pgin, pgsize * sizeof *pgin); + pgll = realloc(pgll, pgsize * sizeof *pgll); + pgwdin = realloc(pgwdin, pgsize * sizeof *pgwdin); + pgwdll = realloc(pgwdll, pgsize * sizeof *pgwdll); + pgflags = realloc(pgflags, pgsize * sizeof *pgflags); + pglno = realloc(pglno, pgsize * sizeof *pglno); + pgpenal = realloc(pgpenal, pgsize * sizeof *pgpenal); + if (pgwordp == NULL || pgwordw == NULL || pghyphw == NULL || + pgopt == NULL || pgspacw == NULL || + pgadspc == NULL || pglsphc == NULL || + pglgsc == NULL || pglgec == NULL || + pglgsw == NULL || pglgew == NULL || + pglgsh == NULL || pglgeh == NULL || + pgin == NULL || pgll == NULL || + pgwdin == NULL || pgwdll == NULL || + pgflags == NULL || pglno == NULL || + pgpenal == NULL || pgwdin == NULL || pgwdin == NULL) { + errprint("out of memory justifying paragraphs"); + done(02); + } +} + +static void +parlgzero(int i) +{ + pglgsc[i] = 0; + pglgec[i] = 0; + pglgsw[i] = 0; + pglgew[i] = 0; + pglgsh[i] = 0; + pglgeh[i] = 0; +} + +static float +makepgpenal(int p) +{ + p &= ~0x80000000; + p -= INFPENALTY0 + 1; + if (p >= INFPENALTY0) + return INFPENALTY; + else if (p <= -INFPENALTY0) + return -INFPENALTY; + else + return p * PENALSCALE; +} + +static void +parword(void) +{ + int a, c, w, hc; + tchar i, *wp; + + if (pgwords + 1 >= pgsize) + growpgsize(); + hc = shc ? shc : HYPHEN; + pglastw = pgwords; + wp = wordp; + a = w = 0; + pglno[pgwords] = numtab[CD].val; + pgspacp[pgwords] = pgspacs; + pgpenal[pgwords] = 0; + pgwdin[pgwords] = in; + pgwdll[pgwords] = ll; + if (pgwords == 0) + pgflags[pgwords] = 0; + un1 = -1; + while ((c = cbits(i = *wp++)) == ' ' || c == STRETCH) { + if (iszbit(i)) + break; + wch--; + minflg = minspsz && ad && !admod; + w += width(i); + a += minspc; + w += kernadjust(wp[-1], wp[0]); + if (pgspacs >= pgssize) { + pgssize += 60; + parsp = realloc(parsp, pgssize * sizeof *parsp); + if (parsp == NULL) { + errprint("no memory for spaces in paragraph"); + done(02); + } + } + parsp[pgspacs++] = i; + if (c == STRETCH) + pgpenal[pgwords] = INFPENALTY; + else if (wdpenal[wp-word-1]) + pgpenal[pgwords] = makepgpenal(wdpenal[wp-word-1]); + } + if (wch == 0) + return; + pgspacp[pgwords+1] = pgspacs; + if (--wp > wordp && pgchars > 0) + w += kernadjust(para[pgchars-1], wordp[0]); + wne -= w; + pgspacw[pgwords] = pgwords ? w + a : 0; + pghyphw[pgwords] = 0; + pgadspc[pgwords] = pgwords ? a : 0; + pglsphc[pgwords] = 0; + pgwordw[pgwords] = 0; + pgwordp[pgwords] = pgchars; + pgne += pgspacw[pgwords]; + parlgzero(pgwords); + parlgzero(pgwords+1); + if (wdhyf == -1) + wdhyf = hyf; + if (!hyoff && wdhyf && hlm) + hyphen(wp); + hyp = hyptr; + nhyp = 0; + while (*hyp && *hyp <= wp) + hyp++; + while (wch) { + if (ishyp(wp) && !maybreak(wp[-1], 1)) { + i = sfmask(wp[-1]) | hc; + w = width(i); + w += kernadjust(wp[-1], i); + pghyphw[pgwords] = w; +#ifndef NROFF + { + int *ip; + intptr_t n; + tchar e, s; + + n = (intptr_t)hyp[-1] & 03; + ip = n ? lgrevtab[fbits(*wp)][cbits(*wp)] : NULL; + if (n != 0 && ip != NULL) { + pglgec[pgwords] = e = + strlg(fbits(*wp), ip, n) | + sfmask(*wp) | AUTOLIG; + for (w = 0; ip[n+w]; w++); + pglgsc[pgwords+1] = s = + strlg(fbits(*wp), &ip[n], w) | + sfmask(*wp) | AUTOLIG; + pglgew[pgwords] = width(e); + pglgeh[pgwords] = getlsh(e, rawwidth) * + lshmin / LAFACT; + pglgew[pgwords] += kernadjust(wp[-1], e); + pghyphw[pgwords] += kernadjust(e, i); + pghyphw[pgwords] -= kernadjust(wp[-1], i); + pglgsw[pgwords+1] = width(s); + pglgsh[pgwords+1] = getlsh(s, rawwidth) * + lshmin / LAFACT; + pglgsw[pgwords+1] -= width(*wp); + pglgsh[pgwords+1] -= getlsh(*wp, rawwidth) * + lshmin / LAFACT; + pglgsw[pgwords+1] += kernadjust(s, wp[1]); + pglgsw[pgwords+1] -= kernadjust(wp[0], wp[1]); + } } +#endif /* !NROFF */ + } + if (pghyphw[pgwords] || (wp > word && maybreak(wp[-1], 1))) { + if (pghyphw[pgwords]) + pghyphw[pgwords] -= kernadjust(wp[-1], wp[0]); + pgne += pgwordw[pgwords]; + pgwordp[++pgwords] = pgchars; + if (pgwords + 1 >= pgsize) + growpgsize(); + pglno[pgwords] = numtab[CD].val; + pgspacp[pgwords] = pgspacs; + pgspacp[pgwords+1] = pgspacs; + pgspacw[pgwords] = 0; + pgwordw[pgwords] = 0; + pghyphw[pgwords] = 0; + pgadspc[pgwords] = 0; + pglsphc[pgwords] = 0; + pgpenal[pgwords] = 0; + pgwdin[pgwords] = in; + pgwdll[pgwords] = ll; + pgflags[pgwords] = 0; + parlgzero(pgwords+1); + } + i = *wp++; + w = width(i); + pglsphc[pgwords] += getlsh(i, rawwidth) * lshmin / LAFACT; + w += kernadjust(i, *wp); + wne -= w; + wch--; + pgwordw[pgwords] += w; + if (letsps) + pglsphc[pgwords] += getlsp(i) * lspmin / LAFACT; + if (pgchars + 1 >= pgcsize) { + pgcsize += 600; + para = realloc(para, pgcsize * sizeof *para); + if (para == NULL) { + errprint("no memory for characters " + "in paragraph"); + done(02); + } + } + para[pgchars++] = i; + if (wdpenal[wp-word-1]) + pgpenal[pgwords] = makepgpenal(wdpenal[wp-word-1]); + } + pgne += pgwordw[pgwords]; + pgwordp[++pgwords] = pgchars; + pgspacw[pgwords] = 0; + pgwordw[pgwords] = 0; + pghyphw[pgwords] = 0; + pgadspc[pgwords] = 0; + pglsphc[pgwords] = 0; + pgpenal[pgwords] = 0; + pgwdin[pgwords] = in; + pgwdll[pgwords] = ll; + pgflags[pgwords] = 0; + parlgzero(pgwords); + if (spread) + tbreak(); +} + +static void +pbreak(int sprd, int lastf, struct s *s) +{ + int j; + + if (sprd) + adflg |= 5; + if (pshapes) { + j = pglnout < pshapes ? pglnout : pshapes - 1; + un = pgin[j]; + } + nlflg = 1; + tbreak(); + pglnout++; + if (trap) { + extern jmp_buf sjbuf; + jmp_buf savsjbuf; + if (setjmp(*s->jmp) == 0) { + nlflg = 1; + memcpy(&savsjbuf, &sjbuf, sizeof sjbuf); + if (donep && lastf) + donef = -1; + mainloop(); + } + memcpy(&sjbuf, &savsjbuf, sizeof sjbuf); + } +} + +void +parpr(struct s *s) +{ + int i, j, k = 0, nw = 0, w, stretches, _spread = spread, hc; + int savll, savin, savcd, lastin, lastll, curin, curll; + tchar c, e, lastc, lgs; + + savll = ll; + savin = in; + curin = 0; + lastin = 0; + curll = -1; + lastll = 0; + savcd = numtab[CD].val; + hc = shc ? shc : HYPHEN; + nw = 0; + for (i = 0; i < pgwords; i++) { + lgs = 0; + numtab[CD].val = pglno[i]; + if (i == 0 || pgflags[i] & PG_NEWIN) + lastin = pgwdin[i]; + if (i == 0 || pgflags[i] & PG_NEWLL) + lastll = pgwdll[i]; + if (k == 0 || pgopt[k] == i) { + if (k++ > 0) { + if (pghyphw[i-1]) { +#ifndef NROFF + if ((e = pglgec[i-1]) != 0) { + w = width(e); + storelsh(e, rawwidth); + w += kernadjust(para[pgwordp[i]-1], e); + storeline(e, w); + if (letsps) + storelsp(e, 0); + lgs = pglgsc[i]; + } else +#endif + e = para[pgwordp[i]-1]; + c = sfmask(e) | hc; + w = width(c); + storelsh(c, rawwidth); + w += kernadjust(e, c); + storeline(c, w); + if (letsps) + storelsp(c, 0); + } + pbreak(1, i >= pgwords, s); + if (i >= pgwords) + break; + } + if (pshapes) { + if (k == 1) + parcomp(0); + j = k-1 < pshapes ? k-1 : pshapes - 1; + ll = pgll[j]; + un = pgin[j]; + nel = ll - un; + } else if (k > 1 && (in != curin || ll != curll)) { + savin = curin = lastin = in; + savll = curll = lastll = ll; + un = in; + nel = ll - un; + parcomp(i); + } else if (lastin != curin || lastll != curll) { + savin = in = curin = lastin; + savll = ll = curll = lastll; + if (k > 1) + un = in; + nel = ll - un; + parcomp(i); + } + nel = ll - un; + nw = nwd = 1; + leftend(para[pgwordp[i]], admod != 1 && admod != 2, 1); + } else { + for (j = pgspacp[i]; j < pgspacp[i+1]; j++) { + c = parsp[j]; + minflg = minspsz && ad && !admod; + w = width(c); + adspc += minspc; + if (j == pgspacp[i] && i > 0) + w += kernadjust(para[pgwordp[i]-1], c); + if (j == pgspacp[i+1]-1) + w += kernadjust(c, para[pgwordp[i]]); + storeline(c, w); + spbits = sfmask(c); + } + nwd += pgspacp[i] != pgspacp[i+1]; + } + stretches = 0; + lastc = 0; + for (j = pgwordp[i]; j < pgwordp[i+1]; j++) { + c = lgs ? lgs : para[j]; + lgs = 0; + w = width(c); + storelsh(c, rawwidth); + if (j == pgwordp[i] && i > 0 && nw > 1 && + pgspacp[i] == pgspacp[i+1]) + w += kernadjust(para[j-1], c); + if (j < pgwordp[i+1]-1) + w += kernadjust(c, para[j+1]); + storeline(c, w); + if (cbits(c) == STRETCH && cbits(lastc) != STRETCH) + stretches++; + lastc = c; + if (letsps) + storelsp(c, 0); + } + nwd += stretches; + nw++; + } + pbreak((nel - adspc < 0 && nwd > 1) || _spread, 1, s); + if (pgflags[pgwords] & PG_NEWIN) + savin = pgwdin[pgwords]; + if (pgflags[pgwords] & PG_NEWLL) + savll = pgwdll[pgwords]; + pgwords = pgchars = pgspacs = pglines = pgne = pglastw = 0; + ll = savll; + in = un = savin; + numtab[CD].val = savcd; +} + +static void +parfmt(void) +{ + int _nlflg = nlflg; + int _spread = spread; + struct s *s; + + if (pgchars == 0) + return; + setnel(); + pglnout = 0; + s = frame; + nxf->jmp = malloc(sizeof *nxf->jmp); + pushi(-2, 0, FLAG_PARAGRAPH); + parpr(frame); + while (frame != s) + ch = popi(); + nlflg = _nlflg; + if (_spread == 1 && pshapes > pglnout) { + memmove(&pgin[0], &pgin[pglnout], + (pshapes - pglnout) * sizeof *pgin); + memmove(&pgll[0], &pgll[pglnout], + (pshapes - pglnout) * sizeof *pgll); + pshapes -= pglnout; + } else + pshapes = 0; +} |
