From aa23a004eb502cf67af388be4976d369784961db Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Tue, 10 Apr 2018 00:52:30 +0000 Subject: 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. --- TODO | 10 +------ regress/roff/nr/Makefile | 2 +- regress/roff/nr/incr.in | 30 +++++++++++++++++++++ regress/roff/nr/incr.out_ascii | 19 ++++++++++++++ roff.7 | 24 +++++++++++++---- roff.c | 59 +++++++++++++++++++++++++++++++----------- 6 files changed, 114 insertions(+), 30 deletions(-) create mode 100644 regress/roff/nr/incr.in create mode 100644 regress/roff/nr/incr.out_ascii diff --git a/TODO b/TODO index 4d74fd06..0e324d9c 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ ************************************************************************ * Official mandoc TODO. -* $Id: TODO,v 1.249 2018/04/09 02:31:42 schwarze Exp $ +* $Id: TODO,v 1.250 2018/04/10 00:52:30 schwarze Exp $ ************************************************************************ Many issues are annotated for difficulty as follows: @@ -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 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 58b5379e..8cb922c7 100644 --- a/roff.7 +++ b/roff.7 @@ -1,7 +1,7 @@ -.\" $Id: roff.7,v 1.95 2017/12/15 23:39:07 schwarze Exp $ +.\" $Id: roff.7,v 1.96 2018/04/10 00:52:30 schwarze Exp $ .\" .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons -.\" Copyright (c) 2010,2011,2013-2015,2017 Ingo Schwarze +.\" Copyright (c) 2010-2018 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 15 2017 $ +.Dd $Mdocdate: April 10 2018 $ .Dt ROFF 7 .Os .Sh NAME @@ -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 08c0afc5..d37a9fc7 100644 --- a/roff.c +++ b/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.326 2018/04/09 22:27:04 schwarze Exp $ */ +/* $Id: roff.c,v 1.327 2018/04/10 00:52:30 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze @@ -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; } -- cgit v1.2.3-56-ge451