summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mandoc.113
-rw-r--r--mandoc.h2
-rw-r--r--read.c2
-rw-r--r--regress/roff/Makefile4
-rw-r--r--regress/roff/char/Makefile6
-rw-r--r--regress/roff/char/badarg.in10
-rw-r--r--regress/roff/char/badarg.out_ascii13
-rw-r--r--regress/roff/char/badarg.out_lint6
-rw-r--r--regress/roff/char/basic.in11
-rw-r--r--regress/roff/char/basic.out_ascii13
-rw-r--r--roff.713
-rw-r--r--roff.c73
12 files changed, 160 insertions, 6 deletions
diff --git a/mandoc.1 b/mandoc.1
index 0a49de0e..4cdfe150 100644
--- a/mandoc.1
+++ b/mandoc.1
@@ -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/mandoc.h b/mandoc.h
index 38733dc4..52c9232f 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -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/read.c b/read.c
index 84e70afc..8bf0ef84 100644
--- a/read.c
+++ b/read.c
@@ -198,6 +198,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",
@@ -252,6 +253,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/regress/roff/Makefile b/regress/roff/Makefile
index f338f83d..036a66e5 100644
--- a/regress/roff/Makefile
+++ b/regress/roff/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.26 2018/08/24 22:56:37 schwarze Exp $
+# $OpenBSD: Makefile,v 1.27 2018/08/25 16:46:28 schwarze Exp $
SUBDIR = args cond esc scale string
-SUBDIR += br cc de ds ft ig it ll na nr po ps
+SUBDIR += br cc char de ds ft ig it ll na nr po ps
SUBDIR += return rm rn shift sp ta ti tr while
.include "../Makefile.sub"
diff --git a/regress/roff/char/Makefile b/regress/roff/char/Makefile
new file mode 100644
index 00000000..ebd68458
--- /dev/null
+++ b/regress/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 <bsd.regress.mk>
diff --git a/regress/roff/char/badarg.in b/regress/roff/char/badarg.in
new file mode 100644
index 00000000..3b343640
--- /dev/null
+++ b/regress/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/roff/char/badarg.out_ascii b/regress/roff/char/badarg.out_ascii
new file mode 100644
index 00000000..287479a8
--- /dev/null
+++ b/regress/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/roff/char/badarg.out_lint b/regress/roff/char/badarg.out_lint
new file mode 100644
index 00000000..e07faa3c
--- /dev/null
+++ b/regress/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/roff/char/basic.in b/regress/roff/char/basic.in
new file mode 100644
index 00000000..cfa1880a
--- /dev/null
+++ b/regress/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/roff/char/basic.out_ascii b/regress/roff/char/basic.out_ascii
new file mode 100644
index 00000000..85207cee
--- /dev/null
+++ b/regress/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/roff.7 b/roff.7
index a1160b2b..67c04680 100644
--- a/roff.7
+++ b/roff.7
@@ -507,9 +507,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/roff.c b/roff.c
index 5175cd6b..eff423dc 100644
--- a/roff.c
+++ b/roff.c
@@ -176,6 +176,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);
@@ -397,7 +398,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 */
@@ -3322,6 +3323,76 @@ roff_cc(ROFF_ARGS)
}
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)
{
const char *p;