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 \n(.d value */
18 int prev_h
; /* previous \n(.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 */
33 static int ren_aborted
; /* .ab executed */
35 static int bp_first
= 1; /* prior to the first page */
36 static int bp_next
= 1; /* next page number */
37 static int bp_count
; /* number of pages so far */
38 static int bp_ejected
; /* current ejected page */
39 static int bp_final
; /* 1: executing em, 2: the final page, 3: the 2nd final page */
41 static int c_fa
; /* field delimiter */
42 static char c_fb
[GNLEN
]; /* field padding */
44 static int ren_next(void)
46 return ren_un
> 0 ? ren_unbuf
[--ren_un
] : tr_next();
49 static void ren_back(int c
)
51 ren_unbuf
[ren_un
++] = c
;
54 void tr_di(char **args
)
57 cdiv
= cdiv
? cdiv
+ 1 : divs
;
58 memset(cdiv
, 0, sizeof(*cdiv
));
59 sbuf_init(&cdiv
->sbuf
);
60 cdiv
->reg
= map(args
[1]);
62 if (args
[0][2] == 'a' && str_get(cdiv
->reg
)) /* .da */
63 sbuf_append(&cdiv
->sbuf
, str_get(cdiv
->reg
));
64 sbuf_printf(&cdiv
->sbuf
, "%c%s\n", c_cc
, TR_DIVBEG
);
74 sbuf_putnl(&cdiv
->sbuf
);
75 sbuf_printf(&cdiv
->sbuf
, "%c%s\n", c_cc
, TR_DIVEND
);
76 str_set(cdiv
->reg
, sbuf_buf(&cdiv
->sbuf
));
77 sbuf_done(&cdiv
->sbuf
);
84 cdiv
= cdiv
> divs
? cdiv
- 1 : NULL
;
88 int charwid_base(int fn
, int sz
, int wid
)
90 /* the original troff rounds the widths up */
91 return (wid
* sz
+ dev_uwid
/ 2) / dev_uwid
;
94 int charwid(int fn
, int sz
, int wid
)
97 return dev_getcs(n_f
) * SC_EM
/ 36;
98 return charwid_base(fn
, sz
, wid
) +
99 (dev_getbd(fn
) ? dev_getbd(fn
) - 1 : 0);
102 int spacewid(int fn
, int sz
)
104 return charwid(fn
, sz
, (dev_font(fn
)->spacewid
* n_ss
+ 6) / 12);
109 return cdiv
? cdiv
->reg
: -1;
114 return adj_wid(cadj
) + wb_wid(&ren_wb
);
117 void tr_divbeg(char **args
)
123 void tr_divend(char **args
)
129 static int trap_reg(int pos
);
130 static int trap_pos(int pos
);
131 static void trap_exec(int reg
);
133 static void ren_page(int pg
, int force
)
135 if (!force
&& bp_final
>= 2)
145 if (trap_pos(-1) == 0)
146 trap_exec(trap_reg(-1));
149 static void ren_first(void)
151 if (bp_first
&& !cdiv
) {
153 ren_page(bp_next
, 1);
157 /* when nodiv, do not append .sp to diversions */
158 static void ren_sp(int n
, int nodiv
)
161 /* ignore .sp without arguments when reading diversions */
162 if (!n
&& ren_div
&& !n_u
)
167 if (cdiv
&& !nodiv
) {
168 sbuf_putnl(&cdiv
->sbuf
);
169 sbuf_printf(&cdiv
->sbuf
, "%csp %du\n", c_cc
, n
? n
: n_v
);
175 static void trap_exec(int reg
)
178 in_pushnl(str_get(reg
), NULL
);
181 static int detect_traps(int beg
, int end
)
183 int pos
= trap_pos(beg
);
184 return pos
>= 0 && (cdiv
|| pos
< n_p
) && pos
<= end
;
187 /* return 1 if executed a trap */
188 static int ren_traps(int beg
, int end
, int dosp
)
190 int pos
= trap_pos(beg
);
191 if (detect_traps(beg
, end
)) {
192 if (dosp
&& pos
> beg
)
193 ren_sp(pos
- beg
, 0);
194 trap_exec(trap_reg(beg
));
200 static int detect_pagelimit(int ne
)
202 return !cdiv
&& n_nl
+ ne
>= n_p
;
205 /* start a new page if needed */
206 static int ren_pagelimit(int ne
)
208 if (detect_pagelimit(ne
)) {
209 ren_page(bp_next
, 0);
215 static void down(int n
)
217 if (!ren_traps(n_d
, n_d
+ (n
? n
: n_v
), 1)) {
223 /* line adjustment */
224 static int ren_ljust(struct sbuf
*spre
, int w
, int ad
, int ll
, int li
, int lt
)
226 int ljust
= lt
>= 0 ? lt
: li
;
227 int llen
= ll
- ljust
;
230 ljust
+= llen
> w
? (llen
- w
) / 2 : 0;
234 sbuf_printf(spre
, "%ch'%du'", c_ec
, ljust
);
235 if (cdiv
&& cdiv
->dl
< w
)
240 /* append the line to the current diversion or send it to out.c */
241 static void ren_line(struct sbuf
*spre
, struct sbuf
*sbuf
)
244 if (!sbuf_empty(spre
))
245 sbuf_append(&cdiv
->sbuf
, sbuf_buf(spre
));
246 sbuf_append(&cdiv
->sbuf
, sbuf_buf(sbuf
));
250 if (!sbuf_empty(spre
))
251 out_line(sbuf_buf(spre
));
252 out_line(sbuf_buf(sbuf
));
256 static void ren_transparent(char *s
)
259 sbuf_printf(&cdiv
->sbuf
, "%s\n", s
);
264 static int zwid(void)
266 struct glyph
*g
= dev_glyph("0", n_f
);
267 return charwid(n_f
, n_s
, g
? g
->wid
: SC_DW
);
270 /* append the line number to the output line */
271 static void ren_lnum(struct sbuf
*spre
)
278 if (n_nn
<= 0 && (n_ln
% n_nM
) == 0)
279 sprintf(num
, "%d", n_ln
);
280 wb_hmov(&wb
, n_nI
* zwid());
282 wb_hmov(&wb
, (3 - strlen(num
)) * zwid());
287 wb_hmov(&wb
, n_nS
* zwid());
288 sbuf_append(spre
, sbuf_buf(&wb
.sbuf
));
296 /* append margin character */
297 static void ren_mc(struct sbuf
*sbuf
, int w
, int ljust
)
301 if (w
+ ljust
< n_l
+ n_mcn
)
302 wb_hmov(&wb
, n_l
+ n_mcn
- w
- ljust
);
304 sbuf_append(sbuf
, sbuf_buf(&wb
.sbuf
));
308 /* return 1 if triggered a trap */
309 static int ren_bradj(struct adj
*adj
, int fill
, int ad
, int body
)
312 struct sbuf sbuf
, spre
;
313 int ll
, li
, lt
, els_neg
, els_pos
;
314 int w
, prev_d
, lspc
, ljust
;
316 if (!adj_empty(adj
, fill
)) {
319 w
= adj_fill(adj
, ad
== AD_B
, fill
, n_hy
, &sbuf
,
320 &ll
, &li
, <
, &els_neg
, &els_pos
);
324 if (!n_ns
|| !sbuf_empty(&sbuf
) || els_neg
|| els_pos
) {
326 if (!sbuf_empty(&sbuf
) && n_nm
&& body
)
328 ljust
= ren_ljust(&spre
, w
, ad
, ll
, li
, lt
);
329 if (!sbuf_empty(&sbuf
) && body
&& n_mc
)
330 ren_mc(&sbuf
, w
, ljust
);
331 ren_line(&spre
, &sbuf
);
339 lspc
= MAX(1, n_L
) * n_v
- n_v
;
340 if (detect_traps(prev_d
, n_d
) || detect_pagelimit(lspc
)) {
341 sprintf(cmd
, "%c&", c_ec
);
342 if (!ren_cnl
) /* prevent unwanted newlines */
344 if (!ren_traps(prev_d
, n_d
, 0))
354 /* return 1 if triggered a trap */
355 static int ren_br(int force
)
358 if (!n_u
|| n_na
|| (n_j
== AD_B
&& force
))
362 return ren_bradj(cadj
, !force
&& !n_ce
&& n_u
, ad
, 1);
365 void tr_br(char **args
)
367 if (args
[0][0] == c_cc
)
371 void tr_sp(char **args
)
374 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
375 if (args
[0][0] == c_cc
)
377 if (n
&& !n_ns
&& !traps
)
381 void tr_sv(char **args
)
383 int n
= eval(args
[1], 'v');
385 if (n_d
+ n
< f_nexttrap())
391 void tr_ns(char **args
)
396 void tr_rs(char **args
)
401 void tr_os(char **args
)
408 void tr_mk(char **args
)
411 num_set(map(args
[1]), n_d
);
416 void tr_rt(char **args
)
418 int n
= args
[1] ? eval_re(args
[1], n_d
, 'v') : n_mk
;
419 if (n
>= 0 && n
< n_d
)
423 void tr_ne(char **args
)
425 int n
= args
[1] ? eval(args
[1], 'v') : n_v
;
426 if (!ren_traps(n_d
, n_d
+ n
- 1, 1))
430 static void push_eject(void)
433 bp_ejected
= bp_count
;
434 sprintf(buf
, "%c%s %d\n", c_cc
, TR_EJECT
, bp_ejected
);
435 in_pushnl(buf
, NULL
);
438 static void push_br(void)
440 char br
[8] = {c_cc
, 'b', 'r', '\n'};
444 static void ren_eject(int id
)
446 if (id
== bp_ejected
&& id
== bp_count
&& !cdiv
) {
447 if (detect_traps(n_d
, n_p
)) {
449 ren_traps(n_d
, n_p
, 1);
452 ren_page(bp_next
, 0);
457 void tr_eject(char **args
)
459 ren_eject(atoi(args
[1]));
462 void tr_bp(char **args
)
464 if (!cdiv
&& (args
[1] || !n_ns
)) {
465 if (bp_ejected
!= bp_count
)
467 if (args
[0][0] == c_cc
)
470 bp_next
= eval_re(args
[1], n_pg
, 0);
474 void tr_pn(char **args
)
477 bp_next
= eval_re(args
[1], n_pg
, 0);
480 static void ren_ps(char *s
)
482 int ps
= !s
|| !*s
|| !strcmp("0", s
) ? n_s0
: eval_re(s
, n_s
, 0);
487 void tr_ps(char **args
)
492 void tr_ll(char **args
)
494 int ll
= args
[1] ? eval_re(args
[1], n_l
, 'm') : n_l0
;
500 void tr_in(char **args
)
502 int in
= args
[1] ? eval_re(args
[1], n_i
, 'm') : n_i0
;
503 if (args
[0][0] == c_cc
)
511 void tr_ti(char **args
)
513 if (args
[0][0] == c_cc
)
516 adj_ti(cadj
, eval_re(args
[1], n_i
, 'm'));
519 static void ren_ft(char *s
)
521 int fn
= !s
|| !*s
|| !strcmp("P", s
) ? n_f0
: dev_pos(s
);
523 errmsg("neatroff: failed to mount <%s>\n", s
);
530 void tr_ft(char **args
)
535 void tr_fp(char **args
)
539 if (dev_mnt(atoi(args
[1]), args
[2], args
[3] ? args
[3] : args
[2]) < 0)
540 errmsg("neatroff: failed to mount <%s>\n", args
[2]);
543 void tr_nf(char **args
)
545 if (args
[0][0] == c_cc
)
550 void tr_fi(char **args
)
552 if (args
[0][0] == c_cc
)
557 void tr_ce(char **args
)
559 if (args
[0][0] == c_cc
)
561 n_ce
= args
[1] ? atoi(args
[1]) : 1;
564 void tr_fc(char **args
)
568 strcpy(c_fb
, args
[2] ? args
[2] : " ");
575 static void ren_m(char *s
)
577 int m
= !s
|| !*s
? n_m0
: clr_get(s
);
582 void tr_ab(char **args
)
584 fprintf(stderr
, "%s\n", args
[1]);
588 static void escarg_ren(char *d
, int cmd
, int (*next
)(void), void (*back
)(int))
592 if (strchr(ESC_P
, cmd
)) {
594 if (cmd
== 's' && (c
== '-' || c
== '+')) {
601 } else if (!n_cp
&& c
== '[') {
603 while (c
> 0 && c
!= '\n' && c
!= ']') {
609 if (cmd
== 's' && c
>= '1' && c
<= '3') {
618 if (strchr(ESC_Q
, cmd
)) {
619 schar_read(delim
, next
);
620 while (schar_jump(delim
, next
, back
)) {
621 if ((c
= next()) < 0)
629 static int nextchar(char *s
, int (*next
)(void))
637 for (i
= 1; i
< l
; i
++)
643 static void ren_cmd(struct wb
*wb
, int c
, char *arg
)
647 wb_hmov(wb
, spacewid(n_f
, n_s
));
659 wb_vmov(wb
, SC_EM
/ 2);
665 wb_hmov(wb
, eval(arg
, 'm'));
668 num_set(map(arg
), RENWB(wb
) ? f_hpos() - n_lb
: wb_wid(wb
));
693 wb_vmov(wb
, -SC_EM
/ 2);
696 wb_vmov(wb
, eval(arg
, 'v'));
702 wb_els(wb
, eval(arg
, 'v'));
708 wb_hmov(wb
, SC_EM
/ 6);
714 wb_hmov(wb
, SC_EM
/ 12);
722 static void ren_field(struct wb
*wb
, int (*next
)(void), void (*back
)(int));
723 static void ren_tab(struct wb
*wb
, char *tc
, int (*next
)(void), void (*back
)(int));
725 /* read one character and place it inside wb buffer */
726 void ren_char(struct wb
*wb
, int (*next
)(void), void (*back
)(int))
734 if (c
[0] == ' ' || c
[0] == '\n') {
738 if (c
[0] == '\t' || c
[0] == '\x01') {
739 ren_tab(wb
, c
[0] == '\t' ? c_tc
: c_lc
, next
, back
);
743 ren_field(wb
, next
, back
);
747 nextchar(c
+ 1, next
);
749 nextchar(c
+ 1, next
);
751 l
= nextchar(c
+ 2, next
);
752 l
+= nextchar(c
+ 2 + l
, next
);
754 } else if (!n_cp
&& c
[1] == '[') {
757 while (n
>= 0 && n
!= '\n' && n
!= ']' && l
< GNLEN
- 1) {
762 } else if (c
[1] == 'z') {
764 ren_char(wb
, next
, back
);
765 wb_hmov(wb
, w
- wb_wid(wb
));
767 } else if (c
[1] == '!') {
768 if (ren_nl
&& next
== ren_next
) {
771 while (n
>= 0 && n
!= '\n') {
776 ren_transparent(arg
);
779 } else if (strchr(" bCcDdfHhkLlmNoprSsuvXxz0^|{}&", c
[1])) {
780 escarg_ren(arg
, c
[1], next
, back
);
782 g
= dev_glyph_byid(arg
, n_f
);
784 strcpy(arg
, g
? g
->name
: "cnull");
786 if (c
[1] == 'S' || c
[1] == 'H')
787 return; /* not implemented */
789 ren_cmd(wb
, c
[1], arg
);
795 if (!n_lg
|| wb_lig(wb
, c
)) {
802 /* read the argument of \w and push its width */
803 int ren_wid(int (*next
)(void), void (*back
)(int))
809 schar_read(delim
, next
);
812 while (c
>= 0 && c
!= '\n') {
814 if (!schar_jump(delim
, next
, back
))
816 ren_char(&wb
, next
, back
);
821 wb_wconf(&wb
, &n_ct
, &n_st
, &n_sb
);
826 /* return 1 if the ending character (ec) was read */
827 static int ren_until(struct wb
*wb
, char *delim
, int ec
,
828 int (*next
)(void), void (*back
)(int))
832 while (c
>= 0 && c
!= '\n' && c
!= ec
) {
834 if (!schar_jump(delim
, next
, back
))
836 ren_char(wb
, next
, back
);
844 static void wb_cpy(struct wb
*dst
, struct wb
*src
, int left
)
846 wb_hmov(dst
, left
- wb_wid(dst
));
850 void ren_tl(int (*next
)(void), void (*back
)(int))
858 schar_read(delim
, next
);
859 /* the left-adjusted string */
860 ren_until(&wb2
, delim
, '\n', next
, back
);
861 wb_cpy(&wb
, &wb2
, 0);
862 /* the centered string */
863 ren_until(&wb2
, delim
, '\n', next
, back
);
864 wb_cpy(&wb
, &wb2
, (n_lt
- wb_wid(&wb2
)) / 2);
865 /* the right-adjusted string */
866 ren_until(&wb2
, delim
, '\n', next
, back
);
867 wb_cpy(&wb
, &wb2
, n_lt
- wb_wid(&wb2
));
868 /* flushing the line */
872 ren_bradj(adj
, 0, AD_L
, 0);
878 static void ren_field(struct wb
*wb
, int (*next
)(void), void (*back
)(int))
880 struct wb wbs
[NFIELDS
];
883 int left
, right
, cur_left
;
885 while (n
< LEN(wbs
)) {
887 if (ren_until(&wbs
[n
++], c_fb
, c_fa
, next
, back
))
890 left
= RENWB(wb
) ? f_hpos() : wb_wid(wb
);
891 right
= tab_next(left
);
892 for (i
= 0; i
< n
; i
++)
893 wid
+= wb_wid(&wbs
[i
]);
894 pad
= (right
- left
- wid
) / (n
> 1 ? n
- 1 : 1);
895 rem
= (right
- left
- wid
) % (n
> 1 ? n
- 1 : 1);
896 for (i
= 0; i
< n
; i
++) {
900 cur_left
= right
- wb_wid(&wbs
[i
]);
902 cur_left
= wb_wid(wb
) + pad
+ (i
+ rem
>= n
);
903 wb_cpy(wb
, &wbs
[i
], cur_left
);
908 static void ren_tab(struct wb
*wb
, char *tc
, int (*next
)(void), void (*back
)(int))
911 int pos
= RENWB(wb
) ? f_hpos() : wb_wid(wb
);
912 int ins
= tab_next(pos
); /* insertion position */
913 int typ
= tab_type(pos
); /* tab type */
916 if (typ
== 'R' || typ
== 'C') {
918 while (c
>= 0 && c
!= '\n' && c
!= '\t' && c
!= '\x01') {
920 ren_char(&t
, next
, back
);
926 ins
-= wb_wid(&t
) / 2;
929 if (!tc
[0] || ins
<= pos
)
930 wb_hmov(wb
, ins
- pos
);
932 ren_hline(wb
, ins
- pos
, tc
);
937 /* read characters from in.c and pass rendered lines to out.c */
940 struct wb
*wb
= &ren_wb
;
946 ren_first(); /* transition to the first page */
954 if (bp_final
== 0 && trap_em
>= 0) {
967 /* add wb (the current word) to cadj */
968 if (c
== ' ' || c
== '\n') {
969 adj_swid(cadj
, spacewid(n_f
, n_s
));
970 if (!wb_part(wb
)) { /* not after a \c */
972 fillreq
= ren_fillreq
;
980 while ((fillreq
&& !n_ce
&& n_u
) || adj_full(cadj
, !n_ce
&& n_u
)) {
984 if (c
== '\n' || ren_nl
) /* end or start of input line */
986 if (c
== '\n' && n_it
&& --n_itn
== 0)
988 if (c
== '\n' && !wb_part(wb
))
989 n_ce
= MAX(0, n_ce
- 1);
992 ren_char(wb
, ren_next
, ren_back
);
993 if (c
!= '\n' && wb_empty(wb
))
1000 if (!adj_empty(cadj
, 0))
1001 ren_page(bp_next
, 1);
1009 #define tposval(i) (tpos[i] < 0 ? n_p + tpos[i] : tpos[i])
1011 static int tpos
[NTRAPS
]; /* trap positions */
1012 static int treg
[NTRAPS
]; /* trap registers */
1015 static int trap_first(int pos
)
1019 for (i
= 0; i
< ntraps
; i
++)
1020 if (treg
[i
] >= 0 && tposval(i
) > pos
)
1021 if (best
< 0 || tposval(i
) < tposval(best
))
1026 static int trap_byreg(int reg
)
1029 for (i
= 0; i
< ntraps
; i
++)
1035 static int trap_bypos(int reg
, int pos
)
1038 for (i
= 0; i
< ntraps
; i
++)
1039 if (treg
[i
] >= 0 && tposval(i
) == pos
)
1040 if (reg
== -1 || treg
[i
] == reg
)
1045 void tr_wh(char **args
)
1050 pos
= eval(args
[1], 'v');
1051 id
= trap_bypos(-1, pos
);
1059 id
= trap_byreg(-1);
1066 void tr_ch(char **args
)
1073 id
= trap_byreg(reg
);
1075 tpos
[id
] = args
[2] ? eval(args
[2], 'v') : -1;
1078 void tr_dt(char **args
)
1083 cdiv
->tpos
= eval(args
[1], 'v');
1084 cdiv
->treg
= map(args
[2]);
1090 void tr_em(char **args
)
1092 trap_em
= args
[1] ? map(args
[1]) : -1;
1095 static int trap_pos(int pos
)
1097 int ret
= trap_first(pos
);
1101 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->tpos
: -1;
1102 return ret
>= 0 ? tposval(ret
) : -1;
1105 static int trap_reg(int pos
)
1107 int ret
= trap_first(pos
);
1109 return cdiv
->treg
&& cdiv
->tpos
> pos
? cdiv
->treg
: -1;
1110 return ret
>= 0 ? treg
[ret
] : -1;
1113 int f_nexttrap(void)
1115 int pos
= trap_pos(n_d
);
1117 return pos
>= 0 ? pos
: 0x7fffffff;
1118 return (pos
>= 0 && pos
< n_p
? pos
: n_p
) - n_d
;