hyph: drop non-alpha characters for HY_FIRST2 and HY_FINAL2
[neatroff.git] / reg.c
blob86a60e8271bc6210ac869f02354069d4ac579bc9
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[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",
39 "\0t", "\0T", "\0v",
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 numbuf[0] = '\0';
57 switch (id) {
58 case REG('.', 'b'):
59 sprintf(numbuf, "%d", dev_getbd(n_f));
60 break;
61 case REG('.', 'c'):
62 sprintf(numbuf, "%d", in_lnum());
63 break;
64 case REG('.', 'k'):
65 sprintf(numbuf, "%d", f_hpos());
66 break;
67 case REG('.', 'm'):
68 sprintf(numbuf, "#%02x%02x%02x", CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
69 break;
70 case REG('.', 't'):
71 sprintf(numbuf, "%d", f_nexttrap());
72 break;
73 case REG('.', 'z'):
74 if (f_divreg() >= 0)
75 sprintf(numbuf, "%s", map_name(f_divreg()));
76 break;
77 case REG('.', 'F'):
78 sprintf(numbuf, "%s", in_filename());
79 break;
80 case REG('.', '$'):
81 sprintf(numbuf, "%d", in_nargs());
82 break;
83 case REG('y', 'r'):
84 sprintf(numbuf, "%02d", nregs[id]);
85 break;
86 default:
87 if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
88 sprintf(numbuf, "%d", *nreg(id));
90 return numbuf;
93 void num_set(int id, int val)
95 *nreg(id) = val;
98 void num_inc(int id, int val)
100 nregs_inc[id] = val;
103 void num_del(int id)
105 *nreg(id) = 0;
106 nregs_inc[id] = 0;
107 nregs_fmt[id] = 0;
110 int num_get(int id, int inc)
112 if (inc)
113 *nreg(id) += inc > 0 ? nregs_inc[id] : -nregs_inc[id];
114 return *nreg(id);
117 void str_set(int id, char *s)
119 int len = strlen(s) + 1;
120 if (sregs[id])
121 free(sregs[id]);
122 sregs[id] = malloc(len);
123 memcpy(sregs[id], s, len);
124 sregs_dat[id] = NULL;
127 char *str_get(int id)
129 return sregs[id];
132 void *str_dget(int id)
134 return sregs_dat[id];
137 void str_dset(int id, void *d)
139 sregs_dat[id] = d;
142 void str_rm(int id)
144 if (sregs[id])
145 free(sregs[id]);
146 sregs[id] = NULL;
147 sregs_dat[id] = NULL;
150 void str_rn(int src, int dst)
152 str_rm(dst);
153 sregs[dst] = sregs[src];
154 sregs_dat[dst] = sregs_dat[src];
155 sregs[src] = NULL;
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();
164 return env;
167 static void env_free(struct env *env)
169 adj_free(env->adj);
170 free(env);
173 static void env_set(int id)
175 int i;
176 env = envs[id];
177 env_id = id;
178 if (!env) {
179 envs[id] = env_alloc();
180 env = envs[id];
181 n_f = 1;
182 n_i = 0;
183 n_j = AD_B;
184 n_l = SC_IN * 65 / 10;
185 n_L = 1;
186 n_s = 10;
187 n_u = 1;
188 n_v = 12 * SC_PT;
189 n_s0 = n_s;
190 n_f0 = n_f;
191 n_na = 0;
192 n_lt = SC_IN * 65 / 10;
193 n_hy = 1;
194 n_ss = 12;
195 n_nM = 1;
196 n_nS = 1;
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;
216 void env_init(void)
218 int i;
219 init_time();
220 for (i = 0; i < LEN(eregs); i++)
221 eregs_idx[map(eregs[i])] = i + 1;
222 env_set(0);
225 void env_done(void)
227 int i;
228 for (i = 0; i < LEN(envs); i++)
229 if (envs[i])
230 env_free(envs[i]);
233 static int oenv[NPREV]; /* environment stack */
234 static int nenv;
236 void tr_ev(char **args)
238 int id = -1;
239 if (args[1])
240 id = map(args[1]);
241 else
242 id = nenv ? oenv[--nenv] : -1;
243 if (id < 0)
244 return;
245 if (args[1] && env && nenv < NPREV)
246 oenv[nenv++] = env_id;
247 env_set(id);
250 struct adj *env_adj(void)
252 return env->adj;
255 char *env_hc(void)
257 return env->hc;
260 char *env_mc(void)
262 return env->mc;
265 char *env_tc(void)
267 return env->tc;
270 char *env_lc(void)
272 return env->lc;
275 /* saving and restoring registers around diverted lines */
276 struct odiv {
277 int f, s, m, f0, s0, m0;
280 static struct odiv odivs[NPREV]; /* state before diverted text */
281 static int nodivs;
283 /* begin outputting diverted line */
284 void odiv_beg(void)
286 struct odiv *o = &odivs[nodivs++];
287 o->f = n_f;
288 o->s = n_s;
289 o->m = n_m;
290 o->f0 = n_f0;
291 o->s0 = n_s0;
292 o->m0 = n_m0;
295 /* end outputting diverted line */
296 void odiv_end(void)
298 struct odiv *o = &odivs[--nodivs];
299 n_f = o->f;
300 n_s = o->s;
301 n_m = o->m;
302 n_f0 = o->f0;
303 n_s0 = o->s0;
304 n_m0 = o->m0;
307 void tr_ta(char **args)
309 int i;
310 char *s;
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)
320 int i;
321 for (i = 0; i < LEN(env->tabs); i++)
322 if (env->tabs[i] > pos)
323 return i;
324 return -1;
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];
347 char *s = fmtbuf;
348 int i;
349 if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') {
350 *s++ = '0';
351 i = nregs_fmt[id] >> NF_LSH;
352 while (i-- > 1)
353 *s++ = '0';
354 } else {
355 *s++ = nregs_fmt[id] & NF_FMT;
357 *s = '\0';
358 return fmtbuf;
361 void num_setfmt(int id, char *s)
363 int i = 0;
364 if (strchr("iIaA", s[0])) {
365 nregs_fmt[id] = s[0];
366 } else {
367 while (isdigit(s[i]))
368 i++;
369 nregs_fmt[id] = '0' | (i << NF_LSH);
373 static void nf_reverse(char *s)
375 char r[128];
376 int i, l;
377 strcpy(r, s);
378 l = strlen(r);
379 for (i = 0; i < l; i++)
380 s[i] = r[l - i - 1];
383 static void nf_roman(char *s, int n, char *I, char *V)
385 int i;
386 if (!n)
387 return;
388 if (n % 5 == 4) {
389 *s++ = n % 10 == 9 ? I[1] : V[0];
390 *s++ = I[0];
391 } else {
392 for (i = 0; i < n % 5; i++)
393 *s++ = I[0];
394 if (n % 10 >= 5)
395 *s++ = V[0];
397 *s = '\0';
398 nf_roman(s, n / 10, I + 1, V + 1);
401 static void nf_alpha(char *s, int n, int a)
403 while (n) {
404 *s++ = a + ((n - 1) % 26);
405 n /= 26;
407 *s = '\0';
410 /* returns nonzero on failure */
411 static int num_fmt(char *s, int n, int fmt)
413 int type = fmt & NF_FMT;
414 int len;
415 if (n < 0) {
416 n = -n;
417 *s++ = '-';
419 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
420 if (type == 'i')
421 nf_roman(s, n, "ixcmz", "vldw");
422 else
423 nf_roman(s, n, "IXCMZ", "VLDW");
424 nf_reverse(s);
425 return 0;
427 if ((type == 'a' || type == 'A') && n > 0) {
428 nf_alpha(s, n, type);
429 nf_reverse(s);
430 return 0;
432 if (type == '0') {
433 sprintf(s, "%d", n);
434 len = strlen(s);
435 while (len++ < fmt >> NF_LSH)
436 *s++ = '0';
437 sprintf(s, "%d", n);
438 return 0;
440 return 1;