adj: access n_ll and n_i directly
[neatroff.git] / reg.c
blob994269aaf0027d2e1e94561ab96c98e80896d3a2
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 ".ti", ".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 for (i = 0; i < NTABS; i++)
204 env->tabs[i] = i * SC_IN / 2;
208 static void init_time(void)
210 time_t t = time(NULL);
211 struct tm *tm = localtime(&t);
212 nregs[map("dw")] = tm->tm_wday + 1;
213 nregs[map("dy")] = tm->tm_mday;
214 nregs[map("mo")] = tm->tm_mon + 1;
215 nregs[map("yr")] = tm->tm_year % 100;
218 static void init_globals(void)
220 n_o = SC_IN;
221 n_p = SC_IN * 11;
222 n_lg = 1;
223 n_kn = 0;
226 void env_init(void)
228 int i;
229 init_time();
230 init_globals();
231 for (i = 0; i < LEN(eregs); i++)
232 eregs_idx[map(eregs[i])] = i + 1;
233 env_set(0);
236 void env_done(void)
238 int i;
239 for (i = 0; i < LEN(envs); i++)
240 if (envs[i])
241 env_free(envs[i]);
244 static int oenv[NPREV]; /* environment stack */
245 static int nenv;
247 void tr_ev(char **args)
249 int id = -1;
250 if (args[1])
251 id = map(args[1]);
252 else
253 id = nenv ? oenv[--nenv] : -1;
254 if (id < 0)
255 return;
256 if (args[1] && env && nenv < NPREV)
257 oenv[nenv++] = env_id;
258 env_set(id);
261 struct adj *env_adj(void)
263 return env->adj;
266 char *env_hc(void)
268 return env->hc;
271 char *env_mc(void)
273 return env->mc;
276 char *env_tc(void)
278 return env->tc;
281 char *env_lc(void)
283 return env->lc;
286 /* saving and restoring registers around diverted lines */
287 struct odiv {
288 int f, s, m, f0, s0, m0;
291 static struct odiv odivs[NPREV]; /* state before diverted text */
292 static int nodivs;
294 /* begin outputting diverted line */
295 void odiv_beg(void)
297 struct odiv *o = &odivs[nodivs++];
298 o->f = n_f;
299 o->s = n_s;
300 o->m = n_m;
301 o->f0 = n_f0;
302 o->s0 = n_s0;
303 o->m0 = n_m0;
306 /* end outputting diverted line */
307 void odiv_end(void)
309 struct odiv *o = &odivs[--nodivs];
310 n_f = o->f;
311 n_s = o->s;
312 n_m = o->m;
313 n_f0 = o->f0;
314 n_s0 = o->s0;
315 n_m0 = o->m0;
318 void tr_ta(char **args)
320 int i;
321 char *s;
322 for (i = 0; i < NARGS && args[i]; i++) {
323 env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm');
324 s = args[i][0] ? strchr(args[i], '\0') - 1 : "";
325 env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L';
329 static int tab_idx(int pos)
331 int i;
332 for (i = 0; i < LEN(env->tabs); i++)
333 if (env->tabs[i] > pos)
334 return i;
335 return -1;
338 int tab_next(int pos)
340 int i = tab_idx(pos);
341 return i >= 0 ? env->tabs[i] : pos;
344 int tab_type(int pos)
346 int i = tab_idx(pos);
347 return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L';
350 /* number register format (.af) */
351 #define NF_LSH 8 /* number format length shifts */
352 #define NF_FMT 0x00ff /* number format mask */
354 /* the format of a number register (returns a static buffer) */
355 char *num_getfmt(int id)
357 static char fmtbuf[128];
358 char *s = fmtbuf;
359 int i;
360 if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') {
361 *s++ = '0';
362 i = nregs_fmt[id] >> NF_LSH;
363 while (i-- > 1)
364 *s++ = '0';
365 } else {
366 *s++ = nregs_fmt[id] & NF_FMT;
368 *s = '\0';
369 return fmtbuf;
372 void num_setfmt(int id, char *s)
374 int i = 0;
375 if (strchr("iIaA", s[0])) {
376 nregs_fmt[id] = s[0];
377 } else {
378 while (isdigit(s[i]))
379 i++;
380 nregs_fmt[id] = '0' | (i << NF_LSH);
384 static void nf_reverse(char *s)
386 char r[128];
387 int i, l;
388 strcpy(r, s);
389 l = strlen(r);
390 for (i = 0; i < l; i++)
391 s[i] = r[l - i - 1];
394 static void nf_roman(char *s, int n, char *I, char *V)
396 int i;
397 if (!n)
398 return;
399 if (n % 5 == 4) {
400 *s++ = n % 10 == 9 ? I[1] : V[0];
401 *s++ = I[0];
402 } else {
403 for (i = 0; i < n % 5; i++)
404 *s++ = I[0];
405 if (n % 10 >= 5)
406 *s++ = V[0];
408 *s = '\0';
409 nf_roman(s, n / 10, I + 1, V + 1);
412 static void nf_alpha(char *s, int n, int a)
414 while (n) {
415 *s++ = a + ((n - 1) % 26);
416 n /= 26;
418 *s = '\0';
421 /* returns nonzero on failure */
422 static int num_fmt(char *s, int n, int fmt)
424 int type = fmt & NF_FMT;
425 int len;
426 if (n < 0) {
427 n = -n;
428 *s++ = '-';
430 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
431 if (type == 'i')
432 nf_roman(s, n, "ixcmz", "vldw");
433 else
434 nf_roman(s, n, "IXCMZ", "VLDW");
435 nf_reverse(s);
436 return 0;
438 if ((type == 'a' || type == 'A') && n > 0) {
439 nf_alpha(s, n, type);
440 nf_reverse(s);
441 return 0;
443 if (type == '0') {
444 sprintf(s, "%d", n);
445 len = strlen(s);
446 while (len++ < fmt >> NF_LSH)
447 *s++ = '0';
448 sprintf(s, "%d", n);
449 return 0;
451 return 1;