cp: remove c_ni from strings not pushed via in_push()
[neatroff.git] / tr.c
blobefb46832472b9192380549c81d8ca6ca75f2f589
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' || c == c_ni)
116 c = cp_next();
117 while (c >= 0 && c != ' ' && c != '\t' && c != '\n' && --n >= 0) {
118 *s++ = c;
119 do {
120 c = cp_next();
121 } while (n && c == c_ni);
123 if (c >= 0)
124 cp_back(c);
125 *s = '\0';
128 static void macrobody(struct sbuf *sbuf, char *end)
130 char buf[NMLEN];
131 int i, c;
132 int first = 1;
133 cp_back('\n');
134 cp_copymode(1);
135 while ((c = cp_next()) >= 0) {
136 if (sbuf && !first)
137 sbuf_add(sbuf, c);
138 first = 0;
139 if (c == '\n') {
140 if ((c = cp_next()) != '.') {
141 cp_back(c);
142 continue;
144 read_regname(buf);
145 if ((n_cp && end[0] == buf[0] && end[1] == buf[1]) ||
146 !strcmp(end, buf)) {
147 jmp_eol();
148 break;
150 if (sbuf) {
151 sbuf_add(sbuf, '.');
152 for (i = 0; buf[i]; i++)
153 sbuf_add(sbuf, (unsigned char) buf[i]);
157 cp_copymode(0);
160 static void tr_de(char **args)
162 struct sbuf sbuf;
163 int id;
164 if (!args[1])
165 return;
166 id = map(args[1]);
167 sbuf_init(&sbuf);
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));
172 sbuf_done(&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];
185 int c;
186 while ((c = next()) >= 0) {
187 if (c == c_ni)
188 continue;
189 back(c);
190 if (c == '\n')
191 return 1;
192 if (!stop && (c == ' ' || c == '\t'))
193 return 0;
194 charnext(cs, next, back);
195 if (stop && !strcmp(stop, cs))
196 return 0;
197 charnext_str(cs2, cs);
198 sbuf_append(sbuf, cs2);
200 return 1;
203 /* evaluate .if strcmp (i.e. 'str'str') */
204 static int if_strcmp(int (*next)(void), void (*back)(int))
206 char delim[GNLEN];
207 struct sbuf s1, s2;
208 int ret;
209 charnext(delim, next, back);
210 sbuf_init(&s1);
211 sbuf_init(&s2);
212 read_until(&s1, delim, next, back);
213 read_until(&s2, delim, next, back);
214 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
215 sbuf_done(&s1);
216 sbuf_done(&s2);
217 return ret;
220 /* evaluate .if condition letters */
221 static int if_cond(int (*next)(void), void (*back)(int))
223 switch (cp_next()) {
224 case 'o':
225 return n_pg % 2;
226 case 'e':
227 return !(n_pg % 2);
228 case 't':
229 return 1;
230 case 'n':
231 return 0;
233 return 0;
236 /* evaluate .if condition */
237 static int if_eval(int (*next)(void), void (*back)(int))
239 struct sbuf sbuf;
240 int ret;
241 sbuf_init(&sbuf);
242 read_until(&sbuf, NULL, next, back);
243 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
244 sbuf_done(&sbuf);
245 return ret;
248 static int eval_if(int (*next)(void), void (*back)(int))
250 int neg = 0;
251 int ret;
252 int c;
253 do {
254 c = next();
255 } while (c == ' ' || c == '\t');
256 if (c == '!') {
257 neg = 1;
258 c = next();
260 back(c);
261 if (strchr("oetn", c)) {
262 ret = if_cond(next, back);
263 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
264 ret = if_strcmp(next, back);
265 } else {
266 ret = if_eval(next, back);
268 return ret != neg;
271 static int ie_cond[NIES]; /* .ie condition stack */
272 static int ie_depth;
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 */
278 if (ie_depth < NIES)
279 ie_cond[ie_depth++] = c;
280 cp_blk(!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)
290 n_na = 1;
293 static int adjmode(int c, int def)
295 switch (c) {
296 case 'l':
297 return AD_L;
298 case 'r':
299 return AD_R;
300 case 'c':
301 return AD_C;
302 case 'b':
303 case 'n':
304 return AD_B;
306 return def;
309 static void tr_ad(char **args)
311 char *s = args[1];
312 n_na = 0;
313 if (!s)
314 return;
315 if (isdigit(s[0]))
316 n_j = atoi(s) & 15;
317 else
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)
328 if (args[1])
329 in_so(args[1]);
332 static void tr_nx(char **args)
334 in_nx(args[1]);
337 static void tr_ex(char **args)
339 in_ex();
342 static void tr_sy(char **args)
344 system(args[1]);
347 static void tr_lt(char **args)
349 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
350 n_t0 = n_t0;
351 n_lt = MAX(0, lt);
354 static void tr_pc(char **args)
356 c_pc = args[1] ? args[1][0] : -1;
359 static int tl_next(void)
361 int c = cp_next();
362 if (c >= 0 && c == c_pc) {
363 in_push(num_str(map("%")), NULL);
364 c = cp_next();
366 return c;
369 static void tr_tl(char **args)
371 int c;
372 do {
373 c = cp_next();
374 } while (c >= 0 && (c == ' ' || c == '\t'));
375 cp_back(c);
376 ren_tl(tl_next, cp_back);
377 do {
378 c = cp_next();
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)
399 c_ec = -1;
402 static void tr_hc(char **args)
404 char *s = args[1];
405 if (!s || charread(&s, c_hc) < 0)
406 strcpy(c_hc, "\\%");
409 static void tr_nh(char **args)
411 n_hy = 0;
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)
426 if (args[1])
427 n_lg = atoi(args[1]);
430 static void tr_kn(char **args)
432 if (args[1])
433 n_kn = atoi(args[1]);
436 static void tr_cp(char **args)
438 if (args[1])
439 n_cp = atoi(args[1]);
442 static void tr_ss(char **args)
444 if (args[1]) {
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;
458 if (fn)
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;
466 if (fn)
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;
473 int i;
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)
481 if (!args[1]) {
482 n_nm = 0;
483 return;
485 n_nm = 1;
486 n_ln = eval_re(args[1], n_ln, 0);
487 n_ln = MAX(0, n_ln);
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]))
504 return;
505 font_setbd(dev_font(dev_pos(args[1])), args[2] ? eval(args[2], 'u') : 0);
508 static void tr_it(char **args)
510 if (args[2]) {
511 n_it = map(args[2]);
512 n_itn = eval(args[1], 0);
513 } else {
514 n_it = 0;
518 static void tr_mc(char **args)
520 char *s = args[1];
521 if (s && charread(&s, c_mc) >= 0) {
522 n_mc = 1;
523 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
524 } else {
525 n_mc = 0;
529 static void tr_tc(char **args)
531 char *s = args[1];
532 if (!s || charread(&s, c_tc) < 0)
533 strcpy(c_tc, "");
536 static void tr_lc(char **args)
538 char *s = args[1];
539 if (!s || charread(&s, c_lc) < 0)
540 strcpy(c_lc, "");
543 static void tr_lf(char **args)
545 if (args[1])
546 in_lf(args[2], eval(args[1], 0));
549 static void tr_chop(char **args)
551 struct sbuf sbuf;
552 int id;
553 if (args[1])
554 in_lf(args[2], eval(args[1], 0));
555 id = map(args[1]);
556 if (str_get(id)) {
557 sbuf_init(&sbuf);
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));
563 sbuf_done(&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);
576 if (i >= 0) {
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);
582 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)
594 char *s = args[1];
595 char c1[GNLEN], c2[GNLEN];
596 while (s && charread(&s, c1) >= 0) {
597 if (charread(&s, c2) < 0)
598 strcpy(c2, " ");
599 cmap_add(c1, c2);
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)
612 int i;
613 for (i = 0; i < cdef_n; i++)
614 if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
615 return i;
616 return -1;
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);
629 if (!d)
630 return 1;
631 cdef_expanding = 1;
632 ren_parse(wb, d);
633 cdef_expanding = 0;
634 return 0;
637 static void cdef_add(char *fn, char *cs, char *def)
639 char c[GNLEN];
640 int i;
641 if (!def || charread(&cs, c) < 0)
642 return;
643 i = cdef_find(c, -1);
644 if (i < 0 && cdef_n < NCDEFS)
645 i = cdef_n++;
646 if (i >= 0) {
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)
656 char c[GNLEN];
657 int i;
658 if (!cs || charread(&cs, c) < 0)
659 return;
660 for (i = 0; i < cdef_n; i++) {
661 if (!strcmp(cdef_src[i], c)) {
662 free(cdef_dst[i]);
663 cdef_dst[i] = NULL;
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)
676 int i;
677 for (i = 1; i <= NARGS; i++)
678 if (args[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;
690 if (fn && args[2])
691 font_map(fn, args[2], args[3]);
694 static void arg_regname(struct sbuf *sbuf)
696 char reg[NMLEN];
697 read_regname(reg);
698 sbuf_append(sbuf, reg);
699 sbuf_add(sbuf, 0);
702 static void arg_string(struct sbuf *sbuf)
704 int c;
705 while ((c = cp_next()) == ' ')
707 if (c == '"')
708 c = cp_next();
709 while (c > 0 && c != '\n') {
710 if (c != c_ni)
711 sbuf_add(sbuf, c);
712 c = cp_next();
714 sbuf_add(sbuf, 0);
715 if (c >= 0)
716 cp_back(c);
719 static int mkargs_arg(struct sbuf *sbuf, int (*next)(void), void (*back)(int))
721 int quoted = 0;
722 int c;
723 c = next();
724 while (c == ' ')
725 c = next();
726 if (c == '\n')
727 back(c);
728 if (c < 0 || c == '\n')
729 return 1;
730 if (c == '"') {
731 quoted = 1;
732 c = next();
734 while (c >= 0 && c != '\n') {
735 if (!quoted && c == ' ')
736 break;
737 if (quoted && c == '"') {
738 c = next();
739 if (c != '"')
740 break;
742 if (c == c_ec) {
743 sbuf_add(sbuf, c);
744 c = next();
746 sbuf_add(sbuf, c);
747 c = next();
749 sbuf_add(sbuf, 0);
750 if (c >= 0)
751 back(c);
752 return 0;
755 /* read macro arguments */
756 int tr_readargs(char **args, struct sbuf *sbuf, int (*next)(void), void (*back)(int))
758 int idx[NARGS];
759 int i, n = 0;
760 while (n < NARGS) {
761 idx[n] = sbuf_len(sbuf);
762 if (mkargs_arg(sbuf, next, back))
763 break;
764 n++;
766 for (i = 0; i < n; i++)
767 args[i] = sbuf_buf(sbuf) + idx[i];
768 return n;
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);
775 jmp_eol();
776 return n;
779 /* read request arguments; trims tabs too */
780 static int mkargs_req(char **args, struct sbuf *sbuf)
782 int idx[NARGS];
783 int i, n = 0;
784 int c;
785 c = cp_next();
786 while (n < NARGS) {
787 idx[n] = sbuf_len(sbuf);
788 while (c == ' ' || c == '\t')
789 c = cp_next();
790 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
791 if (c != c_ni)
792 sbuf_add(sbuf, c);
793 c = cp_next();
795 if (sbuf_len(sbuf) > idx[n])
796 n++;
797 sbuf_add(sbuf, 0);
798 if (c == '\n')
799 cp_back(c);
800 if (c < 0 || c == '\n')
801 break;
803 for (i = 0; i < n; i++)
804 args[i] = sbuf_buf(sbuf) + idx[i];
805 jmp_eol();
806 return n;
809 /* read arguments for .ds */
810 static int mkargs_ds(char **args, struct sbuf *sbuf)
812 int idx[NARGS];
813 int i, n = 0;
814 idx[n++] = sbuf_len(sbuf);
815 arg_regname(sbuf);
816 idx[n++] = sbuf_len(sbuf);
817 cp_copymode(1);
818 arg_string(sbuf);
819 cp_copymode(0);
820 jmp_eol();
821 for (i = 0; i < n; i++)
822 args[i] = sbuf_buf(sbuf) + idx[i];
823 return n;
826 /* read arguments for commands .nr that expect a register name */
827 static int mkargs_reg1(char **args, struct sbuf *sbuf)
829 int n;
830 int idx0 = sbuf_len(sbuf);
831 arg_regname(sbuf);
832 n = mkargs_req(args + 1, sbuf) + 1;
833 args[0] = sbuf_buf(sbuf) + idx0;
834 return n;
837 /* do not read arguments; for .if, .ie and .el */
838 static int mkargs_null(char **args, struct sbuf *sbuf)
840 return 0;
843 /* read the whole line for .tm */
844 static int mkargs_eol(char **args, struct sbuf *sbuf)
846 int idx0 = sbuf_len(sbuf);
847 int c;
848 cp_copymode(1);
849 c = cp_next();
850 while (c == ' ')
851 c = cp_next();
852 while (c >= 0 && c != '\n') {
853 if (c != c_ni)
854 sbuf_add(sbuf, c);
855 c = cp_next();
857 cp_copymode(0);
858 args[0] = sbuf_buf(sbuf) + idx0;
859 return 1;
862 static struct cmd {
863 char *id;
864 void (*f)(char **args);
865 int (*args)(char **args, struct sbuf *sbuf);
866 } cmds[] = {
867 {TR_DIVBEG, tr_divbeg},
868 {TR_DIVEND, tr_divend},
869 {TR_POPREN, tr_popren},
870 {"ab", tr_ab, mkargs_eol},
871 {"ad", tr_ad},
872 {"af", tr_af},
873 {"am", tr_de, mkargs_reg1},
874 {"as", tr_as, mkargs_ds},
875 {"bd", tr_bd},
876 {"bp", tr_bp},
877 {"br", tr_br},
878 {"c2", tr_c2},
879 {"cc", tr_cc},
880 {"ochar", tr_ochar},
881 {"ce", tr_ce},
882 {"ch", tr_ch},
883 {"char", tr_char, mkargs_ds},
884 {"chop", tr_chop, mkargs_reg1},
885 {"cl", tr_cl},
886 {"cp", tr_cp},
887 {"cs", tr_cs},
888 {"da", tr_di},
889 {"de", tr_de, mkargs_reg1},
890 {"di", tr_di},
891 {"ds", tr_ds, mkargs_ds},
892 {"dt", tr_dt},
893 {"ec", tr_ec},
894 {"el", tr_el, mkargs_null},
895 {"em", tr_em},
896 {"eo", tr_eo},
897 {"ev", tr_ev},
898 {"ex", tr_ex},
899 {"fc", tr_fc},
900 {"ff", tr_ff},
901 {"fi", tr_fi},
902 {"fl", tr_br},
903 {"fmap", tr_fmap},
904 {"fp", tr_fp},
905 {"fspecial", tr_fspecial},
906 {"ft", tr_ft},
907 {"fzoom", tr_fzoom},
908 {"hc", tr_hc},
909 {"hcode", tr_hcode},
910 {"hpf", tr_hpf},
911 {"hpfa", tr_hpfa},
912 {"hy", tr_hy},
913 {"hyp", tr_hyp},
914 {"hw", tr_hw},
915 {"ie", tr_if, mkargs_null},
916 {"if", tr_if, mkargs_null},
917 {"ig", tr_ig},
918 {"in", tr_in},
919 {"it", tr_it},
920 {"kn", tr_kn},
921 {"lc", tr_lc},
922 {"lf", tr_lf},
923 {"lg", tr_lg},
924 {"ll", tr_ll},
925 {"ls", tr_ls},
926 {"lt", tr_lt},
927 {"mc", tr_mc},
928 {"mk", tr_mk},
929 {"na", tr_na},
930 {"ne", tr_ne},
931 {"nf", tr_nf},
932 {"nh", tr_nh},
933 {"nm", tr_nm},
934 {"nn", tr_nn},
935 {"nr", tr_nr, mkargs_reg1},
936 {"ns", tr_ns},
937 {"nx", tr_nx},
938 {"os", tr_os},
939 {"pc", tr_pc},
940 {"pl", tr_pl},
941 {"pn", tr_pn},
942 {"po", tr_po},
943 {"ps", tr_ps},
944 {"rchar", tr_rchar, mkargs_ds},
945 {"rm", tr_rm},
946 {"rn", tr_rn},
947 {"rr", tr_rr},
948 {"rs", tr_rs},
949 {"rt", tr_rt},
950 {"so", tr_so},
951 {"sp", tr_sp},
952 {"ss", tr_ss},
953 {"ssh", tr_ssh},
954 {"sv", tr_sv},
955 {"sy", tr_sy, mkargs_eol},
956 {"ta", tr_ta},
957 {"tc", tr_tc},
958 {"ti", tr_ti},
959 {"tl", tr_tl, mkargs_null},
960 {"tm", tr_tm, mkargs_eol},
961 {"tr", tr_tr, mkargs_eol},
962 {"vs", tr_vs},
963 {"wh", tr_wh},
966 /* read the next troff request; return zero if a request was executed. */
967 int tr_nextreq(void)
969 char *args[NARGS + 3] = {NULL};
970 char cmd[RNLEN + 1];
971 struct cmd *req;
972 struct sbuf sbuf;
973 int c;
974 if (!tr_nl)
975 return 1;
976 c = cp_next();
977 if (c < 0 || (c != c_cc && c != c_c2)) {
978 cp_back(c);
979 return 1;
981 memset(args, 0, sizeof(args));
982 args[0] = cmd;
983 cmd[0] = c;
984 req = NULL;
985 cp_reqline();
986 read_regname(cmd + 1);
987 sbuf_init(&sbuf);
988 req = str_dget(map(cmd + 1));
989 if (req) {
990 if (req->args)
991 req->args(args + 1, &sbuf);
992 else
993 mkargs_req(args + 1, &sbuf);
994 req->f(args);
995 } else {
996 cp_copymode(1);
997 mkargs(args + 1, &sbuf);
998 cp_copymode(0);
999 if (str_get(map(cmd + 1)))
1000 in_push(str_get(map(cmd + 1)), args + 1);
1002 sbuf_done(&sbuf);
1003 return 0;
1006 int tr_next(void)
1008 int c;
1009 while (!tr_nextreq())
1011 c = cp_next();
1012 tr_nl = c == '\n' || c < 0;
1013 return c;
1016 void tr_init(void)
1018 int i;
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);