hyph: do not read more than GNLEN characters in hy_cget()
[neatroff.git] / tr.c
blob1c32cbeb9758736f9d3c58c3d09b7f984faa37e5
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 char c_pc[GNLEN] = "%"; /* page number character */
10 int c_ec = '\\'; /* escape character */
11 int c_cc = '.'; /* control character */
12 int c_c2 = '\''; /* no-break control character */
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 for (i = strlen(buf) - 1; i >= 0; i--)
148 cp_back((unsigned char) buf[i]);
149 cp_back('.');
150 break;
152 if (sbuf) {
153 sbuf_add(sbuf, '.');
154 for (i = 0; buf[i]; i++)
155 sbuf_add(sbuf, (unsigned char) buf[i]);
159 cp_copymode(0);
162 static void tr_de(char **args)
164 struct sbuf sbuf;
165 int id;
166 if (!args[1])
167 return;
168 id = map(args[1]);
169 sbuf_init(&sbuf);
170 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
171 sbuf_append(&sbuf, str_get(id));
172 macrobody(&sbuf, args[2] ? args[2] : ".");
173 str_set(id, sbuf_buf(&sbuf));
174 sbuf_done(&sbuf);
177 static void tr_ig(char **args)
179 macrobody(NULL, args[1] ? args[1] : ".");
182 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
183 static int read_until(struct sbuf *sbuf, char *stop,
184 int (*next)(void), void (*back)(int))
186 char cs[GNLEN], cs2[GNLEN];
187 int c;
188 while ((c = next()) >= 0) {
189 if (c == c_ni)
190 continue;
191 back(c);
192 if (c == '\n')
193 return 1;
194 if (!stop && (c == ' ' || c == '\t'))
195 return 0;
196 charnext(cs, next, back);
197 if (stop && !strcmp(stop, cs))
198 return 0;
199 charnext_str(cs2, cs);
200 sbuf_append(sbuf, cs2);
202 return 1;
205 /* evaluate .if strcmp (i.e. 'str'str') */
206 static int if_strcmp(int (*next)(void), void (*back)(int))
208 char delim[GNLEN];
209 struct sbuf s1, s2;
210 int ret;
211 charnext(delim, next, back);
212 sbuf_init(&s1);
213 sbuf_init(&s2);
214 read_until(&s1, delim, next, back);
215 read_until(&s2, delim, next, back);
216 cp_reqbeg();
217 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
218 sbuf_done(&s1);
219 sbuf_done(&s2);
220 return ret;
223 /* evaluate .if condition letters */
224 static int if_cond(int (*next)(void), void (*back)(int))
226 switch (cp_next()) {
227 case 'o':
228 return n_pg % 2;
229 case 'e':
230 return !(n_pg % 2);
231 case 't':
232 return 1;
233 case 'n':
234 return 0;
236 return 0;
239 /* evaluate .if condition */
240 static int if_eval(int (*next)(void), void (*back)(int))
242 struct sbuf sbuf;
243 int ret;
244 sbuf_init(&sbuf);
245 read_until(&sbuf, NULL, next, back);
246 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
247 sbuf_done(&sbuf);
248 return ret;
251 static int eval_if(int (*next)(void), void (*back)(int))
253 int neg = 0;
254 int ret;
255 int c;
256 do {
257 c = next();
258 } while (c == ' ' || c == '\t');
259 if (c == '!') {
260 neg = 1;
261 c = next();
263 back(c);
264 if (strchr("oetn", c)) {
265 ret = if_cond(next, back);
266 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
267 ret = if_strcmp(next, back);
268 } else {
269 ret = if_eval(next, back);
271 return ret != neg;
274 static int ie_cond[NIES]; /* .ie condition stack */
275 static int ie_depth;
277 static void tr_if(char **args)
279 int c = eval_if(cp_next, cp_back);
280 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
281 if (ie_depth < NIES)
282 ie_cond[ie_depth++] = c;
283 cp_blk(!c);
286 static void tr_el(char **args)
288 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
291 static void tr_na(char **args)
293 n_na = 1;
296 static int adjmode(int c, int def)
298 switch (c) {
299 case 'l':
300 return AD_L;
301 case 'r':
302 return AD_R;
303 case 'c':
304 return AD_C;
305 case 'b':
306 case 'n':
307 return AD_B;
309 return def;
312 static void tr_ad(char **args)
314 char *s = args[1];
315 n_na = 0;
316 if (!s)
317 return;
318 if (isdigit(s[0]))
319 n_j = atoi(s) & 15;
320 else
321 n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j);
324 static void tr_tm(char **args)
326 fprintf(stderr, "%s\n", args[1]);
329 static void tr_so(char **args)
331 if (args[1])
332 in_so(args[1]);
335 static void tr_nx(char **args)
337 in_nx(args[1]);
340 static void tr_ex(char **args)
342 in_ex();
345 static void tr_sy(char **args)
347 system(args[1]);
350 static void tr_lt(char **args)
352 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
353 n_t0 = n_t0;
354 n_lt = MAX(0, lt);
357 static void tr_pc(char **args)
359 char *s = args[1];
360 if (!s || charread(&s, c_pc) < 0)
361 strcpy(c_pc, "");
364 static void tr_tl(char **args)
366 int c;
367 do {
368 c = cp_next();
369 } while (c >= 0 && (c == ' ' || c == '\t'));
370 cp_back(c);
371 ren_tl(cp_next, cp_back);
372 do {
373 c = cp_next();
374 } while (c >= 0 && c != '\n');
377 static void tr_ec(char **args)
379 c_ec = args[1] ? args[1][0] : '\\';
382 static void tr_cc(char **args)
384 c_cc = args[1] ? args[1][0] : '.';
387 static void tr_c2(char **args)
389 c_c2 = args[1] ? args[1][0] : '\'';
392 static void tr_eo(char **args)
394 c_ec = -1;
397 static void tr_hc(char **args)
399 char *s = args[1];
400 if (!s || charread(&s, c_hc) < 0)
401 strcpy(c_hc, "\\%");
404 /* sentence ending and their transparent characters */
405 static char eos_sent[NCHARS][GNLEN] = { ".", "?", "!", };
406 static int eos_sentcnt = 3;
407 static char eos_tran[NCHARS][GNLEN] = { "'", "\"", ")", "]", "*", };
408 static int eos_trancnt = 5;
410 static void tr_eos(char **args)
412 eos_sentcnt = 0;
413 eos_trancnt = 0;
414 if (args[1]) {
415 char *s = args[1];
416 while (s && charread(&s, eos_sent[eos_sentcnt]) >= 0)
417 if (eos_sentcnt < NCHARS - 1)
418 eos_sentcnt++;
420 if (args[2]) {
421 char *s = args[2];
422 while (s && charread(&s, eos_tran[eos_trancnt]) >= 0)
423 if (eos_trancnt < NCHARS - 1)
424 eos_trancnt++;
428 int c_eossent(char *s)
430 int i;
431 for (i = 0; i < eos_sentcnt; i++)
432 if (!strcmp(eos_sent[i], s))
433 return 1;
434 return 0;
437 int c_eostran(char *s)
439 int i;
440 for (i = 0; i < eos_trancnt; i++)
441 if (!strcmp(eos_tran[i], s))
442 return 1;
443 return 0;
446 /* hyphenation dashes and hyphenation inhibiting character */
447 static char hy_dash[NCHARS][GNLEN] = { "\\:", "-", "em", "en", "\\-", "--", "hy", };
448 static int hy_dashcnt = 7;
449 static char hy_stop[NCHARS][GNLEN] = { "\\%", };
450 static int hy_stopcnt = 1;
452 static void tr_nh(char **args)
454 n_hy = 0;
457 static void tr_hy(char **args)
459 n_hy = args[1] ? eval_re(args[1], n_hy, '\0') : 1;
462 static void tr_hycost(char **args)
464 n_hycost = args[1] ? eval_re(args[1], n_hycost, '\0') : 0;
465 n_hycost2 = args[2] ? eval_re(args[2], n_hycost2, '\0') : 0;
466 n_hycost3 = args[3] ? eval_re(args[3], n_hycost3, '\0') : 0;
469 static void tr_hydash(char **args)
471 hy_dashcnt = 0;
472 if (args[1]) {
473 char *s = args[1];
474 while (s && charread(&s, hy_dash[hy_dashcnt]) >= 0)
475 if (hy_dashcnt < NCHARS - 1)
476 hy_dashcnt++;
480 static void tr_hystop(char **args)
482 hy_stopcnt = 0;
483 if (args[1]) {
484 char *s = args[1];
485 while (s && charread(&s, hy_stop[hy_stopcnt]) >= 0)
486 if (hy_stopcnt < NCHARS - 1)
487 hy_stopcnt++;
491 int c_hydash(char *s)
493 int i;
494 for (i = 0; i < hy_dashcnt; i++)
495 if (!strcmp(hy_dash[i], s))
496 return 1;
497 return 0;
500 int c_hystop(char *s)
502 int i;
503 for (i = 0; i < hy_stopcnt; i++)
504 if (!strcmp(hy_stop[i], s))
505 return 1;
506 return 0;
509 int c_hymark(char *s)
511 return !strcmp(c_bp, s) || !strcmp(c_hc, s);
514 static void tr_pmll(char **args)
516 n_pmll = args[1] ? eval_re(args[1], n_pmll, '\0') : 0;
517 n_pmllcost = args[2] ? eval_re(args[2], n_pmllcost, '\0') : 100;
520 static void tr_lg(char **args)
522 if (args[1])
523 n_lg = eval(args[1], '\0');
526 static void tr_kn(char **args)
528 if (args[1])
529 n_kn = eval(args[1], '\0');
532 static void tr_cp(char **args)
534 if (args[1])
535 n_cp = atoi(args[1]);
538 static void tr_ss(char **args)
540 if (args[1]) {
541 n_ss = eval_re(args[1], n_ss, 0);
542 n_sss = args[2] ? eval_re(args[2], n_sss, 0) : n_ss;
546 static void tr_ssh(char **args)
548 n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
551 static void tr_cs(char **args)
553 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
554 if (fn)
555 font_setcs(fn, args[2] ? eval(args[2], 0) : 0,
556 args[3] ? eval(args[3], 0) : 0);
559 static void tr_fzoom(char **args)
561 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
562 if (fn)
563 font_setzoom(fn, args[2] ? eval(args[2], 0) : 0);
566 static void tr_ff(char **args)
568 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
569 int i;
570 for (i = 2; i <= NARGS; i++)
571 if (fn && args[i] && args[i][0] && args[i][1])
572 font_feat(fn, args[i] + 1, args[i][0] == '+');
575 static void tr_nm(char **args)
577 if (!args[1]) {
578 n_nm = 0;
579 return;
581 n_nm = 1;
582 n_ln = eval_re(args[1], n_ln, 0);
583 n_ln = MAX(0, n_ln);
584 if (args[2] && isdigit(args[2][0]))
585 n_nM = MAX(1, eval(args[2], 0));
586 if (args[3] && isdigit(args[3][0]))
587 n_nS = MAX(0, eval(args[3], 0));
588 if (args[4] && isdigit(args[4][0]))
589 n_nI = MAX(0, eval(args[4], 0));
592 static void tr_nn(char **args)
594 n_nn = args[1] ? eval(args[1], 0) : 1;
597 static void tr_bd(char **args)
599 if (!args[1] || !strcmp("S", args[1]))
600 return;
601 font_setbd(dev_font(dev_pos(args[1])), args[2] ? eval(args[2], 'u') : 0);
604 static void tr_it(char **args)
606 if (args[2]) {
607 n_it = map(args[2]);
608 n_itn = eval(args[1], 0);
609 } else {
610 n_it = 0;
614 static void tr_mc(char **args)
616 char *s = args[1];
617 if (s && charread(&s, c_mc) >= 0) {
618 n_mc = 1;
619 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
620 } else {
621 n_mc = 0;
625 static void tr_tc(char **args)
627 char *s = args[1];
628 if (!s || charread(&s, c_tc) < 0)
629 strcpy(c_tc, "");
632 static void tr_lc(char **args)
634 char *s = args[1];
635 if (!s || charread(&s, c_lc) < 0)
636 strcpy(c_lc, "");
639 static void tr_lf(char **args)
641 if (args[1])
642 in_lf(args[2], eval(args[1], 0));
645 static void tr_chop(char **args)
647 struct sbuf sbuf;
648 int id;
649 id = map(args[1]);
650 if (str_get(id)) {
651 sbuf_init(&sbuf);
652 sbuf_append(&sbuf, str_get(id));
653 if (!sbuf_empty(&sbuf)) {
654 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
655 str_set(id, sbuf_buf(&sbuf));
657 sbuf_done(&sbuf);
661 /* character translation (.tr) */
662 static struct dict *cmap; /* character mapping */
663 static char cmap_src[NCMAPS][GNLEN]; /* source character */
664 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
665 static int cmap_n; /* number of translated character */
667 void cmap_add(char *c1, char *c2)
669 int i = dict_get(cmap, c1);
670 if (i >= 0) {
671 strcpy(cmap_dst[i], c2);
672 } else if (cmap_n < NCMAPS) {
673 strcpy(cmap_src[cmap_n], c1);
674 strcpy(cmap_dst[cmap_n], c2);
675 dict_put(cmap, cmap_src[cmap_n], cmap_n);
676 cmap_n++;
680 char *cmap_map(char *c)
682 int i = dict_get(cmap, c);
683 return i >= 0 ? cmap_dst[i] : c;
686 static void tr_tr(char **args)
688 char *s = args[1];
689 char c1[GNLEN], c2[GNLEN];
690 while (s && charread(&s, c1) >= 0) {
691 if (charread(&s, c2) < 0)
692 strcpy(c2, " ");
693 cmap_add(c1, c2);
697 /* character definition (.char) */
698 static char cdef_src[NCDEFS][GNLEN]; /* source character */
699 static char *cdef_dst[NCDEFS]; /* character definition */
700 static int cdef_fn[NCDEFS]; /* owning font */
701 static int cdef_n; /* number of defined characters */
702 static int cdef_expanding; /* inside cdef_expand() call */
704 static int cdef_find(char *c, int fn)
706 int i;
707 for (i = 0; i < cdef_n; i++)
708 if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
709 return i;
710 return -1;
713 /* return the definition of the given character */
714 char *cdef_map(char *c, int fn)
716 int i = cdef_find(c, fn);
717 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
720 int cdef_expand(struct wb *wb, char *s, int fn)
722 char *d = cdef_map(s, fn);
723 if (!d)
724 return 1;
725 cdef_expanding = 1;
726 ren_parse(wb, d);
727 cdef_expanding = 0;
728 return 0;
731 static void cdef_add(char *fn, char *cs, char *def)
733 char c[GNLEN];
734 int i;
735 if (!def || charread(&cs, c) < 0)
736 return;
737 i = cdef_find(c, -1);
738 if (i < 0 && cdef_n < NCDEFS)
739 i = cdef_n++;
740 if (i >= 0) {
741 snprintf(cdef_src[i], sizeof(cdef_src[i]), "%s", c);
742 cdef_dst[i] = xmalloc(strlen(def) + 1);
743 strcpy(cdef_dst[i], def);
744 cdef_fn[i] = fn ? dev_pos(fn) : 0;
748 static void cdef_remove(char *cs)
750 char c[GNLEN];
751 int i;
752 if (!cs || charread(&cs, c) < 0)
753 return;
754 for (i = 0; i < cdef_n; i++) {
755 if (!strcmp(cdef_src[i], c)) {
756 free(cdef_dst[i]);
757 cdef_dst[i] = NULL;
758 cdef_src[i][0] = '\0';
763 static void tr_char(char **args)
765 cdef_add(NULL, args[1], args[2]);
768 static void tr_rchar(char **args)
770 int i;
771 for (i = 1; i <= NARGS; i++)
772 if (args[i])
773 cdef_remove(args[i]);
776 static void tr_ochar(char **args)
778 cdef_add(args[1], args[2], args[3]);
781 static void tr_fmap(char **args)
783 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
784 if (fn && args[2])
785 font_map(fn, args[2], args[3]);
788 static void arg_regname(struct sbuf *sbuf)
790 char reg[NMLEN];
791 read_regname(reg);
792 sbuf_append(sbuf, reg);
793 sbuf_add(sbuf, 0);
796 static void arg_string(struct sbuf *sbuf)
798 int c;
799 while ((c = cp_next()) == ' ')
801 if (c == '"')
802 c = cp_next();
803 while (c > 0 && c != '\n') {
804 if (c != c_ni)
805 sbuf_add(sbuf, c);
806 c = cp_next();
808 sbuf_add(sbuf, 0);
809 if (c >= 0)
810 cp_back(c);
813 static int mkargs_arg(struct sbuf *sbuf, int (*next)(void), void (*back)(int))
815 int quoted = 0;
816 int c;
817 c = next();
818 while (c == ' ')
819 c = next();
820 if (c == '\n')
821 back(c);
822 if (c < 0 || c == '\n')
823 return 1;
824 if (c == '"') {
825 quoted = 1;
826 c = next();
828 while (c >= 0 && c != '\n') {
829 if (!quoted && c == ' ')
830 break;
831 if (quoted && c == '"') {
832 c = next();
833 if (c != '"')
834 break;
836 if (c == c_ec) {
837 sbuf_add(sbuf, c);
838 c = next();
840 sbuf_add(sbuf, c);
841 c = next();
843 sbuf_add(sbuf, 0);
844 if (c >= 0)
845 back(c);
846 return 0;
849 /* read macro arguments */
850 int tr_readargs(char **args, struct sbuf *sbuf, int (*next)(void), void (*back)(int))
852 int idx[NARGS];
853 int i, n = 0;
854 while (n < NARGS) {
855 idx[n] = sbuf_len(sbuf);
856 if (mkargs_arg(sbuf, next, back))
857 break;
858 n++;
860 for (i = 0; i < n; i++)
861 args[i] = sbuf_buf(sbuf) + idx[i];
862 return n;
865 /* read macro arguments; trims tabs if rmtabs is nonzero */
866 static int mkargs(char **args, struct sbuf *sbuf)
868 int n = tr_readargs(args, sbuf, cp_next, cp_back);
869 jmp_eol();
870 return n;
873 /* read request arguments; trims tabs too */
874 static int mkargs_req(char **args, struct sbuf *sbuf)
876 int idx[NARGS];
877 int i, n = 0;
878 int c;
879 c = cp_next();
880 while (n < NARGS) {
881 idx[n] = sbuf_len(sbuf);
882 while (c == ' ' || c == '\t')
883 c = cp_next();
884 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
885 if (c != c_ni)
886 sbuf_add(sbuf, c);
887 c = cp_next();
889 if (sbuf_len(sbuf) > idx[n])
890 n++;
891 sbuf_add(sbuf, 0);
892 if (c == '\n')
893 cp_back(c);
894 if (c < 0 || c == '\n')
895 break;
897 for (i = 0; i < n; i++)
898 args[i] = sbuf_buf(sbuf) + idx[i];
899 jmp_eol();
900 return n;
903 /* read arguments for .ds */
904 static int mkargs_ds(char **args, struct sbuf *sbuf)
906 int idx[NARGS];
907 int i, n = 0;
908 idx[n++] = sbuf_len(sbuf);
909 arg_regname(sbuf);
910 idx[n++] = sbuf_len(sbuf);
911 cp_copymode(1);
912 arg_string(sbuf);
913 cp_copymode(0);
914 jmp_eol();
915 for (i = 0; i < n; i++)
916 args[i] = sbuf_buf(sbuf) + idx[i];
917 return n;
920 /* read arguments for commands .nr that expect a register name */
921 static int mkargs_reg1(char **args, struct sbuf *sbuf)
923 int n;
924 int idx0 = sbuf_len(sbuf);
925 arg_regname(sbuf);
926 n = mkargs_req(args + 1, sbuf) + 1;
927 args[0] = sbuf_buf(sbuf) + idx0;
928 return n;
931 /* do not read arguments; for .if, .ie and .el */
932 static int mkargs_null(char **args, struct sbuf *sbuf)
934 return 0;
937 /* read the whole line for .tm */
938 static int mkargs_eol(char **args, struct sbuf *sbuf)
940 int idx0 = sbuf_len(sbuf);
941 int c;
942 cp_copymode(1);
943 c = cp_next();
944 while (c == ' ')
945 c = cp_next();
946 while (c >= 0 && c != '\n') {
947 if (c != c_ni)
948 sbuf_add(sbuf, c);
949 c = cp_next();
951 cp_copymode(0);
952 args[0] = sbuf_buf(sbuf) + idx0;
953 return 1;
956 static struct cmd {
957 char *id;
958 void (*f)(char **args);
959 int (*args)(char **args, struct sbuf *sbuf);
960 } cmds[] = {
961 {TR_DIVBEG, tr_divbeg},
962 {TR_DIVEND, tr_divend},
963 {TR_DIVVS, tr_divvs},
964 {TR_POPREN, tr_popren},
965 {"ab", tr_ab, mkargs_eol},
966 {"ad", tr_ad},
967 {"af", tr_af},
968 {"am", tr_de, mkargs_reg1},
969 {"as", tr_as, mkargs_ds},
970 {"bd", tr_bd},
971 {"bp", tr_bp},
972 {"br", tr_br},
973 {"c2", tr_c2},
974 {"cc", tr_cc},
975 {"ochar", tr_ochar},
976 {"ce", tr_ce},
977 {"ch", tr_ch},
978 {"char", tr_char, mkargs_ds},
979 {"chop", tr_chop, mkargs_reg1},
980 {"cl", tr_cl},
981 {"cp", tr_cp},
982 {"cs", tr_cs},
983 {"da", tr_di},
984 {"de", tr_de, mkargs_reg1},
985 {"di", tr_di},
986 {"ds", tr_ds, mkargs_ds},
987 {"dt", tr_dt},
988 {"ec", tr_ec},
989 {"el", tr_el, mkargs_null},
990 {"em", tr_em},
991 {"eo", tr_eo},
992 {"eos", tr_eos},
993 {"ev", tr_ev},
994 {"ex", tr_ex},
995 {"fc", tr_fc},
996 {"ff", tr_ff},
997 {"fi", tr_fi},
998 {"fl", tr_br},
999 {"fmap", tr_fmap},
1000 {"fp", tr_fp},
1001 {"fspecial", tr_fspecial},
1002 {"ft", tr_ft},
1003 {"fzoom", tr_fzoom},
1004 {"hc", tr_hc},
1005 {"hcode", tr_hcode},
1006 {"hpf", tr_hpf},
1007 {"hpfa", tr_hpfa},
1008 {"hy", tr_hy},
1009 {"hycost", tr_hycost},
1010 {"hydash", tr_hydash},
1011 {"hystop", tr_hystop},
1012 {"hw", tr_hw},
1013 {"ie", tr_if, mkargs_null},
1014 {"if", tr_if, mkargs_null},
1015 {"ig", tr_ig},
1016 {"in", tr_in},
1017 {"it", tr_it},
1018 {"kn", tr_kn},
1019 {"lc", tr_lc},
1020 {"lf", tr_lf},
1021 {"lg", tr_lg},
1022 {"ll", tr_ll},
1023 {"ls", tr_ls},
1024 {"lt", tr_lt},
1025 {"mc", tr_mc},
1026 {"mk", tr_mk},
1027 {"na", tr_na},
1028 {"ne", tr_ne},
1029 {"nf", tr_nf},
1030 {"nh", tr_nh},
1031 {"nm", tr_nm},
1032 {"nn", tr_nn},
1033 {"nr", tr_nr, mkargs_reg1},
1034 {"ns", tr_ns},
1035 {"nx", tr_nx},
1036 {"os", tr_os},
1037 {"pc", tr_pc},
1038 {"pl", tr_pl},
1039 {"pmll", tr_pmll},
1040 {"pn", tr_pn},
1041 {"po", tr_po},
1042 {"ps", tr_ps},
1043 {"rchar", tr_rchar, mkargs_ds},
1044 {"rm", tr_rm},
1045 {"rn", tr_rn},
1046 {"rr", tr_rr},
1047 {"rs", tr_rs},
1048 {"rt", tr_rt},
1049 {"so", tr_so},
1050 {"sp", tr_sp},
1051 {"ss", tr_ss},
1052 {"ssh", tr_ssh},
1053 {"sv", tr_sv},
1054 {"sy", tr_sy, mkargs_eol},
1055 {"ta", tr_ta},
1056 {"tc", tr_tc},
1057 {"ti", tr_ti},
1058 {"tl", tr_tl, mkargs_null},
1059 {"tm", tr_tm, mkargs_eol},
1060 {"tr", tr_tr, mkargs_eol},
1061 {"vs", tr_vs},
1062 {"wh", tr_wh},
1065 /* read the next troff request; return zero if a request was executed. */
1066 int tr_nextreq(void)
1068 char *args[NARGS + 3] = {NULL};
1069 char cmd[RNLEN + 1];
1070 struct cmd *req;
1071 struct sbuf sbuf;
1072 int c;
1073 if (!tr_nl)
1074 return 1;
1075 c = cp_next();
1076 if (c == c_ec) {
1077 int c2 = cp_next();
1078 if (c2 == '!') {
1079 args[0] = "\\!";
1080 sbuf_init(&sbuf);
1081 cp_copymode(1);
1082 mkargs_eol(args + 1, &sbuf);
1083 cp_copymode(0);
1084 tr_transparent(args);
1085 sbuf_done(&sbuf);
1086 return 0;
1088 cp_back(c2);
1090 if (c < 0 || (c != c_cc && c != c_c2)) {
1091 cp_back(c);
1092 return 1;
1094 memset(args, 0, sizeof(args));
1095 args[0] = cmd;
1096 cmd[0] = c;
1097 req = NULL;
1098 cp_reqbeg();
1099 read_regname(cmd + 1);
1100 sbuf_init(&sbuf);
1101 req = str_dget(map(cmd + 1));
1102 if (req) {
1103 if (req->args)
1104 req->args(args + 1, &sbuf);
1105 else
1106 mkargs_req(args + 1, &sbuf);
1107 req->f(args);
1108 } else {
1109 cp_copymode(1);
1110 mkargs(args + 1, &sbuf);
1111 cp_copymode(0);
1112 if (str_get(map(cmd + 1)))
1113 in_push(str_get(map(cmd + 1)), args + 1);
1115 sbuf_done(&sbuf);
1116 return 0;
1119 int tr_next(void)
1121 int c;
1122 while (!tr_nextreq())
1124 c = cp_next();
1125 tr_nl = c == '\n' || c < 0;
1126 return c;
1129 void tr_init(void)
1131 int i;
1132 for (i = 0; i < LEN(cmds); i++)
1133 str_dset(map(cmds[i].id), &cmds[i]);
1134 cmap = dict_make(-1, 0, 0);
1137 void tr_done(void)
1139 dict_free(cmap);