summaryrefslogtreecommitdiffstats
path: root/roff.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2022-04-28 16:21:09 +0000
committerIngo Schwarze <schwarze@openbsd.org>2022-04-28 16:21:09 +0000
commitc0667bb0674363961e21650dd6fa239e4696d039 (patch)
treec2a9b64e56f4ac90b6b29932d5b5df55c2c8d762 /roff.c
parentae95bf4c9468b176445f464bec4255eb69978cfa (diff)
downloadmandoc-c0667bb0674363961e21650dd6fa239e4696d039.tar.gz
The syntax of the roff(7) .mc request is quite special
and the roff_onearg() parsing function is too generic, so provide a dedicated parsing function instead. This fixes an assertion failure when an \o escape sequence is passed as the argument; the bug was found by tb@ using afl(1). It also makes mandoc output more similar to groff in various cases.
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c51
1 files changed, 50 insertions, 1 deletions
diff --git a/roff.c b/roff.c
index f2644602..2d3f44a5 100644
--- a/roff.c
+++ b/roff.c
@@ -227,6 +227,7 @@ static int roff_line_ignore(ROFF_ARGS);
static void roff_man_alloc1(struct roff_man *);
static void roff_man_free1(struct roff_man *);
static int roff_manyarg(ROFF_ARGS);
+static int roff_mc(ROFF_ARGS);
static int roff_noarg(ROFF_ARGS);
static int roff_nop(ROFF_ARGS);
static int roff_nr(ROFF_ARGS);
@@ -379,7 +380,7 @@ static struct roffmac roffs[TOKEN_NONE] = {
{ roff_noarg, NULL, NULL, 0 }, /* fi */
{ roff_onearg, NULL, NULL, 0 }, /* ft */
{ roff_onearg, NULL, NULL, 0 }, /* ll */
- { roff_onearg, NULL, NULL, 0 }, /* mc */
+ { roff_mc, NULL, NULL, 0 }, /* mc */
{ roff_noarg, NULL, NULL, 0 }, /* nf */
{ roff_onearg, NULL, NULL, 0 }, /* po */
{ roff_onearg, NULL, NULL, 0 }, /* rj */
@@ -3732,6 +3733,54 @@ roff_eo(ROFF_ARGS)
}
static int
+roff_mc(ROFF_ARGS)
+{
+ struct roff_node *n;
+ char *cp;
+
+ /* Parse the first argument. */
+
+ cp = buf->buf + pos;
+ if (*cp != '\0')
+ cp++;
+ if (buf->buf[pos] == '\\') {
+ switch (mandoc_escape((const char **)&cp, NULL, NULL)) {
+ case ESCAPE_SPECIAL:
+ case ESCAPE_UNICODE:
+ case ESCAPE_NUMBERED:
+ break;
+ default:
+ *cp = '\0';
+ mandoc_msg(MANDOCERR_MC_ESC, ln, pos,
+ "mc %s", buf->buf + pos);
+ buf->buf[pos] = '\0';
+ break;
+ }
+ }
+
+ /* Ignore additional arguments. */
+
+ while (*cp == ' ')
+ *cp++ = '\0';
+ if (*cp != '\0') {
+ mandoc_msg(MANDOCERR_MC_DIST, ln, (int)(cp - buf->buf),
+ "mc ... %s", cp);
+ *cp = '\0';
+ }
+
+ /* Create the .mc node. */
+
+ roff_elem_alloc(r->man, ln, ppos, tok);
+ n = r->man->last;
+ if (buf->buf[pos] != '\0')
+ roff_word_alloc(r->man, ln, pos, buf->buf + pos);
+ n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
+ r->man->last = n;
+ r->man->next = ROFF_NEXT_SIBLING;
+ return ROFF_IGN;
+}
+
+static int
roff_nop(ROFF_ARGS)
{
while (buf->buf[pos] == ' ')