tr: read transparent output escape sequence in tr.c
[neatroff.git] / reg.c
blob7254d07c8b74ff1a9007e3dd9e539e214524c507
1 /* registers and environments */
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8 #include <unistd.h>
9 #include "roff.h"
11 #define NENVS 64 /* number of environment registers */
13 struct env {
14 int eregs[NENVS]; /* environment-specific number registers */
15 int tabs[NTABS]; /* tab stops */
16 char tabs_type[NTABS]; /* type of tabs: L, C, R */
17 struct fmt *fmt; /* per environment line formatting buffer */
18 struct wb wb; /* per environment partial word */
19 char tc[GNLEN]; /* tab character (.tc) */
20 char lc[GNLEN]; /* leader character (.lc) */
21 char hc[GNLEN]; /* hyphenation character (.hc) */
22 char mc[GNLEN]; /* margin character (.mc) */
25 static int nregs[NREGS]; /* global number registers */
26 static int nregs_inc[NREGS]; /* number register auto-increment size */
27 static int nregs_fmt[NREGS]; /* number register format */
28 static char *sregs[NREGS]; /* global string registers */
29 static void *sregs_dat[NREGS]; /* builtin function data */
30 static struct env *envs[NREGS];/* environments */
31 static struct env *env; /* current enviroment */
32 static int env_id; /* current environment id */
33 static int eregs_idx[NREGS]; /* register environment index in eregs[] */
35 static char *eregs[] = { /* environment-specific number registers */
36 "ln", ".f", ".i", ".j", ".l",
37 ".L", ".nI", ".nm", ".nM", ".nn",
38 ".nS", ".m", ".s", ".u", ".v",
39 ".it", ".itn", ".mc", ".mcn",
40 ".ce", ".f0", ".hy", ".hyp", ".i0", ".l0",
41 ".L0", ".m0", ".n0", ".s0", ".ss", ".ssh", ".sss",
42 ".ti", ".lt", ".lt0", ".v0",
45 /* return the address of a number register */
46 int *nreg(int id)
48 if (eregs_idx[id])
49 return &env->eregs[eregs_idx[id]];
50 return &nregs[id];
53 static char *directory(char *path)
55 static char dst[PATHLEN];
56 char *s = strrchr(path, '/');
57 if (!s)
58 return ".";
59 if (path == s)
60 return "/";
61 memcpy(dst, path, s - path);
62 dst[s - path] = '\0';
63 return dst;
66 static int num_fmt(char *s, int n, int fmt);
68 /* the contents of a number register (returns a static buffer) */
69 char *num_str(int id)
71 static char numbuf[128];
72 char *s = map_name(id);
73 if (!nregs_fmt[id])
74 nregs_fmt[id] = '0';
75 numbuf[0] = '\0';
76 if (s[0] == '.' && !s[2]) {
77 switch (s[1]) {
78 case 'b':
79 sprintf(numbuf, "%d", font_getbd(dev_font(n_f)));
80 return numbuf;
81 case 'c':
82 sprintf(numbuf, "%d", in_lnum());
83 return numbuf;
84 case 'k':
85 sprintf(numbuf, "%d", f_hpos());
86 return numbuf;
87 case 'm':
88 sprintf(numbuf, "#%02x%02x%02x",
89 CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
90 return numbuf;
91 case 't':
92 sprintf(numbuf, "%d", f_nexttrap());
93 return numbuf;
94 case 'z':
95 if (f_divreg() >= 0)
96 sprintf(numbuf, "%s", map_name(f_divreg()));
97 return numbuf;
98 case 'F':
99 sprintf(numbuf, "%s", in_filename());
100 return numbuf;
101 case 'D':
102 sprintf(numbuf, "%s", directory(in_filename()));
103 return numbuf;
104 case '$':
105 sprintf(numbuf, "%d", in_nargs());
106 return numbuf;
109 if (s[0] == '.' && !strcmp(".neat", s))
110 return "1";
111 if (s[0] == '.' && s[1] == 'e' && s[2] == 'v' && !s[3])
112 return map_name(env_id);
113 if (s[0] == '$' && s[1] == '$' && !s[2]) {
114 sprintf(numbuf, "%d", getpid());
115 return numbuf;
117 if (s[0] == 'y' && s[1] == 'r' && !s[2]) {
118 sprintf(numbuf, "%02d", *nreg(id));
119 return numbuf;
121 if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
122 sprintf(numbuf, "%d", *nreg(id));
123 return numbuf;
126 void num_set(int id, int val)
128 if (!nregs_fmt[id])
129 nregs_fmt[id] = '0';
130 *nreg(id) = val;
133 void num_setinc(int id, int val)
135 nregs_inc[id] = val;
138 void num_inc(int id, int pos)
140 *nreg(id) += pos > 0 ? nregs_inc[id] : -nregs_inc[id];
143 void num_del(int id)
145 *nreg(id) = 0;
146 nregs_inc[id] = 0;
147 nregs_fmt[id] = 0;
150 void str_set(int id, char *s)
152 int len = strlen(s) + 1;
153 if (sregs[id])
154 free(sregs[id]);
155 sregs[id] = xmalloc(len);
156 memcpy(sregs[id], s, len);
157 sregs_dat[id] = NULL;
160 char *str_get(int id)
162 return sregs[id];
165 void *str_dget(int id)
167 return sregs_dat[id];
170 void str_dset(int id, void *d)
172 sregs_dat[id] = d;
175 void str_rm(int id)
177 if (sregs[id])
178 free(sregs[id]);
179 sregs[id] = NULL;
180 sregs_dat[id] = NULL;
183 void str_rn(int src, int dst)
185 if (!sregs[src] && !sregs_dat[src])
186 return;
187 str_rm(dst);
188 sregs[dst] = sregs[src];
189 sregs_dat[dst] = sregs_dat[src];
190 sregs[src] = NULL;
191 sregs_dat[src] = NULL;
194 static struct env *env_alloc(void)
196 struct env *env = xmalloc(sizeof(*env));
197 memset(env, 0, sizeof(*env));
198 wb_init(&env->wb);
199 env->fmt = fmt_alloc();
200 return env;
203 static void env_free(struct env *env)
205 fmt_free(env->fmt);
206 wb_done(&env->wb);
207 free(env);
210 static void env_set(int id)
212 int i;
213 env = envs[id];
214 env_id = id;
215 if (!env) {
216 envs[id] = env_alloc();
217 env = envs[id];
218 n_f = 1;
219 n_i = 0;
220 n_j = AD_B;
221 n_l = SC_IN * 65 / 10;
222 n_L = 1;
223 n_s = 10;
224 n_u = 1;
225 n_v = 12 * SC_PT;
226 n_s0 = n_s;
227 n_f0 = n_f;
228 n_na = 0;
229 n_lt = SC_IN * 65 / 10;
230 n_hy = 1;
231 n_ss = 12;
232 n_sss = 12;
233 n_nM = 1;
234 n_nS = 1;
235 strcpy(env->hc, "\\%");
236 strcpy(env->lc, ".");
237 for (i = 0; i < NTABS; i++)
238 env->tabs[i] = i * SC_IN / 2;
242 static void init_time(void)
244 time_t t = time(NULL);
245 struct tm *tm = localtime(&t);
246 num_set(map("dw"), tm->tm_wday + 1);
247 num_set(map("dy"), tm->tm_mday);
248 num_set(map("mo"), tm->tm_mon + 1);
249 num_set(map("yr"), tm->tm_year % 100);
252 static void init_globals(void)
254 n_o = SC_IN;
255 n_p = SC_IN * 11;
256 n_lg = 1;
257 n_kn = 0;
258 num_set(map(".H"), 1);
259 num_set(map(".V"), 1);
262 void env_init(void)
264 int i;
265 init_time();
266 init_globals();
267 for (i = 0; i < LEN(eregs); i++)
268 eregs_idx[map(eregs[i])] = i + 1;
269 env_set(map("0"));
272 void env_done(void)
274 int i;
275 for (i = 0; i < LEN(envs); i++)
276 if (envs[i])
277 env_free(envs[i]);
280 static int oenv[NPREV]; /* environment stack */
281 static int nenv;
283 void tr_ev(char **args)
285 int id = -1;
286 if (args[1])
287 id = map(args[1]);
288 else
289 id = nenv ? oenv[--nenv] : -1;
290 if (id < 0)
291 return;
292 if (args[1] && env && nenv < NPREV)
293 oenv[nenv++] = env_id;
294 env_set(id);
297 struct fmt *env_fmt(void)
299 return env->fmt;
302 struct wb *env_wb(void)
304 return &env->wb;
307 char *env_hc(void)
309 return env->hc;
312 char *env_mc(void)
314 return env->mc;
317 char *env_tc(void)
319 return env->tc;
322 char *env_lc(void)
324 return env->lc;
327 /* saving and restoring registers around diverted lines */
328 struct odiv {
329 int f, s, m, f0, s0, m0;
332 static struct odiv odivs[NPREV]; /* state before diverted text */
333 static int nodivs;
335 /* begin outputting diverted line */
336 void odiv_beg(void)
338 struct odiv *o = &odivs[nodivs++];
339 o->f = n_f;
340 o->s = n_s;
341 o->m = n_m;
342 o->f0 = n_f0;
343 o->s0 = n_s0;
344 o->m0 = n_m0;
347 /* end outputting diverted line */
348 void odiv_end(void)
350 struct odiv *o = &odivs[--nodivs];
351 n_f = o->f;
352 n_s = o->s;
353 n_m = o->m;
354 n_f0 = o->f0;
355 n_s0 = o->s0;
356 n_m0 = o->m0;
359 void tr_ta(char **args)
361 int i;
362 char *s;
363 for (i = 0; i < NARGS && args[i]; i++) {
364 env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm');
365 s = args[i][0] ? strchr(args[i], '\0') - 1 : "";
366 env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L';
370 static int tab_idx(int pos)
372 int i;
373 for (i = 0; i < LEN(env->tabs); i++)
374 if (env->tabs[i] > pos)
375 return i;
376 return -1;
379 int tab_next(int pos)
381 int i = tab_idx(pos);
382 return i >= 0 ? env->tabs[i] : pos;
385 int tab_type(int pos)
387 int i = tab_idx(pos);
388 return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L';
391 /* number register format (.af) */
392 #define NF_LSH 8 /* number format length shifts */
393 #define NF_FMT 0x00ff /* number format mask */
395 /* the format of a number register (returns a static buffer) */
396 char *num_getfmt(int id)
398 static char fmtbuf[128];
399 char *s = fmtbuf;
400 int i;
401 if ((nregs_fmt[id] & NF_FMT) == '0') {
402 *s++ = '0';
403 i = nregs_fmt[id] >> NF_LSH;
404 while (i-- > 1)
405 *s++ = '0';
406 } else if (nregs_fmt[id]) {
407 *s++ = nregs_fmt[id] & NF_FMT;
409 *s = '\0';
410 return fmtbuf;
413 void num_setfmt(int id, char *s)
415 int i = 0;
416 if (strchr("iIaA", s[0])) {
417 nregs_fmt[id] = s[0];
418 } else {
419 while (isdigit(s[i]))
420 i++;
421 nregs_fmt[id] = '0' | (i << NF_LSH);
425 static void nf_reverse(char *s)
427 char r[128];
428 int i, l;
429 strcpy(r, s);
430 l = strlen(r);
431 for (i = 0; i < l; i++)
432 s[i] = r[l - i - 1];
435 static void nf_roman(char *s, int n, char *I, char *V)
437 int i;
438 if (!n)
439 return;
440 if (n % 5 == 4) {
441 *s++ = n % 10 == 9 ? I[1] : V[0];
442 *s++ = I[0];
443 } else {
444 for (i = 0; i < n % 5; i++)
445 *s++ = I[0];
446 if (n % 10 >= 5)
447 *s++ = V[0];
449 *s = '\0';
450 nf_roman(s, n / 10, I + 1, V + 1);
453 static void nf_alpha(char *s, int n, int a)
455 while (n) {
456 *s++ = a + ((n - 1) % 26);
457 n /= 26;
459 *s = '\0';
462 /* returns nonzero on failure */
463 static int num_fmt(char *s, int n, int fmt)
465 int type = fmt & NF_FMT;
466 int len;
467 if (n < 0) {
468 n = -n;
469 *s++ = '-';
471 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
472 if (type == 'i')
473 nf_roman(s, n, "ixcmz", "vldw");
474 else
475 nf_roman(s, n, "IXCMZ", "VLDW");
476 nf_reverse(s);
477 return 0;
479 if ((type == 'a' || type == 'A') && n > 0) {
480 nf_alpha(s, n, type);
481 nf_reverse(s);
482 return 0;
484 if (type == '0') {
485 sprintf(s, "%d", n);
486 len = strlen(s);
487 while (len++ < fmt >> NF_LSH)
488 *s++ = '0';
489 sprintf(s, "%d", n);
490 return 0;
492 return 1;