tr: .shift request
[neatroff.git] / draw.c
blob98e292479b44ddd36c8beb41df275653cbf8fdd3
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 while (**s == ' ' || **s == '\t')
138 (*s)++;
139 return eval_up(s, scale);
142 static int tok_numpt(char **s, int scale, int *i)
144 char *o;
145 while (**s == ' ' || **s == '\t')
146 (*s)++;
147 o = *s;
148 *i = eval_up(s, scale);
149 return o == *s ? 1 : 0;
152 void ren_dcmd(struct wb *wb, char *s)
154 int h1, h2, v1, v2;
155 int c = *s++;
156 switch (tolower(c)) {
157 case 'l':
158 h1 = tok_num(&s, 'm');
159 v1 = tok_num(&s, 'v');
160 wb_drawl(wb, c, h1, v1);
161 break;
162 case 'c':
163 h1 = tok_num(&s, 'm');
164 wb_drawc(wb, c, h1);
165 break;
166 case 'e':
167 h1 = tok_num(&s, 'm');
168 v1 = tok_num(&s, 'v');
169 wb_drawe(wb, c, h1, v1);
170 break;
171 case 'a':
172 h1 = tok_num(&s, 'm');
173 v1 = tok_num(&s, 'v');
174 h2 = tok_num(&s, 'm');
175 v2 = tok_num(&s, 'v');
176 wb_drawa(wb, c, h1, v1, h2, v2);
177 break;
178 case '~':
179 case 'p':
180 wb_drawxbeg(wb, c);
181 while (*s) {
182 if (tok_numpt(&s, 'm', &h1) || tok_numpt(&s, 'v', &v1)) {
183 char tok[64];
184 int i = 0;
185 while (i < sizeof(tok) - 1 && *s && *s != ' ')
186 tok[i++] = *s++;
187 tok[i] = '\0';
188 wb_drawxcmd(wb, tok);
189 } else {
190 wb_drawxdot(wb, h1, v1);
193 wb_drawxend(wb);
194 break;
198 void ren_bcmd(struct wb *wb, char *arg)
200 struct wb wb2;
201 int n = 0, w = 0;
202 int c, center;
203 sstr_push(arg); /* using ren_char()'s interface */
204 wb_init(&wb2);
205 c = sstr_next();
206 while (c >= 0) {
207 sstr_back(c);
208 ren_char(&wb2, sstr_next, sstr_back);
209 if (wb_wid(&wb2) > w)
210 w = wb_wid(&wb2);
211 wb_hmov(&wb2, -wb_wid(&wb2));
212 wb_vmov(&wb2, SC_EM);
213 n++;
214 c = sstr_next();
216 sstr_pop();
217 center = -(n * SC_EM + SC_EM) / 2;
218 wb_vmov(wb, center + SC_EM);
219 wb_cat(wb, &wb2);
220 wb_done(&wb2);
221 wb_vmov(wb, center);
222 wb_hmov(wb, w);
225 void ren_ocmd(struct wb *wb, char *arg)
227 struct wb wb2, wb3;
228 int w = 0, wc;
229 int c;
230 sstr_push(arg); /* using ren_char()'s interface */
231 wb_init(&wb2);
232 wb_init(&wb3);
233 c = sstr_next();
234 while (c >= 0) {
235 sstr_back(c);
236 ren_char(&wb3, sstr_next, sstr_back);
237 wc = wb_wid(&wb3);
238 if (wc > w)
239 w = wc;
240 wb_hmov(&wb2, -wc / 2);
241 wb_cat(&wb2, &wb3);
242 wb_hmov(&wb2, -wc / 2);
243 c = sstr_next();
245 sstr_pop();
246 wb_hmov(wb, w / 2);
247 wb_cat(wb, &wb2);
248 wb_hmov(wb, w / 2);
249 wb_done(&wb3);
250 wb_done(&wb2);
253 void ren_zcmd(struct wb *wb, char *arg)
255 int h, v;
256 int c;
257 h = wb_hpos(wb);
258 v = wb_vpos(wb);
259 sstr_push(arg);
260 while ((c = sstr_next()) >= 0) {
261 sstr_back(c);
262 ren_char(wb, sstr_next, sstr_back);
264 sstr_pop();
265 wb_hmov(wb, h - wb_hpos(wb));
266 wb_vmov(wb, v - wb_vpos(wb));