1 /* built-in troff requests */
8 static int tr_nl
= 1; /* just read a newline */
9 static int c_pc
= '%'; /* page number 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
)
359 c_pc
= args
[1] ? args
[1][0] : -1;
362 static int tl_next(void)
365 if (c
>= 0 && c
== c_pc
) {
366 in_push(num_str(map("%")), NULL
);
372 static void tr_tl(char **args
)
377 } while (c
>= 0 && (c
== ' ' || c
== '\t'));
379 ren_tl(tl_next
, cp_back
);
382 } while (c
>= 0 && c
!= '\n');
385 static void tr_ec(char **args
)
387 c_ec
= args
[1] ? args
[1][0] : '\\';
390 static void tr_cc(char **args
)
392 c_cc
= args
[1] ? args
[1][0] : '.';
395 static void tr_c2(char **args
)
397 c_c2
= args
[1] ? args
[1][0] : '\'';
400 static void tr_eo(char **args
)
405 static void tr_hc(char **args
)
408 if (!s
|| charread(&s
, c_hc
) < 0)
412 static void tr_nh(char **args
)
417 static void tr_hy(char **args
)
419 n_hy
= args
[1] ? atoi(args
[1]) : 1;
422 static void tr_hyp(char **args
)
424 n_hyp
= args
[1] ? atoi(args
[1]) : 1;
427 static void tr_pmll(char **args
)
429 n_pmll
= args
[1] ? atoi(args
[1]) : 0;
432 static void tr_lg(char **args
)
435 n_lg
= atoi(args
[1]);
438 static void tr_kn(char **args
)
441 n_kn
= atoi(args
[1]);
444 static void tr_cp(char **args
)
447 n_cp
= atoi(args
[1]);
450 static void tr_ss(char **args
)
453 n_ss
= eval_re(args
[1], n_ss
, 0);
454 n_sss
= args
[2] ? eval_re(args
[2], n_sss
, 0) : n_ss
;
458 static void tr_ssh(char **args
)
460 n_ssh
= args
[1] ? eval_re(args
[1], n_ssh
, 0) : 0;
463 static void tr_cs(char **args
)
465 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
467 font_setcs(fn
, args
[2] ? eval(args
[2], 0) : 0,
468 args
[3] ? eval(args
[3], 0) : 0);
471 static void tr_fzoom(char **args
)
473 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
475 font_setzoom(fn
, args
[2] ? eval(args
[2], 0) : 0);
478 static void tr_ff(char **args
)
480 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
482 for (i
= 2; i
<= NARGS
; i
++)
483 if (fn
&& args
[i
] && args
[i
][0] && args
[i
][1])
484 font_feat(fn
, args
[i
] + 1, args
[i
][0] == '+');
487 static void tr_nm(char **args
)
494 n_ln
= eval_re(args
[1], n_ln
, 0);
496 if (args
[2] && isdigit(args
[2][0]))
497 n_nM
= MAX(1, eval(args
[2], 0));
498 if (args
[3] && isdigit(args
[3][0]))
499 n_nS
= MAX(0, eval(args
[3], 0));
500 if (args
[4] && isdigit(args
[4][0]))
501 n_nI
= MAX(0, eval(args
[4], 0));
504 static void tr_nn(char **args
)
506 n_nn
= args
[1] ? eval(args
[1], 0) : 1;
509 static void tr_bd(char **args
)
511 if (!args
[1] || !strcmp("S", args
[1]))
513 font_setbd(dev_font(dev_pos(args
[1])), args
[2] ? eval(args
[2], 'u') : 0);
516 static void tr_it(char **args
)
520 n_itn
= eval(args
[1], 0);
526 static void tr_mc(char **args
)
529 if (s
&& charread(&s
, c_mc
) >= 0) {
531 n_mcn
= args
[2] ? eval(args
[2], 'm') : SC_EM
;
537 static void tr_tc(char **args
)
540 if (!s
|| charread(&s
, c_tc
) < 0)
544 static void tr_lc(char **args
)
547 if (!s
|| charread(&s
, c_lc
) < 0)
551 static void tr_lf(char **args
)
554 in_lf(args
[2], eval(args
[1], 0));
557 static void tr_chop(char **args
)
562 in_lf(args
[2], eval(args
[1], 0));
566 sbuf_append(&sbuf
, str_get(id
));
567 if (!sbuf_empty(&sbuf
)) {
568 sbuf_cut(&sbuf
, sbuf_len(&sbuf
) - 1);
569 str_set(id
, sbuf_buf(&sbuf
));
575 /* character translation (.tr) */
576 static struct dict cmap
; /* character mapping */
577 static char cmap_src
[NCMAPS
][GNLEN
]; /* source character */
578 static char cmap_dst
[NCMAPS
][GNLEN
]; /* character mapping */
579 static int cmap_n
; /* number of translated character */
581 void cmap_add(char *c1
, char *c2
)
583 int i
= dict_get(&cmap
, c1
);
585 strcpy(cmap_dst
[i
], c2
);
586 } else if (cmap_n
< NCMAPS
) {
587 strcpy(cmap_src
[cmap_n
], c1
);
588 strcpy(cmap_dst
[cmap_n
], c2
);
589 dict_put(&cmap
, cmap_src
[cmap_n
], cmap_n
);
594 char *cmap_map(char *c
)
596 int i
= dict_get(&cmap
, c
);
597 return i
>= 0 ? cmap_dst
[i
] : c
;
600 static void tr_tr(char **args
)
603 char c1
[GNLEN
], c2
[GNLEN
];
604 while (s
&& charread(&s
, c1
) >= 0) {
605 if (charread(&s
, c2
) < 0)
611 /* character definition (.char) */
612 static char cdef_src
[NCDEFS
][GNLEN
]; /* source character */
613 static char *cdef_dst
[NCDEFS
]; /* character definition */
614 static int cdef_fn
[NCDEFS
]; /* owning font */
615 static int cdef_n
; /* number of defined characters */
616 static int cdef_expanding
; /* inside cdef_expand() call */
618 static int cdef_find(char *c
, int fn
)
621 for (i
= 0; i
< cdef_n
; i
++)
622 if ((!cdef_fn
[i
] || cdef_fn
[i
] == fn
) && !strcmp(cdef_src
[i
], c
))
627 /* return the definition of the given character */
628 char *cdef_map(char *c
, int fn
)
630 int i
= cdef_find(c
, fn
);
631 return !cdef_expanding
&& i
>= 0 ? cdef_dst
[i
] : NULL
;
634 int cdef_expand(struct wb
*wb
, char *s
, int fn
)
636 char *d
= cdef_map(s
, fn
);
645 static void cdef_add(char *fn
, char *cs
, char *def
)
649 if (!def
|| charread(&cs
, c
) < 0)
651 i
= cdef_find(c
, -1);
652 if (i
< 0 && cdef_n
< NCDEFS
)
655 strncpy(cdef_src
[i
], c
, sizeof(cdef_src
[i
]) - 1);
656 cdef_dst
[i
] = xmalloc(strlen(def
) + 1);
657 strcpy(cdef_dst
[i
], def
);
658 cdef_fn
[i
] = fn
? dev_pos(fn
) : 0;
662 static void cdef_remove(char *cs
)
666 if (!cs
|| charread(&cs
, c
) < 0)
668 for (i
= 0; i
< cdef_n
; i
++) {
669 if (!strcmp(cdef_src
[i
], c
)) {
672 cdef_src
[i
][0] = '\0';
677 static void tr_char(char **args
)
679 cdef_add(NULL
, args
[1], args
[2]);
682 static void tr_rchar(char **args
)
685 for (i
= 1; i
<= NARGS
; i
++)
687 cdef_remove(args
[i
]);
690 static void tr_ochar(char **args
)
692 cdef_add(args
[1], args
[2], args
[3]);
695 static void tr_fmap(char **args
)
697 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
699 font_map(fn
, args
[2], args
[3]);
702 static void arg_regname(struct sbuf
*sbuf
)
706 sbuf_append(sbuf
, reg
);
710 static void arg_string(struct sbuf
*sbuf
)
713 while ((c
= cp_next()) == ' ')
717 while (c
> 0 && c
!= '\n') {
727 static int mkargs_arg(struct sbuf
*sbuf
, int (*next
)(void), void (*back
)(int))
736 if (c
< 0 || c
== '\n')
742 while (c
>= 0 && c
!= '\n') {
743 if (!quoted
&& c
== ' ')
745 if (quoted
&& c
== '"') {
763 /* read macro arguments */
764 int tr_readargs(char **args
, struct sbuf
*sbuf
, int (*next
)(void), void (*back
)(int))
769 idx
[n
] = sbuf_len(sbuf
);
770 if (mkargs_arg(sbuf
, next
, back
))
774 for (i
= 0; i
< n
; i
++)
775 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
779 /* read macro arguments; trims tabs if rmtabs is nonzero */
780 static int mkargs(char **args
, struct sbuf
*sbuf
)
782 int n
= tr_readargs(args
, sbuf
, cp_next
, cp_back
);
787 /* read request arguments; trims tabs too */
788 static int mkargs_req(char **args
, struct sbuf
*sbuf
)
795 idx
[n
] = sbuf_len(sbuf
);
796 while (c
== ' ' || c
== '\t')
798 while (c
>= 0 && c
!= '\n' && c
!= ' ' && c
!= '\t') {
803 if (sbuf_len(sbuf
) > idx
[n
])
808 if (c
< 0 || c
== '\n')
811 for (i
= 0; i
< n
; i
++)
812 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
817 /* read arguments for .ds */
818 static int mkargs_ds(char **args
, struct sbuf
*sbuf
)
822 idx
[n
++] = sbuf_len(sbuf
);
824 idx
[n
++] = sbuf_len(sbuf
);
829 for (i
= 0; i
< n
; i
++)
830 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
834 /* read arguments for commands .nr that expect a register name */
835 static int mkargs_reg1(char **args
, struct sbuf
*sbuf
)
838 int idx0
= sbuf_len(sbuf
);
840 n
= mkargs_req(args
+ 1, sbuf
) + 1;
841 args
[0] = sbuf_buf(sbuf
) + idx0
;
845 /* do not read arguments; for .if, .ie and .el */
846 static int mkargs_null(char **args
, struct sbuf
*sbuf
)
851 /* read the whole line for .tm */
852 static int mkargs_eol(char **args
, struct sbuf
*sbuf
)
854 int idx0
= sbuf_len(sbuf
);
860 while (c
>= 0 && c
!= '\n') {
866 args
[0] = sbuf_buf(sbuf
) + idx0
;
872 void (*f
)(char **args
);
873 int (*args
)(char **args
, struct sbuf
*sbuf
);
875 {TR_DIVBEG
, tr_divbeg
},
876 {TR_DIVEND
, tr_divend
},
877 {TR_DIVVS
, tr_divvs
},
878 {TR_POPREN
, tr_popren
},
879 {"ab", tr_ab
, mkargs_eol
},
882 {"am", tr_de
, mkargs_reg1
},
883 {"as", tr_as
, mkargs_ds
},
892 {"char", tr_char
, mkargs_ds
},
893 {"chop", tr_chop
, mkargs_reg1
},
898 {"de", tr_de
, mkargs_reg1
},
900 {"ds", tr_ds
, mkargs_ds
},
903 {"el", tr_el
, mkargs_null
},
914 {"fspecial", tr_fspecial
},
924 {"ie", tr_if
, mkargs_null
},
925 {"if", tr_if
, mkargs_null
},
944 {"nr", tr_nr
, mkargs_reg1
},
954 {"rchar", tr_rchar
, mkargs_ds
},
965 {"sy", tr_sy
, mkargs_eol
},
969 {"tl", tr_tl
, mkargs_null
},
970 {"tm", tr_tm
, mkargs_eol
},
971 {"tr", tr_tr
, mkargs_eol
},
976 /* read the next troff request; return zero if a request was executed. */
979 char *args
[NARGS
+ 3] = {NULL
};
993 mkargs_eol(args
+ 1, &sbuf
);
995 tr_transparent(args
);
1001 if (c
< 0 || (c
!= c_cc
&& c
!= c_c2
)) {
1005 memset(args
, 0, sizeof(args
));
1010 read_regname(cmd
+ 1);
1012 req
= str_dget(map(cmd
+ 1));
1015 req
->args(args
+ 1, &sbuf
);
1017 mkargs_req(args
+ 1, &sbuf
);
1021 mkargs(args
+ 1, &sbuf
);
1023 if (str_get(map(cmd
+ 1)))
1024 in_push(str_get(map(cmd
+ 1)), args
+ 1);
1033 while (!tr_nextreq())
1036 tr_nl
= c
== '\n' || c
< 0;
1043 for (i
= 0; i
< LEN(cmds
); i
++)
1044 str_dset(map(cmds
[i
].id
), &cmds
[i
]);
1045 dict_init(&cmap
, NCMAPS
, -1, 0, 0);