font: unmap glyphs with .fmap
[neatroff.git] / tr.c
blob501e76bbb7ef60d82bd5c618ae9788a166f8aafe
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 tr_bm = -1; /* blank line macro */
10 char c_pc[GNLEN] = "%"; /* page number character */
11 int c_ec = '\\'; /* escape character */
12 int c_cc = '.'; /* control character */
13 int c_c2 = '\''; /* no-break control character */
15 /* skip everything until the end of line */
16 static void jmp_eol(void)
18 int c;
19 do {
20 c = cp_next();
21 } while (c >= 0 && c != '\n');
24 static void tr_vs(char **args)
26 int vs = args[1] ? eval_re(args[1], n_v, 'p') : n_v0;
27 n_v0 = n_v;
28 n_v = MAX(0, vs);
31 static void tr_ls(char **args)
33 int ls = args[1] ? eval_re(args[1], n_L, 0) : n_L0;
34 n_L0 = n_L;
35 n_L = MAX(1, ls);
38 static void tr_pl(char **args)
40 int n = eval_re(args[1] ? args[1] : "11i", n_p, 'v');
41 n_p = MAX(0, n);
44 static void tr_nr(char **args)
46 int id;
47 if (!args[2])
48 return;
49 id = map(args[1]);
50 num_set(id, eval_re(args[2], num_get(id), 'u'));
51 num_setinc(id, args[3] ? eval(args[3], 'u') : 0);
54 static void tr_rr(char **args)
56 int i;
57 for (i = 1; i <= NARGS; i++)
58 if (args[i])
59 num_del(map(args[i]));
62 static void tr_af(char **args)
64 if (args[2])
65 num_setfmt(map(args[1]), args[2]);
68 static void tr_ds(char **args)
70 str_set(map(args[1]), args[2] ? args[2] : "");
73 static void tr_as(char **args)
75 int reg;
76 char *s1, *s2, *s;
77 reg = map(args[1]);
78 s1 = str_get(reg) ? str_get(reg) : "";
79 s2 = args[2] ? args[2] : "";
80 s = xmalloc(strlen(s1) + strlen(s2) + 1);
81 strcpy(s, s1);
82 strcat(s, s2);
83 str_set(reg, s);
84 free(s);
87 static void tr_rm(char **args)
89 int i;
90 for (i = 1; i <= NARGS; i++)
91 if (args[i])
92 str_rm(map(args[i]));
95 static void tr_rn(char **args)
97 if (!args[2])
98 return;
99 str_rn(map(args[1]), map(args[2]));
102 static void tr_po(char **args)
104 int po = args[1] ? eval_re(args[1], n_o, 'm') : n_o0;
105 n_o0 = n_o;
106 n_o = MAX(0, po);
109 /* read a string argument of a macro */
110 static char *read_string(void)
112 struct sbuf sbuf;
113 int c;
114 int empty;
115 sbuf_init(&sbuf);
116 cp_copymode(1);
117 while ((c = cp_next()) == ' ')
119 empty = c <= 0 || c == '\n';
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 if (empty) {
131 sbuf_done(&sbuf);
132 return NULL;
134 return sbuf_out(&sbuf);
137 /* read a space separated macro argument; if two, read at most two characters */
138 static char *read_name(int two)
140 struct sbuf sbuf;
141 int c = cp_next();
142 int i = 0;
143 sbuf_init(&sbuf);
144 while (c == ' ' || c == '\t' || c == c_ni)
145 c = cp_next();
146 while (c > 0 && c != ' ' && c != '\t' && c != '\n' && (!two || i < 2)) {
147 if (c != c_ni) {
148 sbuf_add(&sbuf, c);
149 i++;
151 c = cp_next();
153 if (c >= 0)
154 cp_back(c);
155 return sbuf_out(&sbuf);
158 static void macrobody(struct sbuf *sbuf, char *end)
160 int first = 1;
161 int c;
162 char *req = NULL;
163 cp_back('\n');
164 cp_copymode(1);
165 while ((c = cp_next()) >= 0) {
166 if (sbuf && !first)
167 sbuf_add(sbuf, c);
168 first = 0;
169 if (c == '\n') {
170 if ((c = cp_next()) != c_cc) {
171 cp_back(c);
172 continue;
174 req = read_name(n_cp);
175 if (!strcmp(end, req)) {
176 in_push(end, NULL);
177 cp_back(c_cc);
178 break;
180 if (sbuf) {
181 sbuf_add(sbuf, c_cc);
182 sbuf_append(sbuf, req);
184 free(req);
185 req = NULL;
188 free(req);
189 cp_copymode(0);
192 static void tr_de(char **args)
194 struct sbuf sbuf;
195 int id;
196 if (!args[1])
197 return;
198 id = map(args[1]);
199 sbuf_init(&sbuf);
200 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
201 sbuf_append(&sbuf, str_get(id));
202 macrobody(&sbuf, args[2] ? args[2] : ".");
203 str_set(id, sbuf_buf(&sbuf));
204 sbuf_done(&sbuf);
207 static void tr_ig(char **args)
209 macrobody(NULL, args[1] ? args[1] : ".");
212 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
213 static int read_until(struct sbuf *sbuf, char *stop,
214 int (*next)(void), void (*back)(int))
216 char cs[GNLEN], cs2[GNLEN];
217 int c;
218 while ((c = next()) >= 0) {
219 if (c == c_ni)
220 continue;
221 back(c);
222 if (c == '\n')
223 return 1;
224 if (!stop && (c == ' ' || c == '\t'))
225 return 0;
226 charnext(cs, next, back);
227 if (stop && !strcmp(stop, cs))
228 return 0;
229 charnext_str(cs2, cs);
230 sbuf_append(sbuf, cs2);
232 return 1;
235 /* evaluate .if strcmp (i.e. 'str'str') */
236 static int if_strcmp(int (*next)(void), void (*back)(int))
238 char delim[GNLEN];
239 struct sbuf s1, s2;
240 int ret;
241 charnext(delim, next, back);
242 sbuf_init(&s1);
243 sbuf_init(&s2);
244 read_until(&s1, delim, next, back);
245 read_until(&s2, delim, next, back);
246 cp_reqbeg();
247 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
248 sbuf_done(&s1);
249 sbuf_done(&s2);
250 return ret;
253 /* evaluate .if condition letters */
254 static int if_cond(int (*next)(void), void (*back)(int))
256 switch (cp_next()) {
257 case 'o':
258 return n_pg % 2;
259 case 'e':
260 return !(n_pg % 2);
261 case 't':
262 return 1;
263 case 'n':
264 return 0;
266 return 0;
269 /* evaluate .if condition */
270 static int if_eval(int (*next)(void), void (*back)(int))
272 struct sbuf sbuf;
273 int ret;
274 sbuf_init(&sbuf);
275 read_until(&sbuf, NULL, next, back);
276 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
277 sbuf_done(&sbuf);
278 return ret;
281 static int eval_if(int (*next)(void), void (*back)(int))
283 int neg = 0;
284 int ret;
285 int c;
286 do {
287 c = next();
288 } while (c == ' ' || c == '\t');
289 if (c == '!') {
290 neg = 1;
291 c = next();
293 back(c);
294 if (strchr("oetn", c)) {
295 ret = if_cond(next, back);
296 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
297 ret = if_strcmp(next, back);
298 } else {
299 ret = if_eval(next, back);
301 return ret != neg;
304 static int ie_cond[NIES]; /* .ie condition stack */
305 static int ie_depth;
307 static void tr_if(char **args)
309 int c = eval_if(cp_next, cp_back);
310 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
311 if (ie_depth < NIES)
312 ie_cond[ie_depth++] = c;
313 cp_blk(!c);
316 static void tr_el(char **args)
318 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
321 static void tr_na(char **args)
323 n_na = 1;
326 static int adjmode(int c, int def)
328 switch (c) {
329 case 'l':
330 return AD_L;
331 case 'r':
332 return AD_R;
333 case 'c':
334 return AD_C;
335 case 'b':
336 case 'n':
337 return AD_B;
339 return def;
342 static void tr_ad(char **args)
344 char *s = args[1];
345 n_na = 0;
346 if (!s)
347 return;
348 if (isdigit(s[0]))
349 n_j = atoi(s) & 15;
350 else
351 n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j);
354 static void tr_tm(char **args)
356 fprintf(stderr, "%s\n", args[1]);
359 static void tr_so(char **args)
361 if (args[1])
362 in_so(args[1]);
365 static void tr_nx(char **args)
367 in_nx(args[1]);
370 static void tr_ex(char **args)
372 in_ex();
375 static void tr_sy(char **args)
377 system(args[1]);
380 static void tr_lt(char **args)
382 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
383 n_t0 = n_t0;
384 n_lt = MAX(0, lt);
387 static void tr_pc(char **args)
389 char *s = args[1];
390 if (!s || charread(&s, c_pc) < 0)
391 strcpy(c_pc, "");
394 static void tr_tl(char **args)
396 int c;
397 do {
398 c = cp_next();
399 } while (c >= 0 && (c == ' ' || c == '\t'));
400 cp_back(c);
401 ren_tl(cp_next, cp_back);
402 do {
403 c = cp_next();
404 } while (c >= 0 && c != '\n');
407 static void tr_ec(char **args)
409 c_ec = args[1] ? args[1][0] : '\\';
412 static void tr_cc(char **args)
414 c_cc = args[1] ? args[1][0] : '.';
417 static void tr_c2(char **args)
419 c_c2 = args[1] ? args[1][0] : '\'';
422 static void tr_eo(char **args)
424 c_ec = -1;
427 static void tr_hc(char **args)
429 char *s = args[1];
430 if (!s || charread(&s, c_hc) < 0)
431 strcpy(c_hc, "\\%");
434 /* sentence ending and their transparent characters */
435 static char eos_sent[NCHARS][GNLEN] = { ".", "?", "!", };
436 static int eos_sentcnt = 3;
437 static char eos_tran[NCHARS][GNLEN] = { "'", "\"", ")", "]", "*", };
438 static int eos_trancnt = 5;
440 static void tr_eos(char **args)
442 eos_sentcnt = 0;
443 eos_trancnt = 0;
444 if (args[1]) {
445 char *s = args[1];
446 while (s && charread(&s, eos_sent[eos_sentcnt]) >= 0)
447 if (eos_sentcnt < NCHARS - 1)
448 eos_sentcnt++;
450 if (args[2]) {
451 char *s = args[2];
452 while (s && charread(&s, eos_tran[eos_trancnt]) >= 0)
453 if (eos_trancnt < NCHARS - 1)
454 eos_trancnt++;
458 int c_eossent(char *s)
460 int i;
461 for (i = 0; i < eos_sentcnt; i++)
462 if (!strcmp(eos_sent[i], s))
463 return 1;
464 return 0;
467 int c_eostran(char *s)
469 int i;
470 for (i = 0; i < eos_trancnt; i++)
471 if (!strcmp(eos_tran[i], s))
472 return 1;
473 return 0;
476 /* hyphenation dashes and hyphenation inhibiting character */
477 static char hy_dash[NCHARS][GNLEN] = { "\\:", "-", "em", "en", "\\-", "--", "hy", };
478 static int hy_dashcnt = 7;
479 static char hy_stop[NCHARS][GNLEN] = { "\\%", };
480 static int hy_stopcnt = 1;
482 static void tr_nh(char **args)
484 n_hy = 0;
487 static void tr_hy(char **args)
489 n_hy = args[1] ? eval_re(args[1], n_hy, '\0') : 1;
492 static void tr_hlm(char **args)
494 n_hlm = args[1] ? eval_re(args[1], n_hlm, '\0') : 0;
497 static void tr_hycost(char **args)
499 n_hycost = args[1] ? eval_re(args[1], n_hycost, '\0') : 0;
500 n_hycost2 = args[2] ? eval_re(args[2], n_hycost2, '\0') : 0;
501 n_hycost3 = args[3] ? eval_re(args[3], n_hycost3, '\0') : 0;
504 static void tr_hydash(char **args)
506 hy_dashcnt = 0;
507 if (args[1]) {
508 char *s = args[1];
509 while (s && charread(&s, hy_dash[hy_dashcnt]) >= 0)
510 if (hy_dashcnt < NCHARS - 1)
511 hy_dashcnt++;
515 static void tr_hystop(char **args)
517 hy_stopcnt = 0;
518 if (args[1]) {
519 char *s = args[1];
520 while (s && charread(&s, hy_stop[hy_stopcnt]) >= 0)
521 if (hy_stopcnt < NCHARS - 1)
522 hy_stopcnt++;
526 int c_hydash(char *s)
528 int i;
529 for (i = 0; i < hy_dashcnt; i++)
530 if (!strcmp(hy_dash[i], s))
531 return 1;
532 return 0;
535 int c_hystop(char *s)
537 int i;
538 for (i = 0; i < hy_stopcnt; i++)
539 if (!strcmp(hy_stop[i], s))
540 return 1;
541 return 0;
544 int c_hymark(char *s)
546 return !strcmp(c_bp, s) || !strcmp(c_hc, s);
549 static void tr_pmll(char **args)
551 n_pmll = args[1] ? eval_re(args[1], n_pmll, '\0') : 0;
552 n_pmllcost = args[2] ? eval_re(args[2], n_pmllcost, '\0') : 100;
555 static void tr_lg(char **args)
557 if (args[1])
558 n_lg = eval(args[1], '\0');
561 static void tr_kn(char **args)
563 if (args[1])
564 n_kn = eval(args[1], '\0');
567 static void tr_cp(char **args)
569 if (args[1])
570 n_cp = atoi(args[1]);
573 static void tr_ss(char **args)
575 if (args[1]) {
576 n_ss = eval_re(args[1], n_ss, 0);
577 n_sss = args[2] ? eval_re(args[2], n_sss, 0) : n_ss;
581 static void tr_ssh(char **args)
583 n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
586 static void tr_cs(char **args)
588 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
589 if (fn)
590 font_setcs(fn, args[2] ? eval(args[2], 0) : 0,
591 args[3] ? eval(args[3], 0) : 0);
594 static void tr_fzoom(char **args)
596 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
597 if (fn)
598 font_setzoom(fn, args[2] ? eval(args[2], 0) : 0);
601 static void tr_tkf(char **args)
603 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
604 if (fn && args[5])
605 font_track(fn, eval(args[2], 0), eval(args[3], 0),
606 eval(args[4], 0), eval(args[5], 0));
609 static void tr_ff(char **args)
611 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
612 int i;
613 for (i = 2; i <= NARGS; i++)
614 if (fn && args[i] && args[i][0] && args[i][1])
615 font_feat(fn, args[i] + 1, args[i][0] == '+');
618 static void tr_ffsc(char **args)
620 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
621 if (fn && args[2])
622 font_scrp(fn, args[2] ? args[2] : NULL);
625 static void tr_nm(char **args)
627 if (!args[1]) {
628 n_nm = 0;
629 return;
631 n_nm = 1;
632 n_ln = eval_re(args[1], n_ln, 0);
633 n_ln = MAX(0, n_ln);
634 if (args[2] && isdigit(args[2][0]))
635 n_nM = MAX(1, eval(args[2], 0));
636 if (args[3] && isdigit(args[3][0]))
637 n_nS = MAX(0, eval(args[3], 0));
638 if (args[4] && isdigit(args[4][0]))
639 n_nI = MAX(0, eval(args[4], 0));
642 static void tr_nn(char **args)
644 n_nn = args[1] ? eval(args[1], 0) : 1;
647 static void tr_bd(char **args)
649 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
650 if (!args[1] || !strcmp("S", args[1]))
651 return;
652 if (fn)
653 font_setbd(fn, args[2] ? eval(args[2], 'u') : 0);
656 static void tr_it(char **args)
658 if (args[2]) {
659 n_it = map(args[2]);
660 n_itn = eval(args[1], 0);
661 } else {
662 n_it = 0;
666 static void tr_mc(char **args)
668 char *s = args[1];
669 if (s && charread(&s, c_mc) >= 0) {
670 n_mc = 1;
671 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
672 } else {
673 n_mc = 0;
677 static void tr_tc(char **args)
679 char *s = args[1];
680 if (!s || charread(&s, c_tc) < 0)
681 strcpy(c_tc, "");
684 static void tr_lc(char **args)
686 char *s = args[1];
687 if (!s || charread(&s, c_lc) < 0)
688 strcpy(c_lc, "");
691 static void tr_lf(char **args)
693 if (args[1])
694 in_lf(args[2], eval(args[1], 0));
697 static void tr_chop(char **args)
699 struct sbuf sbuf;
700 int id;
701 id = map(args[1]);
702 if (str_get(id)) {
703 sbuf_init(&sbuf);
704 sbuf_append(&sbuf, str_get(id));
705 if (!sbuf_empty(&sbuf)) {
706 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
707 str_set(id, sbuf_buf(&sbuf));
709 sbuf_done(&sbuf);
713 /* character translation (.tr) */
714 static struct dict *cmap; /* character mapping */
715 static char cmap_src[NCMAPS][GNLEN]; /* source character */
716 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
717 static int cmap_n; /* number of translated character */
719 void cmap_add(char *c1, char *c2)
721 int i = dict_get(cmap, c1);
722 if (i >= 0) {
723 strcpy(cmap_dst[i], c2);
724 } else if (cmap_n < NCMAPS) {
725 strcpy(cmap_src[cmap_n], c1);
726 strcpy(cmap_dst[cmap_n], c2);
727 dict_put(cmap, cmap_src[cmap_n], cmap_n);
728 cmap_n++;
732 char *cmap_map(char *c)
734 int i = dict_get(cmap, c);
735 return i >= 0 ? cmap_dst[i] : c;
738 static void tr_tr(char **args)
740 char *s = args[1];
741 char c1[GNLEN], c2[GNLEN];
742 while (s && charread(&s, c1) >= 0) {
743 if (charread(&s, c2) < 0)
744 strcpy(c2, " ");
745 cmap_add(c1, c2);
749 /* character definition (.char) */
750 static char cdef_src[NCDEFS][GNLEN]; /* source character */
751 static char *cdef_dst[NCDEFS]; /* character definition */
752 static int cdef_fn[NCDEFS]; /* owning font */
753 static int cdef_n; /* number of defined characters */
754 static int cdef_expanding; /* inside cdef_expand() call */
756 static int cdef_find(char *c, int fn)
758 int i;
759 for (i = 0; i < cdef_n; i++)
760 if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
761 return i;
762 return -1;
765 /* return the definition of the given character */
766 char *cdef_map(char *c, int fn)
768 int i = cdef_find(c, fn);
769 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
772 int cdef_expand(struct wb *wb, char *s, int fn)
774 char *d = cdef_map(s, fn);
775 if (!d)
776 return 1;
777 cdef_expanding = 1;
778 ren_parse(wb, d);
779 cdef_expanding = 0;
780 return 0;
783 static void cdef_remove(char *fn, char *cs)
785 char c[GNLEN];
786 int i;
787 int fp = fn ? dev_pos(fn) : -1;
788 if (!cs || charread(&cs, c) < 0)
789 return;
790 for (i = 0; i < cdef_n; i++) {
791 if (!strcmp(cdef_src[i], c)) {
792 if (!fn || (fp > 0 && cdef_fn[i] == fp)) {
793 free(cdef_dst[i]);
794 cdef_dst[i] = NULL;
795 cdef_src[i][0] = '\0';
801 static void cdef_add(char *fn, char *cs, char *def)
803 char c[GNLEN];
804 int i;
805 if (!def || charread(&cs, c) < 0)
806 return;
807 i = cdef_find(c, fn ? dev_pos(fn) : -1);
808 if (i < 0) {
809 for (i = 0; i < cdef_n; i++)
810 if (!cdef_dst[i])
811 break;
812 if (i == cdef_n && cdef_n < NCDEFS)
813 cdef_n++;
815 if (i >= 0 && i < cdef_n) {
816 snprintf(cdef_src[i], sizeof(cdef_src[i]), "%s", c);
817 cdef_dst[i] = xmalloc(strlen(def) + 1);
818 strcpy(cdef_dst[i], def);
819 cdef_fn[i] = fn ? dev_pos(fn) : 0;
823 static void tr_rchar(char **args)
825 int i;
826 for (i = 1; i <= NARGS; i++)
827 if (args[i])
828 cdef_remove(NULL, args[i]);
831 static void tr_char(char **args)
833 if (args[2])
834 cdef_add(NULL, args[1], args[2]);
835 else
836 cdef_remove(NULL, args[1]);
839 static void tr_ochar(char **args)
841 if (args[3])
842 cdef_add(args[1], args[2], args[3]);
843 else
844 cdef_remove(args[1], args[2]);
847 static void tr_fmap(char **args)
849 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
850 if (fn && args[2])
851 font_map(fn, args[2], args[3]);
854 static void tr_blm(char **args)
856 tr_bm = args[1] ? map(args[1]) : -1;
859 /* read a macro argument */
860 static int tr_arg(struct sbuf *sbuf, int brk, int (*next)(void), void (*back)(int))
862 int quoted = 0;
863 int c;
864 c = next();
865 while (c == ' ')
866 c = next();
867 if (c == '\n' || c == brk)
868 back(c);
869 if (c < 0 || c == '\n' || c == brk)
870 return 1;
871 if (c == '"') {
872 quoted = 1;
873 c = next();
875 while (c >= 0 && c != '\n' && (quoted || c != brk)) {
876 if (!quoted && c == ' ')
877 break;
878 if (quoted && c == '"') {
879 c = next();
880 if (c != '"')
881 break;
883 if (c == c_ec) {
884 sbuf_add(sbuf, c);
885 c = next();
887 sbuf_add(sbuf, c);
888 c = next();
890 sbuf_add(sbuf, 0);
891 if (c >= 0)
892 back(c);
893 return 0;
896 /* read macro arguments; free the returned pointer when done */
897 char *tr_args(char **args, int brk, int (*next)(void), void (*back)(int))
899 struct sbuf sbuf;
900 char *s, *e;
901 int n = 0;
902 sbuf_init(&sbuf);
903 while (!tr_arg(&sbuf, brk, next, back))
905 s = sbuf_buf(&sbuf);
906 e = s + sbuf_len(&sbuf);
907 while (n < NARGS && s && s < e) {
908 args[n++] = s;
909 if ((s = memchr(s, '\0', e - s)))
910 s++;
912 return sbuf_out(&sbuf);
915 /* split the arguments in sbuf */
916 static int tr_argschop(struct sbuf *sbuf, char **args)
918 char *s = sbuf_buf(sbuf);
919 char *e = s + sbuf_len(sbuf);
920 int n = 0;
921 while (n < NARGS && s && s < e) {
922 args[n++] = s;
923 if ((s = memchr(s, '\0', e - s)))
924 s++;
926 return n;
929 /* read request arguments; trims tabs too */
930 static void mkargs_req(struct sbuf *sbuf)
932 int n = 0;
933 int c;
934 c = cp_next();
935 while (n < NARGS) {
936 int ok = 0;
937 while (c == ' ' || c == '\t')
938 c = cp_next();
939 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
940 if (c != c_ni)
941 sbuf_add(sbuf, c);
942 c = cp_next();
943 ok = 1;
945 if (ok) {
946 n++;
947 sbuf_add(sbuf, 0);
949 if (c == '\n')
950 cp_back(c);
951 if (c < 0 || c == '\n')
952 break;
954 jmp_eol();
957 /* read arguments for .ds and .char */
958 static void mkargs_ds(struct sbuf *sbuf)
960 char *s = read_name(n_cp);
961 sbuf_append(sbuf, s);
962 sbuf_add(sbuf, 0);
963 free(s);
964 s = read_string();
965 if (s) {
966 sbuf_append(sbuf, s);
967 sbuf_add(sbuf, 0);
968 free(s);
970 jmp_eol();
973 /* read arguments for .ochar */
974 static void mkargs_ochar(struct sbuf *sbuf)
976 char *s = read_name(0);
977 sbuf_append(sbuf, s);
978 sbuf_add(sbuf, 0);
979 free(s);
980 mkargs_ds(sbuf);
983 /* read arguments for .nr */
984 static void mkargs_reg1(struct sbuf *sbuf)
986 char *s = read_name(n_cp);
987 sbuf_append(sbuf, s);
988 sbuf_add(sbuf, 0);
989 free(s);
990 mkargs_req(sbuf);
993 /* do not read any arguments; for .if, .ie and .el */
994 static void mkargs_null(struct sbuf *sbuf)
998 /* read the whole line for .tm */
999 static void mkargs_eol(struct sbuf *sbuf)
1001 int c;
1002 cp_copymode(1);
1003 c = cp_next();
1004 while (c == ' ')
1005 c = cp_next();
1006 while (c >= 0 && c != '\n') {
1007 if (c != c_ni)
1008 sbuf_add(sbuf, c);
1009 c = cp_next();
1011 cp_copymode(0);
1014 static struct cmd {
1015 char *id;
1016 void (*f)(char **args);
1017 void (*args)(struct sbuf *sbuf);
1018 } cmds[] = {
1019 {TR_DIVBEG, tr_divbeg},
1020 {TR_DIVEND, tr_divend},
1021 {TR_DIVVS, tr_divvs},
1022 {TR_POPREN, tr_popren},
1023 {"ab", tr_ab, mkargs_eol},
1024 {"ad", tr_ad},
1025 {"af", tr_af},
1026 {"am", tr_de, mkargs_reg1},
1027 {"as", tr_as, mkargs_ds},
1028 {"bd", tr_bd},
1029 {"blm", tr_blm},
1030 {"bp", tr_bp},
1031 {"br", tr_br},
1032 {"c2", tr_c2},
1033 {"cc", tr_cc},
1034 {"ochar", tr_ochar, mkargs_ochar},
1035 {"ce", tr_ce},
1036 {"ch", tr_ch},
1037 {"char", tr_char, mkargs_ds},
1038 {"chop", tr_chop, mkargs_reg1},
1039 {"cl", tr_cl},
1040 {"cp", tr_cp},
1041 {"cs", tr_cs},
1042 {"da", tr_di},
1043 {"de", tr_de, mkargs_reg1},
1044 {"di", tr_di},
1045 {"ds", tr_ds, mkargs_ds},
1046 {"dt", tr_dt},
1047 {"ec", tr_ec},
1048 {"el", tr_el, mkargs_null},
1049 {"em", tr_em},
1050 {"eo", tr_eo},
1051 {"eos", tr_eos},
1052 {"ev", tr_ev},
1053 {"ex", tr_ex},
1054 {"fc", tr_fc},
1055 {"ff", tr_ff},
1056 {"fi", tr_fi},
1057 {"fl", tr_br},
1058 {"fmap", tr_fmap},
1059 {"fp", tr_fp},
1060 {"ffsc", tr_ffsc},
1061 {"fspecial", tr_fspecial},
1062 {"ft", tr_ft},
1063 {"fzoom", tr_fzoom},
1064 {"hc", tr_hc},
1065 {"hcode", tr_hcode},
1066 {"hlm", tr_hlm},
1067 {"hpf", tr_hpf},
1068 {"hpfa", tr_hpfa},
1069 {"hy", tr_hy},
1070 {"hycost", tr_hycost},
1071 {"hydash", tr_hydash},
1072 {"hystop", tr_hystop},
1073 {"hw", tr_hw},
1074 {"ie", tr_if, mkargs_null},
1075 {"if", tr_if, mkargs_null},
1076 {"ig", tr_ig},
1077 {"in", tr_in},
1078 {"it", tr_it},
1079 {"kn", tr_kn},
1080 {"lc", tr_lc},
1081 {"lf", tr_lf},
1082 {"lg", tr_lg},
1083 {"ll", tr_ll},
1084 {"ls", tr_ls},
1085 {"lt", tr_lt},
1086 {"mc", tr_mc},
1087 {"mk", tr_mk},
1088 {"na", tr_na},
1089 {"ne", tr_ne},
1090 {"nf", tr_nf},
1091 {"nh", tr_nh},
1092 {"nm", tr_nm},
1093 {"nn", tr_nn},
1094 {"nr", tr_nr, mkargs_reg1},
1095 {"ns", tr_ns},
1096 {"nx", tr_nx},
1097 {"os", tr_os},
1098 {"pc", tr_pc},
1099 {"pl", tr_pl},
1100 {"pmll", tr_pmll},
1101 {"pn", tr_pn},
1102 {"po", tr_po},
1103 {"ps", tr_ps},
1104 {"rchar", tr_rchar},
1105 {"rm", tr_rm},
1106 {"rn", tr_rn},
1107 {"rr", tr_rr},
1108 {"rs", tr_rs},
1109 {"rt", tr_rt},
1110 {"so", tr_so},
1111 {"sp", tr_sp},
1112 {"ss", tr_ss},
1113 {"ssh", tr_ssh},
1114 {"sv", tr_sv},
1115 {"sy", tr_sy, mkargs_eol},
1116 {"ta", tr_ta},
1117 {"tc", tr_tc},
1118 {"ti", tr_ti},
1119 {"tkf", tr_tkf},
1120 {"tl", tr_tl, mkargs_null},
1121 {"tm", tr_tm, mkargs_eol},
1122 {"tr", tr_tr, mkargs_eol},
1123 {"vs", tr_vs},
1124 {"wh", tr_wh},
1127 static char *dotted(char *name, int dot)
1129 char *out = xmalloc(strlen(name) + 2);
1130 out[0] = dot;
1131 strcpy(out + 1, name);
1132 return out;
1135 /* read the next troff request; return zero if a request was executed. */
1136 int tr_nextreq(void)
1138 char *args[NARGS + 3] = {NULL};
1139 char *cmd;
1140 struct cmd *req;
1141 struct sbuf sbuf;
1142 int c;
1143 if (!tr_nl)
1144 return 1;
1145 c = cp_next();
1146 if (c == c_ec) {
1147 int c2 = cp_next();
1148 if (c2 == '!') {
1149 args[0] = "\\!";
1150 sbuf_init(&sbuf);
1151 cp_copymode(1);
1152 mkargs_eol(&sbuf);
1153 cp_copymode(0);
1154 tr_argschop(&sbuf, args + 1);
1155 tr_transparent(args);
1156 sbuf_done(&sbuf);
1157 return 0;
1159 cp_back(c2);
1161 if (c < 0 || (c != c_cc && c != c_c2 && (c != '\n' || tr_bm < 0))) {
1162 cp_back(c);
1163 return 1;
1165 cp_reqbeg();
1166 if (c != '\n') {
1167 cmd = read_name(n_cp);
1168 } else { /* blank line macro */
1169 cmd = malloc(strlen(map_name(tr_bm)) + 1);
1170 strcpy(cmd, map_name(tr_bm));
1171 cp_back(c);
1173 args[0] = dotted(cmd, c);
1174 req = str_dget(map(cmd));
1175 if (req) {
1176 sbuf_init(&sbuf);
1177 if (req->args)
1178 req->args(&sbuf);
1179 else
1180 mkargs_req(&sbuf);
1181 tr_argschop(&sbuf, args + 1);
1182 req->f(args);
1183 sbuf_done(&sbuf);
1184 } else {
1185 char *buf;
1186 cp_copymode(1);
1187 buf = tr_args(args + 1, -1, cp_next, cp_back);
1188 jmp_eol();
1189 cp_copymode(0);
1190 if (str_get(map(cmd)))
1191 in_push(str_get(map(cmd)), args + 1);
1192 free(buf);
1194 free(args[0]);
1195 free(cmd);
1196 return 0;
1199 int tr_next(void)
1201 int c;
1202 while (!tr_nextreq())
1204 c = cp_next();
1205 tr_nl = c == '\n' || c < 0;
1206 return c;
1209 void tr_init(void)
1211 int i;
1212 for (i = 0; i < LEN(cmds); i++)
1213 str_dset(map(cmds[i].id), &cmds[i]);
1214 cmap = dict_make(-1, 0, 0);
1217 void tr_done(void)
1219 int i;
1220 for (i = 0; i < cdef_n; i++)
1221 free(cdef_dst[i]);
1222 dict_free(cmap);