ren: add .ls and \n(.L
[neatroff.git] / tr.c
blob81cb461f520287de0d0b5a92a15f5fe36478dd14
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "xroff.h"
6 static int tr_nl = 1;
8 /* skip everything until the end of line */
9 static void jmp_eol(void)
11 int c;
12 do {
13 c = cp_next();
14 } while (c >= 0 && c != '\n');
17 static void tr_vs(char **args)
19 int vs = args[1] ? eval(args[1], n_v, 'p') : n_v0;
20 n_v0 = n_v;
21 n_v = vs;
24 static void tr_ls(char **args)
26 int ls = args[1] ? eval(args[1], n_L, 'v') : n_L0;
27 n_L0 = n_L;
28 n_L = ls;
31 static void tr_pl(char **args)
33 if (args[1])
34 n_p = eval(args[1], n_p, 'v');
37 static void tr_nr(char **args)
39 int id;
40 if (!args[2])
41 return;
42 id = REG(args[1][0], args[1][1]);
43 num_set(id, eval(args[2], num_get(id, 0), 'u'));
44 num_inc(id, args[3] ? eval(args[3], 0, 'u') : 0);
47 static void tr_rr(char **args)
49 int i;
50 for (i = 1; i <= NARGS; i++)
51 if (args[i])
52 num_del(REG(args[i][0], args[i][1]));
55 static void tr_ds(char **args)
57 if (!args[2])
58 return;
59 str_set(REG(args[1][0], args[1][1]), args[2]);
62 static void tr_as(char **args)
64 int reg;
65 char *s1, *s2, *s;
66 if (!args[2])
67 return;
68 reg = REG(args[1][0], args[1][1]);
69 s1 = str_get(reg) ? str_get(reg) : "";
70 s2 = args[2];
71 s = malloc(strlen(s1) + strlen(s2) + 1);
72 strcpy(s, s1);
73 strcat(s, s2);
74 str_set(reg, s);
75 free(s);
78 static void tr_rm(char **args)
80 int i;
81 for (i = 1; i <= NARGS; i++)
82 if (args[i])
83 str_rm(REG(args[i][0], args[i][1]));
86 static void tr_rn(char **args)
88 if (!args[2])
89 return;
90 str_rn(REG(args[1][0], args[1][1]), REG(args[2][0], args[2][1]));
93 static void tr_po(char **args)
95 int po = args[1] ? eval(args[1], n_o, 'm') : n_o0;
96 n_o0 = n_o;
97 n_o = po;
100 static char *arg_regname(char *s, int len);
102 static void macrobody(struct sbuf *sbuf, char *end)
104 char buf[4];
105 int i, c;
106 while ((c = cp_next()) >= 0) {
107 if (sbuf)
108 sbuf_add(sbuf, c);
109 if (c == '\n') {
110 c = cp_next();
111 if (c == '.') {
112 arg_regname(buf, 4);
113 if (buf[0] == end[0] && buf[1] == end[1]) {
114 jmp_eol();
115 break;
117 if (!sbuf)
118 continue;
119 sbuf_add(sbuf, '.');
120 for (i = 0; buf[i]; i++)
121 sbuf_add(sbuf, (unsigned char) buf[i]);
122 continue;
124 if (sbuf && c >= 0)
125 sbuf_add(sbuf, c);
130 static void tr_de(char **args)
132 struct sbuf sbuf;
133 int id;
134 if (!args[1])
135 return;
136 id = REG(args[1][0], args[1][1]);
137 sbuf_init(&sbuf);
138 if (args[0][1] == 'a' && args[0][2] == 'm' && str_get(id))
139 sbuf_append(&sbuf, str_get(id));
140 macrobody(&sbuf, args[2] ? args[2] : ".");
141 str_set(id, sbuf_buf(&sbuf));
142 sbuf_done(&sbuf);
145 static void tr_ig(char **args)
147 macrobody(NULL, args[1] ? args[1] : ".");
150 /* read into sbuf until stop */
151 static void read_until(struct sbuf *sbuf, int stop)
153 int c;
154 while ((c = cp_next()) >= 0) {
155 if (c == stop)
156 return;
157 if (c == '\n') {
158 cp_back(c);
159 return;
161 sbuf_add(sbuf, c);
165 /* evaluate .if strcmp (i.e. 'str'str') */
166 static int if_strcmp(void)
168 struct sbuf s1, s2;
169 int ret;
170 sbuf_init(&s1);
171 sbuf_init(&s2);
172 read_until(&s1, '\'');
173 read_until(&s2, '\'');
174 ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
175 sbuf_done(&s1);
176 sbuf_done(&s2);
177 return ret;
180 /* evaluate .if condition */
181 static int if_cond(void)
183 struct sbuf sbuf;
184 char *s;
185 int ret;
186 sbuf_init(&sbuf);
187 read_until(&sbuf, ' ');
188 s = sbuf_buf(&sbuf);
189 if (s[0] == 'o' && s[1] == '\0')
190 ret = n_pg % 2;
191 else if (s[0] == 'e' && s[1] == '\0')
192 ret = !(n_pg % 2);
193 else if (s[0] == 't' && s[1] == '\0')
194 ret = 1;
195 else if (s[0] == 'n' && s[1] == '\0')
196 ret = 0;
197 else
198 ret = eval(s, 0, '\0') > 0;
199 sbuf_done(&sbuf);
200 return ret;
203 /* execute or skip the line or block following .if */
204 static void if_blk(int doexec)
206 int c;
207 if (doexec) {
208 do {
209 c = cp_next();
210 } while (c == ' ');
211 cp_back(c);
212 } else {
213 cp_skip();
217 static int ie_cond[NIES]; /* .ie condition stack */
218 static int ie_depth;
220 static void tr_if(char **args)
222 int neg = 0;
223 int ret;
224 int c;
225 do {
226 c = cp_next();
227 } while (c == ' ' || c == '\t');
228 if (c == '!') {
229 neg = 1;
230 c = cp_next();
232 if (c == '\'') {
233 ret = if_strcmp();
234 } else {
235 cp_back(c);
236 ret = if_cond();
238 if (args[0][1] == 'i' && args[0][2] == 'e') /* .ie command */
239 if (ie_depth < NIES)
240 ie_cond[ie_depth++] = ret != neg;
241 if_blk(ret != neg);
244 static void tr_el(char **args)
246 if_blk(ie_depth > 0 ? !ie_cond[--ie_depth] : 0);
249 static void tr_na(char **args)
251 n_na = 1;
254 static void tr_ad(char **args)
256 n_na = 0;
257 if (!args[1])
258 return;
259 switch (args[1][0]) {
260 case '0' + AD_L:
261 case 'l':
262 n_j = AD_L;
263 break;
264 case '0' + AD_R:
265 case 'r':
266 n_j = AD_R;
267 break;
268 case '0' + AD_C:
269 case 'c':
270 n_j = AD_C;
271 break;
272 case '0' + AD_B:
273 case 'b':
274 case 'n':
275 n_j = AD_B;
276 break;
280 static void tr_tm(char **args)
282 fprintf(stderr, "%s\n", args[1]);
285 static void tr_so(char **args)
287 if (args[1])
288 in_source(args[1]);
291 static char *arg_regname(char *s, int len)
293 char *e = s + 2;
294 int c;
295 while ((c = cp_next()) == ' ')
297 while (s < e && c >= 0 && c != ' ' && c != '\n') {
298 *s++ = c;
299 c = cp_next();
301 if (c >= 0)
302 cp_back(c);
303 *s++ = '\0';
304 return s;
307 static char *arg_normal(char *s, int len)
309 char *e = s + len - 1;
310 int quoted = 0;
311 int c;
312 c = cp_next();
313 while (c == ' ')
314 c = cp_next();
315 if (c == '"') {
316 quoted = 1;
317 c = cp_next();
319 while (s < e && c > 0 && c != '\n') {
320 if (!quoted && c == ' ')
321 break;
322 if (quoted && c == '"') {
323 c = cp_next();
324 if (c != '"')
325 break;
327 *s++ = c;
328 c = cp_next();
330 if (c >= 0)
331 cp_back(c);
332 *s++ = '\0';
333 return s;
336 static char *arg_string(char *s, int len)
338 char *e = s + len - 1;
339 int c;
340 while ((c = cp_next()) == ' ')
342 if (c == '"')
343 c = cp_next();
344 while (s < e && c > 0 && c != '\n') {
345 *s++ = c;
346 c = cp_next();
348 *s++ = '\0';
349 if (c >= 0)
350 cp_back(c);
351 return s;
354 /* read macro arguments; trims tabs if rmtabs is nonzero */
355 static int mkargs(char **args, char *buf, int len)
357 char *s = buf;
358 char *e = buf + len - 1;
359 int c;
360 int n = 0;
361 while (n < NARGS) {
362 char *r = s;
363 c = cp_next();
364 if (c < 0 || c == '\n')
365 return n;
366 cp_back(c);
367 s = arg_normal(s, e - s);
368 if (*r != '\0')
369 args[n++] = r;
371 jmp_eol();
372 return n;
375 /* read request arguments; trims tabs too */
376 static int mkargs_req(char **args, char *buf, int len)
378 char *r, *s = buf;
379 char *e = buf + len - 1;
380 int c;
381 int n = 0;
382 c = cp_next();
383 while (n < NARGS && s < e) {
384 r = s;
385 while (c == ' ' || c == '\t')
386 c = cp_next();
387 while (c >= 0 && c != '\n' && c != ' ' && c != '\t' && s < e) {
388 *s++ = c;
389 c = cp_next();
391 *s++ = '\0';
392 if (*r != '\0')
393 args[n++] = r;
394 if (c < 0 || c == '\n')
395 return n;
397 jmp_eol();
398 return n;
401 /* read arguments for .ds */
402 static int mkargs_ds(char **args, char *buf, int len)
404 char *s = buf;
405 char *e = buf + len - 1;
406 int c;
407 args[0] = s;
408 s = arg_regname(s, e - s);
409 args[1] = s;
410 s = arg_string(s, e - s);
411 c = cp_next();
412 if (c >= 0 && c != '\n')
413 jmp_eol();
414 return 2;
417 /* read arguments for commands .nr that expect a register name */
418 static int mkargs_reg1(char **args, char *buf, int len)
420 char *s = buf;
421 char *e = buf + len - 1;
422 args[0] = s;
423 s = arg_regname(s, e - s);
424 return mkargs_req(args + 1, s, e - s) + 1;
427 /* do not read arguments; for .if, .ie and .el */
428 static int mkargs_null(char **args, char *buf, int len)
430 return 0;
433 /* read the whole line for .tm */
434 static int mkargs_eol(char **args, char *buf, int len)
436 char *s = buf;
437 char *e = buf + len - 1;
438 int c;
439 args[0] = s;
440 c = cp_next();
441 while (c == ' ')
442 c = cp_next();
443 while (s < e && c >= 0 && c != '\n') {
444 *s++ = c;
445 c = cp_next();
447 *s = '\0';
448 return 1;
451 static struct cmd {
452 char *id;
453 void (*f)(char **args);
454 int (*args)(char **args, char *buf, int len);
455 } cmds[] = {
456 {DIV_BEG + 1, tr_divbeg},
457 {DIV_END + 1, tr_divend},
458 {"ad", tr_ad},
459 {"am", tr_de, mkargs_reg1},
460 {"as", tr_as, mkargs_ds},
461 {"bp", tr_bp},
462 {"br", tr_br},
463 {"ch", tr_ch},
464 {"da", tr_di},
465 {"de", tr_de, mkargs_reg1},
466 {"di", tr_di},
467 {"ds", tr_ds, mkargs_ds},
468 {"dt", tr_dt},
469 {"el", tr_el, mkargs_null},
470 {"ev", tr_ev},
471 {"fi", tr_fi},
472 {"fp", tr_fp},
473 {"ft", tr_ft},
474 {"ie", tr_if, mkargs_null},
475 {"if", tr_if, mkargs_null},
476 {"ig", tr_ig},
477 {"in", tr_in},
478 {"ll", tr_ll},
479 {"ls", tr_ls},
480 {"mk", tr_mk},
481 {"na", tr_na},
482 {"ne", tr_ne},
483 {"nf", tr_nf},
484 {"nr", tr_nr, mkargs_reg1},
485 {"ns", tr_ns},
486 {"os", tr_os},
487 {"pl", tr_pl},
488 {"pn", tr_pn},
489 {"po", tr_po},
490 {"ps", tr_ps},
491 {"rm", tr_rm},
492 {"rn", tr_rn},
493 {"rr", tr_rr},
494 {"rs", tr_rs},
495 {"rt", tr_rt},
496 {"so", tr_so},
497 {"sp", tr_sp},
498 {"sv", tr_sv},
499 {"ti", tr_ti},
500 {"tm", tr_tm, mkargs_eol},
501 {"vs", tr_vs},
502 {"wh", tr_wh},
505 int tr_next(void)
507 int c = cp_next();
508 int nl = c == '\n';
509 char *args[NARGS + 3] = {NULL};
510 char cmd[RLEN];
511 char buf[LNLEN];
512 struct cmd *req;
513 while (tr_nl && (c == '.' || c == '\'')) {
514 nl = 1;
515 memset(args, 0, sizeof(args));
516 args[0] = cmd;
517 cmd[0] = c;
518 req = NULL;
519 arg_regname(cmd + 1, sizeof(cmd) - 1);
520 req = str_dget(REG(cmd[1], cmd[2]));
521 if (req) {
522 if (req->args)
523 req->args(args + 1, buf, sizeof(buf));
524 else
525 mkargs_req(args + 1, buf, sizeof(buf));
526 req->f(args);
527 } else {
528 mkargs(args + 1, buf, sizeof(buf));
529 if (str_get(REG(cmd[1], cmd[2])))
530 in_push(str_get(REG(cmd[1], cmd[2])), args + 1);
532 c = cp_next();
534 tr_nl = nl;
535 return c;
538 void tr_init(void)
540 int i;
541 for (i = 0; i < LEN(cmds); i++)
542 str_dset(REG(cmds[i].id[0], cmds[i].id[1]), &cmds[i]);