tr: map font name to font position earlier for .ochar
[neatroff.git] / tr.c
blob42b7e315b15a180612ffbcd2b8f615fda4bfddfc
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 static int tr_nl = 1;
8 static int c_pc = '%'; /* page number character */
9 int c_ec = '\\';
10 int c_cc = '.';
11 int c_c2 = '\'';
13 /* skip everything until the end of line */
14 static void jmp_eol(void)
16 int c;
17 do {
18 c = cp_next();
19 } while (c >= 0 && c != '\n');
22 static void tr_vs(char **args)
24 int vs = args[1] ? eval_re(args[1], n_v, 'p') : n_v0;
25 n_v0 = n_v;
26 n_v = MAX(0, vs);
29 static void tr_ls(char **args)
31 int ls = args[1] ? eval_re(args[1], n_L, 0) : n_L0;
32 n_L0 = n_L;
33 n_L = MAX(1, ls);
36 static void tr_pl(char **args)
38 int n = eval_re(args[1] ? args[1] : "11i", n_p, 'v');
39 n_p = MAX(0, n);
42 static void tr_nr(char **args)
44 int id;
45 if (!args[2])
46 return;
47 id = map(args[1]);
48 num_set(id, eval_re(args[2], num_get(id, 0), 'u'));
49 num_inc(id, args[3] ? eval(args[3], 'u') : 0);
52 static void tr_rr(char **args)
54 int i;
55 for (i = 1; i <= NARGS; i++)
56 if (args[i])
57 num_del(map(args[i]));
60 static void tr_af(char **args)
62 if (args[2])
63 num_setfmt(map(args[1]), args[2]);
66 static void tr_ds(char **args)
68 if (args[2])
69 str_set(map(args[1]), args[2]);
72 static void tr_as(char **args)
74 int reg;
75 char *s1, *s2, *s;
76 if (!args[2])
77 return;
78 reg = map(args[1]);
79 s1 = str_get(reg) ? str_get(reg) : "";
80 s2 = args[2];
81 s = malloc(strlen(s1) + strlen(s2) + 1);
82 strcpy(s, s1);
83 strcat(s, s2);
84 str_set(reg, s);
85 free(s);
88 static void tr_rm(char **args)
90 int i;
91 for (i = 1; i <= NARGS; i++)
92 if (args[i])
93 str_rm(map(args[i]));
96 static void tr_rn(char **args)
98 if (!args[2])
99 return;
100 str_rn(map(args[1]), map(args[2]));
103 static void tr_po(char **args)
105 int po = args[1] ? eval_re(args[1], n_o, 'm') : n_o0;
106 n_o0 = n_o;
107 n_o = MAX(0, po);
110 static char *arg_regname(char *s, int len);
112 static void macrobody(struct sbuf *sbuf, char *end)
114 char buf[NMLEN];
115 int i, c;
116 int first = 1;
117 cp_back('\n');
118 cp_wid(0); /* copy-mode; disable \w handling */
119 while ((c = cp_next()) >= 0) {
120 if (sbuf && !first)
121 sbuf_add(sbuf, c);
122 first = 0;
123 if (c == '\n') {
124 c = cp_next();
125 if (c == '.') {
126 arg_regname(buf, sizeof(buf));
127 if ((n_cp && end[0] == buf[0] && end[1] == buf[1]) ||
128 !strcmp(end, buf)) {
129 jmp_eol();
130 break;
132 if (!sbuf)
133 continue;
134 sbuf_add(sbuf, '.');
135 for (i = 0; buf[i]; i++)
136 sbuf_add(sbuf, (unsigned char) buf[i]);
137 continue;
139 if (sbuf && c >= 0)
140 sbuf_add(sbuf, c);
143 cp_wid(1);
146 static void tr_de(char **args)
148 struct sbuf sbuf;
149 int id;
150 if (!args[1])
151 return;
152 id = map(args[1]);
153 sbuf_init(&sbuf);
154 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
155 sbuf_append(&sbuf, str_get(id));
156 macrobody(&sbuf, args[2] ? args[2] : ".");
157 str_set(id, sbuf_buf(&sbuf));
158 sbuf_done(&sbuf);
161 static void tr_ig(char **args)
163 macrobody(NULL, args[1] ? args[1] : ".");
166 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
167 static int read_until(struct sbuf *sbuf, char *stop)
169 char cs[GNLEN], cs2[GNLEN];
170 int c;
171 while ((c = cp_next()) >= 0) {
172 cp_back(c);
173 if (c == '\n')
174 return 1;
175 if (!stop && (c == ' ' || c == '\t'))
176 return 0;
177 charnext(cs, cp_next, cp_back);
178 if (stop && !strcmp(stop, cs))
179 return 0;
180 charnext_str(cs2, cs);
181 sbuf_append(sbuf, cs2);
183 return 1;
186 /* evaluate .if strcmp (i.e. 'str'str') */
187 static int if_strcmp(void)
189 char delim[GNLEN];
190 struct sbuf s1, s2;
191 int ret;
192 charnext(delim, cp_next, cp_back);
193 sbuf_init(&s1);
194 sbuf_init(&s2);
195 read_until(&s1, delim);
196 read_until(&s2, delim);
197 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
198 sbuf_done(&s1);
199 sbuf_done(&s2);
200 return ret;
203 /* evaluate .if condition letters */
204 static int if_cond(void)
206 switch (cp_next()) {
207 case 'o':
208 return n_pg % 2;
209 case 'e':
210 return !(n_pg % 2);
211 case 't':
212 return 1;
213 case 'n':
214 return 0;
216 return 0;
219 /* evaluate .if condition */
220 static int if_eval(void)
222 struct sbuf sbuf;
223 int ret;
224 sbuf_init(&sbuf);
225 if (!read_until(&sbuf, NULL))
226 cp_back(' ');
227 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
228 sbuf_done(&sbuf);
229 return ret;
232 static int ie_cond[NIES]; /* .ie condition stack */
233 static int ie_depth;
235 static void tr_if(char **args)
237 int neg = 0;
238 int ret;
239 int c;
240 do {
241 c = cp_next();
242 } while (c == ' ' || c == '\t');
243 if (c == '!') {
244 neg = 1;
245 c = cp_next();
247 cp_back(c);
248 if (strchr("oetn", c)) {
249 ret = if_cond();
250 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
251 ret = if_strcmp();
252 } else {
253 ret = if_eval();
255 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
256 if (ie_depth < NIES)
257 ie_cond[ie_depth++] = ret != neg;
258 cp_blk(ret == neg);
261 static void tr_el(char **args)
263 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
266 static void tr_na(char **args)
268 n_na = 1;
271 static void tr_ad(char **args)
273 n_na = 0;
274 if (!args[1])
275 return;
276 switch (args[1][0]) {
277 case '0' + AD_L:
278 case 'l':
279 n_j = AD_L;
280 break;
281 case '0' + AD_R:
282 case 'r':
283 n_j = AD_R;
284 break;
285 case '0' + AD_C:
286 case 'c':
287 n_j = AD_C;
288 break;
289 case '0' + AD_B:
290 case 'b':
291 case 'n':
292 n_j = AD_B;
293 break;
297 static void tr_tm(char **args)
299 fprintf(stderr, "%s\n", args[1]);
302 static void tr_so(char **args)
304 if (args[1])
305 in_so(args[1]);
308 static void tr_nx(char **args)
310 in_nx(args[1]);
313 static void tr_ex(char **args)
315 in_ex();
318 static void tr_sy(char **args)
320 system(args[1]);
323 static void tr_lt(char **args)
325 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
326 n_t0 = n_t0;
327 n_lt = MAX(0, lt);
330 static void tr_pc(char **args)
332 c_pc = args[1] ? args[1][0] : -1;
335 static int tl_next(void)
337 int c = cp_next();
338 if (c >= 0 && c == c_pc) {
339 in_push(num_str(map("%")), NULL);
340 c = cp_next();
342 return c;
345 static void tr_tl(char **args)
347 int c;
348 do {
349 c = cp_next();
350 } while (c >= 0 && (c == ' ' || c == '\t'));
351 cp_back(c);
352 ren_tl(tl_next, cp_back);
353 do {
354 c = cp_next();
355 } while (c >= 0 && c != '\n');
358 static void tr_ec(char **args)
360 c_ec = args[1] ? args[1][0] : '\\';
363 static void tr_cc(char **args)
365 c_ec = args[1] ? args[1][0] : '.';
368 static void tr_c2(char **args)
370 c_ec = args[1] ? args[1][0] : '\'';
373 static void tr_eo(char **args)
375 c_ec = -1;
378 static void tr_hc(char **args)
380 char *s = args[1];
381 if (!s || charread(&s, c_hc) < 0)
382 strcpy(c_hc, "\\%");
385 static void tr_nh(char **args)
387 n_hy = 0;
390 static void tr_hy(char **args)
392 n_hy = args[1] ? atoi(args[1]) : 1;
395 static void tr_lg(char **args)
397 if (args[1])
398 n_lg = atoi(args[1]);
401 static void tr_kn(char **args)
403 if (args[1])
404 n_kn = atoi(args[1]);
407 static void tr_cp(char **args)
409 if (args[1])
410 n_cp = atoi(args[1]);
413 static void tr_ss(char **args)
415 if (args[1])
416 n_ss = eval_re(args[1], n_ss, 0);
419 static void tr_cs(char **args)
421 if (!args[1])
422 return;
423 dev_setcs(dev_pos(args[1]), args[2] ? eval(args[2], 0) : 0);
426 static void tr_nm(char **args)
428 if (!args[1]) {
429 n_nm = 0;
430 return;
432 n_nm = 1;
433 n_ln = eval_re(args[1], n_ln, 0);
434 n_ln = MAX(0, n_ln);
435 if (args[2] && isdigit(args[2][0]))
436 n_nM = MAX(1, eval(args[2], 0));
437 if (args[3] && isdigit(args[3][0]))
438 n_nS = MAX(0, eval(args[3], 0));
439 if (args[4] && isdigit(args[4][0]))
440 n_nI = MAX(0, eval(args[4], 0));
443 static void tr_nn(char **args)
445 n_nn = args[1] ? eval(args[1], 0) : 1;
448 static void tr_bd(char **args)
450 if (!args[1] || !strcmp("S", args[1]))
451 return;
452 dev_setbd(dev_pos(args[1]), args[2] ? eval(args[2], 'u') : 0);
455 static void tr_it(char **args)
457 if (args[2]) {
458 n_it = map(args[2]);
459 n_itn = eval(args[1], 0);
460 } else {
461 n_it = 0;
465 static void tr_mc(char **args)
467 char *s = args[1];
468 if (s && charread(&s, c_mc) >= 0) {
469 n_mc = 1;
470 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
471 } else {
472 n_mc = 0;
476 static void tr_tc(char **args)
478 char *s = args[1];
479 if (!s || charread(&s, c_tc) < 0)
480 strcpy(c_tc, "");
483 static void tr_lc(char **args)
485 char *s = args[1];
486 if (!s || charread(&s, c_lc) < 0)
487 strcpy(c_lc, "");
490 static void tr_lf(char **args)
492 if (args[1])
493 in_lf(args[2], eval(args[1], 0));
496 static void tr_chop(char **args)
498 struct sbuf sbuf;
499 int id;
500 if (args[1])
501 in_lf(args[2], eval(args[1], 0));
502 id = map(args[1]);
503 if (str_get(id)) {
504 sbuf_init(&sbuf);
505 sbuf_append(&sbuf, str_get(id));
506 if (!sbuf_empty(&sbuf)) {
507 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
508 str_set(id, sbuf_buf(&sbuf));
510 sbuf_done(&sbuf);
514 /* character translation (.tr) */
515 static char cmap_src[NCMAPS][GNLEN]; /* source character */
516 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
517 static int cmap_n; /* number of translated character */
519 static int tr_find(char *c)
521 int i;
522 for (i = 0; i < cmap_n; i++)
523 if (!strcmp(c, cmap_src[i]))
524 return i;
525 return -1;
528 void cmap_add(char *c1, char *c2)
530 int i = tr_find(c1);
531 if (i < 0 && cmap_n < NCMAPS)
532 i = cmap_n++;
533 if (i >= 0) {
534 strcpy(cmap_src[i], c1);
535 strcpy(cmap_dst[i], c2);
539 char *cmap_map(char *c)
541 int i = tr_find(c);
542 return i >= 0 ? cmap_dst[i] : c;
545 static void tr_tr(char **args)
547 char *s = args[1];
548 char c1[GNLEN], c2[GNLEN];
549 while (s && charread(&s, c1) >= 0) {
550 if (charread(&s, c2) < 0)
551 strcpy(c2, " ");
552 cmap_add(c1, c2);
556 /* character definition (.char) */
557 static char cdef_src[NCDEFS][GNLEN]; /* source character */
558 static char *cdef_dst[NCDEFS]; /* character definition */
559 static int cdef_fn[NCDEFS]; /* owning font */
560 static int cdef_n; /* number of defined characters */
561 static int cdef_expanding; /* inside cdef_expand() call */
563 static int cdef_find(char *c, int fn)
565 int i;
566 for (i = 0; i < cdef_n; i++)
567 if (!strcmp(cdef_src[i], c) && (!cdef_fn[i] || cdef_fn[i] == fn))
568 return i;
569 return -1;
572 /* return the definition of the given character */
573 char *cdef_map(char *c, int fn)
575 int i = cdef_find(c, fn);
576 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
579 int cdef_expand(struct wb *wb, char *s, int fn)
581 char *d = cdef_map(s, fn);
582 if (!d)
583 return 1;
584 cdef_expanding = 1;
585 ren_parse(wb, d);
586 cdef_expanding = 0;
587 return 0;
590 static void cdef_add(char *fn, char *cs, char *def)
592 char c[GNLEN];
593 int i;
594 if (!def || charread(&cs, c) < 0)
595 return;
596 i = cdef_find(c, -1);
597 if (i < 0 && cdef_n < NCDEFS)
598 i = cdef_n++;
599 if (i >= 0) {
600 strncpy(cdef_src[i], c, sizeof(cdef_src[i]) - 1);
601 cdef_dst[i] = malloc(strlen(def) + 1);
602 strcpy(cdef_dst[i], def);
603 cdef_fn[i] = fn ? dev_pos(fn) : 0;
607 static void cdef_remove(char *cs)
609 char c[GNLEN];
610 int i;
611 if (!cs || charread(&cs, c) < 0)
612 return;
613 for (i = 0; i < cdef_n; i++) {
614 if (!strcmp(cdef_src[i], c)) {
615 free(cdef_dst[i]);
616 cdef_dst[i] = NULL;
617 cdef_src[i][0] = '\0';
622 static void tr_char(char **args)
624 cdef_add(NULL, args[1], args[2]);
627 static void tr_rchar(char **args)
629 int i;
630 for (i = 1; i <= NARGS; i++)
631 if (args[i])
632 cdef_remove(args[i]);
635 static void tr_ochar(char **args)
637 cdef_add(args[1], args[2], args[3]);
640 static char *arg_regname(char *s, int len)
642 char *e = n_cp ? s + 2 : s + len;
643 int c = cp_next();
644 while (c == ' ' || c == '\t')
645 c = cp_next();
646 while (s < e && c >= 0 && c != ' ' && c != '\t' && c != '\n') {
647 *s++ = c;
648 c = cp_next();
650 if (c >= 0)
651 cp_back(c);
652 *s++ = '\0';
653 return s;
656 static char *arg_normal(char *s, int len)
658 char *e = s + len - 1;
659 int quoted = 0;
660 int c;
661 c = cp_next();
662 while (c == ' ')
663 c = cp_next();
664 if (c == '"') {
665 quoted = 1;
666 c = cp_next();
668 while (s < e && c > 0 && c != '\n') {
669 if (!quoted && c == ' ')
670 break;
671 if (quoted && c == '"') {
672 c = cp_next();
673 if (c != '"')
674 break;
676 *s++ = c;
677 c = cp_next();
679 if (c >= 0)
680 cp_back(c);
681 *s++ = '\0';
682 return s;
685 static char *arg_string(char *s, int len)
687 char *e = s + len - 1;
688 int c;
689 while ((c = cp_next()) == ' ')
691 if (c == '"')
692 c = cp_next();
693 while (s < e && c > 0 && c != '\n') {
694 *s++ = c;
695 c = cp_next();
697 *s++ = '\0';
698 if (c >= 0)
699 cp_back(c);
700 return s;
703 /* read macro arguments; trims tabs if rmtabs is nonzero */
704 static int mkargs(char **args, char *buf, int len)
706 char *s = buf;
707 char *e = buf + len - 1;
708 int c;
709 int n = 0;
710 while (n < NARGS) {
711 char *r = s;
712 c = cp_next();
713 if (c < 0 || c == '\n')
714 return n;
715 cp_back(c);
716 s = arg_normal(s, e - s);
717 if (*r != '\0')
718 args[n++] = r;
720 jmp_eol();
721 return n;
724 /* read request arguments; trims tabs too */
725 static int mkargs_req(char **args, char *buf, int len)
727 char *r, *s = buf;
728 char *e = buf + len - 1;
729 int c;
730 int n = 0;
731 c = cp_next();
732 while (n < NARGS && s < e) {
733 r = s;
734 while (c == ' ' || c == '\t')
735 c = cp_next();
736 while (c >= 0 && c != '\n' && c != ' ' && c != '\t' && s < e) {
737 *s++ = c;
738 c = cp_next();
740 *s++ = '\0';
741 if (*r != '\0')
742 args[n++] = r;
743 if (c < 0 || c == '\n')
744 return n;
746 jmp_eol();
747 return n;
750 /* read arguments for .ds */
751 static int mkargs_ds(char **args, char *buf, int len)
753 char *s = buf;
754 char *e = buf + len - 1;
755 int c;
756 args[0] = s;
757 s = arg_regname(s, e - s);
758 args[1] = s;
759 cp_wid(0);
760 s = arg_string(s, e - s);
761 cp_wid(1);
762 c = cp_next();
763 if (c >= 0 && c != '\n')
764 jmp_eol();
765 return 2;
768 /* read arguments for commands .nr that expect a register name */
769 static int mkargs_reg1(char **args, char *buf, int len)
771 char *s = buf;
772 char *e = buf + len - 1;
773 args[0] = s;
774 s = arg_regname(s, e - s);
775 return mkargs_req(args + 1, s, e - s) + 1;
778 /* do not read arguments; for .if, .ie and .el */
779 static int mkargs_null(char **args, char *buf, int len)
781 return 0;
784 /* read the whole line for .tm */
785 static int mkargs_eol(char **args, char *buf, int len)
787 char *s = buf;
788 char *e = buf + len - 1;
789 int c;
790 args[0] = s;
791 c = cp_next();
792 while (c == ' ')
793 c = cp_next();
794 while (s < e && c >= 0 && c != '\n') {
795 *s++ = c;
796 c = cp_next();
798 *s = '\0';
799 return 1;
802 static struct cmd {
803 char *id;
804 void (*f)(char **args);
805 int (*args)(char **args, char *buf, int len);
806 } cmds[] = {
807 {TR_DIVBEG, tr_divbeg},
808 {TR_DIVEND, tr_divend},
809 {TR_EJECT, tr_eject},
810 {"ab", tr_ab, mkargs_eol},
811 {"ad", tr_ad},
812 {"af", tr_af},
813 {"am", tr_de, mkargs_reg1},
814 {"as", tr_as, mkargs_ds},
815 {"bd", tr_bd},
816 {"bp", tr_bp},
817 {"br", tr_br},
818 {"c2", tr_c2},
819 {"cc", tr_cc},
820 {"ochar", tr_ochar},
821 {"ce", tr_ce},
822 {"ch", tr_ch},
823 {"char", tr_char, mkargs_ds},
824 {"chop", tr_chop, mkargs_reg1},
825 {"cl", tr_cl},
826 {"cp", tr_cp},
827 {"cs", tr_cs},
828 {"da", tr_di},
829 {"de", tr_de, mkargs_reg1},
830 {"di", tr_di},
831 {"ds", tr_ds, mkargs_ds},
832 {"dt", tr_dt},
833 {"ec", tr_ec},
834 {"el", tr_el, mkargs_null},
835 {"em", tr_em},
836 {"eo", tr_eo},
837 {"ev", tr_ev},
838 {"ex", tr_ex},
839 {"fc", tr_fc},
840 {"fi", tr_fi},
841 {"fp", tr_fp},
842 {"fspecial", tr_fspecial},
843 {"ft", tr_ft},
844 {"hc", tr_hc},
845 {"hy", tr_hy},
846 {"hw", tr_hw},
847 {"ie", tr_if, mkargs_null},
848 {"if", tr_if, mkargs_null},
849 {"ig", tr_ig},
850 {"in", tr_in},
851 {"it", tr_it},
852 {"kn", tr_kn},
853 {"lc", tr_lc},
854 {"lf", tr_lf},
855 {"lg", tr_lg},
856 {"ll", tr_ll},
857 {"ls", tr_ls},
858 {"lt", tr_lt},
859 {"mc", tr_mc},
860 {"mk", tr_mk},
861 {"na", tr_na},
862 {"ne", tr_ne},
863 {"nf", tr_nf},
864 {"nh", tr_nh},
865 {"nm", tr_nm},
866 {"nn", tr_nn},
867 {"nr", tr_nr, mkargs_reg1},
868 {"ns", tr_ns},
869 {"nx", tr_nx},
870 {"os", tr_os},
871 {"pc", tr_pc},
872 {"pl", tr_pl},
873 {"pn", tr_pn},
874 {"po", tr_po},
875 {"ps", tr_ps},
876 {"rchar", tr_rchar, mkargs_ds},
877 {"rm", tr_rm},
878 {"rn", tr_rn},
879 {"rr", tr_rr},
880 {"rs", tr_rs},
881 {"rt", tr_rt},
882 {"so", tr_so},
883 {"sp", tr_sp},
884 {"ss", tr_ss},
885 {"sv", tr_sv},
886 {"sy", tr_sy, mkargs_eol},
887 {"ta", tr_ta},
888 {"tc", tr_tc},
889 {"ti", tr_ti},
890 {"tl", tr_tl, mkargs_null},
891 {"tm", tr_tm, mkargs_eol},
892 {"tr", tr_tr, mkargs_eol},
893 {"vs", tr_vs},
894 {"wh", tr_wh},
897 int tr_next(void)
899 int c = cp_next();
900 int nl = c == '\n';
901 char *args[NARGS + 3] = {NULL};
902 char cmd[RNLEN];
903 char buf[LNLEN];
904 struct cmd *req;
905 while (tr_nl && c >= 0 && (c == c_cc || c == c_c2)) {
906 nl = 1;
907 memset(args, 0, sizeof(args));
908 args[0] = cmd;
909 cmd[0] = c;
910 req = NULL;
911 arg_regname(cmd + 1, sizeof(cmd) - 1);
912 req = str_dget(map(cmd + 1));
913 if (req) {
914 if (req->args)
915 req->args(args + 1, buf, sizeof(buf));
916 else
917 mkargs_req(args + 1, buf, sizeof(buf));
918 req->f(args);
919 } else {
920 cp_wid(0);
921 mkargs(args + 1, buf, sizeof(buf));
922 cp_wid(1);
923 if (str_get(map(cmd + 1)))
924 in_push(str_get(map(cmd + 1)), args + 1);
926 c = cp_next();
927 nl = c == '\n';
929 tr_nl = c < 0 || nl;
930 return c;
933 void tr_init(void)
935 int i;
936 for (i = 0; i < LEN(cmds); i++)
937 str_dset(map(cmds[i].id), &cmds[i]);
940 void tr_first(void)
942 cp_back(tr_next());
943 tr_nl = 1;