wb: ignore requests in diverted text
[neatroff.git] / wb.c
blobbac149658e0f89297b3f2df451d8d6f9d006a239
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "roff.h"
6 #define R_F(wb) ((wb)->r_f >= 0 ? (wb)->r_f : n_f) /* current font */
7 #define R_S(wb) ((wb)->r_s >= 0 ? (wb)->r_s : n_s) /* current size */
8 #define R_M(wb) ((wb)->r_m >= 0 ? (wb)->r_m : n_m) /* current color */
10 void wb_init(struct wb *wb)
12 memset(wb, 0, sizeof(*wb));
13 sbuf_init(&wb->sbuf);
14 wb->f = -1;
15 wb->s = -1;
16 wb->m = -1;
17 wb->r_f = -1;
18 wb->r_s = -1;
19 wb->r_m = -1;
22 void wb_done(struct wb *wb)
24 sbuf_done(&wb->sbuf);
27 /* update wb->st and wb->sb */
28 static void wb_stsb(struct wb *wb)
30 wb->st = MIN(wb->st, wb->v - SC_HT);
31 wb->sb = MAX(wb->sb, wb->v);
34 /* append font and size to the buffer if needed */
35 static void wb_font(struct wb *wb)
37 if (wb->f != R_F(wb)) {
38 sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, R_F(wb));
39 wb->f = R_F(wb);
41 if (wb->s != R_S(wb)) {
42 sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
43 wb->s = R_S(wb);
45 if (!n_cp && wb->m != R_M(wb)) {
46 sbuf_printf(&wb->sbuf, "%cm[%s]", c_ec, clr_str(R_M(wb)));
47 wb->m = R_M(wb);
49 wb_stsb(wb);
52 void wb_hmov(struct wb *wb, int n)
54 wb->h += n;
55 sbuf_printf(&wb->sbuf, "%ch'%du'", c_ec, n);
58 void wb_vmov(struct wb *wb, int n)
60 wb->v += n;
61 sbuf_printf(&wb->sbuf, "%cv'%du'", c_ec, n);
64 void wb_els(struct wb *wb, int els)
66 if (els > wb->els_pos)
67 wb->els_pos = els;
68 if (els < wb->els_neg)
69 wb->els_neg = els;
70 sbuf_printf(&wb->sbuf, "%cx'%du'", c_ec, els);
73 void wb_etc(struct wb *wb, char *x)
75 wb_font(wb);
76 sbuf_printf(&wb->sbuf, "%cX\x02%s\x02", c_ec, x);
79 void wb_put(struct wb *wb, char *c)
81 struct glyph *g;
82 if (c[0] == '\n') {
83 wb->part = 0;
84 return;
86 if (c[0] == ' ') {
87 wb_hmov(wb, charwid(dev_spacewid(), R_S(wb)));
88 return;
90 if (c[0] == '\t' || c[0] == '\x01' ||
91 (c[0] == c_ni && (c[1] == '\t' || c[1] == '\x01'))) {
92 sbuf_append(&wb->sbuf, c);
93 return;
95 g = dev_glyph(c, R_F(wb));
96 wb_font(wb);
97 if (!c[1] || c[0] == c_ec || c[0] == c_ni ||
98 utf8len((unsigned char) c[0]) == strlen(c)) {
99 if (c[0] == c_ni && c[1] == c_ec)
100 sbuf_printf(&wb->sbuf, "%c%c", c_ec, c_ec);
101 else
102 sbuf_append(&wb->sbuf, c);
103 } else {
104 if (c[1] && !c[2])
105 sbuf_printf(&wb->sbuf, "%c(%s", c_ec, c);
106 else
107 sbuf_printf(&wb->sbuf, "%cC'%s'", c_ec, c);
109 if (strcmp(c_hc, c)) {
110 strcpy(wb->prev_c, c);
111 wb->prev_l = sbuf_len(&wb->sbuf);
112 wb->prev_h = wb->h;
113 wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
114 wb->ct |= g ? g->type : 0;
115 wb_stsb(wb);
119 /* return zero if c formed a ligature with its previous character */
120 int wb_lig(struct wb *wb, char *c)
122 char lig[GNLEN * 2];
123 if (wb->prev_l != sbuf_len(&wb->sbuf) || !wb->prev_c[0])
124 return 1;
125 sprintf(lig, "%s%s", wb->prev_c, c);
126 if (font_lig(dev_font(R_F(wb)), lig)) {
127 wb->h = wb->prev_h;
128 sbuf_pop(&wb->sbuf);
129 wb_put(wb, lig);
130 return 0;
132 return 1;
135 /* return 0 if pairwise kerning was done */
136 int wb_kern(struct wb *wb, char *c)
138 int val;
139 if (wb->prev_l != sbuf_len(&wb->sbuf) || !wb->prev_c[0])
140 return 1;
141 val = font_kern(dev_font(R_F(wb)), wb->prev_c, c);
142 if (val)
143 wb_hmov(wb, charwid(val, R_S(wb)));
144 return !val;
147 int wb_part(struct wb *wb)
149 return wb->part;
152 void wb_setpart(struct wb *wb)
154 wb->part = 1;
157 void wb_drawl(struct wb *wb, int h, int v)
159 wb_font(wb);
160 sbuf_printf(&wb->sbuf, "%cD'l %du %du'", c_ec, h, v);
161 wb->h += h;
162 wb->v += v;
163 wb_stsb(wb);
166 void wb_drawc(struct wb *wb, int r)
168 wb_font(wb);
169 sbuf_printf(&wb->sbuf, "%cD'c %du'", c_ec, r);
170 wb->h += r;
173 void wb_drawe(struct wb *wb, int h, int v)
175 wb_font(wb);
176 sbuf_printf(&wb->sbuf, "%cD'e %du %du'", c_ec, h, v);
177 wb->h += h;
180 void wb_drawa(struct wb *wb, int h1, int v1, int h2, int v2)
182 wb_font(wb);
183 sbuf_printf(&wb->sbuf, "%cD'a %du %du %du %du'", c_ec, h1, v1, h2, v2);
184 wb->h += h1 + h2;
185 wb->v += v1 + v2;
186 wb_stsb(wb);
189 void wb_drawxbeg(struct wb *wb, int c)
191 wb_font(wb);
192 sbuf_printf(&wb->sbuf, "%cD'%c", c_ec, c);
195 void wb_drawxdot(struct wb *wb, int h, int v)
197 sbuf_printf(&wb->sbuf, " %du %du", h, v);
198 wb->h += h;
199 wb->v += v;
200 wb_stsb(wb);
203 void wb_drawxend(struct wb *wb)
205 sbuf_printf(&wb->sbuf, "'");
208 static void wb_reset(struct wb *wb)
210 wb_done(wb);
211 wb_init(wb);
214 static void wb_putc(struct wb *wb, int t, char *s)
216 switch (t) {
217 case 0:
218 case 'C':
219 wb_put(wb, s);
220 break;
221 case 'D':
222 ren_draw(wb, s);
223 break;
224 case 'f':
225 wb->r_f = atoi(s);
226 break;
227 case 'h':
228 wb_hmov(wb, atoi(s));
229 break;
230 case 'm':
231 wb->r_m = clr_get(s);
232 break;
233 case 's':
234 wb->r_s = atoi(s);
235 break;
236 case 'v':
237 wb_vmov(wb, atoi(s));
238 break;
239 case 'x':
240 wb_els(wb, atoi(s));
241 break;
242 case 'X':
243 wb_etc(wb, s);
244 break;
248 void wb_cat(struct wb *wb, struct wb *src)
250 char *s = sbuf_buf(&src->sbuf);
251 char d[ILNLEN];
252 int c, part;
253 while ((c = out_readc(&s, d)) >= 0)
254 wb_putc(wb, c, d);
255 part = src->part;
256 wb->r_s = -1;
257 wb->r_f = -1;
258 wb->r_m = -1;
259 wb_reset(src);
260 src->part = part;
263 int wb_wid(struct wb *wb)
265 return wb->h;
268 int wb_empty(struct wb *wb)
270 return sbuf_empty(&wb->sbuf);
273 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb)
275 *ct = wb->ct;
276 *st = -wb->st;
277 *sb = -wb->sb;
280 /* skip troff requests; return 1 if read c_hc */
281 static int skipreqs(char **s, struct wb *w1)
283 char d[ILNLEN];
284 char *r = *s;
285 int c;
286 wb_reset(w1);
287 while ((c = out_readc(s, d)) > 0) {
288 wb_putc(w1, c, d);
289 r = *s;
291 if (c < 0 || !strcmp(c_hc, d))
292 return 1;
293 *s = r;
294 return 0;
297 static char *dashpos(char *s, int w, struct wb *w1, int any)
299 char d[ILNLEN];
300 char *r = NULL;
301 int c;
302 skipreqs(&s, w1);
303 while ((c = out_readc(&s, d)) >= 0) {
304 wb_putc(w1, c, d);
305 if (wb_wid(w1) > w && (!any || r))
306 continue;
307 if (!c && (!strcmp("-", d) || (!strcmp("em", d) || !strcmp("hy", d))))
308 r = s;
310 return r;
313 static int wb_dashwid(struct wb *wb)
315 struct glyph *g = dev_glyph("hy", R_F(wb));
316 return charwid(g ? g->wid : SC_DW, R_S(wb));
319 static char *indicatorpos(char *s, int w, struct wb *w1, int flg)
321 char d[ILNLEN];
322 char *r = NULL;
323 int c;
324 skipreqs(&s, w1);
325 while ((c = out_readc(&s, d)) >= 0) {
326 wb_putc(w1, c, d);
327 if (wb_wid(w1) + wb_dashwid(w1) > w && (!(flg & HY_ANY) || r))
328 continue;
329 if (!c && !strcmp(c_hc, d))
330 r = s;
332 return r;
335 static char *hyphpos(char *s, int w, struct wb *w1, int flg)
337 char *map[ILNLEN] = {NULL}; /* mapping from word to s */
338 int fits[ILNLEN] = {0}; /* fits[i] if word[0..i]- fits w */
339 char word[ILNLEN];
340 char hyph[ILNLEN];
341 char d[ILNLEN];
342 char *prev_s = s;
343 char *r = NULL;
344 char *wp = word, *we = word + sizeof(word);
345 int beg, end;
346 int i, c;
347 skipreqs(&s, w1);
348 while ((c = out_readc(&s, d)) >= 0 && wp + strlen(d) + 1 < we) {
349 wb_putc(w1, c, d);
350 if (c == 0) {
351 strcpy(wp, d);
352 map[wp - word] = prev_s;
353 wp = strchr(wp, '\0');
354 fits[wp - word] = wb_wid(w1) + wb_dashwid(w1) <= w;
356 prev_s = s;
358 if (strlen(word) < 4)
359 return NULL;
360 hyphenate(hyph, word);
361 beg = flg & HY_FIRSTTWO ? 3 : 2;
362 end = strlen(word) - (flg & HY_FINAL ? 2 : 1);
363 for (i = beg; i < end; i++)
364 if (map[i] && hyph[i] && (fits[i] || ((flg & HY_ANY) && !r)))
365 r = map[i];
366 return r;
369 static void dohyph(char *s, char *pos, int dash, struct wb *w1, struct wb *w2)
371 char d[ILNLEN];
372 int c = -1;
373 wb_reset(w1);
374 wb_reset(w2);
375 while (s != pos && (c = out_readc(&s, d)) >= 0)
376 wb_putc(w1, c, d);
377 if (dash)
378 wb_putc(w1, 0, "hy");
379 w2->r_s = w1->r_s;
380 w2->r_f = w1->r_f;
381 w2->r_m = w1->r_m;
382 while ((c = out_readc(&s, d)) >= 0)
383 wb_putc(w2, c, d);
386 /* hyphenate wb into w1 and w2; return zero on success */
387 int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2, int flg)
389 char *s = sbuf_buf(&wb->sbuf);
390 char *dp, *hp, *p;
391 if (skipreqs(&s, w1))
392 return 1;
393 dp = dashpos(sbuf_buf(&wb->sbuf), w, w1, flg & HY_ANY);
394 hp = indicatorpos(sbuf_buf(&wb->sbuf), w, w1, flg & HY_ANY);
395 p = flg & HY_ANY ? MIN(dp, hp) : MAX(dp, hp);
396 if (!p && flg & HY_MASK)
397 p = hyphpos(sbuf_buf(&wb->sbuf), w, w1, flg & HY_ANY);
398 if (p)
399 dohyph(sbuf_buf(&wb->sbuf), p, p != dp, w1, w2);
400 return !p;