ren: disable ligatures and pairwise kerning when interpolating diverted text
[neatroff.git] / char.c
blobc0a4568531ebbc74d4a7912535a841612f2d20a0
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "roff.h"
6 int utf8len(int c)
8 if (c > 0 && c <= 0x7f)
9 return 1;
10 if (c >= 0xfc)
11 return 6;
12 if (c >= 0xf8)
13 return 5;
14 if (c >= 0xf0)
15 return 4;
16 if (c >= 0xe0)
17 return 3;
18 if (c >= 0xc0)
19 return 2;
20 return c != 0;
23 int utf8read(char **s, char *d)
25 int l = utf8len((unsigned char) **s);
26 int i;
27 for (i = 0; i < l; i++)
28 d[i] = (*s)[i];
29 d[l] = '\0';
30 *s += l;
31 return l;
34 int utf8next(char *s, int (*next)(void))
36 int c = next();
37 int l = utf8len(c);
38 int i;
39 if (c < 0)
40 return 0;
41 s[0] = c;
42 for (i = 1; i < l; i++)
43 s[i] = next();
44 s[l] = '\0';
45 return l;
49 * read the next character or escape sequence (x, \x, \(xy, \[xyz], \C'xyz')
51 * character returned contents of c
52 * x '\0' x
53 * \4x c_ni \4x
54 * \\x '\\' \\x
55 * \\(xy '(' xy
56 * \\[xyz] '[' xyz
57 * \\C'xyz' 'C' xyz
59 int charnext(char *c, int (*next)(void), void (*back)(int))
61 int l, n;
62 if (!utf8next(c, next))
63 return -1;
64 if (c[0] == c_ni) {
65 utf8next(c + 1, next);
66 return c_ni;
68 if (c[0] == c_ec) {
69 utf8next(c + 1, next);
70 if (c[1] == '(') {
71 l = utf8next(c, next);
72 l += utf8next(c + l, next);
73 return '(';
74 } else if (!n_cp && c[1] == '[') {
75 l = 0;
76 n = next();
77 while (n >= 0 && n != '\n' && n != ']' && l < GNLEN - 1) {
78 c[l++] = n;
79 n = next();
81 c[l] = '\0';
82 return '[';
83 } else if (c[1] == 'C') {
84 argnext(c, 'C', next, back);
85 return 'C';
87 return '\\';
89 return '\0';
92 /* like nextchar(), but return -1 if delim was read */
93 int charnext_delim(char *c, int (*next)(void), void (*back)(int), char *delim)
95 int t = charnext(c, next, back);
96 return strcmp(c, delim) ? t : -1;
99 /* convert back the character read from nextchar() (e.g. xy -> \\(xy) */
100 void charnext_str(char *d, char *c)
102 int c0 = (unsigned char) c[0];
103 if (c0 == c_ec || c0 == c_ni || !c[1] || utf8len(c0) == strlen(c)) {
104 strcpy(d, c);
105 return;
107 if (!c[2] && utf8len(c0) == 1)
108 sprintf(d, "%c(%s", c_ec, c);
109 else
110 sprintf(d, "%cC'%s'", c_ec, c);
113 /* like charnext() for string buffers */
114 int charread(char **s, char *c)
116 int ret;
117 sstr_push(*s);
118 ret = charnext(c, sstr_next, sstr_back);
119 *s = sstr_pop();
120 return ret;
123 /* read the argument of a troff escape sequence */
124 void argnext(char *d, int cmd, int (*next)(void), void (*back)(int))
126 char delim[GNLEN], cs[GNLEN];
127 int c;
128 if (strchr(ESC_P, cmd)) {
129 c = next();
130 if (cmd == 's' && (c == '-' || c == '+')) {
131 *d++ = c;
132 c = next();
134 if (c == '(') {
135 *d++ = next();
136 *d++ = next();
137 } else if (!n_cp && c == '[') {
138 c = next();
139 while (c > 0 && c != '\n' && c != ']') {
140 *d++ = c;
141 c = next();
143 } else {
144 *d++ = c;
145 if (cmd == 's' && c >= '1' && c <= '3') {
146 c = next();
147 if (isdigit(c))
148 *d++ = c;
149 else
150 back(c);
154 if (strchr(ESC_Q, cmd)) {
155 charnext(delim, next, back);
156 while (charnext_delim(cs, next, back, delim) >= 0) {
157 charnext_str(d, cs);
158 d = strchr(d, '\0');
161 *d = '\0';
164 /* this is called only for internal neatroff strings */
165 void argread(char **sp, char *d, int cmd)
167 char *s = *sp;
168 int q;
169 if (strchr(ESC_P, cmd)) {
170 if (cmd == 's' && (*s == '-' || *s == '+'))
171 *d++ = *s++;
172 if (*s == '(') {
173 s++;
174 *d++ = *s++;
175 *d++ = *s++;
176 } else if (!n_cp && *s == '[') {
177 s++;
178 while (*s && *s != ']')
179 *d++ = *s++;
180 if (*s == ']')
181 s++;
182 } else {
183 *d++ = *s++;
184 if (cmd == 's' && s[-1] >= '1' && s[-1] <= '3')
185 if (isdigit(*s))
186 *d++ = *s++;
189 if (strchr(ESC_Q, cmd)) {
190 q = *s++;
191 while (*s && *s != q)
192 *d++ = *s++;
193 if (*s == q)
194 s++;
196 if (cmd == 'z')
197 *d++ = *s++;
198 *d = '\0';
199 *sp = s;
203 * read a glyph or an escape sequence
205 * This functions reads from s either an output troff request
206 * (only the ones emitted by wb.c) or a glyph name and updates
207 * s. The return value is the name of the troff request (the
208 * argument is copied into d) or zero for glyph names (it is
209 * copied into d). Returns -1 when the end of s is reached.
211 int escread(char **s, char *d)
213 char *r = d;
214 if (!**s)
215 return -1;
216 utf8read(s, d);
217 if (d[0] == c_ec) {
218 utf8read(s, d + 1);
219 if (d[1] == '(') {
220 utf8read(s, d);
221 utf8read(s, d + strlen(d));
222 } else if (!n_cp && d[1] == '[') {
223 while (**s && **s != ']')
224 *r++ = *(*s)++;
225 if (**s == ']')
226 (*s)++;
227 } else if (strchr("CDfhmsvXx", d[1])) {
228 int c = d[1];
229 argread(s, d, d[1]);
230 return c == 'C' ? 0 : c;
233 if (d[0] == c_ni)
234 utf8read(s, d + 1);
235 return 0;
239 * string streams: provide next()/back() interface for string buffers
241 * Functions like charnext() require a next()/back() interface
242 * for reading input streams. In order to provide this interface
243 * for string buffers, the following functions can be used:
245 * sstr_push(s);
246 * charnext(c, sstr_next, sstr_back);
247 * sstr_pop();
249 * The calls to sstr_push()/sstr_pop() may be nested.
251 static char *sstr_bufs[NSSTR]; /* buffer stack */
252 static int sstr_n; /* numbers of items in sstr_bufs[] */
253 static char *sstr_s; /* current buffer */
255 void sstr_push(char *s)
257 sstr_bufs[sstr_n++] = sstr_s;
258 sstr_s = s;
261 char *sstr_pop(void)
263 char *ret = sstr_s;
264 sstr_s = sstr_bufs[--sstr_n];
265 return ret;
268 int sstr_next(void)
270 return *sstr_s ? (unsigned char) *sstr_s++ : -1;
273 void sstr_back(int c)
275 sstr_s--;