hyph: handle special characters
[neatroff.git] / cp.c
blobfb9a8cb77ec8b45e53a5dc96f55f7d11afd80c59
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 static void cparg(char *d, int len)
22 int c = cp_noninext();
23 int i = 0;
24 if (c == '(') {
25 d[i++] = cp_noninext();
26 d[i++] = cp_noninext();
27 } else if (!n_cp && c == '[') {
28 c = cp_noninext();
29 while (i < NMLEN - 1 && c >= 0 && c != ']') {
30 d[i++] = c;
31 c = cp_noninext();
33 } else {
34 d[i++] = c;
36 d[i] = '\0';
39 static int regid(void)
41 char regname[NMLEN];
42 cparg(regname, sizeof(regname));
43 return map(regname);
46 /* interpolate \n(xy */
47 static void cp_num(void)
49 int id;
50 int c = cp_noninext();
51 if (c != '-' && c != '+')
52 cp_back(c);
53 id = regid();
54 if (c == '-' || c == '+')
55 num_inc(id, c == '+');
56 if (num_str(id))
57 in_push(num_str(id), NULL);
60 /* interpolate \*(xy */
61 static void cp_str(void)
63 char arg[ILNLEN];
64 struct sbuf sbuf;
65 char *args[NARGS] = {NULL};
66 cparg(arg, sizeof(arg));
67 if (strchr(arg, ' ')) {
68 sbuf_init(&sbuf);
69 sstr_push(strchr(arg, ' ') + 1);
70 tr_readargs(args, &sbuf, sstr_next, sstr_back);
71 sstr_pop();
72 *strchr(arg, ' ') = '\0';
73 if (str_get(map(arg)))
74 in_push(str_get(map(arg)), args);
75 sbuf_done(&sbuf);
76 } else {
77 if (str_get(map(arg)))
78 in_push(str_get(map(arg)), 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[ILNLEN];
114 char *s;
115 quotednext(arg, cp_noninext, cp_back);
116 s = arg;
117 while (*s && *s != ' ')
118 s++;
119 if (!*s)
120 return;
121 *s++ = '\0';
122 num_set(map(arg), eval_re(s, num_get(map(arg)), 'u'));
125 /* conditional interpolation as \?'cond@expr1@expr2@' */
126 static void cp_cond(void)
128 char arg[ILNLEN];
129 char delim[GNLEN], cs[GNLEN];
130 char *r, *s = arg;
131 char *s1, *s2;
132 int n;
133 quotednext(arg, cp_noninext, cp_back);
134 n = eval_up(&s, '\0');
135 if (charread(&s, delim) < 0)
136 return;
137 if (!strcmp(delim, "\\&") && charread(&s, delim) < 0)
138 return;
139 s1 = s;
140 r = s;
141 while (charread_delim(&s, cs, delim) >= 0)
142 r = s;
143 *r = '\0';
144 s2 = s;
145 r = s;
146 while (charread_delim(&s, cs, delim) >= 0)
147 r = s;
148 *r = '\0';
149 in_push(n > 0 ? s1 : s2, NULL);
152 static int cp_raw(void)
154 int c;
155 if (in_top() >= 0)
156 return in_next();
157 do {
158 c = in_next();
159 } while (c == c_ni);
160 if (c == c_ec) {
161 do {
162 c = in_next();
163 } while (c == c_ni);
164 if (c == '\n')
165 return cp_raw();
166 if (c == '.')
167 return '.';
168 if (c == '\\') {
169 in_back('\\');
170 return c_ni;
172 if (c == 't') {
173 in_back('\t');
174 return c_ni;
176 if (c == 'a') {
177 in_back('\x01');
178 return c_ni;
180 /* replace \{ and \} with a space if not in copy mode */
181 if (c == '}' && !cp_cpmode) {
182 cp_blkdep--;
183 return ' ';
185 if (c == '{' && !cp_cpmode) {
186 cp_blkdep++;
187 return ' ';
189 in_back(c);
190 return c_ec;
192 return c;
195 int cp_next(void)
197 int c;
198 if (in_top() >= 0)
199 return in_next();
200 c = cp_raw();
201 if (c == c_ec) {
202 c = cp_raw();
203 if (c == 'E' && !cp_cpmode)
204 c = cp_next();
205 if (c == '"') {
206 while (c >= 0 && c != '\n')
207 c = cp_raw();
208 } else if (c == 'w' && !cp_cpmode) {
209 cp_width();
210 c = cp_next();
211 } else if (c == 'n') {
212 cp_num();
213 c = cp_next();
214 } else if (c == '*') {
215 cp_str();
216 c = cp_next();
217 } else if (c == 'g') {
218 cp_numfmt();
219 c = cp_next();
220 } else if (c == '$') {
221 cp_arg();
222 c = cp_next();
223 } else if (c == 'R' && !cp_cpmode) {
224 cp_numdef();
225 c = cp_next();
226 } else if (c == '?' && !cp_cpmode) {
227 cp_cond();
228 c = cp_next();
229 } else {
230 cp_back(c);
231 c = c_ec;
234 return c;
237 void cp_blk(int skip)
239 if (skip) {
240 int c = cp_raw();
241 while (c >= 0 && (c != '\n' || cp_blkdep > cp_reqdep))
242 c = cp_raw();
243 } else {
244 int c = cp_next();
245 while ((c == ' ' || c == '\t'))
246 c = cp_next();
247 /* push back if the space is not inserted due to \{ and \} */
248 if (c != ' ' && c != '\t')
249 cp_back(c);
253 void cp_copymode(int mode)
255 cp_cpmode = mode;
258 /* beginning of a request; save current cp_blkdep */
259 void cp_reqbeg(void)
261 cp_reqdep = cp_blkdep;