ren: output \x request only once in diversions
[neatroff.git] / wb.c
blob3b0e34610f32b234bef08ee162b0fed372c66ae2
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "xroff.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 */
9 void wb_init(struct wb *wb)
11 memset(wb, 0, sizeof(*wb));
12 sbuf_init(&wb->sbuf);
13 wb->f = -1;
14 wb->s = -1;
15 wb->r_f = -1;
16 wb->r_s = -1;
19 void wb_done(struct wb *wb)
21 sbuf_done(&wb->sbuf);
24 /* update wb->st and wb->sb */
25 static void wb_stsb(struct wb *wb)
27 wb->st = MIN(wb->st, wb->v - SC_HT);
28 wb->sb = MAX(wb->sb, wb->v);
31 /* append font and size to the buffer if needed */
32 static void wb_font(struct wb *wb)
34 if (wb->f != R_F(wb)) {
35 sbuf_printf(&wb->sbuf, "%cf(%02d", c_ec, R_F(wb));
36 wb->f = R_F(wb);
38 if (wb->s != R_S(wb)) {
39 sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
40 wb->s = R_S(wb);
42 wb_stsb(wb);
45 void wb_hmov(struct wb *wb, int n)
47 wb->h += n;
48 sbuf_printf(&wb->sbuf, "%ch'%du'", c_ec, n);
51 void wb_vmov(struct wb *wb, int n)
53 wb->v += n;
54 sbuf_printf(&wb->sbuf, "%cv'%du'", c_ec, n);
57 void wb_els(struct wb *wb, int els)
59 if (els > wb->els_pos)
60 wb->els_pos = els;
61 if (els < wb->els_neg)
62 wb->els_neg = els;
63 sbuf_printf(&wb->sbuf, "%cx'%du'", c_ec, els);
66 void wb_etc(struct wb *wb, char *x)
68 wb_font(wb);
69 sbuf_printf(&wb->sbuf, "%cX\x02%s\x02", c_ec, x);
72 void wb_put(struct wb *wb, char *c)
74 struct glyph *g;
75 if (c[0] == '\n') {
76 wb->part = 0;
77 return;
79 if (c[0] == ' ') {
80 wb_hmov(wb, charwid(dev_spacewid(), R_S(wb)));
81 return;
83 if (c[0] == '\t' || c[0] == '\x01' ||
84 (c[0] == c_ni && (c[1] == '\t' || c[1] == '\x01'))) {
85 sbuf_append(&wb->sbuf, c);
86 return;
88 g = dev_glyph(c, R_F(wb));
89 wb_font(wb);
90 sbuf_append(&wb->sbuf, c);
91 if (strcmp(c_hc, c)) {
92 wb->h += charwid(g ? g->wid : SC_DW, R_S(wb));
93 wb->ct |= g ? g->type : 0;
94 wb_stsb(wb);
98 int wb_part(struct wb *wb)
100 return wb->part;
103 void wb_setpart(struct wb *wb)
105 wb->part = 1;
108 void wb_drawl(struct wb *wb, int h, int v)
110 wb_font(wb);
111 sbuf_printf(&wb->sbuf, "%cD'l %du %du'", c_ec, h, v);
112 wb->h += h;
113 wb->v += v;
114 wb_stsb(wb);
117 void wb_drawc(struct wb *wb, int r)
119 wb_font(wb);
120 sbuf_printf(&wb->sbuf, "%cD'c %du'", c_ec, r);
121 wb->h += r;
124 void wb_drawe(struct wb *wb, int h, int v)
126 wb_font(wb);
127 sbuf_printf(&wb->sbuf, "%cD'e %du %du'", c_ec, h, v);
128 wb->h += h;
131 void wb_drawa(struct wb *wb, int h1, int v1, int h2, int v2)
133 wb_font(wb);
134 sbuf_printf(&wb->sbuf, "%cD'a %du %du %du %du'", c_ec, h1, v1, h2, v2);
135 wb->h += h1 + h2;
136 wb->v += v1 + v2;
137 wb_stsb(wb);
140 void wb_drawxbeg(struct wb *wb, int c)
142 wb_font(wb);
143 sbuf_printf(&wb->sbuf, "%cD'%c", c_ec, c);
146 void wb_drawxdot(struct wb *wb, int h, int v)
148 sbuf_printf(&wb->sbuf, " %du %du", h, v);
149 wb->h += h;
150 wb->v += v;
151 wb_stsb(wb);
154 void wb_drawxend(struct wb *wb)
156 sbuf_printf(&wb->sbuf, "'");
159 static void wb_reset(struct wb *wb)
161 wb_done(wb);
162 wb_init(wb);
165 static void wb_putc(struct wb *wb, int t, char *s)
167 switch (t) {
168 case 0:
169 wb_put(wb, s);
170 break;
171 case 'D':
172 ren_draw(wb, s);
173 break;
174 case 'f':
175 wb->r_f = atoi(s);
176 break;
177 case 'h':
178 wb_hmov(wb, atoi(s));
179 break;
180 case 's':
181 wb->r_s = atoi(s);
182 break;
183 case 'v':
184 wb_vmov(wb, atoi(s));
185 break;
186 case 'x':
187 wb_els(wb, atoi(s));
188 break;
189 case 'X':
190 wb_etc(wb, s);
191 break;
195 void wb_cat(struct wb *wb, struct wb *src)
197 char *s = sbuf_buf(&src->sbuf);
198 char d[ILNLEN];
199 int c, part;
200 while ((c = out_readc(&s, d)) >= 0)
201 wb_putc(wb, c, d);
202 part = src->part;
203 wb->r_s = -1;
204 wb->r_f = -1;
205 wb_reset(src);
206 src->part = part;
209 int wb_wid(struct wb *wb)
211 return wb->h;
214 int wb_empty(struct wb *wb)
216 return sbuf_empty(&wb->sbuf);
219 void wb_wconf(struct wb *wb, int *ct, int *st, int *sb)
221 *ct = wb->ct;
222 *st = -wb->st;
223 *sb = -wb->sb;
226 /* skip troff requests; return 1 if read c_hc */
227 static int skipreqs(char **s, struct wb *w1)
229 char d[ILNLEN];
230 char *r = *s;
231 int c;
232 wb_reset(w1);
233 while ((c = out_readc(s, d)) > 0) {
234 wb_putc(w1, c, d);
235 r = *s;
237 if (c < 0 || !strcmp(c_hc, d))
238 return 1;
239 *s = r;
240 return 0;
243 static char *dashpos(char *s, int w, struct wb *w1, int any)
245 char d[ILNLEN];
246 char *r = NULL;
247 int c;
248 skipreqs(&s, w1);
249 while ((c = out_readc(&s, d)) == 0) {
250 wb_putc(w1, c, d);
251 if (wb_wid(w1) > w && (!any || r))
252 break;
253 if (!strcmp("-", d) || (d[0] == c_ec && (!strcmp("(em", d + 1) ||
254 !strcmp("(hy", d + 1))))
255 r = s;
257 return r;
260 static int wb_dashwid(struct wb *wb)
262 struct glyph *g = dev_glyph("hy", R_F(wb));
263 return charwid(g ? g->wid : SC_DW, R_S(wb));
266 static char *indicatorpos(char *s, int w, struct wb *w1, int flg)
268 char d[ILNLEN];
269 char *r = NULL;
270 int c;
271 skipreqs(&s, w1);
272 while ((c = out_readc(&s, d)) == 0) {
273 wb_putc(w1, c, d);
274 if (wb_wid(w1) + wb_dashwid(w1) > w && (!(flg & HY_ANY) || r))
275 break;
276 if (!strcmp(c_hc, d))
277 r = s;
279 return r;
282 static char *hyphpos(char *s, int w, struct wb *w1, int flg)
284 char word[ILNLEN];
285 char hyph[ILNLEN];
286 char d[ILNLEN];
287 char *r = NULL;
288 char *hy_beg, *hy_wid = NULL, *hy_end = NULL;
289 char *wp = word;
290 int beg, end;
291 int i, c;
292 skipreqs(&s, w1);
293 hy_beg = s;
294 while ((c = out_readc(&s, d)) == 0) {
295 wb_putc(w1, c, d);
296 if (wb_wid(w1) + wb_dashwid(w1) <= w)
297 hy_wid = s;
298 hy_end = s;
299 strcpy(wp, d);
300 wp = strchr(wp, '\0');
302 if (strlen(word) < 4)
303 return NULL;
304 hyphenate(hyph, word);
305 beg = flg & HY_FIRSTTWO ? 3 : 2;
306 end = hy_end - hy_beg - (flg & HY_FINAL ? 1 : 0);
307 for (i = beg; i < end; i++)
308 if (hyph[i] && (hy_beg + i <= hy_wid || ((flg & HY_ANY) && !r)))
309 r = hy_beg + i;
310 return r;
313 static void dohyph(char *s, char *pos, int dash, struct wb *w1, struct wb *w2)
315 char d[ILNLEN];
316 char hy[GNLEN] = {c_ec, '(', 'h', 'y'};
317 int c = -1;
318 wb_reset(w1);
319 wb_reset(w2);
320 while (s != pos && (c = out_readc(&s, d)) >= 0)
321 wb_putc(w1, c, d);
322 if (dash)
323 wb_putc(w1, 0, hy);
324 w2->r_s = w1->r_s;
325 w2->r_f = w1->r_f;
326 while ((c = out_readc(&s, d)) >= 0)
327 wb_putc(w2, c, d);
330 /* hyphenate wb into w1 and w2; return zero on success */
331 int wb_hyph(struct wb *wb, int w, struct wb *w1, struct wb *w2, int flg)
333 char *s = sbuf_buf(&wb->sbuf);
334 char *dp, *hp, *p;
335 if (skipreqs(&s, w1))
336 return 1;
337 dp = dashpos(sbuf_buf(&wb->sbuf), w, w1, flg & HY_ANY);
338 hp = indicatorpos(sbuf_buf(&wb->sbuf), w, w1, flg & HY_ANY);
339 p = flg & HY_ANY ? MIN(dp, hp) : MAX(dp, hp);
340 if (!p && flg & HY_MASK)
341 p = hyphpos(sbuf_buf(&wb->sbuf), w, w1, flg & HY_ANY);
342 if (p)
343 dohyph(sbuf_buf(&wb->sbuf), p, p != dp, w1, w2);
344 return !p;