1 /* registers and environments */
11 #define NENVS 64 /* number of environment registers */
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", ".i0", ".l0",
41 ".hy", ".hycost", ".hycost2", ".hycost3", ".hlm",
42 ".L0", ".m0", ".n0", ".s0", ".ss", ".ssh", ".sss", ".pmll", ".pmllcost",
43 ".ti", ".lt", ".lt0", ".v0",
46 /* return the address of a number register */
50 return &env
->eregs
[eregs_idx
[id
]];
54 static char *directory(char *path
)
56 static char dst
[PATHLEN
];
57 char *s
= strrchr(path
, '/');
62 memcpy(dst
, path
, s
- path
);
67 static char *num_tabs(void)
69 static char tabs
[16 * NTABS
];
72 for (i
= 0; i
< NTABS
&& env
->tabs_type
[i
]; i
++)
73 s
+= sprintf(s
, "%du%c ", env
->tabs
[i
], env
->tabs_type
[i
]);
77 static int num_fmt(char *s
, int n
, int fmt
);
79 /* the contents of a number register (returns a static buffer) */
82 static char numbuf
[128];
83 char *s
= map_name(id
);
87 if (s
[0] == '.' && !s
[2]) {
90 sprintf(numbuf
, "%d", font_getbd(dev_font(n_f
)));
93 sprintf(numbuf
, "%d", in_lnum());
96 sprintf(numbuf
, "%d", f_hpos());
99 sprintf(numbuf
, "#%02x%02x%02x",
100 CLR_R(n_m
), CLR_G(n_m
), CLR_B(n_m
));
103 sprintf(numbuf
, "%d", f_nexttrap());
107 sprintf(numbuf
, "%s", map_name(f_divreg()));
110 sprintf(numbuf
, "%s", in_filename());
113 sprintf(numbuf
, "%s", directory(in_filename()));
116 sprintf(numbuf
, "%d", in_nargs());
120 if (s
[0] == '.' && !strcmp(".neat", s
))
122 if (s
[0] == '.' && s
[1] == 'e' && s
[2] == 'v' && !s
[3])
123 return map_name(env_id
);
124 if (s
[0] == '$' && s
[1] == '$' && !s
[2]) {
125 sprintf(numbuf
, "%d", getpid());
128 if (s
[0] == 'y' && s
[1] == 'r' && !s
[2]) {
129 sprintf(numbuf
, "%02d", *nreg(id
));
132 if (s
[0] == '.' && !strcmp(".tabs", s
))
134 if (!nregs_fmt
[id
] || num_fmt(numbuf
, *nreg(id
), nregs_fmt
[id
]))
135 sprintf(numbuf
, "%d", *nreg(id
));
139 void num_set(int id
, int val
)
146 void num_setinc(int id
, int val
)
151 void num_inc(int id
, int pos
)
153 *nreg(id
) += pos
> 0 ? nregs_inc
[id
] : -nregs_inc
[id
];
163 void str_set(int id
, char *s
)
165 int len
= strlen(s
) + 1;
168 sregs
[id
] = xmalloc(len
);
169 memcpy(sregs
[id
], s
, len
);
170 sregs_dat
[id
] = NULL
;
173 char *str_get(int id
)
178 void *str_dget(int id
)
180 return sregs_dat
[id
];
183 void str_dset(int id
, void *d
)
193 sregs_dat
[id
] = NULL
;
196 void str_rn(int src
, int dst
)
198 if (!sregs
[src
] && !sregs_dat
[src
])
201 sregs
[dst
] = sregs
[src
];
202 sregs_dat
[dst
] = sregs_dat
[src
];
204 sregs_dat
[src
] = NULL
;
207 static struct env
*env_alloc(void)
209 struct env
*env
= xmalloc(sizeof(*env
));
210 memset(env
, 0, sizeof(*env
));
212 env
->fmt
= fmt_alloc();
216 static void env_free(struct env
*env
)
223 static void env_set(int id
)
229 envs
[id
] = env_alloc();
234 n_l
= SC_IN
* 65 / 10;
242 n_lt
= SC_IN
* 65 / 10;
248 strcpy(env
->hc
, "\\%");
249 strcpy(env
->lc
, ".");
250 for (i
= 0; i
< NTABS
; i
++) {
251 env
->tabs
[i
] = i
* SC_IN
/ 2;
252 env
->tabs_type
[i
] = 'L';
257 static void init_time(void)
259 time_t t
= time(NULL
);
260 struct tm
*tm
= localtime(&t
);
261 num_set(map("dw"), tm
->tm_wday
+ 1);
262 num_set(map("dy"), tm
->tm_mday
);
263 num_set(map("mo"), tm
->tm_mon
+ 1);
264 num_set(map("yr"), tm
->tm_year
% 100);
267 static void init_globals(void)
273 num_set(map(".H"), 1);
274 num_set(map(".V"), 1);
282 for (i
= 0; i
< LEN(eregs
); i
++)
283 eregs_idx
[map(eregs
[i
])] = i
+ 1;
290 for (i
= 0; i
< LEN(envs
); i
++)
293 for (i
= 0; i
< LEN(sregs
); i
++)
297 static int oenv
[NPREV
]; /* environment stack */
300 void tr_ev(char **args
)
306 id
= nenv
? oenv
[--nenv
] : -1;
309 if (args
[1] && env
&& nenv
< NPREV
)
310 oenv
[nenv
++] = env_id
;
314 struct fmt
*env_fmt(void)
319 struct wb
*env_wb(void)
344 /* saving and restoring registers around diverted lines */
346 int f
, s
, m
, f0
, s0
, m0
;
349 static struct odiv odivs
[NPREV
]; /* state before diverted text */
352 /* begin outputting diverted line */
355 struct odiv
*o
= &odivs
[nodivs
++];
364 /* end outputting diverted line */
367 struct odiv
*o
= &odivs
[--nodivs
];
376 void tr_ta(char **args
)
380 for (i
= 0; i
< NTABS
; i
++) {
381 if (i
+ 1 < NARGS
&& args
[i
+ 1]) {
382 char *a
= args
[i
+ 1];
383 env
->tabs
[i
] = eval_re(a
, i
> 0 ? env
->tabs
[i
- 1] : 0, 'm');
384 c
= a
[0] ? (unsigned char) strchr(a
, '\0')[-1] : 0;
385 env
->tabs_type
[i
] = strchr("LRC", c
) ? c
: 'L';
388 env
->tabs_type
[i
] = 0;
393 static int tab_idx(int pos
)
396 for (i
= 0; i
< LEN(env
->tabs
); i
++)
397 if (env
->tabs
[i
] > pos
)
402 int tab_next(int pos
)
404 int i
= tab_idx(pos
);
405 return i
>= 0 ? env
->tabs
[i
] : pos
;
408 int tab_type(int pos
)
410 int i
= tab_idx(pos
);
411 return i
>= 0 && env
->tabs_type
[i
] ? env
->tabs_type
[i
] : 'L';
414 /* number register format (.af) */
415 #define NF_LSH 8 /* number format length shifts */
416 #define NF_FMT 0x00ff /* number format mask */
418 /* the format of a number register (returns a static buffer) */
419 char *num_getfmt(int id
)
421 static char fmtbuf
[128];
423 int fmt
= nregs_fmt
[id
] & NF_FMT
;
425 if (fmt
== '0' || fmt
== 'x' || fmt
== 'X') {
426 i
= nregs_fmt
[id
] >> NF_LSH
;
430 } else if (nregs_fmt
[id
]) {
437 void num_setfmt(int id
, char *s
)
440 if (strchr("iIaA", s
[0])) {
441 nregs_fmt
[id
] = s
[0];
443 while (isdigit((unsigned char) s
[i
]))
445 if (s
[i
] == 'x' || s
[i
] == 'X')
446 nregs_fmt
[id
] = s
[i
] | ((i
+ 1) << NF_LSH
);
448 nregs_fmt
[id
] = '0' | (i
<< NF_LSH
);
452 static void nf_reverse(char *s
)
458 for (i
= 0; i
< l
; i
++)
462 static void nf_roman(char *s
, int n
, char *I
, char *V
)
468 *s
++ = n
% 10 == 9 ? I
[1] : V
[0];
471 for (i
= 0; i
< n
% 5; i
++)
477 nf_roman(s
, n
/ 10, I
+ 1, V
+ 1);
480 static void nf_alpha(char *s
, int n
, int a
)
483 *s
++ = a
+ ((n
- 1) % 26);
489 /* returns nonzero on failure */
490 static int num_fmt(char *s
, int n
, int fmt
)
492 int type
= fmt
& NF_FMT
;
497 if ((type
== 'i' || type
== 'I') && n
> 0 && n
< 40000) {
499 nf_roman(s
, n
, "ixcmz", "vldw");
501 nf_roman(s
, n
, "IXCMZ", "VLDW");
505 if ((type
== 'a' || type
== 'A') && n
> 0) {
506 nf_alpha(s
, n
, type
);
510 if (type
== '0' || type
== 'x' || type
== 'X') {
512 sprintf(pat
, "%%0%d%c", fmt
>> NF_LSH
, type
== '0' ? 'd' : type
);