tr: fix .cc and .c2
[neatroff.git] / tr.c
blob1e43cc9c02720abc13bc2eb6f75a1c2954479ef4
1 /* built-in troff requests */
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "roff.h"
8 static int tr_nl = 1; /* just read a newline */
9 static int c_pc = '%'; /* page number character */
10 int c_ec = '\\';
11 int c_cc = '.';
12 int c_c2 = '\'';
14 /* skip everything until the end of line */
15 static void jmp_eol(void)
17 int c;
18 do {
19 c = cp_next();
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;
26 n_v0 = n_v;
27 n_v = MAX(0, vs);
30 static void tr_ls(char **args)
32 int ls = args[1] ? eval_re(args[1], n_L, 0) : n_L0;
33 n_L0 = n_L;
34 n_L = MAX(1, ls);
37 static void tr_pl(char **args)
39 int n = eval_re(args[1] ? args[1] : "11i", n_p, 'v');
40 n_p = MAX(0, n);
43 static void tr_nr(char **args)
45 int id;
46 if (!args[2])
47 return;
48 id = map(args[1]);
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)
55 int i;
56 for (i = 1; i <= NARGS; i++)
57 if (args[i])
58 num_del(map(args[i]));
61 static void tr_af(char **args)
63 if (args[2])
64 num_setfmt(map(args[1]), args[2]);
67 static void tr_ds(char **args)
69 if (args[2])
70 str_set(map(args[1]), args[2]);
73 static void tr_as(char **args)
75 int reg;
76 char *s1, *s2, *s;
77 if (!args[2])
78 return;
79 reg = map(args[1]);
80 s1 = str_get(reg) ? str_get(reg) : "";
81 s2 = args[2];
82 s = xmalloc(strlen(s1) + strlen(s2) + 1);
83 strcpy(s, s1);
84 strcat(s, s2);
85 str_set(reg, s);
86 free(s);
89 static void tr_rm(char **args)
91 int i;
92 for (i = 1; i <= NARGS; i++)
93 if (args[i])
94 str_rm(map(args[i]));
97 static void tr_rn(char **args)
99 if (!args[2])
100 return;
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;
107 n_o0 = n_o;
108 n_o = MAX(0, po);
111 static void read_regname(char *s)
113 int c = cp_next();
114 int n = n_cp ? 2 : NMLEN - 1;
115 while (c == ' ' || c == '\t')
116 c = cp_next();
117 while (c >= 0 && c != ' ' && c != '\t' && c != '\n' && --n >= 0) {
118 *s++ = c;
119 c = cp_next();
121 if (c >= 0)
122 cp_back(c);
123 *s = '\0';
126 static void macrobody(struct sbuf *sbuf, char *end)
128 char buf[NMLEN];
129 int i, c;
130 int first = 1;
131 cp_back('\n');
132 cp_copymode(1);
133 while ((c = cp_next()) >= 0) {
134 if (sbuf && !first)
135 sbuf_add(sbuf, c);
136 first = 0;
137 if (c == '\n') {
138 if ((c = cp_next()) != '.') {
139 cp_back(c);
140 continue;
142 read_regname(buf);
143 if ((n_cp && end[0] == buf[0] && end[1] == buf[1]) ||
144 !strcmp(end, buf)) {
145 jmp_eol();
146 break;
148 if (sbuf) {
149 sbuf_add(sbuf, '.');
150 for (i = 0; buf[i]; i++)
151 sbuf_add(sbuf, (unsigned char) buf[i]);
155 cp_copymode(0);
158 static void tr_de(char **args)
160 struct sbuf sbuf;
161 int id;
162 if (!args[1])
163 return;
164 id = map(args[1]);
165 sbuf_init(&sbuf);
166 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
167 sbuf_append(&sbuf, str_get(id));
168 macrobody(&sbuf, args[2] ? args[2] : ".");
169 str_set(id, sbuf_buf(&sbuf));
170 sbuf_done(&sbuf);
173 static void tr_ig(char **args)
175 macrobody(NULL, args[1] ? args[1] : ".");
178 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
179 static int read_until(struct sbuf *sbuf, char *stop,
180 int (*next)(void), void (*back)(int))
182 char cs[GNLEN], cs2[GNLEN];
183 int c;
184 while ((c = next()) >= 0) {
185 back(c);
186 if (c == '\n')
187 return 1;
188 if (!stop && (c == ' ' || c == '\t'))
189 return 0;
190 charnext(cs, next, back);
191 if (stop && !strcmp(stop, cs))
192 return 0;
193 charnext_str(cs2, cs);
194 sbuf_append(sbuf, cs2);
196 return 1;
199 /* evaluate .if strcmp (i.e. 'str'str') */
200 static int if_strcmp(int (*next)(void), void (*back)(int))
202 char delim[GNLEN];
203 struct sbuf s1, s2;
204 int ret;
205 charnext(delim, next, back);
206 sbuf_init(&s1);
207 sbuf_init(&s2);
208 read_until(&s1, delim, next, back);
209 read_until(&s2, delim, next, back);
210 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
211 sbuf_done(&s1);
212 sbuf_done(&s2);
213 return ret;
216 /* evaluate .if condition letters */
217 static int if_cond(int (*next)(void), void (*back)(int))
219 switch (cp_next()) {
220 case 'o':
221 return n_pg % 2;
222 case 'e':
223 return !(n_pg % 2);
224 case 't':
225 return 1;
226 case 'n':
227 return 0;
229 return 0;
232 /* evaluate .if condition */
233 static int if_eval(int (*next)(void), void (*back)(int))
235 struct sbuf sbuf;
236 int ret;
237 sbuf_init(&sbuf);
238 read_until(&sbuf, NULL, next, back);
239 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
240 sbuf_done(&sbuf);
241 return ret;
244 static int eval_if(int (*next)(void), void (*back)(int))
246 int neg = 0;
247 int ret;
248 int c;
249 do {
250 c = next();
251 } while (c == ' ' || c == '\t');
252 if (c == '!') {
253 neg = 1;
254 c = next();
256 back(c);
257 if (strchr("oetn", c)) {
258 ret = if_cond(next, back);
259 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
260 ret = if_strcmp(next, back);
261 } else {
262 ret = if_eval(next, back);
264 return ret != neg;
267 static int ie_cond[NIES]; /* .ie condition stack */
268 static int ie_depth;
270 static void tr_if(char **args)
272 int c = eval_if(cp_next, cp_back);
273 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
274 if (ie_depth < NIES)
275 ie_cond[ie_depth++] = c;
276 cp_blk(!c);
279 static void tr_el(char **args)
281 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
284 static void tr_na(char **args)
286 n_na = 1;
289 static int adjmode(int c, int def)
291 switch (c) {
292 case 'l':
293 return AD_L;
294 case 'r':
295 return AD_R;
296 case 'c':
297 return AD_C;
298 case 'b':
299 case 'n':
300 return AD_B;
302 return def;
305 static void tr_ad(char **args)
307 char *s = args[1];
308 n_na = 0;
309 if (!s)
310 return;
311 if (isdigit(s[0]))
312 n_j = atoi(s) & 15;
313 else
314 n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j);
317 static void tr_tm(char **args)
319 fprintf(stderr, "%s\n", args[1]);
322 static void tr_so(char **args)
324 if (args[1])
325 in_so(args[1]);
328 static void tr_nx(char **args)
330 in_nx(args[1]);
333 static void tr_ex(char **args)
335 in_ex();
338 static void tr_sy(char **args)
340 system(args[1]);
343 static void tr_lt(char **args)
345 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
346 n_t0 = n_t0;
347 n_lt = MAX(0, lt);
350 static void tr_pc(char **args)
352 c_pc = args[1] ? args[1][0] : -1;
355 static int tl_next(void)
357 int c = cp_next();
358 if (c >= 0 && c == c_pc) {
359 in_push(num_str(map("%")), NULL);
360 c = cp_next();
362 return c;
365 static void tr_tl(char **args)
367 int c;
368 do {
369 c = cp_next();
370 } while (c >= 0 && (c == ' ' || c == '\t'));
371 cp_back(c);
372 ren_tl(tl_next, cp_back);
373 do {
374 c = cp_next();
375 } while (c >= 0 && c != '\n');
378 static void tr_ec(char **args)
380 c_ec = args[1] ? args[1][0] : '\\';
383 static void tr_cc(char **args)
385 c_cc = args[1] ? args[1][0] : '.';
388 static void tr_c2(char **args)
390 c_c2 = args[1] ? args[1][0] : '\'';
393 static void tr_eo(char **args)
395 c_ec = -1;
398 static void tr_hc(char **args)
400 char *s = args[1];
401 if (!s || charread(&s, c_hc) < 0)
402 strcpy(c_hc, "\\%");
405 static void tr_nh(char **args)
407 n_hy = 0;
410 static void tr_hy(char **args)
412 n_hy = args[1] ? atoi(args[1]) : 1;
415 static void tr_hyp(char **args)
417 n_hyp = args[1] ? atoi(args[1]) : 1;
420 static void tr_lg(char **args)
422 if (args[1])
423 n_lg = atoi(args[1]);
426 static void tr_kn(char **args)
428 if (args[1])
429 n_kn = atoi(args[1]);
432 static void tr_cp(char **args)
434 if (args[1])
435 n_cp = atoi(args[1]);
438 static void tr_ss(char **args)
440 if (args[1]) {
441 n_ss = eval_re(args[1], n_ss, 0);
442 n_sss = args[2] ? eval_re(args[2], n_sss, 0) : n_ss;
446 static void tr_ssh(char **args)
448 n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
451 static void tr_cs(char **args)
453 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
454 if (fn)
455 font_setcs(fn, args[2] ? eval(args[2], 0) : 0,
456 args[3] ? eval(args[3], 0) : 0);
459 static void tr_fzoom(char **args)
461 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
462 if (fn)
463 font_setzoom(fn, args[2] ? eval(args[2], 0) : 0);
466 static void tr_ff(char **args)
468 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
469 int i;
470 for (i = 2; i <= NARGS; i++)
471 if (fn && args[i] && args[i][0] && args[i][1])
472 font_feat(fn, args[i] + 1, args[i][0] == '+');
475 static void tr_nm(char **args)
477 if (!args[1]) {
478 n_nm = 0;
479 return;
481 n_nm = 1;
482 n_ln = eval_re(args[1], n_ln, 0);
483 n_ln = MAX(0, n_ln);
484 if (args[2] && isdigit(args[2][0]))
485 n_nM = MAX(1, eval(args[2], 0));
486 if (args[3] && isdigit(args[3][0]))
487 n_nS = MAX(0, eval(args[3], 0));
488 if (args[4] && isdigit(args[4][0]))
489 n_nI = MAX(0, eval(args[4], 0));
492 static void tr_nn(char **args)
494 n_nn = args[1] ? eval(args[1], 0) : 1;
497 static void tr_bd(char **args)
499 if (!args[1] || !strcmp("S", args[1]))
500 return;
501 font_setbd(dev_font(dev_pos(args[1])), args[2] ? eval(args[2], 'u') : 0);
504 static void tr_it(char **args)
506 if (args[2]) {
507 n_it = map(args[2]);
508 n_itn = eval(args[1], 0);
509 } else {
510 n_it = 0;
514 static void tr_mc(char **args)
516 char *s = args[1];
517 if (s && charread(&s, c_mc) >= 0) {
518 n_mc = 1;
519 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
520 } else {
521 n_mc = 0;
525 static void tr_tc(char **args)
527 char *s = args[1];
528 if (!s || charread(&s, c_tc) < 0)
529 strcpy(c_tc, "");
532 static void tr_lc(char **args)
534 char *s = args[1];
535 if (!s || charread(&s, c_lc) < 0)
536 strcpy(c_lc, "");
539 static void tr_lf(char **args)
541 if (args[1])
542 in_lf(args[2], eval(args[1], 0));
545 static void tr_chop(char **args)
547 struct sbuf sbuf;
548 int id;
549 if (args[1])
550 in_lf(args[2], eval(args[1], 0));
551 id = map(args[1]);
552 if (str_get(id)) {
553 sbuf_init(&sbuf);
554 sbuf_append(&sbuf, str_get(id));
555 if (!sbuf_empty(&sbuf)) {
556 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
557 str_set(id, sbuf_buf(&sbuf));
559 sbuf_done(&sbuf);
563 /* character translation (.tr) */
564 static struct dict cmap; /* character mapping */
565 static char cmap_src[NCMAPS][GNLEN]; /* source character */
566 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
567 static int cmap_n; /* number of translated character */
569 void cmap_add(char *c1, char *c2)
571 int i = dict_get(&cmap, c1);
572 if (i >= 0) {
573 strcpy(cmap_dst[i], c2);
574 } else if (cmap_n < NCMAPS) {
575 strcpy(cmap_src[cmap_n], c1);
576 strcpy(cmap_dst[cmap_n], c2);
577 dict_put(&cmap, cmap_src[cmap_n], cmap_n);
578 cmap_n++;
582 char *cmap_map(char *c)
584 int i = dict_get(&cmap, c);
585 return i >= 0 ? cmap_dst[i] : c;
588 static void tr_tr(char **args)
590 char *s = args[1];
591 char c1[GNLEN], c2[GNLEN];
592 while (s && charread(&s, c1) >= 0) {
593 if (charread(&s, c2) < 0)
594 strcpy(c2, " ");
595 cmap_add(c1, c2);
599 /* character definition (.char) */
600 static char cdef_src[NCDEFS][GNLEN]; /* source character */
601 static char *cdef_dst[NCDEFS]; /* character definition */
602 static int cdef_fn[NCDEFS]; /* owning font */
603 static int cdef_n; /* number of defined characters */
604 static int cdef_expanding; /* inside cdef_expand() call */
606 static int cdef_find(char *c, int fn)
608 int i;
609 for (i = 0; i < cdef_n; i++)
610 if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
611 return i;
612 return -1;
615 /* return the definition of the given character */
616 char *cdef_map(char *c, int fn)
618 int i = cdef_find(c, fn);
619 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
622 int cdef_expand(struct wb *wb, char *s, int fn)
624 char *d = cdef_map(s, fn);
625 if (!d)
626 return 1;
627 cdef_expanding = 1;
628 ren_parse(wb, d);
629 cdef_expanding = 0;
630 return 0;
633 static void cdef_add(char *fn, char *cs, char *def)
635 char c[GNLEN];
636 int i;
637 if (!def || charread(&cs, c) < 0)
638 return;
639 i = cdef_find(c, -1);
640 if (i < 0 && cdef_n < NCDEFS)
641 i = cdef_n++;
642 if (i >= 0) {
643 strncpy(cdef_src[i], c, sizeof(cdef_src[i]) - 1);
644 cdef_dst[i] = xmalloc(strlen(def) + 1);
645 strcpy(cdef_dst[i], def);
646 cdef_fn[i] = fn ? dev_pos(fn) : 0;
650 static void cdef_remove(char *cs)
652 char c[GNLEN];
653 int i;
654 if (!cs || charread(&cs, c) < 0)
655 return;
656 for (i = 0; i < cdef_n; i++) {
657 if (!strcmp(cdef_src[i], c)) {
658 free(cdef_dst[i]);
659 cdef_dst[i] = NULL;
660 cdef_src[i][0] = '\0';
665 static void tr_char(char **args)
667 cdef_add(NULL, args[1], args[2]);
670 static void tr_rchar(char **args)
672 int i;
673 for (i = 1; i <= NARGS; i++)
674 if (args[i])
675 cdef_remove(args[i]);
678 static void tr_ochar(char **args)
680 cdef_add(args[1], args[2], args[3]);
683 static void tr_fmap(char **args)
685 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
686 if (fn && args[2])
687 font_map(fn, args[2], args[3]);
690 static void arg_regname(struct sbuf *sbuf)
692 char reg[NMLEN];
693 read_regname(reg);
694 sbuf_append(sbuf, reg);
695 sbuf_add(sbuf, 0);
698 static void arg_string(struct sbuf *sbuf)
700 int c;
701 while ((c = cp_next()) == ' ')
703 if (c == '"')
704 c = cp_next();
705 while (c > 0 && c != '\n') {
706 sbuf_add(sbuf, c);
707 c = cp_next();
709 sbuf_add(sbuf, 0);
710 if (c >= 0)
711 cp_back(c);
714 static int mkargs_arg(struct sbuf *sbuf, int (*next)(void), void (*back)(int))
716 int quoted = 0;
717 int c;
718 c = next();
719 while (c == ' ')
720 c = next();
721 if (c == '\n')
722 back(c);
723 if (c < 0 || c == '\n')
724 return 1;
725 if (c == '"') {
726 quoted = 1;
727 c = next();
729 while (c >= 0 && c != '\n') {
730 if (!quoted && c == ' ')
731 break;
732 if (quoted && c == '"') {
733 c = next();
734 if (c != '"')
735 break;
737 if (c == c_ec) {
738 sbuf_add(sbuf, c);
739 c = next();
741 sbuf_add(sbuf, c);
742 c = next();
744 sbuf_add(sbuf, 0);
745 if (c >= 0)
746 back(c);
747 return 0;
750 /* read macro arguments */
751 int tr_readargs(char **args, struct sbuf *sbuf, int (*next)(void), void (*back)(int))
753 int idx[NARGS];
754 int i, n = 0;
755 while (n < NARGS) {
756 idx[n] = sbuf_len(sbuf);
757 if (mkargs_arg(sbuf, next, back))
758 break;
759 n++;
761 for (i = 0; i < n; i++)
762 args[i] = sbuf_buf(sbuf) + idx[i];
763 return n;
766 /* read macro arguments; trims tabs if rmtabs is nonzero */
767 static int mkargs(char **args, struct sbuf *sbuf)
769 int n = tr_readargs(args, sbuf, cp_next, cp_back);
770 jmp_eol();
771 return n;
774 /* read request arguments; trims tabs too */
775 static int mkargs_req(char **args, struct sbuf *sbuf)
777 int idx[NARGS];
778 int i, n = 0;
779 int c;
780 c = cp_next();
781 while (n < NARGS) {
782 idx[n] = sbuf_len(sbuf);
783 while (c == ' ' || c == '\t')
784 c = cp_next();
785 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
786 sbuf_add(sbuf, c);
787 c = cp_next();
789 if (sbuf_len(sbuf) > idx[n])
790 n++;
791 sbuf_add(sbuf, 0);
792 if (c == '\n')
793 cp_back(c);
794 if (c < 0 || c == '\n')
795 break;
797 for (i = 0; i < n; i++)
798 args[i] = sbuf_buf(sbuf) + idx[i];
799 jmp_eol();
800 return n;
803 /* read arguments for .ds */
804 static int mkargs_ds(char **args, struct sbuf *sbuf)
806 int idx[NARGS];
807 int i, n = 0;
808 idx[n++] = sbuf_len(sbuf);
809 arg_regname(sbuf);
810 idx[n++] = sbuf_len(sbuf);
811 cp_copymode(1);
812 arg_string(sbuf);
813 cp_copymode(0);
814 jmp_eol();
815 for (i = 0; i < n; i++)
816 args[i] = sbuf_buf(sbuf) + idx[i];
817 return n;
820 /* read arguments for commands .nr that expect a register name */
821 static int mkargs_reg1(char **args, struct sbuf *sbuf)
823 int n;
824 int idx0 = sbuf_len(sbuf);
825 arg_regname(sbuf);
826 n = mkargs_req(args + 1, sbuf) + 1;
827 args[0] = sbuf_buf(sbuf) + idx0;
828 return n;
831 /* do not read arguments; for .if, .ie and .el */
832 static int mkargs_null(char **args, struct sbuf *sbuf)
834 return 0;
837 /* read the whole line for .tm */
838 static int mkargs_eol(char **args, struct sbuf *sbuf)
840 int idx0 = sbuf_len(sbuf);
841 int c;
842 c = cp_next();
843 while (c == ' ')
844 c = cp_next();
845 while (c >= 0 && c != '\n') {
846 sbuf_add(sbuf, c);
847 c = cp_next();
849 args[0] = sbuf_buf(sbuf) + idx0;
850 return 1;
853 static struct cmd {
854 char *id;
855 void (*f)(char **args);
856 int (*args)(char **args, struct sbuf *sbuf);
857 } cmds[] = {
858 {TR_DIVBEG, tr_divbeg},
859 {TR_DIVEND, tr_divend},
860 {TR_POPREN, tr_popren},
861 {"ab", tr_ab, mkargs_eol},
862 {"ad", tr_ad},
863 {"af", tr_af},
864 {"am", tr_de, mkargs_reg1},
865 {"as", tr_as, mkargs_ds},
866 {"bd", tr_bd},
867 {"bp", tr_bp},
868 {"br", tr_br},
869 {"c2", tr_c2},
870 {"cc", tr_cc},
871 {"ochar", tr_ochar},
872 {"ce", tr_ce},
873 {"ch", tr_ch},
874 {"char", tr_char, mkargs_ds},
875 {"chop", tr_chop, mkargs_reg1},
876 {"cl", tr_cl},
877 {"cp", tr_cp},
878 {"cs", tr_cs},
879 {"da", tr_di},
880 {"de", tr_de, mkargs_reg1},
881 {"di", tr_di},
882 {"ds", tr_ds, mkargs_ds},
883 {"dt", tr_dt},
884 {"ec", tr_ec},
885 {"el", tr_el, mkargs_null},
886 {"em", tr_em},
887 {"eo", tr_eo},
888 {"ev", tr_ev},
889 {"ex", tr_ex},
890 {"fc", tr_fc},
891 {"ff", tr_ff},
892 {"fi", tr_fi},
893 {"fmap", tr_fmap},
894 {"fp", tr_fp},
895 {"fspecial", tr_fspecial},
896 {"ft", tr_ft},
897 {"fzoom", tr_fzoom},
898 {"hc", tr_hc},
899 {"hcode", tr_hcode},
900 {"hpf", tr_hpf},
901 {"hpfa", tr_hpfa},
902 {"hy", tr_hy},
903 {"hyp", tr_hyp},
904 {"hw", tr_hw},
905 {"ie", tr_if, mkargs_null},
906 {"if", tr_if, mkargs_null},
907 {"ig", tr_ig},
908 {"in", tr_in},
909 {"it", tr_it},
910 {"kn", tr_kn},
911 {"lc", tr_lc},
912 {"lf", tr_lf},
913 {"lg", tr_lg},
914 {"ll", tr_ll},
915 {"ls", tr_ls},
916 {"lt", tr_lt},
917 {"mc", tr_mc},
918 {"mk", tr_mk},
919 {"na", tr_na},
920 {"ne", tr_ne},
921 {"nf", tr_nf},
922 {"nh", tr_nh},
923 {"nm", tr_nm},
924 {"nn", tr_nn},
925 {"nr", tr_nr, mkargs_reg1},
926 {"ns", tr_ns},
927 {"nx", tr_nx},
928 {"os", tr_os},
929 {"pc", tr_pc},
930 {"pl", tr_pl},
931 {"pn", tr_pn},
932 {"po", tr_po},
933 {"ps", tr_ps},
934 {"rchar", tr_rchar, mkargs_ds},
935 {"rm", tr_rm},
936 {"rn", tr_rn},
937 {"rr", tr_rr},
938 {"rs", tr_rs},
939 {"rt", tr_rt},
940 {"so", tr_so},
941 {"sp", tr_sp},
942 {"ss", tr_ss},
943 {"ssh", tr_ssh},
944 {"sv", tr_sv},
945 {"sy", tr_sy, mkargs_eol},
946 {"ta", tr_ta},
947 {"tc", tr_tc},
948 {"ti", tr_ti},
949 {"tl", tr_tl, mkargs_null},
950 {"tm", tr_tm, mkargs_eol},
951 {"tr", tr_tr, mkargs_eol},
952 {"vs", tr_vs},
953 {"wh", tr_wh},
956 /* read the next troff request; return zero if a request was executed. */
957 int tr_nextreq(void)
959 char *args[NARGS + 3] = {NULL};
960 char cmd[RNLEN + 1];
961 struct cmd *req;
962 struct sbuf sbuf;
963 int c;
964 if (!tr_nl)
965 return 1;
966 c = cp_next();
967 if (c < 0 || (c != c_cc && c != c_c2)) {
968 cp_back(c);
969 return 1;
971 memset(args, 0, sizeof(args));
972 args[0] = cmd;
973 cmd[0] = c;
974 req = NULL;
975 cp_reqline();
976 read_regname(cmd + 1);
977 sbuf_init(&sbuf);
978 req = str_dget(map(cmd + 1));
979 if (req) {
980 if (req->args)
981 req->args(args + 1, &sbuf);
982 else
983 mkargs_req(args + 1, &sbuf);
984 req->f(args);
985 } else {
986 cp_copymode(1);
987 mkargs(args + 1, &sbuf);
988 cp_copymode(0);
989 if (str_get(map(cmd + 1)))
990 in_push(str_get(map(cmd + 1)), args + 1);
992 sbuf_done(&sbuf);
993 return 0;
996 int tr_next(void)
998 int c;
999 while (!tr_nextreq())
1001 c = cp_next();
1002 tr_nl = c == '\n' || c < 0;
1003 return c;
1006 void tr_init(void)
1008 int i;
1009 for (i = 0; i < LEN(cmds); i++)
1010 str_dset(map(cmds[i].id), &cmds[i]);
1011 dict_init(&cmap, NCMAPS, -1, 0, 0);