shithub: neatroff

Download patch

ref: 3c3327f92ca9d383b829070b428dfc10425439f9
parent: 9f3b72a0dc3b3943e1c262e4d9f21a614ff08590
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Jun 3 13:07:19 EDT 2014

cp: passing arguments when interpolating strings

This adds support for \*[xyz arg1 arg2 ...].

--- a/cp.c
+++ b/cp.c
@@ -1,6 +1,7 @@
 /* copy-mode character interpretation */
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include "roff.h"
 
 static int cp_nblk;		/* input block depth (text in \{ and \}) */
@@ -7,7 +8,7 @@
 static int cp_sblk[NIES];	/* skip \} escape at this depth, if set */
 static int cp_cpmode;		/* disable the interpretation \w and \E */
 
-static void cparg(char *d)
+static void cparg(char *d, int len)
 {
 	int c = cp_next();
 	int i = 0;
@@ -29,7 +30,7 @@
 static int regid(void)
 {
 	char regname[NMLEN];
-	cparg(regname);
+	cparg(regname, sizeof(regname));
 	return map(regname);
 }
 
@@ -48,9 +49,23 @@
 
 static void cp_str(void)
 {
-	char *buf = str_get(regid());
-	if (buf)
-		in_push(buf, NULL);
+	char arg[ILNLEN];
+	struct sbuf sbuf;
+	char *args[NARGS] = {NULL};
+	cparg(arg, sizeof(arg));
+	if (strchr(arg, ' ')) {
+		sbuf_init(&sbuf);
+		sstr_push(strchr(arg, ' ') + 1);
+		tr_readargs(args, &sbuf, sstr_next, sstr_back);
+		sstr_pop();
+		*strchr(arg, ' ') = '\0';
+		if (str_get(map(arg)))
+			in_push(str_get(map(arg)), args);
+		sbuf_done(&sbuf);
+	} else {
+		if (str_get(map(arg)))
+			in_push(str_get(map(arg)), NULL);
+	}
 }
 
 static void cp_numfmt(void)
@@ -63,7 +78,7 @@
 	char argname[NMLEN];
 	char *arg = NULL;
 	int argnum;
-	cparg(argname);
+	cparg(argname, sizeof(argname));
 	argnum = atoi(argname);
 	if (argnum > 0 && argnum < NARGS + 1)
 		arg = in_arg(argnum);
--- a/roff.h
+++ b/roff.h
@@ -378,6 +378,8 @@
 void tr_popren(char **args);
 
 void tr_init(void);
+int tr_readargs(char **args, struct sbuf *sbuf,
+		int (*next)(void), void (*back)(int));
 
 /* helpers */
 void errmsg(char *msg, ...);
--- a/tr.c
+++ b/tr.c
@@ -108,7 +108,20 @@
 	n_o = MAX(0, po);
 }
 
-static char *arg_regname(char *s, int len);
+static void read_regname(char *s)
+{
+	int c = cp_next();
+	int n = n_cp ? 2 : NMLEN - 1;
+	while (c == ' ' || c == '\t')
+		c = cp_next();
+	while (c >= 0 && c != ' ' && c != '\t' && c != '\n' && --n >= 0) {
+		*s++ = c;
+		c = cp_next();
+	}
+	if (c >= 0)
+		cp_back(c);
+	*s = '\0';
+}
 
 static void macrobody(struct sbuf *sbuf, char *end)
 {
@@ -124,7 +137,7 @@
 		if (c == '\n') {
 			c = cp_next();
 			if (c == '.') {
-				arg_regname(buf, sizeof(buf));
+				read_regname(buf);
 				if ((n_cp && end[0] == buf[0] && end[1] == buf[1]) ||
 							!strcmp(end, buf)) {
 					jmp_eol();
@@ -165,17 +178,18 @@
 }
 
 /* read into sbuf until stop; if stop is NULL, stop at whitespace */
-static int read_until(struct sbuf *sbuf, char *stop)
+static int read_until(struct sbuf *sbuf, char *stop,
+			int (*next)(void), void (*back)(int))
 {
 	char cs[GNLEN], cs2[GNLEN];
 	int c;
-	while ((c = cp_next()) >= 0) {
-		cp_back(c);
+	while ((c = next()) >= 0) {
+		back(c);
 		if (c == '\n')
 			return 1;
 		if (!stop && (c == ' ' || c == '\t'))
 			return 0;
-		charnext(cs, cp_next, cp_back);
+		charnext(cs, next, back);
 		if (stop && !strcmp(stop, cs))
 			return 0;
 		charnext_str(cs2, cs);
@@ -185,16 +199,16 @@
 }
 
 /* evaluate .if strcmp (i.e. 'str'str') */
-static int if_strcmp(void)
+static int if_strcmp(int (*next)(void), void (*back)(int))
 {
 	char delim[GNLEN];
 	struct sbuf s1, s2;
 	int ret;
-	charnext(delim, cp_next, cp_back);
+	charnext(delim, next, back);
 	sbuf_init(&s1);
 	sbuf_init(&s2);
-	read_until(&s1, delim);
-	read_until(&s2, delim);
+	read_until(&s1, delim, next, back);
+	read_until(&s2, delim, next, back);
 	ret = !strcmp(sbuf_buf(&s1), sbuf_buf(&s2));
 	sbuf_done(&s1);
 	sbuf_done(&s2);
@@ -202,7 +216,7 @@
 }
 
 /* evaluate .if condition letters */
-static int if_cond(void)
+static int if_cond(int (*next)(void), void (*back)(int))
 {
 	switch (cp_next()) {
 	case 'o':
@@ -218,45 +232,51 @@
 }
 
 /* evaluate .if condition */
-static int if_eval(void)
+static int if_eval(int (*next)(void), void (*back)(int))
 {
 	struct sbuf sbuf;
 	int ret;
 	sbuf_init(&sbuf);
-	if (!read_until(&sbuf, NULL))
-		cp_back(' ');
+	if (!read_until(&sbuf, NULL, next, back))
+		back(' ');
 	ret = eval(sbuf_buf(&sbuf), '\0') > 0;
 	sbuf_done(&sbuf);
 	return ret;
 }
 
-static int ie_cond[NIES];	/* .ie condition stack */
-static int ie_depth;
-
-static void tr_if(char **args)
+static int eval_if(int (*next)(void), void (*back)(int))
 {
 	int neg = 0;
 	int ret;
 	int c;
 	do {
-		c = cp_next();
+		c = next();
 	} while (c == ' ' || c == '\t');
 	if (c == '!') {
 		neg = 1;
-		c = cp_next();
+		c = next();
 	}
-	cp_back(c);
+	back(c);
 	if (strchr("oetn", c)) {
-		ret = if_cond();
+		ret = if_cond(next, back);
 	} else if (!isdigit(c) && !strchr("-+*/%<=>&:.|()", c)) {
-		ret = if_strcmp();
+		ret = if_strcmp(next, back);
 	} else {
-		ret = if_eval();
+		ret = if_eval(next, back);
 	}
+	return ret != neg;
+}
+
+static int ie_cond[NIES];	/* .ie condition stack */
+static int ie_depth;
+
+static void tr_if(char **args)
+{
+	int c = eval_if(cp_next, cp_back);
 	if (args[0][1] == 'i' && args[0][2] == 'e')	/* .ie command */
 		if (ie_depth < NIES)
-			ie_cond[ie_depth++] = ret != neg;
-	cp_blk(ret == neg);
+			ie_cond[ie_depth++] = c;
+	cp_blk(!c);
 }
 
 static void tr_el(char **args)
@@ -662,165 +682,162 @@
 		font_map(fn, args[2], args[3] ? font_glyph(fn, args[3]) : NULL);
 }
 
-static char *arg_regname(char *s, int len)
+static void arg_regname(struct sbuf *sbuf)
 {
-	char *e = n_cp ? s + 2 : s + len;
-	int c = cp_next();
-	while (c == ' ' || c == '\t')
+	char reg[NMLEN];
+	read_regname(reg);
+	sbuf_append(sbuf, reg);
+	sbuf_add(sbuf, 0);
+}
+
+static void arg_string(struct sbuf *sbuf)
+{
+	int c;
+	while ((c = cp_next()) == ' ')
+		;
+	if (c == '"')
 		c = cp_next();
-	while (s < e && c >= 0 && c != ' ' && c != '\t' && c != '\n') {
-		*s++ = c;
+	while (c > 0 && c != '\n') {
+		sbuf_add(sbuf, c);
 		c = cp_next();
 	}
+	sbuf_add(sbuf, 0);
 	if (c >= 0)
 		cp_back(c);
-	*s++ = '\0';
-	return s;
 }
 
-static char *arg_normal(char *s, int len)
+static int mkargs_arg(struct sbuf *sbuf, int (*next)(void), void (*back)(int))
 {
-	char *e = s + len - 1;
 	int quoted = 0;
 	int c;
-	c = cp_next();
+	c = next();
 	while (c == ' ')
-		c = cp_next();
+		c = next();
+	if (c == '\n')
+		back(c);
+	if (c < 0 || c == '\n')
+		return 1;
 	if (c == '"') {
 		quoted = 1;
-		c = cp_next();
+		c = next();
 	}
-	while (s < e && c > 0 && c != '\n') {
+	while (c >= 0 && c != '\n') {
 		if (!quoted && c == ' ')
 			break;
 		if (quoted && c == '"') {
-			c = cp_next();
+			c = next();
 			if (c != '"')
 				break;
 		}
-		*s++ = c;
-		c = cp_next();
+		sbuf_add(sbuf, c);
+		c = next();
 	}
+	sbuf_add(sbuf, 0);
 	if (c >= 0)
-		cp_back(c);
-	*s++ = '\0';
-	return s;
+		back(c);
+	return 0;
 }
 
-static char *arg_string(char *s, int len)
+/* read macro arguments */
+int tr_readargs(char **args, struct sbuf *sbuf, int (*next)(void), void (*back)(int))
 {
-	char *e = s + len - 1;
-	int c;
-	while ((c = cp_next()) == ' ')
-		;
-	if (c == '"')
-		c = cp_next();
-	while (s < e && c > 0 && c != '\n') {
-		*s++ = c;
-		c = cp_next();
+	int idx[NARGS];
+	int i, n = 0;
+	while (n < NARGS) {
+		idx[n] = sbuf_len(sbuf);
+		if (mkargs_arg(sbuf, next, back))
+			break;
+		n++;
 	}
-	*s++ = '\0';
-	if (c >= 0)
-		cp_back(c);
-	return s;
+	for (i = 0; i < n; i++)
+		args[i] = sbuf_buf(sbuf) + idx[i];
+	return n;
 }
 
 /* read macro arguments; trims tabs if rmtabs is nonzero */
-static int mkargs(char **args, char *buf, int len)
+static int mkargs(char **args, struct sbuf *sbuf)
 {
-	char *s = buf;
-	char *e = buf + len - 1;
-	int c;
-	int n = 0;
-	while (n < NARGS) {
-		char *r = s;
-		c = cp_next();
-		if (c < 0 || c == '\n')
-			return n;
-		cp_back(c);
-		s = arg_normal(s, e - s);
-		if (*r != '\0')
-			args[n++] = r;
-	}
+	int n = tr_readargs(args, sbuf, cp_next, cp_back);
 	jmp_eol();
 	return n;
 }
 
 /* read request arguments; trims tabs too */
-static int mkargs_req(char **args, char *buf, int len)
+static int mkargs_req(char **args, struct sbuf *sbuf)
 {
-	char *r, *s = buf;
-	char *e = buf + len - 1;
+	int idx[NARGS];
+	int i, n = 0;
 	int c;
-	int n = 0;
 	c = cp_next();
-	while (n < NARGS && s < e) {
-		r = s;
+	while (n < NARGS) {
+		idx[n] = sbuf_len(sbuf);
 		while (c == ' ' || c == '\t')
 			c = cp_next();
-		while (c >= 0 && c != '\n' && c != ' ' && c != '\t' && s < e) {
-			*s++ = c;
+		while (c >= 0 && c != '\n' && c != ' ' && c != '\t') {
+			sbuf_add(sbuf, c);
 			c = cp_next();
 		}
-		*s++ = '\0';
-		if (*r != '\0')
-			args[n++] = r;
+		if (sbuf_len(sbuf) > idx[n])
+			n++;
+		sbuf_add(sbuf, 0);
+		if (c == '\n')
+			cp_back(c);
 		if (c < 0 || c == '\n')
-			return n;
+			break;
 	}
+	for (i = 0; i < n; i++)
+		args[i] = sbuf_buf(sbuf) + idx[i];
 	jmp_eol();
 	return n;
 }
 
 /* read arguments for .ds */
-static int mkargs_ds(char **args, char *buf, int len)
+static int mkargs_ds(char **args, struct sbuf *sbuf)
 {
-	char *s = buf;
-	char *e = buf + len - 1;
-	int c;
-	args[0] = s;
-	s = arg_regname(s, e - s);
-	args[1] = s;
+	int idx[NARGS];
+	int i, n = 0;
+	idx[n++] = sbuf_len(sbuf);
+	arg_regname(sbuf);
+	idx[n++] = sbuf_len(sbuf);
 	cp_copymode(1);
-	s = arg_string(s, e - s);
+	arg_string(sbuf);
 	cp_copymode(0);
-	c = cp_next();
-	if (c >= 0 && c != '\n')
-		jmp_eol();
-	return 2;
+	jmp_eol();
+	for (i = 0; i < n; i++)
+		args[i] = sbuf_buf(sbuf) + idx[i];
+	return n;
 }
 
 /* read arguments for commands .nr that expect a register name */
-static int mkargs_reg1(char **args, char *buf, int len)
+static int mkargs_reg1(char **args, struct sbuf *sbuf)
 {
-	char *s = buf;
-	char *e = buf + len - 1;
-	args[0] = s;
-	s = arg_regname(s, e - s);
-	return mkargs_req(args + 1, s, e - s) + 1;
+	int n;
+	int idx0 = sbuf_len(sbuf);
+	arg_regname(sbuf);
+	n = mkargs_req(args + 1, sbuf) + 1;
+	args[0] = sbuf_buf(sbuf) + idx0;
+	return n;
 }
 
 /* do not read arguments; for .if, .ie and .el */
-static int mkargs_null(char **args, char *buf, int len)
+static int mkargs_null(char **args, struct sbuf *sbuf)
 {
 	return 0;
 }
 
 /* read the whole line for .tm */
-static int mkargs_eol(char **args, char *buf, int len)
+static int mkargs_eol(char **args, struct sbuf *sbuf)
 {
-	char *s = buf;
-	char *e = buf + len - 1;
+	int idx0 = sbuf_len(sbuf);
 	int c;
-	args[0] = s;
 	c = cp_next();
 	while (c == ' ')
 		c = cp_next();
-	while (s < e && c >= 0 && c != '\n') {
-		*s++ = c;
+	while (c >= 0 && c != '\n') {
+		sbuf_add(sbuf, c);
 		c = cp_next();
 	}
-	*s = '\0';
+	args[0] = sbuf_buf(sbuf) + idx0;
 	return 1;
 }
 
@@ -827,7 +844,7 @@
 static struct cmd {
 	char *id;
 	void (*f)(char **args);
-	int (*args)(char **args, char *buf, int len);
+	int (*args)(char **args, struct sbuf *sbuf);
 } cmds[] = {
 	{TR_DIVBEG, tr_divbeg},
 	{TR_DIVEND, tr_divend},
@@ -926,9 +943,9 @@
 int tr_nextreq(void)
 {
 	char *args[NARGS + 3] = {NULL};
-	char cmd[RNLEN];
-	char buf[LNLEN];
+	char cmd[RNLEN + 1];
 	struct cmd *req;
+	struct sbuf sbuf;
 	int c;
 	if (!tr_nl)
 		return 1;
@@ -941,21 +958,23 @@
 	args[0] = cmd;
 	cmd[0] = c;
 	req = NULL;
-	arg_regname(cmd + 1, sizeof(cmd) - 1);
+	read_regname(cmd + 1);
+	sbuf_init(&sbuf);
 	req = str_dget(map(cmd + 1));
 	if (req) {
 		if (req->args)
-			req->args(args + 1, buf, sizeof(buf));
+			req->args(args + 1, &sbuf);
 		else
-			mkargs_req(args + 1, buf, sizeof(buf));
+			mkargs_req(args + 1, &sbuf);
 		req->f(args);
 	} else {
 		cp_copymode(1);
-		mkargs(args + 1, buf, sizeof(buf));
+		mkargs(args + 1, &sbuf);
 		cp_copymode(0);
 		if (str_get(map(cmd + 1)))
 			in_push(str_get(map(cmd + 1)), args + 1);
 	}
+	sbuf_done(&sbuf);
 	return 0;
 }