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 static void read_regname(char *s
)
114 int n
= n_cp
? 2 : NMLEN
- 1;
115 while (c
== ' ' || c
== '\t' || c
== c_ni
)
117 while (c
>= 0 && c
!= ' ' && c
!= '\t' && c
!= '\n' && --n
>= 0) {
121 } while (n
&& c
== c_ni
);
128 static void macrobody(struct sbuf
*sbuf
, char *end
)
135 while ((c
= cp_next()) >= 0) {
140 if ((c
= cp_next()) != '.') {
145 if ((n_cp
&& end
[0] == buf
[0] && end
[1] == buf
[1]) ||
147 for (i
= strlen(buf
) - 1; i
>= 0; i
--)
148 cp_back((unsigned char) buf
[i
]);
154 for (i
= 0; buf
[i
]; i
++)
155 sbuf_add(sbuf
, (unsigned char) buf
[i
]);
162 static void tr_de(char **args
)
170 if (args
[0][1] == 'a' && args
[0][2] == 'm' && str_get(id
))
171 sbuf_append(&sbuf
, str_get(id
));
172 macrobody(&sbuf
, args
[2] ? args
[2] : ".");
173 str_set(id
, sbuf_buf(&sbuf
));
177 static void tr_ig(char **args
)
179 macrobody(NULL
, args
[1] ? args
[1] : ".");
182 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
183 static int read_until(struct sbuf
*sbuf
, char *stop
,
184 int (*next
)(void), void (*back
)(int))
186 char cs
[GNLEN
], cs2
[GNLEN
];
188 while ((c
= next()) >= 0) {
194 if (!stop
&& (c
== ' ' || c
== '\t'))
196 charnext(cs
, next
, back
);
197 if (stop
&& !strcmp(stop
, cs
))
199 charnext_str(cs2
, cs
);
200 sbuf_append(sbuf
, cs2
);
205 /* evaluate .if strcmp (i.e. 'str'str') */
206 static int if_strcmp(int (*next
)(void), void (*back
)(int))
211 charnext(delim
, next
, back
);
214 read_until(&s1
, delim
, next
, back
);
215 read_until(&s2
, delim
, next
, back
);
217 ret
= !strcmp(sbuf_buf(&s1
), sbuf_buf(&s2
));
223 /* evaluate .if condition letters */
224 static int if_cond(int (*next
)(void), void (*back
)(int))
239 /* evaluate .if condition */
240 static int if_eval(int (*next
)(void), void (*back
)(int))
245 read_until(&sbuf
, NULL
, next
, back
);
246 ret
= eval(sbuf_buf(&sbuf
), '\0') > 0;
251 static int eval_if(int (*next
)(void), void (*back
)(int))
258 } while (c
== ' ' || c
== '\t');
264 if (strchr("oetn", c
)) {
265 ret
= if_cond(next
, back
);
266 } else if (!isdigit(c
) && !strchr("-+*/%<=>&:.|()", c
)) {
267 ret
= if_strcmp(next
, back
);
269 ret
= if_eval(next
, back
);
274 static int ie_cond
[NIES
]; /* .ie condition stack */
277 static void tr_if(char **args
)
279 int c
= eval_if(cp_next
, cp_back
);
280 if (args
[0][1] == 'i' && args
[0][2] == 'e') /* .ie command */
282 ie_cond
[ie_depth
++] = c
;
286 static void tr_el(char **args
)
288 cp_blk(ie_depth
> 0 ? ie_cond
[--ie_depth
] : 1);
291 static void tr_na(char **args
)
296 static int adjmode(int c
, int def
)
312 static void tr_ad(char **args
)
321 n_j
= s
[0] == 'p' ? AD_P
| adjmode(s
[1], AD_B
) : adjmode(s
[0], n_j
);
324 static void tr_tm(char **args
)
326 fprintf(stderr
, "%s\n", args
[1]);
329 static void tr_so(char **args
)
335 static void tr_nx(char **args
)
340 static void tr_ex(char **args
)
345 static void tr_sy(char **args
)
350 static void tr_lt(char **args
)
352 int lt
= args
[1] ? eval_re(args
[1], n_lt
, 'm') : n_t0
;
357 static void tr_pc(char **args
)
360 if (!s
|| charread(&s
, c_pc
) < 0)
364 static void tr_tl(char **args
)
369 } while (c
>= 0 && (c
== ' ' || c
== '\t'));
371 ren_tl(cp_next
, cp_back
);
374 } while (c
>= 0 && c
!= '\n');
377 static void tr_ec(char **args
)
379 c_ec
= args
[1] ? args
[1][0] : '\\';
382 static void tr_cc(char **args
)
384 c_cc
= args
[1] ? args
[1][0] : '.';
387 static void tr_c2(char **args
)
389 c_c2
= args
[1] ? args
[1][0] : '\'';
392 static void tr_eo(char **args
)
397 static void tr_hc(char **args
)
400 if (!s
|| charread(&s
, c_hc
) < 0)
404 /* sentence ending and their transparent characters */
405 static char eos_sent
[NCHARS
][GNLEN
] = { ".", "?", "!", };
406 static int eos_sentcnt
= 3;
407 static char eos_tran
[NCHARS
][GNLEN
] = { "'", "\"", ")", "]", "*", };
408 static int eos_trancnt
= 5;
410 static void tr_eos(char **args
)
416 while (s
&& charread(&s
, eos_sent
[eos_sentcnt
]) >= 0)
417 if (eos_sentcnt
< NCHARS
- 1)
422 while (s
&& charread(&s
, eos_tran
[eos_trancnt
]) >= 0)
423 if (eos_trancnt
< NCHARS
- 1)
428 int c_eossent(char *s
)
431 for (i
= 0; i
< eos_sentcnt
; i
++)
432 if (!strcmp(eos_sent
[i
], s
))
437 int c_eostran(char *s
)
440 for (i
= 0; i
< eos_trancnt
; i
++)
441 if (!strcmp(eos_tran
[i
], s
))
446 /* hyphenation dashes and hyphenation inhibiting character */
447 static char hy_dash
[NCHARS
][GNLEN
] = { "\\:", "-", "em", "en", "\\-", "--", "hy", };
448 static int hy_dashcnt
= 7;
449 static char hy_stop
[NCHARS
][GNLEN
] = { "\\%", };
450 static int hy_stopcnt
= 1;
452 static void tr_nh(char **args
)
457 static void tr_hy(char **args
)
459 n_hy
= args
[1] ? eval_re(args
[1], n_hy
, '\0') : 1;
462 static void tr_hycost(char **args
)
464 n_hycost
= args
[1] ? eval_re(args
[1], n_hycost
, '\0') : 0;
465 n_hycost2
= args
[2] ? eval_re(args
[2], n_hycost2
, '\0') : 0;
466 n_hycost3
= args
[3] ? eval_re(args
[3], n_hycost3
, '\0') : 0;
469 static void tr_hydash(char **args
)
474 while (s
&& charread(&s
, hy_dash
[hy_dashcnt
]) >= 0)
475 if (hy_dashcnt
< NCHARS
- 1)
480 static void tr_hystop(char **args
)
485 while (s
&& charread(&s
, hy_stop
[hy_stopcnt
]) >= 0)
486 if (hy_stopcnt
< NCHARS
- 1)
491 int c_hydash(char *s
)
494 for (i
= 0; i
< hy_dashcnt
; i
++)
495 if (!strcmp(hy_dash
[i
], s
))
500 int c_hystop(char *s
)
503 for (i
= 0; i
< hy_stopcnt
; i
++)
504 if (!strcmp(hy_stop
[i
], s
))
509 int c_hymark(char *s
)
511 return !strcmp(c_bp
, s
) || !strcmp(c_hc
, s
);
514 static void tr_pmll(char **args
)
516 n_pmll
= args
[1] ? eval_re(args
[1], n_pmll
, '\0') : 0;
517 n_pmllcost
= args
[2] ? eval_re(args
[2], n_pmllcost
, '\0') : 100;
520 static void tr_lg(char **args
)
523 n_lg
= eval(args
[1], '\0');
526 static void tr_kn(char **args
)
529 n_kn
= eval(args
[1], '\0');
532 static void tr_cp(char **args
)
535 n_cp
= atoi(args
[1]);
538 static void tr_ss(char **args
)
541 n_ss
= eval_re(args
[1], n_ss
, 0);
542 n_sss
= args
[2] ? eval_re(args
[2], n_sss
, 0) : n_ss
;
546 static void tr_ssh(char **args
)
548 n_ssh
= args
[1] ? eval_re(args
[1], n_ssh
, 0) : 0;
551 static void tr_cs(char **args
)
553 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
555 font_setcs(fn
, args
[2] ? eval(args
[2], 0) : 0,
556 args
[3] ? eval(args
[3], 0) : 0);
559 static void tr_fzoom(char **args
)
561 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
563 font_setzoom(fn
, args
[2] ? eval(args
[2], 0) : 0);
566 static void tr_ff(char **args
)
568 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
570 for (i
= 2; i
<= NARGS
; i
++)
571 if (fn
&& args
[i
] && args
[i
][0] && args
[i
][1])
572 font_feat(fn
, args
[i
] + 1, args
[i
][0] == '+');
575 static void tr_nm(char **args
)
582 n_ln
= eval_re(args
[1], n_ln
, 0);
584 if (args
[2] && isdigit(args
[2][0]))
585 n_nM
= MAX(1, eval(args
[2], 0));
586 if (args
[3] && isdigit(args
[3][0]))
587 n_nS
= MAX(0, eval(args
[3], 0));
588 if (args
[4] && isdigit(args
[4][0]))
589 n_nI
= MAX(0, eval(args
[4], 0));
592 static void tr_nn(char **args
)
594 n_nn
= args
[1] ? eval(args
[1], 0) : 1;
597 static void tr_bd(char **args
)
599 if (!args
[1] || !strcmp("S", args
[1]))
601 font_setbd(dev_font(dev_pos(args
[1])), args
[2] ? eval(args
[2], 'u') : 0);
604 static void tr_it(char **args
)
608 n_itn
= eval(args
[1], 0);
614 static void tr_mc(char **args
)
617 if (s
&& charread(&s
, c_mc
) >= 0) {
619 n_mcn
= args
[2] ? eval(args
[2], 'm') : SC_EM
;
625 static void tr_tc(char **args
)
628 if (!s
|| charread(&s
, c_tc
) < 0)
632 static void tr_lc(char **args
)
635 if (!s
|| charread(&s
, c_lc
) < 0)
639 static void tr_lf(char **args
)
642 in_lf(args
[2], eval(args
[1], 0));
645 static void tr_chop(char **args
)
652 sbuf_append(&sbuf
, str_get(id
));
653 if (!sbuf_empty(&sbuf
)) {
654 sbuf_cut(&sbuf
, sbuf_len(&sbuf
) - 1);
655 str_set(id
, sbuf_buf(&sbuf
));
661 /* character translation (.tr) */
662 static struct dict
*cmap
; /* character mapping */
663 static char cmap_src
[NCMAPS
][GNLEN
]; /* source character */
664 static char cmap_dst
[NCMAPS
][GNLEN
]; /* character mapping */
665 static int cmap_n
; /* number of translated character */
667 void cmap_add(char *c1
, char *c2
)
669 int i
= dict_get(cmap
, c1
);
671 strcpy(cmap_dst
[i
], c2
);
672 } else if (cmap_n
< NCMAPS
) {
673 strcpy(cmap_src
[cmap_n
], c1
);
674 strcpy(cmap_dst
[cmap_n
], c2
);
675 dict_put(cmap
, cmap_src
[cmap_n
], cmap_n
);
680 char *cmap_map(char *c
)
682 int i
= dict_get(cmap
, c
);
683 return i
>= 0 ? cmap_dst
[i
] : c
;
686 static void tr_tr(char **args
)
689 char c1
[GNLEN
], c2
[GNLEN
];
690 while (s
&& charread(&s
, c1
) >= 0) {
691 if (charread(&s
, c2
) < 0)
697 /* character definition (.char) */
698 static char cdef_src
[NCDEFS
][GNLEN
]; /* source character */
699 static char *cdef_dst
[NCDEFS
]; /* character definition */
700 static int cdef_fn
[NCDEFS
]; /* owning font */
701 static int cdef_n
; /* number of defined characters */
702 static int cdef_expanding
; /* inside cdef_expand() call */
704 static int cdef_find(char *c
, int fn
)
707 for (i
= 0; i
< cdef_n
; i
++)
708 if ((!cdef_fn
[i
] || cdef_fn
[i
] == fn
) && !strcmp(cdef_src
[i
], c
))
713 /* return the definition of the given character */
714 char *cdef_map(char *c
, int fn
)
716 int i
= cdef_find(c
, fn
);
717 return !cdef_expanding
&& i
>= 0 ? cdef_dst
[i
] : NULL
;
720 int cdef_expand(struct wb
*wb
, char *s
, int fn
)
722 char *d
= cdef_map(s
, fn
);
731 static void cdef_add(char *fn
, char *cs
, char *def
)
735 if (!def
|| charread(&cs
, c
) < 0)
737 i
= cdef_find(c
, -1);
738 if (i
< 0 && cdef_n
< NCDEFS
)
741 snprintf(cdef_src
[i
], sizeof(cdef_src
[i
]), "%s", c
);
742 cdef_dst
[i
] = xmalloc(strlen(def
) + 1);
743 strcpy(cdef_dst
[i
], def
);
744 cdef_fn
[i
] = fn
? dev_pos(fn
) : 0;
748 static void cdef_remove(char *cs
)
752 if (!cs
|| charread(&cs
, c
) < 0)
754 for (i
= 0; i
< cdef_n
; i
++) {
755 if (!strcmp(cdef_src
[i
], c
)) {
758 cdef_src
[i
][0] = '\0';
763 static void tr_char(char **args
)
765 cdef_add(NULL
, args
[1], args
[2]);
768 static void tr_rchar(char **args
)
771 for (i
= 1; i
<= NARGS
; i
++)
773 cdef_remove(args
[i
]);
776 static void tr_ochar(char **args
)
778 cdef_add(args
[1], args
[2], args
[3]);
781 static void tr_fmap(char **args
)
783 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
785 font_map(fn
, args
[2], args
[3]);
788 static void arg_regname(struct sbuf
*sbuf
)
792 sbuf_append(sbuf
, reg
);
796 static void arg_string(struct sbuf
*sbuf
)
799 while ((c
= cp_next()) == ' ')
803 while (c
> 0 && c
!= '\n') {
813 static int mkargs_arg(struct sbuf
*sbuf
, int (*next
)(void), void (*back
)(int))
822 if (c
< 0 || c
== '\n')
828 while (c
>= 0 && c
!= '\n') {
829 if (!quoted
&& c
== ' ')
831 if (quoted
&& c
== '"') {
849 /* read macro arguments */
850 int tr_readargs(char **args
, struct sbuf
*sbuf
, int (*next
)(void), void (*back
)(int))
855 idx
[n
] = sbuf_len(sbuf
);
856 if (mkargs_arg(sbuf
, next
, back
))
860 for (i
= 0; i
< n
; i
++)
861 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
865 /* read macro arguments; trims tabs if rmtabs is nonzero */
866 static int mkargs(char **args
, struct sbuf
*sbuf
)
868 int n
= tr_readargs(args
, sbuf
, cp_next
, cp_back
);
873 /* read request arguments; trims tabs too */
874 static int mkargs_req(char **args
, struct sbuf
*sbuf
)
881 idx
[n
] = sbuf_len(sbuf
);
882 while (c
== ' ' || c
== '\t')
884 while (c
>= 0 && c
!= '\n' && c
!= ' ' && c
!= '\t') {
889 if (sbuf_len(sbuf
) > idx
[n
])
894 if (c
< 0 || c
== '\n')
897 for (i
= 0; i
< n
; i
++)
898 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
903 /* read arguments for .ds */
904 static int mkargs_ds(char **args
, struct sbuf
*sbuf
)
908 idx
[n
++] = sbuf_len(sbuf
);
910 idx
[n
++] = sbuf_len(sbuf
);
915 for (i
= 0; i
< n
; i
++)
916 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
920 /* read arguments for commands .nr that expect a register name */
921 static int mkargs_reg1(char **args
, struct sbuf
*sbuf
)
924 int idx0
= sbuf_len(sbuf
);
926 n
= mkargs_req(args
+ 1, sbuf
) + 1;
927 args
[0] = sbuf_buf(sbuf
) + idx0
;
931 /* do not read arguments; for .if, .ie and .el */
932 static int mkargs_null(char **args
, struct sbuf
*sbuf
)
937 /* read the whole line for .tm */
938 static int mkargs_eol(char **args
, struct sbuf
*sbuf
)
940 int idx0
= sbuf_len(sbuf
);
946 while (c
>= 0 && c
!= '\n') {
952 args
[0] = sbuf_buf(sbuf
) + idx0
;
958 void (*f
)(char **args
);
959 int (*args
)(char **args
, struct sbuf
*sbuf
);
961 {TR_DIVBEG
, tr_divbeg
},
962 {TR_DIVEND
, tr_divend
},
963 {TR_DIVVS
, tr_divvs
},
964 {TR_POPREN
, tr_popren
},
965 {"ab", tr_ab
, mkargs_eol
},
968 {"am", tr_de
, mkargs_reg1
},
969 {"as", tr_as
, mkargs_ds
},
978 {"char", tr_char
, mkargs_ds
},
979 {"chop", tr_chop
, mkargs_reg1
},
984 {"de", tr_de
, mkargs_reg1
},
986 {"ds", tr_ds
, mkargs_ds
},
989 {"el", tr_el
, mkargs_null
},
1001 {"fspecial", tr_fspecial
},
1003 {"fzoom", tr_fzoom
},
1005 {"hcode", tr_hcode
},
1009 {"hycost", tr_hycost
},
1010 {"hydash", tr_hydash
},
1011 {"hystop", tr_hystop
},
1013 {"ie", tr_if
, mkargs_null
},
1014 {"if", tr_if
, mkargs_null
},
1033 {"nr", tr_nr
, mkargs_reg1
},
1043 {"rchar", tr_rchar
, mkargs_ds
},
1054 {"sy", tr_sy
, mkargs_eol
},
1058 {"tl", tr_tl
, mkargs_null
},
1059 {"tm", tr_tm
, mkargs_eol
},
1060 {"tr", tr_tr
, mkargs_eol
},
1065 /* read the next troff request; return zero if a request was executed. */
1066 int tr_nextreq(void)
1068 char *args
[NARGS
+ 3] = {NULL
};
1069 char cmd
[RNLEN
+ 1];
1082 mkargs_eol(args
+ 1, &sbuf
);
1084 tr_transparent(args
);
1090 if (c
< 0 || (c
!= c_cc
&& c
!= c_c2
)) {
1094 memset(args
, 0, sizeof(args
));
1099 read_regname(cmd
+ 1);
1101 req
= str_dget(map(cmd
+ 1));
1104 req
->args(args
+ 1, &sbuf
);
1106 mkargs_req(args
+ 1, &sbuf
);
1110 mkargs(args
+ 1, &sbuf
);
1112 if (str_get(map(cmd
+ 1)))
1113 in_push(str_get(map(cmd
+ 1)), args
+ 1);
1122 while (!tr_nextreq())
1125 tr_nl
= c
== '\n' || c
< 0;
1132 for (i
= 0; i
< LEN(cmds
); i
++)
1133 str_dset(map(cmds
[i
].id
), &cmds
[i
]);
1134 cmap
= dict_make(-1, 0, 0);