font: "ggrp" lines in font descriptions define character groups
[neatroff.git] / cp.c
blob8f6ac4a9883f7299e0d05f5c906367ef4cf502d2
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_nblk; /* input block depth (text in \{ and \}) */
8 static int cp_sblk[NIES]; /* skip \} escape at this depth, if set */
9 static int cp_cpmode; /* disable the interpretation \w and \E */
11 static void cparg(char *d, int len)
13 int c = cp_next();
14 int i = 0;
15 if (c == '(') {
16 d[i++] = cp_next();
17 d[i++] = cp_next();
18 } else if (!n_cp && c == '[') {
19 c = cp_next();
20 while (i < NMLEN - 1 && c >= 0 && c != ']') {
21 d[i++] = c;
22 c = cp_next();
24 } else {
25 d[i++] = c;
27 d[i] = '\0';
30 static int regid(void)
32 char regname[NMLEN];
33 cparg(regname, sizeof(regname));
34 return map(regname);
37 /* interpolate \n(xy */
38 static void cp_num(void)
40 int id;
41 int c = cp_next();
42 if (c != '-' && c != '+')
43 cp_back(c);
44 id = regid();
45 if (c == '-' || c == '+')
46 num_get(id, c == '+' ? 1 : -1);
47 if (num_str(id))
48 in_push(num_str(id), NULL);
51 /* interpolate \*(xy */
52 static void cp_str(void)
54 char arg[ILNLEN];
55 struct sbuf sbuf;
56 char *args[NARGS] = {NULL};
57 cparg(arg, sizeof(arg));
58 if (strchr(arg, ' ')) {
59 sbuf_init(&sbuf);
60 sstr_push(strchr(arg, ' ') + 1);
61 tr_readargs(args, &sbuf, sstr_next, sstr_back);
62 sstr_pop();
63 *strchr(arg, ' ') = '\0';
64 if (str_get(map(arg)))
65 in_push(str_get(map(arg)), args);
66 sbuf_done(&sbuf);
67 } else {
68 if (str_get(map(arg)))
69 in_push(str_get(map(arg)), NULL);
73 /* interpolate \g(xy */
74 static void cp_numfmt(void)
76 in_push(num_getfmt(regid()), NULL);
79 /* interpolate \$1 */
80 static void cp_arg(void)
82 char argname[NMLEN];
83 char *arg = NULL;
84 int argnum;
85 cparg(argname, sizeof(argname));
86 argnum = atoi(argname);
87 if (argnum > 0 && argnum < NARGS + 1)
88 arg = in_arg(argnum);
89 if (arg)
90 in_push(arg, NULL);
93 /* interpolate \w'xyz' */
94 static void cp_width(void)
96 char wid[16];
97 sprintf(wid, "%d", ren_wid(cp_next, cp_back));
98 in_push(wid, NULL);
101 /* define a register as \R'xyz expr' */
102 static void cp_numdef(void)
104 char arg[ILNLEN];
105 char *s;
106 quotednext(arg, cp_next, cp_back);
107 s = arg;
108 while (*s && *s != ' ')
109 s++;
110 if (!*s)
111 return;
112 *s++ = '\0';
113 num_set(map(arg), eval_re(s, num_get(map(arg), 0), 'u'));
116 /* conditional interpolation as \?'cond@expr1@expr2@' */
117 static void cp_cond(void)
119 char arg[ILNLEN];
120 char delim[GNLEN], cs[GNLEN];
121 char *r, *s = arg;
122 char *s1, *s2;
123 int n;
124 quotednext(arg, cp_next, cp_back);
125 n = eval_up(&s, '\0');
126 if (charread(&s, delim) < 0)
127 return;
128 if (!strcmp(delim, "\\&") && charread(&s, delim) < 0)
129 return;
130 s1 = s;
131 r = s;
132 while (charread_delim(&s, cs, delim) >= 0)
133 r = s;
134 *r = '\0';
135 s2 = s;
136 r = s;
137 while (charread_delim(&s, cs, delim) >= 0)
138 r = s;
139 *r = '\0';
140 in_push(n > 0 ? s1 : s2, NULL);
143 static int cp_raw(void)
145 int c;
146 if (in_top() >= 0)
147 return in_next();
148 do {
149 c = in_next();
150 } while (c == c_ni);
151 if (c == c_ec) {
152 do {
153 c = in_next();
154 } while (c == c_ni);
155 if (c == '\n')
156 return cp_raw();
157 if (c == '.')
158 return '.';
159 if (c == '\\') {
160 in_back('\\');
161 return c_ni;
163 if (c == 't') {
164 in_back('\t');
165 return c_ni;
167 if (c == 'a') {
168 in_back('\x01');
169 return c_ni;
171 if (c == '{' && cp_nblk < LEN(cp_sblk))
172 cp_sblk[cp_nblk++] = 0;
173 if (c == '}' && cp_nblk > 0)
174 if (cp_sblk[--cp_nblk])
175 return cp_raw();
176 in_back(c);
177 return c_ec;
179 return c;
182 int cp_next(void)
184 int c;
185 if (in_top() >= 0)
186 return in_next();
187 c = cp_raw();
188 if (c == c_ec) {
189 c = cp_raw();
190 if (c == 'E' && !cp_cpmode)
191 c = cp_next();
192 if (c == '"') {
193 while (c >= 0 && c != '\n')
194 c = cp_raw();
195 } else if (c == 'w' && !cp_cpmode) {
196 cp_width();
197 c = cp_next();
198 } else if (c == 'n') {
199 cp_num();
200 c = cp_next();
201 } else if (c == '*') {
202 cp_str();
203 c = cp_next();
204 } else if (c == 'g') {
205 cp_numfmt();
206 c = cp_next();
207 } else if (c == '$') {
208 cp_arg();
209 c = cp_next();
210 } else if (c == 'R' && !cp_cpmode) {
211 cp_numdef();
212 c = cp_next();
213 } else if (c == '?' && !cp_cpmode) {
214 cp_cond();
215 c = cp_next();
216 } else {
217 cp_back(c);
218 c = c_ec;
221 return c;
224 void cp_blk(int skip)
226 int c;
227 int nblk = cp_nblk;
228 do {
229 c = skip ? cp_raw() : cp_next();
230 } while (c == ' ' || c == '\t');
231 if (skip) {
232 while (c >= 0 && (c != '\n' || cp_nblk > nblk))
233 c = cp_raw();
234 } else {
235 if (c == c_ec && in_top() == '{') { /* a troff \{ \} block */
236 cp_sblk[nblk] = 1;
237 cp_raw();
238 } else {
239 cp_back(c);
244 void cp_copymode(int mode)
246 cp_cpmode = mode;