cp: remove c_ni from strings not pushed via in_push()
[neatroff.git] / cp.c
blob61f6ae8ce84bf5f85b404dbf49c53a63a0afa44f
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 \w and \E */
9 static int cp_reqln; /* a request line; replace \{ with an space */
10 static int cp_reqdep; /* the block depth of current request line */
12 /* just like cp_next(), but remove c_ni characters */
13 static int cp_noninext(void)
15 int c = cp_next();
16 while (c == c_ni)
17 c = cp_next();
18 return c;
21 static void cparg(char *d, int len)
23 int c = cp_noninext();
24 int i = 0;
25 if (c == '(') {
26 d[i++] = cp_noninext();
27 d[i++] = cp_noninext();
28 } else if (!n_cp && c == '[') {
29 c = cp_noninext();
30 while (i < NMLEN - 1 && c >= 0 && c != ']') {
31 d[i++] = c;
32 c = cp_noninext();
34 } else {
35 d[i++] = c;
37 d[i] = '\0';
40 static int regid(void)
42 char regname[NMLEN];
43 cparg(regname, sizeof(regname));
44 return map(regname);
47 /* interpolate \n(xy */
48 static void cp_num(void)
50 int id;
51 int c = cp_noninext();
52 if (c != '-' && c != '+')
53 cp_back(c);
54 id = regid();
55 if (c == '-' || c == '+')
56 num_inc(id, c == '+');
57 if (num_str(id))
58 in_push(num_str(id), NULL);
61 /* interpolate \*(xy */
62 static void cp_str(void)
64 char arg[ILNLEN];
65 struct sbuf sbuf;
66 char *args[NARGS] = {NULL};
67 cparg(arg, sizeof(arg));
68 if (strchr(arg, ' ')) {
69 sbuf_init(&sbuf);
70 sstr_push(strchr(arg, ' ') + 1);
71 tr_readargs(args, &sbuf, sstr_next, sstr_back);
72 sstr_pop();
73 *strchr(arg, ' ') = '\0';
74 if (str_get(map(arg)))
75 in_push(str_get(map(arg)), args);
76 sbuf_done(&sbuf);
77 } else {
78 if (str_get(map(arg)))
79 in_push(str_get(map(arg)), NULL);
83 /* interpolate \g(xy */
84 static void cp_numfmt(void)
86 in_push(num_getfmt(regid()), NULL);
89 /* interpolate \$1 */
90 static void cp_arg(void)
92 char argname[NMLEN];
93 char *arg = NULL;
94 int argnum;
95 cparg(argname, sizeof(argname));
96 argnum = atoi(argname);
97 if (argnum > 0 && argnum < NARGS + 1)
98 arg = in_arg(argnum);
99 if (arg)
100 in_push(arg, NULL);
103 /* interpolate \w'xyz' */
104 static void cp_width(void)
106 char wid[16];
107 sprintf(wid, "%d", ren_wid(cp_next, cp_back));
108 in_push(wid, NULL);
111 /* define a register as \R'xyz expr' */
112 static void cp_numdef(void)
114 char arg[ILNLEN];
115 char *s;
116 quotednext(arg, cp_noninext, cp_back);
117 s = arg;
118 while (*s && *s != ' ')
119 s++;
120 if (!*s)
121 return;
122 *s++ = '\0';
123 num_set(map(arg), eval_re(s, num_get(map(arg)), 'u'));
126 /* conditional interpolation as \?'cond@expr1@expr2@' */
127 static void cp_cond(void)
129 char arg[ILNLEN];
130 char delim[GNLEN], cs[GNLEN];
131 char *r, *s = arg;
132 char *s1, *s2;
133 int n;
134 quotednext(arg, cp_noninext, cp_back);
135 n = eval_up(&s, '\0');
136 if (charread(&s, delim) < 0)
137 return;
138 if (!strcmp(delim, "\\&") && charread(&s, delim) < 0)
139 return;
140 s1 = s;
141 r = s;
142 while (charread_delim(&s, cs, delim) >= 0)
143 r = s;
144 *r = '\0';
145 s2 = s;
146 r = s;
147 while (charread_delim(&s, cs, delim) >= 0)
148 r = s;
149 *r = '\0';
150 in_push(n > 0 ? s1 : s2, NULL);
153 static int cp_raw(void)
155 int c;
156 if (in_top() >= 0)
157 return in_next();
158 do {
159 c = in_next();
160 } while (c == c_ni);
161 if (c == c_ec) {
162 do {
163 c = in_next();
164 } while (c == c_ni);
165 if (c == '\n')
166 return cp_raw();
167 if (c == '.')
168 return '.';
169 if (c == '\\') {
170 in_back('\\');
171 return c_ni;
173 if (c == 't') {
174 in_back('\t');
175 return c_ni;
177 if (c == 'a') {
178 in_back('\x01');
179 return c_ni;
181 if (c == '}' && !cp_cpmode) {
182 cp_blkdep--;
183 return cp_raw();
185 if (c == '{' && !cp_cpmode) {
186 cp_blkdep++;
187 return cp_reqln ? ' ' : cp_raw();
189 in_back(c);
190 return c_ec;
192 if (c == '\n')
193 cp_reqln = 0;
194 return c;
197 int cp_next(void)
199 int c;
200 if (in_top() >= 0)
201 return in_next();
202 c = cp_raw();
203 if (c == c_ec) {
204 c = cp_raw();
205 if (c == 'E' && !cp_cpmode)
206 c = cp_next();
207 if (c == '"') {
208 while (c >= 0 && c != '\n')
209 c = cp_raw();
210 } else if (c == 'w' && !cp_cpmode) {
211 cp_width();
212 c = cp_next();
213 } else if (c == 'n') {
214 cp_num();
215 c = cp_next();
216 } else if (c == '*') {
217 cp_str();
218 c = cp_next();
219 } else if (c == 'g') {
220 cp_numfmt();
221 c = cp_next();
222 } else if (c == '$') {
223 cp_arg();
224 c = cp_next();
225 } else if (c == 'R' && !cp_cpmode) {
226 cp_numdef();
227 c = cp_next();
228 } else if (c == '?' && !cp_cpmode) {
229 cp_cond();
230 c = cp_next();
231 } else {
232 cp_back(c);
233 c = c_ec;
236 return c;
239 void cp_blk(int skip)
241 if (skip) {
242 int c = cp_raw();
243 while (c >= 0 && (c != '\n' || cp_blkdep > cp_reqdep))
244 c = cp_raw();
245 } else {
246 int c = cp_next();
247 while ((c == ' ' || c == '\t'))
248 c = cp_next();
249 /* push back if the space is not inserted because of cp_reqln */
250 if (c != ' ' && c != '\t')
251 cp_back(c);
255 void cp_copymode(int mode)
257 cp_cpmode = mode;
260 /* beginning of a request line; replace \{ with a space until an EOL */
261 void cp_reqline(void)
263 cp_reqln = 1;
264 cp_reqdep = cp_blkdep;