7 #define cadj env_adj() /* line buffer */
11 struct sbuf sbuf
; /* diversion output */
12 int reg
; /* diversion register */
13 int tpos
; /* diversion trap position */
14 int treg
; /* diversion trap register */
15 int dl
; /* diversion width */
16 int prev_d
; /* previous \(.d value */
17 int prev_h
; /* previous \(.h value */
18 int prev_mk
; /* previous .mk internal register */
19 int prev_ns
; /* previous .ns value */
21 static struct div divs
[NPREV
]; /* diversion stack */
22 static struct div
*cdiv
; /* current diversion */
23 static int ren_f
= -1; /* last rendered n_f */
24 static int ren_s
= -1; /* last rendered n_s */
25 static int ren_div
; /* rendering a diversion */
27 static int ren_backed
= -1; /* pushed back character */
29 static int bp_first
= 1; /* prior to the first page */
30 static int bp_next
= 1; /* next page number */
31 static int bp_force
; /* execute the traps until the next page */
33 static int ren_next(void)
35 int c
= ren_backed
>= 0 ? ren_backed
: tr_next();
40 static void ren_back(int c
)
45 void tr_di(char **args
)
48 cdiv
= cdiv
? cdiv
+ 1 : divs
;
49 memset(cdiv
, 0, sizeof(*cdiv
));
50 sbuf_init(&cdiv
->sbuf
);
51 cdiv
->reg
= REG(args
[1][0], args
[1][1]);
53 if (args
[0][2] == 'a' && str_get(cdiv
->reg
)) /* .da */
54 sbuf_append(&cdiv
->sbuf
, str_get(cdiv
->reg
));
55 sbuf_append(&cdiv
->sbuf
, DIV_BEG
"\n");
67 sbuf_putnl(&cdiv
->sbuf
);
68 sbuf_append(&cdiv
->sbuf
, DIV_END
"\n");
69 str_set(cdiv
->reg
, sbuf_buf(&cdiv
->sbuf
));
70 sbuf_done(&cdiv
->sbuf
);
77 cdiv
= cdiv
> divs
? cdiv
- 1 : NULL
;
85 return cdiv
? cdiv
->reg
: -1;
93 void tr_divbeg(char **args
)
99 void tr_divend(char **args
)
105 static int trap_reg(int pos
);
106 static int trap_pos(int pos
);
107 static void trap_exec(int reg
);
109 static void ren_page(int pg
)
118 if (trap_pos(-1) == 0)
119 trap_exec(trap_reg(-1));
122 static void ren_first(void)
130 static void ren_sp(int n
)
134 if (!n
&& ren_div
&& !n_u
)
140 sbuf_putnl(&cdiv
->sbuf
);
141 sprintf(cmd
, "'sp %du\n", n
? n
: n_v
);
142 sbuf_append(&cdiv
->sbuf
, cmd
);
148 static void push_ne(void)
151 sprintf(buf
, ".ne %du\n", n_p
);
152 in_pushnl(buf
, NULL
);
155 static void trap_exec(int reg
)
160 in_pushnl(str_get(reg
), NULL
);
163 /* return 1 if executed a trap */
164 static int ren_traps(int beg
, int end
, int dosp
)
166 int pos
= trap_pos(beg
);
167 if (pos
>= 0 && (cdiv
|| pos
< n_p
) && pos
<= end
) {
168 if (dosp
&& pos
> beg
)
170 trap_exec(trap_reg(beg
));
176 /* start a new page if needed */
177 static int ren_pagelimit(int ne
)
179 if (n_nl
+ ne
>= n_p
&& !cdiv
) {
187 static void down(int n
)
189 if (!ren_traps(n_d
, n_d
+ (n
? n
: n_v
), 1)) {
195 /* flush the given line and send it to out.c */
196 static void ren_line(char *s
, int w
, int ll
, int li
, int lt
)
200 int llen
= ll
- (lt
>= 0 ? lt
: li
);
202 if (n_u
&& !n_na
&& (n_j
== AD_C
|| n_j
== AD_R
))
203 ljust
= n_j
== AD_C
? (llen
- w
) / 2 : llen
- w
;
205 ljust
= llen
> w
? (llen
- w
) / 2 : 0;
209 ljust
+= lt
>= 0 ? lt
: li
;
211 sprintf(cmd
, "\\h'%du'", ljust
);
212 sbuf_append(&cdiv
->sbuf
, cmd
);
214 sbuf_append(&cdiv
->sbuf
, s
);
216 out("H%d\n", n_o
+ (lt
>= 0 ? lt
: li
) + ljust
);
222 /* return 1 if triggered a trap */
223 static int ren_br(int force
)
226 int ll
, li
, lt
, els_neg
, els_pos
;
227 int adj_b
, fill
, w
, prev_d
;
229 if (!adj_empty(cadj
, !n_ce
&& n_u
)) {
230 adj_b
= !n_ce
&& n_u
&& !n_na
&& n_j
== AD_B
;
232 w
= adj_fill(cadj
, !force
&& adj_b
, !force
&& fill
, buf
,
233 &ll
, &li
, <
, &els_neg
, &els_pos
);
237 if (!n_ns
|| w
|| els_neg
|| els_pos
) {
239 ren_line(buf
, w
, ll
, li
, lt
);
245 if (!ren_traps(prev_d
, n_d
, 0)) {
246 if (n_L
> n_v
&& (cdiv
|| n_d
< n_p
)) {
249 if (ren_pagelimit(0))
259 void tr_br(char **args
)
261 if (args
[0][0] == '.')
265 void tr_sp(char **args
)
268 if (args
[0][0] == '.')
271 down(args
[1] ? eval(args
[1], 'v') : n_v
);
274 void tr_sv(char **args
)
276 int n
= eval(args
[1], 'v');
278 if (n_d
+ n
< f_nexttrap())
284 void tr_ns(char **args
)
289 void tr_rs(char **args
)
294 void tr_os(char **args
)
301 void tr_mk(char **args
)
304 num_set(REG(args
[1][0], args
[1][1]), n_d
);
309 void tr_rt(char **args
)
311 int n
= args
[1] ? eval_re(args
[1], n_d
, 'v') : n_mk
;
312 if (n
>= 0 && n
< n_d
)
316 void tr_ne(char **args
)
318 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
319 if (!ren_traps(n_d
, n_d
+ n
- 1, 1))
323 void tr_bp(char **args
)
325 if (!cdiv
&& (args
[1] || !n_ns
)) {
328 if (args
[0][0] == '.')
329 in_pushnl(".br\n", NULL
);
332 bp_next
= eval_re(args
[1], n_pg
, 0);
336 void tr_pn(char **args
)
339 bp_next
= eval_re(args
[1], n_pg
, 0);
342 static void ren_ps(char *s
)
344 int ps
= !s
|| !*s
|| !strcmp("0", s
) ? n_s0
: eval_re(s
, n_s
, 0);
349 void tr_ps(char **args
)
354 void tr_ll(char **args
)
356 int ll
= args
[1] ? eval_re(args
[1], n_l
, 'm') : n_l0
;
362 void tr_in(char **args
)
364 int in
= args
[1] ? eval_re(args
[1], n_i
, 'm') : n_i0
;
365 if (args
[0][0] == '.')
373 void tr_ti(char **args
)
375 if (args
[0][0] == '.')
378 adj_ti(cadj
, eval_re(args
[1], n_i
, 'm'));
381 static void ren_ft(char *s
)
383 int fn
= !*s
|| !strcmp("P", s
) ? n_f0
: dev_font(s
);
390 void tr_ft(char **args
)
396 void tr_fp(char **args
)
400 if (dev_mnt(atoi(args
[1]), args
[2], args
[3] ? args
[3] : args
[2]) < 0)
401 errmsg("troff: failed to mount %s\n", args
[2]);
404 void tr_nf(char **args
)
406 if (args
[0][0] == '.')
411 void tr_fi(char **args
)
413 if (args
[0][0] == '.')
418 void tr_ce(char **args
)
420 if (args
[0][0] == '.')
422 n_ce
= args
[1] ? atoi(args
[1]) : 1;
425 static void escarg_ren(char *d
, int cmd
, int (*next
)(void), void (*back
)(int))
428 if (strchr(ESC_P
, cmd
)) {
430 if (cmd
== 's' && (c
== '-' || c
== '+')) {
439 if (cmd
== 's' && c
>= '1' && c
<= '3') {
448 if (strchr(ESC_Q
, cmd
)) {
462 static int nextchar(char *s
, int (*next
)(void))
470 for (i
= 1; i
< l
; i
++)
476 static void ren_cmd(struct adj
*adj
, int c
, char *arg
)
478 char draw_arg
[ILNLEN
];
484 adj_put(adj
, w
, "\\h'%du'", w
);
487 ren_bracket(adj
, arg
);
490 w
= out_draw(arg
, draw_arg
);
491 adj_put(adj
, w
, "\\D'%s'", draw_arg
);
494 adj_put(adj
, 0, "\\v'%du'", eval(".5m", 0));
501 adj_put(adj
, n
, "\\h'%du'", n
);
504 num_set(REG(arg
[0], arg
[1]), f_hpos() - n_lb
);
516 adj_put(adj
, 0, "\\v'%du'", eval("-1m", 0));
522 adj_put(adj
, 0, "\\v'%du'", eval("-.5m", 0));
525 adj_put(adj
, 0, "\\v'%du'", eval(arg
, 'v'));
528 adj_put(adj
, 0, "\\X'%s'", arg
);
531 adj_els(adj
, eval(arg
, 'v'));
534 g
= dev_glyph("0", n_f
);
535 w
= charwid(g
? g
->wid
: SC_DW
, n_s
);
536 adj_put(adj
, w
, "\\h'%du'", w
);
540 adj_put(adj
, w
, "\\h'%du'", w
);
543 w
= eval("1m/12", 0);
544 adj_put(adj
, w
, "\\h'%du'", w
);
552 /* read one character and place it inside adj buffer */
553 static int ren_char(struct adj
*adj
, int (*next
)(void), void (*back
)(int))
562 if (c
[0] == ' ' || c
[0] == '\n') {
563 adj_put(adj
, charwid(dev_spacewid(), n_s
), c
);
567 nextchar(c
+ 1, next
);
569 int l
= nextchar(c
+ 2, next
);
570 l
+= nextchar(c
+ 2 + l
, next
);
572 } else if (c
[1] == 'z') {
576 nextchar(c
+ 1, next
);
578 nextchar(c
+ 2, next
);
579 nextchar(c
+ strlen(c
), next
);
582 } else if (c
[1] == 'w') {
583 n
= ren_wid(next
, back
);
584 sprintf(widbuf
, "%d", n
);
585 in_push(widbuf
, NULL
);
587 } else if (strchr(" bDdfhkLlorsuvXxz0^|{}&", c
[1])) {
588 escarg_ren(arg
, c
[1], next
, back
);
589 ren_cmd(adj
, c
[1], arg
);
594 adj_swid(adj
, charwid(dev_spacewid(), n_s
));
595 adj_put(adj
, 0, "\\s(%02d", n_s
);
599 adj_put(adj
, 0, "\\f(%02d", n_f
);
602 g
= dev_glyph(c
, n_f
);
603 w
= charwid(g
? g
->wid
: SC_DW
, n_s
);
606 adj_put(adj
, -w
, "\\h'%du'", -w
);
607 return g
? g
->type
: 0;
610 /* read the argument of \w and push its width */
611 int ren_wid(int (*next
)(void), void (*back
)(int))
613 struct adj
*adj
= adj_alloc();
620 while (c
>= 0 && c
!= wid_c
) {
622 type
|= ren_char(adj
, next
, back
);
634 /* read characters from in.c and pass rendered lines to out.c */
640 ren_first(); /* transition to the first page */
643 if (c
== ' ' || c
== '\n') {
645 ren_char(cadj
, ren_next
, ren_back
);
647 while (adj_full(cadj
, !n_ce
&& n_u
))
649 if (c
== '\n') { /* end of input line */
650 n_lb
= adj_wid(cadj
);
651 n_ce
= MAX(0, n_ce
- 1);
653 if (c
!= ' ' && c
!= '\n') {
655 ren_char(cadj
, ren_next
, ren_back
);
664 static int tpos
[NTRAPS
]; /* trap positions */
665 static int treg
[NTRAPS
]; /* trap registers */
668 static int trap_first(int pos
)
672 for (i
= 0; i
< ntraps
; i
++)
673 if (treg
[i
] >= 0 && tpos
[i
] > pos
)
674 if (best
< 0 || tpos
[i
] < tpos
[best
])
679 static int trap_byreg(int reg
)
682 for (i
= 0; i
< ntraps
; i
++)
688 static int trap_bypos(int reg
, int pos
)
691 for (i
= 0; i
< ntraps
; i
++)
692 if (treg
[i
] >= 0 && tpos
[i
] == pos
)
693 if (reg
== -1 || treg
[i
] == reg
)
698 static int tpos_parse(char *s
)
700 int pos
= eval(s
, 'v');
701 return pos
>= 0 ? pos
: n_p
+ pos
;
704 void tr_wh(char **args
)
709 pos
= tpos_parse(args
[1]);
710 id
= trap_bypos(-1, pos
);
716 reg
= REG(args
[2][0], args
[2][1]);
725 void tr_ch(char **args
)
731 reg
= REG(args
[1][0], args
[1][1]);
732 id
= trap_byreg(reg
);
734 tpos
[id
] = args
[2] ? tpos_parse(args
[2]) : -1;
737 void tr_dt(char **args
)
742 cdiv
->tpos
= eval(args
[1], 'v');
743 cdiv
->treg
= REG(args
[2][0], args
[2][1]);
749 static int trap_pos(int pos
)
751 int ret
= trap_first(pos
);
753 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->tpos
: -1;
754 return ret
>= 0 ? tpos
[ret
] : -1;
757 static int trap_reg(int pos
)
759 int ret
= trap_first(pos
);
761 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->treg
: -1;
762 return ret
>= 0 ? treg
[ret
] : -1;
767 int pos
= trap_pos(n_d
);
769 return pos
>= 0 ? pos
: 0x7fffffff;
770 return pos
>= 0 && pos
< n_p
? pos
: n_p
- n_d
;