]> git.cameronkatri.com Git - mandoc.git/commitdiff
During identifier parsing, handle undefined escape sequences
authorIngo Schwarze <schwarze@openbsd.org>
Fri, 3 Jun 2022 12:15:55 +0000 (12:15 +0000)
committerIngo Schwarze <schwarze@openbsd.org>
Fri, 3 Jun 2022 12:15:55 +0000 (12:15 +0000)
in the same way as groff:
* \\ is always reduced to \
* \. is always reduced to .
* other undefined escape sequences are usually reduced to the escape name,
for example \G to G, except during the expansion of expanding escape
sequences having the standard argument form (in particular \* and \n),
in which case the backslash is preserved literally.

Yes, this is confusing indeed.
For example, the following have the same meaning:
* .ds \.   and   .ds .     which is not the same as   .ds \\.
* \*[\.]   and   \*[.]     which is not the same as   \*[\\.]
* .ds \G   and   .ds G     which is not the same as   .ds \\G
* \*[\G]   and   \*[\\G]   which is not the same as   \*[G]   <- sic!

To feel less dirty, have a leaning toothpick, if you are so inclined.

This patch also slightly improves the string shown by the "escaped
character not allowed in a name" error message.

18 files changed:
regress/roff/args/man.out_lint
regress/roff/args/mdoc.out_lint
regress/roff/cond/register.in
regress/roff/cond/register.out_ascii
regress/roff/cond/string.in
regress/roff/cond/string.out_ascii
regress/roff/de/escname.in
regress/roff/de/escname.out_ascii
regress/roff/de/escname.out_lint
regress/roff/ds/Makefile
regress/roff/nr/escname.in
regress/roff/nr/escname.out_ascii
regress/roff/nr/escname.out_lint
regress/roff/string/Makefile
regress/roff/string/name.in
regress/roff/string/name.out_ascii
regress/roff/string/name.out_lint
roff.c

index 6d6bbd84e3d6cbb78bdfa1d116c8c1529e673f2f..5aaebd9e79fa7e0f3a633ce12ba53e7bbd5a0fe5 100644 (file)
@@ -6,4 +6,4 @@ mandoc: man.in:87:26: STYLE: whitespace at end of input line
 mandoc: man.in:91:27: STYLE: whitespace at end of input line
 mandoc: man.in:104:5: STYLE: unterminated quoted argument
 mandoc: man.in:107:9: STYLE: unterminated quoted argument
-mandoc: man.in:131:1: ERROR: escaped character not allowed in a name: IB\(
+mandoc: man.in:131:1: ERROR: escaped character not allowed in a name: IB\(lq
index 4422d754f9b9e504d5c86000822354f9bb9ee1c6..1691cf2d4cae452dc096aa9d1518a94a190c5466 100644 (file)
@@ -14,4 +14,4 @@ mandoc: mdoc.in:112:5: STYLE: unterminated quoted argument
 mandoc: mdoc.in:112:11: STYLE: whitespace at end of input line
 mandoc: mdoc.in:113:9: STYLE: unterminated quoted argument
 mandoc: mdoc.in:113:15: STYLE: whitespace at end of input line
-mandoc: mdoc.in:121:1: ERROR: escaped character not allowed in a name: Fl\(
+mandoc: mdoc.in:121:1: ERROR: escaped character not allowed in a name: Fl\(lq
index 879c573c2d91d468af2e1dc01a9f4ee9d6f91fe0..7f137c9c1671f0668748b573e68dfb9d0c6a8af2 100644 (file)
@@ -1,5 +1,5 @@
-.\" $OpenBSD: register.in,v 1.3 2019/02/06 20:54:28 schwarze Exp $
-.TH REGISTER 1 "February 6, 2019"
+.\" $OpenBSD: register.in,v 1.4 2022/06/03 11:50:25 schwarze Exp $
+.TH REGISTER 1 "June 3, 2022"
 .SH NAME
 register \- conditional testing whether a register is defined
 .SH DESCRIPTION
@@ -11,10 +11,35 @@ register \- conditional testing whether a register is defined
 .el OOPS
 .if !rmyreg OOPS
 .PP
-identifier + identifier:
+tab after identifier:
 .ie rmyreg     myreg is defined
 .el OOPS
 .PP
 escape sequence after identifier:
 .ie rmyreg\(enmyreg is defined
 .el OOPS
+.PP
+backslash in name:
+.nr \\ 0
+.ie r\\ \e is defined
+.el OOPS
+.rr \\
+.if r\\ is still defined!?
+.PP
+dot in name:
+.nr . 0
+.ie r. \&. is defined
+.el OOPS
+.ie r\. \e. is defined
+.el OOPS
+.rr \.
+.if r. is still defined!?
+.PP
+invalid escape in name:
+.nr G 0
+.ie rG G is defined
+.el OOPS
+.ie r\G \eG is defined
+.el OOPS
+.rr \G
+.if rG is still defined!?
index 928c6138289b8dd0da610089f029642f42899a99..673b9f12400d60ca2267836b498355b5e018f61c 100644 (file)
@@ -7,8 +7,14 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
        not yet defined
        now defined
 
-       identifier + identifier:      myreg is defined
+       tab after identifier:    myreg is defined
 
        escape sequence after identifier: -myreg is defined
 
-OpenBSD                        February 6, 2019                    REGISTER(1)
+       backslash in name: \ is defined
+
+       dot in name: . is defined \. is defined
+
+       invalid escape in name: G is defined \G is defined
+
+OpenBSD                          June 3, 2022                      REGISTER(1)
index 273984be9e74ed79d86a8518add1aeabf70613e0..fedb4d819303a6f5ef4ba0df761fa1a7412d3798 100644 (file)
@@ -1,5 +1,5 @@
-.\" $OpenBSD: string.in,v 1.4 2019/02/06 20:54:28 schwarze Exp $
-.TH STRING 1 "February 6, 2019"
+.\" $OpenBSD: string.in,v 1.5 2022/06/03 11:50:25 schwarze Exp $
+.TH STRING 1 "June 3, 2022"
 .SH NAME
 string \- conditional testing whether a string is defined
 .SH DESCRIPTION
@@ -40,3 +40,28 @@ identifier and tab:
 escape sequence after identifier:
 .ie d mystr\(enmystr is defined
 .el OOPS
+.PP
+backslash in name:
+.ds \\ value
+.ie d \\ \e is defined
+.el OOPS
+.rm \\
+.if d \\ still defined!?
+.PP
+dot in name:
+.ds . value
+.ie d . \&. is defined
+.el OOPS
+.ie d \. \e. is defined
+.el OOPS
+.rm .
+.if d . still defined!?
+.PP
+invalid escape in name:
+.ds G value
+.ie d G G is defined
+.el OOPS
+.ie d \G \eG is defined
+.el OOPS
+.rm \G
+.if d G still defined!?
index 2d80a9033f4535ba553e777a2312c8004b9bedae..c67c0c55a24c1a07cbe6705bc6a1a7197609549b 100644 (file)
@@ -19,4 +19,10 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
        escape sequence after identifier: -mystr is defined
 
-OpenBSD                        February 6, 2019                      STRING(1)
+       backslash in name: \ is defined
+
+       dot in name: . is defined \. is defined
+
+       invalid escape in name: G is defined \G is defined
+
+OpenBSD                          June 3, 2022                        STRING(1)
index 67d260910903eb27b4feec75536d03eb9c2e639b..99305eaf7c111b75348bf7ccaff99323ea3a473d 100644 (file)
@@ -1,5 +1,5 @@
-.\" $OpenBSD: escname.in,v 1.4 2017/07/04 14:53:27 schwarze Exp $
-.Dd $Mdocdate: July 4 2017 $
+.\" $OpenBSD: escname.in,v 1.5 2022/06/03 11:50:25 schwarze Exp $
+.Dd $Mdocdate: June 3 2022 $
 .Dt DE-ESCNAME 1
 .Os
 .Sh NAME
@@ -23,10 +23,33 @@ define first = val1
 val1
 ..
 .Pp
-Values (first, second, first\esecond):
+define first\e.second = val_dot
+.de first\.second
+val_dot
+..
+.Pp
+define first\eGsecond = val_inval
+.de first\Gsecond
+val_inval
+..
+.Pp
+Values:
+.Bl -tag -width first_.second -compact
+.It first
 .first
+.It second
 .second
+.It first\esecond
 .first\\second
+.It first.second
+.first.second
+.It first\e.second
+.first\.second
+.It firstGsecond
+.firstGsecond
+.It first\eGsecond
+.first\Gsecond
+.El
 .Pp
 Remove all but second:
 .rm first\\second first\esecond second
index 367b5d0fb2c92a42be98dd1641540f22586d25ad..e096fd71d3dc69711b7bcd305298385ac0ccd466 100644 (file)
@@ -12,7 +12,18 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
      define first = val1
 
-     Values (first, second, first\second): val1 val2 val3
+     define first\.second = val_dot
+
+     define first\Gsecond = val_inval
+
+     Values:
+     first          val1
+     second         val2
+     first\second   val3
+     first.second   val_dot
+     first\.second  val_dot
+     firstGsecond   val_inval
+     first\Gsecond  val_inval
 
      Remove all but second: val2
 
@@ -20,4 +31,4 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
      final text
 
-OpenBSD                          July 4, 2017                          OpenBSD
+OpenBSD                          June 3, 2022                          OpenBSD
index a3f9396f124e1bd9d74dd27f05a128e27a6111fb..5dba1973f3c9805ba596fff9a897fcf270875ae4 100644 (file)
@@ -1,8 +1,10 @@
 mandoc: escname.in:22:2: ERROR: escaped character not allowed in a name: first\e
-mandoc: escname.in:32:19: ERROR: escaped character not allowed in a name: first\e
-mandoc: escname.in:33:2: ERROR: skipping unknown macro: .first
-mandoc: escname.in:35:2: ERROR: skipping unknown macro: .first\\second
-mandoc: escname.in:38:5: ERROR: skipping excess arguments: .de ... excess arguments
-mandoc: escname.in:41:1: ERROR: escaped character not allowed in a name: witharg\(
-mandoc: escname.in:43:1: ERROR: escaped character not allowed in a name: de\e
-mandoc: escname.in:43:2: WARNING: skipping empty request: de
+mandoc: escname.in:32:10: WARNING: undefined escape, printing literally: \G
+mandoc: escname.in:51:7: WARNING: undefined escape, printing literally: \G
+mandoc: escname.in:55:19: ERROR: escaped character not allowed in a name: first\e
+mandoc: escname.in:56:2: ERROR: skipping unknown macro: .first
+mandoc: escname.in:58:2: ERROR: skipping unknown macro: .first\second 
+mandoc: escname.in:61:5: ERROR: skipping excess arguments: .de ... excess arguments
+mandoc: escname.in:64:1: ERROR: escaped character not allowed in a name: witharg\(en
+mandoc: escname.in:66:1: ERROR: escaped character not allowed in a name: de\e
+mandoc: escname.in:66:2: WARNING: skipping empty request: de
index 773105e8e6b1523967d01be52076a789b2f4bb75..68a8b3bf84e6fde9feb8c5ee8b3257fffa10798c 100644 (file)
@@ -1,4 +1,9 @@
-# $OpenBSD: Makefile,v 1.6 2019/02/06 20:54:28 schwarze Exp $
+# $OpenBSD: Makefile,v 1.7 2022/06/03 11:50:25 schwarze Exp $
+#
+# This directory is intended for tests of string *definitions*,
+# in particular testing the behaviour of the .ds and .as macros.
+# Tests of string *expansion* are better placed in the roff/string
+# directory.
 
 REGRESS_TARGETS = append escname nested quoting tab
 
index f81627e16f387b3f92ba762fbae727ac6011e860..d46255528c60371a7b71bdb0a4a495fb49002312 100644 (file)
@@ -1,5 +1,5 @@
-.\" $OpenBSD: escname.in,v 1.3 2017/07/04 14:53:27 schwarze Exp $
-.TH NR-ESCNAME 1 "June 29, 2014"
+.\" $OpenBSD: escname.in,v 1.4 2022/06/03 11:50:25 schwarze Exp $
+.TH NR-ESCNAME 1 "June 3, 2022"
 .SH NAME
 nr-escname \- escape sequences in register names
 .SH DESCRIPTION
@@ -7,7 +7,9 @@ nr-escname \- escape sequences in register names
 .nr second 2
 .nr first\\second 3
 .nr first\esecond 4
-\n[first] \n[second] \n[first\\second]
+.nr first\.second 5
+.nr first\Gsecond 6
+\n[first] \n[second] \n[first\\second] \n[first.second] \n[firstGsecond]
 .PP
 .rr first\esecond
 \n[first] \n[second] \n[first\\second]
index ca2d50f5c4f55ab97abfca4eee1fdf3171007c3b..d0301af91de8e22dead808f06ab24a0acb96561f 100644 (file)
@@ -4,7 +4,7 @@ N\bNA\bAM\bME\bE
        nr-escname - escape sequences in register names
 
 D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
-       1 2 3
+       1 2 3 5 6
 
        0 2 3
 
@@ -12,4 +12,4 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
        incomplete:
 
-OpenBSD                          June 29, 2014                   NR-ESCNAME(1)
+OpenBSD                          June 3, 2022                    NR-ESCNAME(1)
index a2dabebeb3e42be2075c055ff92db34481d76bb2..edec17faea4afbb03c18298a566fda1cac93bc70 100644 (file)
@@ -1,4 +1,5 @@
 mandoc: escname.in:9:5: ERROR: escaped character not allowed in a name: first\e
-mandoc: escname.in:12:5: ERROR: escaped character not allowed in a name: first\e
-mandoc: escname.in:18:13: WARNING: invalid escape sequence: \n[second
-mandoc: escname.in:18:12: STYLE: whitespace at end of input line
+mandoc: escname.in:11:10: WARNING: undefined escape, printing literally: \G
+mandoc: escname.in:14:5: ERROR: escaped character not allowed in a name: first\e
+mandoc: escname.in:20:13: WARNING: invalid escape sequence: \n[second
+mandoc: escname.in:20:12: STYLE: whitespace at end of input line
index b8885c65f73c125f1789687f5e21fd4d38803306..2fa10557722db9e420b8189b18e1f3307b9a1324 100644 (file)
@@ -1,4 +1,9 @@
-# $OpenBSD: Makefile,v 1.6 2014/07/06 19:08:57 schwarze Exp $
+# $OpenBSD: Makefile,v 1.10 2022/06/03 11:50:25 schwarze Exp $
+#
+# This directory is intended for tests of string *expansion*,
+# in particular testing the behaviour of the \* escape sequence.
+# Tests of string *definitions* are better placed in the roff/ds
+# directory.
 
 REGRESS_TARGETS         = dotT escape infinite name std undef zerolength
 LINT_TARGETS    = name std undef
index 2948f164dcb593719f2f6a495fd540dc09000343..b2612be2040bad3b8b75cd7ae23eea9cf0c0c559 100644 (file)
@@ -1,5 +1,5 @@
-.\" $OpenBSD: name.in,v 1.4 2017/07/04 14:53:27 schwarze Exp $
-.Dd $Mdocdate: July 4 2017 $
+.\" $OpenBSD: name.in,v 1.5 2022/06/03 11:50:25 schwarze Exp $
+.Dd $Mdocdate: June 3 2022 $
 .Dt STRING-NAME 1
 .Os
 .Sh NAME
@@ -10,7 +10,9 @@
 .ds "quot" value of "quot"
 .ds bs\e value of bs\ee
 .ds bs\\e value of bs\e\ee
+.ds dot. value of dot.
 .ds bl\ e value of bl\e e
+.ds inval\\G value of inval\eG
 norm: \*[norm]
 .br
 norm without closing brace: \*[norm
@@ -26,6 +28,10 @@ bs\e\ee: \*[bs\\e]
 bse: \*[bse]
 .br
 bs: \*[bs]
+.br
+dot.: \*[dot.]
+.br
+dot\e.: \*[dot\.]
 .\".br
 .\"bl\e e: \*[bl\ e]
 .br
@@ -34,3 +40,7 @@ bl e: \*[bl e]
 ble: \*[ble]
 .br
 bl: \*[bl]
+.br
+inval\e\eG: \*[inval\\G]
+.br
+inval\eG: \*[inval\G]
index 325e28aabc2b67342246ed09361017d4f3568099..38258a729034512ad764fd20b20eb954b2ce03c8 100644 (file)
@@ -11,8 +11,12 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
      bs\\e: value of bs\\e
      bse:
      bs:
+     dot.: value of dot.
+     dot\.: value of dot.
      bl e:
      ble:
      bl:
+     inval\\G: value of inval\G
+     inval\G: value of inval\G
 
-OpenBSD                          July 4, 2017                          OpenBSD
+OpenBSD                          June 3, 2022                          OpenBSD
index 5a6340a01ca32300eaf892831acff896f6d357cc..13283f5dc2dbda85dd6d54fcdd9c85e3934395ca 100644 (file)
@@ -1,16 +1,17 @@
 mandoc: name.in:11:5: ERROR: escaped character not allowed in a name: bs\e
-mandoc: name.in:13:5: ERROR: escaped character not allowed in a name: bl\ 
-mandoc: name.in:16:29: WARNING: invalid escape sequence: \*[norm
-mandoc: name.in:16:28: STYLE: whitespace at end of input line
-mandoc: name.in:18:7: WARNING: undefined string, using "": quot
-mandoc: name.in:18:6: STYLE: whitespace at end of input line
-mandoc: name.in:26:6: WARNING: undefined string, using "": bse
-mandoc: name.in:26:5: STYLE: whitespace at end of input line
-mandoc: name.in:28:5: WARNING: undefined string, using "": bs
-mandoc: name.in:28:4: STYLE: whitespace at end of input line
-mandoc: name.in:32:7: WARNING: undefined string, using "": bl e
-mandoc: name.in:32:6: STYLE: whitespace at end of input line
-mandoc: name.in:34:6: WARNING: undefined string, using "": ble
-mandoc: name.in:34:5: STYLE: whitespace at end of input line
-mandoc: name.in:36:5: WARNING: undefined string, using "": bl
-mandoc: name.in:36:4: STYLE: whitespace at end of input line
+mandoc: name.in:14:5: ERROR: escaped character not allowed in a name: bl\ 
+mandoc: name.in:18:29: WARNING: invalid escape sequence: \*[norm
+mandoc: name.in:18:28: STYLE: whitespace at end of input line
+mandoc: name.in:20:7: WARNING: undefined string, using "": quot
+mandoc: name.in:20:6: STYLE: whitespace at end of input line
+mandoc: name.in:28:6: WARNING: undefined string, using "": bse
+mandoc: name.in:28:5: STYLE: whitespace at end of input line
+mandoc: name.in:30:5: WARNING: undefined string, using "": bs
+mandoc: name.in:30:4: STYLE: whitespace at end of input line
+mandoc: name.in:38:7: WARNING: undefined string, using "": bl e
+mandoc: name.in:38:6: STYLE: whitespace at end of input line
+mandoc: name.in:40:6: WARNING: undefined string, using "": ble
+mandoc: name.in:40:5: STYLE: whitespace at end of input line
+mandoc: name.in:42:5: WARNING: undefined string, using "": bl
+mandoc: name.in:42:4: STYLE: whitespace at end of input line
+mandoc: name.in:46:19: WARNING: undefined escape, printing literally: \G
diff --git a/roff.c b/roff.c
index c4b944e3b763d7c0f664e8b74b2448e073f253c9..b78ef59ee3245fb9e6e4c0cbdde5911512ee7ea4 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/* $Id: roff.c,v 1.392 2022/06/02 11:29:07 schwarze Exp $ */
+/* $Id: roff.c,v 1.393 2022/06/03 12:15:55 schwarze Exp $ */
 /*
  * Copyright (c) 2010-2015, 2017-2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -1375,6 +1375,7 @@ roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char ec)
        int              iarg;          /* index beginning the argument */
        int              iendarg;       /* index right after the argument */
        int              iend;          /* index right after the sequence */
+       int              isrc, idst;    /* to reduce \\ and \. in names */
        int              deftype;       /* type of definition to paste */
        int              argi;          /* macro argument index */
        int              quote_args;    /* true for \\$@, false for \\$* */
@@ -1428,6 +1429,21 @@ roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char ec)
                        continue;
                }
 
+               /* Reduce \\ and \. in names. */
+
+               if (buf->buf[inam] == '*' || buf->buf[inam] == 'n') {
+                       isrc = idst = iarg;
+                       while (isrc < iendarg) {
+                               if (isrc + 1 < iendarg &&
+                                   buf->buf[isrc] == '\\' &&
+                                   (buf->buf[isrc + 1] == '\\' ||
+                                    buf->buf[isrc + 1] == '.'))
+                                       isrc++;
+                               buf->buf[idst++] = buf->buf[isrc++];
+                       }
+                       iendarg -= isrc - idst;
+               }
+
                /* Handle expansion. */
 
                res = NULL;
@@ -4002,7 +4018,7 @@ static size_t
 roff_getname(struct roff *r, char **cpp, int ln, int pos)
 {
        char     *name, *cp;
-       size_t    namesz;
+       int       namesz, inam, iend;
 
        name = *cpp;
        if (*name == '\0')
@@ -4010,24 +4026,46 @@ roff_getname(struct roff *r, char **cpp, int ln, int pos)
 
        /* Advance cp to the byte after the end of the name. */
 
-       for (cp = name; 1; cp++) {
-               namesz = cp - name;
+       cp = name;
+       namesz = 0;
+       for (;;) {
                if (*cp == '\0')
                        break;
                if (*cp == ' ' || *cp == '\t') {
                        cp++;
                        break;
                }
-               if (*cp != '\\')
+               if (*cp != '\\') {
+                       if (name + namesz < cp) {
+                               name[namesz] = *cp;
+                               *cp = ' ';
+                       }
+                       namesz++;
+                       cp++;
                        continue;
+               }
                if (cp[1] == '{' || cp[1] == '}')
                        break;
-               if (*++cp == '\\')
-                       continue;
-               mandoc_msg(MANDOCERR_NAMESC, ln, pos,
-                   "%.*s", (int)(cp - name + 1), name);
-               mandoc_escape((const char **)&cp, NULL, NULL);
-               break;
+               if (roff_escape(cp, 0, 0, NULL, &inam,
+                   NULL, NULL, &iend) != ESCAPE_UNDEF) {
+                       mandoc_msg(MANDOCERR_NAMESC, ln, pos,
+                           "%.*s%.*s", namesz, name, iend, cp);
+                       cp += iend;
+                       break;
+               }
+
+               /*
+                * In an identifier, \\, \., \G and so on
+                * are reduced to \, ., G and so on,
+                * vaguely similar to copy mode.
+                */
+
+               name[namesz++] = cp[inam];
+               while (iend--) {
+                       if (cp >= name + namesz)
+                               *cp = ' ';
+                       cp++;
+               }
        }
 
        /* Read past spaces. */