Rudimentary implementation of the roff(7) .char (output glyph
authorschwarze <schwarze@openbsd.org>
Sat, 25 Aug 2018 16:43:52 +0000 (16:43 +0000)
committerschwarze <schwarze@openbsd.org>
Sat, 25 Aug 2018 16:43:52 +0000 (16:43 +0000)
definition) request, used for example by groff_hdtbl(7).

This simplistic implementation may interact incorrectly
with the .tr (input character translation) request.
But come on, you are not only using .char *and* .tr, but you do so
with respect to the same character in the same manual page?

regress/usr.bin/mandoc/roff/char/Makefile [new file with mode: 0644]
regress/usr.bin/mandoc/roff/char/badarg.in [new file with mode: 0644]
regress/usr.bin/mandoc/roff/char/badarg.out_ascii [new file with mode: 0644]
regress/usr.bin/mandoc/roff/char/badarg.out_lint [new file with mode: 0644]
regress/usr.bin/mandoc/roff/char/basic.in [new file with mode: 0644]
regress/usr.bin/mandoc/roff/char/basic.out_ascii [new file with mode: 0644]
share/man/man7/roff.7
usr.bin/mandoc/mandoc.1
usr.bin/mandoc/mandoc.h
usr.bin/mandoc/read.c
usr.bin/mandoc/roff.c

diff --git a/regress/usr.bin/mandoc/roff/char/Makefile b/regress/usr.bin/mandoc/roff/char/Makefile
new file mode 100644 (file)
index 0000000..ebd6845
--- /dev/null
@@ -0,0 +1,6 @@
+# $OpenBSD: Makefile,v 1.1 2018/08/25 16:43:52 schwarze Exp $
+
+REGRESS_TARGETS        = basic badarg
+LINT_TARGETS   = badarg
+
+.include <bsd.regress.mk>
diff --git a/regress/usr.bin/mandoc/roff/char/badarg.in b/regress/usr.bin/mandoc/roff/char/badarg.in
new file mode 100644 (file)
index 0000000..3b34364
--- /dev/null
@@ -0,0 +1,10 @@
+.\" $OpenBSD: badarg.in,v 1.1 2018/08/25 16:43:52 schwarze Exp $
+.TH CHAR-BADARG 1 "August 25, 2018"
+.SH NAME
+char-badarg \(en char requests with invalid arguments
+.SH DESCRIPTION
+.char
+.char \fR myval
+.char \[myc]x myval
+.char xy myval
+myc: <\[myc]> x
diff --git a/regress/usr.bin/mandoc/roff/char/badarg.out_ascii b/regress/usr.bin/mandoc/roff/char/badarg.out_ascii
new file mode 100644 (file)
index 0000000..287479a
--- /dev/null
@@ -0,0 +1,13 @@
+CHAR-BADARG(1)              General Commands Manual             CHAR-BADARG(1)
+
+
+
+N\bNA\bAM\bME\bE
+       char-badarg - char requests with invalid arguments
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       myc: <> x
+
+
+
+OpenBSD                         August 25, 2018                 CHAR-BADARG(1)
diff --git a/regress/usr.bin/mandoc/roff/char/badarg.out_lint b/regress/usr.bin/mandoc/roff/char/badarg.out_lint
new file mode 100644 (file)
index 0000000..e07faa3
--- /dev/null
@@ -0,0 +1,6 @@
+mandoc: badarg.in:6:6: ERROR: argument is not a character: char 
+mandoc: badarg.in:7:7: ERROR: argument is not a character: char \fR myval
+mandoc: badarg.in:8:7: WARNING: invalid escape sequence: \[myc]
+mandoc: badarg.in:8:7: ERROR: argument is not a character: char \[myc]x myval
+mandoc: badarg.in:9:7: ERROR: argument is not a character: char xy myval
+mandoc: badarg.in:10:7: WARNING: invalid escape sequence: \[myc]
diff --git a/regress/usr.bin/mandoc/roff/char/basic.in b/regress/usr.bin/mandoc/roff/char/basic.in
new file mode 100644 (file)
index 0000000..cfa1880
--- /dev/null
@@ -0,0 +1,11 @@
+.\" $OpenBSD: basic.in,v 1.1 2018/08/25 16:43:52 schwarze Exp $
+.TH CHAR-BASIC 1 "August 25, 2018"
+.SH NAME
+char-basic \(en the char request
+.SH DESCRIPTION
+initial text
+.char \[myc] myval
+.char x y
+.char \[boldX] \fBX
+\[boldX] \[myc]
+final text
diff --git a/regress/usr.bin/mandoc/roff/char/basic.out_ascii b/regress/usr.bin/mandoc/roff/char/basic.out_ascii
new file mode 100644 (file)
index 0000000..85207ce
--- /dev/null
@@ -0,0 +1,13 @@
+CHAR-BASIC(1)               General Commands Manual              CHAR-BASIC(1)
+
+
+
+N\bNA\bAM\bME\bE
+       char-basic - the char request
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+       initial text X\bX myval final teyt
+
+
+
+OpenBSD                         August 25, 2018                  CHAR-BASIC(1)
index e1bf722..03a3a09 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.84 2018/08/24 22:56:37 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.85 2018/08/25 16:43:52 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010-2018 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: August 24 2018 $
+.Dd $Mdocdate: August 25 2018 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -505,9 +505,16 @@ This is a groff extension and currently ignored.
 .It Ic \&ch Ar macroname Op Ar dist
 Change a trap location.
 Currently ignored.
-.It Ic \&char Ar glyphname Op Ar string
-Define a new glyph.
-Currently unsupported.
+.It Ic \&char Ar glyph Op Ar string
+Define or redefine the ASCII character or character escape sequence
+.Ar glyph
+to be rendered as
+.Ar string ,
+which can be empty.
+Only partially supported in
+.Xr mandoc 1 ;
+may interact incorrectly with
+.Ic \&tr .
 .It Ic \&chop Ar stringname
 Remove the last character from a macro, string, or diversion.
 Currently unsupported.
index cc55b3c..aa19c49 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: mandoc.1,v 1.151 2018/08/23 14:16:12 schwarze Exp $
+.\"    $OpenBSD: mandoc.1,v 1.152 2018/08/25 16:43:52 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2012, 2014-2018 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: August 23 2018 $
+.Dd $Mdocdate: August 25 2018 $
 .Dt MANDOC 1
 .Os
 .Sh NAME
@@ -1606,6 +1606,12 @@ or
 .Cm off .
 The invalid argument is moved out of the macro, which leaves the macro
 empty, causing it to toggle the spacing mode.
+.It Sy "argument contains two font escapes"
+.Pq roff
+The second argument of a
+.Ic char
+request contains more than one font escape sequence.
+A wrong font may remain active after using the character.
 .It Sy "unknown font, skipping request"
 .Pq man , tbl
 A
@@ -1959,6 +1965,13 @@ macro fails to specify the list type.
 The argument of a
 .Ic \&ce
 request is not a number.
+.It Sy "argument is not a character"
+.Pq roff
+The first argument of a
+.Ic char
+request is neither a single ASCII character
+nor a single character escape sequence.
+The request is ignored including all its arguments.
 .It Sy "missing manual name, using \(dq\(dq"
 .Pq mdoc
 The first call to
index 6b39fc0..4a46bd8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mandoc.h,v 1.194 2018/08/24 22:56:37 schwarze Exp $ */
+/*     $OpenBSD: mandoc.h,v 1.195 2018/08/25 16:43:52 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -158,6 +158,7 @@ enum        mandocerr {
        MANDOCERR_LB_BAD, /* unknown library name: Lb ... */
        MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
        MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
+       MANDOCERR_CHAR_FONT, /* argument contains two font escapes */
        MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
        MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
 
@@ -212,6 +213,7 @@ enum        mandocerr {
        MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
        MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
        MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
+       MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */
        MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
        MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
        MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
index 2ab9dae..e6c81ed 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: read.c,v 1.171 2018/08/24 22:56:37 schwarze Exp $ */
+/*     $OpenBSD: read.c,v 1.172 2018/08/25 16:43:52 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -196,6 +196,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "unknown library name",
        "invalid content in Rs block",
        "invalid Boolean argument",
+       "argument contains two font escapes",
        "unknown font, skipping request",
        "odd number of characters in request",
 
@@ -250,6 +251,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "skipping display without arguments",
        "missing list type, using -item",
        "argument is not numeric, using 1",
+       "argument is not a character",
        "missing manual name, using \"\"",
        "uname(3) system call failed, using UNKNOWN",
        "unknown standard specifier",
index 57ff4a1..d6fc50b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.212 2018/08/24 22:56:37 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.213 2018/08/25 16:43:52 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -174,6 +174,7 @@ static      int              roff_br(ROFF_ARGS);
 static int              roff_cblock(ROFF_ARGS);
 static int              roff_cc(ROFF_ARGS);
 static int              roff_ccond(struct roff *, int, int);
+static int              roff_char(ROFF_ARGS);
 static int              roff_cond(ROFF_ARGS);
 static int              roff_cond_text(ROFF_ARGS);
 static int              roff_cond_sub(ROFF_ARGS);
@@ -395,7 +396,7 @@ static      struct roffmac   roffs[TOKEN_NONE] = {
        { roff_insec, NULL, NULL, 0 },  /* cf */
        { roff_line_ignore, NULL, NULL, 0 },  /* cflags */
        { roff_line_ignore, NULL, NULL, 0 },  /* ch */
-       { roff_unsupp, NULL, NULL, 0 },  /* char */
+       { roff_char, NULL, NULL, 0 },  /* char */
        { roff_unsupp, NULL, NULL, 0 },  /* chop */
        { roff_line_ignore, NULL, NULL, 0 },  /* class */
        { roff_insec, NULL, NULL, 0 },  /* close */
@@ -3319,6 +3320,76 @@ roff_cc(ROFF_ARGS)
        return ROFF_IGN;
 }
 
+static int
+roff_char(ROFF_ARGS)
+{
+       const char      *p, *kp, *vp;
+       size_t           ksz, vsz;
+       int              font;
+
+       /* Parse the character to be replaced. */
+
+       kp = buf->buf + pos;
+       p = kp + 1;
+       if (*kp == '\0' || (*kp == '\\' &&
+            mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) ||
+           (*p != ' ' && *p != '\0')) {
+               mandoc_vmsg(MANDOCERR_CHAR_ARG, r->parse,
+                   ln, pos, "char %s", kp);
+               return ROFF_IGN;
+       }
+       ksz = p - kp;
+       while (*p == ' ')
+               p++;
+
+       /*
+        * If the replacement string contains a font escape sequence,
+        * we have to restore the font at the end.
+        */
+
+       vp = p;
+       vsz = strlen(p);
+       font = 0;
+       while (*p != '\0') {
+               if (*p++ != '\\')
+                       continue;
+               switch (mandoc_escape(&p, NULL, NULL)) {
+               case ESCAPE_FONT:
+               case ESCAPE_FONTROMAN:
+               case ESCAPE_FONTITALIC:
+               case ESCAPE_FONTBOLD:
+               case ESCAPE_FONTBI:
+               case ESCAPE_FONTPREV:
+                       font++;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (font > 1)
+               mandoc_msg(MANDOCERR_CHAR_FONT, r->parse,
+                   ln, vp - buf->buf, vp);
+
+       /*
+        * Approximate the effect of .char using the .tr tables.
+        * XXX In groff, .char and .tr interact differently.
+        */
+
+       if (ksz == 1) {
+               if (r->xtab == NULL)
+                       r->xtab = mandoc_calloc(128, sizeof(*r->xtab));
+               assert((unsigned int)*kp < 128);
+               free(r->xtab[(int)*kp].p);
+               r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p,
+                   "%s%s", vp, font ? "\fP" : "");
+       } else {
+               roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0);
+               if (font)
+                       roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1);
+       }
+       return ROFF_IGN;
+}
+
 static int
 roff_ec(ROFF_ARGS)
 {