aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2022-05-31 20:23:05 +0000
committerIngo Schwarze <schwarze@openbsd.org>2022-05-31 20:23:05 +0000
commitbfab7104d861ff6e91e84c914c0f977343449298 (patch)
tree6d4648f1138aeb04731afc789a621012a21cab6c
parentea452a23a02a06e590a1b863b12b3fa42b728535 (diff)
downloadmandoc-bfab7104d861ff6e91e84c914c0f977343449298.tar.gz
mandoc-bfab7104d861ff6e91e84c914c0f977343449298.tar.zst
mandoc-bfab7104d861ff6e91e84c914c0f977343449298.zip
Rudimentary implementation of the \A escape sequence, following groff
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.
-rw-r--r--roff.721
-rw-r--r--roff.c7
-rw-r--r--roff_escape.c21
3 files changed, 42 insertions, 7 deletions
diff --git a/roff.7 b/roff.7
index cafa5287..2d58efd6 100644
--- 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>
@@ -2021,8 +2021,23 @@ End conditional input; see
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
diff --git a/roff.c b/roff.c
index 0c36e08e..83701f7d 100644
--- 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>
@@ -1520,6 +1520,11 @@ roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char ec)
*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 &&
diff --git a/roff_escape.c b/roff_escape.c
index 3c38ced7..20e5267a 100644
--- a/roff_escape.c
+++ b/roff_escape.c
@@ -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 valid_A; /* for \A parsing */
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 */
+ case 'A':
case 'B':
case 'w':
rval = ESCAPE_EXPAND;
term = '\b';
break;
- case 'A':
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. */
+ valid_A = 1;
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]) {
- 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;
+ case ESCAPE_UNDEF:
+ break;
+ default:
+ valid_A = 0;
+ break;
+ }
iendarg = iend = send;
} else {
+ if (buf[iendarg] == ' ' || buf[iendarg] == '\t')
+ valid_A = 0;
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;
+ case 'A':
+ if (valid_A == 0)
+ iendarg = iarg;
+ break;
case 'O':
switch (buf[iarg]) {
case '0':