ren: output \x request only once in diversions
[neatroff.git] / draw.c
blobdaf506318f91d0c616cd7b2561712d9d54cc90be
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "xroff.h"
6 static char *ln_s;
8 static int ln_next(void)
10 return *ln_s ? (unsigned char) *ln_s++ : -1;
13 static void ln_back(int c)
15 ln_s--;
18 static char *ln_push(char *s)
20 char *old_s = ln_s;
21 ln_s = s;
22 return old_s;
25 static void ln_pop(char *s)
27 ln_s = s;
30 static int cwid(char *c)
32 struct glyph *g = dev_glyph(c, n_f);
33 return charwid(g ? g->wid : SC_DW, n_s);
36 static int hchar(char *c)
38 if (c[0] != c_ec)
39 return c[0] == '_';
40 if (c[1] != '(')
41 return c[1] == '_' || c[1] == '-';
42 return (c[2] == 'r' && c[3] == 'u') || (c[2] == 'u' && c[3] == 'l') ||
43 (c[2] == 'r' && c[3] == 'n');
46 static int vchar(char *c)
48 if (c[0] != c_ec || c[1] != '(')
49 return c[0] == '_';
50 return (c[2] == 'b' && c[3] == 'v') || (c[2] == 'b' && c[3] == 'r');
53 void ren_hline(struct wb *wb, char *arg)
55 char lc[GNLEN] = {c_ec, '(', 'r', 'u'};
56 int w, l, n, i, rem;
57 l = eval_up(&arg, 'm');
58 if (!l)
59 return;
60 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
61 arg += 2;
62 if (*arg)
63 strcpy(lc, arg);
64 w = cwid(lc);
65 /* negative length; moving backwards */
66 if (l < 0) {
67 wb_hmov(wb, l);
68 l = -l;
70 n = l / w;
71 rem = l % w;
72 /* length less than character width */
73 if (l < w) {
74 n = 1;
75 rem = 0;
76 wb_hmov(wb, -(w - l) / 2);
78 /* the initial gap */
79 if (rem) {
80 if (hchar(lc)) {
81 wb_put(wb, lc);
82 wb_hmov(wb, rem - w);
83 } else {
84 wb_hmov(wb, rem);
87 for (i = 0; i < n; i++)
88 wb_put(wb, lc);
89 /* moving back */
90 if (l < w)
91 wb_hmov(wb, -(w - l + 1) / 2);
94 void ren_vline(struct wb *wb, char *arg)
96 char lc[GNLEN] = {c_ec, '(', 'b', 'r'};
97 int w, l, n, i, rem, hw, neg;
98 l = eval_up(&arg, 'v');
99 if (!l)
100 return;
101 neg = l < 0;
102 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
103 arg += 2;
104 if (*arg)
105 strcpy(lc, arg);
106 w = SC_HT; /* character height */
107 hw = cwid(lc); /* character width */
108 /* negative length; moving backwards */
109 if (l < 0) {
110 wb_vmov(wb, l);
111 l = -l;
113 n = l / w;
114 rem = l % w;
115 /* length less than character width */
116 if (l < w) {
117 n = 1;
118 rem = 0;
119 wb_vmov(wb, -w + l / 2);
121 /* the initial gap */
122 if (rem) {
123 if (vchar(lc)) {
124 wb_vmov(wb, w);
125 wb_put(wb, lc);
126 wb_hmov(wb, -hw);
127 wb_vmov(wb, rem - w);
128 } else {
129 wb_vmov(wb, rem);
132 for (i = 0; i < n; i++) {
133 wb_vmov(wb, w);
134 wb_put(wb, lc);
135 wb_hmov(wb, -hw);
137 /* moving back */
138 if (l < w)
139 wb_vmov(wb, l / 2);
140 if (neg)
141 wb_vmov(wb, -l);
142 wb_hmov(wb, hw);
145 void ren_bracket(struct wb *wb, char *arg)
147 struct wb wb2;
148 int n = 0, w = 0;
149 int c, center;
150 char *ln_prev = ln_push(arg);
151 wb_init(&wb2);
152 c = ln_next();
153 while (c >= 0) {
154 ln_back(c);
155 ren_char(&wb2, ln_next, ln_back);
156 if (wb_wid(&wb2) > w)
157 w = wb_wid(&wb2);
158 wb_hmov(&wb2, -wb_wid(&wb2));
159 wb_vmov(&wb2, SC_HT);
160 n++;
161 c = ln_next();
163 ln_pop(ln_prev);
164 center = -(n * SC_HT + SC_EM) / 2;
165 wb_vmov(wb, center + SC_HT);
166 wb_cat(wb, &wb2);
167 wb_done(&wb2);
168 wb_vmov(wb, center);
169 wb_hmov(wb, w);
172 void ren_over(struct wb *wb, char *arg)
174 struct wb wb2, wb3;
175 int w = 0, wc;
176 int c;
177 char *ln_prev = ln_push(arg);
178 wb_init(&wb2);
179 wb_init(&wb3);
180 c = ln_next();
181 while (c >= 0) {
182 ln_back(c);
183 ren_char(&wb3, ln_next, ln_back);
184 wc = wb_wid(&wb3);
185 if (wc > w)
186 w = wc;
187 wb_hmov(&wb2, -wc / 2);
188 wb_cat(&wb2, &wb3);
189 wb_hmov(&wb2, -wc / 2);
190 c = ln_next();
192 ln_pop(ln_prev);
193 wb_hmov(wb, w / 2);
194 wb_cat(wb, &wb2);
195 wb_hmov(wb, w / 2);
196 wb_done(&wb3);
197 wb_done(&wb2);
200 static int tok_num(char **s, int scale)
202 char tok[ILNLEN];
203 char *d = tok;
204 while (isspace(**s))
205 (*s)++;
206 while (**s && !isspace(**s))
207 *d++ = *(*s)++;
208 *d = '\0';
209 return eval(tok, scale);
212 void ren_draw(struct wb *wb, char *s)
214 int h1, h2, v1, v2;
215 int c = *s++;
216 switch (c) {
217 case 'l':
218 h1 = tok_num(&s, 'm');
219 v1 = tok_num(&s, 'v');
220 wb_drawl(wb, h1, v1);
221 break;
222 case 'c':
223 h1 = tok_num(&s, 'm');
224 wb_drawc(wb, h1);
225 break;
226 case 'e':
227 h1 = tok_num(&s, 'm');
228 v1 = tok_num(&s, 'v');
229 wb_drawe(wb, h1, v1);
230 break;
231 case 'a':
232 h1 = tok_num(&s, 'm');
233 v1 = tok_num(&s, 'v');
234 h2 = tok_num(&s, 'm');
235 v2 = tok_num(&s, 'v');
236 wb_drawa(wb, h1, v1, h2, v2);
237 break;
238 default:
239 wb_drawxbeg(wb, c);
240 while (*s) {
241 h1 = tok_num(&s, 'm');
242 v1 = tok_num(&s, 'v');
243 wb_drawxdot(wb, h1, v1);
245 wb_drawxend(wb);