hyph: allow utf-8 hyphenation patterns
[neatroff.git] / tr.c
blob011a103120983bb04fd79af19fcfce33b6fa2484
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, 0), 'u'));
50 num_inc(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 = malloc(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 c = cp_next();
139 if (c == '.') {
140 read_regname(buf);
141 if ((n_cp && end[0] == buf[0] && end[1] == buf[1]) ||
142 !strcmp(end, buf)) {
143 jmp_eol();
144 break;
146 if (!sbuf)
147 continue;
148 sbuf_add(sbuf, '.');
149 for (i = 0; buf[i]; i++)
150 sbuf_add(sbuf, (unsigned char) buf[i]);
151 continue;
153 if (sbuf && c >= 0)
154 sbuf_add(sbuf, c);
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 back(c);
188 if (c == '\n')
189 return 1;
190 if (!stop && (c == ' ' || c == '\t'))
191 return 0;
192 charnext(cs, next, back);
193 if (stop && !strcmp(stop, cs))
194 return 0;
195 charnext_str(cs2, cs);
196 sbuf_append(sbuf, cs2);
198 return 1;
201 /* evaluate .if strcmp (i.e. 'str'str') */
202 static int if_strcmp(int (*next)(void), void (*back)(int))
204 char delim[GNLEN];
205 struct sbuf s1, s2;
206 int ret;
207 charnext(delim, next, back);
208 sbuf_init(&s1);
209 sbuf_init(&s2);
210 read_until(&s1, delim, next, back);
211 read_until(&s2, delim, next, back);
212 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
213 sbuf_done(&s1);
214 sbuf_done(&s2);
215 return ret;
218 /* evaluate .if condition letters */
219 static int if_cond(int (*next)(void), void (*back)(int))
221 switch (cp_next()) {
222 case 'o':
223 return n_pg % 2;
224 case 'e':
225 return !(n_pg % 2);
226 case 't':
227 return 1;
228 case 'n':
229 return 0;
231 return 0;
234 /* evaluate .if condition */
235 static int if_eval(int (*next)(void), void (*back)(int))
237 struct sbuf sbuf;
238 int ret;
239 sbuf_init(&sbuf);
240 if (!read_until(&sbuf, NULL, next, back))
241 back(' ');
242 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
243 sbuf_done(&sbuf);
244 return ret;
247 static int eval_if(int (*next)(void), void (*back)(int))
249 int neg = 0;
250 int ret;
251 int c;
252 do {
253 c = next();
254 } while (c == ' ' || c == '\t');
255 if (c == '!') {
256 neg = 1;
257 c = next();
259 back(c);
260 if (strchr("oetn", c)) {
261 ret = if_cond(next, back);
262 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
263 ret = if_strcmp(next, back);
264 } else {
265 ret = if_eval(next, back);
267 return ret != neg;
270 static int ie_cond[NIES]; /* .ie condition stack */
271 static int ie_depth;
273 static void tr_if(char **args)
275 int c = eval_if(cp_next, cp_back);
276 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
277 if (ie_depth < NIES)
278 ie_cond[ie_depth++] = c;
279 cp_blk(!c);
282 static void tr_el(char **args)
284 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
287 static void tr_na(char **args)
289 n_na = 1;
292 static int adjmode(int c, int def)
294 switch (c) {
295 case 'l':
296 return AD_L;
297 case 'r':
298 return AD_R;
299 case 'c':
300 return AD_C;
301 case 'b':
302 case 'n':
303 return AD_B;
305 return def;
308 static void tr_ad(char **args)
310 char *s = args[1];
311 n_na = 0;
312 if (!s)
313 return;
314 if (isdigit(s[0]))
315 n_j = atoi(s) & 15;
316 else
317 n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j);
320 static void tr_tm(char **args)
322 fprintf(stderr, "%s\n", args[1]);
325 static void tr_so(char **args)
327 if (args[1])
328 in_so(args[1]);
331 static void tr_nx(char **args)
333 in_nx(args[1]);
336 static void tr_ex(char **args)
338 in_ex();
341 static void tr_sy(char **args)
343 system(args[1]);
346 static void tr_lt(char **args)
348 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
349 n_t0 = n_t0;
350 n_lt = MAX(0, lt);
353 static void tr_pc(char **args)
355 c_pc = args[1] ? args[1][0] : -1;
358 static int tl_next(void)
360 int c = cp_next();
361 if (c >= 0 && c == c_pc) {
362 in_push(num_str(map("%")), NULL);
363 c = cp_next();
365 return c;
368 static void tr_tl(char **args)
370 int c;
371 do {
372 c = cp_next();
373 } while (c >= 0 && (c == ' ' || c == '\t'));
374 cp_back(c);
375 ren_tl(tl_next, cp_back);
376 do {
377 c = cp_next();
378 } while (c >= 0 && c != '\n');
381 static void tr_ec(char **args)
383 c_ec = args[1] ? args[1][0] : '\\';
386 static void tr_cc(char **args)
388 c_ec = args[1] ? args[1][0] : '.';
391 static void tr_c2(char **args)
393 c_ec = args[1] ? args[1][0] : '\'';
396 static void tr_eo(char **args)
398 c_ec = -1;
401 static void tr_hc(char **args)
403 char *s = args[1];
404 if (!s || charread(&s, c_hc) < 0)
405 strcpy(c_hc, "\\%");
408 static void tr_nh(char **args)
410 n_hy = 0;
413 static void tr_hy(char **args)
415 n_hy = args[1] ? atoi(args[1]) : 1;
418 static void tr_hyp(char **args)
420 n_hyp = args[1] ? atoi(args[1]) : 1;
423 static void tr_lg(char **args)
425 if (args[1])
426 n_lg = atoi(args[1]);
429 static void tr_kn(char **args)
431 if (args[1])
432 n_kn = atoi(args[1]);
435 static void tr_cp(char **args)
437 if (args[1])
438 n_cp = atoi(args[1]);
441 static void tr_ss(char **args)
443 if (args[1]) {
444 n_ss = eval_re(args[1], n_ss, 0);
445 n_sss = args[2] ? eval_re(args[2], n_sss, 0) : n_ss;
449 static void tr_ssh(char **args)
451 n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
454 static void tr_cs(char **args)
456 if (!args[1])
457 return;
458 dev_setcs(dev_pos(args[1]), args[2] ? eval(args[2], 0) : 0);
461 static void tr_nm(char **args)
463 if (!args[1]) {
464 n_nm = 0;
465 return;
467 n_nm = 1;
468 n_ln = eval_re(args[1], n_ln, 0);
469 n_ln = MAX(0, n_ln);
470 if (args[2] && isdigit(args[2][0]))
471 n_nM = MAX(1, eval(args[2], 0));
472 if (args[3] && isdigit(args[3][0]))
473 n_nS = MAX(0, eval(args[3], 0));
474 if (args[4] && isdigit(args[4][0]))
475 n_nI = MAX(0, eval(args[4], 0));
478 static void tr_nn(char **args)
480 n_nn = args[1] ? eval(args[1], 0) : 1;
483 static void tr_bd(char **args)
485 if (!args[1] || !strcmp("S", args[1]))
486 return;
487 dev_setbd(dev_pos(args[1]), args[2] ? eval(args[2], 'u') : 0);
490 static void tr_it(char **args)
492 if (args[2]) {
493 n_it = map(args[2]);
494 n_itn = eval(args[1], 0);
495 } else {
496 n_it = 0;
500 static void tr_mc(char **args)
502 char *s = args[1];
503 if (s && charread(&s, c_mc) >= 0) {
504 n_mc = 1;
505 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
506 } else {
507 n_mc = 0;
511 static void tr_tc(char **args)
513 char *s = args[1];
514 if (!s || charread(&s, c_tc) < 0)
515 strcpy(c_tc, "");
518 static void tr_lc(char **args)
520 char *s = args[1];
521 if (!s || charread(&s, c_lc) < 0)
522 strcpy(c_lc, "");
525 static void tr_lf(char **args)
527 if (args[1])
528 in_lf(args[2], eval(args[1], 0));
531 static void tr_chop(char **args)
533 struct sbuf sbuf;
534 int id;
535 if (args[1])
536 in_lf(args[2], eval(args[1], 0));
537 id = map(args[1]);
538 if (str_get(id)) {
539 sbuf_init(&sbuf);
540 sbuf_append(&sbuf, str_get(id));
541 if (!sbuf_empty(&sbuf)) {
542 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
543 str_set(id, sbuf_buf(&sbuf));
545 sbuf_done(&sbuf);
549 /* character translation (.tr) */
550 static char cmap_src[NCMAPS][GNLEN]; /* source character */
551 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
552 static int cmap_n; /* number of translated character */
554 static int tr_find(char *c)
556 int i;
557 for (i = 0; i < cmap_n; i++)
558 if (!strcmp(c, cmap_src[i]))
559 return i;
560 return -1;
563 void cmap_add(char *c1, char *c2)
565 int i = tr_find(c1);
566 if (i < 0 && cmap_n < NCMAPS)
567 i = cmap_n++;
568 if (i >= 0) {
569 strcpy(cmap_src[i], c1);
570 strcpy(cmap_dst[i], c2);
574 char *cmap_map(char *c)
576 int i = tr_find(c);
577 return i >= 0 ? cmap_dst[i] : c;
580 static void tr_tr(char **args)
582 char *s = args[1];
583 char c1[GNLEN], c2[GNLEN];
584 while (s && charread(&s, c1) >= 0) {
585 if (charread(&s, c2) < 0)
586 strcpy(c2, " ");
587 cmap_add(c1, c2);
591 /* character definition (.char) */
592 static char cdef_src[NCDEFS][GNLEN]; /* source character */
593 static char *cdef_dst[NCDEFS]; /* character definition */
594 static int cdef_fn[NCDEFS]; /* owning font */
595 static int cdef_n; /* number of defined characters */
596 static int cdef_expanding; /* inside cdef_expand() call */
598 static int cdef_find(char *c, int fn)
600 int i;
601 for (i = 0; i < cdef_n; i++)
602 if (!strcmp(cdef_src[i], c) && (!cdef_fn[i] || cdef_fn[i] == fn))
603 return i;
604 return -1;
607 /* return the definition of the given character */
608 char *cdef_map(char *c, int fn)
610 int i = cdef_find(c, fn);
611 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
614 int cdef_expand(struct wb *wb, char *s, int fn)
616 char *d = cdef_map(s, fn);
617 if (!d)
618 return 1;
619 cdef_expanding = 1;
620 ren_parse(wb, d);
621 cdef_expanding = 0;
622 return 0;
625 static void cdef_add(char *fn, char *cs, char *def)
627 char c[GNLEN];
628 int i;
629 if (!def || charread(&cs, c) < 0)
630 return;
631 i = cdef_find(c, -1);
632 if (i < 0 && cdef_n < NCDEFS)
633 i = cdef_n++;
634 if (i >= 0) {
635 strncpy(cdef_src[i], c, sizeof(cdef_src[i]) - 1);
636 cdef_dst[i] = malloc(strlen(def) + 1);
637 strcpy(cdef_dst[i], def);
638 cdef_fn[i] = fn ? dev_pos(fn) : 0;
642 static void cdef_remove(char *cs)
644 char c[GNLEN];
645 int i;
646 if (!cs || charread(&cs, c) < 0)
647 return;
648 for (i = 0; i < cdef_n; i++) {
649 if (!strcmp(cdef_src[i], c)) {
650 free(cdef_dst[i]);
651 cdef_dst[i] = NULL;
652 cdef_src[i][0] = '\0';
657 static void tr_char(char **args)
659 cdef_add(NULL, args[1], args[2]);
662 static void tr_rchar(char **args)
664 int i;
665 for (i = 1; i <= NARGS; i++)
666 if (args[i])
667 cdef_remove(args[i]);
670 static void tr_ochar(char **args)
672 cdef_add(args[1], args[2], args[3]);
675 static void tr_fmap(char **args)
677 struct font *fn;
678 if (!args[2])
679 return;
680 fn = dev_font(dev_pos(args[1]));
681 if (fn)
682 font_map(fn, args[2], args[3] ? font_glyph(fn, args[3]) : NULL);
685 static void arg_regname(struct sbuf *sbuf)
687 char reg[NMLEN];
688 read_regname(reg);
689 sbuf_append(sbuf, reg);
690 sbuf_add(sbuf, 0);
693 static void arg_string(struct sbuf *sbuf)
695 int c;
696 while ((c = cp_next()) == ' ')
698 if (c == '"')
699 c = cp_next();
700 while (c > 0 && c != '\n') {
701 sbuf_add(sbuf, c);
702 c = cp_next();
704 sbuf_add(sbuf, 0);
705 if (c >= 0)
706 cp_back(c);
709 static int mkargs_arg(struct sbuf *sbuf, int (*next)(void), void (*back)(int))
711 int quoted = 0;
712 int c;
713 c = next();
714 while (c == ' ')
715 c = next();
716 if (c == '\n')
717 back(c);
718 if (c < 0 || c == '\n')
719 return 1;
720 if (c == '"') {
721 quoted = 1;
722 c = next();
724 while (c >= 0 && c != '\n') {
725 if (!quoted && c == ' ')
726 break;
727 if (quoted && c == '"') {
728 c = next();
729 if (c != '"')
730 break;
732 sbuf_add(sbuf, c);
733 c = next();
735 sbuf_add(sbuf, 0);
736 if (c >= 0)
737 back(c);
738 return 0;
741 /* read macro arguments */
742 int tr_readargs(char **args, struct sbuf *sbuf, int (*next)(void), void (*back)(int))
744 int idx[NARGS];
745 int i, n = 0;
746 while (n < NARGS) {
747 idx[n] = sbuf_len(sbuf);
748 if (mkargs_arg(sbuf, next, back))
749 break;
750 n++;
752 for (i = 0; i < n; i++)
753 args[i] = sbuf_buf(sbuf) + idx[i];
754 return n;
757 /* read macro arguments; trims tabs if rmtabs is nonzero */
758 static int mkargs(char **args, struct sbuf *sbuf)
760 int n = tr_readargs(args, sbuf, cp_next, cp_back);
761 jmp_eol();
762 return n;
765 /* read request arguments; trims tabs too */
766 static int mkargs_req(char **args, struct sbuf *sbuf)
768 int idx[NARGS];
769 int i, n = 0;
770 int c;
771 c = cp_next();
772 while (n < NARGS) {
773 idx[n] = sbuf_len(sbuf);
774 while (c == ' ' || c == '\t')
775 c = cp_next();
776 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
777 sbuf_add(sbuf, c);
778 c = cp_next();
780 if (sbuf_len(sbuf) > idx[n])
781 n++;
782 sbuf_add(sbuf, 0);
783 if (c == '\n')
784 cp_back(c);
785 if (c < 0 || c == '\n')
786 break;
788 for (i = 0; i < n; i++)
789 args[i] = sbuf_buf(sbuf) + idx[i];
790 jmp_eol();
791 return n;
794 /* read arguments for .ds */
795 static int mkargs_ds(char **args, struct sbuf *sbuf)
797 int idx[NARGS];
798 int i, n = 0;
799 idx[n++] = sbuf_len(sbuf);
800 arg_regname(sbuf);
801 idx[n++] = sbuf_len(sbuf);
802 cp_copymode(1);
803 arg_string(sbuf);
804 cp_copymode(0);
805 jmp_eol();
806 for (i = 0; i < n; i++)
807 args[i] = sbuf_buf(sbuf) + idx[i];
808 return n;
811 /* read arguments for commands .nr that expect a register name */
812 static int mkargs_reg1(char **args, struct sbuf *sbuf)
814 int n;
815 int idx0 = sbuf_len(sbuf);
816 arg_regname(sbuf);
817 n = mkargs_req(args + 1, sbuf) + 1;
818 args[0] = sbuf_buf(sbuf) + idx0;
819 return n;
822 /* do not read arguments; for .if, .ie and .el */
823 static int mkargs_null(char **args, struct sbuf *sbuf)
825 return 0;
828 /* read the whole line for .tm */
829 static int mkargs_eol(char **args, struct sbuf *sbuf)
831 int idx0 = sbuf_len(sbuf);
832 int c;
833 c = cp_next();
834 while (c == ' ')
835 c = cp_next();
836 while (c >= 0 && c != '\n') {
837 sbuf_add(sbuf, c);
838 c = cp_next();
840 args[0] = sbuf_buf(sbuf) + idx0;
841 return 1;
844 static struct cmd {
845 char *id;
846 void (*f)(char **args);
847 int (*args)(char **args, struct sbuf *sbuf);
848 } cmds[] = {
849 {TR_DIVBEG, tr_divbeg},
850 {TR_DIVEND, tr_divend},
851 {TR_POPREN, tr_popren},
852 {"ab", tr_ab, mkargs_eol},
853 {"ad", tr_ad},
854 {"af", tr_af},
855 {"am", tr_de, mkargs_reg1},
856 {"as", tr_as, mkargs_ds},
857 {"bd", tr_bd},
858 {"bp", tr_bp},
859 {"br", tr_br},
860 {"c2", tr_c2},
861 {"cc", tr_cc},
862 {"ochar", tr_ochar},
863 {"ce", tr_ce},
864 {"ch", tr_ch},
865 {"char", tr_char, mkargs_ds},
866 {"chop", tr_chop, mkargs_reg1},
867 {"cl", tr_cl},
868 {"cp", tr_cp},
869 {"cs", tr_cs},
870 {"da", tr_di},
871 {"de", tr_de, mkargs_reg1},
872 {"di", tr_di},
873 {"ds", tr_ds, mkargs_ds},
874 {"dt", tr_dt},
875 {"ec", tr_ec},
876 {"el", tr_el, mkargs_null},
877 {"em", tr_em},
878 {"eo", tr_eo},
879 {"ev", tr_ev},
880 {"ex", tr_ex},
881 {"fc", tr_fc},
882 {"fi", tr_fi},
883 {"fmap", tr_fmap},
884 {"fp", tr_fp},
885 {"fspecial", tr_fspecial},
886 {"ft", tr_ft},
887 {"hc", tr_hc},
888 {"hpf", tr_hpf},
889 {"hpfa", tr_hpfa},
890 {"hy", tr_hy},
891 {"hyp", tr_hyp},
892 {"hw", tr_hw},
893 {"ie", tr_if, mkargs_null},
894 {"if", tr_if, mkargs_null},
895 {"ig", tr_ig},
896 {"in", tr_in},
897 {"it", tr_it},
898 {"kn", tr_kn},
899 {"lc", tr_lc},
900 {"lf", tr_lf},
901 {"lg", tr_lg},
902 {"ll", tr_ll},
903 {"ls", tr_ls},
904 {"lt", tr_lt},
905 {"mc", tr_mc},
906 {"mk", tr_mk},
907 {"na", tr_na},
908 {"ne", tr_ne},
909 {"nf", tr_nf},
910 {"nh", tr_nh},
911 {"nm", tr_nm},
912 {"nn", tr_nn},
913 {"nr", tr_nr, mkargs_reg1},
914 {"ns", tr_ns},
915 {"nx", tr_nx},
916 {"os", tr_os},
917 {"pc", tr_pc},
918 {"pl", tr_pl},
919 {"pn", tr_pn},
920 {"po", tr_po},
921 {"ps", tr_ps},
922 {"rchar", tr_rchar, mkargs_ds},
923 {"rm", tr_rm},
924 {"rn", tr_rn},
925 {"rr", tr_rr},
926 {"rs", tr_rs},
927 {"rt", tr_rt},
928 {"so", tr_so},
929 {"sp", tr_sp},
930 {"ss", tr_ss},
931 {"ssh", tr_ssh},
932 {"sv", tr_sv},
933 {"sy", tr_sy, mkargs_eol},
934 {"ta", tr_ta},
935 {"tc", tr_tc},
936 {"ti", tr_ti},
937 {"tl", tr_tl, mkargs_null},
938 {"tm", tr_tm, mkargs_eol},
939 {"tr", tr_tr, mkargs_eol},
940 {"vs", tr_vs},
941 {"wh", tr_wh},
944 /* read the next troff request; return zero if a request was executed. */
945 int tr_nextreq(void)
947 char *args[NARGS + 3] = {NULL};
948 char cmd[RNLEN + 1];
949 struct cmd *req;
950 struct sbuf sbuf;
951 int c;
952 if (!tr_nl)
953 return 1;
954 c = cp_next();
955 if (c < 0 || (c != c_cc && c != c_c2)) {
956 cp_back(c);
957 return 1;
959 memset(args, 0, sizeof(args));
960 args[0] = cmd;
961 cmd[0] = c;
962 req = NULL;
963 read_regname(cmd + 1);
964 sbuf_init(&sbuf);
965 req = str_dget(map(cmd + 1));
966 if (req) {
967 if (req->args)
968 req->args(args + 1, &sbuf);
969 else
970 mkargs_req(args + 1, &sbuf);
971 req->f(args);
972 } else {
973 cp_copymode(1);
974 mkargs(args + 1, &sbuf);
975 cp_copymode(0);
976 if (str_get(map(cmd + 1)))
977 in_push(str_get(map(cmd + 1)), args + 1);
979 sbuf_done(&sbuf);
980 return 0;
983 int tr_next(void)
985 int c;
986 while (!tr_nextreq())
988 c = cp_next();
989 tr_nl = c == '\n' || c < 0;
990 return c;
993 void tr_init(void)
995 int i;
996 for (i = 0; i < LEN(cmds); i++)
997 str_dset(map(cmds[i].id), &cmds[i]);