ren: add local motion functions
[neatroff.git] / out.c
blob9a3ce0a9394cee4074b2c5ee148dd5ecf6119ec5
1 #include <ctype.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "xroff.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 1;
54 static char *utf8get(char *d, char *s)
56 int l = utf8len(*s);
57 int i;
58 for (i = 0; i < l; i++)
59 d[i] = s[i];
60 d[l] = '\0';
61 return s + l;
64 static int o_s = 10;
65 static int o_f = 1;
67 static void out_ps(int n)
69 if (o_s != n) {
70 o_s = n;
71 out("s%d\n", o_s);
75 static void out_ft(int n)
77 if (n >= 0 && o_f != n) {
78 o_f = n;
79 out("f%d\n", o_f);
83 static char *escarg(char *s, char *d, int cmd)
85 int q;
86 if (strchr(ESC_P, cmd)) {
87 if (cmd == 's' && (*s == '-' || *s == '+'))
88 *d++ = *s++;
89 if (*s == '(') {
90 s++;
91 *d++ = *s++;
92 *d++ = *s++;
93 } else {
94 *d++ = *s++;
95 if (cmd == 's' && s[-1] >= '1' && s[-1] <= '3')
96 if (isdigit(*s))
97 *d++ = *s++;
100 if (strchr(ESC_Q, cmd)) {
101 q = *s++;
102 while (*s && *s != q)
103 *d++ = *s++;
104 if (*s == q)
105 s++;
107 if (cmd == 'z')
108 *d++ = *s++;
109 *d = '\0';
110 return s;
113 static char *tok_str(char *d, char *s)
115 while (isspace(*s))
116 s++;
117 while (*s && !isspace(*s))
118 *d++ = *s++;
119 *d = '\0';
120 return s;
123 static char *tok_num(int *d, char *s, char **cc, int scale)
125 char tok[ILNLEN];
126 s = tok_str(tok, s);
127 *d = eval(tok, 0, scale);
128 if (*cc)
129 *cc += sprintf(*cc, " %du", *d);
130 else
131 outnn(" %d", *d);
132 return s;
135 /* parse \D arguments and copy them into cc; return the width */
136 int out_draw(char *s, char *cc)
138 int h1, h2, v1, v2;
139 int hd = 0, vd = 0;
140 int c = *s++;
141 if (cc)
142 *cc++ = c;
143 else
144 out("D%c", c);
145 switch (c) {
146 case 'l':
147 s = tok_num(&h1, s, &cc, 'm');
148 s = tok_num(&v1, s, &cc, 'v');
149 if (!cc) /* dpost requires this */
150 outnn(" .");
151 hd = h1;
152 vd = v1;
153 break;
154 case 'c':
155 s = tok_num(&h1, s, &cc, 'm');
156 hd = h1;
157 vd = 0;
158 break;
159 case 'e':
160 s = tok_num(&h1, s, &cc, 'm');
161 s = tok_num(&v1, s, &cc, 'v');
162 hd = h1;
163 vd = 0;
164 break;
165 case 'a':
166 s = tok_num(&h1, s, &cc, 'm');
167 s = tok_num(&v1, s, &cc, 'v');
168 s = tok_num(&h2, s, &cc, 'm');
169 s = tok_num(&v2, s, &cc, 'v');
170 hd = h1 + h2;
171 vd = v1 + v2;
172 break;
173 default:
174 s = tok_num(&h1, s, &cc, 'm');
175 s = tok_num(&v1, s, &cc, 'v');
176 hd = h1;
177 vd = v1;
178 while (*s) {
179 s = tok_num(&h2, s, &cc, 'm');
180 s = tok_num(&v2, s, &cc, 'v');
181 hd += h2;
182 vd += v2;
184 break;
186 if (cc)
187 *cc = '\0';
188 else
189 outnn("\n");
190 return hd;
193 void out_line(char *s)
195 struct glyph *g;
196 char c[GNLEN * 2];
197 char arg[ILNLEN];
198 while (*s) {
199 s = utf8get(c, s);
200 if (c[0] == '\\') {
201 s = utf8get(c, s);
202 if (c[0] == '(') {
203 s = utf8get(c, s);
204 s = utf8get(c + strlen(c), s);
205 } else if (strchr("DfhsvX", c[0])) {
206 s = escarg(s, arg, c[0]);
207 if (c[0] == 'D') {
208 out_draw(arg, NULL);
209 continue;
211 if (c[0] == 'f') {
212 out_ft(dev_font(arg));
213 continue;
215 if (c[0] == 'h') {
216 outnn("h%d", eval(arg, 0, 'm'));
217 continue;
219 if (c[0] == 's') {
220 out_ps(eval(arg, o_s, '\0'));
221 continue;
223 if (c[0] == 'v') {
224 outnn("v%d", eval(arg, 0, 'v'));
225 continue;
227 if (c[0] == 'X') {
228 out("x X %s\n", arg);
229 continue;
233 g = dev_glyph(c, o_f);
234 if (g) {
235 if (utf8len(c[0]) == strlen(c)) {
236 outnn("c%s%s", c, c[1] ? "\n" : "");
237 } else {
238 out("C%s\n", c);
241 outnn("h%d", charwid(g ? g->wid : dev_spacewid(), o_s));