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]) ||
152 for (i
= 0; buf
[i
]; i
++)
153 sbuf_add(sbuf
, (unsigned char) buf
[i
]);
160 static void tr_de(char **args
)
168 if (args
[0][1] == 'a' && args
[0][2] == 'm' && str_get(id
))
169 sbuf_append(&sbuf
, str_get(id
));
170 macrobody(&sbuf
, args
[2] ? args
[2] : ".");
171 str_set(id
, sbuf_buf(&sbuf
));
175 static void tr_ig(char **args
)
177 macrobody(NULL
, args
[1] ? args
[1] : ".");
180 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
181 static int read_until(struct sbuf
*sbuf
, char *stop
,
182 int (*next
)(void), void (*back
)(int))
184 char cs
[GNLEN
], cs2
[GNLEN
];
186 while ((c
= next()) >= 0) {
192 if (!stop
&& (c
== ' ' || c
== '\t'))
194 charnext(cs
, next
, back
);
195 if (stop
&& !strcmp(stop
, cs
))
197 charnext_str(cs2
, cs
);
198 sbuf_append(sbuf
, cs2
);
203 /* evaluate .if strcmp (i.e. 'str'str') */
204 static int if_strcmp(int (*next
)(void), void (*back
)(int))
209 charnext(delim
, next
, back
);
212 read_until(&s1
, delim
, next
, back
);
213 read_until(&s2
, delim
, next
, back
);
214 ret
= !strcmp(sbuf_buf(&s1
), sbuf_buf(&s2
));
220 /* evaluate .if condition letters */
221 static int if_cond(int (*next
)(void), void (*back
)(int))
236 /* evaluate .if condition */
237 static int if_eval(int (*next
)(void), void (*back
)(int))
242 read_until(&sbuf
, NULL
, next
, back
);
243 ret
= eval(sbuf_buf(&sbuf
), '\0') > 0;
248 static int eval_if(int (*next
)(void), void (*back
)(int))
255 } while (c
== ' ' || c
== '\t');
261 if (strchr("oetn", c
)) {
262 ret
= if_cond(next
, back
);
263 } else if (!isdigit(c
) && !strchr("-+*/%<=>&:.|()", c
)) {
264 ret
= if_strcmp(next
, back
);
266 ret
= if_eval(next
, back
);
271 static int ie_cond
[NIES
]; /* .ie condition stack */
274 static void tr_if(char **args
)
276 int c
= eval_if(cp_next
, cp_back
);
277 if (args
[0][1] == 'i' && args
[0][2] == 'e') /* .ie command */
279 ie_cond
[ie_depth
++] = c
;
283 static void tr_el(char **args
)
285 cp_blk(ie_depth
> 0 ? ie_cond
[--ie_depth
] : 1);
288 static void tr_na(char **args
)
293 static int adjmode(int c
, int def
)
309 static void tr_ad(char **args
)
318 n_j
= s
[0] == 'p' ? AD_P
| adjmode(s
[1], AD_B
) : adjmode(s
[0], n_j
);
321 static void tr_tm(char **args
)
323 fprintf(stderr
, "%s\n", args
[1]);
326 static void tr_so(char **args
)
332 static void tr_nx(char **args
)
337 static void tr_ex(char **args
)
342 static void tr_sy(char **args
)
347 static void tr_lt(char **args
)
349 int lt
= args
[1] ? eval_re(args
[1], n_lt
, 'm') : n_t0
;
354 static void tr_pc(char **args
)
356 c_pc
= args
[1] ? args
[1][0] : -1;
359 static int tl_next(void)
362 if (c
>= 0 && c
== c_pc
) {
363 in_push(num_str(map("%")), NULL
);
369 static void tr_tl(char **args
)
374 } while (c
>= 0 && (c
== ' ' || c
== '\t'));
376 ren_tl(tl_next
, cp_back
);
379 } while (c
>= 0 && c
!= '\n');
382 static void tr_ec(char **args
)
384 c_ec
= args
[1] ? args
[1][0] : '\\';
387 static void tr_cc(char **args
)
389 c_cc
= args
[1] ? args
[1][0] : '.';
392 static void tr_c2(char **args
)
394 c_c2
= args
[1] ? args
[1][0] : '\'';
397 static void tr_eo(char **args
)
402 static void tr_hc(char **args
)
405 if (!s
|| charread(&s
, c_hc
) < 0)
409 static void tr_nh(char **args
)
414 static void tr_hy(char **args
)
416 n_hy
= args
[1] ? atoi(args
[1]) : 1;
419 static void tr_hyp(char **args
)
421 n_hyp
= args
[1] ? atoi(args
[1]) : 1;
424 static void tr_lg(char **args
)
427 n_lg
= atoi(args
[1]);
430 static void tr_kn(char **args
)
433 n_kn
= atoi(args
[1]);
436 static void tr_cp(char **args
)
439 n_cp
= atoi(args
[1]);
442 static void tr_ss(char **args
)
445 n_ss
= eval_re(args
[1], n_ss
, 0);
446 n_sss
= args
[2] ? eval_re(args
[2], n_sss
, 0) : n_ss
;
450 static void tr_ssh(char **args
)
452 n_ssh
= args
[1] ? eval_re(args
[1], n_ssh
, 0) : 0;
455 static void tr_cs(char **args
)
457 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
459 font_setcs(fn
, args
[2] ? eval(args
[2], 0) : 0,
460 args
[3] ? eval(args
[3], 0) : 0);
463 static void tr_fzoom(char **args
)
465 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
467 font_setzoom(fn
, args
[2] ? eval(args
[2], 0) : 0);
470 static void tr_ff(char **args
)
472 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
474 for (i
= 2; i
<= NARGS
; i
++)
475 if (fn
&& args
[i
] && args
[i
][0] && args
[i
][1])
476 font_feat(fn
, args
[i
] + 1, args
[i
][0] == '+');
479 static void tr_nm(char **args
)
486 n_ln
= eval_re(args
[1], n_ln
, 0);
488 if (args
[2] && isdigit(args
[2][0]))
489 n_nM
= MAX(1, eval(args
[2], 0));
490 if (args
[3] && isdigit(args
[3][0]))
491 n_nS
= MAX(0, eval(args
[3], 0));
492 if (args
[4] && isdigit(args
[4][0]))
493 n_nI
= MAX(0, eval(args
[4], 0));
496 static void tr_nn(char **args
)
498 n_nn
= args
[1] ? eval(args
[1], 0) : 1;
501 static void tr_bd(char **args
)
503 if (!args
[1] || !strcmp("S", args
[1]))
505 font_setbd(dev_font(dev_pos(args
[1])), args
[2] ? eval(args
[2], 'u') : 0);
508 static void tr_it(char **args
)
512 n_itn
= eval(args
[1], 0);
518 static void tr_mc(char **args
)
521 if (s
&& charread(&s
, c_mc
) >= 0) {
523 n_mcn
= args
[2] ? eval(args
[2], 'm') : SC_EM
;
529 static void tr_tc(char **args
)
532 if (!s
|| charread(&s
, c_tc
) < 0)
536 static void tr_lc(char **args
)
539 if (!s
|| charread(&s
, c_lc
) < 0)
543 static void tr_lf(char **args
)
546 in_lf(args
[2], eval(args
[1], 0));
549 static void tr_chop(char **args
)
554 in_lf(args
[2], eval(args
[1], 0));
558 sbuf_append(&sbuf
, str_get(id
));
559 if (!sbuf_empty(&sbuf
)) {
560 sbuf_cut(&sbuf
, sbuf_len(&sbuf
) - 1);
561 str_set(id
, sbuf_buf(&sbuf
));
567 /* character translation (.tr) */
568 static struct dict cmap
; /* character mapping */
569 static char cmap_src
[NCMAPS
][GNLEN
]; /* source character */
570 static char cmap_dst
[NCMAPS
][GNLEN
]; /* character mapping */
571 static int cmap_n
; /* number of translated character */
573 void cmap_add(char *c1
, char *c2
)
575 int i
= dict_get(&cmap
, c1
);
577 strcpy(cmap_dst
[i
], c2
);
578 } else if (cmap_n
< NCMAPS
) {
579 strcpy(cmap_src
[cmap_n
], c1
);
580 strcpy(cmap_dst
[cmap_n
], c2
);
581 dict_put(&cmap
, cmap_src
[cmap_n
], cmap_n
);
586 char *cmap_map(char *c
)
588 int i
= dict_get(&cmap
, c
);
589 return i
>= 0 ? cmap_dst
[i
] : c
;
592 static void tr_tr(char **args
)
595 char c1
[GNLEN
], c2
[GNLEN
];
596 while (s
&& charread(&s
, c1
) >= 0) {
597 if (charread(&s
, c2
) < 0)
603 /* character definition (.char) */
604 static char cdef_src
[NCDEFS
][GNLEN
]; /* source character */
605 static char *cdef_dst
[NCDEFS
]; /* character definition */
606 static int cdef_fn
[NCDEFS
]; /* owning font */
607 static int cdef_n
; /* number of defined characters */
608 static int cdef_expanding
; /* inside cdef_expand() call */
610 static int cdef_find(char *c
, int fn
)
613 for (i
= 0; i
< cdef_n
; i
++)
614 if ((!cdef_fn
[i
] || cdef_fn
[i
] == fn
) && !strcmp(cdef_src
[i
], c
))
619 /* return the definition of the given character */
620 char *cdef_map(char *c
, int fn
)
622 int i
= cdef_find(c
, fn
);
623 return !cdef_expanding
&& i
>= 0 ? cdef_dst
[i
] : NULL
;
626 int cdef_expand(struct wb
*wb
, char *s
, int fn
)
628 char *d
= cdef_map(s
, fn
);
637 static void cdef_add(char *fn
, char *cs
, char *def
)
641 if (!def
|| charread(&cs
, c
) < 0)
643 i
= cdef_find(c
, -1);
644 if (i
< 0 && cdef_n
< NCDEFS
)
647 strncpy(cdef_src
[i
], c
, sizeof(cdef_src
[i
]) - 1);
648 cdef_dst
[i
] = xmalloc(strlen(def
) + 1);
649 strcpy(cdef_dst
[i
], def
);
650 cdef_fn
[i
] = fn
? dev_pos(fn
) : 0;
654 static void cdef_remove(char *cs
)
658 if (!cs
|| charread(&cs
, c
) < 0)
660 for (i
= 0; i
< cdef_n
; i
++) {
661 if (!strcmp(cdef_src
[i
], c
)) {
664 cdef_src
[i
][0] = '\0';
669 static void tr_char(char **args
)
671 cdef_add(NULL
, args
[1], args
[2]);
674 static void tr_rchar(char **args
)
677 for (i
= 1; i
<= NARGS
; i
++)
679 cdef_remove(args
[i
]);
682 static void tr_ochar(char **args
)
684 cdef_add(args
[1], args
[2], args
[3]);
687 static void tr_fmap(char **args
)
689 struct font
*fn
= args
[1] ? dev_font(dev_pos(args
[1])) : NULL
;
691 font_map(fn
, args
[2], args
[3]);
694 static void arg_regname(struct sbuf
*sbuf
)
698 sbuf_append(sbuf
, reg
);
702 static void arg_string(struct sbuf
*sbuf
)
705 while ((c
= cp_next()) == ' ')
709 while (c
> 0 && c
!= '\n') {
719 static int mkargs_arg(struct sbuf
*sbuf
, int (*next
)(void), void (*back
)(int))
728 if (c
< 0 || c
== '\n')
734 while (c
>= 0 && c
!= '\n') {
735 if (!quoted
&& c
== ' ')
737 if (quoted
&& c
== '"') {
755 /* read macro arguments */
756 int tr_readargs(char **args
, struct sbuf
*sbuf
, int (*next
)(void), void (*back
)(int))
761 idx
[n
] = sbuf_len(sbuf
);
762 if (mkargs_arg(sbuf
, next
, back
))
766 for (i
= 0; i
< n
; i
++)
767 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
771 /* read macro arguments; trims tabs if rmtabs is nonzero */
772 static int mkargs(char **args
, struct sbuf
*sbuf
)
774 int n
= tr_readargs(args
, sbuf
, cp_next
, cp_back
);
779 /* read request arguments; trims tabs too */
780 static int mkargs_req(char **args
, struct sbuf
*sbuf
)
787 idx
[n
] = sbuf_len(sbuf
);
788 while (c
== ' ' || c
== '\t')
790 while (c
>= 0 && c
!= '\n' && c
!= ' ' && c
!= '\t') {
795 if (sbuf_len(sbuf
) > idx
[n
])
800 if (c
< 0 || c
== '\n')
803 for (i
= 0; i
< n
; i
++)
804 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
809 /* read arguments for .ds */
810 static int mkargs_ds(char **args
, struct sbuf
*sbuf
)
814 idx
[n
++] = sbuf_len(sbuf
);
816 idx
[n
++] = sbuf_len(sbuf
);
821 for (i
= 0; i
< n
; i
++)
822 args
[i
] = sbuf_buf(sbuf
) + idx
[i
];
826 /* read arguments for commands .nr that expect a register name */
827 static int mkargs_reg1(char **args
, struct sbuf
*sbuf
)
830 int idx0
= sbuf_len(sbuf
);
832 n
= mkargs_req(args
+ 1, sbuf
) + 1;
833 args
[0] = sbuf_buf(sbuf
) + idx0
;
837 /* do not read arguments; for .if, .ie and .el */
838 static int mkargs_null(char **args
, struct sbuf
*sbuf
)
843 /* read the whole line for .tm */
844 static int mkargs_eol(char **args
, struct sbuf
*sbuf
)
846 int idx0
= sbuf_len(sbuf
);
852 while (c
>= 0 && c
!= '\n') {
858 args
[0] = sbuf_buf(sbuf
) + idx0
;
864 void (*f
)(char **args
);
865 int (*args
)(char **args
, struct sbuf
*sbuf
);
867 {TR_DIVBEG
, tr_divbeg
},
868 {TR_DIVEND
, tr_divend
},
869 {TR_POPREN
, tr_popren
},
870 {"ab", tr_ab
, mkargs_eol
},
873 {"am", tr_de
, mkargs_reg1
},
874 {"as", tr_as
, mkargs_ds
},
883 {"char", tr_char
, mkargs_ds
},
884 {"chop", tr_chop
, mkargs_reg1
},
889 {"de", tr_de
, mkargs_reg1
},
891 {"ds", tr_ds
, mkargs_ds
},
894 {"el", tr_el
, mkargs_null
},
905 {"fspecial", tr_fspecial
},
915 {"ie", tr_if
, mkargs_null
},
916 {"if", tr_if
, mkargs_null
},
935 {"nr", tr_nr
, mkargs_reg1
},
944 {"rchar", tr_rchar
, mkargs_ds
},
955 {"sy", tr_sy
, mkargs_eol
},
959 {"tl", tr_tl
, mkargs_null
},
960 {"tm", tr_tm
, mkargs_eol
},
961 {"tr", tr_tr
, mkargs_eol
},
966 /* read the next troff request; return zero if a request was executed. */
969 char *args
[NARGS
+ 3] = {NULL
};
977 if (c
< 0 || (c
!= c_cc
&& c
!= c_c2
)) {
981 memset(args
, 0, sizeof(args
));
986 read_regname(cmd
+ 1);
988 req
= str_dget(map(cmd
+ 1));
991 req
->args(args
+ 1, &sbuf
);
993 mkargs_req(args
+ 1, &sbuf
);
997 mkargs(args
+ 1, &sbuf
);
999 if (str_get(map(cmd
+ 1)))
1000 in_push(str_get(map(cmd
+ 1)), args
+ 1);
1009 while (!tr_nextreq())
1012 tr_nl
= c
== '\n' || c
< 0;
1019 for (i
= 0; i
< LEN(cmds
); i
++)
1020 str_dset(map(cmds
[i
].id
), &cmds
[i
]);
1021 dict_init(&cmap
, NCMAPS
, -1, 0, 0);