1 /* built-in troff requests */
8 static int tr_nl
= 1; /* just read a newline */
9 char c_pc
[GNLEN
] = "%"; /* page number character */
10 int c_ec
= '\\'; /* escape character */
11 int c_cc
= '.'; /* control character */
12 int c_c2
= '\''; /* no-break control character */
14 /* skip everything until the end of line */
15 static void jmp_eol(void)
20 } while (c
>= 0 && c
!= '\n');
23 static void tr_vs(char **args
)
25 int vs
= args
[1] ? eval_re(args
[1], n_v
, 'p') : n_v0
;
30 static void tr_ls(char **args
)
32 int ls
= args
[1] ? eval_re(args
[1], n_L
, 0) : n_L0
;
37 static void tr_pl(char **args
)
39 int n
= eval_re(args
[1] ? args
[1] : "11i", n_p
, 'v');
43 static void tr_nr(char **args
)
49 num_set(id
, eval_re(args
[2], num_get(id
), 'u'));
50 num_setinc(id
, args
[3] ? eval(args
[3], 'u') : 0);
53 static void tr_rr(char **args
)
56 for (i
= 1; i
<= NARGS
; i
++)
58 num_del(map(args
[i
]));
61 static void tr_af(char **args
)
64 num_setfmt(map(args
[1]), args
[2]);
67 static void tr_ds(char **args
)
70 str_set(map(args
[1]), args
[2]);
73 static void tr_as(char **args
)
80 s1
= str_get(reg
) ? str_get(reg
) : "";
82 s
= xmalloc(strlen(s1
) + strlen(s2
) + 1);
89 static void tr_rm(char **args
)
92 for (i
= 1; i
<= NARGS
; i
++)
97 static void tr_rn(char **args
)
101 str_rn(map(args
[1]), map(args
[2]));
104 static void tr_po(char **args
)
106 int po
= args
[1] ? eval_re(args
[1], n_o
, 'm') : n_o0
;
111 /* read a string argument of a macro */
112 static char *read_string(void)
118 while ((c
= cp_next()) == ' ')
122 while (c
> 0 && c
!= '\n') {
130 return sbuf_out(&sbuf
);
133 /* read a register name argument; if two, read at most two characters */
134 static char *read_name(int two
)
140 while (c
== ' ' || c
== '\t' || c
== c_ni
)
142 while (c
> 0 && c
!= ' ' && c
!= '\t' && c
!= '\n' && (!two
|| i
< 2)) {
151 return sbuf_out(&sbuf
);
155 static void macrobody(struct sbuf
*sbuf
, char *end
)
162 while ((c
= cp_next()) >= 0) {
167 if ((c
= cp_next()) != c_cc
) {
171 req
= read_name(n_cp
);
172 if (!strcmp(end
, req
)) {
178 sbuf_add(sbuf
, c_cc
);
179 sbuf_append(sbuf
, req
);
189 static void tr_de(char **args
)
197 if (args
[0][1] == 'a' && args
[0][2] == 'm' && str_get(id
))
198 sbuf_append(&sbuf
, str_get(id
));
199 macrobody(&sbuf
, args
[2] ? args
[2] : ".");
200 str_set(id
, sbuf_buf(&sbuf
));
204 static void tr_ig(char **args
)
206 macrobody(NULL
, args
[1] ? args
[1] : ".");
209 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
210 static int read_until(struct sbuf
*sbuf
, char *stop
,
211 int (*next
)(void), void (*back
)(int))
213 char cs
[GNLEN
], cs2
[GNLEN
];
215 while ((c
= next()) >= 0) {
221 if (!stop
&& (c
== ' ' || c
== '\t'))
223 charnext(cs
, next
, back
);
224 if (stop
&& !strcmp(stop
, cs
))
226 charnext_str(cs2
, cs
);
227 sbuf_append(sbuf
, cs2
);
232 /* evaluate .if strcmp (i.e. 'str'str') */
233 static int if_strcmp(int (*next
)(void), void (*back
)(int))
238 charnext(delim
, next
, back
);
241 read_until(&s1
, delim
, next
, back
);
242 read_until(&s2
, delim
, next
, back
);
244 ret
= !strcmp(sbuf_buf(&s1
), sbuf_buf(&s2
));
250 /* evaluate .if condition letters */
251 static int if_cond(int (*next
)(void), void (*back
)(int))
266 /* evaluate .if condition */
267 static int if_eval(int (*next
)(void), void (*back
)(int))
272 read_until(&sbuf
, NULL
, next
, back
);
273 ret
= eval(sbuf_buf(&sbuf
), '\0') > 0;
278 static int eval_if(int (*next
)(void), void (*back
)(int))
285 } while (c
== ' ' || c
== '\t');
291 if (strchr("oetn", c
)) {
292 ret
= if_cond(next
, back
);
293 } else if (!isdigit(c
) && !strchr("-+*/%<=>&:.|()", c
)) {
294 ret
= if_strcmp(next
, back
);
296 ret
= if_eval(next
, back
);
301 static int ie_cond
[NIES
]; /* .ie condition stack */
304 static void tr_if(char **args
)
306 int c
= eval_if(cp_next
, cp_back
);
307 if (args
[0][1] == 'i' && args
[0][2] == 'e') /* .ie command */
309 ie_cond
[ie_depth
++] = c
;
313 static void tr_el(char **args
)
315 cp_blk(ie_depth
> 0 ? ie_cond
[--ie_depth
] : 1);
318 static void tr_na(char **args
)
323 static int adjmode(int c
, int def
)
339 static void tr_ad(char **args
)
348 n_j
= s
[0] == 'p' ? AD_P
| adjmode(s
[1], AD_B
) : adjmode(s
[0], n_j
);
351 static void tr_tm(char **args
)
353 fprintf(stderr
, "%s\n", args
[1]);
356 static void tr_so(char **args
)
362 static void tr_nx(char **args
)
367 static void tr_ex(char **args
)
372 static void tr_sy(char **args
)
377 static void tr_lt(char **args
)
379 int lt
= args
[1] ? eval_re(args
[1], n_lt
, 'm') : n_t0
;
384 static void tr_pc(char **args
)
387 if (!s
|| charread(&s
, c_pc
) < 0)
391 static void tr_tl(char **args
)
396 } while (c
>= 0 && (c
== ' ' || c
== '\t'));
398 ren_tl(cp_next
, cp_back
);
401 } while (c
>= 0 && c
!= '\n');
404 static void tr_ec(char **args
)
406 c_ec
= args
[1] ? args
[1][0] : '\\';
409 static void tr_cc(char **args
)
411 c_cc
= args
[1] ? args
[1][0] : '.';
414 static void tr_c2(char **args
)
416 c_c2
= args
[1] ? args
[1][0] : '\'';
419 static void tr_eo(char **args
)
424 static void tr_hc(char **args
)
427 if (!s
|| charread(&s
, c_hc
) < 0)
431 /* sentence ending and their transparent characters */
432 static char eos_sent
[NCHARS
][GNLEN
] = { ".", "?", "!", };
433 static int eos_sentcnt
= 3;
434 static char eos_tran
[NCHARS
][GNLEN
] = { "'", "\"", ")", "]", "*", };
435 static int eos_trancnt
= 5;
437 static void tr_eos(char **args
)
443 while (s
&& charread(&s
, eos_sent
[eos_sentcnt
]) >= 0)
444 if (eos_sentcnt
< NCHARS
- 1)
449 while (s
&& charread(&s
, eos_tran
[eos_trancnt
]) >= 0)
450 if (eos_trancnt
< NCHARS
- 1)
455 int c_eossent(char *s
)
458 for (i
= 0; i
< eos_sentcnt
; i
++)
459 if (!strcmp(eos_sent
[i
], s
))
464 int c_eostran(char *s
)
467 for (i
= 0; i
< eos_trancnt
; i
++)
468 if (!strcmp(eos_tran
[i
], s
))
473 /* hyphenation dashes and hyphenation inhibiting character */
474 static char hy_dash
[NCHARS
][GNLEN
] = { "\\:", "-", "em", "en", "\\-", "--", "hy", };
475 static int hy_dashcnt
= 7;
476 static char hy_stop
[NCHARS
][GNLEN
] = { "\\%", };
477 static int hy_stopcnt
= 1;
479 static void tr_nh(char **args
)
484 static void tr_hy(char **args
)
486 n_hy
= args
[1] ? eval_re(args
[1], n_hy
, '\0') : 1;
489 static void tr_hlm(char **args
)
491 n_hlm
= args
[1] ? eval_re(args
[1], n_hlm
, '\0') : 0;
494 static void tr_hycost(char **args
)
496 n_hycost
= args
[1] ? eval_re(args
[1], n_hycost
, '\0') : 0;
497 n_hycost2
= args
[2] ? eval_re(args
[2], n_hycost2
, '\0') : 0;
498 n_hycost3
= args
[3] ? eval_re(args
[3], n_hycost3
, '\0') : 0;
501 static void tr_hydash(char **args
)
506 while (s
&& charread(&s
, hy_dash
[hy_dashcnt
]) >= 0)
507 if (hy_dashcnt
< NCHARS
- 1)
512 static void tr_hystop(char **args
)
517 while (s
&& charread(&s
, hy_stop
[hy_stopcnt
]) >= 0)
518 if (hy_stopcnt
< NCHARS
- 1)
523 int c_hydash(char *s
)
526 for (i
= 0; i
< hy_dashcnt
; i
++)
527 if (!strcmp(hy_dash
[i
], s
))
532 int c_hystop(char *s
)
535 for (i
= 0; i
< hy_stopcnt
; i
++)
536 if (!strcmp(hy_stop
[i
], s
))
541 int c_hymark(char *s
)
543 return !strcmp(c_bp
, s
) || !strcmp(c_hc
, s
);
546 static void tr_pmll(char **args
)
548 n_pmll
= args
[1] ? eval_re(args
[1], n_pmll
, '\0') : 0;
549 n_pmllcost
= args
[2] ? eval_re(args
[2], n_pmllcost
, '\0') : 100;
552 static void tr_lg(char **args
)
555 n_lg
= eval(args
[1], '\0');
558 static void tr_kn(char **args
)
561 n_kn
= eval(args
[1], '\0');
564 static void tr_cp(char **args
)
567 n_cp
= atoi(args
[1]);
570 static void tr_ss(char **args
)
573 n_ss
= eval_re(args
[1], n_ss
, 0);
574 n_sss
= args
[2] ? eval_re(args
[2], n_sss
, 0) : n_ss
;
578 static void tr_ssh(char **args
)
580 n_ssh
= args
[1] ? eval_re(args
[1], n_ssh
, 0) : 0;
583 static void tr_cs(char **args
)
585 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
587 font_setcs(fn
, args
[2] ? eval(args
[2], 0) : 0,
588 args
[3] ? eval(args
[3], 0) : 0);
591 static void tr_fzoom(char **args
)
593 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
595 font_setzoom(fn
, args
[2] ? eval(args
[2], 0) : 0);
598 static void tr_ff(char **args
)
600 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
602 for (i
= 2; i
<= NARGS
; i
++)
603 if (fn
&& args
[i
] && args
[i
][0] && args
[i
][1])
604 font_feat(fn
, args
[i
] + 1, args
[i
][0] == '+');
607 static void tr_nm(char **args
)
614 n_ln
= eval_re(args
[1], n_ln
, 0);
616 if (args
[2] && isdigit(args
[2][0]))
617 n_nM
= MAX(1, eval(args
[2], 0));
618 if (args
[3] && isdigit(args
[3][0]))
619 n_nS
= MAX(0, eval(args
[3], 0));
620 if (args
[4] && isdigit(args
[4][0]))
621 n_nI
= MAX(0, eval(args
[4], 0));
624 static void tr_nn(char **args
)
626 n_nn
= args
[1] ? eval(args
[1], 0) : 1;
629 static void tr_bd(char **args
)
631 if (!args
[1] || !strcmp("S", args
[1]))
633 font_setbd(dev_font(dev_pos(args
[1])), args
[2] ? eval(args
[2], 'u') : 0);
636 static void tr_it(char **args
)
640 n_itn
= eval(args
[1], 0);
646 static void tr_mc(char **args
)
649 if (s
&& charread(&s
, c_mc
) >= 0) {
651 n_mcn
= args
[2] ? eval(args
[2], 'm') : SC_EM
;
657 static void tr_tc(char **args
)
660 if (!s
|| charread(&s
, c_tc
) < 0)
664 static void tr_lc(char **args
)
667 if (!s
|| charread(&s
, c_lc
) < 0)
671 static void tr_lf(char **args
)
674 in_lf(args
[2], eval(args
[1], 0));
677 static void tr_chop(char **args
)
684 sbuf_append(&sbuf
, str_get(id
));
685 if (!sbuf_empty(&sbuf
)) {
686 sbuf_cut(&sbuf
, sbuf_len(&sbuf
) - 1);
687 str_set(id
, sbuf_buf(&sbuf
));
693 /* character translation (.tr) */
694 static struct dict
*cmap
; /* character mapping */
695 static char cmap_src
[NCMAPS
][GNLEN
]; /* source character */
696 static char cmap_dst
[NCMAPS
][GNLEN
]; /* character mapping */
697 static int cmap_n
; /* number of translated character */
699 void cmap_add(char *c1
, char *c2
)
701 int i
= dict_get(cmap
, c1
);
703 strcpy(cmap_dst
[i
], c2
);
704 } else if (cmap_n
< NCMAPS
) {
705 strcpy(cmap_src
[cmap_n
], c1
);
706 strcpy(cmap_dst
[cmap_n
], c2
);
707 dict_put(cmap
, cmap_src
[cmap_n
], cmap_n
);
712 char *cmap_map(char *c
)
714 int i
= dict_get(cmap
, c
);
715 return i
>= 0 ? cmap_dst
[i
] : c
;
718 static void tr_tr(char **args
)
721 char c1
[GNLEN
], c2
[GNLEN
];
722 while (s
&& charread(&s
, c1
) >= 0) {
723 if (charread(&s
, c2
) < 0)
729 /* character definition (.char) */
730 static char cdef_src
[NCDEFS
][GNLEN
]; /* source character */
731 static char *cdef_dst
[NCDEFS
]; /* character definition */
732 static int cdef_fn
[NCDEFS
]; /* owning font */
733 static int cdef_n
; /* number of defined characters */
734 static int cdef_expanding
; /* inside cdef_expand() call */
736 static int cdef_find(char *c
, int fn
)
739 for (i
= 0; i
< cdef_n
; i
++)
740 if ((!cdef_fn
[i
] || cdef_fn
[i
] == fn
) && !strcmp(cdef_src
[i
], c
))
745 /* return the definition of the given character */
746 char *cdef_map(char *c
, int fn
)
748 int i
= cdef_find(c
, fn
);
749 return !cdef_expanding
&& i
>= 0 ? cdef_dst
[i
] : NULL
;
752 int cdef_expand(struct wb
*wb
, char *s
, int fn
)
754 char *d
= cdef_map(s
, fn
);
763 static void cdef_add(char *fn
, char *cs
, char *def
)
767 if (!def
|| charread(&cs
, c
) < 0)
769 i
= cdef_find(c
, -1);
770 if (i
< 0 && cdef_n
< NCDEFS
)
773 snprintf(cdef_src
[i
], sizeof(cdef_src
[i
]), "%s", c
);
774 cdef_dst
[i
] = xmalloc(strlen(def
) + 1);
775 strcpy(cdef_dst
[i
], def
);
776 cdef_fn
[i
] = fn
? dev_pos(fn
) : 0;
780 static void cdef_remove(char *cs
)
784 if (!cs
|| charread(&cs
, c
) < 0)
786 for (i
= 0; i
< cdef_n
; i
++) {
787 if (!strcmp(cdef_src
[i
], c
)) {
790 cdef_src
[i
][0] = '\0';
795 static void tr_char(char **args
)
797 cdef_add(NULL
, args
[1], args
[2]);
800 static void tr_rchar(char **args
)
803 for (i
= 1; i
<= NARGS
; i
++)
805 cdef_remove(args
[i
]);
808 static void tr_ochar(char **args
)
810 cdef_add(args
[1], args
[2], args
[3]);
813 static void tr_fmap(char **args
)
815 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
817 font_map(fn
, args
[2], args
[3]);
820 /* read a macro argument */
821 static int tr_arg(struct sbuf
*sbuf
, int brk
, int (*next
)(void), void (*back
)(int))
828 if (c
== '\n' || c
== brk
)
830 if (c
< 0 || c
== '\n' || c
== brk
)
836 while (c
>= 0 && c
!= '\n' && (quoted
|| c
!= brk
)) {
837 if (!quoted
&& c
== ' ')
839 if (quoted
&& c
== '"') {
857 /* read macro arguments; free the returned pointer when done */
858 char *tr_args(char **args
, int brk
, int (*next
)(void), void (*back
)(int))
864 while (!tr_arg(&sbuf
, brk
, next
, back
))
867 e
= s
+ sbuf_len(&sbuf
);
868 while (n
< NARGS
&& s
&& s
< e
) {
870 if ((s
= memchr(s
, '\0', e
- s
)))
873 return sbuf_out(&sbuf
);
876 /* split the arguments in sbuf */
877 static int tr_argschop(struct sbuf
*sbuf
, char **args
)
879 char *s
= sbuf_buf(sbuf
);
880 char *e
= s
+ sbuf_len(sbuf
);
882 while (n
< NARGS
&& s
&& s
< e
) {
884 if ((s
= memchr(s
, '\0', e
- s
)))
890 /* read request arguments; trims tabs too */
891 static void mkargs_req(struct sbuf
*sbuf
)
898 while (c
== ' ' || c
== '\t')
900 while (c
>= 0 && c
!= '\n' && c
!= ' ' && c
!= '\t') {
912 if (c
< 0 || c
== '\n')
918 /* read arguments for .ds */
919 static void mkargs_ds(struct sbuf
*sbuf
)
921 char *s
= read_name(n_cp
);
922 sbuf_append(sbuf
, s
);
926 sbuf_append(sbuf
, s
);
932 /* read arguments for .char */
933 static void mkargs_def(struct sbuf
*sbuf
)
935 char *s
= read_name(0);
936 sbuf_append(sbuf
, s
);
940 sbuf_append(sbuf
, s
);
946 /* read arguments for .ochar */
947 static void mkargs_def3(struct sbuf
*sbuf
)
949 char *s
= read_name(0);
950 sbuf_append(sbuf
, s
);
956 /* read arguments for .nr */
957 static void mkargs_reg1(struct sbuf
*sbuf
)
959 char *s
= read_name(n_cp
);
960 sbuf_append(sbuf
, s
);
966 /* do not read any arguments; for .if, .ie and .el */
967 static void mkargs_null(struct sbuf
*sbuf
)
971 /* read the whole line for .tm */
972 static void mkargs_eol(struct sbuf
*sbuf
)
979 while (c
>= 0 && c
!= '\n') {
989 void (*f
)(char **args
);
990 void (*args
)(struct sbuf
*sbuf
);
992 {TR_DIVBEG
, tr_divbeg
},
993 {TR_DIVEND
, tr_divend
},
994 {TR_DIVVS
, tr_divvs
},
995 {TR_POPREN
, tr_popren
},
996 {"ab", tr_ab
, mkargs_eol
},
999 {"am", tr_de
, mkargs_reg1
},
1000 {"as", tr_as
, mkargs_ds
},
1006 {"ochar", tr_ochar
, mkargs_def3
},
1009 {"char", tr_char
, mkargs_def
},
1010 {"chop", tr_chop
, mkargs_reg1
},
1015 {"de", tr_de
, mkargs_reg1
},
1017 {"ds", tr_ds
, mkargs_ds
},
1020 {"el", tr_el
, mkargs_null
},
1032 {"fspecial", tr_fspecial
},
1034 {"fzoom", tr_fzoom
},
1036 {"hcode", tr_hcode
},
1041 {"hycost", tr_hycost
},
1042 {"hydash", tr_hydash
},
1043 {"hystop", tr_hystop
},
1045 {"ie", tr_if
, mkargs_null
},
1046 {"if", tr_if
, mkargs_null
},
1065 {"nr", tr_nr
, mkargs_reg1
},
1075 {"rchar", tr_rchar
},
1086 {"sy", tr_sy
, mkargs_eol
},
1090 {"tl", tr_tl
, mkargs_null
},
1091 {"tm", tr_tm
, mkargs_eol
},
1092 {"tr", tr_tr
, mkargs_eol
},
1097 static char *dotted(char *name
, int dot
)
1099 char *out
= xmalloc(strlen(name
) + 2);
1101 strcpy(out
+ 1, name
);
1105 /* read the next troff request; return zero if a request was executed. */
1106 int tr_nextreq(void)
1108 char *args
[NARGS
+ 3] = {NULL
};
1124 tr_argschop(&sbuf
, args
+ 1);
1125 tr_transparent(args
);
1131 if (c
< 0 || (c
!= c_cc
&& c
!= c_c2
)) {
1136 cmd
= read_name(n_cp
);
1137 args
[0] = dotted(cmd
, c
);
1138 req
= str_dget(map(cmd
));
1145 tr_argschop(&sbuf
, args
+ 1);
1151 buf
= tr_args(args
+ 1, -1, cp_next
, cp_back
);
1154 if (str_get(map(cmd
)))
1155 in_push(str_get(map(cmd
)), args
+ 1);
1166 while (!tr_nextreq())
1169 tr_nl
= c
== '\n' || c
< 0;
1176 for (i
= 0; i
< LEN(cmds
); i
++)
1177 str_dset(map(cmds
[i
].id
), &cmds
[i
]);
1178 cmap
= dict_make(-1, 0, 0);