tr: add .ochar to define a characters for a font
[neatroff.git] / reg.c
blob7131e619fb06ac05c5bf8e6549e0f235d206c8c4
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.h>
7 #include "roff.h"
9 #define NENVS 64 /* number of environment registers */
11 struct env {
12 int eregs[NENVS]; /* environment-specific number registers */
13 int tabs[NTABS]; /* tab stops */
14 char tabs_type[NTABS]; /* type of tabs: L, C, R */
15 struct adj *adj; /* per environment line buffer */
16 char tc[GNLEN]; /* tab character (.tc) */
17 char lc[GNLEN]; /* leader character (.lc) */
18 char hc[GNLEN]; /* hyphenation character (.hc) */
19 char mc[GNLEN]; /* margin character (.mc) */
22 static int nregs[NREGS]; /* global number registers */
23 static int nregs_inc[NREGS]; /* number register auto-increment size */
24 static int nregs_fmt[NREGS]; /* number register format */
25 static char *sregs[NREGS]; /* global string registers */
26 static void *sregs_dat[NREGS]; /* builtin function data */
27 static struct env *envs[NREGS];/* environments */
28 static struct env *env; /* current enviroment */
29 static int env_id; /* current environment id */
30 static int eregs_idx[NREGS]; /* register environment index in eregs[] */
32 static char *eregs[] = { /* environment-specific number registers */
33 "ln", ".f", ".i", ".j", ".l",
34 ".L", ".nI", ".nm", ".nM", ".nn",
35 ".nS", ".m", ".s", ".u", ".v",
36 ".it", ".itn", ".mc", ".mcn",
37 ".ce", ".f0", ".hy", ".i0", ".l0",
38 ".L0", ".m0", ".n0", ".s0", ".ss",
39 ".lt", ".lt0", ".v0",
42 /* return the address of a number register */
43 int *nreg(int id)
45 if (eregs_idx[id])
46 return &env->eregs[eregs_idx[id]];
47 return &nregs[id];
50 static int num_fmt(char *s, int n, int fmt);
52 /* the contents of a number register (returns a static buffer) */
53 char *num_str(int id)
55 static char numbuf[128];
56 char *s = map_name(id);
57 numbuf[0] = '\0';
58 if (s[0] == '.' && !s[2]) {
59 switch (s[1]) {
60 case 'b':
61 sprintf(numbuf, "%d", dev_getbd(n_f));
62 return numbuf;
63 case 'c':
64 sprintf(numbuf, "%d", in_lnum());
65 return numbuf;
66 case 'k':
67 sprintf(numbuf, "%d", f_hpos());
68 return numbuf;
69 case 'm':
70 sprintf(numbuf, "#%02x%02x%02x", CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
71 return numbuf;
72 case 't':
73 sprintf(numbuf, "%d", f_nexttrap());
74 return numbuf;
75 case 'z':
76 if (f_divreg() >= 0)
77 sprintf(numbuf, "%s", map_name(f_divreg()));
78 return numbuf;
79 case 'F':
80 sprintf(numbuf, "%s", in_filename());
81 return numbuf;
82 case '$':
83 sprintf(numbuf, "%d", in_nargs());
84 return numbuf;
87 if (id == map("yr")) {
88 sprintf(numbuf, "%02d", nregs[id]);
89 return numbuf;
91 if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
92 sprintf(numbuf, "%d", *nreg(id));
93 return numbuf;
96 void num_set(int id, int val)
98 *nreg(id) = val;
101 void num_inc(int id, int val)
103 nregs_inc[id] = val;
106 void num_del(int id)
108 *nreg(id) = 0;
109 nregs_inc[id] = 0;
110 nregs_fmt[id] = 0;
113 int num_get(int id, int inc)
115 if (inc)
116 *nreg(id) += inc > 0 ? nregs_inc[id] : -nregs_inc[id];
117 return *nreg(id);
120 void str_set(int id, char *s)
122 int len = strlen(s) + 1;
123 if (sregs[id])
124 free(sregs[id]);
125 sregs[id] = malloc(len);
126 memcpy(sregs[id], s, len);
127 sregs_dat[id] = NULL;
130 char *str_get(int id)
132 return sregs[id];
135 void *str_dget(int id)
137 return sregs_dat[id];
140 void str_dset(int id, void *d)
142 sregs_dat[id] = d;
145 void str_rm(int id)
147 if (sregs[id])
148 free(sregs[id]);
149 sregs[id] = NULL;
150 sregs_dat[id] = NULL;
153 void str_rn(int src, int dst)
155 str_rm(dst);
156 sregs[dst] = sregs[src];
157 sregs_dat[dst] = sregs_dat[src];
158 sregs[src] = NULL;
159 sregs_dat[src] = NULL;
162 static struct env *env_alloc(void)
164 struct env *env = malloc(sizeof(*env));
165 memset(env, 0, sizeof(*env));
166 env->adj = adj_alloc();
167 return env;
170 static void env_free(struct env *env)
172 adj_free(env->adj);
173 free(env);
176 static void env_set(int id)
178 int i;
179 env = envs[id];
180 env_id = id;
181 if (!env) {
182 envs[id] = env_alloc();
183 env = envs[id];
184 n_f = 1;
185 n_i = 0;
186 n_j = AD_B;
187 n_l = SC_IN * 65 / 10;
188 n_L = 1;
189 n_s = 10;
190 n_u = 1;
191 n_v = 12 * SC_PT;
192 n_s0 = n_s;
193 n_f0 = n_f;
194 n_na = 0;
195 n_lt = SC_IN * 65 / 10;
196 n_hy = 1;
197 n_ss = 12;
198 n_nM = 1;
199 n_nS = 1;
200 strcpy(env->hc, "\\%");
201 strcpy(env->lc, ".");
202 adj_ll(env->adj, n_l);
203 adj_in(env->adj, n_i);
204 for (i = 0; i < NTABS; i++)
205 env->tabs[i] = i * SC_IN / 2;
209 static void init_time(void)
211 time_t t = time(NULL);
212 struct tm *tm = localtime(&t);
213 nregs[map("dw")] = tm->tm_wday + 1;
214 nregs[map("dy")] = tm->tm_mday;
215 nregs[map("mo")] = tm->tm_mon + 1;
216 nregs[map("yr")] = tm->tm_year % 100;
219 void env_init(void)
221 int i;
222 init_time();
223 for (i = 0; i < LEN(eregs); i++)
224 eregs_idx[map(eregs[i])] = i + 1;
225 env_set(0);
228 void env_done(void)
230 int i;
231 for (i = 0; i < LEN(envs); i++)
232 if (envs[i])
233 env_free(envs[i]);
236 static int oenv[NPREV]; /* environment stack */
237 static int nenv;
239 void tr_ev(char **args)
241 int id = -1;
242 if (args[1])
243 id = map(args[1]);
244 else
245 id = nenv ? oenv[--nenv] : -1;
246 if (id < 0)
247 return;
248 if (args[1] && env && nenv < NPREV)
249 oenv[nenv++] = env_id;
250 env_set(id);
253 struct adj *env_adj(void)
255 return env->adj;
258 char *env_hc(void)
260 return env->hc;
263 char *env_mc(void)
265 return env->mc;
268 char *env_tc(void)
270 return env->tc;
273 char *env_lc(void)
275 return env->lc;
278 /* saving and restoring registers around diverted lines */
279 struct odiv {
280 int f, s, m, f0, s0, m0;
283 static struct odiv odivs[NPREV]; /* state before diverted text */
284 static int nodivs;
286 /* begin outputting diverted line */
287 void odiv_beg(void)
289 struct odiv *o = &odivs[nodivs++];
290 o->f = n_f;
291 o->s = n_s;
292 o->m = n_m;
293 o->f0 = n_f0;
294 o->s0 = n_s0;
295 o->m0 = n_m0;
298 /* end outputting diverted line */
299 void odiv_end(void)
301 struct odiv *o = &odivs[--nodivs];
302 n_f = o->f;
303 n_s = o->s;
304 n_m = o->m;
305 n_f0 = o->f0;
306 n_s0 = o->s0;
307 n_m0 = o->m0;
310 void tr_ta(char **args)
312 int i;
313 char *s;
314 for (i = 0; i < NARGS && args[i]; i++) {
315 env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm');
316 s = args[i][0] ? strchr(args[i], '\0') - 1 : "";
317 env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L';
321 static int tab_idx(int pos)
323 int i;
324 for (i = 0; i < LEN(env->tabs); i++)
325 if (env->tabs[i] > pos)
326 return i;
327 return -1;
330 int tab_next(int pos)
332 int i = tab_idx(pos);
333 return i >= 0 ? env->tabs[i] : pos;
336 int tab_type(int pos)
338 int i = tab_idx(pos);
339 return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L';
342 /* number register format (.af) */
343 #define NF_LSH 8 /* number format length shifts */
344 #define NF_FMT 0x00ff /* number format mask */
346 /* the format of a number register (returns a static buffer) */
347 char *num_getfmt(int id)
349 static char fmtbuf[128];
350 char *s = fmtbuf;
351 int i;
352 if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') {
353 *s++ = '0';
354 i = nregs_fmt[id] >> NF_LSH;
355 while (i-- > 1)
356 *s++ = '0';
357 } else {
358 *s++ = nregs_fmt[id] & NF_FMT;
360 *s = '\0';
361 return fmtbuf;
364 void num_setfmt(int id, char *s)
366 int i = 0;
367 if (strchr("iIaA", s[0])) {
368 nregs_fmt[id] = s[0];
369 } else {
370 while (isdigit(s[i]))
371 i++;
372 nregs_fmt[id] = '0' | (i << NF_LSH);
376 static void nf_reverse(char *s)
378 char r[128];
379 int i, l;
380 strcpy(r, s);
381 l = strlen(r);
382 for (i = 0; i < l; i++)
383 s[i] = r[l - i - 1];
386 static void nf_roman(char *s, int n, char *I, char *V)
388 int i;
389 if (!n)
390 return;
391 if (n % 5 == 4) {
392 *s++ = n % 10 == 9 ? I[1] : V[0];
393 *s++ = I[0];
394 } else {
395 for (i = 0; i < n % 5; i++)
396 *s++ = I[0];
397 if (n % 10 >= 5)
398 *s++ = V[0];
400 *s = '\0';
401 nf_roman(s, n / 10, I + 1, V + 1);
404 static void nf_alpha(char *s, int n, int a)
406 while (n) {
407 *s++ = a + ((n - 1) % 26);
408 n /= 26;
410 *s = '\0';
413 /* returns nonzero on failure */
414 static int num_fmt(char *s, int n, int fmt)
416 int type = fmt & NF_FMT;
417 int len;
418 if (n < 0) {
419 n = -n;
420 *s++ = '-';
422 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
423 if (type == 'i')
424 nf_roman(s, n, "ixcmz", "vldw");
425 else
426 nf_roman(s, n, "IXCMZ", "VLDW");
427 nf_reverse(s);
428 return 0;
430 if ((type == 'a' || type == 'A') && n > 0) {
431 nf_alpha(s, n, type);
432 nf_reverse(s);
433 return 0;
435 if (type == '0') {
436 sprintf(s, "%d", n);
437 len = strlen(s);
438 while (len++ < fmt >> NF_LSH)
439 *s++ = '0';
440 sprintf(s, "%d", n);
441 return 0;
443 return 1;