fmt: consider the whole paragraphs before traps
[neatroff.git] / reg.c
blobe947573d0e2b3e977f2867da1b7a0d62e560ec36
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 fmt *fmt; /* per environment line formatting 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", ".hyp", ".i0", ".l0",
39 ".L0", ".m0", ".n0", ".s0", ".ss", ".ssh", ".sss",
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",
72 CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
73 return numbuf;
74 case 't':
75 sprintf(numbuf, "%d", f_nexttrap());
76 return numbuf;
77 case 'z':
78 if (f_divreg() >= 0)
79 sprintf(numbuf, "%s", map_name(f_divreg()));
80 return numbuf;
81 case 'F':
82 sprintf(numbuf, "%s", in_filename());
83 return numbuf;
84 case '$':
85 sprintf(numbuf, "%d", in_nargs());
86 return numbuf;
89 if (s[0] == '.' && !strcmp(".neat", s))
90 return "1";
91 if (id == map("yr")) {
92 sprintf(numbuf, "%02d", nregs[id]);
93 return numbuf;
95 if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
96 sprintf(numbuf, "%d", *nreg(id));
97 return numbuf;
100 void num_set(int id, int val)
102 *nreg(id) = val;
105 void num_inc(int id, int val)
107 nregs_inc[id] = val;
110 void num_del(int id)
112 *nreg(id) = 0;
113 nregs_inc[id] = 0;
114 nregs_fmt[id] = 0;
117 int num_get(int id, int inc)
119 if (inc)
120 *nreg(id) += inc > 0 ? nregs_inc[id] : -nregs_inc[id];
121 return *nreg(id);
124 void str_set(int id, char *s)
126 int len = strlen(s) + 1;
127 if (sregs[id])
128 free(sregs[id]);
129 sregs[id] = malloc(len);
130 memcpy(sregs[id], s, len);
131 sregs_dat[id] = NULL;
134 char *str_get(int id)
136 return sregs[id];
139 void *str_dget(int id)
141 return sregs_dat[id];
144 void str_dset(int id, void *d)
146 sregs_dat[id] = d;
149 void str_rm(int id)
151 if (sregs[id])
152 free(sregs[id]);
153 sregs[id] = NULL;
154 sregs_dat[id] = NULL;
157 void str_rn(int src, int dst)
159 str_rm(dst);
160 sregs[dst] = sregs[src];
161 sregs_dat[dst] = sregs_dat[src];
162 sregs[src] = NULL;
163 sregs_dat[src] = NULL;
166 static struct env *env_alloc(void)
168 struct env *env = malloc(sizeof(*env));
169 memset(env, 0, sizeof(*env));
170 env->fmt = fmt_alloc();
171 return env;
174 static void env_free(struct env *env)
176 fmt_free(env->fmt);
177 free(env);
180 static void env_set(int id)
182 int i;
183 env = envs[id];
184 env_id = id;
185 if (!env) {
186 envs[id] = env_alloc();
187 env = envs[id];
188 n_f = 1;
189 n_i = 0;
190 n_j = AD_B;
191 n_l = SC_IN * 65 / 10;
192 n_L = 1;
193 n_s = 10;
194 n_u = 1;
195 n_v = 12 * SC_PT;
196 n_s0 = n_s;
197 n_f0 = n_f;
198 n_na = 0;
199 n_lt = SC_IN * 65 / 10;
200 n_hy = 1;
201 n_ss = 12;
202 n_sss = 12;
203 n_nM = 1;
204 n_nS = 1;
205 strcpy(env->hc, "\\%");
206 strcpy(env->lc, ".");
207 for (i = 0; i < NTABS; i++)
208 env->tabs[i] = i * SC_IN / 2;
212 static void init_time(void)
214 time_t t = time(NULL);
215 struct tm *tm = localtime(&t);
216 nregs[map("dw")] = tm->tm_wday + 1;
217 nregs[map("dy")] = tm->tm_mday;
218 nregs[map("mo")] = tm->tm_mon + 1;
219 nregs[map("yr")] = tm->tm_year % 100;
222 static void init_globals(void)
224 n_o = SC_IN;
225 n_p = SC_IN * 11;
226 n_lg = 1;
227 n_kn = 0;
230 void env_init(void)
232 int i;
233 init_time();
234 init_globals();
235 for (i = 0; i < LEN(eregs); i++)
236 eregs_idx[map(eregs[i])] = i + 1;
237 env_set(0);
240 void env_done(void)
242 int i;
243 for (i = 0; i < LEN(envs); i++)
244 if (envs[i])
245 env_free(envs[i]);
248 static int oenv[NPREV]; /* environment stack */
249 static int nenv;
251 void tr_ev(char **args)
253 int id = -1;
254 if (args[1])
255 id = map(args[1]);
256 else
257 id = nenv ? oenv[--nenv] : -1;
258 if (id < 0)
259 return;
260 if (args[1] && env && nenv < NPREV)
261 oenv[nenv++] = env_id;
262 env_set(id);
265 struct fmt *env_fmt(void)
267 return env->fmt;
270 char *env_hc(void)
272 return env->hc;
275 char *env_mc(void)
277 return env->mc;
280 char *env_tc(void)
282 return env->tc;
285 char *env_lc(void)
287 return env->lc;
290 /* saving and restoring registers around diverted lines */
291 struct odiv {
292 int f, s, m, f0, s0, m0;
295 static struct odiv odivs[NPREV]; /* state before diverted text */
296 static int nodivs;
298 /* begin outputting diverted line */
299 void odiv_beg(void)
301 struct odiv *o = &odivs[nodivs++];
302 o->f = n_f;
303 o->s = n_s;
304 o->m = n_m;
305 o->f0 = n_f0;
306 o->s0 = n_s0;
307 o->m0 = n_m0;
310 /* end outputting diverted line */
311 void odiv_end(void)
313 struct odiv *o = &odivs[--nodivs];
314 n_f = o->f;
315 n_s = o->s;
316 n_m = o->m;
317 n_f0 = o->f0;
318 n_s0 = o->s0;
319 n_m0 = o->m0;
322 void tr_ta(char **args)
324 int i;
325 char *s;
326 for (i = 0; i < NARGS && args[i]; i++) {
327 env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm');
328 s = args[i][0] ? strchr(args[i], '\0') - 1 : "";
329 env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L';
333 static int tab_idx(int pos)
335 int i;
336 for (i = 0; i < LEN(env->tabs); i++)
337 if (env->tabs[i] > pos)
338 return i;
339 return -1;
342 int tab_next(int pos)
344 int i = tab_idx(pos);
345 return i >= 0 ? env->tabs[i] : pos;
348 int tab_type(int pos)
350 int i = tab_idx(pos);
351 return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L';
354 /* number register format (.af) */
355 #define NF_LSH 8 /* number format length shifts */
356 #define NF_FMT 0x00ff /* number format mask */
358 /* the format of a number register (returns a static buffer) */
359 char *num_getfmt(int id)
361 static char fmtbuf[128];
362 char *s = fmtbuf;
363 int i;
364 if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') {
365 *s++ = '0';
366 i = nregs_fmt[id] >> NF_LSH;
367 while (i-- > 1)
368 *s++ = '0';
369 } else {
370 *s++ = nregs_fmt[id] & NF_FMT;
372 *s = '\0';
373 return fmtbuf;
376 void num_setfmt(int id, char *s)
378 int i = 0;
379 if (strchr("iIaA", s[0])) {
380 nregs_fmt[id] = s[0];
381 } else {
382 while (isdigit(s[i]))
383 i++;
384 nregs_fmt[id] = '0' | (i << NF_LSH);
388 static void nf_reverse(char *s)
390 char r[128];
391 int i, l;
392 strcpy(r, s);
393 l = strlen(r);
394 for (i = 0; i < l; i++)
395 s[i] = r[l - i - 1];
398 static void nf_roman(char *s, int n, char *I, char *V)
400 int i;
401 if (!n)
402 return;
403 if (n % 5 == 4) {
404 *s++ = n % 10 == 9 ? I[1] : V[0];
405 *s++ = I[0];
406 } else {
407 for (i = 0; i < n % 5; i++)
408 *s++ = I[0];
409 if (n % 10 >= 5)
410 *s++ = V[0];
412 *s = '\0';
413 nf_roman(s, n / 10, I + 1, V + 1);
416 static void nf_alpha(char *s, int n, int a)
418 while (n) {
419 *s++ = a + ((n - 1) % 26);
420 n /= 26;
422 *s = '\0';
425 /* returns nonzero on failure */
426 static int num_fmt(char *s, int n, int fmt)
428 int type = fmt & NF_FMT;
429 int len;
430 if (n < 0) {
431 n = -n;
432 *s++ = '-';
434 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
435 if (type == 'i')
436 nf_roman(s, n, "ixcmz", "vldw");
437 else
438 nf_roman(s, n, "IXCMZ", "VLDW");
439 nf_reverse(s);
440 return 0;
442 if ((type == 'a' || type == 'A') && n > 0) {
443 nf_alpha(s, n, type);
444 nf_reverse(s);
445 return 0;
447 if (type == '0') {
448 sprintf(s, "%d", n);
449 len = strlen(s);
450 while (len++ < fmt >> NF_LSH)
451 *s++ = '0';
452 sprintf(s, "%d", n);
453 return 0;
455 return 1;