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
, 0), 'u'));
50 num_inc(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
= malloc(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 char *arg_regname(char *s
, int len
);
113 static void macrobody(struct sbuf
*sbuf
, char *end
)
119 cp_wid(0); /* copy-mode; disable \w handling */
120 while ((c
= cp_next()) >= 0) {
127 arg_regname(buf
, sizeof(buf
));
128 if ((n_cp
&& end
[0] == buf
[0] && end
[1] == buf
[1]) ||
136 for (i
= 0; buf
[i
]; i
++)
137 sbuf_add(sbuf
, (unsigned char) buf
[i
]);
147 static void tr_de(char **args
)
155 if (args
[0][1] == 'a' && args
[0][2] == 'm' && str_get(id
))
156 sbuf_append(&sbuf
, str_get(id
));
157 macrobody(&sbuf
, args
[2] ? args
[2] : ".");
158 str_set(id
, sbuf_buf(&sbuf
));
162 static void tr_ig(char **args
)
164 macrobody(NULL
, args
[1] ? args
[1] : ".");
167 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
168 static int read_until(struct sbuf
*sbuf
, char *stop
)
170 char cs
[GNLEN
], cs2
[GNLEN
];
172 while ((c
= cp_next()) >= 0) {
176 if (!stop
&& (c
== ' ' || c
== '\t'))
178 charnext(cs
, cp_next
, cp_back
);
179 if (stop
&& !strcmp(stop
, cs
))
181 charnext_str(cs2
, cs
);
182 sbuf_append(sbuf
, cs2
);
187 /* evaluate .if strcmp (i.e. 'str'str') */
188 static int if_strcmp(void)
193 charnext(delim
, cp_next
, cp_back
);
196 read_until(&s1
, delim
);
197 read_until(&s2
, delim
);
198 ret
= !strcmp(sbuf_buf(&s1
), sbuf_buf(&s2
));
204 /* evaluate .if condition letters */
205 static int if_cond(void)
220 /* evaluate .if condition */
221 static int if_eval(void)
226 if (!read_until(&sbuf
, NULL
))
228 ret
= eval(sbuf_buf(&sbuf
), '\0') > 0;
233 static int ie_cond
[NIES
]; /* .ie condition stack */
236 static void tr_if(char **args
)
243 } while (c
== ' ' || c
== '\t');
249 if (strchr("oetn", c
)) {
251 } else if (!isdigit(c
) && !strchr("-+*/%<=>&:.|()", c
)) {
256 if (args
[0][1] == 'i' && args
[0][2] == 'e') /* .ie command */
258 ie_cond
[ie_depth
++] = ret
!= neg
;
262 static void tr_el(char **args
)
264 cp_blk(ie_depth
> 0 ? ie_cond
[--ie_depth
] : 1);
267 static void tr_na(char **args
)
272 static void tr_ad(char **args
)
277 switch (args
[1][0]) {
298 static void tr_tm(char **args
)
300 fprintf(stderr
, "%s\n", args
[1]);
303 static void tr_so(char **args
)
309 static void tr_nx(char **args
)
314 static void tr_ex(char **args
)
319 static void tr_sy(char **args
)
324 static void tr_lt(char **args
)
326 int lt
= args
[1] ? eval_re(args
[1], n_lt
, 'm') : n_t0
;
331 static void tr_pc(char **args
)
333 c_pc
= args
[1] ? args
[1][0] : -1;
336 static int tl_next(void)
339 if (c
>= 0 && c
== c_pc
) {
340 in_push(num_str(map("%")), NULL
);
346 static void tr_tl(char **args
)
351 } while (c
>= 0 && (c
== ' ' || c
== '\t'));
353 ren_tl(tl_next
, cp_back
);
356 } while (c
>= 0 && c
!= '\n');
359 static void tr_ec(char **args
)
361 c_ec
= args
[1] ? args
[1][0] : '\\';
364 static void tr_cc(char **args
)
366 c_ec
= args
[1] ? args
[1][0] : '.';
369 static void tr_c2(char **args
)
371 c_ec
= args
[1] ? args
[1][0] : '\'';
374 static void tr_eo(char **args
)
379 static void tr_hc(char **args
)
382 if (!s
|| charread(&s
, c_hc
) < 0)
386 static void tr_nh(char **args
)
391 static void tr_hy(char **args
)
393 n_hy
= args
[1] ? atoi(args
[1]) : 1;
396 static void tr_lg(char **args
)
399 n_lg
= atoi(args
[1]);
402 static void tr_kn(char **args
)
405 n_kn
= atoi(args
[1]);
408 static void tr_cp(char **args
)
411 n_cp
= atoi(args
[1]);
414 static void tr_ss(char **args
)
417 n_ss
= eval_re(args
[1], n_ss
, 0);
420 static void tr_cs(char **args
)
424 dev_setcs(dev_pos(args
[1]), args
[2] ? eval(args
[2], 0) : 0);
427 static void tr_nm(char **args
)
434 n_ln
= eval_re(args
[1], n_ln
, 0);
436 if (args
[2] && isdigit(args
[2][0]))
437 n_nM
= MAX(1, eval(args
[2], 0));
438 if (args
[3] && isdigit(args
[3][0]))
439 n_nS
= MAX(0, eval(args
[3], 0));
440 if (args
[4] && isdigit(args
[4][0]))
441 n_nI
= MAX(0, eval(args
[4], 0));
444 static void tr_nn(char **args
)
446 n_nn
= args
[1] ? eval(args
[1], 0) : 1;
449 static void tr_bd(char **args
)
451 if (!args
[1] || !strcmp("S", args
[1]))
453 dev_setbd(dev_pos(args
[1]), args
[2] ? eval(args
[2], 'u') : 0);
456 static void tr_it(char **args
)
460 n_itn
= eval(args
[1], 0);
466 static void tr_mc(char **args
)
469 if (s
&& charread(&s
, c_mc
) >= 0) {
471 n_mcn
= args
[2] ? eval(args
[2], 'm') : SC_EM
;
477 static void tr_tc(char **args
)
480 if (!s
|| charread(&s
, c_tc
) < 0)
484 static void tr_lc(char **args
)
487 if (!s
|| charread(&s
, c_lc
) < 0)
491 static void tr_lf(char **args
)
494 in_lf(args
[2], eval(args
[1], 0));
497 static void tr_chop(char **args
)
502 in_lf(args
[2], eval(args
[1], 0));
506 sbuf_append(&sbuf
, str_get(id
));
507 if (!sbuf_empty(&sbuf
)) {
508 sbuf_cut(&sbuf
, sbuf_len(&sbuf
) - 1);
509 str_set(id
, sbuf_buf(&sbuf
));
515 /* character translation (.tr) */
516 static char cmap_src
[NCMAPS
][GNLEN
]; /* source character */
517 static char cmap_dst
[NCMAPS
][GNLEN
]; /* character mapping */
518 static int cmap_n
; /* number of translated character */
520 static int tr_find(char *c
)
523 for (i
= 0; i
< cmap_n
; i
++)
524 if (!strcmp(c
, cmap_src
[i
]))
529 void cmap_add(char *c1
, char *c2
)
532 if (i
< 0 && cmap_n
< NCMAPS
)
535 strcpy(cmap_src
[i
], c1
);
536 strcpy(cmap_dst
[i
], c2
);
540 char *cmap_map(char *c
)
543 return i
>= 0 ? cmap_dst
[i
] : c
;
546 static void tr_tr(char **args
)
549 char c1
[GNLEN
], c2
[GNLEN
];
550 while (s
&& charread(&s
, c1
) >= 0) {
551 if (charread(&s
, c2
) < 0)
557 /* character definition (.char) */
558 static char cdef_src
[NCDEFS
][GNLEN
]; /* source character */
559 static char *cdef_dst
[NCDEFS
]; /* character definition */
560 static int cdef_fn
[NCDEFS
]; /* owning font */
561 static int cdef_n
; /* number of defined characters */
562 static int cdef_expanding
; /* inside cdef_expand() call */
564 static int cdef_find(char *c
, int fn
)
567 for (i
= 0; i
< cdef_n
; i
++)
568 if (!strcmp(cdef_src
[i
], c
) && (!cdef_fn
[i
] || cdef_fn
[i
] == fn
))
573 /* return the definition of the given character */
574 char *cdef_map(char *c
, int fn
)
576 int i
= cdef_find(c
, fn
);
577 return !cdef_expanding
&& i
>= 0 ? cdef_dst
[i
] : NULL
;
580 int cdef_expand(struct wb
*wb
, char *s
, int fn
)
582 char *d
= cdef_map(s
, fn
);
591 static void cdef_add(char *fn
, char *cs
, char *def
)
595 if (!def
|| charread(&cs
, c
) < 0)
597 i
= cdef_find(c
, -1);
598 if (i
< 0 && cdef_n
< NCDEFS
)
601 strncpy(cdef_src
[i
], c
, sizeof(cdef_src
[i
]) - 1);
602 cdef_dst
[i
] = malloc(strlen(def
) + 1);
603 strcpy(cdef_dst
[i
], def
);
604 cdef_fn
[i
] = fn
? dev_pos(fn
) : 0;
608 static void cdef_remove(char *cs
)
612 if (!cs
|| charread(&cs
, c
) < 0)
614 for (i
= 0; i
< cdef_n
; i
++) {
615 if (!strcmp(cdef_src
[i
], c
)) {
618 cdef_src
[i
][0] = '\0';
623 static void tr_char(char **args
)
625 cdef_add(NULL
, args
[1], args
[2]);
628 static void tr_rchar(char **args
)
631 for (i
= 1; i
<= NARGS
; i
++)
633 cdef_remove(args
[i
]);
636 static void tr_ochar(char **args
)
638 cdef_add(args
[1], args
[2], args
[3]);
641 static void tr_fmap(char **args
)
646 fn
= dev_font(dev_pos(args
[1]));
648 font_map(fn
, args
[2], args
[3] ? font_glyph(fn
, args
[3]) : NULL
);
651 static char *arg_regname(char *s
, int len
)
653 char *e
= n_cp
? s
+ 2 : s
+ len
;
655 while (c
== ' ' || c
== '\t')
657 while (s
< e
&& c
>= 0 && c
!= ' ' && c
!= '\t' && c
!= '\n') {
667 static char *arg_normal(char *s
, int len
)
669 char *e
= s
+ len
- 1;
679 while (s
< e
&& c
> 0 && c
!= '\n') {
680 if (!quoted
&& c
== ' ')
682 if (quoted
&& c
== '"') {
696 static char *arg_string(char *s
, int len
)
698 char *e
= s
+ len
- 1;
700 while ((c
= cp_next()) == ' ')
704 while (s
< e
&& c
> 0 && c
!= '\n') {
714 /* read macro arguments; trims tabs if rmtabs is nonzero */
715 static int mkargs(char **args
, char *buf
, int len
)
718 char *e
= buf
+ len
- 1;
724 if (c
< 0 || c
== '\n')
727 s
= arg_normal(s
, e
- s
);
735 /* read request arguments; trims tabs too */
736 static int mkargs_req(char **args
, char *buf
, int len
)
739 char *e
= buf
+ len
- 1;
743 while (n
< NARGS
&& s
< e
) {
745 while (c
== ' ' || c
== '\t')
747 while (c
>= 0 && c
!= '\n' && c
!= ' ' && c
!= '\t' && s
< e
) {
754 if (c
< 0 || c
== '\n')
761 /* read arguments for .ds */
762 static int mkargs_ds(char **args
, char *buf
, int len
)
765 char *e
= buf
+ len
- 1;
768 s
= arg_regname(s
, e
- s
);
771 s
= arg_string(s
, e
- s
);
774 if (c
>= 0 && c
!= '\n')
779 /* read arguments for commands .nr that expect a register name */
780 static int mkargs_reg1(char **args
, char *buf
, int len
)
783 char *e
= buf
+ len
- 1;
785 s
= arg_regname(s
, e
- s
);
786 return mkargs_req(args
+ 1, s
, e
- s
) + 1;
789 /* do not read arguments; for .if, .ie and .el */
790 static int mkargs_null(char **args
, char *buf
, int len
)
795 /* read the whole line for .tm */
796 static int mkargs_eol(char **args
, char *buf
, int len
)
799 char *e
= buf
+ len
- 1;
805 while (s
< e
&& c
>= 0 && c
!= '\n') {
815 void (*f
)(char **args
);
816 int (*args
)(char **args
, char *buf
, int len
);
818 {TR_DIVBEG
, tr_divbeg
},
819 {TR_DIVEND
, tr_divend
},
820 {TR_EJECT
, tr_eject
},
821 {"ab", tr_ab
, mkargs_eol
},
824 {"am", tr_de
, mkargs_reg1
},
825 {"as", tr_as
, mkargs_ds
},
834 {"char", tr_char
, mkargs_ds
},
835 {"chop", tr_chop
, mkargs_reg1
},
840 {"de", tr_de
, mkargs_reg1
},
842 {"ds", tr_ds
, mkargs_ds
},
845 {"el", tr_el
, mkargs_null
},
854 {"fspecial", tr_fspecial
},
859 {"ie", tr_if
, mkargs_null
},
860 {"if", tr_if
, mkargs_null
},
879 {"nr", tr_nr
, mkargs_reg1
},
888 {"rchar", tr_rchar
, mkargs_ds
},
898 {"sy", tr_sy
, mkargs_eol
},
902 {"tl", tr_tl
, mkargs_null
},
903 {"tm", tr_tm
, mkargs_eol
},
904 {"tr", tr_tr
, mkargs_eol
},
913 char *args
[NARGS
+ 3] = {NULL
};
917 while (tr_nl
&& c
>= 0 && (c
== c_cc
|| c
== c_c2
)) {
919 memset(args
, 0, sizeof(args
));
923 arg_regname(cmd
+ 1, sizeof(cmd
) - 1);
924 req
= str_dget(map(cmd
+ 1));
927 req
->args(args
+ 1, buf
, sizeof(buf
));
929 mkargs_req(args
+ 1, buf
, sizeof(buf
));
933 mkargs(args
+ 1, buf
, sizeof(buf
));
935 if (str_get(map(cmd
+ 1)))
936 in_push(str_get(map(cmd
+ 1)), args
+ 1);
948 for (i
= 0; i
< LEN(cmds
); i
++)
949 str_dset(map(cmds
[i
].id
), &cmds
[i
]);