out: simply ignore unknown characters
[neatroff.git] / reg.c
blob3f372d412e97b3402127523b5eadb4e842e6b8f1
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 "roff.h"
10 #define NENVS 64 /* number of environment registers */
12 struct env {
13 int eregs[NENVS]; /* environment-specific number registers */
14 int tabs[NTABS]; /* tab stops */
15 char tabs_type[NTABS]; /* type of tabs: L, C, R */
16 struct adj *adj; /* per environment line buffer */
17 char tc[GNLEN]; /* tab character (.tc) */
18 char lc[GNLEN]; /* leader character (.lc) */
19 char hc[GNLEN]; /* hyphenation character (.hc) */
20 char mc[GNLEN]; /* margin character (.mc) */
23 static int nregs[NREGS]; /* global number registers */
24 static int nregs_inc[NREGS]; /* number register auto-increment size */
25 static int nregs_fmt[NREGS]; /* number register format */
26 static char *sregs[NREGS]; /* global string registers */
27 static void *sregs_dat[NREGS]; /* builtin function data */
28 static struct env *envs[NREGS];/* environments */
29 static struct env *env; /* current enviroment */
30 static int env_id; /* current environment id */
31 static int eregs_idx[NREGS]; /* register environment index in eregs[] */
33 static char *eregs[] = { /* environment-specific number registers */
34 "ln", ".f", ".i", ".j", ".l",
35 ".L", ".nI", ".nm", ".nM", ".nn",
36 ".nS", ".m", ".s", ".u", ".v",
37 ".it", ".itn", ".mc", ".mcn",
38 ".ce", ".f0", ".hy", ".i0", ".l0",
39 ".L0", ".m0", ".n0", ".s0", ".ss",
40 ".lt", ".lt0", ".v0",
43 /* return the address of a number register */
44 int *nreg(int id)
46 if (eregs_idx[id])
47 return &env->eregs[eregs_idx[id]];
48 return &nregs[id];
51 static int num_fmt(char *s, int n, int fmt);
53 /* the contents of a number register (returns a static buffer) */
54 char *num_str(int id)
56 static char numbuf[128];
57 char *s = map_name(id);
58 numbuf[0] = '\0';
59 if (s[0] == '.' && !s[2]) {
60 switch (s[1]) {
61 case 'b':
62 sprintf(numbuf, "%d", dev_getbd(n_f));
63 return numbuf;
64 case 'c':
65 sprintf(numbuf, "%d", in_lnum());
66 return numbuf;
67 case 'k':
68 sprintf(numbuf, "%d", f_hpos());
69 return numbuf;
70 case 'm':
71 sprintf(numbuf, "#%02x%02x%02x", CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
72 return numbuf;
73 case 't':
74 sprintf(numbuf, "%d", f_nexttrap());
75 return numbuf;
76 case 'z':
77 if (f_divreg() >= 0)
78 sprintf(numbuf, "%s", map_name(f_divreg()));
79 return numbuf;
80 case 'F':
81 sprintf(numbuf, "%s", in_filename());
82 return numbuf;
83 case '$':
84 sprintf(numbuf, "%d", in_nargs());
85 return numbuf;
88 if (id == map("yr")) {
89 sprintf(numbuf, "%02d", nregs[id]);
90 return numbuf;
92 if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
93 sprintf(numbuf, "%d", *nreg(id));
94 return numbuf;
97 void num_set(int id, int val)
99 *nreg(id) = val;
102 void num_inc(int id, int val)
104 nregs_inc[id] = val;
107 void num_del(int id)
109 *nreg(id) = 0;
110 nregs_inc[id] = 0;
111 nregs_fmt[id] = 0;
114 int num_get(int id, int inc)
116 if (inc)
117 *nreg(id) += inc > 0 ? nregs_inc[id] : -nregs_inc[id];
118 return *nreg(id);
121 void str_set(int id, char *s)
123 int len = strlen(s) + 1;
124 if (sregs[id])
125 free(sregs[id]);
126 sregs[id] = malloc(len);
127 memcpy(sregs[id], s, len);
128 sregs_dat[id] = NULL;
131 char *str_get(int id)
133 return sregs[id];
136 void *str_dget(int id)
138 return sregs_dat[id];
141 void str_dset(int id, void *d)
143 sregs_dat[id] = d;
146 void str_rm(int id)
148 if (sregs[id])
149 free(sregs[id]);
150 sregs[id] = NULL;
151 sregs_dat[id] = NULL;
154 void str_rn(int src, int dst)
156 str_rm(dst);
157 sregs[dst] = sregs[src];
158 sregs_dat[dst] = sregs_dat[src];
159 sregs[src] = NULL;
160 sregs_dat[src] = NULL;
163 static struct env *env_alloc(void)
165 struct env *env = malloc(sizeof(*env));
166 memset(env, 0, sizeof(*env));
167 env->adj = adj_alloc();
168 return env;
171 static void env_free(struct env *env)
173 adj_free(env->adj);
174 free(env);
177 static void env_set(int id)
179 int i;
180 env = envs[id];
181 env_id = id;
182 if (!env) {
183 envs[id] = env_alloc();
184 env = envs[id];
185 n_f = 1;
186 n_i = 0;
187 n_j = AD_B;
188 n_l = SC_IN * 65 / 10;
189 n_L = 1;
190 n_s = 10;
191 n_u = 1;
192 n_v = 12 * SC_PT;
193 n_s0 = n_s;
194 n_f0 = n_f;
195 n_na = 0;
196 n_lt = SC_IN * 65 / 10;
197 n_hy = 1;
198 n_ss = 12;
199 n_nM = 1;
200 n_nS = 1;
201 strcpy(env->hc, "\\%");
202 strcpy(env->lc, ".");
203 adj_ll(env->adj, n_l);
204 adj_in(env->adj, n_i);
205 for (i = 0; i < NTABS; i++)
206 env->tabs[i] = i * SC_IN / 2;
210 static void init_time(void)
212 time_t t = time(NULL);
213 struct tm *tm = localtime(&t);
214 nregs[map("dw")] = tm->tm_wday + 1;
215 nregs[map("dy")] = tm->tm_mday;
216 nregs[map("mo")] = tm->tm_mon + 1;
217 nregs[map("yr")] = tm->tm_year % 100;
220 static void init_globals(void)
222 n_o = SC_IN;
223 n_p = SC_IN * 11;
224 n_lg = 1;
225 n_kn = 0;
228 void env_init(void)
230 int i;
231 init_time();
232 init_globals();
233 for (i = 0; i < LEN(eregs); i++)
234 eregs_idx[map(eregs[i])] = i + 1;
235 env_set(0);
238 void env_done(void)
240 int i;
241 for (i = 0; i < LEN(envs); i++)
242 if (envs[i])
243 env_free(envs[i]);
246 static int oenv[NPREV]; /* environment stack */
247 static int nenv;
249 void tr_ev(char **args)
251 int id = -1;
252 if (args[1])
253 id = map(args[1]);
254 else
255 id = nenv ? oenv[--nenv] : -1;
256 if (id < 0)
257 return;
258 if (args[1] && env && nenv < NPREV)
259 oenv[nenv++] = env_id;
260 env_set(id);
263 struct adj *env_adj(void)
265 return env->adj;
268 char *env_hc(void)
270 return env->hc;
273 char *env_mc(void)
275 return env->mc;
278 char *env_tc(void)
280 return env->tc;
283 char *env_lc(void)
285 return env->lc;
288 /* saving and restoring registers around diverted lines */
289 struct odiv {
290 int f, s, m, f0, s0, m0;
293 static struct odiv odivs[NPREV]; /* state before diverted text */
294 static int nodivs;
296 /* begin outputting diverted line */
297 void odiv_beg(void)
299 struct odiv *o = &odivs[nodivs++];
300 o->f = n_f;
301 o->s = n_s;
302 o->m = n_m;
303 o->f0 = n_f0;
304 o->s0 = n_s0;
305 o->m0 = n_m0;
308 /* end outputting diverted line */
309 void odiv_end(void)
311 struct odiv *o = &odivs[--nodivs];
312 n_f = o->f;
313 n_s = o->s;
314 n_m = o->m;
315 n_f0 = o->f0;
316 n_s0 = o->s0;
317 n_m0 = o->m0;
320 void tr_ta(char **args)
322 int i;
323 char *s;
324 for (i = 0; i < NARGS && args[i]; i++) {
325 env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm');
326 s = args[i][0] ? strchr(args[i], '\0') - 1 : "";
327 env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L';
331 static int tab_idx(int pos)
333 int i;
334 for (i = 0; i < LEN(env->tabs); i++)
335 if (env->tabs[i] > pos)
336 return i;
337 return -1;
340 int tab_next(int pos)
342 int i = tab_idx(pos);
343 return i >= 0 ? env->tabs[i] : pos;
346 int tab_type(int pos)
348 int i = tab_idx(pos);
349 return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L';
352 /* number register format (.af) */
353 #define NF_LSH 8 /* number format length shifts */
354 #define NF_FMT 0x00ff /* number format mask */
356 /* the format of a number register (returns a static buffer) */
357 char *num_getfmt(int id)
359 static char fmtbuf[128];
360 char *s = fmtbuf;
361 int i;
362 if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') {
363 *s++ = '0';
364 i = nregs_fmt[id] >> NF_LSH;
365 while (i-- > 1)
366 *s++ = '0';
367 } else {
368 *s++ = nregs_fmt[id] & NF_FMT;
370 *s = '\0';
371 return fmtbuf;
374 void num_setfmt(int id, char *s)
376 int i = 0;
377 if (strchr("iIaA", s[0])) {
378 nregs_fmt[id] = s[0];
379 } else {
380 while (isdigit(s[i]))
381 i++;
382 nregs_fmt[id] = '0' | (i << NF_LSH);
386 static void nf_reverse(char *s)
388 char r[128];
389 int i, l;
390 strcpy(r, s);
391 l = strlen(r);
392 for (i = 0; i < l; i++)
393 s[i] = r[l - i - 1];
396 static void nf_roman(char *s, int n, char *I, char *V)
398 int i;
399 if (!n)
400 return;
401 if (n % 5 == 4) {
402 *s++ = n % 10 == 9 ? I[1] : V[0];
403 *s++ = I[0];
404 } else {
405 for (i = 0; i < n % 5; i++)
406 *s++ = I[0];
407 if (n % 10 >= 5)
408 *s++ = V[0];
410 *s = '\0';
411 nf_roman(s, n / 10, I + 1, V + 1);
414 static void nf_alpha(char *s, int n, int a)
416 while (n) {
417 *s++ = a + ((n - 1) % 26);
418 n /= 26;
420 *s = '\0';
423 /* returns nonzero on failure */
424 static int num_fmt(char *s, int n, int fmt)
426 int type = fmt & NF_FMT;
427 int len;
428 if (n < 0) {
429 n = -n;
430 *s++ = '-';
432 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
433 if (type == 'i')
434 nf_roman(s, n, "ixcmz", "vldw");
435 else
436 nf_roman(s, n, "IXCMZ", "VLDW");
437 nf_reverse(s);
438 return 0;
440 if ((type == 'a' || type == 'A') && n > 0) {
441 nf_alpha(s, n, type);
442 nf_reverse(s);
443 return 0;
445 if (type == '0') {
446 sprintf(s, "%d", n);
447 len = strlen(s);
448 while (len++ < fmt >> NF_LSH)
449 *s++ = '0';
450 sprintf(s, "%d", n);
451 return 0;
453 return 1;