map: use starting character lists for keys[]
[neatroff.git] / draw.c
blob92bcc0305909df90b9b56a750d248f5087a3cc68
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[0] == '_';
16 if (c[1] != '(')
17 return c[1] == '_' || c[1] == '-';
18 return (c[2] == 'r' && c[3] == 'u') || (c[2] == 'u' && c[3] == 'l') ||
19 (c[2] == 'r' && c[3] == 'n');
22 static int vchar(char *c)
24 if (c[0] != c_ec || c[1] != '(')
25 return c[0] == '_';
26 return (c[2] == 'b' && c[3] == 'v') || (c[2] == 'b' && c[3] == '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] = {c_ec, '(', 'r', 'u'};
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 (l)
112 ren_hline(wb, l, *arg ? arg : lc);
115 void ren_vlcmd(struct wb *wb, char *arg)
117 char lc[GNLEN] = {c_ec, '(', 'b', 'r'};
118 int l = eval_up(&arg, 'v');
119 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
120 arg += 2;
121 if (l)
122 ren_vline(wb, l, *arg ? arg : lc);
125 static int tok_num(char **s, int scale)
127 char tok[ILNLEN];
128 char *d = tok;
129 while (isspace(**s))
130 (*s)++;
131 while (**s && !isspace(**s))
132 *d++ = *(*s)++;
133 *d = '\0';
134 return eval(tok, scale);
137 void ren_dcmd(struct wb *wb, char *s)
139 int h1, h2, v1, v2;
140 int c = *s++;
141 switch (c) {
142 case 'l':
143 h1 = tok_num(&s, 'm');
144 v1 = tok_num(&s, 'v');
145 wb_drawl(wb, h1, v1);
146 break;
147 case 'c':
148 h1 = tok_num(&s, 'm');
149 wb_drawc(wb, h1);
150 break;
151 case 'e':
152 h1 = tok_num(&s, 'm');
153 v1 = tok_num(&s, 'v');
154 wb_drawe(wb, h1, v1);
155 break;
156 case 'a':
157 h1 = tok_num(&s, 'm');
158 v1 = tok_num(&s, 'v');
159 h2 = tok_num(&s, 'm');
160 v2 = tok_num(&s, 'v');
161 wb_drawa(wb, h1, v1, h2, v2);
162 break;
163 default:
164 wb_drawxbeg(wb, c);
165 while (*s) {
166 h1 = tok_num(&s, 'm');
167 v1 = tok_num(&s, 'v');
168 wb_drawxdot(wb, h1, v1);
170 wb_drawxend(wb);
175 * the implementation of \b and \o
177 * ren_bcmd() and ren_ocmd() call ren_char(), which requires
178 * next() and back() functions, similar to ren_next() and ren_back().
179 * ln_*() here provide such an interface for the given string,
180 * added via ln_push(). ln_*() may be called recursively to
181 * handle \o'\b"ab"c'.
183 static char *ln_s;
185 static int ln_next(void)
187 return *ln_s ? (unsigned char) *ln_s++ : -1;
190 static void ln_back(int c)
192 ln_s--;
195 static char *ln_push(char *s)
197 char *old_s = ln_s;
198 ln_s = s;
199 return old_s;
202 static void ln_pop(char *s)
204 ln_s = s;
207 void ren_bcmd(struct wb *wb, char *arg)
209 struct wb wb2;
210 int n = 0, w = 0;
211 int c, center;
212 char *ln_prev = ln_push(arg);
213 wb_init(&wb2);
214 c = ln_next();
215 while (c >= 0) {
216 ln_back(c);
217 ren_char(&wb2, ln_next, ln_back);
218 if (wb_wid(&wb2) > w)
219 w = wb_wid(&wb2);
220 wb_hmov(&wb2, -wb_wid(&wb2));
221 wb_vmov(&wb2, SC_HT);
222 n++;
223 c = ln_next();
225 ln_pop(ln_prev);
226 center = -(n * SC_HT + SC_EM) / 2;
227 wb_vmov(wb, center + SC_HT);
228 wb_cat(wb, &wb2);
229 wb_done(&wb2);
230 wb_vmov(wb, center);
231 wb_hmov(wb, w);
234 void ren_ocmd(struct wb *wb, char *arg)
236 struct wb wb2, wb3;
237 int w = 0, wc;
238 int c;
239 char *ln_prev = ln_push(arg);
240 wb_init(&wb2);
241 wb_init(&wb3);
242 c = ln_next();
243 while (c >= 0) {
244 ln_back(c);
245 ren_char(&wb3, ln_next, ln_back);
246 wc = wb_wid(&wb3);
247 if (wc > w)
248 w = wc;
249 wb_hmov(&wb2, -wc / 2);
250 wb_cat(&wb2, &wb3);
251 wb_hmov(&wb2, -wc / 2);
252 c = ln_next();
254 ln_pop(ln_prev);
255 wb_hmov(wb, w / 2);
256 wb_cat(wb, &wb2);
257 wb_hmov(wb, w / 2);
258 wb_done(&wb3);
259 wb_done(&wb2);