summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--TODO8
-rw-r--r--regress/roff/nr/Makefile2
-rw-r--r--regress/roff/nr/incr.in30
-rw-r--r--regress/roff/nr/incr.out_ascii19
-rw-r--r--roff.720
-rw-r--r--roff.c57
6 files changed, 110 insertions, 26 deletions
diff --git a/TODO b/TODO
index 3055df6d..ccfd625d 100644
--- a/TODO
+++ b/TODO
@@ -52,10 +52,6 @@ are mere guesses, and some may be wrong.
found by naddy@ in xloadimage(1)
loc ** exist *** algo * size * imp *
-- .nr third argument (auto-increment step size, requires \n+)
- found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
- loc * exist * algo * size * imp **
-
- .ns (no-space mode) occurs in xine-config(1)
when implementing this, also let .TH set it
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
@@ -65,10 +61,6 @@ are mere guesses, and some may be wrong.
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
loc * exist ** algo ** size ** imp **
-- \n+ and \n- numerical register increment and decrement
- found by bentley@ in sbcl(1) Mon, 9 Dec 2013 18:36:57 -0700
- loc * exist * algo * size * imp **
-
- \w'' improve width measurements
would not be very useful without an expression parser, see below
needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
diff --git a/regress/roff/nr/Makefile b/regress/roff/nr/Makefile
index b3ba8102..562a5f30 100644
--- a/regress/roff/nr/Makefile
+++ b/regress/roff/nr/Makefile
@@ -1,6 +1,6 @@
# $OpenBSD: Makefile,v 1.9 2015/01/23 00:38:43 schwarze Exp $
-REGRESS_TARGETS = argc divzero escname eval int predef rr scale undef
+REGRESS_TARGETS = argc divzero escname eval incr int predef rr scale undef
LINT_TARGETS = divzero escname
.include <bsd.regress.mk>
diff --git a/regress/roff/nr/incr.in b/regress/roff/nr/incr.in
new file mode 100644
index 00000000..a03493ff
--- /dev/null
+++ b/regress/roff/nr/incr.in
@@ -0,0 +1,30 @@
+.\" $OpenBSD: undef.in,v 1.1 2018/04/09 22:26:25 schwarze Exp $
+.TH NR-INCR 1 "April 10, 2018"
+.SH NAME
+nr-incr \- increment a number register by accessing it
+.SH DESCRIPTION
+.nr myr 0 1
+Roff can count by merely accessing a number register:
+\n+[myr]
+\n+[myr]
+\n+[myr]
+.PP
+.nr myr +0 1+1
+It can also change the step size:
+\n+[myr]
+\n+[myr]
+\n+[myr]
+.PP
+.nr myr +0 3
+It can also count down:
+\n-[myr]
+\n-[myr]
+\n-[myr]
+\n-[myr]
+.PP
+.nr myr -0 -2
+Down in negative steps is up:
+\n-[myr]
+\n-[myr]
+\n-[myr]
+\n-[myr]
diff --git a/regress/roff/nr/incr.out_ascii b/regress/roff/nr/incr.out_ascii
new file mode 100644
index 00000000..d039d5b1
--- /dev/null
+++ b/regress/roff/nr/incr.out_ascii
@@ -0,0 +1,19 @@
+NR-INCR(1) General Commands Manual NR-INCR(1)
+
+
+
+NNAAMMEE
+ nr-incr - increment a number register by accessing it
+
+DDEESSCCRRIIPPTTIIOONN
+ Roff can count by merely accessing a number register: 1 2 3
+
+ It can also change the step size: 5 7 9
+
+ It can also count down: 6 3 0 -3
+
+ Down in negative steps is up: -1 1 3 5
+
+
+
+OpenBSD April 10, 2018 NR-INCR(1)
diff --git a/roff.7 b/roff.7
index 2b9053e4..b7f499d9 100644
--- a/roff.7
+++ b/roff.7
@@ -1,7 +1,7 @@
.\" $Id$
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010,2011,2013-2015,2017 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -1348,7 +1348,7 @@ Currently unsupported.
.It Ic \&nop Ar body
Execute the rest of the input line as a request or macro line.
Currently unsupported.
-.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression
+.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression Op Ar stepsize
Define or change a register.
A register is an arbitrary string value that defines some sort of state,
which influences parsing and/or formatting.
@@ -1360,6 +1360,14 @@ below.
If it is prefixed by a sign, the register will be
incremented or decremented instead of assigned to.
.Pp
+The
+.Ar stepsize
+is used by the
+.Ic \en+
+auto-increment feature.
+It remains unchanged when omitted while changing an existing register,
+and it defaults to 0 when defining a new register.
+.Pp
The following
.Ar register
is handled specially:
@@ -1996,13 +2004,19 @@ and
Character
.Ar number
on the current font.
-.Ss \en Ns Bq Ar name
+.Ss \en Ns Oo +|- Oc Ns Bq Ar name
Interpolate the number register
.Ar name .
For short names, there are variants
.No \en Ns Ar c
and
.No \en( Ns Ar cc .
+If the optional sign is specified,
+the register is first incremented or decremented by the
+.Ar stepsize
+that was specified in the relevant
+.Ic \&nr
+request, and the changed value is interpolated.
.Ss \eo\(aq Ns Ar string Ns \(aq
Overstrike, writing all the characters contained in the
.Ar string
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;
}