summaryrefslogtreecommitdiffstats
path: root/roff.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2013-10-05 22:25:12 +0000
committerIngo Schwarze <schwarze@openbsd.org>2013-10-05 22:25:12 +0000
commitf62813aec818d1bcaed673a7433a6d984db22a1c (patch)
tree0132d7a478a99b9c8441e3dfa577d14b9acc32ca /roff.c
parent42f5a4cc132dc305b6ded5b24570986d7e25a176 (diff)
downloadmandoc-f62813aec818d1bcaed673a7433a6d984db22a1c.tar.gz
Support simple numerical conditions.
Original code from Christos Zoulas, NetBSD rev. 1.11-1.13, April 3, 2013. I tweaked the code as follows: * In roff_getnum(), don't skip a minus that isn't followed by a digit. * In roff_getop(), do not handle "!=", groff doesn't support it either. * In roff_evalcond(), treat negative numbers as false, like groff. Besides, make the interfaces of roff_getnum() and roff_getop() more similar to each other and simplify parts of the code a bit.
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c94
1 files changed, 91 insertions, 3 deletions
diff --git a/roff.c b/roff.c
index e91efc8e..e5f1a33b 100644
--- a/roff.c
+++ b/roff.c
@@ -185,6 +185,8 @@ static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
static char *roff_getname(struct roff *, char **, int, int);
+static int roff_getnum(const char *, int *, int *);
+static int roff_getop(const char *, int *, char *);
static int roff_getregn(const struct roff *,
const char *, size_t);
static const char *roff_getstrn(const struct roff *,
@@ -1125,9 +1127,61 @@ roff_cond_text(ROFF_ARGS)
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
}
+static int
+roff_getnum(const char *v, int *pos, int *res)
+{
+ int p, n;
+
+ p = *pos;
+ n = v[p] == '-';
+ if (n)
+ p++;
+
+ for (*res = 0; isdigit((unsigned char)v[p]); p++)
+ *res += 10 * *res + v[p] - '0';
+ if (p == *pos + n)
+ return 0;
+
+ if (n)
+ *res = -*res;
+
+ *pos = p;
+ return 1;
+}
+
+static int
+roff_getop(const char *v, int *pos, char *res)
+{
+ int e;
+
+ *res = v[*pos];
+ e = v[*pos + 1] == '=';
+
+ switch (*res) {
+ case '=':
+ break;
+ case '>':
+ if (e)
+ *res = 'g';
+ break;
+ case '<':
+ if (e)
+ *res = 'l';
+ break;
+ default:
+ return(0);
+ }
+
+ *pos += 1 + e;
+
+ return(*res);
+}
+
static enum roffrule
roff_evalcond(const char *v, int *pos)
{
+ int not, lh, rh;
+ char op;
switch (v[*pos]) {
case ('n'):
@@ -1140,13 +1194,47 @@ roff_evalcond(const char *v, int *pos)
case ('t'):
(*pos)++;
return(ROFFRULE_DENY);
+ case ('!'):
+ (*pos)++;
+ not = 1;
+ break;
default:
+ not = 0;
break;
}
- while (v[*pos] && ' ' != v[*pos])
- (*pos)++;
- return(ROFFRULE_DENY);
+ if (!roff_getnum(v, pos, &lh))
+ return ROFFRULE_DENY;
+ if (!roff_getop(v, pos, &op)) {
+ if (lh < 0)
+ lh = 0;
+ goto out;
+ }
+ if (!roff_getnum(v, pos, &rh))
+ return ROFFRULE_DENY;
+ switch (op) {
+ case 'g':
+ lh = lh >= rh;
+ break;
+ case 'l':
+ lh = lh <= rh;
+ break;
+ case '=':
+ lh = lh == rh;
+ break;
+ case '>':
+ lh = lh > rh;
+ break;
+ case '<':
+ lh = lh < rh;
+ break;
+ default:
+ return ROFFRULE_DENY;
+ }
+out:
+ if (not)
+ lh = !lh;
+ return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
}
/* ARGSUSED */