Implement the roff(7) `r' (register exists) conditional.
authorschwarze <schwarze@openbsd.org>
Sun, 31 May 2015 23:12:16 +0000 (23:12 +0000)
committerschwarze <schwarze@openbsd.org>
Sun, 31 May 2015 23:12:16 +0000 (23:12 +0000)
Missing feature found by Markus <Waldeck at gmx dot de>
in Debian's bash(1) manual page.

regress/usr.bin/mandoc/roff/cond/Makefile
regress/usr.bin/mandoc/roff/cond/register.in [new file with mode: 0644]
regress/usr.bin/mandoc/roff/cond/register.out_ascii [new file with mode: 0644]
share/man/man7/roff.7
usr.bin/mandoc/roff.c

index 9c84708..68a8869 100644 (file)
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.7 2014/07/07 21:35:42 schwarze Exp $
+# $OpenBSD: Makefile,v 1.8 2015/05/31 23:12:17 schwarze Exp $
 
-REGRESS_TARGETS = if ie close numeric strcmp before-Dd
+REGRESS_TARGETS = if ie close numeric register strcmp before-Dd
 LINT_TARGETS   = if close
 
 .include <bsd.regress.mk>
diff --git a/regress/usr.bin/mandoc/roff/cond/register.in b/regress/usr.bin/mandoc/roff/cond/register.in
new file mode 100644 (file)
index 0000000..d8c9629
--- /dev/null
@@ -0,0 +1,11 @@
+.TH REGISTER 1 "May 31, 2015" OpenBSD
+.SH NAME
+register \- conditional testing whether a register is defined
+.SH DESCRIPTION
+.ie rmyreg OOPS
+.el not yet defined
+.br
+.nr myreg 0
+.ie rmyreg now defined
+.el OOPS
+.if !rmyreg OOPS
diff --git a/regress/usr.bin/mandoc/roff/cond/register.out_ascii b/regress/usr.bin/mandoc/roff/cond/register.out_ascii
new file mode 100644 (file)
index 0000000..acd0f72
--- /dev/null
@@ -0,0 +1,14 @@
+REGISTER(1)                 General Commands Manual                REGISTER(1)
+
+
+
+N\bNA\bAM\bME\bE
+       register - conditional testing whether a register is defined
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       not yet defined
+       now defined
+
+
+
+OpenBSD                          May 31, 2015                      REGISTER(1)
index 13743c1..5426baf 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.51 2015/04/29 18:32:57 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.52 2015/05/31 23:12:16 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010, 2011, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -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: April 29 2015 $
+.Dd $Mdocdate: May 31 2015 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -1055,8 +1055,6 @@ If the first character of COND is
 .Pq string defined ,
 .Sq e
 .Pq even page ,
-.Sq r
-.Pq register accessed ,
 .Sq t
 .Pq troff mode ,
 or
@@ -1064,6 +1062,11 @@ or
 .Pq vroff mode ,
 COND evaluates to false.
 .It
+If the first character of COND is
+.Sq r ,
+it evalutes to true if the rest of COND is the name of an existing
+number register; otherwise, it evaluates to false.
+.It
 If COND starts with a parenthesis or with an optionally signed
 integer number, it is evaluated according to the rules of
 .Sx Numerical expressions
index f99246a..62f524f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.142 2015/05/01 16:01:53 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.143 2015/05/31 23:12:16 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -395,8 +395,7 @@ static      enum rofferr     roff_cond_text(ROFF_ARGS);
 static enum rofferr     roff_cond_sub(ROFF_ARGS);
 static enum rofferr     roff_ds(ROFF_ARGS);
 static enum rofferr     roff_eqndelim(struct roff *, struct buf *, int);
-static int              roff_evalcond(struct roff *r, int,
-                               const char *, int *);
+static int              roff_evalcond(struct roff *r, int, char *, int *);
 static int              roff_evalnum(struct roff *, int,
                                const char *, int *, int *, int);
 static int              roff_evalpar(struct roff *, int,
@@ -413,6 +412,8 @@ static      int              roff_getregn(const struct roff *,
 static int              roff_getregro(const char *name);
 static const char      *roff_getstrn(const struct roff *,
                                const char *, size_t);
+static int              roff_hasregn(const struct roff *,
+                               const char *, size_t);
 static enum rofferr     roff_insec(ROFF_ARGS);
 static enum rofferr     roff_it(ROFF_ARGS);
 static enum rofferr     roff_line_ignore(ROFF_ARGS);
@@ -2132,8 +2133,10 @@ out:
  * or string condition.
  */
 static int
-roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
+roff_evalcond(struct roff *r, int ln, char *v, int *pos)
 {
+       char    *cp, *name;
+       size_t   sz;
        int      number, savepos, wanttrue;
 
        if ('!' == v[*pos]) {
@@ -2156,13 +2159,16 @@ roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
                /* FALLTHROUGH */
        case 'e':
                /* FALLTHROUGH */
-       case 'r':
-               /* FALLTHROUGH */
        case 't':
                /* FALLTHROUGH */
        case 'v':
                (*pos)++;
                return(!wanttrue);
+       case 'r':
+               cp = name = v + ++*pos;
+               sz = roff_getname(r, &cp, ln, *pos);
+               *pos = cp - v;
+               return((sz && roff_hasregn(r, name, sz)) == wanttrue);
        default:
                break;
        }
@@ -2625,6 +2631,26 @@ roff_getregn(const struct roff *r, const char *name, size_t len)
        return(0);
 }
 
+static int
+roff_hasregn(const struct roff *r, const char *name, size_t len)
+{
+       struct roffreg  *reg;
+       int              val;
+
+       if ('.' == name[0] && 2 == len) {
+               val = roff_getregro(name + 1);
+               if (-1 != val)
+                       return(1);
+       }
+
+       for (reg = r->regtab; reg; reg = reg->next)
+               if (len == reg->key.sz &&
+                   0 == strncmp(name, reg->key.p, len))
+                       return(1);
+
+       return(0);
+}
+
 static void
 roff_freereg(struct roffreg *reg)
 {