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 int num_fmt(char *s
, int n
, int fmt
);
69 /* the contents of a number register (returns a static buffer) */
72 static char numbuf
[128];
73 char *s
= map_name(id
);
77 if (s
[0] == '.' && !s
[2]) {
80 sprintf(numbuf
, "%d", font_getbd(dev_font(n_f
)));
83 sprintf(numbuf
, "%d", in_lnum());
86 sprintf(numbuf
, "%d", f_hpos());
89 sprintf(numbuf
, "#%02x%02x%02x",
90 CLR_R(n_m
), CLR_G(n_m
), CLR_B(n_m
));
93 sprintf(numbuf
, "%d", f_nexttrap());
97 sprintf(numbuf
, "%s", map_name(f_divreg()));
100 sprintf(numbuf
, "%s", in_filename());
103 sprintf(numbuf
, "%s", directory(in_filename()));
106 sprintf(numbuf
, "%d", in_nargs());
110 if (s
[0] == '.' && !strcmp(".neat", s
))
112 if (s
[0] == '.' && s
[1] == 'e' && s
[2] == 'v' && !s
[3])
113 return map_name(env_id
);
114 if (s
[0] == '$' && s
[1] == '$' && !s
[2]) {
115 sprintf(numbuf
, "%d", getpid());
118 if (s
[0] == 'y' && s
[1] == 'r' && !s
[2]) {
119 sprintf(numbuf
, "%02d", *nreg(id
));
122 if (!nregs_fmt
[id
] || num_fmt(numbuf
, *nreg(id
), nregs_fmt
[id
]))
123 sprintf(numbuf
, "%d", *nreg(id
));
127 void num_set(int id
, int val
)
134 void num_setinc(int id
, int val
)
139 void num_inc(int id
, int pos
)
141 *nreg(id
) += pos
> 0 ? nregs_inc
[id
] : -nregs_inc
[id
];
151 void str_set(int id
, char *s
)
153 int len
= strlen(s
) + 1;
156 sregs
[id
] = xmalloc(len
);
157 memcpy(sregs
[id
], s
, len
);
158 sregs_dat
[id
] = NULL
;
161 char *str_get(int id
)
166 void *str_dget(int id
)
168 return sregs_dat
[id
];
171 void str_dset(int id
, void *d
)
181 sregs_dat
[id
] = NULL
;
184 void str_rn(int src
, int dst
)
186 if (!sregs
[src
] && !sregs_dat
[src
])
189 sregs
[dst
] = sregs
[src
];
190 sregs_dat
[dst
] = sregs_dat
[src
];
192 sregs_dat
[src
] = NULL
;
195 static struct env
*env_alloc(void)
197 struct env
*env
= xmalloc(sizeof(*env
));
198 memset(env
, 0, sizeof(*env
));
200 env
->fmt
= fmt_alloc();
204 static void env_free(struct env
*env
)
211 static void env_set(int id
)
217 envs
[id
] = env_alloc();
222 n_l
= SC_IN
* 65 / 10;
230 n_lt
= SC_IN
* 65 / 10;
236 strcpy(env
->hc
, "\\%");
237 strcpy(env
->lc
, ".");
238 for (i
= 0; i
< NTABS
; i
++)
239 env
->tabs
[i
] = i
* SC_IN
/ 2;
243 static void init_time(void)
245 time_t t
= time(NULL
);
246 struct tm
*tm
= localtime(&t
);
247 num_set(map("dw"), tm
->tm_wday
+ 1);
248 num_set(map("dy"), tm
->tm_mday
);
249 num_set(map("mo"), tm
->tm_mon
+ 1);
250 num_set(map("yr"), tm
->tm_year
% 100);
253 static void init_globals(void)
259 num_set(map(".H"), 1);
260 num_set(map(".V"), 1);
268 for (i
= 0; i
< LEN(eregs
); i
++)
269 eregs_idx
[map(eregs
[i
])] = i
+ 1;
276 for (i
= 0; i
< LEN(envs
); i
++)
279 for (i
= 0; i
< LEN(sregs
); i
++)
283 static int oenv
[NPREV
]; /* environment stack */
286 void tr_ev(char **args
)
292 id
= nenv
? oenv
[--nenv
] : -1;
295 if (args
[1] && env
&& nenv
< NPREV
)
296 oenv
[nenv
++] = env_id
;
300 struct fmt
*env_fmt(void)
305 struct wb
*env_wb(void)
330 /* saving and restoring registers around diverted lines */
332 int f
, s
, m
, f0
, s0
, m0
;
335 static struct odiv odivs
[NPREV
]; /* state before diverted text */
338 /* begin outputting diverted line */
341 struct odiv
*o
= &odivs
[nodivs
++];
350 /* end outputting diverted line */
353 struct odiv
*o
= &odivs
[--nodivs
];
362 void tr_ta(char **args
)
366 for (i
= 0; i
< NARGS
&& args
[i
]; i
++) {
367 env
->tabs
[i
] = eval_re(args
[i
], i
> 0 ? env
->tabs
[i
- 1] : 0, 'm');
368 s
= args
[i
][0] ? strchr(args
[i
], '\0') - 1 : "";
369 env
->tabs_type
[i
] = strchr("LRC", *s
) ? *s
: 'L';
373 static int tab_idx(int pos
)
376 for (i
= 0; i
< LEN(env
->tabs
); i
++)
377 if (env
->tabs
[i
] > pos
)
382 int tab_next(int pos
)
384 int i
= tab_idx(pos
);
385 return i
>= 0 ? env
->tabs
[i
] : pos
;
388 int tab_type(int pos
)
390 int i
= tab_idx(pos
);
391 return i
>= 0 && env
->tabs_type
[i
] ? env
->tabs_type
[i
] : 'L';
394 /* number register format (.af) */
395 #define NF_LSH 8 /* number format length shifts */
396 #define NF_FMT 0x00ff /* number format mask */
398 /* the format of a number register (returns a static buffer) */
399 char *num_getfmt(int id
)
401 static char fmtbuf
[128];
404 if ((nregs_fmt
[id
] & NF_FMT
) == '0') {
406 i
= nregs_fmt
[id
] >> NF_LSH
;
409 } else if (nregs_fmt
[id
]) {
410 *s
++ = nregs_fmt
[id
] & NF_FMT
;
416 void num_setfmt(int id
, char *s
)
419 if (strchr("iIaA", s
[0])) {
420 nregs_fmt
[id
] = s
[0];
422 while (isdigit(s
[i
]))
424 nregs_fmt
[id
] = '0' | (i
<< NF_LSH
);
428 static void nf_reverse(char *s
)
434 for (i
= 0; i
< l
; i
++)
438 static void nf_roman(char *s
, int n
, char *I
, char *V
)
444 *s
++ = n
% 10 == 9 ? I
[1] : V
[0];
447 for (i
= 0; i
< n
% 5; i
++)
453 nf_roman(s
, n
/ 10, I
+ 1, V
+ 1);
456 static void nf_alpha(char *s
, int n
, int a
)
459 *s
++ = a
+ ((n
- 1) % 26);
465 /* returns nonzero on failure */
466 static int num_fmt(char *s
, int n
, int fmt
)
468 int type
= fmt
& NF_FMT
;
474 if ((type
== 'i' || type
== 'I') && n
> 0 && n
< 40000) {
476 nf_roman(s
, n
, "ixcmz", "vldw");
478 nf_roman(s
, n
, "IXCMZ", "VLDW");
482 if ((type
== 'a' || type
== 'A') && n
> 0) {
483 nf_alpha(s
, n
, type
);
490 while (len
++ < fmt
>> NF_LSH
)