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
));
22 void wb_done(struct wb
*wb
)
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
));
41 if (wb
->s
!= R_S(wb
)) {
42 sbuf_printf(&wb
->sbuf
, "%cs(%02d", c_ec
, 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
)));
52 void wb_hmov(struct wb
*wb
, int n
)
55 sbuf_printf(&wb
->sbuf
, "%ch'%du'", c_ec
, n
);
58 void wb_vmov(struct wb
*wb
, int 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
)
68 if (els
< wb
->els_neg
)
70 sbuf_printf(&wb
->sbuf
, "%cx'%du'", c_ec
, els
);
73 void wb_etc(struct wb
*wb
, char *x
)
76 sbuf_printf(&wb
->sbuf
, "%cX\x02%s\x02", c_ec
, x
);
79 /* make sure nothing is appended to wb after the last wb_put() */
80 static void wb_prevcheck(struct wb
*wb
)
82 if (wb
->prev_ll
!= sbuf_len(&wb
->sbuf
))
86 /* mark wb->prev_c[] as valid */
87 static void wb_prevok(struct wb
*wb
)
89 wb
->prev_ll
= sbuf_len(&wb
->sbuf
);
92 /* append c to wb->prev_c[] */
93 static void wb_prevput(struct wb
*wb
, char *c
, int ll
)
95 if (wb
->prev_n
== LEN(wb
->prev_c
))
97 memmove(wb
->prev_l
+ 1, wb
->prev_l
, wb
->prev_n
* sizeof(wb
->prev_l
[0]));
98 memmove(wb
->prev_h
+ 1, wb
->prev_h
, wb
->prev_n
* sizeof(wb
->prev_h
[0]));
99 memmove(wb
->prev_c
+ 1, wb
->prev_c
, wb
->prev_n
* sizeof(wb
->prev_c
[0]));
101 wb
->prev_h
[0] = wb
->h
;
102 strcpy(wb
->prev_c
[0], c
);
107 /* strip the last i characters from wb */
108 static void wb_prevpop(struct wb
*wb
, int i
)
110 int n
= wb
->prev_n
- i
;
111 sbuf_cut(&wb
->sbuf
, wb
->prev_l
[i
- 1]);
112 wb
->h
= wb
->prev_h
[i
- 1];
113 memmove(wb
->prev_l
, wb
->prev_l
+ i
, n
* sizeof(wb
->prev_l
[0]));
114 memmove(wb
->prev_h
, wb
->prev_h
+ i
, n
* sizeof(wb
->prev_h
[0]));
115 memmove(wb
->prev_c
, wb
->prev_c
+ i
, n
* sizeof(wb
->prev_c
[0]));
117 wb
->prev_ll
= sbuf_len(&wb
->sbuf
);
120 /* return the i-th last character inserted via wb_put() */
121 static char *wb_prev(struct wb
*wb
, int i
)
124 return i
< wb
->prev_n
? wb
->prev_c
[i
] : NULL
;
127 void wb_put(struct wb
*wb
, char *c
)
136 wb_hmov(wb
, spacewid(R_F(wb
), R_S(wb
)));
139 if (c
[0] == '\t' || c
[0] == '\x01' ||
140 (c
[0] == c_ni
&& (c
[1] == '\t' || c
[1] == '\x01'))) {
141 sbuf_append(&wb
->sbuf
, c
);
144 g
= dev_glyph(c
, R_F(wb
));
146 wb_prevcheck(wb
); /* make sure wb->prev_c[] is valid */
147 ll
= sbuf_len(&wb
->sbuf
); /* sbuf length before inserting c */
148 if (!c
[1] || c
[0] == c_ec
|| c
[0] == c_ni
|| utf8one(c
)) {
149 if (c
[0] == c_ni
&& c
[1] == c_ec
)
150 sbuf_printf(&wb
->sbuf
, "%c%c", c_ec
, c_ec
);
152 sbuf_append(&wb
->sbuf
, c
);
155 sbuf_printf(&wb
->sbuf
, "%c(%s", c_ec
, c
);
157 sbuf_printf(&wb
->sbuf
, "%cC'%s'", c_ec
, c
);
159 if (strcmp(c_hc
, c
)) {
160 wb_prevput(wb
, c
, ll
);
161 wb
->h
+= charwid(R_F(wb
), R_S(wb
), g
? g
->wid
: SC_DW
);
162 wb
->ct
|= g
? g
->type
: 0;
167 /* just like wb_put(), but call cdef_expand() if c is defined */
168 void wb_putexpand(struct wb
*wb
, char *c
)
170 if (cdef_expand(wb
, c
, R_F(wb
)))
174 /* return zero if c formed a ligature with its previous character */
175 int wb_lig(struct wb
*wb
, char *c
)
177 char lig
[GNLEN
] = "";
178 char *cs
[LIGLEN
+ 2];
182 while (wb_prev(wb
, ++i
))
183 cs
[i
+ 1] = wb_prev(wb
, i
);
184 ligpos
= font_lig(dev_font(R_F(wb
)), cs
, i
+ 1);
186 for (i
= 0; i
< ligpos
- 1; i
++)
187 strcat(lig
, wb_prev(wb
, ligpos
- i
- 2));
189 wb_prevpop(wb
, ligpos
- 1);
196 /* return 0 if pairwise kerning was done */
197 int wb_kern(struct wb
*wb
, char *c
)
202 val
= font_kern(dev_font(R_F(wb
)), wb_prev(wb
, 0), c
);
204 wb_hmov(wb
, charwid(R_F(wb
), R_S(wb
), val
));
205 wb_prevok(wb
); /* kerning should not prevent ligatures */
209 int wb_part(struct wb
*wb
)
214 void wb_setpart(struct wb
*wb
)
219 void wb_drawl(struct wb
*wb
, int c
, int h
, int v
)
222 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
228 void wb_drawc(struct wb
*wb
, int c
, int r
)
231 sbuf_printf(&wb
->sbuf
, "%cD'%c %du'", c_ec
, c
, r
);
235 void wb_drawe(struct wb
*wb
, int c
, int h
, int v
)
238 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du'", c_ec
, c
, h
, v
);
242 void wb_drawa(struct wb
*wb
, int c
, int h1
, int v1
, int h2
, int v2
)
245 sbuf_printf(&wb
->sbuf
, "%cD'%c %du %du %du %du'", c_ec
, c
, h1
, v1
, h2
, v2
);
251 void wb_drawxbeg(struct wb
*wb
, int c
)
254 sbuf_printf(&wb
->sbuf
, "%cD'%c", c_ec
, c
);
257 void wb_drawxdot(struct wb
*wb
, int h
, int v
)
259 sbuf_printf(&wb
->sbuf
, " %du %du", h
, v
);
265 void wb_drawxend(struct wb
*wb
)
267 sbuf_printf(&wb
->sbuf
, "'");
270 static void wb_reset(struct wb
*wb
)
276 static void wb_putc(struct wb
*wb
, int t
, char *s
)
290 wb_hmov(wb
, atoi(s
));
293 wb
->r_m
= clr_get(s
);
299 wb_vmov(wb
, atoi(s
));
310 void wb_cat(struct wb
*wb
, struct wb
*src
)
312 char *s
= sbuf_buf(&src
->sbuf
);
315 while ((c
= escread(&s
, d
)) >= 0)
325 int wb_wid(struct wb
*wb
)
330 int wb_empty(struct wb
*wb
)
332 return sbuf_empty(&wb
->sbuf
);
335 /* return 1 if wb ends a sentence (.?!) */
336 int wb_eos(struct wb
*wb
)
339 while (wb_prev(wb
, i
) && strchr("'\")]*", wb_prev(wb
, i
)[0]))
341 return wb_prev(wb
, i
) && strchr(".?!", wb_prev(wb
, i
)[0]);
344 void wb_wconf(struct wb
*wb
, int *ct
, int *st
, int *sb
)
351 /* skip troff requests; return 1 if read c_hc */
352 static int skipreqs(char **s
, struct wb
*w1
)
358 while ((c
= escread(s
, d
)) > 0) {
362 if (c
< 0 || !strcmp(c_hc
, d
))
368 static char *dashpos(char *s
, int w
, struct wb
*w1
, int flg
)
374 while ((c
= escread(&s
, d
)) >= 0) {
376 if (wb_wid(w1
) > w
&& (!(flg
& HY_ANY
) || r
))
378 if (!c
&& (!strcmp("-", d
) || (!strcmp("em", d
) || !strcmp("hy", d
))))
384 static int wb_dashwid(struct wb
*wb
)
386 struct glyph
*g
= dev_glyph("hy", R_F(wb
));
387 return charwid(R_F(wb
), R_S(wb
), g
? g
->wid
: SC_DW
);
390 static char *indicatorpos(char *s
, int w
, struct wb
*w1
, int flg
)
396 while ((c
= escread(&s
, d
)) >= 0) {
398 if (wb_wid(w1
) + wb_dashwid(w1
) > w
&& (!(flg
& HY_ANY
) || r
))
400 if (!c
&& !strcmp(c_hc
, d
))
406 static char *hyphpos(char *s
, int w
, struct wb
*w1
, int flg
)
408 char word
[ILNLEN
]; /* word to pass to hyphenate() */
409 char hyph
[ILNLEN
]; /* hyphenation points returned from hyphenate() */
410 char *iw
[ILNLEN
]; /* beginning of i-th char in word */
411 char *is
[ILNLEN
]; /* beginning of i-th char in s */
412 int fits
[ILNLEN
]; /* fits[i] is 1, if the first i chars fit w */
413 int n
= 0; /* the number of characters in word */
417 char *wp
= word
, *we
= word
+ sizeof(word
);
420 while ((c
= escread(&s
, d
)) >= 0 && (c
> 0 || strlen(d
) + 1 < we
- wp
)) {
421 fits
[n
] = wb_wid(w1
) + wb_dashwid(w1
) <= w
;
426 /* ignore multi-char aliases except for ligatures */
427 if (!utf8one(d
) && !font_islig(dev_font(R_F(w1
)), d
))
430 wp
= strchr(wp
, '\0');
437 hyphenate(hyph
, word
, flg
);
438 for (i
= 1; i
< n
- 1; i
++)
439 if (hyph
[iw
[i
] - word
] && (fits
[i
] || ((flg
& HY_ANY
) && !r
)))
444 static void dohyph(char *s
, char *pos
, int dash
, struct wb
*w1
, struct wb
*w2
)
450 while (s
!= pos
&& (c
= escread(&s
, d
)) >= 0)
453 wb_putc(w1
, 0, "hy");
457 while ((c
= escread(&s
, d
)) >= 0)
461 /* hyphenate wb into w1 and w2; return zero on success */
462 int wb_hyph(struct wb
*wb
, int w
, struct wb
*w1
, struct wb
*w2
, int flg
)
464 char *s
= sbuf_buf(&wb
->sbuf
);
466 if (skipreqs(&s
, w1
))
468 dp
= dashpos(sbuf_buf(&wb
->sbuf
), w
, w1
, flg
);
469 hp
= indicatorpos(sbuf_buf(&wb
->sbuf
), w
, w1
, flg
);
471 p
= flg
& HY_ANY
? MIN(dp
, hp
) : MAX(dp
, hp
);
474 if (!p
&& flg
& HY_MASK
)
475 p
= hyphpos(sbuf_buf(&wb
->sbuf
), w
, w1
, flg
);
477 dohyph(sbuf_buf(&wb
->sbuf
), p
, p
!= dp
, w1
, w2
);