summaryrefslogtreecommitdiffstats
path: root/roff.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2018-04-10 00:52:30 +0000
committerIngo Schwarze <schwarze@openbsd.org>2018-04-10 00:52:30 +0000
commit37f94bbdf74663ed1f212a4a0aa87e4faf4ca885 (patch)
tree2fa8495fcc4d028ad7c5b27d0950eb9637149e7f /roff.c
parent272b0bdc5c87bfffd9b9864eac579487de6636ea (diff)
downloadmandoc-37f94bbdf74663ed1f212a4a0aa87e4faf4ca885.tar.gz
Two new low-level roff(7) features:
* .nr optional third argument (auto-increment step size) * \n+ and \n- numerical register auto-increment and -decrement bentley@ reported on Dec 9, 2013 that lang/sbcl(1) uses these.
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c57
1 files changed, 43 insertions, 14 deletions
diff --git a/roff.c b/roff.c
index e85961b6..d820ee15 100644
--- a/roff.c
+++ b/roff.c
@@ -73,6 +73,7 @@ struct roffkv {
struct roffreg {
struct roffstr key;
int val;
+ int step;
struct roffreg *next;
};
@@ -182,7 +183,8 @@ static void roff_freestr(struct roffkv *);
static size_t roff_getname(struct roff *, char **, int, int);
static int roff_getnum(const char *, int *, int *, int);
static int roff_getop(const char *, int *, char *);
-static int roff_getregn(struct roff *, const char *, size_t);
+static int roff_getregn(struct roff *,
+ const char *, size_t, char);
static int roff_getregro(const struct roff *,
const char *name);
static const char *roff_getstrn(struct roff *,
@@ -207,7 +209,7 @@ static enum rofferr roff_rm(ROFF_ARGS);
static enum rofferr roff_rn(ROFF_ARGS);
static enum rofferr roff_rr(ROFF_ARGS);
static void roff_setregn(struct roff *, const char *,
- size_t, int, char);
+ size_t, int, char, int);
static void roff_setstr(struct roff *,
const char *, const char *, int);
static void roff_setstrn(struct roffkv **, const char *,
@@ -1136,6 +1138,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
int done; /* no more input available */
int deftype; /* type of definition to paste */
int rcsid; /* kind of RCS id seen */
+ char sign; /* increment number register */
char term; /* character terminating the escape */
/* Search forward for comments. */
@@ -1246,6 +1249,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
term = cp[1];
/* FALLTHROUGH */
case 'n':
+ sign = cp[1];
+ if (sign == '+' || sign == '-')
+ cp++;
res = ubuf;
break;
default:
@@ -1350,7 +1356,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
case 'n':
if (arg_complete)
(void)snprintf(ubuf, sizeof(ubuf), "%d",
- roff_getregn(r, stnam, naml));
+ roff_getregn(r, stnam, naml, sign));
else
ubuf[0] = '\0';
break;
@@ -2522,12 +2528,12 @@ roff_evalnum(struct roff *r, int ln, const char *v,
void
roff_setreg(struct roff *r, const char *name, int val, char sign)
{
- roff_setregn(r, name, strlen(name), val, sign);
+ roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
}
static void
roff_setregn(struct roff *r, const char *name, size_t len,
- int val, char sign)
+ int val, char sign, int step)
{
struct roffreg *reg;
@@ -2544,6 +2550,7 @@ roff_setregn(struct roff *r, const char *name, size_t len,
reg->key.p = mandoc_strndup(name, len);
reg->key.sz = len;
reg->val = 0;
+ reg->step = 0;
reg->next = r->regtab;
r->regtab = reg;
}
@@ -2554,6 +2561,8 @@ roff_setregn(struct roff *r, const char *name, size_t len,
reg->val -= val;
else
reg->val = val;
+ if (step != INT_MIN)
+ reg->step = step;
}
/*
@@ -2589,11 +2598,11 @@ roff_getregro(const struct roff *r, const char *name)
int
roff_getreg(struct roff *r, const char *name)
{
- return roff_getregn(r, name, strlen(name));
+ return roff_getregn(r, name, strlen(name), '\0');
}
static int
-roff_getregn(struct roff *r, const char *name, size_t len)
+roff_getregn(struct roff *r, const char *name, size_t len, char sign)
{
struct roffreg *reg;
int val;
@@ -2604,12 +2613,24 @@ roff_getregn(struct roff *r, const char *name, size_t len)
return val;
}
- for (reg = r->regtab; reg; reg = reg->next)
+ for (reg = r->regtab; reg; reg = reg->next) {
if (len == reg->key.sz &&
- 0 == strncmp(name, reg->key.p, len))
+ 0 == strncmp(name, reg->key.p, len)) {
+ switch (sign) {
+ case '+':
+ reg->val += reg->step;
+ break;
+ case '-':
+ reg->val -= reg->step;
+ break;
+ default:
+ break;
+ }
return reg->val;
+ }
+ }
- roff_setregn(r, name, len, 0, '\0');
+ roff_setregn(r, name, len, 0, '\0', INT_MIN);
return 0;
}
@@ -2649,9 +2670,9 @@ roff_freereg(struct roffreg *reg)
static enum rofferr
roff_nr(ROFF_ARGS)
{
- char *key, *val;
+ char *key, *val, *step;
size_t keysz;
- int iv;
+ int iv, is, len;
char sign;
key = val = buf->buf + pos;
@@ -2666,9 +2687,17 @@ roff_nr(ROFF_ARGS)
if (sign == '+' || sign == '-')
val++;
- if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
- roff_setregn(r, key, keysz, iv, sign);
+ len = 0;
+ if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
+ return ROFF_IGN;
+
+ step = val + len;
+ while (isspace((unsigned char)*step))
+ step++;
+ if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
+ is = INT_MIN;
+ roff_setregn(r, key, keysz, iv, sign, is);
return ROFF_IGN;
}