ren: disable ligatures and pairwise kerning when interpolating diverted text
[neatroff.git] / adj.c
blob5e0693b3c0f7795e5afdc854eb1a5541d3051b2e
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "roff.h"
6 #define ADJ_LLEN(a) MAX(0, (a)->ll - ((a)->lt >= 0 ? (a)->lt : (a)->li))
8 struct adj {
9 struct wb wbs[NWORDS]; /* words in buf */
10 int gaps[NWORDS]; /* gaps before words */
11 int nwords;
12 int wid; /* total width of buf */
13 int swid; /* current space width */
14 int gap; /* space before the next word */
15 int nls; /* newlines before the next word */
16 int l, i, t; /* current .l, .i and ti */
17 int ll, li, lt; /* current line's .l, .i and ti */
18 int filled; /* filled all words in the last adj_fill() */
21 void adj_ll(struct adj *adj, int ll)
23 adj->l = ll;
26 void adj_ti(struct adj *adj, int ti)
28 adj->t = ti;
31 void adj_in(struct adj *adj, int in)
33 adj->i = in;
36 /* .ll, .in and .ti are delayed until the partial line is output */
37 static void adj_confupdate(struct adj *adj)
39 adj->ll = adj->l;
40 adj->li = adj->i;
41 adj->lt = adj->t;
42 adj->t = -1;
45 /* does the adjustment buffer need to be flushed without filling? */
46 static int adj_fullnf(struct adj *a)
48 /* blank lines; indented lines; newlines when buffer is empty */
49 return a->nls > 1 || (a->nls && a->gap) ||
50 (a->nls - a->filled > 0 && !a->nwords);
53 /* does the adjustment buffer need to be flushed? */
54 int adj_full(struct adj *a, int fill)
56 if (!fill)
57 return a->nls - a->filled > 0;
58 if (adj_fullnf(a))
59 return 1;
60 return a->nwords && a->wid > ADJ_LLEN(a);
63 /* is the adjustment buffer empty? */
64 int adj_empty(struct adj *a, int fill)
66 return !fill ? a->nls - a->filled <= 0 : !a->nwords && !adj_fullnf(a);
69 /* set space width */
70 void adj_swid(struct adj *adj, int swid)
72 adj->swid = swid;
75 /* move words inside an adj struct */
76 static void adj_movewords(struct adj *a, int dst, int src, int len)
78 memmove(a->wbs + dst, a->wbs + src, len * sizeof(a->wbs[0]));
79 memmove(a->gaps + dst, a->gaps + src, len * sizeof(a->gaps[0]));
82 static int adj_linewid(struct adj *a, int n)
84 int i, w = 0;
85 for (i = 0; i < n; i++)
86 w += wb_wid(&a->wbs[i]) + a->gaps[i];
87 return w;
90 static int adj_linefit(struct adj *a, int llen)
92 int i, w = 0;
93 for (i = 0; i < a->nwords; i++) {
94 w += wb_wid(&a->wbs[i]) + a->gaps[i];
95 if (w > llen)
96 return i;
98 return i;
101 /* move n words from the adjustment buffer to s */
102 static int adj_move(struct adj *a, int n, struct sbuf *s, int *els_neg, int *els_pos)
104 struct wb *cur;
105 int w = 0;
106 int i;
107 *els_neg = 0;
108 *els_pos = 0;
109 for (i = 0; i < n; i++) {
110 cur = &a->wbs[i];
111 sbuf_printf(s, "%ch'%du'", c_ec, a->gaps[i]);
112 sbuf_append(s, sbuf_buf(&cur->sbuf));
113 w += wb_wid(cur) + a->gaps[i];
114 if (cur->els_neg < *els_neg)
115 *els_neg = cur->els_neg;
116 if (cur->els_pos > *els_pos)
117 *els_pos = cur->els_pos;
118 wb_done(cur);
120 if (!n)
121 return 0;
122 a->nwords -= n;
123 adj_movewords(a, 0, n, a->nwords);
124 a->wid = adj_linewid(a, a->nwords);
125 if (a->nwords) /* apply the new .l and .i */
126 adj_confupdate(a);
127 return w;
130 /* try to hyphenate the n-th word */
131 static void adj_hyph(struct adj *a, int n, int w, int hyph)
133 struct wb w1, w2;
134 int flg = hyph | (n ? 0 : HY_ANY);
135 wb_init(&w1);
136 wb_init(&w2);
137 if (wb_hyph(&a->wbs[n], w, &w1, &w2, flg)) {
138 wb_done(&w1);
139 wb_done(&w2);
140 return;
142 adj_movewords(a, n + 2, n + 1, a->nwords - n);
143 wb_done(&a->wbs[n]);
144 memcpy(&a->wbs[n], &w1, sizeof(w1));
145 memcpy(&a->wbs[n + 1], &w2, sizeof(w2));
146 a->nwords++;
147 a->gaps[n + 1] = 0;
148 a->wid = adj_linewid(a, a->nwords);
151 /* fill and copy a line into s */
152 int adj_fill(struct adj *a, int ad_b, int fill, int hyph, struct sbuf *s,
153 int *ll, int *in, int *ti, int *els_neg, int *els_pos)
155 int adj_div, adj_rem;
156 int w = 0;
157 int i, n;
158 int llen = ADJ_LLEN(a);
159 *ll = a->ll;
160 *in = a->li;
161 *ti = a->lt;
162 if (!fill || adj_fullnf(a)) {
163 a->filled = 0;
164 a->nls--;
165 return adj_move(a, a->nwords, s, els_neg, els_pos);
167 n = adj_linefit(a, llen);
168 if (n < a->nwords)
169 adj_hyph(a, n, llen - adj_linewid(a, n) - a->gaps[n], hyph);
170 n = adj_linefit(a, llen);
171 if (!n && a->nwords)
172 n = 1;
173 w = adj_linewid(a, n);
174 if (ad_b && n > 1) {
175 adj_div = (llen - w) / (n - 1);
176 adj_rem = (llen - w) % (n - 1);
177 for (i = 0; i < n - 1; i++)
178 a->gaps[i + 1] += adj_div + (i < adj_rem);
180 w = adj_move(a, n, s, els_neg, els_pos);
181 if (a->nwords)
182 a->wid -= a->gaps[0];
183 a->gaps[0] = 0;
184 a->filled = n && !a->nwords;
185 return w;
188 void adj_sp(struct adj *adj)
190 adj->gap += adj->swid;
193 void adj_nl(struct adj *adj)
195 adj->nls++;
196 adj->gap = 0;
199 /* ignore the previous newline */
200 void adj_nonl(struct adj *adj)
202 if (adj->nls)
203 adj->gap += adj->swid;
204 adj->nls = 0;
207 static void adj_word(struct adj *adj, struct wb *wb)
209 int i = adj->nwords++;
210 wb_init(&adj->wbs[i]);
211 adj->gaps[i] = adj->filled ? 0 : adj->gap;
212 adj->filled = 0;
213 adj->wid += wb_wid(wb) + adj->gap;
214 wb_cat(&adj->wbs[i], wb);
217 static int adj_eos(struct adj *adj)
219 return adj->nwords && wb_eos(&adj->wbs[adj->nwords - 1]);
222 /* insert wb into the adjustment buffer */
223 void adj_wb(struct adj *adj, struct wb *wb)
225 if (wb_empty(wb) || adj->nwords == NWORDS)
226 return;
227 if (!adj->nwords) /* apply the new .l and .i */
228 adj_confupdate(adj);
229 if (adj->nls && !adj->gap && adj->nwords >= 1)
230 adj->gap = adj_eos(adj) ? adj->swid * 2 : adj->swid;
231 adj_word(adj, wb);
232 adj->nls = 0;
233 adj->gap = 0;
236 struct adj *adj_alloc(void)
238 struct adj *adj = malloc(sizeof(*adj));
239 memset(adj, 0, sizeof(*adj));
240 return adj;
243 void adj_free(struct adj *adj)
245 free(adj);
248 int adj_wid(struct adj *adj)
250 return adj->wid + (adj->nls ? adj->swid : adj->gap);