7 #define cadj env_adj() /* line buffer */
8 #define RENWB(wb) ((wb) == &ren_wb) /* is ren_wb */
12 struct sbuf sbuf
; /* diversion output */
13 int reg
; /* diversion register */
14 int tpos
; /* diversion trap position */
15 int treg
; /* diversion trap register */
16 int dl
; /* diversion width */
17 int prev_d
; /* previous \(.d value */
18 int prev_h
; /* previous \(.h value */
19 int prev_mk
; /* previous .mk internal register */
20 int prev_ns
; /* previous .ns value */
22 static struct div divs
[NPREV
]; /* diversion stack */
23 static struct div
*cdiv
; /* current diversion */
24 static int ren_div
; /* rendering a diversion */
25 static int trap_em
= -1; /* end macro */
27 static struct wb ren_wb
; /* the main ren.c word buffer */
28 static int ren_nl
; /* just after newline */
29 static int ren_cnl
; /* current char is a newline */
30 static int ren_unbuf
[8]; /* ren_back() buffer */
32 static int ren_fillreq
; /* \p request */
34 static int bp_first
= 1; /* prior to the first page */
35 static int bp_next
= 1; /* next page number */
36 static int bp_count
; /* number of pages so far */
37 static int bp_ejected
; /* current ejected page */
38 static int bp_final
; /* 1: executing em, 2: the final page, 3: the 2nd final page */
40 static int c_fa
; /* field delimiter */
41 static char c_fb
[GNLEN
]; /* field padding */
43 static int ren_next(void)
45 return ren_un
> 0 ? ren_unbuf
[--ren_un
] : tr_next();
48 static void ren_back(int c
)
50 ren_unbuf
[ren_un
++] = c
;
53 void tr_di(char **args
)
56 cdiv
= cdiv
? cdiv
+ 1 : divs
;
57 memset(cdiv
, 0, sizeof(*cdiv
));
58 sbuf_init(&cdiv
->sbuf
);
59 cdiv
->reg
= map(args
[1]);
61 if (args
[0][2] == 'a' && str_get(cdiv
->reg
)) /* .da */
62 sbuf_append(&cdiv
->sbuf
, str_get(cdiv
->reg
));
63 sbuf_printf(&cdiv
->sbuf
, "%c%s\n", c_cc
, TR_DIVBEG
);
73 sbuf_putnl(&cdiv
->sbuf
);
74 sbuf_printf(&cdiv
->sbuf
, "%c%s\n", c_cc
, TR_DIVEND
);
75 str_set(cdiv
->reg
, sbuf_buf(&cdiv
->sbuf
));
76 sbuf_done(&cdiv
->sbuf
);
83 cdiv
= cdiv
> divs
? cdiv
- 1 : NULL
;
89 return cdiv
? cdiv
->reg
: -1;
94 return adj_wid(cadj
) + wb_wid(&ren_wb
);
97 void tr_divbeg(char **args
)
103 void tr_divend(char **args
)
109 static int trap_reg(int pos
);
110 static int trap_pos(int pos
);
111 static void trap_exec(int reg
);
113 static void ren_page(int pg
, int force
)
115 if (!force
&& bp_final
>= 2)
125 if (trap_pos(-1) == 0)
126 trap_exec(trap_reg(-1));
129 static void ren_first(void)
131 if (bp_first
&& !cdiv
) {
133 ren_page(bp_next
, 1);
137 /* when nodiv, do not append .sp to diversions */
138 static void ren_sp(int n
, int nodiv
)
141 /* ignore .sp without arguments when reading diversions */
142 if (!n
&& ren_div
&& !n_u
)
147 if (cdiv
&& !nodiv
) {
148 sbuf_putnl(&cdiv
->sbuf
);
149 sbuf_printf(&cdiv
->sbuf
, "%csp %du\n", c_cc
, n
? n
: n_v
);
155 static void trap_exec(int reg
)
158 in_pushnl(str_get(reg
), NULL
);
161 static int detect_traps(int beg
, int end
)
163 int pos
= trap_pos(beg
);
164 return pos
>= 0 && (cdiv
|| pos
< n_p
) && pos
<= end
;
167 /* return 1 if executed a trap */
168 static int ren_traps(int beg
, int end
, int dosp
)
170 int pos
= trap_pos(beg
);
171 if (detect_traps(beg
, end
)) {
172 if (dosp
&& pos
> beg
)
173 ren_sp(pos
- beg
, 0);
174 trap_exec(trap_reg(beg
));
180 static int detect_pagelimit(int ne
)
182 return !cdiv
&& n_nl
+ ne
>= n_p
;
185 /* start a new page if needed */
186 static int ren_pagelimit(int ne
)
188 if (detect_pagelimit(ne
)) {
189 ren_page(bp_next
, 0);
195 static void down(int n
)
197 if (!ren_traps(n_d
, n_d
+ (n
? n
: n_v
), 1)) {
203 /* flush the given line and send it to out.c */
204 static void ren_line(char *s
, int w
, int ad
, int ll
, int li
, int lt
)
206 int ljust
= lt
>= 0 ? lt
: li
;
207 int llen
= ll
- ljust
;
210 ljust
+= llen
> w
? (llen
- w
) / 2 : 0;
217 sbuf_printf(&cdiv
->sbuf
, "%ch'%du'", c_ec
, ljust
);
218 sbuf_append(&cdiv
->sbuf
, s
);
220 out("H%d\n", n_o
+ ljust
);
226 static void ren_transparent(char *s
)
229 sbuf_printf(&cdiv
->sbuf
, "%s\n", s
);
234 /* return 1 if triggered a trap */
235 static int ren_bradj(struct adj
*adj
, int fill
, int ad
)
239 int ll
, li
, lt
, els_neg
, els_pos
;
242 if (!adj_empty(adj
, fill
)) {
244 w
= adj_fill(adj
, ad
== AD_B
, fill
, n_hy
, &sbuf
,
245 &ll
, &li
, <
, &els_neg
, &els_pos
);
249 if (!n_ns
|| !sbuf_empty(&sbuf
) || els_neg
|| els_pos
) {
251 ren_line(sbuf_buf(&sbuf
), w
, ad
, ll
, li
, lt
);
258 lspc
= MAX(1, n_L
) * n_v
- n_v
;
259 if (detect_traps(prev_d
, n_d
) || detect_pagelimit(lspc
)) {
260 sprintf(cmd
, "%c&", c_ec
);
261 if (!ren_cnl
) /* prevent unwanted newlines */
263 if (!ren_traps(prev_d
, n_d
, 0))
273 /* return 1 if triggered a trap */
274 static int ren_br(int force
)
276 return ren_bradj(cadj
, !force
&& !n_ce
&& n_u
,
277 n_ce
? AD_C
: (n_u
&& !n_na
&& (n_j
!= AD_B
|| !force
) ? n_j
: AD_L
));
280 void tr_br(char **args
)
282 if (args
[0][0] == c_cc
)
286 void tr_sp(char **args
)
289 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
290 if (args
[0][0] == c_cc
)
292 if (n
&& !n_ns
&& !traps
)
296 void tr_sv(char **args
)
298 int n
= eval(args
[1], 'v');
300 if (n_d
+ n
< f_nexttrap())
306 void tr_ns(char **args
)
311 void tr_rs(char **args
)
316 void tr_os(char **args
)
323 void tr_mk(char **args
)
326 num_set(map(args
[1]), n_d
);
331 void tr_rt(char **args
)
333 int n
= args
[1] ? eval_re(args
[1], n_d
, 'v') : n_mk
;
334 if (n
>= 0 && n
< n_d
)
338 void tr_ne(char **args
)
340 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
341 if (!ren_traps(n_d
, n_d
+ n
- 1, 1))
345 static void push_eject(void)
348 bp_ejected
= bp_count
;
349 sprintf(buf
, "%c%s %d\n", c_cc
, TR_EJECT
, bp_ejected
);
350 in_pushnl(buf
, NULL
);
353 static void push_br(void)
355 char br
[8] = {c_cc
, 'b', 'r', '\n'};
359 static void ren_eject(int id
)
361 if (id
== bp_ejected
&& id
== bp_count
&& !cdiv
) {
362 if (detect_traps(n_d
, n_p
)) {
364 ren_traps(n_d
, n_p
, 1);
367 ren_page(bp_next
, 0);
372 void tr_eject(char **args
)
374 ren_eject(atoi(args
[1]));
377 void tr_bp(char **args
)
379 if (!cdiv
&& (args
[1] || !n_ns
)) {
380 if (bp_ejected
!= bp_count
)
382 if (args
[0][0] == c_cc
)
385 bp_next
= eval_re(args
[1], n_pg
, 0);
389 void tr_pn(char **args
)
392 bp_next
= eval_re(args
[1], n_pg
, 0);
395 static void ren_ps(char *s
)
397 int ps
= !s
|| !*s
|| !strcmp("0", s
) ? n_s0
: eval_re(s
, n_s
, 0);
402 void tr_ps(char **args
)
407 void tr_ll(char **args
)
409 int ll
= args
[1] ? eval_re(args
[1], n_l
, 'm') : n_l0
;
415 void tr_in(char **args
)
417 int in
= args
[1] ? eval_re(args
[1], n_i
, 'm') : n_i0
;
418 if (args
[0][0] == c_cc
)
426 void tr_ti(char **args
)
428 if (args
[0][0] == c_cc
)
431 adj_ti(cadj
, eval_re(args
[1], n_i
, 'm'));
434 static void ren_ft(char *s
)
436 int fn
= !s
|| !*s
|| !strcmp("P", s
) ? n_f0
: dev_pos(s
);
443 void tr_ft(char **args
)
448 void tr_fp(char **args
)
452 if (dev_mnt(atoi(args
[1]), args
[2], args
[3] ? args
[3] : args
[2]) < 0)
453 errmsg("troff: failed to mount %s\n", args
[2]);
456 void tr_nf(char **args
)
458 if (args
[0][0] == c_cc
)
463 void tr_fi(char **args
)
465 if (args
[0][0] == c_cc
)
470 void tr_ce(char **args
)
472 if (args
[0][0] == c_cc
)
474 n_ce
= args
[1] ? atoi(args
[1]) : 1;
477 void tr_fc(char **args
)
481 strcpy(c_fb
, args
[2] ? args
[2] : " ");
488 static void ren_m(char *s
)
490 int m
= !s
|| !*s
? n_m0
: clr_get(s
);
495 static void escarg_ren(char *d
, int cmd
, int (*next
)(void), void (*back
)(int))
499 if (strchr(ESC_P
, cmd
)) {
501 if (cmd
== 's' && (c
== '-' || c
== '+')) {
508 } else if (!n_cp
&& c
== '[') {
510 while (c
> 0 && c
!= '\n' && c
!= ']') {
516 if (cmd
== 's' && c
>= '1' && c
<= '3') {
525 if (strchr(ESC_Q
, cmd
)) {
526 schar_read(delim
, next
);
527 while (schar_jump(delim
, next
, back
)) {
528 if ((c
= next()) < 0)
536 static int nextchar(char *s
, int (*next
)(void))
544 for (i
= 1; i
< l
; i
++)
550 static void ren_cmd(struct wb
*wb
, int c
, char *arg
)
555 wb_hmov(wb
, charwid(dev_spacewid(), n_s
));
558 ren_bracket(wb
, arg
);
567 wb_vmov(wb
, SC_EM
/ 2);
573 wb_hmov(wb
, eval(arg
, 'm'));
576 num_set(map(arg
), RENWB(wb
) ? f_hpos() - n_lb
: wb_wid(wb
));
601 wb_vmov(wb
, -SC_EM
/ 2);
604 wb_vmov(wb
, eval(arg
, 'v'));
610 wb_els(wb
, eval(arg
, 'v'));
613 g
= dev_glyph("0", n_f
);
614 wb_hmov(wb
, charwid(g
? g
->wid
: SC_DW
, n_s
));
617 wb_hmov(wb
, SC_EM
/ 6);
623 wb_hmov(wb
, SC_EM
/ 12);
631 static void ren_field(struct wb
*wb
, int (*next
)(void), void (*back
)(int));
633 /* read one character and place it inside wb buffer */
634 void ren_char(struct wb
*wb
, int (*next
)(void), void (*back
)(int))
641 if (c
[0] == ' ' || c
[0] == '\n') {
645 if (c
[0] == '\t' || c
[0] == '\x01') {
646 n
= RENWB(wb
) ? f_hpos() : wb_wid(wb
);
647 wb_hmov(wb
, tab_next(n
) - n
);
651 ren_field(wb
, next
, back
);
655 nextchar(c
+ 1, next
);
657 l
= nextchar(c
+ 2, next
);
658 l
+= nextchar(c
+ 2 + l
, next
);
660 } else if (!n_cp
&& c
[1] == '[') {
663 while (n
>= 0 && n
!= '\n' && n
!= ']' && l
< GNLEN
- 1) {
668 } else if (c
[1] == 'z') {
670 ren_char(wb
, next
, back
);
671 wb_hmov(wb
, w
- wb_wid(wb
));
673 } else if (c
[1] == '!') {
674 if (ren_nl
&& next
== ren_next
) {
677 while (n
>= 0 && n
!= '\n') {
682 ren_transparent(arg
);
685 } else if (strchr(" bCcDdfhkLlmoprsuvXxz0^|{}&", c
[1])) {
686 escarg_ren(arg
, c
[1], next
, back
);
688 ren_cmd(wb
, c
[1], arg
);
695 nextchar(c
+ 1, next
);
696 if (!n_lg
|| wb_lig(wb
, c
)) {
703 /* read the argument of \w and push its width */
704 int ren_wid(int (*next
)(void), void (*back
)(int))
710 schar_read(delim
, next
);
713 while (c
>= 0 && c
!= '\n') {
715 if (!schar_jump(delim
, next
, back
))
717 ren_char(&wb
, next
, back
);
722 wb_wconf(&wb
, &n_ct
, &n_st
, &n_sb
);
727 /* return 1 if the ending character (ec) was read */
728 static int ren_until(struct wb
*wb
, char *delim
, int ec
,
729 int (*next
)(void), void (*back
)(int))
733 while (c
>= 0 && c
!= '\n' && c
!= ec
) {
735 if (!schar_jump(delim
, next
, back
))
737 ren_char(wb
, next
, back
);
745 static void wb_cpy(struct wb
*dst
, struct wb
*src
, int left
)
747 wb_hmov(dst
, left
- wb_wid(dst
));
751 void ren_tl(int (*next
)(void), void (*back
)(int))
759 schar_read(delim
, next
);
760 /* the left-adjusted string */
761 ren_until(&wb2
, delim
, '\n', next
, back
);
762 wb_cpy(&wb
, &wb2
, 0);
763 /* the centered string */
764 ren_until(&wb2
, delim
, '\n', next
, back
);
765 wb_cpy(&wb
, &wb2
, (n_lt
- wb_wid(&wb2
)) / 2);
766 /* the right-adjusted string */
767 ren_until(&wb2
, delim
, '\n', next
, back
);
768 wb_cpy(&wb
, &wb2
, n_lt
- wb_wid(&wb2
));
769 /* flushing the line */
773 ren_bradj(adj
, 0, AD_L
);
779 static void ren_field(struct wb
*wb
, int (*next
)(void), void (*back
)(int))
781 struct wb wbs
[NFIELDS
];
784 int left
, right
, cur_left
;
786 while (n
< LEN(wbs
)) {
788 if (ren_until(&wbs
[n
++], c_fb
, c_fa
, next
, back
))
791 left
= RENWB(wb
) ? f_hpos() : wb_wid(wb
);
792 right
= tab_next(left
);
793 for (i
= 0; i
< n
; i
++)
794 wid
+= wb_wid(&wbs
[i
]);
795 pad
= (right
- left
- wid
) / (n
> 1 ? n
- 1 : 1);
796 rem
= (right
- left
- wid
) % (n
> 1 ? n
- 1 : 1);
797 for (i
= 0; i
< n
; i
++) {
801 cur_left
= right
- wb_wid(&wbs
[i
]);
803 cur_left
= wb_wid(wb
) + pad
+ (i
+ rem
>= n
);
804 wb_cpy(wb
, &wbs
[i
], cur_left
);
809 /* read characters from in.c and pass rendered lines to out.c */
812 struct wb
*wb
= &ren_wb
;
818 ren_first(); /* transition to the first page */
824 if (bp_final
== 0 && trap_em
>= 0) {
837 /* add wb (the current word) to cadj */
838 if (c
== ' ' || c
== '\n') {
839 adj_swid(cadj
, charwid(dev_spacewid(), n_s
));
840 if (!wb_part(wb
)) { /* not after a \c */
842 fillreq
= ren_fillreq
;
850 while ((fillreq
&& !n_ce
&& n_u
) || adj_full(cadj
, !n_ce
&& n_u
)) {
854 if (c
== '\n' || ren_nl
) /* end or start of input line */
856 if (c
== '\n' && !wb_part(wb
))
857 n_ce
= MAX(0, n_ce
- 1);
860 ren_char(wb
, ren_next
, ren_back
);
861 if (c
!= '\n' && wb_empty(wb
))
868 if (!adj_empty(cadj
, 0))
869 ren_page(bp_next
, 1);
876 #define tposval(i) (tpos[i] < 0 ? n_p + tpos[i] : tpos[i])
878 static int tpos
[NTRAPS
]; /* trap positions */
879 static int treg
[NTRAPS
]; /* trap registers */
882 static int trap_first(int pos
)
886 for (i
= 0; i
< ntraps
; i
++)
887 if (treg
[i
] >= 0 && tposval(i
) > pos
)
888 if (best
< 0 || tposval(i
) < tposval(best
))
893 static int trap_byreg(int reg
)
896 for (i
= 0; i
< ntraps
; i
++)
902 static int trap_bypos(int reg
, int pos
)
905 for (i
= 0; i
< ntraps
; i
++)
906 if (treg
[i
] >= 0 && tposval(i
) == pos
)
907 if (reg
== -1 || treg
[i
] == reg
)
912 void tr_wh(char **args
)
917 pos
= eval(args
[1], 'v');
918 id
= trap_bypos(-1, pos
);
933 void tr_ch(char **args
)
940 id
= trap_byreg(reg
);
942 tpos
[id
] = args
[2] ? eval(args
[2], 'v') : -1;
945 void tr_dt(char **args
)
950 cdiv
->tpos
= eval(args
[1], 'v');
951 cdiv
->treg
= map(args
[2]);
957 void tr_em(char **args
)
959 trap_em
= args
[1] ? map(args
[1]) : -1;
962 static int trap_pos(int pos
)
964 int ret
= trap_first(pos
);
968 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->tpos
: -1;
969 return ret
>= 0 ? tposval(ret
) : -1;
972 static int trap_reg(int pos
)
974 int ret
= trap_first(pos
);
976 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->treg
: -1;
977 return ret
>= 0 ? treg
[ret
] : -1;
982 int pos
= trap_pos(n_d
);
984 return pos
>= 0 ? pos
: 0x7fffffff;
985 return (pos
>= 0 && pos
< n_p
? pos
: n_p
) - n_d
;