9 #define NENVS 64 /* number of environment registers */
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
[NREGS2
]; /* global number registers */
23 static int nregs_inc
[NREGS2
]; /* number register auto-increment size */
24 static int nregs_fmt
[NREGS2
]; /* number register format */
25 static char *sregs
[NREGS2
]; /* global string registers */
26 static void *sregs_dat
[NREGS2
]; /* builtin function data */
27 static struct env
*envs
[NREGS2
];/* environments */
28 static struct env
*env
; /* current enviroment */
29 static int env_id
; /* current environment id */
30 static int eregs_idx
[NREGS2
]; /* 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 "\0c", "\0f", "\0h", "\0i", "\0l",
38 "\0L", "\0n", "\0m", "\0p", "\0s",
42 /* return the address of a number register */
46 return &env
->eregs
[eregs_idx
[id
]];
50 static int num_fmt(char *s
, int n
, int fmt
);
52 /* the contents of a number register (returns a static buffer) */
55 static char numbuf
[128];
59 sprintf(numbuf
, "%d", dev_getbd(n_f
));
62 sprintf(numbuf
, "%d", in_lnum());
65 sprintf(numbuf
, "%d", f_hpos());
68 sprintf(numbuf
, "#%02x%02x%02x", CLR_R(n_m
), CLR_G(n_m
), CLR_B(n_m
));
71 sprintf(numbuf
, "%d", f_nexttrap());
75 sprintf(numbuf
, "%s", map_name(f_divreg()));
78 sprintf(numbuf
, "%s", in_filename());
81 sprintf(numbuf
, "%d", in_nargs());
84 sprintf(numbuf
, "%02d", nregs
[id
]);
87 if (!nregs_fmt
[id
] || num_fmt(numbuf
, *nreg(id
), nregs_fmt
[id
]))
88 sprintf(numbuf
, "%d", *nreg(id
));
93 void num_set(int id
, int val
)
98 void num_inc(int id
, int val
)
110 int num_get(int id
, int inc
)
113 *nreg(id
) += inc
> 0 ? nregs_inc
[id
] : -nregs_inc
[id
];
117 void str_set(int id
, char *s
)
119 int len
= strlen(s
) + 1;
122 sregs
[id
] = malloc(len
);
123 memcpy(sregs
[id
], s
, len
);
124 sregs_dat
[id
] = NULL
;
127 char *str_get(int id
)
132 void *str_dget(int id
)
134 return sregs_dat
[id
];
137 void str_dset(int id
, void *d
)
147 sregs_dat
[id
] = NULL
;
150 void str_rn(int src
, int dst
)
153 sregs
[dst
] = sregs
[src
];
154 sregs_dat
[dst
] = sregs_dat
[src
];
156 sregs_dat
[src
] = NULL
;
159 static struct env
*env_alloc(void)
161 struct env
*env
= malloc(sizeof(*env
));
162 memset(env
, 0, sizeof(*env
));
163 env
->adj
= adj_alloc();
167 static void env_free(struct env
*env
)
173 static void env_set(int id
)
179 envs
[id
] = env_alloc();
184 n_l
= SC_IN
* 65 / 10;
192 n_lt
= SC_IN
* 65 / 10;
197 strcpy(env
->hc
, "\\%");
198 strcpy(env
->lc
, ".");
199 adj_ll(env
->adj
, n_l
);
200 adj_in(env
->adj
, n_i
);
201 for (i
= 0; i
< NTABS
; i
++)
202 env
->tabs
[i
] = i
* SC_IN
/ 2;
206 static void init_time(void)
208 time_t t
= time(NULL
);
209 struct tm
*tm
= localtime(&t
);
210 nregs
[REG('d', 'w')] = tm
->tm_wday
+ 1;
211 nregs
[REG('d', 'y')] = tm
->tm_mday
;
212 nregs
[REG('m', 'o')] = tm
->tm_mon
+ 1;
213 nregs
[REG('y', 'r')] = tm
->tm_year
% 100;
220 for (i
= 0; i
< LEN(eregs
); i
++)
221 eregs_idx
[map(eregs
[i
])] = i
+ 1;
228 for (i
= 0; i
< LEN(envs
); i
++)
233 static int oenv
[NPREV
]; /* environment stack */
236 void tr_ev(char **args
)
242 id
= nenv
? oenv
[--nenv
] : -1;
245 if (args
[1] && env
&& nenv
< NPREV
)
246 oenv
[nenv
++] = env_id
;
250 struct adj
*env_adj(void)
275 /* saving and restoring registers around diverted lines */
277 int f
, s
, m
, f0
, s0
, m0
;
280 static struct odiv odivs
[NPREV
]; /* state before diverted text */
283 /* begin outputting diverted line */
286 struct odiv
*o
= &odivs
[nodivs
++];
295 /* end outputting diverted line */
298 struct odiv
*o
= &odivs
[--nodivs
];
307 void tr_ta(char **args
)
311 for (i
= 0; i
< NARGS
&& args
[i
]; i
++) {
312 env
->tabs
[i
] = eval_re(args
[i
], i
> 0 ? env
->tabs
[i
- 1] : 0, 'm');
313 s
= args
[i
][0] ? strchr(args
[i
], '\0') - 1 : "";
314 env
->tabs_type
[i
] = strchr("LRC", *s
) ? *s
: 'L';
318 static int tab_idx(int pos
)
321 for (i
= 0; i
< LEN(env
->tabs
); i
++)
322 if (env
->tabs
[i
] > pos
)
327 int tab_next(int pos
)
329 int i
= tab_idx(pos
);
330 return i
>= 0 ? env
->tabs
[i
] : pos
;
333 int tab_type(int pos
)
335 int i
= tab_idx(pos
);
336 return i
>= 0 && env
->tabs_type
[i
] ? env
->tabs_type
[i
] : 'L';
339 /* number register format (.af) */
340 #define NF_LSH 8 /* number format length shifts */
341 #define NF_FMT 0x00ff /* number format mask */
343 /* the format of a number register (returns a static buffer) */
344 char *num_getfmt(int id
)
346 static char fmtbuf
[128];
349 if (!nregs_fmt
[id
] || (nregs_fmt
[id
] & NF_FMT
) == '0') {
351 i
= nregs_fmt
[id
] >> NF_LSH
;
355 *s
++ = nregs_fmt
[id
] & NF_FMT
;
361 void num_setfmt(int id
, char *s
)
364 if (strchr("iIaA", s
[0])) {
365 nregs_fmt
[id
] = s
[0];
367 while (isdigit(s
[i
]))
369 nregs_fmt
[id
] = '0' | (i
<< NF_LSH
);
373 static void nf_reverse(char *s
)
379 for (i
= 0; i
< l
; i
++)
383 static void nf_roman(char *s
, int n
, char *I
, char *V
)
389 *s
++ = n
% 10 == 9 ? I
[1] : V
[0];
392 for (i
= 0; i
< n
% 5; i
++)
398 nf_roman(s
, n
/ 10, I
+ 1, V
+ 1);
401 static void nf_alpha(char *s
, int n
, int a
)
404 *s
++ = a
+ ((n
- 1) % 26);
410 /* returns nonzero on failure */
411 static int num_fmt(char *s
, int n
, int fmt
)
413 int type
= fmt
& NF_FMT
;
419 if ((type
== 'i' || type
== 'I') && n
> 0 && n
< 40000) {
421 nf_roman(s
, n
, "ixcmz", "vldw");
423 nf_roman(s
, n
, "IXCMZ", "VLDW");
427 if ((type
== 'a' || type
== 'A') && n
> 0) {
428 nf_alpha(s
, n
, type
);
435 while (len
++ < fmt
>> NF_LSH
)