shithub: neatroff

Download patch

ref: bdcf22471658feadd37da3f16dbf98a95dc29dfa
parent: 3c3327f92ca9d383b829070b428dfc10425439f9
author: Ali Gholami Rudi <[email protected]>
date: Tue Jun 3 17:16:45 EDT 2014

cp: support conditional interpolation with \?'cond@expr1@expr2@'

This adds a new escape sequence for conditional interpolation: the
escape sequence \?'cond@expr1@expr2@', evaluates cond (exactly as if
it is a .if condition) and interpolates expr1, if the condition is
true, and expr2, otherwise.  The delimiter (@ in this example) can be
any character that cannot be part of the condition; for numerical
expressions, for instance, it cannot be a digit, an operator sign, or
a scale indicator, unless separated from the condition with \&.  The
final delimiter may be omitted.  Note that this escape sequence is not
interpolated in copy-mode.

--- a/char.c
+++ b/char.c
@@ -130,6 +130,16 @@
 	return ret;
 }
 
+/* like charnext_delim() for string buffers */
+int charread_delim(char **s, char *c, char *delim)
+{
+	int ret;
+	sstr_push(*s);
+	ret = charnext_delim(c, sstr_next, sstr_back, delim);
+	*s = sstr_pop();
+	return ret;
+}
+
 /* read the argument of a troff escape sequence */
 void argnext(char *d, int cmd, int (*next)(void), void (*back)(int))
 {
--- a/cp.c
+++ b/cp.c
@@ -34,6 +34,7 @@
 	return map(regname);
 }
 
+/* interpolate \n(xy */
 static void cp_num(void)
 {
 	int id;
@@ -47,6 +48,7 @@
 		in_push(num_str(id), NULL);
 }
 
+/* interpolate \*(xy */
 static void cp_str(void)
 {
 	char arg[ILNLEN];
@@ -68,11 +70,13 @@
 	}
 }
 
+/* interpolate \g(xy */
 static void cp_numfmt(void)
 {
 	in_push(num_getfmt(regid()), NULL);
 }
 
+/* interpolate \$1 */
 static void cp_arg(void)
 {
 	char argname[NMLEN];
@@ -86,6 +90,7 @@
 		in_push(arg, NULL);
 }
 
+/* interpolate \w'xyz' */
 static void cp_width(void)
 {
 	char wid[16];
@@ -93,6 +98,7 @@
 	in_push(wid, NULL);
 }
 
+/* define a register as \R'xyz expr' */
 static void cp_numdef(void)
 {
 	char arg[ILNLEN];
@@ -107,6 +113,33 @@
 	num_set(map(arg), eval_re(s, num_get(map(arg), 0), 'u'));
 }
 
+/* conditional interpolation as \?'cond@expr1@expr2@' */
+static void cp_cond(void)
+{
+	char arg[ILNLEN];
+	char delim[GNLEN], cs[GNLEN];
+	char *r, *s = arg;
+	char *s1, *s2;
+	int n;
+	argnext(arg, '?', cp_next, cp_back);
+	n = eval_up(&s, '\0');
+	if (charread(&s, delim) < 0)
+		return;
+	if (!strcmp(delim, "\\&") && charread(&s, delim) < 0)
+		return;
+	s1 = s;
+	r = s;
+	while (charread_delim(&s, cs, delim) >= 0)
+		r = s;
+	*r = '\0';
+	s2 = s;
+	r = s;
+	while (charread_delim(&s, cs, delim) >= 0)
+		r = s;
+	*r = '\0';
+	in_push(n > 0 ? s1 : s2, NULL);
+}
+
 static int cp_raw(void)
 {
 	int c;
@@ -176,6 +209,9 @@
 			c = cp_next();
 		} else if (c == 'R' && !cp_cpmode) {
 			cp_numdef();
+			c = cp_next();
+		} else if (c == '?' && !cp_cpmode) {
+			cp_cond();
 			c = cp_next();
 		} else {
 			cp_back(c);
--- a/roff.h
+++ b/roff.h
@@ -56,7 +56,7 @@
 #define SC_EM		(n_s * SC_IN / 72)
 
 /* escape sequences */
-#define ESC_Q	"bCDhHlLNoRSvwxX"	/* \X'ccc' quoted escape sequences */
+#define ESC_Q	"bCDhHlLNoRSvwxX?"	/* \X'ccc' quoted escape sequences */
 #define ESC_P	"*fgkmns"		/* \Xc \X(cc \X[ccc] escape sequences */
 
 #define MIN(a, b)	((a) < (b) ? (a) : (b))
@@ -391,6 +391,7 @@
 int charnext(char *c, int (*next)(void), void (*back)(int));
 int charread(char **s, char *c);
 int charnext_delim(char *c, int (*next)(void), void (*back)(int), char *delim);
+int charread_delim(char **s, char *c, char *delim);
 void charnext_str(char *d, char *c);
 void argnext(char *d, int cmd, int (*next)(void), void (*back)(int));
 void argread(char **sp, char *d, int cmd);