ref: 44ab1b978f5b083dd22c54d3c769192b0790522d
dir: /reg.c/
#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "roff.h" #define NENVS 64 /* number of environment registers */ struct env { int eregs[NENVS]; /* environment-specific number registers */ int tabs[NTABS]; /* tab stops */ char tabs_type[NTABS]; /* type of tabs: L, C, R */ struct adj *adj; /* per environment line buffer */ char tc[GNLEN]; /* tab character (.tc) */ char lc[GNLEN]; /* leader character (.lc) */ char hc[GNLEN]; /* hyphenation character (.hc) */ char mc[GNLEN]; /* margin character (.mc) */ }; static int nregs[NREGS2]; /* global number registers */ static int nregs_inc[NREGS2]; /* number register auto-increment size */ static int nregs_fmt[NREGS2]; /* number register format */ static char *sregs[NREGS2]; /* global string registers */ static void *sregs_dat[NREGS2]; /* builtin function data */ static struct env *envs[NREGS2];/* environments */ static struct env *env; /* current enviroment */ static int env_id; /* current environment id */ static int eregs_idx[NREGS2]; /* register environment index in eregs[] */ static char *eregs[] = { /* environment-specific number registers */ "ln", ".f", ".i", ".j", ".l", ".L", ".nI", ".nm", ".nM", ".nn", ".nS", ".m", ".s", ".u", ".v", ".it", ".itn", ".mc", ".mcn", "\0c", "\0f", "\0h", "\0i", "\0l", "\0L", "\0n", "\0m", "\0p", "\0s", "\0t", "\0T", "\0v", }; /* return the address of a number register */ int *nreg(int id) { if (eregs_idx[id]) return &env->eregs[eregs_idx[id]]; return &nregs[id]; } static int num_fmt(char *s, int n, int fmt); /* the contents of a number register (returns a static buffer) */ char *num_str(int id) { static char numbuf[128]; numbuf[0] = '\0'; switch (id) { case REG('.', 'b'): sprintf(numbuf, "%d", dev_getbd(n_f)); break; case REG('.', 'c'): sprintf(numbuf, "%d", in_lnum()); break; case REG('.', 'k'): sprintf(numbuf, "%d", f_hpos()); break; case REG('.', 'm'): sprintf(numbuf, "#%02x%02x%02x", CLR_R(n_m), CLR_G(n_m), CLR_B(n_m)); break; case REG('.', 't'): sprintf(numbuf, "%d", f_nexttrap()); break; case REG('.', 'z'): if (f_divreg() >= 0) sprintf(numbuf, "%s", map_name(f_divreg())); break; case REG('.', 'F'): sprintf(numbuf, "%s", in_filename()); break; case REG('.', '$'): sprintf(numbuf, "%d", in_nargs()); break; case REG('y', 'r'): sprintf(numbuf, "%02d", nregs[id]); break; default: if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id])) sprintf(numbuf, "%d", *nreg(id)); } return numbuf; } void num_set(int id, int val) { *nreg(id) = val; } void num_inc(int id, int val) { nregs_inc[id] = val; } void num_del(int id) { *nreg(id) = 0; nregs_inc[id] = 0; nregs_fmt[id] = 0; } int num_get(int id, int inc) { if (inc) *nreg(id) += inc > 0 ? nregs_inc[id] : -nregs_inc[id]; return *nreg(id); } void str_set(int id, char *s) { int len = strlen(s) + 1; if (sregs[id]) free(sregs[id]); sregs[id] = malloc(len); memcpy(sregs[id], s, len); sregs_dat[id] = NULL; } char *str_get(int id) { return sregs[id]; } void *str_dget(int id) { return sregs_dat[id]; } void str_dset(int id, void *d) { sregs_dat[id] = d; } void str_rm(int id) { if (sregs[id]) free(sregs[id]); sregs[id] = NULL; sregs_dat[id] = NULL; } void str_rn(int src, int dst) { str_rm(dst); sregs[dst] = sregs[src]; sregs_dat[dst] = sregs_dat[src]; sregs[src] = NULL; sregs_dat[src] = NULL; } static struct env *env_alloc(void) { struct env *env = malloc(sizeof(*env)); memset(env, 0, sizeof(*env)); env->adj = adj_alloc(); return env; } static void env_free(struct env *env) { adj_free(env->adj); free(env); } static void env_set(int id) { int i; env = envs[id]; env_id = id; if (!env) { envs[id] = env_alloc(); env = envs[id]; n_f = 1; n_i = 0; n_j = AD_B; n_l = SC_IN * 65 / 10; n_L = 1; n_s = 10; n_u = 1; n_v = 12 * SC_PT; n_s0 = n_s; n_f0 = n_f; n_na = 0; n_lt = SC_IN * 65 / 10; n_hy = 1; n_ss = 12; n_nM = 1; n_nS = 1; strcpy(env->hc, "\\%"); strcpy(env->lc, "."); adj_ll(env->adj, n_l); adj_in(env->adj, n_i); for (i = 0; i < NTABS; i++) env->tabs[i] = i * SC_IN / 2; } } static void init_time(void) { time_t t = time(NULL); struct tm *tm = localtime(&t); nregs[REG('d', 'w')] = tm->tm_wday + 1; nregs[REG('d', 'y')] = tm->tm_mday; nregs[REG('m', 'o')] = tm->tm_mon + 1; nregs[REG('y', 'r')] = tm->tm_year % 100; } void env_init(void) { int i; init_time(); for (i = 0; i < LEN(eregs); i++) eregs_idx[map(eregs[i])] = i + 1; env_set(0); } void env_done(void) { int i; for (i = 0; i < LEN(envs); i++) if (envs[i]) env_free(envs[i]); } static int oenv[NPREV]; /* environment stack */ static int nenv; void tr_ev(char **args) { int id = -1; if (args[1]) id = map(args[1]); else id = nenv ? oenv[--nenv] : -1; if (id < 0) return; if (args[1] && env && nenv < NPREV) oenv[nenv++] = env_id; env_set(id); } struct adj *env_adj(void) { return env->adj; } char *env_hc(void) { return env->hc; } char *env_mc(void) { return env->mc; } char *env_tc(void) { return env->tc; } char *env_lc(void) { return env->lc; } /* saving and restoring registers around diverted lines */ struct odiv { int f, s, m, f0, s0, m0; }; static struct odiv odivs[NPREV]; /* state before diverted text */ static int nodivs; /* begin outputting diverted line */ void odiv_beg(void) { struct odiv *o = &odivs[nodivs++]; o->f = n_f; o->s = n_s; o->m = n_m; o->f0 = n_f0; o->s0 = n_s0; o->m0 = n_m0; } /* end outputting diverted line */ void odiv_end(void) { struct odiv *o = &odivs[--nodivs]; n_f = o->f; n_s = o->s; n_m = o->m; n_f0 = o->f0; n_s0 = o->s0; n_m0 = o->m0; } void tr_ta(char **args) { int i; char *s; for (i = 0; i < NARGS && args[i]; i++) { env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm'); s = args[i][0] ? strchr(args[i], '\0') - 1 : ""; env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L'; } } static int tab_idx(int pos) { int i; for (i = 0; i < LEN(env->tabs); i++) if (env->tabs[i] > pos) return i; return -1; } int tab_next(int pos) { int i = tab_idx(pos); return i >= 0 ? env->tabs[i] : pos; } int tab_type(int pos) { int i = tab_idx(pos); return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L'; } /* number register format (.af) */ #define NF_LSH 8 /* number format length shifts */ #define NF_FMT 0x00ff /* number format mask */ /* the format of a number register (returns a static buffer) */ char *num_getfmt(int id) { static char fmtbuf[128]; char *s = fmtbuf; int i; if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') { *s++ = '0'; i = nregs_fmt[id] >> NF_LSH; while (i-- > 1) *s++ = '0'; } else { *s++ = nregs_fmt[id] & NF_FMT; } *s = '\0'; return fmtbuf; } void num_setfmt(int id, char *s) { int i = 0; if (strchr("iIaA", s[0])) { nregs_fmt[id] = s[0]; } else { while (isdigit(s[i])) i++; nregs_fmt[id] = '0' | (i << NF_LSH); } } static void nf_reverse(char *s) { char r[128]; int i, l; strcpy(r, s); l = strlen(r); for (i = 0; i < l; i++) s[i] = r[l - i - 1]; } static void nf_roman(char *s, int n, char *I, char *V) { int i; if (!n) return; if (n % 5 == 4) { *s++ = n % 10 == 9 ? I[1] : V[0]; *s++ = I[0]; } else { for (i = 0; i < n % 5; i++) *s++ = I[0]; if (n % 10 >= 5) *s++ = V[0]; } *s = '\0'; nf_roman(s, n / 10, I + 1, V + 1); } static void nf_alpha(char *s, int n, int a) { while (n) { *s++ = a + ((n - 1) % 26); n /= 26; } *s = '\0'; } /* returns nonzero on failure */ static int num_fmt(char *s, int n, int fmt) { int type = fmt & NF_FMT; int len; if (n < 0) { n = -n; *s++ = '-'; } if ((type == 'i' || type == 'I') && n > 0 && n < 40000) { if (type == 'i') nf_roman(s, n, "ixcmz", "vldw"); else nf_roman(s, n, "IXCMZ", "VLDW"); nf_reverse(s); return 0; } if ((type == 'a' || type == 'A') && n > 0) { nf_alpha(s, n, type); nf_reverse(s); return 0; } if (type == '0') { sprintf(s, "%d", n); len = strlen(s); while (len++ < fmt >> NF_LSH) *s++ = '0'; sprintf(s, "%d", n); return 0; } return 1; }