ref: bdcf22471658feadd37da3f16dbf98a95dc29dfa
parent: 3c3327f92ca9d383b829070b428dfc10425439f9
author: Ali Gholami Rudi <ali@rudi.ir>
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);