From 29fcab3e34e97e5bf3f12b6cf7048525b7981deb Mon Sep 17 00:00:00 2001 From: schwarze Date: Sat, 25 Aug 2018 16:43:52 +0000 Subject: [PATCH] Rudimentary implementation of the roff(7) .char (output glyph 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 | 6 ++ regress/usr.bin/mandoc/roff/char/badarg.in | 10 +++ .../usr.bin/mandoc/roff/char/badarg.out_ascii | 13 ++++ .../usr.bin/mandoc/roff/char/badarg.out_lint | 6 ++ regress/usr.bin/mandoc/roff/char/basic.in | 11 +++ .../usr.bin/mandoc/roff/char/basic.out_ascii | 13 ++++ share/man/man7/roff.7 | 17 +++-- usr.bin/mandoc/mandoc.1 | 17 ++++- usr.bin/mandoc/mandoc.h | 4 +- usr.bin/mandoc/read.c | 4 +- usr.bin/mandoc/roff.c | 75 ++++++++++++++++++- 11 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 regress/usr.bin/mandoc/roff/char/Makefile create mode 100644 regress/usr.bin/mandoc/roff/char/badarg.in create mode 100644 regress/usr.bin/mandoc/roff/char/badarg.out_ascii create mode 100644 regress/usr.bin/mandoc/roff/char/badarg.out_lint create mode 100644 regress/usr.bin/mandoc/roff/char/basic.in create mode 100644 regress/usr.bin/mandoc/roff/char/basic.out_ascii diff --git a/regress/usr.bin/mandoc/roff/char/Makefile b/regress/usr.bin/mandoc/roff/char/Makefile new file mode 100644 index 00000000000..ebd68458491 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/char/Makefile @@ -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 diff --git a/regress/usr.bin/mandoc/roff/char/badarg.in b/regress/usr.bin/mandoc/roff/char/badarg.in new file mode 100644 index 00000000000..3b343640f45 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/char/badarg.in @@ -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 index 00000000000..287479a8665 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/char/badarg.out_ascii @@ -0,0 +1,13 @@ +CHAR-BADARG(1) General Commands Manual CHAR-BADARG(1) + + + +NNAAMMEE + char-badarg - char requests with invalid arguments + +DDEESSCCRRIIPPTTIIOONN + 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 index 00000000000..e07faa3cb14 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/char/badarg.out_lint @@ -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 index 00000000000..cfa1880abc3 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/char/basic.in @@ -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 index 00000000000..85207ceefd1 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/char/basic.out_ascii @@ -0,0 +1,13 @@ +CHAR-BASIC(1) General Commands Manual CHAR-BASIC(1) + + + +NNAAMMEE + char-basic - the char request + +DDEESSCCRRIIPPTTIIOONN + initial text XX myval final teyt + + + +OpenBSD August 25, 2018 CHAR-BASIC(1) diff --git a/share/man/man7/roff.7 b/share/man/man7/roff.7 index e1bf722f975..03a3a09dc3b 100644 --- a/share/man/man7/roff.7 +++ b/share/man/man7/roff.7 @@ -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 .\" Copyright (c) 2010-2018 Ingo Schwarze @@ -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. diff --git a/usr.bin/mandoc/mandoc.1 b/usr.bin/mandoc/mandoc.1 index cc55b3ceac0..aa19c49d634 100644 --- a/usr.bin/mandoc/mandoc.1 +++ b/usr.bin/mandoc/mandoc.1 @@ -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 .\" Copyright (c) 2012, 2014-2018 Ingo Schwarze @@ -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 diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index 6b39fc056ee..4a46bd89d13 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -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 * Copyright (c) 2010-2018 Ingo Schwarze @@ -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 */ diff --git a/usr.bin/mandoc/read.c b/usr.bin/mandoc/read.c index 2ab9dae312e..e6c81ed3516 100644 --- a/usr.bin/mandoc/read.c +++ b/usr.bin/mandoc/read.c @@ -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 * Copyright (c) 2010-2018 Ingo Schwarze @@ -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", diff --git a/usr.bin/mandoc/roff.c b/usr.bin/mandoc/roff.c index 57ff4a137db..d6fc50bb27f 100644 --- a/usr.bin/mandoc/roff.c +++ b/usr.bin/mandoc/roff.c @@ -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 * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze @@ -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) { -- 2.20.1