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 snprintf(numbuf
, sizeof(numbuf
), "%s", map_name(f_divreg()));
111 snprintf(numbuf
, sizeof(numbuf
), "%s", in_filename());
114 snprintf(numbuf
, sizeof(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);
267 num_set(map(".yr"), 1900 + tm
->tm_year
);
270 static void init_globals(void)
276 num_set(map(".H"), 1);
277 num_set(map(".V"), 1);
285 for (i
= 0; i
< LEN(eregs
); i
++)
286 eregs_idx
[map(eregs
[i
])] = i
+ 1;
293 for (i
= 0; i
< LEN(envs
); i
++)
296 for (i
= 0; i
< LEN(sregs
); i
++)
300 static int oenv
[NPREV
]; /* environment stack */
303 void tr_ev(char **args
)
309 id
= nenv
? oenv
[--nenv
] : -1;
312 if (args
[1] && env
&& nenv
< NPREV
)
313 oenv
[nenv
++] = env_id
;
317 struct fmt
*env_fmt(void)
322 struct wb
*env_wb(void)
347 /* saving and restoring registers around diverted lines */
349 int f
, s
, m
, f0
, s0
, m0
, cd
;
352 static struct odiv odivs
[NPREV
]; /* state before diverted text */
355 /* begin outputting diverted line */
358 struct odiv
*o
= &odivs
[nodivs
++];
368 /* end outputting diverted line */
371 struct odiv
*o
= &odivs
[--nodivs
];
381 void tr_ta(char **args
)
385 for (i
= 0; i
< NTABS
; i
++) {
386 if (i
+ 1 < NARGS
&& args
[i
+ 1]) {
387 char *a
= args
[i
+ 1];
388 env
->tabs
[i
] = eval_re(a
, i
> 0 ? env
->tabs
[i
- 1] : 0, 'm');
389 c
= a
[0] ? (unsigned char) strchr(a
, '\0')[-1] : 0;
390 env
->tabs_type
[i
] = strchr("LRC", c
) ? c
: 'L';
393 env
->tabs_type
[i
] = 0;
398 static int tab_idx(int pos
)
401 for (i
= 0; i
< LEN(env
->tabs
); i
++)
402 if (env
->tabs
[i
] > pos
)
407 int tab_next(int pos
)
409 int i
= tab_idx(pos
);
410 return i
>= 0 ? env
->tabs
[i
] : pos
;
413 int tab_type(int pos
)
415 int i
= tab_idx(pos
);
416 return i
>= 0 && env
->tabs_type
[i
] ? env
->tabs_type
[i
] : 'L';
419 /* number register format (.af) */
420 #define NF_LSH 8 /* number format length shifts */
421 #define NF_FMT 0x00ff /* number format mask */
423 /* the format of a number register (returns a static buffer) */
424 char *num_getfmt(int id
)
426 static char fmtbuf
[128];
428 int fmt
= nregs_fmt
[id
] & NF_FMT
;
430 if (fmt
== '0' || fmt
== 'x' || fmt
== 'X') {
431 i
= nregs_fmt
[id
] >> NF_LSH
;
435 } else if (nregs_fmt
[id
]) {
442 void num_setfmt(int id
, char *s
)
445 if (strchr("iIaA", s
[0])) {
446 nregs_fmt
[id
] = s
[0];
448 while (isdigit((unsigned char) s
[i
]))
450 if (s
[i
] == 'x' || s
[i
] == 'X')
451 nregs_fmt
[id
] = s
[i
] | ((i
+ 1) << NF_LSH
);
453 nregs_fmt
[id
] = '0' | (i
<< NF_LSH
);
457 static void nf_reverse(char *s
)
463 for (i
= 0; i
< l
; i
++)
467 static void nf_roman(char *s
, int n
, char *I
, char *V
)
473 *s
++ = n
% 10 == 9 ? I
[1] : V
[0];
476 for (i
= 0; i
< n
% 5; i
++)
482 nf_roman(s
, n
/ 10, I
+ 1, V
+ 1);
485 static void nf_alpha(char *s
, int n
, int a
)
488 *s
++ = a
+ ((n
- 1) % 26);
494 /* returns nonzero on failure */
495 static int num_fmt(char *s
, int n
, int fmt
)
497 int type
= fmt
& NF_FMT
;
502 if ((type
== 'i' || type
== 'I') && n
> 0 && n
< 40000) {
504 nf_roman(s
, n
, "ixcmz", "vldw");
506 nf_roman(s
, n
, "IXCMZ", "VLDW");
510 if ((type
== 'a' || type
== 'A') && n
> 0) {
511 nf_alpha(s
, n
, type
);
515 if (type
== '0' || type
== 'x' || type
== 'X') {
517 sprintf(pat
, "%%0%d%c", fmt
>> NF_LSH
, type
== '0' ? 'd' : type
);