tr: removing character definitions with .char and .ochar
[neatroff.git] / tr.c
blobb6d9b272cf90e3056bf2a5a74907563096c403d4
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 if (args[2])
71 str_set(map(args[1]), args[2]);
74 static void tr_as(char **args)
76 int reg;
77 char *s1, *s2, *s;
78 if (!args[2])
79 return;
80 reg = map(args[1]);
81 s1 = str_get(reg) ? str_get(reg) : "";
82 s2 = args[2];
83 s = xmalloc(strlen(s1) + strlen(s2) + 1);
84 strcpy(s, s1);
85 strcat(s, s2);
86 str_set(reg, s);
87 free(s);
90 static void tr_rm(char **args)
92 int i;
93 for (i = 1; i <= NARGS; i++)
94 if (args[i])
95 str_rm(map(args[i]));
98 static void tr_rn(char **args)
100 if (!args[2])
101 return;
102 str_rn(map(args[1]), map(args[2]));
105 static void tr_po(char **args)
107 int po = args[1] ? eval_re(args[1], n_o, 'm') : n_o0;
108 n_o0 = n_o;
109 n_o = MAX(0, po);
112 /* read a string argument of a macro */
113 static char *read_string(void)
115 struct sbuf sbuf;
116 int c;
117 sbuf_init(&sbuf);
118 cp_copymode(1);
119 while ((c = cp_next()) == ' ')
121 if (c == '"')
122 c = cp_next();
123 while (c > 0 && c != '\n') {
124 if (c != c_ni)
125 sbuf_add(&sbuf, c);
126 c = cp_next();
128 if (c >= 0)
129 cp_back(c);
130 cp_copymode(0);
131 return sbuf_out(&sbuf);
134 /* read a register name argument; if two, read at most two characters */
135 static char *read_name(int two)
137 struct sbuf sbuf;
138 int c = cp_next();
139 int i = 0;
140 sbuf_init(&sbuf);
141 while (c == ' ' || c == '\t' || c == c_ni)
142 c = cp_next();
143 while (c > 0 && c != ' ' && c != '\t' && c != '\n' && (!two || i < 2)) {
144 if (c != c_ni) {
145 sbuf_add(&sbuf, c);
146 i++;
148 c = cp_next();
150 if (c >= 0)
151 cp_back(c);
152 return sbuf_out(&sbuf);
156 static void macrobody(struct sbuf *sbuf, char *end)
158 int first = 1;
159 int c;
160 char *req = NULL;
161 cp_back('\n');
162 cp_copymode(1);
163 while ((c = cp_next()) >= 0) {
164 if (sbuf && !first)
165 sbuf_add(sbuf, c);
166 first = 0;
167 if (c == '\n') {
168 if ((c = cp_next()) != c_cc) {
169 cp_back(c);
170 continue;
172 req = read_name(n_cp);
173 if (!strcmp(end, req)) {
174 in_push(end, NULL);
175 cp_back(c_cc);
176 break;
178 if (sbuf) {
179 sbuf_add(sbuf, c_cc);
180 sbuf_append(sbuf, req);
182 free(req);
183 req = NULL;
186 free(req);
187 cp_copymode(0);
190 static void tr_de(char **args)
192 struct sbuf sbuf;
193 int id;
194 if (!args[1])
195 return;
196 id = map(args[1]);
197 sbuf_init(&sbuf);
198 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
199 sbuf_append(&sbuf, str_get(id));
200 macrobody(&sbuf, args[2] ? args[2] : ".");
201 str_set(id, sbuf_buf(&sbuf));
202 sbuf_done(&sbuf);
205 static void tr_ig(char **args)
207 macrobody(NULL, args[1] ? args[1] : ".");
210 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
211 static int read_until(struct sbuf *sbuf, char *stop,
212 int (*next)(void), void (*back)(int))
214 char cs[GNLEN], cs2[GNLEN];
215 int c;
216 while ((c = next()) >= 0) {
217 if (c == c_ni)
218 continue;
219 back(c);
220 if (c == '\n')
221 return 1;
222 if (!stop && (c == ' ' || c == '\t'))
223 return 0;
224 charnext(cs, next, back);
225 if (stop && !strcmp(stop, cs))
226 return 0;
227 charnext_str(cs2, cs);
228 sbuf_append(sbuf, cs2);
230 return 1;
233 /* evaluate .if strcmp (i.e. 'str'str') */
234 static int if_strcmp(int (*next)(void), void (*back)(int))
236 char delim[GNLEN];
237 struct sbuf s1, s2;
238 int ret;
239 charnext(delim, next, back);
240 sbuf_init(&s1);
241 sbuf_init(&s2);
242 read_until(&s1, delim, next, back);
243 read_until(&s2, delim, next, back);
244 cp_reqbeg();
245 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
246 sbuf_done(&s1);
247 sbuf_done(&s2);
248 return ret;
251 /* evaluate .if condition letters */
252 static int if_cond(int (*next)(void), void (*back)(int))
254 switch (cp_next()) {
255 case 'o':
256 return n_pg % 2;
257 case 'e':
258 return !(n_pg % 2);
259 case 't':
260 return 1;
261 case 'n':
262 return 0;
264 return 0;
267 /* evaluate .if condition */
268 static int if_eval(int (*next)(void), void (*back)(int))
270 struct sbuf sbuf;
271 int ret;
272 sbuf_init(&sbuf);
273 read_until(&sbuf, NULL, next, back);
274 ret = eval(sbuf_buf(&sbuf), '\0') > 0;
275 sbuf_done(&sbuf);
276 return ret;
279 static int eval_if(int (*next)(void), void (*back)(int))
281 int neg = 0;
282 int ret;
283 int c;
284 do {
285 c = next();
286 } while (c == ' ' || c == '\t');
287 if (c == '!') {
288 neg = 1;
289 c = next();
291 back(c);
292 if (strchr("oetn", c)) {
293 ret = if_cond(next, back);
294 } else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
295 ret = if_strcmp(next, back);
296 } else {
297 ret = if_eval(next, back);
299 return ret != neg;
302 static int ie_cond[NIES]; /* .ie condition stack */
303 static int ie_depth;
305 static void tr_if(char **args)
307 int c = eval_if(cp_next, cp_back);
308 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
309 if (ie_depth < NIES)
310 ie_cond[ie_depth++] = c;
311 cp_blk(!c);
314 static void tr_el(char **args)
316 cp_blk(ie_depth > 0 ? ie_cond[--ie_depth] : 1);
319 static void tr_na(char **args)
321 n_na = 1;
324 static int adjmode(int c, int def)
326 switch (c) {
327 case 'l':
328 return AD_L;
329 case 'r':
330 return AD_R;
331 case 'c':
332 return AD_C;
333 case 'b':
334 case 'n':
335 return AD_B;
337 return def;
340 static void tr_ad(char **args)
342 char *s = args[1];
343 n_na = 0;
344 if (!s)
345 return;
346 if (isdigit(s[0]))
347 n_j = atoi(s) & 15;
348 else
349 n_j = s[0] == 'p' ? AD_P | adjmode(s[1], AD_B) : adjmode(s[0], n_j);
352 static void tr_tm(char **args)
354 fprintf(stderr, "%s\n", args[1]);
357 static void tr_so(char **args)
359 if (args[1])
360 in_so(args[1]);
363 static void tr_nx(char **args)
365 in_nx(args[1]);
368 static void tr_ex(char **args)
370 in_ex();
373 static void tr_sy(char **args)
375 system(args[1]);
378 static void tr_lt(char **args)
380 int lt = args[1] ? eval_re(args[1], n_lt, 'm') : n_t0;
381 n_t0 = n_t0;
382 n_lt = MAX(0, lt);
385 static void tr_pc(char **args)
387 char *s = args[1];
388 if (!s || charread(&s, c_pc) < 0)
389 strcpy(c_pc, "");
392 static void tr_tl(char **args)
394 int c;
395 do {
396 c = cp_next();
397 } while (c >= 0 && (c == ' ' || c == '\t'));
398 cp_back(c);
399 ren_tl(cp_next, cp_back);
400 do {
401 c = cp_next();
402 } while (c >= 0 && c != '\n');
405 static void tr_ec(char **args)
407 c_ec = args[1] ? args[1][0] : '\\';
410 static void tr_cc(char **args)
412 c_cc = args[1] ? args[1][0] : '.';
415 static void tr_c2(char **args)
417 c_c2 = args[1] ? args[1][0] : '\'';
420 static void tr_eo(char **args)
422 c_ec = -1;
425 static void tr_hc(char **args)
427 char *s = args[1];
428 if (!s || charread(&s, c_hc) < 0)
429 strcpy(c_hc, "\\%");
432 /* sentence ending and their transparent characters */
433 static char eos_sent[NCHARS][GNLEN] = { ".", "?", "!", };
434 static int eos_sentcnt = 3;
435 static char eos_tran[NCHARS][GNLEN] = { "'", "\"", ")", "]", "*", };
436 static int eos_trancnt = 5;
438 static void tr_eos(char **args)
440 eos_sentcnt = 0;
441 eos_trancnt = 0;
442 if (args[1]) {
443 char *s = args[1];
444 while (s && charread(&s, eos_sent[eos_sentcnt]) >= 0)
445 if (eos_sentcnt < NCHARS - 1)
446 eos_sentcnt++;
448 if (args[2]) {
449 char *s = args[2];
450 while (s && charread(&s, eos_tran[eos_trancnt]) >= 0)
451 if (eos_trancnt < NCHARS - 1)
452 eos_trancnt++;
456 int c_eossent(char *s)
458 int i;
459 for (i = 0; i < eos_sentcnt; i++)
460 if (!strcmp(eos_sent[i], s))
461 return 1;
462 return 0;
465 int c_eostran(char *s)
467 int i;
468 for (i = 0; i < eos_trancnt; i++)
469 if (!strcmp(eos_tran[i], s))
470 return 1;
471 return 0;
474 /* hyphenation dashes and hyphenation inhibiting character */
475 static char hy_dash[NCHARS][GNLEN] = { "\\:", "-", "em", "en", "\\-", "--", "hy", };
476 static int hy_dashcnt = 7;
477 static char hy_stop[NCHARS][GNLEN] = { "\\%", };
478 static int hy_stopcnt = 1;
480 static void tr_nh(char **args)
482 n_hy = 0;
485 static void tr_hy(char **args)
487 n_hy = args[1] ? eval_re(args[1], n_hy, '\0') : 1;
490 static void tr_hlm(char **args)
492 n_hlm = args[1] ? eval_re(args[1], n_hlm, '\0') : 0;
495 static void tr_hycost(char **args)
497 n_hycost = args[1] ? eval_re(args[1], n_hycost, '\0') : 0;
498 n_hycost2 = args[2] ? eval_re(args[2], n_hycost2, '\0') : 0;
499 n_hycost3 = args[3] ? eval_re(args[3], n_hycost3, '\0') : 0;
502 static void tr_hydash(char **args)
504 hy_dashcnt = 0;
505 if (args[1]) {
506 char *s = args[1];
507 while (s && charread(&s, hy_dash[hy_dashcnt]) >= 0)
508 if (hy_dashcnt < NCHARS - 1)
509 hy_dashcnt++;
513 static void tr_hystop(char **args)
515 hy_stopcnt = 0;
516 if (args[1]) {
517 char *s = args[1];
518 while (s && charread(&s, hy_stop[hy_stopcnt]) >= 0)
519 if (hy_stopcnt < NCHARS - 1)
520 hy_stopcnt++;
524 int c_hydash(char *s)
526 int i;
527 for (i = 0; i < hy_dashcnt; i++)
528 if (!strcmp(hy_dash[i], s))
529 return 1;
530 return 0;
533 int c_hystop(char *s)
535 int i;
536 for (i = 0; i < hy_stopcnt; i++)
537 if (!strcmp(hy_stop[i], s))
538 return 1;
539 return 0;
542 int c_hymark(char *s)
544 return !strcmp(c_bp, s) || !strcmp(c_hc, s);
547 static void tr_pmll(char **args)
549 n_pmll = args[1] ? eval_re(args[1], n_pmll, '\0') : 0;
550 n_pmllcost = args[2] ? eval_re(args[2], n_pmllcost, '\0') : 100;
553 static void tr_lg(char **args)
555 if (args[1])
556 n_lg = eval(args[1], '\0');
559 static void tr_kn(char **args)
561 if (args[1])
562 n_kn = eval(args[1], '\0');
565 static void tr_cp(char **args)
567 if (args[1])
568 n_cp = atoi(args[1]);
571 static void tr_ss(char **args)
573 if (args[1]) {
574 n_ss = eval_re(args[1], n_ss, 0);
575 n_sss = args[2] ? eval_re(args[2], n_sss, 0) : n_ss;
579 static void tr_ssh(char **args)
581 n_ssh = args[1] ? eval_re(args[1], n_ssh, 0) : 0;
584 static void tr_cs(char **args)
586 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
587 if (fn)
588 font_setcs(fn, args[2] ? eval(args[2], 0) : 0,
589 args[3] ? eval(args[3], 0) : 0);
592 static void tr_fzoom(char **args)
594 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
595 if (fn)
596 font_setzoom(fn, args[2] ? eval(args[2], 0) : 0);
599 static void tr_tkf(char **args)
601 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
602 if (fn && args[5])
603 font_track(fn, eval(args[2], 0), eval(args[3], 0),
604 eval(args[4], 0), eval(args[5], 0));
607 static void tr_ff(char **args)
609 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
610 int i;
611 for (i = 2; i <= NARGS; i++)
612 if (fn && args[i] && args[i][0] && args[i][1])
613 font_feat(fn, args[i] + 1, args[i][0] == '+');
616 static void tr_ffsc(char **args)
618 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
619 if (fn && args[2])
620 font_scrp(fn, args[2] ? args[2] : NULL);
623 static void tr_nm(char **args)
625 if (!args[1]) {
626 n_nm = 0;
627 return;
629 n_nm = 1;
630 n_ln = eval_re(args[1], n_ln, 0);
631 n_ln = MAX(0, n_ln);
632 if (args[2] && isdigit(args[2][0]))
633 n_nM = MAX(1, eval(args[2], 0));
634 if (args[3] && isdigit(args[3][0]))
635 n_nS = MAX(0, eval(args[3], 0));
636 if (args[4] && isdigit(args[4][0]))
637 n_nI = MAX(0, eval(args[4], 0));
640 static void tr_nn(char **args)
642 n_nn = args[1] ? eval(args[1], 0) : 1;
645 static void tr_bd(char **args)
647 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
648 if (!args[1] || !strcmp("S", args[1]))
649 return;
650 if (fn)
651 font_setbd(fn, args[2] ? eval(args[2], 'u') : 0);
654 static void tr_it(char **args)
656 if (args[2]) {
657 n_it = map(args[2]);
658 n_itn = eval(args[1], 0);
659 } else {
660 n_it = 0;
664 static void tr_mc(char **args)
666 char *s = args[1];
667 if (s && charread(&s, c_mc) >= 0) {
668 n_mc = 1;
669 n_mcn = args[2] ? eval(args[2], 'm') : SC_EM;
670 } else {
671 n_mc = 0;
675 static void tr_tc(char **args)
677 char *s = args[1];
678 if (!s || charread(&s, c_tc) < 0)
679 strcpy(c_tc, "");
682 static void tr_lc(char **args)
684 char *s = args[1];
685 if (!s || charread(&s, c_lc) < 0)
686 strcpy(c_lc, "");
689 static void tr_lf(char **args)
691 if (args[1])
692 in_lf(args[2], eval(args[1], 0));
695 static void tr_chop(char **args)
697 struct sbuf sbuf;
698 int id;
699 id = map(args[1]);
700 if (str_get(id)) {
701 sbuf_init(&sbuf);
702 sbuf_append(&sbuf, str_get(id));
703 if (!sbuf_empty(&sbuf)) {
704 sbuf_cut(&sbuf, sbuf_len(&sbuf) - 1);
705 str_set(id, sbuf_buf(&sbuf));
707 sbuf_done(&sbuf);
711 /* character translation (.tr) */
712 static struct dict *cmap; /* character mapping */
713 static char cmap_src[NCMAPS][GNLEN]; /* source character */
714 static char cmap_dst[NCMAPS][GNLEN]; /* character mapping */
715 static int cmap_n; /* number of translated character */
717 void cmap_add(char *c1, char *c2)
719 int i = dict_get(cmap, c1);
720 if (i >= 0) {
721 strcpy(cmap_dst[i], c2);
722 } else if (cmap_n < NCMAPS) {
723 strcpy(cmap_src[cmap_n], c1);
724 strcpy(cmap_dst[cmap_n], c2);
725 dict_put(cmap, cmap_src[cmap_n], cmap_n);
726 cmap_n++;
730 char *cmap_map(char *c)
732 int i = dict_get(cmap, c);
733 return i >= 0 ? cmap_dst[i] : c;
736 static void tr_tr(char **args)
738 char *s = args[1];
739 char c1[GNLEN], c2[GNLEN];
740 while (s && charread(&s, c1) >= 0) {
741 if (charread(&s, c2) < 0)
742 strcpy(c2, " ");
743 cmap_add(c1, c2);
747 /* character definition (.char) */
748 static char cdef_src[NCDEFS][GNLEN]; /* source character */
749 static char *cdef_dst[NCDEFS]; /* character definition */
750 static int cdef_fn[NCDEFS]; /* owning font */
751 static int cdef_n; /* number of defined characters */
752 static int cdef_expanding; /* inside cdef_expand() call */
754 static int cdef_find(char *c, int fn)
756 int i;
757 for (i = 0; i < cdef_n; i++)
758 if ((!cdef_fn[i] || cdef_fn[i] == fn) && !strcmp(cdef_src[i], c))
759 return i;
760 return -1;
763 /* return the definition of the given character */
764 char *cdef_map(char *c, int fn)
766 int i = cdef_find(c, fn);
767 return !cdef_expanding && i >= 0 ? cdef_dst[i] : NULL;
770 int cdef_expand(struct wb *wb, char *s, int fn)
772 char *d = cdef_map(s, fn);
773 if (!d)
774 return 1;
775 cdef_expanding = 1;
776 ren_parse(wb, d);
777 cdef_expanding = 0;
778 return 0;
781 static void cdef_remove(char *fn, char *cs)
783 char c[GNLEN];
784 int i;
785 int fp = fn ? dev_pos(fn) : -1;
786 if (!cs || charread(&cs, c) < 0)
787 return;
788 for (i = 0; i < cdef_n; i++) {
789 if (!strcmp(cdef_src[i], c)) {
790 if (!fn || (fp > 0 && cdef_fn[i] == fp)) {
791 free(cdef_dst[i]);
792 cdef_dst[i] = NULL;
793 cdef_src[i][0] = '\0';
799 static void cdef_add(char *fn, char *cs, char *def)
801 char c[GNLEN];
802 int i;
803 if (!def || charread(&cs, c) < 0)
804 return;
805 i = cdef_find(c, fn ? dev_pos(fn) : -1);
806 if (i < 0) {
807 for (i = 0; i < cdef_n; i++)
808 if (!cdef_dst[i])
809 break;
810 if (i == cdef_n && cdef_n < NCDEFS)
811 cdef_n++;
813 if (i >= 0 && i < cdef_n) {
814 snprintf(cdef_src[i], sizeof(cdef_src[i]), "%s", c);
815 cdef_dst[i] = xmalloc(strlen(def) + 1);
816 strcpy(cdef_dst[i], def);
817 cdef_fn[i] = fn ? dev_pos(fn) : 0;
821 static void tr_rchar(char **args)
823 int i;
824 for (i = 1; i <= NARGS; i++)
825 if (args[i])
826 cdef_remove(NULL, args[i]);
829 static void tr_char(char **args)
831 if (args[2])
832 cdef_add(NULL, args[1], args[2]);
833 else
834 cdef_remove(NULL, args[1]);
837 static void tr_ochar(char **args)
839 if (args[3])
840 cdef_add(args[1], args[2], args[3]);
841 else
842 cdef_remove(args[1], args[2]);
845 static void tr_fmap(char **args)
847 struct font *fn = args[1] ? dev_font(dev_pos(args[1])) : NULL;
848 if (fn && args[2])
849 font_map(fn, args[2], args[3]);
852 static void tr_blm(char **args)
854 tr_bm = args[1] ? map(args[1]) : -1;
857 /* read a macro argument */
858 static int tr_arg(struct sbuf *sbuf, int brk, int (*next)(void), void (*back)(int))
860 int quoted = 0;
861 int c;
862 c = next();
863 while (c == ' ')
864 c = next();
865 if (c == '\n' || c == brk)
866 back(c);
867 if (c < 0 || c == '\n' || c == brk)
868 return 1;
869 if (c == '"') {
870 quoted = 1;
871 c = next();
873 while (c >= 0 && c != '\n' && (quoted || c != brk)) {
874 if (!quoted && c == ' ')
875 break;
876 if (quoted && c == '"') {
877 c = next();
878 if (c != '"')
879 break;
881 if (c == c_ec) {
882 sbuf_add(sbuf, c);
883 c = next();
885 sbuf_add(sbuf, c);
886 c = next();
888 sbuf_add(sbuf, 0);
889 if (c >= 0)
890 back(c);
891 return 0;
894 /* read macro arguments; free the returned pointer when done */
895 char *tr_args(char **args, int brk, int (*next)(void), void (*back)(int))
897 struct sbuf sbuf;
898 char *s, *e;
899 int n = 0;
900 sbuf_init(&sbuf);
901 while (!tr_arg(&sbuf, brk, next, back))
903 s = sbuf_buf(&sbuf);
904 e = s + sbuf_len(&sbuf);
905 while (n < NARGS && s && s < e) {
906 args[n++] = s;
907 if ((s = memchr(s, '\0', e - s)))
908 s++;
910 return sbuf_out(&sbuf);
913 /* split the arguments in sbuf */
914 static int tr_argschop(struct sbuf *sbuf, char **args)
916 char *s = sbuf_buf(sbuf);
917 char *e = s + sbuf_len(sbuf);
918 int n = 0;
919 while (n < NARGS && s && s < e) {
920 args[n++] = s;
921 if ((s = memchr(s, '\0', e - s)))
922 s++;
924 return n;
927 /* read request arguments; trims tabs too */
928 static void mkargs_req(struct sbuf *sbuf)
930 int n = 0;
931 int c;
932 c = cp_next();
933 while (n < NARGS) {
934 int ok = 0;
935 while (c == ' ' || c == '\t')
936 c = cp_next();
937 while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
938 if (c != c_ni)
939 sbuf_add(sbuf, c);
940 c = cp_next();
941 ok = 1;
943 if (ok) {
944 n++;
945 sbuf_add(sbuf, 0);
947 if (c == '\n')
948 cp_back(c);
949 if (c < 0 || c == '\n')
950 break;
952 jmp_eol();
955 /* read arguments for .ds */
956 static void mkargs_ds(struct sbuf *sbuf)
958 char *s = read_name(n_cp);
959 sbuf_append(sbuf, s);
960 sbuf_add(sbuf, 0);
961 free(s);
962 s = read_string();
963 sbuf_append(sbuf, s);
964 sbuf_add(sbuf, 0);
965 free(s);
966 jmp_eol();
969 /* read arguments for .nr */
970 static void mkargs_reg1(struct sbuf *sbuf)
972 char *s = read_name(n_cp);
973 sbuf_append(sbuf, s);
974 sbuf_add(sbuf, 0);
975 free(s);
976 mkargs_req(sbuf);
979 /* do not read any arguments; for .if, .ie and .el */
980 static void mkargs_null(struct sbuf *sbuf)
984 /* read the whole line for .tm */
985 static void mkargs_eol(struct sbuf *sbuf)
987 int c;
988 cp_copymode(1);
989 c = cp_next();
990 while (c == ' ')
991 c = cp_next();
992 while (c >= 0 && c != '\n') {
993 if (c != c_ni)
994 sbuf_add(sbuf, c);
995 c = cp_next();
997 cp_copymode(0);
1000 static struct cmd {
1001 char *id;
1002 void (*f)(char **args);
1003 void (*args)(struct sbuf *sbuf);
1004 } cmds[] = {
1005 {TR_DIVBEG, tr_divbeg},
1006 {TR_DIVEND, tr_divend},
1007 {TR_DIVVS, tr_divvs},
1008 {TR_POPREN, tr_popren},
1009 {"ab", tr_ab, mkargs_eol},
1010 {"ad", tr_ad},
1011 {"af", tr_af},
1012 {"am", tr_de, mkargs_reg1},
1013 {"as", tr_as, mkargs_ds},
1014 {"bd", tr_bd},
1015 {"blm", tr_blm},
1016 {"bp", tr_bp},
1017 {"br", tr_br},
1018 {"c2", tr_c2},
1019 {"cc", tr_cc},
1020 {"ochar", tr_ochar},
1021 {"ce", tr_ce},
1022 {"ch", tr_ch},
1023 {"char", tr_char},
1024 {"chop", tr_chop, mkargs_reg1},
1025 {"cl", tr_cl},
1026 {"cp", tr_cp},
1027 {"cs", tr_cs},
1028 {"da", tr_di},
1029 {"de", tr_de, mkargs_reg1},
1030 {"di", tr_di},
1031 {"ds", tr_ds, mkargs_ds},
1032 {"dt", tr_dt},
1033 {"ec", tr_ec},
1034 {"el", tr_el, mkargs_null},
1035 {"em", tr_em},
1036 {"eo", tr_eo},
1037 {"eos", tr_eos},
1038 {"ev", tr_ev},
1039 {"ex", tr_ex},
1040 {"fc", tr_fc},
1041 {"ff", tr_ff},
1042 {"fi", tr_fi},
1043 {"fl", tr_br},
1044 {"fmap", tr_fmap},
1045 {"fp", tr_fp},
1046 {"ffsc", tr_ffsc},
1047 {"fspecial", tr_fspecial},
1048 {"ft", tr_ft},
1049 {"fzoom", tr_fzoom},
1050 {"hc", tr_hc},
1051 {"hcode", tr_hcode},
1052 {"hlm", tr_hlm},
1053 {"hpf", tr_hpf},
1054 {"hpfa", tr_hpfa},
1055 {"hy", tr_hy},
1056 {"hycost", tr_hycost},
1057 {"hydash", tr_hydash},
1058 {"hystop", tr_hystop},
1059 {"hw", tr_hw},
1060 {"ie", tr_if, mkargs_null},
1061 {"if", tr_if, mkargs_null},
1062 {"ig", tr_ig},
1063 {"in", tr_in},
1064 {"it", tr_it},
1065 {"kn", tr_kn},
1066 {"lc", tr_lc},
1067 {"lf", tr_lf},
1068 {"lg", tr_lg},
1069 {"ll", tr_ll},
1070 {"ls", tr_ls},
1071 {"lt", tr_lt},
1072 {"mc", tr_mc},
1073 {"mk", tr_mk},
1074 {"na", tr_na},
1075 {"ne", tr_ne},
1076 {"nf", tr_nf},
1077 {"nh", tr_nh},
1078 {"nm", tr_nm},
1079 {"nn", tr_nn},
1080 {"nr", tr_nr, mkargs_reg1},
1081 {"ns", tr_ns},
1082 {"nx", tr_nx},
1083 {"os", tr_os},
1084 {"pc", tr_pc},
1085 {"pl", tr_pl},
1086 {"pmll", tr_pmll},
1087 {"pn", tr_pn},
1088 {"po", tr_po},
1089 {"ps", tr_ps},
1090 {"rchar", tr_rchar},
1091 {"rm", tr_rm},
1092 {"rn", tr_rn},
1093 {"rr", tr_rr},
1094 {"rs", tr_rs},
1095 {"rt", tr_rt},
1096 {"so", tr_so},
1097 {"sp", tr_sp},
1098 {"ss", tr_ss},
1099 {"ssh", tr_ssh},
1100 {"sv", tr_sv},
1101 {"sy", tr_sy, mkargs_eol},
1102 {"ta", tr_ta},
1103 {"tc", tr_tc},
1104 {"ti", tr_ti},
1105 {"tkf", tr_tkf},
1106 {"tl", tr_tl, mkargs_null},
1107 {"tm", tr_tm, mkargs_eol},
1108 {"tr", tr_tr, mkargs_eol},
1109 {"vs", tr_vs},
1110 {"wh", tr_wh},
1113 static char *dotted(char *name, int dot)
1115 char *out = xmalloc(strlen(name) + 2);
1116 out[0] = dot;
1117 strcpy(out + 1, name);
1118 return out;
1121 /* read the next troff request; return zero if a request was executed. */
1122 int tr_nextreq(void)
1124 char *args[NARGS + 3] = {NULL};
1125 char *cmd;
1126 struct cmd *req;
1127 struct sbuf sbuf;
1128 int c;
1129 if (!tr_nl)
1130 return 1;
1131 c = cp_next();
1132 if (c == c_ec) {
1133 int c2 = cp_next();
1134 if (c2 == '!') {
1135 args[0] = "\\!";
1136 sbuf_init(&sbuf);
1137 cp_copymode(1);
1138 mkargs_eol(&sbuf);
1139 cp_copymode(0);
1140 tr_argschop(&sbuf, args + 1);
1141 tr_transparent(args);
1142 sbuf_done(&sbuf);
1143 return 0;
1145 cp_back(c2);
1147 if (c < 0 || (c != c_cc && c != c_c2 && (c != '\n' || tr_bm < 0))) {
1148 cp_back(c);
1149 return 1;
1151 cp_reqbeg();
1152 if (c != '\n') {
1153 cmd = read_name(n_cp);
1154 } else { /* blank line macro */
1155 cmd = malloc(strlen(map_name(tr_bm)) + 1);
1156 strcpy(cmd, map_name(tr_bm));
1157 cp_back(c);
1159 args[0] = dotted(cmd, c);
1160 req = str_dget(map(cmd));
1161 if (req) {
1162 sbuf_init(&sbuf);
1163 if (req->args)
1164 req->args(&sbuf);
1165 else
1166 mkargs_req(&sbuf);
1167 tr_argschop(&sbuf, args + 1);
1168 req->f(args);
1169 sbuf_done(&sbuf);
1170 } else {
1171 char *buf;
1172 cp_copymode(1);
1173 buf = tr_args(args + 1, -1, cp_next, cp_back);
1174 jmp_eol();
1175 cp_copymode(0);
1176 if (str_get(map(cmd)))
1177 in_push(str_get(map(cmd)), args + 1);
1178 free(buf);
1180 free(args[0]);
1181 free(cmd);
1182 return 0;
1185 int tr_next(void)
1187 int c;
1188 while (!tr_nextreq())
1190 c = cp_next();
1191 tr_nl = c == '\n' || c < 0;
1192 return c;
1195 void tr_init(void)
1197 int i;
1198 for (i = 0; i < LEN(cmds); i++)
1199 str_dset(map(cmds[i].id), &cmds[i]);
1200 cmap = dict_make(-1, 0, 0);
1203 void tr_done(void)
1205 int i;
1206 for (i = 0; i < cdef_n; i++)
1207 free(cdef_dst[i]);
1208 dict_free(cmap);