roff: switch to ISC
[neatroff.git] / tr.c
blob97b1c2c9f4ba4cca5fb62e0e5e1ff07ba820ae04
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 /* read a string argument of a macro */
112 static char *read_string(void)
114 struct sbuf sbuf;
115 int c;
116 sbuf_init(&sbuf);
117 cp_copymode(1);
118 while ((c = cp_next()) == ' ')
120 if (c == '"')
121 c = cp_next();
122 while (c > 0 && c != '\n') {
123 if (c != c_ni)
124 sbuf_add(&sbuf, c);
125 c = cp_next();
127 if (c >= 0)
128 cp_back(c);
129 cp_copymode(0);
130 return sbuf_out(&sbuf);
133 /* read a register name argument; if two, read at most two characters */
134 static char *read_name(int two)
136 struct sbuf sbuf;
137 int c = cp_next();
138 int i = 0;
139 sbuf_init(&sbuf);
140 while (c == ' ' || c == '\t' || c == c_ni)
141 c = cp_next();
142 while (c > 0 && c != ' ' && c != '\t' && c != '\n' && (!two || i < 2)) {
143 if (c != c_ni) {
144 sbuf_add(&sbuf, c);
145 i++;
147 c = cp_next();
149 if (c >= 0)
150 cp_back(c);
151 return sbuf_out(&sbuf);
155 static void macrobody(struct sbuf *sbuf, char *end)
157 int first = 1;
158 int c;
159 char *req = NULL;
160 cp_back('\n');
161 cp_copymode(1);
162 while ((c = cp_next()) >= 0) {
163 if (sbuf && !first)
164 sbuf_add(sbuf, c);
165 first = 0;
166 if (c == '\n') {
167 if ((c = cp_next()) != c_cc) {
168 cp_back(c);
169 continue;
171 req = read_name(n_cp);
172 if (!strcmp(end, req)) {
173 in_push(end, NULL);
174 cp_back(c_cc);
175 break;
177 if (sbuf) {
178 sbuf_add(sbuf, c_cc);
179 sbuf_append(sbuf, req);
181 free(req);
182 req = NULL;
185 free(req);
186 cp_copymode(0);
189 static void tr_de(char **args)
191 struct sbuf sbuf;
192 int id;
193 if (!args[1])
194 return;
195 id = map(args[1]);
196 sbuf_init(&sbuf);
197 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
198 sbuf_append(&sbuf, str_get(id));
199 macrobody(&sbuf, args[2] ? args[2] : ".");
200 str_set(id, sbuf_buf(&sbuf));
201 sbuf_done(&sbuf);
204 static void tr_ig(char **args)
206 macrobody(NULL, args[1] ? args[1] : ".");
209 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
210 static int read_until(struct sbuf *sbuf, char *stop,
211 int (*next)(void), void (*back)(int))
213 char cs[GNLEN], cs2[GNLEN];
214 int c;
215 while ((c = next()) >= 0) {
216 if (c == c_ni)
217 continue;
218 back(c);
219 if (c == '\n')
220 return 1;
221 if (!stop && (c == ' ' || c == '\t'))
222 return 0;
223 charnext(cs, next, back);
224 if (stop && !strcmp(stop, cs))
225 return 0;
226 charnext_str(cs2, cs);
227 sbuf_append(sbuf, cs2);
229 return 1;
232 /* evaluate .if strcmp (i.e. 'str'str') */
233 static int if_strcmp(int (*next)(void), void (*back)(int))
235 char delim[GNLEN];
236 struct sbuf s1, s2;
237 int ret;
238 charnext(delim, next, back);
239 sbuf_init(&s1);
240 sbuf_init(&s2);
241 read_until(&s1, delim, next, back);
242 read_until(&s2, delim, next, back);
243 cp_reqbeg();
244 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
245 sbuf_done(&s1);
246 sbuf_done(&s2);
247 return ret;
250 /* evaluate .if condition letters */
251 static int if_cond(int (*next)(void), void (*back)(int))
253 switch (cp_next()) {
254 case 'o':
255 return n_pg % 2;
256 case 'e':
257 return !(n_pg % 2);
258 case 't':
259 return 1;
260 case 'n':
261 return 0;
263 return 0;
266 /* evaluate .if condition */
267 static int if_eval(int (*next)(void), void (*back)(int))
269 struct sbuf sbuf;
270 int ret;
271 sbuf_init(&sbuf);
272 read_until(&sbuf, NULL, next, back);
273 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
274 sbuf_done(&sbuf);
275 return ret;
278 static int eval_if(int (*next)(void), void (*back)(int))
280 int neg = 0;
281 int ret;
282 int c;
283 do {
284 c = next();
285 } while (c == ' ' || c == '\t');
286 if (c == '!') {
287 neg = 1;
288 c = next();
290 back(c);
291 if (strchr("oetn", c)) {
292 ret = if_cond(next, back);
293 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
294 ret = if_strcmp(next, back);
295 } else {
296 ret = if_eval(next, back);
298 return ret != neg;
301 static int ie_cond[NIES]; /* .ie condition stack */
302 static int ie_depth;
304 static void tr_if(char **args)
306 int c = eval_if(cp_next, cp_back);
307 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
308 if (ie_depth < NIES)
309 ie_cond[ie_depth++] = c;
310 cp_blk(!c);
313 static void tr_el(char **args)
315 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
318 static void tr_na(char **args)
320 n_na = 1;
323 static int adjmode(int c, int def)
325 switch (c) {
326 case 'l':
327 return AD_L;
328 case 'r':
329 return AD_R;
330 case 'c':
331 return AD_C;
332 case 'b':
333 case 'n':
334 return AD_B;
336 return def;
339 static void tr_ad(char **args)
341 char *s = args[1];
342 n_na = 0;
343 if (!s)
344 return;
345 if (isdigit(s[0]))
346 n_j = atoi(s) & 15;
347 else
348 n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j);
351 static void tr_tm(char **args)
353 fprintf(stderr, "%s\n", args[1]);
356 static void tr_so(char **args)
358 if (args[1])
359 in_so(args[1]);
362 static void tr_nx(char **args)
364 in_nx(args[1]);
367 static void tr_ex(char **args)
369 in_ex();
372 static void tr_sy(char **args)
374 system(args[1]);
377 static void tr_lt(char **args)
379 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
380 n_t0 = n_t0;
381 n_lt = MAX(0, lt);
384 static void tr_pc(char **args)
386 char *s = args[1];
387 if (!s || charread(&s, c_pc) < 0)
388 strcpy(c_pc, "");
391 static void tr_tl(char **args)
393 int c;
394 do {
395 c = cp_next();
396 } while (c >= 0 && (c == ' ' || c == '\t'));
397 cp_back(c);
398 ren_tl(cp_next, cp_back);
399 do {
400 c = cp_next();
401 } while (c >= 0 && c != '\n');
404 static void tr_ec(char **args)
406 c_ec = args[1] ? args[1][0] : '\\';
409 static void tr_cc(char **args)
411 c_cc = args[1] ? args[1][0] : '.';
414 static void tr_c2(char **args)
416 c_c2 = args[1] ? args[1][0] : '\'';
419 static void tr_eo(char **args)
421 c_ec = -1;
424 static void tr_hc(char **args)
426 char *s = args[1];
427 if (!s || charread(&s, c_hc) < 0)
428 strcpy(c_hc, "\\%");
431 /* sentence ending and their transparent characters */
432 static char eos_sent[NCHARS][GNLEN] = { ".", "?", "!", };
433 static int eos_sentcnt = 3;
434 static char eos_tran[NCHARS][GNLEN] = { "'", "\"", ")", "]", "*", };
435 static int eos_trancnt = 5;
437 static void tr_eos(char **args)
439 eos_sentcnt = 0;
440 eos_trancnt = 0;
441 if (args[1]) {
442 char *s = args[1];
443 while (s && charread(&s, eos_sent[eos_sentcnt]) >= 0)
444 if (eos_sentcnt < NCHARS - 1)
445 eos_sentcnt++;
447 if (args[2]) {
448 char *s = args[2];
449 while (s && charread(&s, eos_tran[eos_trancnt]) >= 0)
450 if (eos_trancnt < NCHARS - 1)
451 eos_trancnt++;
455 int c_eossent(char *s)
457 int i;
458 for (i = 0; i < eos_sentcnt; i++)
459 if (!strcmp(eos_sent[i], s))
460 return 1;
461 return 0;
464 int c_eostran(char *s)
466 int i;
467 for (i = 0; i < eos_trancnt; i++)
468 if (!strcmp(eos_tran[i], s))
469 return 1;
470 return 0;
473 /* hyphenation dashes and hyphenation inhibiting character */
474 static char hy_dash[NCHARS][GNLEN] = { "\\:", "-", "em", "en", "\\-", "--", "hy", };
475 static int hy_dashcnt = 7;
476 static char hy_stop[NCHARS][GNLEN] = { "\\%", };
477 static int hy_stopcnt = 1;
479 static void tr_nh(char **args)
481 n_hy = 0;
484 static void tr_hy(char **args)
486 n_hy = args[1] ? eval_re(args[1], n_hy, '\0') : 1;
489 static void tr_hlm(char **args)
491 n_hlm = args[1] ? eval_re(args[1], n_hlm, '\0') : 0;
494 static void tr_hycost(char **args)
496 n_hycost = args[1] ? eval_re(args[1], n_hycost, '\0') : 0;
497 n_hycost2 = args[2] ? eval_re(args[2], n_hycost2, '\0') : 0;
498 n_hycost3 = args[3] ? eval_re(args[3], n_hycost3, '\0') : 0;
501 static void tr_hydash(char **args)
503 hy_dashcnt = 0;
504 if (args[1]) {
505 char *s = args[1];
506 while (s && charread(&s, hy_dash[hy_dashcnt]) >= 0)
507 if (hy_dashcnt < NCHARS - 1)
508 hy_dashcnt++;
512 static void tr_hystop(char **args)
514 hy_stopcnt = 0;
515 if (args[1]) {
516 char *s = args[1];
517 while (s && charread(&s, hy_stop[hy_stopcnt]) >= 0)
518 if (hy_stopcnt < NCHARS - 1)
519 hy_stopcnt++;
523 int c_hydash(char *s)
525 int i;
526 for (i = 0; i < hy_dashcnt; i++)
527 if (!strcmp(hy_dash[i], s))
528 return 1;
529 return 0;
532 int c_hystop(char *s)
534 int i;
535 for (i = 0; i < hy_stopcnt; i++)
536 if (!strcmp(hy_stop[i], s))
537 return 1;
538 return 0;
541 int c_hymark(char *s)
543 return !strcmp(c_bp, s) || !strcmp(c_hc, s);
546 static void tr_pmll(char **args)
548 n_pmll = args[1] ? eval_re(args[1], n_pmll, '\0') : 0;
549 n_pmllcost = args[2] ? eval_re(args[2], n_pmllcost, '\0') : 100;
552 static void tr_lg(char **args)
554 if (args[1])
555 n_lg = eval(args[1], '\0');
558 static void tr_kn(char **args)
560 if (args[1])
561 n_kn = eval(args[1], '\0');
564 static void tr_cp(char **args)
566 if (args[1])
567 n_cp = atoi(args[1]);
570 static void tr_ss(char **args)
572 if (args[1]) {
573 n_ss = eval_re(args[1], n_ss, 0);
574 n_sss = args[2] ? eval_re(args[2], n_sss, 0) : n_ss;
578 static void tr_ssh(char **args)
580 n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
583 static void tr_cs(char **args)
585 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
586 if (fn)
587 font_setcs(fn, args[2] ? eval(args[2], 0) : 0,
588 args[3] ? eval(args[3], 0) : 0);
591 static void tr_fzoom(char **args)
593 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
594 if (fn)
595 font_setzoom(fn, args[2] ? eval(args[2], 0) : 0);
598 static void tr_tkf(char **args)
600 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
601 if (fn && args[5])
602 font_track(fn, eval(args[2], 0), eval(args[3], 0),
603 eval(args[4], 0), eval(args[5], 0));
606 static void tr_ff(char **args)
608 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
609 int i;
610 for (i = 2; i <= NARGS; i++)
611 if (fn && args[i] && args[i][0] && args[i][1])
612 font_feat(fn, args[i] + 1, args[i][0] == '+');
615 static void tr_nm(char **args)
617 if (!args[1]) {
618 n_nm = 0;
619 return;
621 n_nm = 1;
622 n_ln = eval_re(args[1], n_ln, 0);
623 n_ln = MAX(0, n_ln);
624 if (args[2] && isdigit(args[2][0]))
625 n_nM = MAX(1, eval(args[2], 0));
626 if (args[3] && isdigit(args[3][0]))
627 n_nS = MAX(0, eval(args[3], 0));
628 if (args[4] && isdigit(args[4][0]))
629 n_nI = MAX(0, eval(args[4], 0));
632 static void tr_nn(char **args)
634 n_nn = args[1] ? eval(args[1], 0) : 1;
637 static void tr_bd(char **args)
639 if (!args[1] || !strcmp("S", args[1]))
640 return;
641 font_setbd(dev_font(dev_pos(args[1])), args[2] ? eval(args[2], 'u') : 0);
644 static void tr_it(char **args)
646 if (args[2]) {
647 n_it = map(args[2]);
648 n_itn = eval(args[1], 0);
649 } else {
650 n_it = 0;
654 static void tr_mc(char **args)
656 char *s = args[1];
657 if (s && charread(&s, c_mc) >= 0) {
658 n_mc = 1;
659 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
660 } else {
661 n_mc = 0;
665 static void tr_tc(char **args)
667 char *s = args[1];
668 if (!s || charread(&s, c_tc) < 0)
669 strcpy(c_tc, "");
672 static void tr_lc(char **args)
674 char *s = args[1];
675 if (!s || charread(&s, c_lc) < 0)
676 strcpy(c_lc, "");
679 static void tr_lf(char **args)
681 if (args[1])
682 in_lf(args[2], eval(args[1], 0));
685 static void tr_chop(char **args)
687 struct sbuf sbuf;
688 int id;
689 id = map(args[1]);
690 if (str_get(id)) {
691 sbuf_init(&sbuf);
692 sbuf_append(&sbuf, str_get(id));
693 if (!sbuf_empty(&sbuf)) {
694 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
695 str_set(id, sbuf_buf(&sbuf));
697 sbuf_done(&sbuf);
701 /* character translation (.tr) */
702 static struct dict *cmap; /* character mapping */
703 static char cmap_src[NCMAPS][GNLEN]; /* source character */
704 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
705 static int cmap_n; /* number of translated character */
707 void cmap_add(char *c1, char *c2)
709 int i = dict_get(cmap, c1);
710 if (i >= 0) {
711 strcpy(cmap_dst[i], c2);
712 } else if (cmap_n < NCMAPS) {
713 strcpy(cmap_src[cmap_n], c1);
714 strcpy(cmap_dst[cmap_n], c2);
715 dict_put(cmap, cmap_src[cmap_n], cmap_n);
716 cmap_n++;
720 char *cmap_map(char *c)
722 int i = dict_get(cmap, c);
723 return i >= 0 ? cmap_dst[i] : c;
726 static void tr_tr(char **args)
728 char *s = args[1];
729 char c1[GNLEN], c2[GNLEN];
730 while (s && charread(&s, c1) >= 0) {
731 if (charread(&s, c2) < 0)
732 strcpy(c2, " ");
733 cmap_add(c1, c2);
737 /* character definition (.char) */
738 static char cdef_src[NCDEFS][GNLEN]; /* source character */
739 static char *cdef_dst[NCDEFS]; /* character definition */
740 static int cdef_fn[NCDEFS]; /* owning font */
741 static int cdef_n; /* number of defined characters */
742 static int cdef_expanding; /* inside cdef_expand() call */
744 static int cdef_find(char *c, int fn)
746 int i;
747 for (i = 0; i < cdef_n; i++)
748 if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
749 return i;
750 return -1;
753 /* return the definition of the given character */
754 char *cdef_map(char *c, int fn)
756 int i = cdef_find(c, fn);
757 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
760 int cdef_expand(struct wb *wb, char *s, int fn)
762 char *d = cdef_map(s, fn);
763 if (!d)
764 return 1;
765 cdef_expanding = 1;
766 ren_parse(wb, d);
767 cdef_expanding = 0;
768 return 0;
771 static void cdef_add(char *fn, char *cs, char *def)
773 char c[GNLEN];
774 int i;
775 if (!def || charread(&cs, c) < 0)
776 return;
777 i = cdef_find(c, -1);
778 if (i < 0 && cdef_n < NCDEFS)
779 i = cdef_n++;
780 if (i >= 0) {
781 snprintf(cdef_src[i], sizeof(cdef_src[i]), "%s", c);
782 cdef_dst[i] = xmalloc(strlen(def) + 1);
783 strcpy(cdef_dst[i], def);
784 cdef_fn[i] = fn ? dev_pos(fn) : 0;
788 static void cdef_remove(char *cs)
790 char c[GNLEN];
791 int i;
792 if (!cs || charread(&cs, c) < 0)
793 return;
794 for (i = 0; i < cdef_n; i++) {
795 if (!strcmp(cdef_src[i], c)) {
796 free(cdef_dst[i]);
797 cdef_dst[i] = NULL;
798 cdef_src[i][0] = '\0';
803 static void tr_char(char **args)
805 cdef_add(NULL, args[1], args[2]);
808 static void tr_rchar(char **args)
810 int i;
811 for (i = 1; i <= NARGS; i++)
812 if (args[i])
813 cdef_remove(args[i]);
816 static void tr_ochar(char **args)
818 cdef_add(args[1], args[2], args[3]);
821 static void tr_fmap(char **args)
823 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
824 if (fn && args[2])
825 font_map(fn, args[2], args[3]);
828 /* read a macro argument */
829 static int tr_arg(struct sbuf *sbuf, int brk, int (*next)(void), void (*back)(int))
831 int quoted = 0;
832 int c;
833 c = next();
834 while (c == ' ')
835 c = next();
836 if (c == '\n' || c == brk)
837 back(c);
838 if (c < 0 || c == '\n' || c == brk)
839 return 1;
840 if (c == '"') {
841 quoted = 1;
842 c = next();
844 while (c >= 0 && c != '\n' && (quoted || c != brk)) {
845 if (!quoted && c == ' ')
846 break;
847 if (quoted && c == '"') {
848 c = next();
849 if (c != '"')
850 break;
852 if (c == c_ec) {
853 sbuf_add(sbuf, c);
854 c = next();
856 sbuf_add(sbuf, c);
857 c = next();
859 sbuf_add(sbuf, 0);
860 if (c >= 0)
861 back(c);
862 return 0;
865 /* read macro arguments; free the returned pointer when done */
866 char *tr_args(char **args, int brk, int (*next)(void), void (*back)(int))
868 struct sbuf sbuf;
869 char *s, *e;
870 int n = 0;
871 sbuf_init(&sbuf);
872 while (!tr_arg(&sbuf, brk, next, back))
874 s = sbuf_buf(&sbuf);
875 e = s + sbuf_len(&sbuf);
876 while (n < NARGS && s && s < e) {
877 args[n++] = s;
878 if ((s = memchr(s, '\0', e - s)))
879 s++;
881 return sbuf_out(&sbuf);
884 /* split the arguments in sbuf */
885 static int tr_argschop(struct sbuf *sbuf, char **args)
887 char *s = sbuf_buf(sbuf);
888 char *e = s + sbuf_len(sbuf);
889 int n = 0;
890 while (n < NARGS && s && s < e) {
891 args[n++] = s;
892 if ((s = memchr(s, '\0', e - s)))
893 s++;
895 return n;
898 /* read request arguments; trims tabs too */
899 static void mkargs_req(struct sbuf *sbuf)
901 int n = 0;
902 int c;
903 c = cp_next();
904 while (n < NARGS) {
905 int ok = 0;
906 while (c == ' ' || c == '\t')
907 c = cp_next();
908 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
909 if (c != c_ni)
910 sbuf_add(sbuf, c);
911 c = cp_next();
912 ok = 1;
914 if (ok) {
915 n++;
916 sbuf_add(sbuf, 0);
918 if (c == '\n')
919 cp_back(c);
920 if (c < 0 || c == '\n')
921 break;
923 jmp_eol();
926 /* read arguments for .ds */
927 static void mkargs_ds(struct sbuf *sbuf)
929 char *s = read_name(n_cp);
930 sbuf_append(sbuf, s);
931 sbuf_add(sbuf, 0);
932 free(s);
933 s = read_string();
934 sbuf_append(sbuf, s);
935 sbuf_add(sbuf, 0);
936 free(s);
937 jmp_eol();
940 /* read arguments for .char */
941 static void mkargs_def(struct sbuf *sbuf)
943 char *s = read_name(0);
944 sbuf_append(sbuf, s);
945 sbuf_add(sbuf, 0);
946 free(s);
947 s = read_string();
948 sbuf_append(sbuf, s);
949 sbuf_add(sbuf, 0);
950 free(s);
951 jmp_eol();
954 /* read arguments for .ochar */
955 static void mkargs_def3(struct sbuf *sbuf)
957 char *s = read_name(0);
958 sbuf_append(sbuf, s);
959 sbuf_add(sbuf, 0);
960 free(s);
961 mkargs_def(sbuf);
964 /* read arguments for .nr */
965 static void mkargs_reg1(struct sbuf *sbuf)
967 char *s = read_name(n_cp);
968 sbuf_append(sbuf, s);
969 sbuf_add(sbuf, 0);
970 free(s);
971 mkargs_req(sbuf);
974 /* do not read any arguments; for .if, .ie and .el */
975 static void mkargs_null(struct sbuf *sbuf)
979 /* read the whole line for .tm */
980 static void mkargs_eol(struct sbuf *sbuf)
982 int c;
983 cp_copymode(1);
984 c = cp_next();
985 while (c == ' ')
986 c = cp_next();
987 while (c >= 0 && c != '\n') {
988 if (c != c_ni)
989 sbuf_add(sbuf, c);
990 c = cp_next();
992 cp_copymode(0);
995 static struct cmd {
996 char *id;
997 void (*f)(char **args);
998 void (*args)(struct sbuf *sbuf);
999 } cmds[] = {
1000 {TR_DIVBEG, tr_divbeg},
1001 {TR_DIVEND, tr_divend},
1002 {TR_DIVVS, tr_divvs},
1003 {TR_POPREN, tr_popren},
1004 {"ab", tr_ab, mkargs_eol},
1005 {"ad", tr_ad},
1006 {"af", tr_af},
1007 {"am", tr_de, mkargs_reg1},
1008 {"as", tr_as, mkargs_ds},
1009 {"bd", tr_bd},
1010 {"bp", tr_bp},
1011 {"br", tr_br},
1012 {"c2", tr_c2},
1013 {"cc", tr_cc},
1014 {"ochar", tr_ochar, mkargs_def3},
1015 {"ce", tr_ce},
1016 {"ch", tr_ch},
1017 {"char", tr_char, mkargs_def},
1018 {"chop", tr_chop, mkargs_reg1},
1019 {"cl", tr_cl},
1020 {"cp", tr_cp},
1021 {"cs", tr_cs},
1022 {"da", tr_di},
1023 {"de", tr_de, mkargs_reg1},
1024 {"di", tr_di},
1025 {"ds", tr_ds, mkargs_ds},
1026 {"dt", tr_dt},
1027 {"ec", tr_ec},
1028 {"el", tr_el, mkargs_null},
1029 {"em", tr_em},
1030 {"eo", tr_eo},
1031 {"eos", tr_eos},
1032 {"ev", tr_ev},
1033 {"ex", tr_ex},
1034 {"fc", tr_fc},
1035 {"ff", tr_ff},
1036 {"fi", tr_fi},
1037 {"fl", tr_br},
1038 {"fmap", tr_fmap},
1039 {"fp", tr_fp},
1040 {"fspecial", tr_fspecial},
1041 {"ft", tr_ft},
1042 {"fzoom", tr_fzoom},
1043 {"hc", tr_hc},
1044 {"hcode", tr_hcode},
1045 {"hlm", tr_hlm},
1046 {"hpf", tr_hpf},
1047 {"hpfa", tr_hpfa},
1048 {"hy", tr_hy},
1049 {"hycost", tr_hycost},
1050 {"hydash", tr_hydash},
1051 {"hystop", tr_hystop},
1052 {"hw", tr_hw},
1053 {"ie", tr_if, mkargs_null},
1054 {"if", tr_if, mkargs_null},
1055 {"ig", tr_ig},
1056 {"in", tr_in},
1057 {"it", tr_it},
1058 {"kn", tr_kn},
1059 {"lc", tr_lc},
1060 {"lf", tr_lf},
1061 {"lg", tr_lg},
1062 {"ll", tr_ll},
1063 {"ls", tr_ls},
1064 {"lt", tr_lt},
1065 {"mc", tr_mc},
1066 {"mk", tr_mk},
1067 {"na", tr_na},
1068 {"ne", tr_ne},
1069 {"nf", tr_nf},
1070 {"nh", tr_nh},
1071 {"nm", tr_nm},
1072 {"nn", tr_nn},
1073 {"nr", tr_nr, mkargs_reg1},
1074 {"ns", tr_ns},
1075 {"nx", tr_nx},
1076 {"os", tr_os},
1077 {"pc", tr_pc},
1078 {"pl", tr_pl},
1079 {"pmll", tr_pmll},
1080 {"pn", tr_pn},
1081 {"po", tr_po},
1082 {"ps", tr_ps},
1083 {"rchar", tr_rchar},
1084 {"rm", tr_rm},
1085 {"rn", tr_rn},
1086 {"rr", tr_rr},
1087 {"rs", tr_rs},
1088 {"rt", tr_rt},
1089 {"so", tr_so},
1090 {"sp", tr_sp},
1091 {"ss", tr_ss},
1092 {"ssh", tr_ssh},
1093 {"sv", tr_sv},
1094 {"sy", tr_sy, mkargs_eol},
1095 {"ta", tr_ta},
1096 {"tc", tr_tc},
1097 {"ti", tr_ti},
1098 {"tkf", tr_tkf},
1099 {"tl", tr_tl, mkargs_null},
1100 {"tm", tr_tm, mkargs_eol},
1101 {"tr", tr_tr, mkargs_eol},
1102 {"vs", tr_vs},
1103 {"wh", tr_wh},
1106 static char *dotted(char *name, int dot)
1108 char *out = xmalloc(strlen(name) + 2);
1109 out[0] = dot;
1110 strcpy(out + 1, name);
1111 return out;
1114 /* read the next troff request; return zero if a request was executed. */
1115 int tr_nextreq(void)
1117 char *args[NARGS + 3] = {NULL};
1118 char *cmd;
1119 struct cmd *req;
1120 struct sbuf sbuf;
1121 int c;
1122 if (!tr_nl)
1123 return 1;
1124 c = cp_next();
1125 if (c == c_ec) {
1126 int c2 = cp_next();
1127 if (c2 == '!') {
1128 args[0] = "\\!";
1129 sbuf_init(&sbuf);
1130 cp_copymode(1);
1131 mkargs_eol(&sbuf);
1132 cp_copymode(0);
1133 tr_argschop(&sbuf, args + 1);
1134 tr_transparent(args);
1135 sbuf_done(&sbuf);
1136 return 0;
1138 cp_back(c2);
1140 if (c < 0 || (c != c_cc && c != c_c2)) {
1141 cp_back(c);
1142 return 1;
1144 cp_reqbeg();
1145 cmd = read_name(n_cp);
1146 args[0] = dotted(cmd, c);
1147 req = str_dget(map(cmd));
1148 if (req) {
1149 sbuf_init(&sbuf);
1150 if (req->args)
1151 req->args(&sbuf);
1152 else
1153 mkargs_req(&sbuf);
1154 tr_argschop(&sbuf, args + 1);
1155 req->f(args);
1156 sbuf_done(&sbuf);
1157 } else {
1158 char *buf;
1159 cp_copymode(1);
1160 buf = tr_args(args + 1, -1, cp_next, cp_back);
1161 jmp_eol();
1162 cp_copymode(0);
1163 if (str_get(map(cmd)))
1164 in_push(str_get(map(cmd)), args + 1);
1165 free(buf);
1167 free(args[0]);
1168 free(cmd);
1169 return 0;
1172 int tr_next(void)
1174 int c;
1175 while (!tr_nextreq())
1177 c = cp_next();
1178 tr_nl = c == '\n' || c < 0;
1179 return c;
1182 void tr_init(void)
1184 int i;
1185 for (i = 0; i < LEN(cmds); i++)
1186 str_dset(map(cmds[i].id), &cmds[i]);
1187 cmap = dict_make(-1, 0, 0);
1190 void tr_done(void)
1192 dict_free(cmap);