From bdcf22471658feadd37da3f16dbf98a95dc29dfa Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Tue, 3 Jun 2014 21:16:45 +0430 Subject: [PATCH] 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. --- char.c | 10 ++++++++++ cp.c | 36 ++++++++++++++++++++++++++++++++++++ roff.h | 3 ++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/char.c b/char.c index ba657be..3817b58 100644 --- a/char.c +++ b/char.c @@ -130,6 +130,16 @@ int charread(char **s, char *c) 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)) { diff --git a/cp.c b/cp.c index e0c555d..1418819 100644 --- a/cp.c +++ b/cp.c @@ -34,6 +34,7 @@ static int regid(void) return map(regname); } +/* interpolate \n(xy */ static void cp_num(void) { int id; @@ -47,6 +48,7 @@ static void cp_num(void) in_push(num_str(id), NULL); } +/* interpolate \*(xy */ static void cp_str(void) { char arg[ILNLEN]; @@ -68,11 +70,13 @@ static void cp_str(void) } } +/* 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 @@ static void cp_arg(void) in_push(arg, NULL); } +/* interpolate \w'xyz' */ static void cp_width(void) { char wid[16]; @@ -93,6 +98,7 @@ static void cp_width(void) in_push(wid, NULL); } +/* define a register as \R'xyz expr' */ static void cp_numdef(void) { char arg[ILNLEN]; @@ -107,6 +113,33 @@ static void cp_numdef(void) 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; @@ -177,6 +210,9 @@ int cp_next(void) } 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); c = c_ec; diff --git a/roff.h b/roff.h index 0e19e77..752d5af 100644 --- 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 utf8one(char *s); 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); -- 2.11.4.GIT