summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2015-02-17 17:16:52 +0000
committerIngo Schwarze <schwarze@openbsd.org>2015-02-17 17:16:52 +0000
commit470431727a7ba5fde764e27df2eb620a81285593 (patch)
treebc25db5aea690976fe84d988e03ed16fe14b41ba
parentd051fb46374527510c8eca76499a77e487090a22 (diff)
downloadmandoc-470431727a7ba5fde764e27df2eb620a81285593.tar.gz
Let .it accept numerical expressions, not just numerical constants.
For .it, ignore scaling units in roff_getnum(). Inside parentheses, skip whitespace after a sign in roff_getnum(). Parse and ignore unary plus in roff_getnum(). As a bonus, get rid of the only call to mandoc_strntoi() in roff.c.
-rw-r--r--roff.713
-rw-r--r--roff.c77
2 files changed, 50 insertions, 40 deletions
diff --git a/roff.7 b/roff.7
index 81413919..bb44f6b4 100644
--- a/roff.7
+++ b/roff.7
@@ -1196,13 +1196,18 @@ This is a Heirloom extension and currently unsupported.
Set an input line trap.
Its syntax is as follows:
.Pp
-.D1 Pf . Cm it Ar number macro
+.D1 Pf . Cm it Ar expression macro
.Pp
The named
.Ar macro
-will be invoked after processing the specified
-.Ar number
-of input text lines.
+will be invoked after processing the number of input text lines
+specified by the numerical
+.Ar expression .
+While evaluating the
+.Ar expression ,
+the unit suffixes described below
+.Sx Scaling Widths
+are ignored.
.Ss \&itc
Set an input line trap, not counting lines ending with \ec.
Currently unsupported.
diff --git a/roff.c b/roff.c
index c07b192e..ad8c6eeb 100644
--- a/roff.c
+++ b/roff.c
@@ -396,13 +396,13 @@ static int roff_evalcond(struct roff *r, int,
static int roff_evalnum(struct roff *, int,
const char *, int *, int *, int);
static int roff_evalpar(struct roff *, int,
- const char *, int *, int *);
+ const char *, int *, int *, int);
static int roff_evalstrcond(const char *, int *);
static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
static size_t roff_getname(struct roff *, char **, int, int);
-static int roff_getnum(const char *, int *, int *);
+static int roff_getnum(const char *, int *, int *, int);
static int roff_getop(const char *, int *, char *);
static int roff_getregn(const struct roff *,
const char *, size_t);
@@ -441,6 +441,9 @@ static enum rofferr roff_userdef(ROFF_ARGS);
#define ASCII_LO 33
#define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
+#define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */
+#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */
+
static struct roffmac *hash[HASHWIDTH];
static struct roffmac roffs[ROFF_MAX] = {
@@ -1050,7 +1053,8 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
case 'B':
npos = 0;
ubuf[0] = arg_complete &&
- roff_evalnum(r, ln, stnam, &npos, NULL, 0) &&
+ roff_evalnum(r, ln, stnam, &npos,
+ NULL, ROFFNUM_SCALE) &&
stnam + npos + 1 == cp ? '1' : '0';
ubuf[1] = '\0';
break;
@@ -1628,18 +1632,22 @@ roff_cond_text(ROFF_ARGS)
* Ignore overflows, treat them just like the C language.
*/
static int
-roff_getnum(const char *v, int *pos, int *res)
+roff_getnum(const char *v, int *pos, int *res, int flags)
{
- int myres, n, p;
+ int myres, scaled, n, p;
if (NULL == res)
res = &myres;
p = *pos;
n = v[p] == '-';
- if (n)
+ if (n || v[p] == '+')
p++;
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[p]))
+ p++;
+
for (*res = 0; isdigit((unsigned char)v[p]); p++)
*res = 10 * *res + v[p] - '0';
if (p == *pos + n)
@@ -1652,39 +1660,40 @@ roff_getnum(const char *v, int *pos, int *res)
switch (v[p]) {
case 'f':
- *res *= 65536;
+ scaled = *res * 65536;
break;
case 'i':
- *res *= 240;
+ scaled = *res * 240;
break;
case 'c':
- *res *= 240;
- *res /= 2.54;
+ scaled = *res * 240 / 2.54;
break;
case 'v':
/* FALLTROUGH */
case 'P':
- *res *= 40;
+ scaled = *res * 40;
break;
case 'm':
/* FALLTROUGH */
case 'n':
- *res *= 24;
+ scaled = *res * 24;
break;
case 'p':
- *res *= 10;
- *res /= 3;
+ scaled = *res * 10 / 3;
break;
case 'u':
+ scaled = *res;
break;
case 'M':
- *res *= 6;
- *res /= 25;
+ scaled = *res * 6 / 25;
break;
default:
+ scaled = *res;
p--;
break;
}
+ if (flags & ROFFNUM_SCALE)
+ *res = scaled;
*pos = p + 1;
return(1);
@@ -1774,7 +1783,7 @@ roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
}
savepos = *pos;
- if (roff_evalnum(r, ln, v, pos, &number, 0))
+ if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
return((number > 0) == wanttrue);
else if (*pos == savepos)
return(roff_evalstrcond(v, pos) == wanttrue);
@@ -1997,14 +2006,14 @@ roff_getop(const char *v, int *pos, char *res)
*/
static int
roff_evalpar(struct roff *r, int ln,
- const char *v, int *pos, int *res)
+ const char *v, int *pos, int *res, int flags)
{
if ('(' != v[*pos])
- return(roff_getnum(v, pos, res));
+ return(roff_getnum(v, pos, res, flags));
(*pos)++;
- if ( ! roff_evalnum(r, ln, v, pos, res, 1))
+ if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
return(0);
/*
@@ -2027,7 +2036,7 @@ roff_evalpar(struct roff *r, int ln,
*/
static int
roff_evalnum(struct roff *r, int ln, const char *v,
- int *pos, int *res, int skipwhite)
+ int *pos, int *res, int flags)
{
int mypos, operand2;
char operator;
@@ -2037,29 +2046,29 @@ roff_evalnum(struct roff *r, int ln, const char *v,
pos = &mypos;
}
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
- if ( ! roff_evalpar(r, ln, v, pos, res))
+ if ( ! roff_evalpar(r, ln, v, pos, res, flags))
return(0);
while (1) {
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
if ( ! roff_getop(v, pos, &operator))
break;
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
- if ( ! roff_evalpar(r, ln, v, pos, &operand2))
+ if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
return(0);
- if (skipwhite)
+ if (flags & ROFFNUM_WHITE)
while (isspace((unsigned char)v[*pos]))
(*pos)++;
@@ -2263,7 +2272,7 @@ roff_nr(ROFF_ARGS)
if (sign == '+' || sign == '-')
val++;
- if (roff_evalnum(r, ln, val, NULL, &iv, 0))
+ if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
roff_setreg(r, key, iv, sign);
return(ROFF_IGN);
@@ -2318,24 +2327,20 @@ roff_rm(ROFF_ARGS)
static enum rofferr
roff_it(ROFF_ARGS)
{
- char *cp;
- size_t len;
int iv;
/* Parse the number of lines. */
- cp = buf->buf + pos;
- len = strcspn(cp, " \t");
- cp[len] = '\0';
- if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
+
+ if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
ln, ppos, buf->buf + 1);
return(ROFF_IGN);
}
- cp += len + 1;
/* Arm the input line trap. */
+
roffit_lines = iv;
- roffit_macro = mandoc_strdup(cp);
+ roffit_macro = mandoc_strdup(buf->buf + pos);
return(ROFF_IGN);
}