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_div
; /* rendering a diversion */
25 static struct wb ren_wb
; /* the main ren.c word buffer */
26 static int ren_nl
; /* just after newline */
27 static int ren_unbuf
[8]; /* ren_back() buffer */
30 static int bp_first
= 1; /* prior to the first page */
31 static int bp_next
= 1; /* next page number */
32 static int bp_force
; /* execute the traps until the next page */
34 static int c_fa
; /* field delimiter */
35 static char c_fb
[GNLEN
]; /* field padding */
37 static int ren_next(void)
39 return ren_un
> 0 ? ren_unbuf
[--ren_un
] : tr_next();
42 static void ren_back(int c
)
44 ren_unbuf
[ren_un
++] = c
;
47 void tr_di(char **args
)
50 cdiv
= cdiv
? cdiv
+ 1 : divs
;
51 memset(cdiv
, 0, sizeof(*cdiv
));
52 sbuf_init(&cdiv
->sbuf
);
53 cdiv
->reg
= REG(args
[1][0], args
[1][1]);
55 if (args
[0][2] == 'a' && str_get(cdiv
->reg
)) /* .da */
56 sbuf_append(&cdiv
->sbuf
, str_get(cdiv
->reg
));
57 sbuf_printf(&cdiv
->sbuf
, "%c%s\n", c_cc
, DIV_BEG
);
67 sbuf_putnl(&cdiv
->sbuf
);
68 sbuf_printf(&cdiv
->sbuf
, "%c%s\n", c_cc
, DIV_END
);
69 str_set(cdiv
->reg
, sbuf_buf(&cdiv
->sbuf
));
70 sbuf_done(&cdiv
->sbuf
);
77 cdiv
= cdiv
> divs
? cdiv
- 1 : NULL
;
83 return cdiv
? cdiv
->reg
: -1;
88 return adj_wid(cadj
) + wb_wid(&ren_wb
);
91 void tr_divbeg(char **args
)
97 void tr_divend(char **args
)
103 static int trap_reg(int pos
);
104 static int trap_pos(int pos
);
105 static void trap_exec(int reg
);
107 static void ren_page(int pg
)
116 if (trap_pos(-1) == 0)
117 trap_exec(trap_reg(-1));
120 static void ren_first(void)
122 if (bp_first
&& !cdiv
) {
128 static void ren_sp(int n
)
132 if (!n
&& ren_div
&& !n_u
)
138 sbuf_putnl(&cdiv
->sbuf
);
139 sprintf(cmd
, "'sp %du\n", n
? n
: n_v
);
140 sbuf_append(&cdiv
->sbuf
, cmd
);
146 static void push_ne(void)
149 sprintf(buf
, "%cne %du\n", c_cc
, n_p
);
150 in_pushnl(buf
, NULL
);
153 static void trap_exec(int reg
)
158 in_pushnl(str_get(reg
), NULL
);
161 /* return 1 if executed a trap */
162 static int ren_traps(int beg
, int end
, int dosp
)
164 int pos
= trap_pos(beg
);
165 if (pos
>= 0 && (cdiv
|| pos
< n_p
) && pos
<= end
) {
166 if (dosp
&& pos
> beg
)
168 trap_exec(trap_reg(beg
));
174 /* start a new page if needed */
175 static int ren_pagelimit(int ne
)
177 if (n_nl
+ ne
>= n_p
&& !cdiv
) {
185 static void down(int n
)
187 if (!ren_traps(n_d
, n_d
+ (n
? n
: n_v
), 1)) {
193 /* flush the given line and send it to out.c */
194 static void ren_line(char *s
, int w
, int ad
, int ll
, int li
, int lt
)
198 int llen
= ll
- (lt
>= 0 ? lt
: li
);
201 ljust
= llen
> w
? (llen
- w
) / 2 : 0;
207 ljust
+= lt
>= 0 ? lt
: li
;
209 sprintf(cmd
, "%ch'%du'", c_ec
, ljust
);
210 sbuf_append(&cdiv
->sbuf
, cmd
);
212 sbuf_append(&cdiv
->sbuf
, s
);
214 out("H%d\n", n_o
+ (lt
>= 0 ? lt
: li
) + ljust
);
220 static void ren_transparent(char *s
)
223 sbuf_printf(&cdiv
->sbuf
, "%s\n", s
);
228 /* return 1 if triggered a trap */
229 static int ren_bradj(struct adj
*adj
, int fill
, int ad
)
232 int ll
, li
, lt
, els_neg
, els_pos
;
235 if (!adj_empty(adj
, fill
)) {
237 w
= adj_fill(adj
, ad
== AD_B
, fill
, &sbuf
,
238 &ll
, &li
, <
, &els_neg
, &els_pos
);
242 if (!n_ns
|| w
|| els_neg
|| els_pos
) {
244 ren_line(sbuf_buf(&sbuf
), w
, ad
, ll
, li
, lt
);
251 if (!ren_traps(prev_d
, n_d
, 0)) {
252 if (n_L
> 1 && (cdiv
|| n_d
< n_p
)) {
253 down(n_L
* n_v
- n_v
);
255 if (ren_pagelimit(0))
265 /* return 1 if triggered a trap */
266 static int ren_br(int force
)
268 return ren_bradj(cadj
, !force
&& !n_ce
&& n_u
,
269 n_ce
? AD_C
: (n_u
&& !n_na
&& (n_j
!= AD_B
|| !force
) ? n_j
: AD_L
));
272 void tr_br(char **args
)
274 if (args
[0][0] == c_cc
)
278 void tr_sp(char **args
)
281 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
282 if (args
[0][0] == c_cc
)
284 if (n
&& !n_ns
&& !traps
)
288 void tr_sv(char **args
)
290 int n
= eval(args
[1], 'v');
292 if (n_d
+ n
< f_nexttrap())
298 void tr_ns(char **args
)
303 void tr_rs(char **args
)
308 void tr_os(char **args
)
315 void tr_mk(char **args
)
318 num_set(REG(args
[1][0], args
[1][1]), n_d
);
323 void tr_rt(char **args
)
325 int n
= args
[1] ? eval_re(args
[1], n_d
, 'v') : n_mk
;
326 if (n
>= 0 && n
< n_d
)
330 void tr_ne(char **args
)
332 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
333 if (!ren_traps(n_d
, n_d
+ n
- 1, 1))
337 void tr_bp(char **args
)
339 char br
[] = {c_cc
, 'b', 'r', '\n'};
340 if (!cdiv
&& (args
[1] || !n_ns
)) {
343 if (args
[0][0] == c_cc
)
347 bp_next
= eval_re(args
[1], n_pg
, 0);
351 void tr_pn(char **args
)
354 bp_next
= eval_re(args
[1], n_pg
, 0);
357 static void ren_ps(char *s
)
359 int ps
= !s
|| !*s
|| !strcmp("0", s
) ? n_s0
: eval_re(s
, n_s
, 0);
364 void tr_ps(char **args
)
369 void tr_ll(char **args
)
371 int ll
= args
[1] ? eval_re(args
[1], n_l
, 'm') : n_l0
;
377 void tr_in(char **args
)
379 int in
= args
[1] ? eval_re(args
[1], n_i
, 'm') : n_i0
;
380 if (args
[0][0] == c_cc
)
388 void tr_ti(char **args
)
390 if (args
[0][0] == c_cc
)
393 adj_ti(cadj
, eval_re(args
[1], n_i
, 'm'));
396 static void ren_ft(char *s
)
398 int fn
= !*s
|| !strcmp("P", s
) ? n_f0
: dev_font(s
);
405 void tr_ft(char **args
)
411 void tr_fp(char **args
)
415 if (dev_mnt(atoi(args
[1]), args
[2], args
[3] ? args
[3] : args
[2]) < 0)
416 errmsg("troff: failed to mount %s\n", args
[2]);
419 void tr_nf(char **args
)
421 if (args
[0][0] == c_cc
)
426 void tr_fi(char **args
)
428 if (args
[0][0] == c_cc
)
433 void tr_ce(char **args
)
435 if (args
[0][0] == c_cc
)
437 n_ce
= args
[1] ? atoi(args
[1]) : 1;
440 void tr_fc(char **args
)
444 strcpy(c_fb
, args
[2] ? args
[2] : " ");
451 static void escarg_ren(char *d
, int cmd
, int (*next
)(void), void (*back
)(int))
455 if (strchr(ESC_P
, cmd
)) {
457 if (cmd
== 's' && (c
== '-' || c
== '+')) {
466 if (cmd
== 's' && c
>= '1' && c
<= '3') {
475 if (strchr(ESC_Q
, cmd
)) {
476 schar_read(delim
, next
);
477 while (schar_jump(delim
, next
, back
)) {
478 if ((c
= next()) < 0)
486 static int nextchar(char *s
, int (*next
)(void))
494 for (i
= 1; i
< l
; i
++)
500 static void ren_cmd(struct wb
*wb
, int c
, char *arg
)
505 wb_hmov(wb
, charwid(dev_spacewid(), n_s
));
508 ren_bracket(wb
, arg
);
517 wb_vmov(wb
, SC_EM
/ 2);
523 wb_hmov(wb
, eval(arg
, 'm'));
526 num_set(REG(arg
[0], arg
[1]),
527 wb
== &ren_wb
? f_hpos() - n_lb
: wb_wid(wb
));
545 wb_vmov(wb
, -SC_EM
/ 2);
548 wb_vmov(wb
, eval(arg
, 'v'));
554 wb_els(wb
, eval(arg
, 'v'));
557 g
= dev_glyph("0", n_f
);
558 wb_hmov(wb
, charwid(g
? g
->wid
: SC_DW
, n_s
));
561 wb_hmov(wb
, SC_EM
/ 6);
564 wb_hmov(wb
, SC_EM
/ 12);
572 static void ren_field(struct wb
*wb
, int (*next
)(void), void (*back
)(int));
574 /* read one character and place it inside wb buffer */
575 void ren_char(struct wb
*wb
, int (*next
)(void), void (*back
)(int))
582 if (c
[0] == ' ' || c
[0] == '\n') {
586 if (c
[0] == '\t' || c
[0] == '\x01') {
587 n
= wb
== &ren_wb
? f_hpos() : wb_wid(wb
);
588 wb_hmov(wb
, tab_next(n
) - n
);
592 ren_field(wb
, next
, back
);
596 nextchar(c
+ 1, next
);
598 int l
= nextchar(c
+ 2, next
);
599 l
+= nextchar(c
+ 2 + l
, next
);
601 } else if (c
[1] == 'z') {
603 ren_char(wb
, next
, back
);
604 wb_hmov(wb
, w
- wb_wid(wb
));
606 } else if (c
[1] == '!') {
607 if (ren_nl
&& next
== ren_next
) {
610 while (n
>= 0 && n
!= '\n') {
615 ren_transparent(arg
);
618 } else if (strchr(" bcDdfhkLlorsuvXxz0^|{}&", c
[1])) {
619 escarg_ren(arg
, c
[1], next
, back
);
620 ren_cmd(wb
, c
[1], arg
);
625 nextchar(c
+ 1, next
);
629 /* read the argument of \w and push its width */
630 int ren_wid(int (*next
)(void), void (*back
)(int))
636 schar_read(delim
, next
);
639 while (c
>= 0 && c
!= '\n') {
641 if (!schar_jump(delim
, next
, back
))
643 ren_char(&wb
, next
, back
);
648 wb_wconf(&wb
, &n_ct
, &n_st
, &n_sb
);
653 /* return 1 if the ending character (ec) was read */
654 static int ren_until(struct wb
*wb
, char *delim
, int ec
,
655 int (*next
)(void), void (*back
)(int))
659 while (c
>= 0 && c
!= '\n' && c
!= ec
) {
661 if (!schar_jump(delim
, next
, back
))
663 ren_char(wb
, next
, back
);
671 static void wb_cpy(struct wb
*dst
, struct wb
*src
, int left
)
673 wb_hmov(dst
, left
- wb_wid(dst
));
677 void ren_tl(int (*next
)(void), void (*back
)(int))
685 schar_read(delim
, next
);
686 /* the left-adjusted string */
687 ren_until(&wb2
, delim
, '\n', next
, back
);
688 wb_cpy(&wb
, &wb2
, 0);
689 /* the centered string */
690 ren_until(&wb2
, delim
, '\n', next
, back
);
691 wb_cpy(&wb
, &wb2
, (n_lt
- wb_wid(&wb2
)) / 2);
692 /* the right-adjusted string */
693 ren_until(&wb2
, delim
, '\n', next
, back
);
694 wb_cpy(&wb
, &wb2
, n_lt
- wb_wid(&wb2
));
695 /* flushing the line */
699 ren_bradj(adj
, 0, AD_L
);
705 static void ren_field(struct wb
*wb
, int (*next
)(void), void (*back
)(int))
707 struct wb wbs
[NFIELDS
];
710 int left
, right
, cur_left
;
712 while (n
< LEN(wbs
)) {
714 if (ren_until(&wbs
[n
++], c_fb
, c_fa
, next
, back
))
717 left
= wb
== &ren_wb
? f_hpos() : wb_wid(wb
);
718 right
= tab_next(left
);
719 for (i
= 0; i
< n
; i
++)
720 wid
+= wb_wid(&wbs
[i
]);
721 pad
= (right
- left
- wid
) / (n
> 1 ? n
- 1 : 1);
722 rem
= (right
- left
- wid
) % (n
> 1 ? n
- 1 : 1);
723 for (i
= 0; i
< n
; i
++) {
727 cur_left
= right
- wb_wid(&wbs
[i
]);
729 cur_left
= wb_wid(wb
) + pad
+ (i
+ rem
>= n
);
730 wb_cpy(wb
, &wbs
[i
], cur_left
);
735 /* read characters from in.c and pass rendered lines to out.c */
738 struct wb
*wb
= &ren_wb
;
743 ren_first(); /* transition to the first page */
746 if (c
== ' ' || c
== '\n') {
747 adj_swid(cadj
, charwid(dev_spacewid(), n_s
));
756 while (adj_full(cadj
, !n_ce
&& n_u
))
758 if (c
== '\n' || ren_nl
) /* end or start of input line */
760 if (c
== '\n' && !wb_part(wb
))
761 n_ce
= MAX(0, n_ce
- 1);
764 ren_char(wb
, ren_next
, ren_back
);
775 static int tpos
[NTRAPS
]; /* trap positions */
776 static int treg
[NTRAPS
]; /* trap registers */
779 static int trap_first(int pos
)
783 for (i
= 0; i
< ntraps
; i
++)
784 if (treg
[i
] >= 0 && tpos
[i
] > pos
)
785 if (best
< 0 || tpos
[i
] < tpos
[best
])
790 static int trap_byreg(int reg
)
793 for (i
= 0; i
< ntraps
; i
++)
799 static int trap_bypos(int reg
, int pos
)
802 for (i
= 0; i
< ntraps
; i
++)
803 if (treg
[i
] >= 0 && tpos
[i
] == pos
)
804 if (reg
== -1 || treg
[i
] == reg
)
809 static int tpos_parse(char *s
)
811 int pos
= eval(s
, 'v');
812 return pos
>= 0 ? pos
: n_p
+ pos
;
815 void tr_wh(char **args
)
820 pos
= tpos_parse(args
[1]);
821 id
= trap_bypos(-1, pos
);
827 reg
= REG(args
[2][0], args
[2][1]);
836 void tr_ch(char **args
)
842 reg
= REG(args
[1][0], args
[1][1]);
843 id
= trap_byreg(reg
);
845 tpos
[id
] = args
[2] ? tpos_parse(args
[2]) : -1;
848 void tr_dt(char **args
)
853 cdiv
->tpos
= eval(args
[1], 'v');
854 cdiv
->treg
= REG(args
[2][0], args
[2][1]);
860 static int trap_pos(int pos
)
862 int ret
= trap_first(pos
);
864 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->tpos
: -1;
865 return ret
>= 0 ? tpos
[ret
] : -1;
868 static int trap_reg(int pos
)
870 int ret
= trap_first(pos
);
872 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->treg
: -1;
873 return ret
>= 0 ? treg
[ret
] : -1;
878 int pos
= trap_pos(n_d
);
880 return pos
>= 0 ? pos
: 0x7fffffff;
881 return (pos
>= 0 && pos
< n_p
? pos
: n_p
) - n_d
;