wb: do not match single character ligatures
[neatroff.git] / draw.c
blob0bb625155a3fb951adda3ba77039616c7d8ee8b8
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "roff.h"
6 static int cwid(char *c)
8 struct glyph *g = dev_glyph(c, n_f);
9 return charwid(n_f, n_s, g ? g->wid : SC_DW);
12 static int hchar(char *c)
14 if (c[0] == c_ec)
15 return c[1] == '_' || c[1] == '-';
16 if (!c[1])
17 return c[0] == '_';
18 return (c[0] == 'r' && c[1] == 'u') || (c[0] == 'u' && c[1] == 'l') ||
19 (c[0] == 'r' && c[1] == 'n');
22 static int vchar(char *c)
24 if (!c[1])
25 return c[0] == '_';
26 return (c[0] == 'b' && c[1] == 'v') || (c[0] == 'b' && c[1] == 'r');
29 void ren_hline(struct wb *wb, int l, char *c)
31 int w, n, i, rem;
32 w = cwid(c);
33 /* negative length; moving backwards */
34 if (l < 0) {
35 wb_hmov(wb, l);
36 l = -l;
38 n = l / w;
39 rem = l % w;
40 /* length less than character width */
41 if (l < w) {
42 n = 1;
43 rem = 0;
44 wb_hmov(wb, -(w - l) / 2);
46 /* the initial gap */
47 if (rem) {
48 if (hchar(c)) {
49 wb_put(wb, c);
50 wb_hmov(wb, rem - w);
51 } else {
52 wb_hmov(wb, rem);
55 for (i = 0; i < n; i++)
56 wb_put(wb, c);
57 /* moving back */
58 if (l < w)
59 wb_hmov(wb, -(w - l + 1) / 2);
62 static void ren_vline(struct wb *wb, int l, char *c)
64 int w, n, i, rem, hw, neg;
65 neg = l < 0;
66 w = SC_HT; /* character height */
67 hw = cwid(c); /* character width */
68 /* negative length; moving backwards */
69 if (l < 0) {
70 wb_vmov(wb, l);
71 l = -l;
73 n = l / w;
74 rem = l % w;
75 /* length less than character width */
76 if (l < w) {
77 n = 1;
78 rem = 0;
79 wb_vmov(wb, -w + l / 2);
81 /* the initial gap */
82 if (rem) {
83 if (vchar(c)) {
84 wb_vmov(wb, w);
85 wb_put(wb, c);
86 wb_hmov(wb, -hw);
87 wb_vmov(wb, rem - w);
88 } else {
89 wb_vmov(wb, rem);
92 for (i = 0; i < n; i++) {
93 wb_vmov(wb, w);
94 wb_put(wb, c);
95 wb_hmov(wb, -hw);
97 /* moving back */
98 if (l < w)
99 wb_vmov(wb, l / 2);
100 if (neg)
101 wb_vmov(wb, -l);
102 wb_hmov(wb, hw);
105 void ren_hlcmd(struct wb *wb, char *arg)
107 char lc[GNLEN];
108 int l = eval_up(&arg, 'm');
109 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
110 arg += 2;
111 if (!*arg || charread(&arg, lc) < 0)
112 strcpy(lc, "ru");
113 if (l)
114 ren_hline(wb, l, lc);
117 void ren_vlcmd(struct wb *wb, char *arg)
119 char lc[GNLEN];
120 int l = eval_up(&arg, 'v');
121 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
122 arg += 2;
123 if (!*arg || charread(&arg, lc) < 0)
124 strcpy(lc, "br");
125 if (l)
126 ren_vline(wb, l, lc);
129 static int tok_num(char **s, int scale)
131 char tok[ILNLEN];
132 char *d = tok;
133 while (isspace(**s))
134 (*s)++;
135 while (**s && !isspace(**s))
136 *d++ = *(*s)++;
137 *d = '\0';
138 return eval(tok, scale);
141 void ren_dcmd(struct wb *wb, char *s)
143 int h1, h2, v1, v2;
144 int c = *s++;
145 switch (c) {
146 case 'l':
147 h1 = tok_num(&s, 'm');
148 v1 = tok_num(&s, 'v');
149 wb_drawl(wb, h1, v1);
150 break;
151 case 'c':
152 h1 = tok_num(&s, 'm');
153 wb_drawc(wb, h1);
154 break;
155 case 'e':
156 h1 = tok_num(&s, 'm');
157 v1 = tok_num(&s, 'v');
158 wb_drawe(wb, h1, v1);
159 break;
160 case 'a':
161 h1 = tok_num(&s, 'm');
162 v1 = tok_num(&s, 'v');
163 h2 = tok_num(&s, 'm');
164 v2 = tok_num(&s, 'v');
165 wb_drawa(wb, h1, v1, h2, v2);
166 break;
167 default:
168 wb_drawxbeg(wb, c);
169 while (*s) {
170 h1 = tok_num(&s, 'm');
171 v1 = tok_num(&s, 'v');
172 wb_drawxdot(wb, h1, v1);
174 wb_drawxend(wb);
178 void ren_bcmd(struct wb *wb, char *arg)
180 struct wb wb2;
181 int n = 0, w = 0;
182 int c, center;
183 sstr_push(arg); /* using ren_char()'s interface */
184 wb_init(&wb2);
185 c = sstr_next();
186 while (c >= 0) {
187 sstr_back(c);
188 ren_char(&wb2, sstr_next, sstr_back);
189 if (wb_wid(&wb2) > w)
190 w = wb_wid(&wb2);
191 wb_hmov(&wb2, -wb_wid(&wb2));
192 wb_vmov(&wb2, SC_HT);
193 n++;
194 c = sstr_next();
196 sstr_pop();
197 center = -(n * SC_HT + SC_EM) / 2;
198 wb_vmov(wb, center + SC_HT);
199 wb_cat(wb, &wb2);
200 wb_done(&wb2);
201 wb_vmov(wb, center);
202 wb_hmov(wb, w);
205 void ren_ocmd(struct wb *wb, char *arg)
207 struct wb wb2, wb3;
208 int w = 0, wc;
209 int c;
210 sstr_push(arg); /* using ren_char()'s interface */
211 wb_init(&wb2);
212 wb_init(&wb3);
213 c = sstr_next();
214 while (c >= 0) {
215 sstr_back(c);
216 ren_char(&wb3, sstr_next, sstr_back);
217 wc = wb_wid(&wb3);
218 if (wc > w)
219 w = wc;
220 wb_hmov(&wb2, -wc / 2);
221 wb_cat(&wb2, &wb3);
222 wb_hmov(&wb2, -wc / 2);
223 c = sstr_next();
225 sstr_pop();
226 wb_hmov(wb, w / 2);
227 wb_cat(wb, &wb2);
228 wb_hmov(wb, w / 2);
229 wb_done(&wb3);
230 wb_done(&wb2);