summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2018-12-15 19:30:25 +0000
committerIngo Schwarze <schwarze@openbsd.org>2018-12-15 19:30:25 +0000
commit0e3f0b740ea18224c3b2c07114be601dd8be97bb (patch)
treec930c6fd7e739e926a7fad1c372897af5ea601fb
parent2b0b19a54638a1b40d908611acc8498a911df29c (diff)
downloadmandoc-0e3f0b740ea18224c3b2c07114be601dd8be97bb.tar.gz
Several improvements to escape sequence handling.
* Add the missing special character \_ (underscore). * Partial implementations of \a (leader character) and \E (uninterpreted escape character). * Parse and ignore \r (reverse line feed). * Add a WARNING message about undefined escape sequences. * Add an UNSUPP message about unsupported escape sequences. * Mark \! and \? (transparent throughput) and \O (suppress output) as unsupported. * Treat the various variants of zero-width spaces as one-byte escape sequences rather than as special characters, to avoid defining bogus forms with square brackets. * For special characters with one-byte names, do not define bogus forms with square brackets, except for \[-], which is valid. * In the form with square brackets, undefined special characters do not fall back to printing the name verbatim, not even for one-byte names. * Starting a special character name with a blank is an error. * Undefined escape sequences never abort formatting of the input string, not even in HTML output mode. * Document the newly handled escapes, and a few that were missing. * Regression tests for most of the above.
-rw-r--r--TODO10
-rw-r--r--chars.c20
-rw-r--r--html.c8
-rw-r--r--mandoc.116
-rw-r--r--mandoc.c94
-rw-r--r--mandoc.h4
-rw-r--r--mandoc_char.78
-rw-r--r--mandoc_msg.c2
-rw-r--r--mdoc_man.c1
-rw-r--r--mdoc_markdown.c3
-rw-r--r--regress/char/accent/Makefile1
-rw-r--r--regress/char/accent/nocombine.in12
-rw-r--r--regress/char/accent/nocombine.out_ascii6
-rw-r--r--regress/char/accent/nocombine.out_lint2
-rw-r--r--regress/char/accent/nocombine.out_utf86
-rw-r--r--regress/char/space/Makefile3
-rw-r--r--regress/char/space/esct-man.in14
-rw-r--r--regress/char/space/esct-man.out_ascii6
-rw-r--r--regress/char/space/esct-man.out_lint10
-rw-r--r--regress/char/space/invalid.in15
-rw-r--r--regress/char/space/invalid.out_ascii21
-rw-r--r--regress/char/space/invalid.out_lint9
-rw-r--r--regress/roff/esc/Makefile5
-rw-r--r--regress/roff/esc/O.in15
-rw-r--r--regress/roff/esc/O.out_ascii21
-rw-r--r--regress/roff/esc/O.out_lint5
-rw-r--r--regress/roff/esc/ignore.in18
-rw-r--r--regress/roff/esc/ignore.out_ascii19
-rw-r--r--regress/roff/esc/ignore.out_lint5
-rw-r--r--regress/roff/esc/invalid.in28
-rw-r--r--regress/roff/esc/invalid.out_ascii34
-rw-r--r--regress/roff/esc/invalid.out_lint43
-rw-r--r--regress/roff/esc/one.in18
-rw-r--r--regress/roff/esc/one.out_ascii18
-rw-r--r--regress/roff/esc/unsupp.in8
-rw-r--r--regress/roff/esc/unsupp.out_ascii14
-rw-r--r--regress/roff/esc/unsupp.out_lint5
-rw-r--r--roff.743
-rw-r--r--roff.c47
-rw-r--r--term.c18
40 files changed, 507 insertions, 128 deletions
diff --git a/TODO b/TODO
index 72b234f0..8f05cb9a 100644
--- a/TODO
+++ b/TODO
@@ -75,12 +75,6 @@ are mere guesses, and some may be wrong.
Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +0100
loc *** exist *** algo *** size ** imp *
-- check for missing roff escape sequences, implement those that are
- trivial even if not usually appearing in manual pages, gracefully
- ignore the non-trivial ones, document what they are supposed to do
- and what mandoc does instead
- loc * exist ** algo * size * imp *
-
--- missing mdoc features ----------------------------------------------
- .Bl -column .Xo support is missing
@@ -534,10 +528,6 @@ are mere guesses, and some may be wrong.
output without intervening whitespace, in particular after a
macro line (from the mdoclint TODO)
-- mandoc_special does not really check the escape sequence,
- but just the overall format
- loc ** exist ** algo *** size ** imp **
-
- makewhatis -p complains about language subdirectories:
/usr/local/man//ru: Unknown directory part
diff --git a/chars.c b/chars.c
index 581f9abc..6efe51e3 100644
--- a/chars.c
+++ b/chars.c
@@ -1,7 +1,7 @@
/* $Id$ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2014,2015,2017,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
@@ -48,21 +48,13 @@ static struct ln lines[] = {
{ " ", ascii_nbrsp, 0x00a0 },
{ "~", ascii_nbrsp, 0x00a0 },
{ "0", " ", 0x2002 },
- { "|", "", 0 },
- { "^", "", 0 },
- { "&", "", 0 },
- { ")", "", 0 },
- { "%", "", 0 },
{ ":", ascii_break, 0 },
- /* XXX The following three do not really belong here. */
- { "t", "", 0 },
- { "c", "", 0 },
- { "}", "", 0 },
/* Lines. */
{ "ba", "|", 0x007c },
{ "br", "|", 0x2502 },
{ "ul", "_", 0x005f },
+ { "_", "_", 0x005f },
{ "ru", "_", 0x005f },
{ "rn", "-", 0x203e },
{ "bb", "|", 0x00a6 },
@@ -465,7 +457,7 @@ mchars_spec2cp(const char *p, size_t sz)
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
- return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1;
+ return ln != NULL ? ln->unicode : -1;
}
int
@@ -495,10 +487,8 @@ mchars_spec2str(const char *p, size_t sz, size_t *rsz)
end = p + sz;
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
- if (ln == NULL) {
- *rsz = 1;
- return sz == 1 ? p : NULL;
- }
+ if (ln == NULL)
+ return NULL;
*rsz = strlen(ln->ascii);
return ln->ascii;
diff --git a/html.c b/html.c
index 42af6962..010eac68 100644
--- a/html.c
+++ b/html.c
@@ -402,9 +402,6 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
continue;
esc = mandoc_escape(&p, &seq, &len);
- if (ESCAPE_ERROR == esc)
- break;
-
switch (esc) {
case ESCAPE_FONT:
case ESCAPE_FONTPREV:
@@ -422,6 +419,8 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
case ESCAPE_SKIPCHAR:
h->flags |= HTML_SKIPCHAR;
continue;
+ case ESCAPE_ERROR:
+ continue;
default:
break;
}
@@ -446,6 +445,9 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
if (c <= 0)
continue;
break;
+ case ESCAPE_UNDEF:
+ c = *seq;
+ break;
case ESCAPE_DEVICE:
print_word(h, "html");
continue;
diff --git a/mandoc.1 b/mandoc.1
index 91b3003f..7aeaa0b6 100644
--- a/mandoc.1
+++ b/mandoc.1
@@ -1676,7 +1676,8 @@ Start it on a new input line to help formatters produce correct spacing.
.It Sy "invalid escape sequence"
.Pq roff
An escape sequence has an invalid opening argument delimiter, lacks the
-closing argument delimiter, or the argument has too few characters.
+closing argument delimiter, the argument is of an invalid form, or it is
+a character escape sequence with an invalid name.
If the argument is incomplete,
.Ic \e*
and
@@ -1689,6 +1690,12 @@ and
.Ic \ew
to the length of the incomplete argument.
All other invalid escape sequences are ignored.
+.It Sy "undefined escape, printing literally"
+.Pq roff
+In an escape sequence, the first character
+right after the leading backslash is invalid.
+That character is printed literally,
+which is equivalent to ignoring the backslash.
.It Sy "undefined string, using \(dq\(dq"
.Pq roff
If a string is used without being defined before,
@@ -2154,6 +2161,13 @@ implementations but not by
.Nm
was found in an input file.
It is replaced by a question mark.
+.It Sy "unsupported escape sequence"
+.Pq roff
+An input file contains an escape sequence supported by GNU troff
+or Heirloom troff but not by
+.Nm ,
+and it is likely that this will cause information loss
+or considerable misformatting.
.It Sy "unsupported roff request"
.Pq roff
An input file contains a
diff --git a/mandoc.c b/mandoc.c
index c20fe33c..aec05f73 100644
--- a/mandoc.c
+++ b/mandoc.c
@@ -56,6 +56,14 @@ mandoc_escape(const char **end, const char **start, int *sz)
sz = &local_sz;
/*
+ * Treat "\E" just like "\";
+ * it only makes a difference in copy mode.
+ */
+
+ if (**end == 'E')
+ ++*end;
+
+ /*
* Beyond the backslash, at least one input character
* is part of the escape sequence. With one exception
* (see below), that character won't be returned.
@@ -77,6 +85,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
*sz = 2;
break;
case '[':
+ if (**start == ' ') {
+ ++*end;
+ return ESCAPE_ERROR;
+ }
gly = ESCAPE_SPECIAL;
term = ']';
break;
@@ -91,11 +103,26 @@ mandoc_escape(const char **end, const char **start, int *sz)
/*
* Escapes taking no arguments at all.
*/
- case 'd':
- case 'u':
+ case '!':
+ case '?':
+ return ESCAPE_UNSUPP;
+ case '%':
+ case '&':
+ case ')':
case ',':
case '/':
+ case '^':
+ case 'a':
+ case 'd':
+ case 'r':
+ case 't':
+ case 'u':
+ case '{':
+ case '|':
+ case '}':
return ESCAPE_IGNORE;
+ case 'c':
+ return ESCAPE_NOSPACE;
case 'p':
return ESCAPE_BREAK;
@@ -113,28 +140,46 @@ mandoc_escape(const char **end, const char **start, int *sz)
* 'X' is the trigger. These have opaque sub-strings.
*/
case 'F':
+ case 'f':
case 'g':
case 'k':
case 'M':
case 'm':
case 'n':
+ case 'O':
case 'V':
case 'Y':
- gly = ESCAPE_IGNORE;
- /* FALLTHROUGH */
- case 'f':
- if (ESCAPE_ERROR == gly)
- gly = ESCAPE_FONT;
+ gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE;
switch (**start) {
case '(':
+ if ((*start)[-1] == 'O')
+ gly = ESCAPE_ERROR;
*start = ++*end;
*sz = 2;
break;
case '[':
+ if ((*start)[-1] == 'O')
+ gly = (*start)[1] == '5' ?
+ ESCAPE_UNSUPP : ESCAPE_ERROR;
*start = ++*end;
term = ']';
break;
default:
+ if ((*start)[-1] == 'O') {
+ switch (**start) {
+ case '0':
+ gly = ESCAPE_UNSUPP;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ break;
+ default:
+ gly = ESCAPE_ERROR;
+ break;
+ }
+ }
*sz = 1;
break;
}
@@ -257,18 +302,29 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
/*
- * Anything else is assumed to be a glyph.
- * In this case, pass back the character after the backslash.
+ * Several special characters can be encoded as
+ * one-byte escape sequences without using \[].
*/
- default:
+ case ' ':
+ case '\'':
+ case '-':
+ case '.':
+ case '0':
+ case ':':
+ case '_':
+ case '`':
+ case 'e':
+ case '~':
gly = ESCAPE_SPECIAL;
+ /* FALLTHROUGH */
+ default:
+ if (gly == ESCAPE_ERROR)
+ gly = ESCAPE_UNDEF;
*start = --*end;
*sz = 1;
break;
}
- assert(ESCAPE_ERROR != gly);
-
/*
* Read up to the terminating character,
* paying attention to nested escapes.
@@ -291,6 +347,15 @@ mandoc_escape(const char **end, const char **start, int *sz)
}
}
*sz = (*end)++ - *start;
+
+ /*
+ * The file chars.c only provides one common list
+ * of character names, but \[-] == \- is the only
+ * one of the characters with one-byte names that
+ * allows enclosing the name in brackets.
+ */
+ if (gly == ESCAPE_SPECIAL && *sz == 1 && **start != '-')
+ return ESCAPE_ERROR;
} else {
assert(*sz > 0);
if ((size_t)*sz > strlen(*start))
@@ -346,10 +411,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
case ESCAPE_SPECIAL:
if (**start == 'c') {
- if (*sz == 1) {
- gly = ESCAPE_NOSPACE;
- break;
- }
if (*sz < 6 || *sz > 7 ||
strncmp(*start, "char", 4) != 0 ||
(int)strspn(*start + 4, "0123456789") + 4 < *sz)
@@ -431,6 +492,7 @@ mandoc_getarg(char **cpp, int ln, int *pos)
* backslashes and backslash-t to literal tabs.
*/
switch (cp[1]) {
+ case 'a':
case 't':
cp[0] = '\t';
/* FALLTHROUGH */
diff --git a/mandoc.h b/mandoc.h
index 2a601b0c..657e5c5c 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -169,6 +169,7 @@ enum mandocerr {
MANDOCERR_FI_TAB, /* tab in filled text */
MANDOCERR_EOS, /* new sentence, new line */
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
+ MANDOCERR_ESC_UNDEF, /* undefined escape, printing literally: char */
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
/* related to tables */
@@ -231,6 +232,7 @@ enum mandocerr {
MANDOCERR_TOOLARGE, /* input too large */
MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
+ MANDOCERR_ESC_UNSUPP, /* unsupported escape sequence: escape */
MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
MANDOCERR_WHILE_NEST, /* nested .while loops */
MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */
@@ -245,7 +247,9 @@ enum mandocerr {
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
+ ESCAPE_UNSUPP, /* unsupported escape; ignore it */
ESCAPE_IGNORE, /* escape to be ignored */
+ ESCAPE_UNDEF, /* undefined escape; print literal character */
ESCAPE_SPECIAL, /* a regular special character */
ESCAPE_FONT, /* a generic font mode */
ESCAPE_FONTBOLD, /* bold font mode */
diff --git a/mandoc_char.7 b/mandoc_char.7
index d57c519a..3320b9aa 100644
--- a/mandoc_char.7
+++ b/mandoc_char.7
@@ -2,7 +2,7 @@
.\"
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2011, 2013, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2011,2013,2015,2017,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
@@ -266,11 +266,13 @@ Spacing:
.It Em Input Ta Em Description
.It Sq \e\ \& Ta unpaddable non-breaking space
.It \e\(ti Ta paddable non-breaking space
-.It \e0 Ta unpaddable, breaking digit-width space
+.It \e0 Ta digit-width space allowing line break
.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode
.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff
-.It \e& Ta zero-width space
+.It \e& Ta zero-width non-breaking space
+.It \e) Ta zero-width space transparent to end-of-sentence detection
.It \e% Ta zero-width space allowing hyphenation
+.It \e: Ta zero-width space allowing line break
.El
.Pp
Lines:
diff --git a/mandoc_msg.c b/mandoc_msg.c
index d2ccb91f..b49555d1 100644
--- a/mandoc_msg.c
+++ b/mandoc_msg.c
@@ -167,6 +167,7 @@ static const char *const type_message[MANDOCERR_MAX] = {
"tab in filled text",
"new sentence, new line",
"invalid escape sequence",
+ "undefined escape, printing literally",
"undefined string, using \"\"",
/* related to tables */
@@ -228,6 +229,7 @@ static const char *const type_message[MANDOCERR_MAX] = {
"unsupported feature",
"input too large",
"unsupported control character",
+ "unsupported escape sequence",
"unsupported roff request",
"nested .while loops",
"end of scope with open .while loop",
diff --git a/mdoc_man.c b/mdoc_man.c
index ce337acd..48c59a1b 100644
--- a/mdoc_man.c
+++ b/mdoc_man.c
@@ -325,6 +325,7 @@ man_strlen(const char *cp)
case ESCAPE_UNICODE:
case ESCAPE_NUMBERED:
case ESCAPE_SPECIAL:
+ case ESCAPE_UNDEF:
case ESCAPE_OVERSTRIKE:
if (skip)
skip = 0;
diff --git a/mdoc_markdown.c b/mdoc_markdown.c
index b5a856a1..07a5f907 100644
--- a/mdoc_markdown.c
+++ b/mdoc_markdown.c
@@ -589,6 +589,9 @@ md_word(const char *s)
case ESCAPE_SPECIAL:
uc = mchars_spec2cp(seq, sz);
break;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
case ESCAPE_DEVICE:
md_rawword("markdown");
continue;
diff --git a/regress/char/accent/Makefile b/regress/char/accent/Makefile
index 4bc149a7..3712217e 100644
--- a/regress/char/accent/Makefile
+++ b/regress/char/accent/Makefile
@@ -3,5 +3,6 @@
REGRESS_TARGETS = nocombine utf8only combine
SKIP_ASCII = utf8only combine
UTF8_TARGETS = nocombine utf8only combine
+LINT_TARGETS = nocombine
.include <bsd.regress.mk>
diff --git a/regress/char/accent/nocombine.in b/regress/char/accent/nocombine.in
index a81d446b..637d337e 100644
--- a/regress/char/accent/nocombine.in
+++ b/regress/char/accent/nocombine.in
@@ -1,17 +1,17 @@
.\" $OpenBSD: nocombine.in,v 1.2 2017/07/04 14:53:23 schwarze Exp $
-.TH CHAR-ACCENT-NOCOMBINE 1 "March 8, 2014"
+.TH CHAR-ACCENT-NOCOMBINE 1 "December 15, 2018"
.SH NAME
\fBchar-accent-nocombine\fR - non-combining accents
.SH DESCRIPTION
bare acute accent: e'e
.br
-escaped acute accent: e\'e
+escaped acute accent: e\'e\[']e
.br
acute accent sequence: e\(aae
.br
bare grave accent: e`e
.br
-escaped grave accent: e\`e
+escaped grave accent: e\`e\[`]e
.br
acute grave sequence: e\(gae
.br
@@ -20,15 +20,15 @@ hungarian umlaut: e\(a"e
.\" XXX This is ridiculous.
.\" XXX groff prints the macron as an underscore in the previous line.
.\" macron: e\(a-e
-.br
+.\" .br
.\" XXX groff doesn't have a dot in ASCII mode, only in UTF-8 mode.
.\" dotted: e\(a.e
-.br
+.\" .br
circumflex: e\(a^e
.br
.\" XXX groff uses a backspace for this one in ASCII mode.
.\" breve: e\(abe
-.br
+.\" .br
cedilla: e\(ace
.br
dieresis: e\(ade
diff --git a/regress/char/accent/nocombine.out_ascii b/regress/char/accent/nocombine.out_ascii
index bc1cce15..0f18ac4a 100644
--- a/regress/char/accent/nocombine.out_ascii
+++ b/regress/char/accent/nocombine.out_ascii
@@ -7,10 +7,10 @@ NNAAMMEE
DDEESSCCRRIIPPTTIIOONN
bare acute accent: e'e
- escaped acute accent: e'e
+ escaped acute accent: e'ee
acute accent sequence: e'e
bare grave accent: e`e
- escaped grave accent: e`e
+ escaped grave accent: e`ee
acute grave sequence: e`e
hungarian umlaut: e"e
circumflex: e^e
@@ -25,4 +25,4 @@ DDEESSCCRRIIPPTTIIOONN
-OpenBSD March 8, 2014 CHAR-ACCENT-NOCOMBINE(1)
+OpenBSD December 15, 2018 CHAR-ACCENT-NOCOMBINE(1)
diff --git a/regress/char/accent/nocombine.out_lint b/regress/char/accent/nocombine.out_lint
new file mode 100644
index 00000000..c9de4162
--- /dev/null
+++ b/regress/char/accent/nocombine.out_lint
@@ -0,0 +1,2 @@
+mandoc: nocombine.in:8:27: WARNING: invalid escape sequence: \[']
+mandoc: nocombine.in:14:27: WARNING: invalid escape sequence: \[`]
diff --git a/regress/char/accent/nocombine.out_utf8 b/regress/char/accent/nocombine.out_utf8
index 3aa441a2..497bf6fd 100644
--- a/regress/char/accent/nocombine.out_utf8
+++ b/regress/char/accent/nocombine.out_utf8
@@ -7,10 +7,10 @@ NNAAMMEE
DDEESSCCRRIIPPTTIIOONN
bare acute accent: e'e
- escaped acute accent: e´e
+ escaped acute accent: e´ee
acute accent sequence: e´e
bare grave accent: e`e
- escaped grave accent: e`e
+ escaped grave accent: e`ee
acute grave sequence: e`e
hungarian umlaut: e˝e
circumflex: e^e
@@ -25,4 +25,4 @@ DDEESSCCRRIIPPTTIIOONN
-OpenBSD March 8, 2014 CHAR-ACCENT-NOCOMBINE(1)
+OpenBSD December 15, 2018 CHAR-ACCENT-NOCOMBINE(1)
diff --git a/regress/char/space/Makefile b/regress/char/space/Makefile
index b6095de3..50c81c4a 100644
--- a/regress/char/space/Makefile
+++ b/regress/char/space/Makefile
@@ -3,11 +3,12 @@
REGRESS_TARGETS = leading-mdoc leading-man multiple trailing-mdoc zerowidth
REGRESS_TARGETS += eos eos-man break nobreak
REGRESS_TARGETS += tab tab-man esct-mdoc esct-man
+REGRESS_TARGETS += invalid
UTF8_TARGETS = zerowidth
HTML_TARGETS = zerowidth
-LINT_TARGETS = trailing-mdoc tab tab-man esct-mdoc esct-man
+LINT_TARGETS = trailing-mdoc tab tab-man esct-mdoc esct-man invalid
.include <bsd.regress.mk>
diff --git a/regress/char/space/esct-man.in b/regress/char/space/esct-man.in
index e7afeefe..f290d9e2 100644
--- a/regress/char/space/esct-man.in
+++ b/regress/char/space/esct-man.in
@@ -1,5 +1,5 @@
.\" $OpenBSD: esct-man.in,v 1.2 2017/07/04 14:53:23 schwarze Exp $
-.TH SPACE-ESCT-MAN 1 2013-06-20
+.TH SPACE-ESCT-MAN 1 "December 15, 2018"
.SH NAME
SPACE-T-MAN \- the t escape sequence in pages with man macros
.SH DESCRIPTION
@@ -9,10 +9,14 @@ single tab
.br
single\tescape-t
.br
+single\aescape-a
+.br
double tab
.br
double\t\tescape-t
.br
+double\a\aescape-a
+.br
\tThis line starts with escape-t and comes close to the right margin.
\tThe next line starts with escape-t as well.
.sp
@@ -20,8 +24,10 @@ In a literal display:
.nf
single tab
single\tescape-t
+single\aescape-a
double tab
double\t\tescape-t
+double\a\aescape-a
.fi
.sp
After the IP macro:
@@ -29,7 +35,13 @@ After the IP macro:
text
.IP single\tescape-t 3n
text
+.\" XXX not implemented
+.\" .IP single\aescape-a 3n
+.\" text
.PP
After font macros:
.br
.B single\ttab
+.\" XXX not implemented
+.\" .br
+.\" .B single\aleader
diff --git a/regress/char/space/esct-man.out_ascii b/regress/char/space/esct-man.out_ascii
index 29fbabea..3056cc72 100644
--- a/regress/char/space/esct-man.out_ascii
+++ b/regress/char/space/esct-man.out_ascii
@@ -9,16 +9,20 @@ DDEESSCCRRIIPPTTIIOONN
In plain text:
single tab
singleescape-t
+ singleescape-a
double tab
doubleescape-t
+ doubleescape-a
This line starts with escape-t and comes close to the right margin.
The next line starts with escape-t as well.
In a literal display:
single tab
singleescape-t
+ singleescape-a
double tab
doubleescape-t
+ doubleescape-a
After the IP macro:
@@ -33,4 +37,4 @@ DDEESSCCRRIIPPTTIIOONN
-OpenBSD 2013-06-20 SPACE-ESCT-MAN(1)
+OpenBSD December 15, 2018 SPACE-ESCT-MAN(1)
diff --git a/regress/char/space/esct-man.out_lint b/regress/char/space/esct-man.out_lint
index c625b3a3..2fa8ba9c 100644
--- a/regress/char/space/esct-man.out_lint
+++ b/regress/char/space/esct-man.out_lint
@@ -1,6 +1,6 @@
mandoc: esct-man.in:8:7: WARNING: tab in filled text
-mandoc: esct-man.in:12:7: WARNING: tab in filled text
-mandoc: esct-man.in:12:8: WARNING: tab in filled text
-mandoc: esct-man.in:28:11: WARNING: tab in filled text
-mandoc: esct-man.in:30:11: WARNING: tab in filled text
-mandoc: esct-man.in:35:10: WARNING: tab in filled text
+mandoc: esct-man.in:14:7: WARNING: tab in filled text
+mandoc: esct-man.in:14:8: WARNING: tab in filled text
+mandoc: esct-man.in:34:11: WARNING: tab in filled text
+mandoc: esct-man.in:36:11: WARNING: tab in filled text
+mandoc: esct-man.in:44:10: WARNING: tab in filled text
diff --git a/regress/char/space/invalid.in b/regress/char/space/invalid.in
new file mode 100644
index 00000000..c4692453
--- /dev/null
+++ b/regress/char/space/invalid.in
@@ -0,0 +1,15 @@
+.\" $OpenBSD$
+.TH SPACE-INVALID 1 "December 15, 2018"
+.SH NAME
+SPACE-INVALID \- invalid whitespace escape sequences
+.SH DESCRIPTION
+.nf
+blank: a\[hy]b\[ hy]c
+percent: a\%b\[%]c
+ampersand: a\&b\[&]c
+colon: a\:b\[:]c
+caret: a\^b\[^]c
+underline: a\_b\[_]c
+pipe: a\|b\[|]c
+tilde: a\~b\[~]c
+digit-width: a\0b\[0]c
diff --git a/regress/char/space/invalid.out_ascii b/regress/char/space/invalid.out_ascii
new file mode 100644
index 00000000..bf3b5a16
--- /dev/null
+++ b/regress/char/space/invalid.out_ascii
@@ -0,0 +1,21 @@
+SPACE-INVALID(1) General Commands Manual SPACE-INVALID(1)
+
+
+
+NNAAMMEE
+ SPACE-INVALID - invalid whitespace escape sequences
+
+DDEESSCCRRIIPPTTIIOONN
+ blank: a-bhy]c
+ percent: abc
+ ampersand: abc
+ colon: abc
+ caret: abc
+ underline: a_bc
+ pipe: abc
+ tilde: a bc
+ digit-width: a bc
+
+
+
+OpenBSD December 15, 2018 SPACE-INVALID(1)
diff --git a/regress/char/space/invalid.out_lint b/regress/char/space/invalid.out_lint
new file mode 100644
index 00000000..c05ef38f
--- /dev/null
+++ b/regress/char/space/invalid.out_lint
@@ -0,0 +1,9 @@
+mandoc: invalid.in:7:15: WARNING: invalid escape sequence: \[
+mandoc: invalid.in:8:14: WARNING: invalid escape sequence: \[%]
+mandoc: invalid.in:9:16: WARNING: invalid escape sequence: \[&]
+mandoc: invalid.in:10:12: WARNING: invalid escape sequence: \[:]
+mandoc: invalid.in:11:12: WARNING: invalid escape sequence: \[^]
+mandoc: invalid.in:12:16: WARNING: invalid escape sequence: \[_]
+mandoc: invalid.in:13:11: WARNING: invalid escape sequence: \[|]
+mandoc: invalid.in:14:12: WARNING: invalid escape sequence: \[~]
+mandoc: invalid.in:15:18: WARNING: invalid escape sequence: \[0]
diff --git a/regress/roff/esc/Makefile b/regress/roff/esc/Makefile
index 32589479..74f153d5 100644
--- a/regress/roff/esc/Makefile
+++ b/regress/roff/esc/Makefile
@@ -1,6 +1,7 @@
# $OpenBSD: Makefile,v 1.11 2015/04/29 18:32:57 schwarze Exp $
-REGRESS_TARGETS = one two multi B c c_man e f h l o p w z ignore
-LINT_TARGETS = B h l w ignore
+REGRESS_TARGETS = one two multi B c c_man e f h l O o p w z
+REGRESS_TARGETS += ignore invalid unsupp
+LINT_TARGETS = B h l O w ignore invalid unsupp
.include <bsd.regress.mk>
diff --git a/regress/roff/esc/O.in b/regress/roff/esc/O.in
new file mode 100644
index 00000000..d446ebb6
--- /dev/null
+++ b/regress/roff/esc/O.in
@@ -0,0 +1,15 @@
+.\" $OpenBSD$
+.TH ESC-O 1 "December 15, 2018"
+.SH NAME
+esc-O \- escape sequence to suppress output
+.SH DESCRIPTION
+.nf
+O1: a\O1b
+O2: a\O2b
+O3: a\O3b
+O4: a\O4b
+O5: a\O5b
+O52: a\O(52b
+O5n: a\O[5dummy]b
+O6: a\O6b
+O0: a\O0\&\O1b
diff --git a/regress/roff/esc/O.out_ascii b/regress/roff/esc/O.out_ascii
new file mode 100644
index 00000000..d2e5668c
--- /dev/null
+++ b/regress/roff/esc/O.out_ascii
@@ -0,0 +1,21 @@
+ESC-O(1) General Commands Manual ESC-O(1)
+
+
+
+NNAAMMEE
+ esc-O - escape sequence to suppress output
+
+DDEESSCCRRIIPPTTIIOONN
+ O1: ab
+ O2: ab
+ O3: ab
+ O4: ab
+ O5: ab
+ O52: ab
+ O5n: ab
+ O6: ab
+ O0: ab
+
+
+
+OpenBSD December 15, 2018 ESC-O(1)
diff --git a/regress/roff/esc/O.out_lint b/regress/roff/esc/O.out_lint
new file mode 100644
index 00000000..ee91008d
--- /dev/null
+++ b/regress/roff/esc/O.out_lint
@@ -0,0 +1,5 @@
+mandoc: O.in:11:6: WARNING: invalid escape sequence: \O5
+mandoc: O.in:12:7: WARNING: invalid escape sequence: \O(52
+mandoc: O.in:13:7: UNSUPP: unsupported escape sequence: \O[5dummy]
+mandoc: O.in:14:6: WARNING: invalid escape sequence: \O6
+mandoc: O.in:15:6: UNSUPP: unsupported escape sequence: \O0
diff --git a/regress/roff/esc/ignore.in b/regress/roff/esc/ignore.in
index 6ba7cccc..48507f44 100644
--- a/regress/roff/esc/ignore.in
+++ b/regress/roff/esc/ignore.in
@@ -1,15 +1,13 @@
.\" $OpenBSD: ignore.in,v 1.3 2017/07/04 14:53:27 schwarze Exp $
-.Dd $Mdocdate$
-.Dt ESC-IGNORE 1
-.Os
-.Sh NAME
-.Nm esc-ignore
-.Nd ignored roff escape sequences
-.Sh DESCRIPTION
+.TH ESC-IGNORE 1 "December 15, 2018"
+.SH NAME
+esc-ignore \- ignored roff escape sequences
+.SH DESCRIPTION
+.nf
+closing parenthesis: a\)b\[)]c
+comma: a\,b\[,]c
+slash: a\/b\[/]c
multiform: a\kxb\k(xyc\k[xyz]d
-.br
quoted: a\R'myreg 0'b\R'myreg \A'y'0'c
-.br
sizes: a\s0b\s(12c\s[123]d\s'123'e\s'1\w'xy'2'f
-.br
signed sizes: a\s-0b\s-(12c\s-[123]d\s-'123'e\s-'1\w'xy'2'f\s-
diff --git a/regress/roff/esc/ignore.out_ascii b/regress/roff/esc/ignore.out_ascii
index fa16f389..eaee36c0 100644
--- a/regress/roff/esc/ignore.out_ascii
+++ b/regress/roff/esc/ignore.out_ascii
@@ -1,12 +1,19 @@
ESC-IGNORE(1) General Commands Manual ESC-IGNORE(1)
+
+
NNAAMMEE
- eesscc--iiggnnoorree - ignored roff escape sequences
+ esc-ignore - ignored roff escape sequences
DDEESSCCRRIIPPTTIIOONN
- multiform: abcd
- quoted: abc
- sizes: abcdef
- signed sizes: abcdef
+ closing parenthesis: abc
+ comma: abc
+ slash: abc
+ multiform: abcd
+ quoted: abc
+ sizes: abcdef
+ signed sizes: abcdef
+
+
-OpenBSD July 4, 2017 OpenBSD
+OpenBSD December 15, 2018 ESC-IGNORE(1)
diff --git a/regress/roff/esc/ignore.out_lint b/regress/roff/esc/ignore.out_lint
index 95eba933..0f33c929 100644
--- a/regress/roff/esc/ignore.out_lint
+++ b/regress/roff/esc/ignore.out_lint
@@ -1 +1,4 @@
-mandoc: ignore.in:15:60: WARNING: invalid escape sequence: \s-
+mandoc: ignore.in:7:26: WARNING: invalid escape sequence: \[)]
+mandoc: ignore.in:8:12: WARNING: invalid escape sequence: \[,]
+mandoc: ignore.in:9:12: WARNING: invalid escape sequence: \[/]
+mandoc: ignore.in:13:60: WARNING: invalid escape sequence: \s-
diff --git a/regress/roff/esc/invalid.in b/regress/roff/esc/invalid.in
new file mode 100644
index 00000000..b2e77159
--- /dev/null
+++ b/regress/roff/esc/invalid.in
@@ -0,0 +1,28 @@
+.\" $OpenBSD$
+.TH ESC-INVALID 1 "December 15, 2018"
+.SH NAME
+esc-invalid \- invalid roff escape sequences
+.SH DESCRIPTION
+.nf
+plus: a\+b\[+]c
+semicolon: a\;b\[;]c
+less than: a\<b\[<]c
+equal to: a\=b\[=]c
+greater than: a\>b\[>]c
+at: a\@b\[@]c
+square bracket: a\]b
+curly braces: a\[{]b\[}]c
+digit: a\1b\[1]c
+G: a\Gb\[G]c
+I: a\Ib\[I]c
+i: a\ib\[i]c
+J: a\Jb\[J]c
+j: a\jb\[j]c
+K: a\Kb\[K]c
+P: a\Pb\[P]c
+Q: a\Qb\[Q]c
+q: a\qb\[q]c
+T: a\Tb\[T]c
+U: a\Ub\[U]c
+W: a\Wb\[W]c
+y: a\yb\[y]c
diff --git a/regress/roff/esc/invalid.out_ascii b/regress/roff/esc/invalid.out_ascii
new file mode 100644
index 00000000..24915262
--- /dev/null
+++ b/regress/roff/esc/invalid.out_ascii
@@ -0,0 +1,34 @@
+ESC-INVALID(1) General Commands Manual ESC-INVALID(1)
+
+
+
+NNAAMMEE
+ esc-invalid - invalid roff escape sequences
+
+DDEESSCCRRIIPPTTIIOONN
+ plus: a+bc
+ semicolon: a;bc
+ less than: a<bc
+ equal to: a=bc
+ greater than: a>bc
+ at: a@bc
+ square bracket: a]b
+ curly braces: abc
+ digit: a1bc
+ G: aGbc
+ I: aIbc
+ i: aibc
+ J: aJbc
+ j: ajbc
+ K: aKbc
+ P: aPbc
+ Q: aQbc
+ q: aqbc
+ T: aTbc
+ U: aUbc
+ W: aWbc
+ y: aybc
+
+
+
+OpenBSD December 15, 2018 ESC-INVALID(1)
diff --git a/regress/roff/esc/invalid.out_lint b/regress/roff/esc/invalid.out_lint
new file mode 100644
index 00000000..a0afa7ae
--- /dev/null
+++ b/regress/roff/esc/invalid.out_lint
@@ -0,0 +1,43 @@
+mandoc: invalid.in:7:11: WARNING: invalid escape sequence: \[+]
+mandoc: invalid.in:7:8: WARNING: undefined escape, printing literally: \+
+mandoc: invalid.in:8:16: WARNING: invalid escape sequence: \[;]
+mandoc: invalid.in:8:13: WARNING: undefined escape, printing literally: \;
+mandoc: invalid.in:9:16: WARNING: invalid escape sequence: \[<]
+mandoc: invalid.in:9:13: WARNING: undefined escape, printing literally: \<
+mandoc: invalid.in:10:15: WARNING: invalid escape sequence: \[=]
+mandoc: invalid.in:10:12: WARNING: undefined escape, printing literally: \=
+mandoc: invalid.in:11:19: WARNING: invalid escape sequence: \[>]
+mandoc: invalid.in:11:16: WARNING: undefined escape, printing literally: \>
+mandoc: invalid.in:12:9: WARNING: invalid escape sequence: \[@]
+mandoc: invalid.in:12:6: WARNING: undefined escape, printing literally: \@
+mandoc: invalid.in:13:18: WARNING: undefined escape, printing literally: \]
+mandoc: invalid.in:14:21: WARNING: invalid escape sequence: \[}]
+mandoc: invalid.in:14:16: WARNING: invalid escape sequence: \[{]
+mandoc: invalid.in:15:12: WARNING: invalid escape sequence: \[1]
+mandoc: invalid.in:15:9: WARNING: undefined escape, printing literally: \1
+mandoc: invalid.in:16:8: WARNING: invalid escape sequence: \[G]
+mandoc: invalid.in:16:5: WARNING: undefined escape, printing literally: \G
+mandoc: invalid.in:17:8: WARNING: invalid escape sequence: \[I]
+mandoc: invalid.in:17:5: WARNING: undefined escape, printing literally: \I
+mandoc: invalid.in:18:8: WARNING: invalid escape sequence: \[i]
+mandoc: invalid.in:18:5: WARNING: undefined escape, printing literally: \i
+mandoc: invalid.in:19:8: WARNING: invalid escape sequence: \[J]
+mandoc: invalid.in:19:5: WARNING: undefined escape, printing literally: \J
+mandoc: invalid.in:20:8: WARNING: invalid escape sequence: \[j]
+mandoc: invalid.in:20:5: WARNING: undefined escape, printing literally: \j
+mandoc: invalid.in:21:8: WARNING: invalid escape sequence: \[K]
+mandoc: invalid.in:21:5: WARNING: undefined escape, printing literally: \K
+mandoc: invalid.in:22:8: WARNING: invalid escape sequence: \[P]
+mandoc: invalid.in:22:5: WARNING: undefined escape, printing literally: \P
+mandoc: invalid.in:23:8: WARNING: invalid escape sequence: \[Q]
+mandoc: invalid.in:23:5: WARNING: undefined escape, printing literally: \Q
+mandoc: invalid.in:24:8: WARNING: invalid escape sequence: \[q]
+mandoc: invalid.in:24:5: WARNING: undefined escape, printing literally: \q
+mandoc: invalid.in:25:8: WARNING: invalid escape sequence: \[T]
+mandoc: invalid.in:25:5: WARNING: undefined escape, printing literally: \T
+mandoc: invalid.in:26:8: WARNING: invalid escape sequence: \[U]
+mandoc: invalid.in:26:5: WARNING: undefined escape, printing literally: \U
+mandoc: invalid.in:27:8: WARNING: invalid escape sequence: \[W]
+mandoc: invalid.in:27:5: WARNING: undefined escape, printing literally: \W
+mandoc: invalid.in:28:8: WARNING: invalid escape sequence: \[y]
+mandoc: invalid.in:28:5: WARNING: undefined escape, printing literally: \y
diff --git a/regress/roff/esc/one.in b/regress/roff/esc/one.in
index 910714d1..6a4b22a8 100644
--- a/regress/roff/esc/one.in
+++ b/regress/roff/esc/one.in
@@ -1,17 +1,11 @@
.\" $OpenBSD: one.in,v 1.3 2017/07/04 14:53:27 schwarze Exp $
-.Dd $Mdocdate$
-.Dt ESC-ONE 1
-.Os
-.Sh NAME
-.Nm esc-one
-.Nd roff one-character escape sequences
-.Sh DESCRIPTION
+.TH ESC-ONE 1 "December 15, 2018"
+.SH NAME
+esc-one \- roff one-character escape sequences
+.SH DESCRIPTION
+.nf
backslash: >\e<
-.br
-minus: >\-<
-.br
+minus: >\-|\[-]<
acute: >\'<
-.br
grave: >\`<
-.br
normal character: >\q<
diff --git a/regress/roff/esc/one.out_ascii b/regress/roff/esc/one.out_ascii
index bc88dcf2..1eb5f1f2 100644
--- a/regress/roff/esc/one.out_ascii
+++ b/regress/roff/esc/one.out_ascii
@@ -1,13 +1,17 @@
ESC-ONE(1) General Commands Manual ESC-ONE(1)
+
+
NNAAMMEE
- eesscc--oonnee - roff one-character escape sequences
+ esc-one - roff one-character escape sequences
DDEESSCCRRIIPPTTIIOONN
- backslash: >\<
- minus: >-<
- acute: >'<
- grave: >`<
- normal character: >q<
+ backslash: >\<
+ minus: >-|-<
+ acute: >'<
+ grave: >`<
+ normal character: >q<
+
+
-OpenBSD July 4, 2017 OpenBSD
+OpenBSD December 15, 2018 ESC-ONE(1)
diff --git a/regress/roff/esc/unsupp.in b/regress/roff/esc/unsupp.in
new file mode 100644
index 00000000..819f6c33
--- /dev/null
+++ b/regress/roff/esc/unsupp.in
@@ -0,0 +1,8 @@
+.\" $OpenBSD$
+.TH ESC-UNSUPP 1 "December 15, 2018"
+.SH NAME
+esc-unsupp \- unsupported escape sequences
+.SH DESCRIPTION
+.nf
+exclamation mark: a\!b\[!]c
+question mark: a\?\&\?b\[?]c
diff --git a/regress/roff/esc/unsupp.out_ascii b/regress/roff/esc/unsupp.out_ascii
new file mode 100644
index 00000000..22613e54
--- /dev/null
+++ b/regress/roff/esc/unsupp.out_ascii
@@ -0,0 +1,14 @@
+ESC-UNSUPP(1) General Commands Manual ESC-UNSUPP(1)
+
+
+
+NNAAMMEE
+ esc-unsupp - unsupported escape sequences
+
+DDEESSCCRRIIPPTTIIOONN
+ exclamation mark: abc
+ question mark: abc
+
+
+
+OpenBSD December 15, 2018 ESC-UNSUPP(1)
diff --git a/regress/roff/esc/unsupp.out_lint b/regress/roff/esc/unsupp.out_lint
new file mode 100644
index 00000000..d3cc4bf1
--- /dev/null
+++ b/regress/roff/esc/unsupp.out_lint
@@ -0,0 +1,5 @@
+mandoc: unsupp.in:7:23: WARNING: invalid escape sequence: \[!]
+mandoc: unsupp.in:7:20: UNSUPP: unsupported escape sequence: \!
+mandoc: unsupp.in:8:24: WARNING: invalid escape sequence: \[?]
+mandoc: unsupp.in:8:21: UNSUPP: unsupported escape sequence: \?
+mandoc: unsupp.in:8:17: UNSUPP: unsupported escape sequence: \?
diff --git a/roff.7 b/roff.7
index dfe52f42..66b7da90 100644
--- a/roff.7
+++ b/roff.7
@@ -1844,6 +1844,11 @@ The escape sequence backslash-space
.Pq Sq \e\ \&
is an unpaddable space-sized non-breaking space character; see
.Sx Whitespace .
+.It Ic \e!
+Embed text up to and including the end of the input line into the
+current diversion or into intermediate output without interpreting
+requests, macros, and escapes.
+Currently unsupported.
.It Ic \e\(dq
The rest of the input line is treated as
.Sx Comments .
@@ -1870,6 +1875,10 @@ instead.
.Sx Special Characters
with two-letter names, see
.Xr mandoc_char 7 .
+.It Ic \e)
+Zero-width space transparent to end-of-sentence detection;
+ignored by
+.Xr mandoc 1 .
.It Ic \e*[ Ns Ar name Ns Ic \&]
Interpolate the string with the
.Ar name .
@@ -1907,6 +1916,15 @@ Special character
.It Ic \e/
Right italic correction (groff extension); ignored by
.Xr mandoc 1 .
+.It Ic \e:
+Breaking the line is allowed at this point of the word
+without inserting a hyphen.
+.It Ic \e?
+Embed the text up to the next
+.Ic \e?
+into the current diversion without interpreting requests, macros,
+and escapes.
+This is a groff extension and currently unsupported.
.It Ic \e[ Ns Ar name Ns Ic \&]
.Sx Special Characters
with names of arbitrary length, see
@@ -1914,6 +1932,10 @@ with names of arbitrary length, see
.It Ic \e^
One-twelfth em half-narrow space character, effectively zero-width in
.Xr mandoc 1 .
+.It Ic \e_
+Underline special character; use
+.Ic \e(ul
+instead.
.It Ic \e`
Grave accent special character; use
.Ic \e(ga
@@ -1934,6 +1956,9 @@ Digit width space character.
.It Ic \eA\(aq Ns Ar string Ns Ic \(aq
Anchor definition; ignored by
.Xr mandoc 1 .
+.It Ic \ea
+Leader character; ignored by
+.Xr mandoc 1 .
.It Ic \eB\(aq Ns Ar string Ns Ic \(aq
Interpolate
.Sq 1
@@ -1961,6 +1986,13 @@ Draw graphics function; ignored by
.It Ic \ed
Move down by half a line; ignored by
.Xr mandoc 1 .
+.It Ic \eE
+Escape character intended to not be interpreted in copy mode.
+In
+.Xr mandoc 1 ,
+it does the same as
+.Ic \e
+itself for now.
.It Ic \ee
Backslash special character.
.It Ic \eF[ Ns Ar name Ns Ic \&]
@@ -2042,6 +2074,14 @@ the register is first incremented or decremented by the
that was specified in the relevant
.Ic \&nr
request, and the changed value is interpolated.
+.It Ic \eO Ns Ar digit , Ic \eO[5 Ns arguments Ns Ic \&]
+Suppress output.
+This is a groff extension and currently unsupported.
+With an argument of
+.Ic 1 , 2 , 3 ,
+or
+.Ic 4 ,
+it is ignored.
.It Ic \eo\(aq Ns Ar string Ns Ic \(aq
Overstrike, writing all the characters contained in the
.Ar string
@@ -2053,6 +2093,9 @@ Break the output line at the end of the current word.
.It Ic \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns Ic \(aq
Set number register; ignored by
.Xr mandoc 1 .
+.It Ic \er
+Move up by one line; ignored by
+.Xr mandoc 1 .
.It Ic \eS\(aq Ns Ar number Ns Ic \(aq
Slant output; ignored by
.Xr mandoc 1 .
diff --git a/roff.c b/roff.c
index 99d33c84..02dae757 100644
--- a/roff.c
+++ b/roff.c
@@ -1154,6 +1154,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
struct roff_node *n; /* used for header comments */
const char *start; /* start of the string to process */
char *stesc; /* start of an escape sequence ('\\') */
+ const char *esct; /* type of esccape sequence */
char *ep; /* end of comment string */
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
@@ -1163,7 +1164,6 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
size_t naml; /* actual length of the escape name */
size_t asz; /* length of the replacement */
size_t rsz; /* length of the rest of the string */
- enum mandoc_esc esc; /* type of the escape sequence */
int inaml; /* length returned from mandoc_escape() */
int expand_count; /* to avoid infinite loops */
int npos; /* position in numeric expression */
@@ -1172,6 +1172,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 */
+ enum mandocerr err; /* for escape sequence problems */
char sign; /* increment number register */
char term; /* character terminating the escape */
@@ -1304,7 +1305,10 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
term = '\0';
cp = stesc + 1;
- switch (*cp) {
+ if (*cp == 'E')
+ cp++;
+ esct = cp;
+ switch (*esct) {
case '*':
case '$':
res = NULL;
@@ -1320,12 +1324,26 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
res = ubuf;
break;
default:
- esc = mandoc_escape(&cp, &stnam, &inaml);
- if (esc == ESCAPE_ERROR ||
- (esc == ESCAPE_SPECIAL &&
- mchars_spec2cp(stnam, inaml) < 0))
- mandoc_msg(MANDOCERR_ESC_BAD,
- ln, (int)(stesc - buf->buf),
+ err = MANDOCERR_OK;
+ switch(mandoc_escape(&cp, &stnam, &inaml)) {
+ case ESCAPE_SPECIAL:
+ if (mchars_spec2cp(stnam, inaml) >= 0)
+ break;
+ /* FALLTHROUGH */
+ case ESCAPE_ERROR:
+ err = MANDOCERR_ESC_BAD;
+ break;
+ case ESCAPE_UNDEF:
+ err = MANDOCERR_ESC_UNDEF;
+ break;
+ case ESCAPE_UNSUPP:
+ err = MANDOCERR_ESC_UNSUPP;
+ break;
+ default:
+ break;
+ }
+ if (err != MANDOCERR_OK)
+ mandoc_msg(err, ln, (int)(stesc - buf->buf),
"%.*s", (int)(cp - stesc), stesc);
stesc--;
continue;
@@ -1382,7 +1400,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
cp++;
break;
}
- if (*cp++ != '\\' || stesc[1] != 'w') {
+ if (*cp++ != '\\' || *esct != 'w') {
naml++;
continue;
}
@@ -1390,6 +1408,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
case ESCAPE_SPECIAL:
case ESCAPE_UNICODE:
case ESCAPE_NUMBERED:
+ case ESCAPE_UNDEF:
case ESCAPE_OVERSTRIKE:
naml++;
break;
@@ -1403,7 +1422,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
* undefined, resume searching for escapes.
*/
- switch (stesc[1]) {
+ switch (*esct) {
case '*':
if (arg_complete) {
deftype = ROFFDEF_USER | ROFFDEF_PRE;
@@ -1430,15 +1449,15 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
break;
}
ctx = r->mstack + r->mstackpos;
- npos = stesc[2] - '1';
+ npos = esct[1] - '1';
if (npos >= 0 && npos <= 8) {
res = npos < ctx->argc ?
ctx->argv[npos] : "";
break;
}
- if (stesc[2] == '*')
+ if (esct[1] == '*')
quote_args = 0;
- else if (stesc[2] == '@')
+ else if (esct[1] == '@')
quote_args = 1;
else {
mandoc_msg(MANDOCERR_ARG_NONUM, ln,
@@ -1500,7 +1519,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
}
if (res == NULL) {
- if (stesc[1] == '*')
+ if (*esct == '*')
mandoc_msg(MANDOCERR_STR_UNDEF,
ln, (int)(stesc - buf->buf),
"%.*s", (int)naml, stnam);
diff --git a/term.c b/term.c
index 0ceb28d6..b0f6fb0d 100644
--- a/term.c
+++ b/term.c
@@ -477,9 +477,6 @@ term_word(struct termp *p, const char *word)
word++;
esc = mandoc_escape(&word, &seq, &sz);
- if (ESCAPE_ERROR == esc)
- continue;
-
switch (esc) {
case ESCAPE_UNICODE:
uc = mchars_num2uc(seq + 1, sz - 1);
@@ -500,6 +497,9 @@ term_word(struct termp *p, const char *word)
encode1(p, uc);
}
continue;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
case ESCAPE_FONTBOLD:
term_fontrepl(p, TERMFONT_BOLD);
continue;
@@ -587,6 +587,9 @@ term_word(struct termp *p, const char *word)
case ESCAPE_SPECIAL:
uc = mchars_spec2cp(cp, sz);
break;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
default:
uc = -1;
break;
@@ -845,12 +848,8 @@ term_strlen(const struct termp *p, const char *cp)
switch (*cp) {
case '\\':
cp++;
- esc = mandoc_escape(&cp, &seq, &ssz);
- if (ESCAPE_ERROR == esc)
- continue;
-
rhs = NULL;
-
+ esc = mandoc_escape(&cp, &seq, &ssz);
switch (esc) {
case ESCAPE_UNICODE:
uc = mchars_num2uc(seq + 1, ssz - 1);
@@ -871,6 +870,9 @@ term_strlen(const struct termp *p, const char *cp)
sz += cond_width(p, uc, &skip);
}
continue;
+ case ESCAPE_UNDEF:
+ uc = *seq;
+ break;
case ESCAPE_DEVICE:
if (p->type == TERMTYPE_PDF) {
rhs = "pdf";