draw: handle invalid line characters
[neatroff.git] / draw.c
blob40bc00f90f004ec7d9ca15c3ac5ae14a50ce08b4
1 /* helper for drawing commands in ren.c */
2 #include <ctype.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 static int cwid(char *c)
9 struct wb wb;
10 int w;
11 wb_init(&wb);
12 wb_putexpand(&wb, c);
13 w = wb_wid(&wb);
14 wb_done(&wb);
15 return w;
18 static int hchar(char *c)
20 if (c[0] == c_ec)
21 return c[1] == '_' || c[1] == '-';
22 if (!c[1])
23 return c[0] == '_';
24 return (c[0] == 'r' && c[1] == 'u') || (c[0] == 'u' && c[1] == 'l') ||
25 (c[0] == 'r' && c[1] == 'n');
28 static int vchar(char *c)
30 if (!c[1])
31 return c[0] == '_';
32 return (c[0] == 'b' && c[1] == 'v') || (c[0] == 'b' && c[1] == 'r');
35 void ren_hline(struct wb *wb, int l, char *c)
37 int w, n, i, rem;
38 w = cwid(c);
39 /* negative length; moving backwards */
40 if (l < 0) {
41 wb_hmov(wb, l);
42 l = -l;
44 n = w ? l / w : 0;
45 rem = w ? l % w : l;
46 /* length less than character width */
47 if (l < w) {
48 n = 1;
49 rem = 0;
50 wb_hmov(wb, -(w - l) / 2);
52 /* the initial gap */
53 if (rem) {
54 if (hchar(c)) {
55 wb_putexpand(wb, c);
56 wb_hmov(wb, rem - w);
57 } else {
58 wb_hmov(wb, rem);
61 for (i = 0; i < n; i++)
62 wb_putexpand(wb, c);
63 /* moving back */
64 if (l < w)
65 wb_hmov(wb, -(w - l + 1) / 2);
68 static void ren_vline(struct wb *wb, int l, char *c)
70 int w, n, i, rem, hw, neg;
71 neg = l < 0;
72 w = SC_EM; /* character height */
73 hw = cwid(c); /* character width */
74 /* negative length; moving backwards */
75 if (l < 0) {
76 wb_vmov(wb, l);
77 l = -l;
79 n = w ? l / w : 0;
80 rem = w ? l % w : l;
81 /* length less than character width */
82 if (l < w) {
83 n = 1;
84 rem = 0;
85 wb_vmov(wb, -w + l / 2);
87 /* the initial gap */
88 if (rem) {
89 if (vchar(c)) {
90 wb_vmov(wb, w);
91 wb_putexpand(wb, c);
92 wb_hmov(wb, -hw);
93 wb_vmov(wb, rem - w);
94 } else {
95 wb_vmov(wb, rem);
98 for (i = 0; i < n; i++) {
99 wb_vmov(wb, w);
100 wb_putexpand(wb, c);
101 wb_hmov(wb, -hw);
103 /* moving back */
104 if (l < w)
105 wb_vmov(wb, l / 2);
106 if (neg)
107 wb_vmov(wb, -l);
108 wb_hmov(wb, hw);
111 void ren_hlcmd(struct wb *wb, char *arg)
113 char lc[GNLEN];
114 int l = eval_up(&arg, 'm');
115 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
116 arg += 2;
117 if (!*arg || charread(&arg, lc) < 0)
118 strcpy(lc, "ru");
119 if (l)
120 ren_hline(wb, l, lc);
123 void ren_vlcmd(struct wb *wb, char *arg)
125 char lc[GNLEN];
126 int l = eval_up(&arg, 'v');
127 if (arg[0] == c_ec && arg[1] == '&') /* \& can be used as a separator */
128 arg += 2;
129 if (!*arg || charread(&arg, lc) < 0)
130 strcpy(lc, "br");
131 if (l)
132 ren_vline(wb, l, lc);
135 static int tok_num(char **s, int scale)
137 char tok[ILNLEN];
138 char *d = tok;
139 while (isspace(**s))
140 (*s)++;
141 while (**s && !isspace(**s))
142 *d++ = *(*s)++;
143 *d = '\0';
144 return eval(tok, scale);
147 void ren_dcmd(struct wb *wb, char *s)
149 int h1, h2, v1, v2;
150 int c = *s++;
151 switch (tolower(c)) {
152 case 'l':
153 h1 = tok_num(&s, 'm');
154 v1 = tok_num(&s, 'v');
155 wb_drawl(wb, c, h1, v1);
156 break;
157 case 'c':
158 h1 = tok_num(&s, 'm');
159 wb_drawc(wb, c, h1);
160 break;
161 case 'e':
162 h1 = tok_num(&s, 'm');
163 v1 = tok_num(&s, 'v');
164 wb_drawe(wb, c, h1, v1);
165 break;
166 case 'a':
167 h1 = tok_num(&s, 'm');
168 v1 = tok_num(&s, 'v');
169 h2 = tok_num(&s, 'm');
170 v2 = tok_num(&s, 'v');
171 wb_drawa(wb, c, h1, v1, h2, v2);
172 break;
173 case '~':
174 case 'p':
175 wb_drawxbeg(wb, c);
176 while (*s) {
177 h1 = tok_num(&s, 'm');
178 v1 = tok_num(&s, 'v');
179 wb_drawxdot(wb, h1, v1);
181 wb_drawxend(wb);
182 break;
186 void ren_bcmd(struct wb *wb, char *arg)
188 struct wb wb2;
189 int n = 0, w = 0;
190 int c, center;
191 sstr_push(arg); /* using ren_char()'s interface */
192 wb_init(&wb2);
193 c = sstr_next();
194 while (c >= 0) {
195 sstr_back(c);
196 ren_char(&wb2, sstr_next, sstr_back);
197 if (wb_wid(&wb2) > w)
198 w = wb_wid(&wb2);
199 wb_hmov(&wb2, -wb_wid(&wb2));
200 wb_vmov(&wb2, SC_EM);
201 n++;
202 c = sstr_next();
204 sstr_pop();
205 center = -(n * SC_EM + SC_EM) / 2;
206 wb_vmov(wb, center + SC_EM);
207 wb_cat(wb, &wb2);
208 wb_done(&wb2);
209 wb_vmov(wb, center);
210 wb_hmov(wb, w);
213 void ren_ocmd(struct wb *wb, char *arg)
215 struct wb wb2, wb3;
216 int w = 0, wc;
217 int c;
218 sstr_push(arg); /* using ren_char()'s interface */
219 wb_init(&wb2);
220 wb_init(&wb3);
221 c = sstr_next();
222 while (c >= 0) {
223 sstr_back(c);
224 ren_char(&wb3, sstr_next, sstr_back);
225 wc = wb_wid(&wb3);
226 if (wc > w)
227 w = wc;
228 wb_hmov(&wb2, -wc / 2);
229 wb_cat(&wb2, &wb3);
230 wb_hmov(&wb2, -wc / 2);
231 c = sstr_next();
233 sstr_pop();
234 wb_hmov(wb, w / 2);
235 wb_cat(wb, &wb2);
236 wb_hmov(wb, w / 2);
237 wb_done(&wb3);
238 wb_done(&wb2);
241 void ren_zcmd(struct wb *wb, char *arg)
243 int h, v;
244 int c;
245 h = wb_hpos(wb);
246 v = wb_vpos(wb);
247 sstr_push(arg);
248 while ((c = sstr_next()) >= 0) {
249 sstr_back(c);
250 ren_char(wb, sstr_next, sstr_back);
252 sstr_pop();
253 wb_hmov(wb, h - wb_hpos(wb));
254 wb_vmov(wb, v - wb_vpos(wb));