hyph: do not read more than GNLEN characters in hy_cget()
[neatroff.git] / reg.c
blob97491b9a967b652622c1df1fc76d0fabd5345405
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 <unistd.h>
9 #include "roff.h"
11 #define NENVS 64 /* number of environment registers */
13 struct env {
14 int eregs[NENVS]; /* environment-specific number registers */
15 int tabs[NTABS]; /* tab stops */
16 char tabs_type[NTABS]; /* type of tabs: L, C, R */
17 struct fmt *fmt; /* per environment line formatting buffer */
18 struct wb wb; /* per environment partial word */
19 char tc[GNLEN]; /* tab character (.tc) */
20 char lc[GNLEN]; /* leader character (.lc) */
21 char hc[GNLEN]; /* hyphenation character (.hc) */
22 char mc[GNLEN]; /* margin character (.mc) */
25 static int nregs[NREGS]; /* global number registers */
26 static int nregs_inc[NREGS]; /* number register auto-increment size */
27 static int nregs_fmt[NREGS]; /* number register format */
28 static char *sregs[NREGS]; /* global string registers */
29 static void *sregs_dat[NREGS]; /* builtin function data */
30 static struct env *envs[NREGS];/* environments */
31 static struct env *env; /* current enviroment */
32 static int env_id; /* current environment id */
33 static int eregs_idx[NREGS]; /* register environment index in eregs[] */
35 static char *eregs[] = { /* environment-specific number registers */
36 "ln", ".f", ".i", ".j", ".l",
37 ".L", ".nI", ".nm", ".nM", ".nn",
38 ".nS", ".m", ".s", ".u", ".v",
39 ".it", ".itn", ".mc", ".mcn",
40 ".ce", ".f0", ".hy", ".hycost", ".hycost2",".hycost3", ".i0", ".l0",
41 ".L0", ".m0", ".n0", ".s0", ".ss", ".ssh", ".sss", ".pmll", ".pmllcost",
42 ".ti", ".lt", ".lt0", ".v0",
45 /* return the address of a number register */
46 int *nreg(int id)
48 if (eregs_idx[id])
49 return &env->eregs[eregs_idx[id]];
50 return &nregs[id];
53 static char *directory(char *path)
55 static char dst[PATHLEN];
56 char *s = strrchr(path, '/');
57 if (!s)
58 return ".";
59 if (path == s)
60 return "/";
61 memcpy(dst, path, s - path);
62 dst[s - path] = '\0';
63 return dst;
66 static int num_fmt(char *s, int n, int fmt);
68 /* the contents of a number register (returns a static buffer) */
69 char *num_str(int id)
71 static char numbuf[128];
72 char *s = map_name(id);
73 if (!nregs_fmt[id])
74 nregs_fmt[id] = '0';
75 numbuf[0] = '\0';
76 if (s[0] == '.' && !s[2]) {
77 switch (s[1]) {
78 case 'b':
79 sprintf(numbuf, "%d", font_getbd(dev_font(n_f)));
80 return numbuf;
81 case 'c':
82 sprintf(numbuf, "%d", in_lnum());
83 return numbuf;
84 case 'k':
85 sprintf(numbuf, "%d", f_hpos());
86 return numbuf;
87 case 'm':
88 sprintf(numbuf, "#%02x%02x%02x",
89 CLR_R(n_m), CLR_G(n_m), CLR_B(n_m));
90 return numbuf;
91 case 't':
92 sprintf(numbuf, "%d", f_nexttrap());
93 return numbuf;
94 case 'z':
95 if (f_divreg() >= 0)
96 sprintf(numbuf, "%s", map_name(f_divreg()));
97 return numbuf;
98 case 'F':
99 sprintf(numbuf, "%s", in_filename());
100 return numbuf;
101 case 'D':
102 sprintf(numbuf, "%s", directory(in_filename()));
103 return numbuf;
104 case '$':
105 sprintf(numbuf, "%d", in_nargs());
106 return numbuf;
109 if (s[0] == '.' && !strcmp(".neat", s))
110 return "1";
111 if (s[0] == '.' && s[1] == 'e' && s[2] == 'v' && !s[3])
112 return map_name(env_id);
113 if (s[0] == '$' && s[1] == '$' && !s[2]) {
114 sprintf(numbuf, "%d", getpid());
115 return numbuf;
117 if (s[0] == 'y' && s[1] == 'r' && !s[2]) {
118 sprintf(numbuf, "%02d", *nreg(id));
119 return numbuf;
121 if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
122 sprintf(numbuf, "%d", *nreg(id));
123 return numbuf;
126 void num_set(int id, int val)
128 if (!nregs_fmt[id])
129 nregs_fmt[id] = '0';
130 *nreg(id) = val;
133 void num_setinc(int id, int val)
135 nregs_inc[id] = val;
138 void num_inc(int id, int pos)
140 *nreg(id) += pos > 0 ? nregs_inc[id] : -nregs_inc[id];
143 void num_del(int id)
145 *nreg(id) = 0;
146 nregs_inc[id] = 0;
147 nregs_fmt[id] = 0;
150 void str_set(int id, char *s)
152 int len = strlen(s) + 1;
153 if (sregs[id])
154 free(sregs[id]);
155 sregs[id] = xmalloc(len);
156 memcpy(sregs[id], s, len);
157 sregs_dat[id] = NULL;
160 char *str_get(int id)
162 return sregs[id];
165 void *str_dget(int id)
167 return sregs_dat[id];
170 void str_dset(int id, void *d)
172 sregs_dat[id] = d;
175 void str_rm(int id)
177 if (sregs[id])
178 free(sregs[id]);
179 sregs[id] = NULL;
180 sregs_dat[id] = NULL;
183 void str_rn(int src, int dst)
185 if (!sregs[src] && !sregs_dat[src])
186 return;
187 str_rm(dst);
188 sregs[dst] = sregs[src];
189 sregs_dat[dst] = sregs_dat[src];
190 sregs[src] = NULL;
191 sregs_dat[src] = NULL;
194 static struct env *env_alloc(void)
196 struct env *env = xmalloc(sizeof(*env));
197 memset(env, 0, sizeof(*env));
198 wb_init(&env->wb);
199 env->fmt = fmt_alloc();
200 return env;
203 static void env_free(struct env *env)
205 fmt_free(env->fmt);
206 wb_done(&env->wb);
207 free(env);
210 static void env_set(int id)
212 int i;
213 env = envs[id];
214 env_id = id;
215 if (!env) {
216 envs[id] = env_alloc();
217 env = envs[id];
218 n_f = 1;
219 n_i = 0;
220 n_j = AD_B;
221 n_l = SC_IN * 65 / 10;
222 n_L = 1;
223 n_s = 10;
224 n_u = 1;
225 n_v = 12 * SC_PT;
226 n_s0 = n_s;
227 n_f0 = n_f;
228 n_na = 0;
229 n_lt = SC_IN * 65 / 10;
230 n_hy = 1;
231 n_ss = 12;
232 n_sss = 12;
233 n_nM = 1;
234 n_nS = 1;
235 strcpy(env->hc, "\\%");
236 strcpy(env->lc, ".");
237 for (i = 0; i < NTABS; i++)
238 env->tabs[i] = i * SC_IN / 2;
242 static void init_time(void)
244 time_t t = time(NULL);
245 struct tm *tm = localtime(&t);
246 num_set(map("dw"), tm->tm_wday + 1);
247 num_set(map("dy"), tm->tm_mday);
248 num_set(map("mo"), tm->tm_mon + 1);
249 num_set(map("yr"), tm->tm_year % 100);
252 static void init_globals(void)
254 n_o = SC_IN;
255 n_p = SC_IN * 11;
256 n_lg = 1;
257 n_kn = 0;
258 num_set(map(".H"), 1);
259 num_set(map(".V"), 1);
262 void env_init(void)
264 int i;
265 init_time();
266 init_globals();
267 for (i = 0; i < LEN(eregs); i++)
268 eregs_idx[map(eregs[i])] = i + 1;
269 env_set(map("0"));
272 void env_done(void)
274 int i;
275 for (i = 0; i < LEN(envs); i++)
276 if (envs[i])
277 env_free(envs[i]);
278 for (i = 0; i < LEN(sregs); i++)
279 free(sregs[i]);
282 static int oenv[NPREV]; /* environment stack */
283 static int nenv;
285 void tr_ev(char **args)
287 int id = -1;
288 if (args[1])
289 id = map(args[1]);
290 else
291 id = nenv ? oenv[--nenv] : -1;
292 if (id < 0)
293 return;
294 if (args[1] && env && nenv < NPREV)
295 oenv[nenv++] = env_id;
296 env_set(id);
299 struct fmt *env_fmt(void)
301 return env->fmt;
304 struct wb *env_wb(void)
306 return &env->wb;
309 char *env_hc(void)
311 return env->hc;
314 char *env_mc(void)
316 return env->mc;
319 char *env_tc(void)
321 return env->tc;
324 char *env_lc(void)
326 return env->lc;
329 /* saving and restoring registers around diverted lines */
330 struct odiv {
331 int f, s, m, f0, s0, m0;
334 static struct odiv odivs[NPREV]; /* state before diverted text */
335 static int nodivs;
337 /* begin outputting diverted line */
338 void odiv_beg(void)
340 struct odiv *o = &odivs[nodivs++];
341 o->f = n_f;
342 o->s = n_s;
343 o->m = n_m;
344 o->f0 = n_f0;
345 o->s0 = n_s0;
346 o->m0 = n_m0;
349 /* end outputting diverted line */
350 void odiv_end(void)
352 struct odiv *o = &odivs[--nodivs];
353 n_f = o->f;
354 n_s = o->s;
355 n_m = o->m;
356 n_f0 = o->f0;
357 n_s0 = o->s0;
358 n_m0 = o->m0;
361 void tr_ta(char **args)
363 int i;
364 char *s;
365 for (i = 0; i < NARGS && args[i]; i++) {
366 env->tabs[i] = eval_re(args[i], i > 0 ? env->tabs[i - 1] : 0, 'm');
367 s = args[i][0] ? strchr(args[i], '\0') - 1 : "";
368 env->tabs_type[i] = strchr("LRC", *s) ? *s : 'L';
372 static int tab_idx(int pos)
374 int i;
375 for (i = 0; i < LEN(env->tabs); i++)
376 if (env->tabs[i] > pos)
377 return i;
378 return -1;
381 int tab_next(int pos)
383 int i = tab_idx(pos);
384 return i >= 0 ? env->tabs[i] : pos;
387 int tab_type(int pos)
389 int i = tab_idx(pos);
390 return i >= 0 && env->tabs_type[i] ? env->tabs_type[i] : 'L';
393 /* number register format (.af) */
394 #define NF_LSH 8 /* number format length shifts */
395 #define NF_FMT 0x00ff /* number format mask */
397 /* the format of a number register (returns a static buffer) */
398 char *num_getfmt(int id)
400 static char fmtbuf[128];
401 char *s = fmtbuf;
402 int i;
403 if ((nregs_fmt[id] & NF_FMT) == '0') {
404 *s++ = '0';
405 i = nregs_fmt[id] >> NF_LSH;
406 while (i-- > 1)
407 *s++ = '0';
408 } else if (nregs_fmt[id]) {
409 *s++ = nregs_fmt[id] & NF_FMT;
411 *s = '\0';
412 return fmtbuf;
415 void num_setfmt(int id, char *s)
417 int i = 0;
418 if (strchr("iIaA", s[0])) {
419 nregs_fmt[id] = s[0];
420 } else {
421 while (isdigit(s[i]))
422 i++;
423 nregs_fmt[id] = '0' | (i << NF_LSH);
427 static void nf_reverse(char *s)
429 char r[128];
430 int i, l;
431 strcpy(r, s);
432 l = strlen(r);
433 for (i = 0; i < l; i++)
434 s[i] = r[l - i - 1];
437 static void nf_roman(char *s, int n, char *I, char *V)
439 int i;
440 if (!n)
441 return;
442 if (n % 5 == 4) {
443 *s++ = n % 10 == 9 ? I[1] : V[0];
444 *s++ = I[0];
445 } else {
446 for (i = 0; i < n % 5; i++)
447 *s++ = I[0];
448 if (n % 10 >= 5)
449 *s++ = V[0];
451 *s = '\0';
452 nf_roman(s, n / 10, I + 1, V + 1);
455 static void nf_alpha(char *s, int n, int a)
457 while (n) {
458 *s++ = a + ((n - 1) % 26);
459 n /= 26;
461 *s = '\0';
464 /* returns nonzero on failure */
465 static int num_fmt(char *s, int n, int fmt)
467 int type = fmt & NF_FMT;
468 int len;
469 if (n < 0) {
470 n = -n;
471 *s++ = '-';
473 if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
474 if (type == 'i')
475 nf_roman(s, n, "ixcmz", "vldw");
476 else
477 nf_roman(s, n, "IXCMZ", "VLDW");
478 nf_reverse(s);
479 return 0;
481 if ((type == 'a' || type == 'A') && n > 0) {
482 nf_alpha(s, n, type);
483 nf_reverse(s);
484 return 0;
486 if (type == '0') {
487 sprintf(s, "%d", n);
488 len = strlen(s);
489 while (len++ < fmt >> NF_LSH)
490 *s++ = '0';
491 sprintf(s, "%d", n);
492 return 0;
494 return 1;