]> git.cameronkatri.com Git - mandoc.git/commitdiff
Rudimentary implementation of the \A escape sequence, following groff
authorIngo Schwarze <schwarze@openbsd.org>
Tue, 31 May 2022 20:23:05 +0000 (20:23 +0000)
committerIngo Schwarze <schwarze@openbsd.org>
Tue, 31 May 2022 20:23:05 +0000 (20:23 +0000)
semantics (test identifier for syntactical validity), not at all
following the completely unrelated Heirloom semantics (define
hyperlink target position).

The main motivation for providing this implementation is to get \A
into the parsing class ESCAPE_EXPAND that corresponds to groff parsing
behaviour, which is quite similar to the \B escape sequence (test
numerical expression for syntactical validity).  This is likely
to improve parsing of nested escape sequences in the future.

Validation isn't perfect yet.  In particular, this implementation
rejects \A arguments containing some escape sequences that groff
allows to slip through.  But that is unlikely to cause trouble even
in documents using \A for non-trivial purposes.  Rejecting the nested
escapes in question might even improve robustnest because the rejected
names are unlikely to really be usable for practical purposes - no
matter that groff dubiously considers them syntactically valid.

roff.7
roff.c
roff_escape.c

diff --git a/roff.7 b/roff.7
index cafa5287640fd345280b97a0b3c4ea37d840cedb..2d58efd6cec3c9ef67e9e515102698eddb7935b9 100644 (file)
--- a/roff.7
+++ b/roff.7
@@ -1,4 +1,4 @@
-.\" $Id: roff.7,v 1.119 2022/05/31 18:09:57 schwarze Exp $
+.\" $Id: roff.7,v 1.120 2022/05/31 20:23:05 schwarze Exp $
 .\"
 .\" Copyright (c) 2010-2019, 2022 Ingo Schwarze <schwarze@openbsd.org>
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\"
 .\" Copyright (c) 2010-2019, 2022 Ingo Schwarze <schwarze@openbsd.org>
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -2021,8 +2021,23 @@ End conditional input; see
 Paddable non-breaking space character.
 .It Ic \e0
 Digit width space character.
 Paddable non-breaking space character.
 .It Ic \e0
 Digit width space character.
-.It Ic \eA\(aq Ns Ar string Ns Ic \(aq
-Anchor definition; ignored by
+.It Ic \eA\(aq Ns Ar name Ns Ic \(aq
+Interpolate
+.Sq 1
+if
+.Ar name
+is a syntactically valid identifier that can be used
+as a name for a macro or user-defined string, or
+.Sq 0
+otherwise.
+This is a thoroughly non-portable groff extension.
+Heirloom troff uses the same escape sequence with the same syntax
+for a completely different purpose,
+defining a hyperlink target position, also called an
+.Dq anchor ,
+with the given
+.Ar name .
+The Heirloom semantics is not supported by
 .Xr mandoc 1 .
 .It Ic \ea
 Leader character; ignored by
 .Xr mandoc 1 .
 .It Ic \ea
 Leader character; ignored by
diff --git a/roff.c b/roff.c
index 0c36e08e24bcacfa8e9268c9b23634ae924a1c0a..83701f7d936979e3b768d4cc0aea3cce18eaa6c8 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/* $Id: roff.c,v 1.390 2022/05/31 18:09:57 schwarze Exp $ */
+/* $Id: roff.c,v 1.391 2022/05/31 20:23:05 schwarze Exp $ */
 /*
  * Copyright (c) 2010-2015, 2017-2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
 /*
  * Copyright (c) 2010-2015, 2017-2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -1520,6 +1520,11 @@ roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char ec)
                                        *dst++ = '"';
                        }
                        continue;
                                        *dst++ = '"';
                        }
                        continue;
+               case 'A':
+                       ubuf[0] = iendarg > iarg ? '1' : '0';
+                       ubuf[1] = '\0';
+                       res = ubuf;
+                       break;
                case 'B':
                        npos = 0;
                        ubuf[0] = iendarg > iarg && iend > iendarg &&
                case 'B':
                        npos = 0;
                        ubuf[0] = iendarg > iarg && iend > iendarg &&
index 3c38ced711a2c77e95fd4d7028fc67a3d8668708..20e5267a59f287167072e4d671956f4eadd0ef65 100644 (file)
@@ -73,6 +73,7 @@ roff_escape(const char *buf, const int ln, const int aesc,
        int              maxl;          /* expected length of the argument */
        int              argl;          /* actual length of the argument */
        int              c, i;          /* for \[char...] parsing */
        int              maxl;          /* expected length of the argument */
        int              argl;          /* actual length of the argument */
        int              c, i;          /* for \[char...] parsing */
+       int              valid_A;       /* for \A parsing */
        enum mandoc_esc  rval;          /* return value */
        enum mandocerr   err;           /* diagnostic code */
        char             esc_name;
        enum mandoc_esc  rval;          /* return value */
        enum mandocerr   err;           /* diagnostic code */
        char             esc_name;
@@ -181,12 +182,12 @@ roff_escape(const char *buf, const int ln, const int aesc,
 
        /* Quoted arguments */
 
 
        /* Quoted arguments */
 
+       case 'A':
        case 'B':
        case 'w':
                rval = ESCAPE_EXPAND;
                term = '\b';
                break;
        case 'B':
        case 'w':
                rval = ESCAPE_EXPAND;
                term = '\b';
                break;
-       case 'A':
        case 'D':
        case 'H':
        case 'L':
        case 'D':
        case 'H':
        case 'L':
@@ -301,6 +302,7 @@ roff_escape(const char *buf, const int ln, const int aesc,
 
        /* Advance to the end of the argument. */
 
 
        /* Advance to the end of the argument. */
 
+       valid_A = 1;
        iendarg = iarg;
        while (maxl > 0) {
                if (buf[iendarg] == '\0') {
        iendarg = iarg;
        while (maxl > 0) {
                if (buf[iendarg] == '\0') {
@@ -319,11 +321,20 @@ roff_escape(const char *buf, const int ln, const int aesc,
                        break;
                }
                if (buf[iendarg] == buf[iesc]) {
                        break;
                }
                if (buf[iendarg] == buf[iesc]) {
-                       if (roff_escape(buf, ln, iendarg,
-                           &sesc, &sarg, &sendarg, &send) == ESCAPE_EXPAND)
+                       switch (roff_escape(buf, ln, iendarg,
+                           &sesc, &sarg, &sendarg, &send)) {
+                       case ESCAPE_EXPAND:
                                goto out_sub;
                                goto out_sub;
+                       case ESCAPE_UNDEF:
+                               break;
+                       default:
+                               valid_A = 0;
+                               break;
+                       }
                        iendarg = iend = send;
                } else {
                        iendarg = iend = send;
                } else {
+                       if (buf[iendarg] == ' ' || buf[iendarg] == '\t')
+                               valid_A = 0;
                        if (maxl != INT_MAX)
                                maxl--;
                        iend = ++iendarg;
                        if (maxl != INT_MAX)
                                maxl--;
                        iend = ++iendarg;
@@ -342,6 +353,10 @@ roff_escape(const char *buf, const int ln, const int aesc,
                    buf[iarg] == '.' && buf[iarg + 1] == 'T')
                        rval = ESCAPE_DEVICE;
                break;
                    buf[iarg] == '.' && buf[iarg + 1] == 'T')
                        rval = ESCAPE_DEVICE;
                break;
+       case 'A':
+               if (valid_A == 0)
+                       iendarg = iarg;
+               break;
        case 'O':
                switch (buf[iarg]) {
                case '0':
        case 'O':
                switch (buf[iarg]) {
                case '0':