tr: .nx with no arguments
[neatroff.git] / out.c
blob6b74986f95072150e5c6fd8da1744457d37d5249
1 #include <ctype.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "roff.h"
8 static int out_nl = 1;
10 /* output troff code; newlines may appear only at the end of s */
11 static void out_out(char *s, va_list ap)
13 out_nl = strchr(s, '\n') != NULL;
14 vfprintf(stdout, s, ap);
17 /* output troff code; no preceding newline is necessary */
18 static void outnn(char *s, ...)
20 va_list ap;
21 va_start(ap, s);
22 out_out(s, ap);
23 va_end(ap);
26 /* output troff cmd; should appear after a newline */
27 void out(char *s, ...)
29 va_list ap;
30 if (!out_nl)
31 outnn("\n");
32 va_start(ap, s);
33 out_out(s, ap);
34 va_end(ap);
37 int utf8len(int c)
39 if (c <= 0x7f)
40 return 1;
41 if (c >= 0xfc)
42 return 6;
43 if (c >= 0xf8)
44 return 5;
45 if (c >= 0xf0)
46 return 4;
47 if (c >= 0xe0)
48 return 3;
49 if (c >= 0xc0)
50 return 2;
51 return c != 0;
54 int utf8read(char **s, char *d)
56 int l = utf8len((unsigned char) **s);
57 int i;
58 for (i = 0; i < l; i++)
59 d[i] = (*s)[i];
60 d[l] = '\0';
61 *s += l;
62 return l;
65 static int o_s = 10;
66 static int o_f = 1;
67 static int o_m = 0;
69 static void out_ps(int n)
71 if (o_s != n) {
72 o_s = n;
73 out("s%d\n", o_s);
77 static void out_ft(int n)
79 if (n >= 0 && o_f != n) {
80 o_f = n;
81 out("f%d\n", o_f);
85 static void out_clr(int n)
87 if (n >= 0 && o_m != n) {
88 o_m = n;
89 out("m%s\n", clr_str(o_m));
93 static void escarg(char **sp, char *d, int cmd)
95 char *s = *sp;
96 int q;
97 if (strchr(ESC_P, cmd)) {
98 if (cmd == 's' && (*s == '-' || *s == '+'))
99 *d++ = *s++;
100 if (*s == '(') {
101 s++;
102 *d++ = *s++;
103 *d++ = *s++;
104 } else if (!n_cp && *s == '[') {
105 s++;
106 while (*s && *s != ']')
107 *d++ = *s++;
108 if (*s == ']')
109 s++;
110 } else {
111 *d++ = *s++;
112 if (cmd == 's' && s[-1] >= '1' && s[-1] <= '3')
113 if (isdigit(*s))
114 *d++ = *s++;
117 if (strchr(ESC_Q, cmd)) {
118 q = *s++;
119 while (*s && *s != q)
120 *d++ = *s++;
121 if (*s == q)
122 s++;
124 if (cmd == 'z')
125 *d++ = *s++;
126 *d = '\0';
127 *sp = s;
130 static int tok_num(char **s, int scale)
132 char tok[ILNLEN];
133 char *d = tok;
134 while (isspace(**s))
135 (*s)++;
136 while (**s && !isspace(**s))
137 *d++ = *(*s)++;
138 *d = '\0';
139 return eval(tok, scale);
142 static void out_draw(char *s)
144 int c = *s++;
145 out("D%c", c);
146 switch (c) {
147 case 'l':
148 outnn(" %d", tok_num(&s, 'm'));
149 outnn(" %d", tok_num(&s, 'v'));
150 outnn(" ."); /* dpost requires this */
151 break;
152 case 'c':
153 outnn(" %d", tok_num(&s, 'm'));
154 break;
155 case 'e':
156 outnn(" %d", tok_num(&s, 'm'));
157 outnn(" %d", tok_num(&s, 'v'));
158 break;
159 case 'a':
160 outnn(" %d", tok_num(&s, 'm'));
161 outnn(" %d", tok_num(&s, 'v'));
162 outnn(" %d", tok_num(&s, 'm'));
163 outnn(" %d", tok_num(&s, 'v'));
164 break;
165 default:
166 outnn(" %d", tok_num(&s, 'm'));
167 outnn(" %d", tok_num(&s, 'v'));
168 while (*s) {
169 outnn(" %d", tok_num(&s, 'm'));
170 outnn(" %d", tok_num(&s, 'v'));
172 break;
174 outnn("\n");
178 * read a glyph or output troff request
180 * This functions reads from s either an output troff request
181 * (only the ones emitted by wb.c) or a glyph name and updates
182 * s. The return value is the name of the troff request (the
183 * argument is copied into d) or zero for glyph names (it is
184 * copied into d). Returns -1 when the end of s is reached.
186 int out_readc(char **s, char *d)
188 char *r = d;
189 if (!**s)
190 return -1;
191 utf8read(s, d);
192 if (d[0] == c_ec) {
193 utf8read(s, d + 1);
194 if (d[1] == '(') {
195 utf8read(s, d);
196 utf8read(s, d + strlen(d));
197 } else if (!n_cp && d[1] == '[') {
198 while (**s && **s != ']')
199 *r++ = *(*s)++;
200 if (**s == ']')
201 (*s)++;
202 } else if (strchr("CDfhmsvXx", d[1])) {
203 int c = d[1];
204 escarg(s, d, d[1]);
205 return c == 'C' ? 0 : c;
208 if (d[0] == c_ni)
209 utf8read(s, d + 1);
210 return 0;
213 static void outg(char *c)
215 if (utf8len((unsigned char) c[0]) == strlen(c))
216 outnn("c%s%s", c, c[1] ? "\n" : "");
217 else
218 out("C%s\n", c[0] == c_ec && c[1] == '(' ? c + 2 : c);
221 static void outc(char *c)
223 struct glyph *g = dev_glyph(c, o_f);
224 int cwid = charwid(o_f, o_s, g ? g->wid : SC_DW);
225 int bwid = charwid_base(o_f, o_s, g ? g->wid : SC_DW);
226 if (dev_getcs(o_f))
227 outnn("h%d", (cwid - bwid) / 2);
228 outg(c);
229 if (dev_getbd(o_f)) {
230 outnn("h%d", dev_getbd(o_f) - 1);
231 outg(c);
232 outnn("h%d", -dev_getbd(o_f) + 1);
234 if (dev_getcs(o_f))
235 outnn("h%d", -(cwid - bwid) / 2);
236 outnn("h%d", cwid);
239 void out_line(char *s)
241 char c[ILNLEN + GNLEN * 4];
242 int t;
243 while ((t = out_readc(&s, c)) >= 0) {
244 if (!t) {
245 if (c[0] == c_ni || (c[0] == '\\' && c[1] == '\\')) {
246 c[0] = c[1];
247 c[1] = '\0';
249 if (c[0] == '\t' || c[0] == '\x01' || !strcmp(c_hc, c))
250 continue;
251 outc(c);
252 continue;
254 switch (t) {
255 case 'D':
256 out_draw(c);
257 break;
258 case 'f':
259 out_ft(dev_pos(c));
260 break;
261 case 'h':
262 outnn("h%d", eval(c, 'm'));
263 break;
264 case 'm':
265 if (!n_cp)
266 out_clr(clr_get(c));
267 break;
268 case 's':
269 out_ps(eval_re(c, o_s, '\0'));
270 break;
271 case 'v':
272 outnn("v%d", eval(c, 'v'));
273 break;
274 case 'X':
275 out("x X %s\n", c);
276 break;