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",
44 ".I", ".I0", ".tI", ".td", ".cd",
47 /* return the address of a number register */
51 return &env
->eregs
[eregs_idx
[id
]];
55 static char *directory(char *path
)
57 static char dst
[PATHLEN
];
58 char *s
= strrchr(path
, '/');
63 memcpy(dst
, path
, s
- path
);
68 static char *num_tabs(void)
70 static char tabs
[16 * NTABS
];
73 for (i
= 0; i
< NTABS
&& env
->tabs_type
[i
]; i
++)
74 s
+= sprintf(s
, "%du%c ", env
->tabs
[i
], env
->tabs_type
[i
]);
78 static int num_fmt(char *s
, int n
, int fmt
);
80 /* the contents of a number register (returns a static buffer) */
83 static char numbuf
[128];
84 char *s
= map_name(id
);
88 if (s
[0] == '.' && !s
[2]) {
91 sprintf(numbuf
, "%d", font_getbd(dev_font(n_f
)));
94 sprintf(numbuf
, "%d", in_lnum());
97 sprintf(numbuf
, "%d", f_hpos());
100 sprintf(numbuf
, "#%02x%02x%02x",
101 CLR_R(n_m
), CLR_G(n_m
), CLR_B(n_m
));
104 sprintf(numbuf
, "%d", f_nexttrap());
108 sprintf(numbuf
, "%s", map_name(f_divreg()));
111 sprintf(numbuf
, "%s", in_filename());
114 sprintf(numbuf
, "%s", directory(in_filename()));
117 sprintf(numbuf
, "%d", in_nargs() - 1);
121 if (s
[0] == '.' && !strcmp(".neat", s
))
123 if (s
[0] == '.' && s
[1] == 'e' && s
[2] == 'v' && !s
[3])
124 return map_name(env_id
);
125 if (s
[0] == '$' && s
[1] == '$' && !s
[2]) {
126 sprintf(numbuf
, "%d", getpid());
129 if (s
[0] == 'y' && s
[1] == 'r' && !s
[2]) {
130 sprintf(numbuf
, "%02d", *nreg(id
));
133 if (s
[0] == '.' && !strcmp(".tabs", s
))
135 if (!nregs_fmt
[id
] || num_fmt(numbuf
, *nreg(id
), nregs_fmt
[id
]))
136 sprintf(numbuf
, "%d", *nreg(id
));
140 void num_set(int id
, int val
)
147 void num_setinc(int id
, int val
)
152 void num_inc(int id
, int pos
)
154 *nreg(id
) += pos
> 0 ? nregs_inc
[id
] : -nregs_inc
[id
];
164 void str_set(int id
, char *s
)
166 int len
= strlen(s
) + 1;
169 sregs
[id
] = xmalloc(len
);
170 memcpy(sregs
[id
], s
, len
);
171 sregs_dat
[id
] = NULL
;
174 char *str_get(int id
)
179 void *str_dget(int id
)
181 return sregs_dat
[id
];
184 void str_dset(int id
, void *d
)
194 sregs_dat
[id
] = NULL
;
197 void str_rn(int src
, int dst
)
199 if (!sregs
[src
] && !sregs_dat
[src
])
202 sregs
[dst
] = sregs
[src
];
203 sregs_dat
[dst
] = sregs_dat
[src
];
205 sregs_dat
[src
] = NULL
;
208 static struct env
*env_alloc(void)
210 struct env
*env
= xmalloc(sizeof(*env
));
211 memset(env
, 0, sizeof(*env
));
213 env
->fmt
= fmt_alloc();
217 static void env_free(struct env
*env
)
224 static void env_set(int id
)
230 envs
[id
] = env_alloc();
236 n_l
= SC_IN
* 65 / 10;
244 n_lt
= SC_IN
* 65 / 10;
250 strcpy(env
->hc
, "\\%");
251 strcpy(env
->lc
, ".");
252 for (i
= 0; i
< NTABS
; i
++) {
253 env
->tabs
[i
] = i
* SC_IN
/ 2;
254 env
->tabs_type
[i
] = 'L';
259 static void init_time(void)
261 time_t t
= time(NULL
);
262 struct tm
*tm
= localtime(&t
);
263 num_set(map("dw"), tm
->tm_wday
+ 1);
264 num_set(map("dy"), tm
->tm_mday
);
265 num_set(map("mo"), tm
->tm_mon
+ 1);
266 num_set(map("yr"), tm
->tm_year
% 100);
269 static void init_globals(void)
275 num_set(map(".H"), 1);
276 num_set(map(".V"), 1);
284 for (i
= 0; i
< LEN(eregs
); i
++)
285 eregs_idx
[map(eregs
[i
])] = i
+ 1;
292 for (i
= 0; i
< LEN(envs
); i
++)
295 for (i
= 0; i
< LEN(sregs
); i
++)
299 static int oenv
[NPREV
]; /* environment stack */
302 void tr_ev(char **args
)
308 id
= nenv
? oenv
[--nenv
] : -1;
311 if (args
[1] && env
&& nenv
< NPREV
)
312 oenv
[nenv
++] = env_id
;
316 struct fmt
*env_fmt(void)
321 struct wb
*env_wb(void)
346 /* saving and restoring registers around diverted lines */
348 int f
, s
, m
, f0
, s0
, m0
, cd
;
351 static struct odiv odivs
[NPREV
]; /* state before diverted text */
354 /* begin outputting diverted line */
357 struct odiv
*o
= &odivs
[nodivs
++];
367 /* end outputting diverted line */
370 struct odiv
*o
= &odivs
[--nodivs
];
380 void tr_ta(char **args
)
384 for (i
= 0; i
< NTABS
; i
++) {
385 if (i
+ 1 < NARGS
&& args
[i
+ 1]) {
386 char *a
= args
[i
+ 1];
387 env
->tabs
[i
] = eval_re(a
, i
> 0 ? env
->tabs
[i
- 1] : 0, 'm');
388 c
= a
[0] ? (unsigned char) strchr(a
, '\0')[-1] : 0;
389 env
->tabs_type
[i
] = strchr("LRC", c
) ? c
: 'L';
392 env
->tabs_type
[i
] = 0;
397 static int tab_idx(int pos
)
400 for (i
= 0; i
< LEN(env
->tabs
); i
++)
401 if (env
->tabs
[i
] > pos
)
406 int tab_next(int pos
)
408 int i
= tab_idx(pos
);
409 return i
>= 0 ? env
->tabs
[i
] : pos
;
412 int tab_type(int pos
)
414 int i
= tab_idx(pos
);
415 return i
>= 0 && env
->tabs_type
[i
] ? env
->tabs_type
[i
] : 'L';
418 /* number register format (.af) */
419 #define NF_LSH 8 /* number format length shifts */
420 #define NF_FMT 0x00ff /* number format mask */
422 /* the format of a number register (returns a static buffer) */
423 char *num_getfmt(int id
)
425 static char fmtbuf
[128];
427 int fmt
= nregs_fmt
[id
] & NF_FMT
;
429 if (fmt
== '0' || fmt
== 'x' || fmt
== 'X') {
430 i
= nregs_fmt
[id
] >> NF_LSH
;
434 } else if (nregs_fmt
[id
]) {
441 void num_setfmt(int id
, char *s
)
444 if (strchr("iIaA", s
[0])) {
445 nregs_fmt
[id
] = s
[0];
447 while (isdigit((unsigned char) s
[i
]))
449 if (s
[i
] == 'x' || s
[i
] == 'X')
450 nregs_fmt
[id
] = s
[i
] | ((i
+ 1) << NF_LSH
);
452 nregs_fmt
[id
] = '0' | (i
<< NF_LSH
);
456 static void nf_reverse(char *s
)
462 for (i
= 0; i
< l
; i
++)
466 static void nf_roman(char *s
, int n
, char *I
, char *V
)
472 *s
++ = n
% 10 == 9 ? I
[1] : V
[0];
475 for (i
= 0; i
< n
% 5; i
++)
481 nf_roman(s
, n
/ 10, I
+ 1, V
+ 1);
484 static void nf_alpha(char *s
, int n
, int a
)
487 *s
++ = a
+ ((n
- 1) % 26);
493 /* returns nonzero on failure */
494 static int num_fmt(char *s
, int n
, int fmt
)
496 int type
= fmt
& NF_FMT
;
501 if ((type
== 'i' || type
== 'I') && n
> 0 && n
< 40000) {
503 nf_roman(s
, n
, "ixcmz", "vldw");
505 nf_roman(s
, n
, "IXCMZ", "VLDW");
509 if ((type
== 'a' || type
== 'A') && n
> 0) {
510 nf_alpha(s
, n
, type
);
514 if (type
== '0' || type
== 'x' || type
== 'X') {
516 sprintf(pat
, "%%0%d%c", fmt
>> NF_LSH
, type
== '0' ? 'd' : type
);