diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2013-10-05 22:25:12 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2013-10-05 22:25:12 +0000 |
commit | f62813aec818d1bcaed673a7433a6d984db22a1c (patch) | |
tree | 0132d7a478a99b9c8441e3dfa577d14b9acc32ca /roff.c | |
parent | 42f5a4cc132dc305b6ded5b24570986d7e25a176 (diff) | |
download | mandoc-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.c | 94 |
1 files changed, 91 insertions, 3 deletions
@@ -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 */ |