font: unmap glyphs with .fmap
[neatroff.git] / cp.c
blobdd4e6b2ab6335cbacc3557b18e433a54081362ff
1 /* copy-mode character interpretation */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 static int cp_blkdep; /* input block depth (text in \{ and \}) */
8 static int cp_cpmode; /* disable the interpretation of \w and \E */
9 static int cp_reqdep; /* the block depth of current request line */
11 /* just like cp_next(), but remove c_ni characters */
12 static int cp_noninext(void)
14 int c = cp_next();
15 while (c == c_ni)
16 c = cp_next();
17 return c;
20 /* return 1 if \*[] includes a space */
21 static int cparg(char *d, int len)
23 int c = cp_noninext();
24 int i = 0;
25 if (c == '(') {
26 i += utf8next(d + i, cp_noninext);
27 i += utf8next(d + i, cp_noninext);
28 } else if (!n_cp && c == '[') {
29 c = cp_noninext();
30 while (c >= 0 && c != ']' && c != ' ') {
31 if (i + 1 < len)
32 d[i++] = c;
33 c = cp_noninext();
35 d[i] = '\0';
36 return c == ' ';
37 } else {
38 cp_back(c);
39 utf8next(d, cp_noninext);
41 return 0;
44 static int regid(void)
46 char regname[NMLEN];
47 cparg(regname, sizeof(regname));
48 return map(regname);
51 /* interpolate \n(xy */
52 static void cp_num(void)
54 int id;
55 int c = cp_noninext();
56 if (c != '-' && c != '+')
57 cp_back(c);
58 id = regid();
59 if (c == '-' || c == '+')
60 num_inc(id, c == '+');
61 if (num_str(id))
62 in_push(num_str(id), NULL);
65 /* interpolate \*(xy */
66 static void cp_str(void)
68 char reg[NMLEN];
69 char *args[NARGS + 1] = {NULL};
70 if (cparg(reg, sizeof(reg))) {
71 char *buf = tr_args(args, ']', cp_noninext, cp_back);
72 cp_noninext();
73 if (str_get(map(reg)))
74 in_push(str_get(map(reg)), args);
75 free(buf);
76 } else {
77 if (str_get(map(reg)))
78 in_push(str_get(map(reg)), NULL);
82 /* interpolate \g(xy */
83 static void cp_numfmt(void)
85 in_push(num_getfmt(regid()), NULL);
88 /* interpolate \$1 */
89 static void cp_arg(void)
91 char argname[NMLEN];
92 char *arg = NULL;
93 int argnum;
94 cparg(argname, sizeof(argname));
95 argnum = atoi(argname);
96 if (argnum > 0 && argnum < NARGS + 1)
97 arg = in_arg(argnum);
98 if (arg)
99 in_push(arg, NULL);
102 /* interpolate \w'xyz' */
103 static void cp_width(void)
105 char wid[16];
106 sprintf(wid, "%d", ren_wid(cp_next, cp_back));
107 in_push(wid, NULL);
110 /* define a register as \R'xyz expr' */
111 static void cp_numdef(void)
113 char *arg = quotednext(cp_noninext, cp_back);
114 char *s = arg;
115 while (*s && *s != ' ')
116 s++;
117 if (!*s) {
118 free(arg);
119 return;
121 *s++ = '\0';
122 num_set(map(arg), eval_re(s, num_get(map(arg)), 'u'));
123 free(arg);
126 /* conditional interpolation as \?'cond@expr1@expr2@' */
127 static void cp_cond(void)
129 char delim[GNLEN], cs[GNLEN];
130 char *r, *s;
131 char *s1, *s2;
132 int n;
133 char *arg = quotednext(cp_noninext, cp_back);
134 s = arg;
135 n = eval_up(&s, '\0');
136 if (charread(&s, delim) < 0) {
137 free(arg);
138 return;
140 if (!strcmp(delim, "\\&") && charread(&s, delim) < 0) {
141 free(arg);
142 return;
144 s1 = s;
145 r = s;
146 while (charread_delim(&s, cs, delim) >= 0)
147 r = s;
148 *r = '\0';
149 s2 = s;
150 r = s;
151 while (charread_delim(&s, cs, delim) >= 0)
152 r = s;
153 *r = '\0';
154 in_push(n > 0 ? s1 : s2, NULL);
155 free(arg);
158 static int cp_raw(void)
160 int c;
161 if (in_top() >= 0)
162 return in_next();
163 do {
164 c = in_next();
165 } while (c == c_ni);
166 if (c == c_ec) {
167 do {
168 c = in_next();
169 } while (c == c_ni);
170 if (c == '\n')
171 return cp_raw();
172 if (c == '.')
173 return '.';
174 if (c == '\\') {
175 in_back('\\');
176 return c_ni;
178 if (c == 't') {
179 in_back('\t');
180 return c_ni;
182 if (c == 'a') {
183 in_back('\x01');
184 return c_ni;
186 /* replace \{ and \} with a space if not in copy mode */
187 if (c == '}' && !cp_cpmode) {
188 cp_blkdep--;
189 return ' ';
191 if (c == '{' && !cp_cpmode) {
192 cp_blkdep++;
193 return ' ';
195 in_back(c);
196 return c_ec;
198 return c;
201 int cp_next(void)
203 int c;
204 if (in_top() >= 0)
205 return in_next();
206 c = cp_raw();
207 if (c == c_ec) {
208 c = cp_raw();
209 if (c == 'E' && !cp_cpmode)
210 c = cp_next();
211 if (c == '"') {
212 while (c >= 0 && c != '\n')
213 c = cp_raw();
214 } else if (c == 'w' && !cp_cpmode) {
215 cp_width();
216 c = cp_next();
217 } else if (c == 'n') {
218 cp_num();
219 c = cp_next();
220 } else if (c == '*') {
221 cp_str();
222 c = cp_next();
223 } else if (c == 'g') {
224 cp_numfmt();
225 c = cp_next();
226 } else if (c == '$') {
227 cp_arg();
228 c = cp_next();
229 } else if (c == 'R' && !cp_cpmode) {
230 cp_numdef();
231 c = cp_next();
232 } else if (c == '?' && !cp_cpmode) {
233 cp_cond();
234 c = cp_next();
235 } else {
236 cp_back(c);
237 c = c_ec;
240 return c;
243 void cp_blk(int skip)
245 if (skip) {
246 int c = cp_raw();
247 while (c >= 0 && (c != '\n' || cp_blkdep > cp_reqdep))
248 c = cp_raw();
249 } else {
250 int c = cp_next();
251 while (c == ' ')
252 c = cp_next();
253 /* push back if the space is not inserted due to \{ and \} */
254 if (c != ' ')
255 cp_back(c);
259 void cp_copymode(int mode)
261 cp_cpmode = mode;
264 /* beginning of a request; save current cp_blkdep */
265 void cp_reqbeg(void)
267 cp_reqdep = cp_blkdep;