font: unmap glyphs with .fmap
[neatroff.git] / char.c
blob7804e63ab9ef1850f58267e0652f22789d8f041b
1 /* reading characters and escapes */
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "roff.h"
8 /* return the length of a utf-8 character based on its first byte */
9 int utf8len(int c)
11 if (~c & 0x80)
12 return c > 0;
13 if (~c & 0x40)
14 return 1;
15 if (~c & 0x20)
16 return 2;
17 if (~c & 0x10)
18 return 3;
19 if (~c & 0x08)
20 return 4;
21 return 1;
24 /* return nonzero if s is a single utf-8 character */
25 int utf8one(char *s)
27 return !s[utf8len((unsigned char) *s)];
30 /* read a utf-8 character from s and copy it to d */
31 int utf8read(char **s, char *d)
33 int l = utf8len((unsigned char) **s);
34 int i;
35 for (i = 0; i < l; i++)
36 d[i] = (*s)[i];
37 d[l] = '\0';
38 *s += l;
39 return l;
42 /* read a utf-8 character with next() and copy it to s */
43 int utf8next(char *s, int (*next)(void))
45 int c = next();
46 int l = utf8len(c);
47 int i;
48 if (c < 0)
49 return 0;
50 s[0] = c;
51 for (i = 1; i < l; i++)
52 s[i] = next();
53 s[l] = '\0';
54 return l;
57 /* read quoted arguments of escape sequences (ESC_Q) */
58 char *quotednext(int (*next)(void), void (*back)(int))
60 char delim[GNLEN], cs[GNLEN];
61 struct sbuf sb;
62 char d[GNLEN];
63 charnext(delim, next, back);
64 sbuf_init(&sb);
65 while (charnext_delim(cs, next, back, delim) >= 0) {
66 charnext_str(d, cs);
67 sbuf_append(&sb, d);
69 return sbuf_out(&sb);
72 /* read unquoted arguments of escape sequences (ESC_P) */
73 char *unquotednext(int cmd, int (*next)(void), void (*back)(int))
75 int c = next();
76 struct sbuf sb;
77 sbuf_init(&sb);
78 if (cmd == 's' && (c == '-' || c == '+')) {
79 cmd = c;
80 sbuf_add(&sb, c);
81 c = next();
83 if (c == '(') {
84 sbuf_add(&sb, next());
85 sbuf_add(&sb, next());
86 } else if (!n_cp && c == '[') {
87 c = next();
88 while (c > 0 && c != '\n' && c != ']') {
89 sbuf_add(&sb, c);
90 c = next();
92 } else {
93 sbuf_add(&sb, c);
94 if (cmd == 's' && c >= '1' && c <= '3') {
95 c = next();
96 if (isdigit(c))
97 sbuf_add(&sb, c);
98 else
99 back(c);
102 return sbuf_out(&sb);
106 * read the next character or escape sequence (x, \x, \(xy, \[xyz], \C'xyz')
108 * character returned contents of c
109 * x '\0' x
110 * \4x c_ni \4x
111 * \\x '\\' \\x
112 * \\(xy '(' xy
113 * \\[xyz] '[' xyz
114 * \\C'xyz' 'C' xyz
116 int charnext(char *c, int (*next)(void), void (*back)(int))
118 int l, n;
119 if (!utf8next(c, next))
120 return -1;
121 if (c[0] == c_ni) {
122 utf8next(c + 1, next);
123 return c_ni;
125 if (c[0] == c_ec) {
126 utf8next(c + 1, next);
127 if (c[1] == '(') {
128 l = utf8next(c, next);
129 l += utf8next(c + l, next);
130 return '(';
131 } else if (!n_cp && c[1] == '[') {
132 l = 0;
133 n = next();
134 while (n >= 0 && n != '\n' && n != ']' && l < GNLEN - 1) {
135 c[l++] = n;
136 n = next();
138 c[l] = '\0';
139 return '[';
140 } else if (c[1] == 'C') {
141 char *chr = quotednext(next, back);
142 snprintf(c, GNLEN, "%s", chr);
143 free(chr);
144 return 'C';
146 return '\\';
148 return '\0';
151 /* like nextchar(), but return -1 if delim was read */
152 int charnext_delim(char *c, int (*next)(void), void (*back)(int), char *delim)
154 int t = charnext(c, next, back);
155 return strcmp(c, delim) ? t : -1;
158 /* convert back the character read from nextchar() (e.g. xy -> \\(xy) */
159 void charnext_str(char *d, char *c)
161 int c0 = (unsigned char) c[0];
162 if (c0 == c_ec || c0 == c_ni || !c[1] || utf8one(c)) {
163 strcpy(d, c);
164 return;
166 if (!c[2] && utf8len(c0) == 1)
167 sprintf(d, "%c(%s", c_ec, c);
168 else
169 sprintf(d, "%cC'%s'", c_ec, c);
172 /* like charnext() for string buffers */
173 int charread(char **s, char *c)
175 int ret;
176 sstr_push(*s);
177 ret = charnext(c, sstr_next, sstr_back);
178 *s = sstr_pop();
179 return ret;
182 /* like charnext_delim() for string buffers */
183 int charread_delim(char **s, char *c, char *delim)
185 int ret;
186 sstr_push(*s);
187 ret = charnext_delim(c, sstr_next, sstr_back, delim);
188 *s = sstr_pop();
189 return ret;
192 /* read quoted arguments; this is called only for internal neatroff strings */
193 static void quotedread(char **sp, char *d)
195 char *s = *sp;
196 int q = *s++;
197 while (*s && *s != q)
198 *d++ = *s++;
199 if (*s == q)
200 s++;
201 *d = '\0';
202 *sp = s;
205 /* read unquoted arguments; this is called only for internal neatroff strings */
206 static void unquotedread(char **sp, char *d)
208 char *s = *sp;
209 if (*s == '(') {
210 s++;
211 *d++ = *s++;
212 *d++ = *s++;
213 } else if (!n_cp && *s == '[') {
214 s++;
215 while (*s && *s != ']')
216 *d++ = *s++;
217 if (*s == ']')
218 s++;
219 } else {
220 *d++ = *s++;
222 *d = '\0';
223 *sp = s;
227 * read a glyph or an escape sequence
229 * This function reads from s either an output troff request
230 * (only the ones emitted by wb.c) or a glyph name and updates
231 * s. The return value is the name of the troff request (the
232 * argument is copied into d) or zero for glyph names (it is
233 * copied into d). Returns -1 when the end of s is reached.
234 * Note that to d, a pointer to a static array is assigned.
236 int escread(char **s, char **d)
238 static char buf[1 << 12];
239 char *r;
240 if (!**s)
241 return -1;
242 r = buf;
243 *d = buf;
244 utf8read(s, r);
245 if (r[0] == c_ec) {
246 utf8read(s, r + 1);
247 if (r[1] == '(') {
248 utf8read(s, r);
249 utf8read(s, r + strlen(r));
250 } else if (!n_cp && r[1] == '[') {
251 while (**s && **s != ']')
252 *r++ = *(*s)++;
253 *r = '\0';
254 if (**s == ']')
255 (*s)++;
256 } else if (strchr("CDfhmsvXx", r[1])) {
257 int c = r[1];
258 r[0] = '\0';
259 if (strchr(ESC_P, c))
260 unquotedread(s, r);
261 if (strchr(ESC_Q, c))
262 quotedread(s, r);
263 return c == 'C' ? 0 : c;
265 } else if (r[0] == c_ni) {
266 utf8read(s, r + 1);
268 return 0;
272 * string streams: provide next()/back() interface for string buffers
274 * Functions like charnext() require a next()/back() interface
275 * for reading input streams. In order to provide this interface
276 * for string buffers, the following functions can be used:
278 * sstr_push(s);
279 * charnext(c, sstr_next, sstr_back);
280 * sstr_pop();
282 * The calls to sstr_push()/sstr_pop() may be nested.
284 static char *sstr_bufs[NSSTR]; /* buffer stack */
285 static int sstr_n; /* numbers of items in sstr_bufs[] */
286 static char *sstr_s; /* current buffer */
288 void sstr_push(char *s)
290 sstr_bufs[sstr_n++] = sstr_s;
291 sstr_s = s;
294 char *sstr_pop(void)
296 char *ret = sstr_s;
297 sstr_s = sstr_bufs[--sstr_n];
298 return ret;
301 int sstr_next(void)
303 return *sstr_s ? (unsigned char) *sstr_s++ : -1;
306 void sstr_back(int c)
308 sstr_s--;