aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/roff.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2022-04-30 18:51:36 +0000
committerIngo Schwarze <schwarze@openbsd.org>2022-04-30 18:51:36 +0000
commitb592e2d9ee8dd845f058dac8ae07a679a4bd10e2 (patch)
tree4274441e268d6735a9caea1b2483186918ca4f8d /roff.c
parent42aa282973a44f08e87cdc71db77df5ac502a1bc (diff)
downloadmandoc-b592e2d9ee8dd845f058dac8ae07a679a4bd10e2.tar.gz
mandoc-b592e2d9ee8dd845f058dac8ae07a679a4bd10e2.tar.zst
mandoc-b592e2d9ee8dd845f058dac8ae07a679a4bd10e2.zip
Provide a new function roff_req_or_macro() to parse and handle a request
or macro, including context-dependent error handling inside tbl(7) code and inside .ce/.rj blocks. Use it both in the top level roff(7) parser and inside conditional blocks. This fixes an assertion failure triggered by ".if 1 .ce" inside tbl(7) code, found by tb@ using afl(1). As a side benefit for readability, only one place remains in the code that calls the main handler functions for the various roff(7) requests. This patch also improves column numbers in some error messages and various comments.
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c71
1 files changed, 35 insertions, 36 deletions
diff --git a/roff.c b/roff.c
index ca45b0f6..323122ba 100644
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/* $Id: roff.c,v 1.385 2022/04/30 11:32:42 schwarze Exp $ */
+/* $Id: roff.c,v 1.386 2022/04/30 18:51:36 schwarze Exp $ */
/*
* Copyright (c) 2010-2015, 2017-2022 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -237,6 +237,7 @@ static enum roff_tok roff_parse(struct roff *, char *, int *,
static int roff_parsetext(struct roff *, struct buf *,
int, int *);
static int roff_renamed(ROFF_ARGS);
+static int roff_req_or_macro(ROFF_ARGS);
static int roff_return(ROFF_ARGS);
static int roff_rm(ROFF_ARGS);
static int roff_rn(ROFF_ARGS);
@@ -1905,7 +1906,6 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs, size_t len)
/*
* If a scope is open, go to the child handler for that macro,
* as it may want to preprocess before doing anything with it.
- * Don't do so if an equation is open.
*/
if (r->last) {
@@ -1913,19 +1913,27 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs, size_t len)
return (*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs);
}
- /* No scope is open. This is a new request or macro. */
-
r->options &= ~MPARSE_COMMENT;
spos = pos;
t = roff_parse(r, buf->buf, &pos, ln, ppos);
+ return roff_req_or_macro(r, t, buf, ln, spos, pos, offs);
+}
+
+/*
+ * Handle a new request or macro.
+ * May be called outside any scope or from inside a conditional scope.
+ */
+static int
+roff_req_or_macro(ROFF_ARGS) {
- /* Tables ignore most macros. */
+ /* For now, tables ignore most macros and some request. */
- if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS ||
- t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) {
+ if (r->tbl != NULL && (tok == TOKEN_NONE || tok == ROFF_TS ||
+ tok == ROFF_br || tok == ROFF_ce || tok == ROFF_rj ||
+ tok == ROFF_sp)) {
mandoc_msg(MANDOCERR_TBLMACRO,
- ln, pos, "%s", buf->buf + spos);
- if (t != TOKEN_NONE)
+ ln, ppos, "%s", buf->buf + ppos);
+ if (tok != TOKEN_NONE)
return ROFF_IGN;
while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
pos++;
@@ -1938,9 +1946,9 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs, size_t len)
/* For now, let high level macros abort .ce mode. */
- if (ctl && roffce_node != NULL &&
- (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
- t == ROFF_TH || t == ROFF_TS)) {
+ if (roffce_node != NULL &&
+ (tok == TOKEN_NONE || tok == ROFF_Dd || tok == ROFF_EQ ||
+ tok == ROFF_TH || tok == ROFF_TS)) {
r->man->last = roffce_node;
r->man->next = ROFF_NEXT_SIBLING;
roffce_lines = 0;
@@ -1952,12 +1960,12 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs, size_t len)
* Let the standard macro set parsers handle it.
*/
- if (t == TOKEN_NONE)
+ if (tok == TOKEN_NONE)
return ROFF_CONT;
- /* Execute a roff request or a user defined macro. */
+ /* Execute a roff request or a user-defined macro. */
- return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs);
+ return (*roffs[tok].proc)(r, tok, buf, ln, ppos, pos, offs);
}
/*
@@ -2000,8 +2008,10 @@ roff_endparse(struct roff *r)
}
/*
- * Parse a roff node's type from the input buffer. This must be in the
- * form of ".foo xxx" in the usual way.
+ * Parse the request or macro name at buf[*pos].
+ * Return ROFF_RENAMED, ROFF_USERDEF, or a ROFF_* token value.
+ * For empty, undefined, mdoc(7), and man(7) macros, return TOKEN_NONE.
+ * As a side effect, set r->current_string to the definition or to NULL.
*/
static enum roff_tok
roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
@@ -2393,27 +2403,18 @@ static int
roff_cond_sub(ROFF_ARGS)
{
struct roffnode *bl;
- int irc, rr;
+ int irc, rr, spos;
enum roff_tok t;
rr = 0; /* If arguments follow "\}", skip them. */
irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
+ spos = pos;
t = roff_parse(r, buf->buf, &pos, ln, ppos);
- /* For now, let high level macros abort .ce mode. */
-
- if (roffce_node != NULL &&
- (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
- t == ROFF_TH || t == ROFF_TS)) {
- r->man->last = roffce_node;
- r->man->next = ROFF_NEXT_SIBLING;
- roffce_lines = 0;
- roffce_node = NULL;
- }
-
/*
- * Fully handle known macros when they are structurally
- * required or when the conditional evaluated to true.
+ * Handle requests and macros if the conditional evaluated
+ * to true or if they are structurally required.
+ * The .break request is always handled specially.
*/
if (t == ROFF_break) {
@@ -2426,13 +2427,11 @@ roff_cond_sub(ROFF_ARGS)
break;
}
}
- } else if (t != TOKEN_NONE &&
- (rr || roffs[t].flags & ROFFMAC_STRUCT)) {
- irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
+ } else if (rr || (t < TOKEN_NONE && roffs[t].flags & ROFFMAC_STRUCT)) {
+ irc |= roff_req_or_macro(r, t, buf, ln, spos, pos, offs);
if (irc & ROFF_WHILE)
irc &= ~(ROFF_LOOPCONT | ROFF_LOOPEXIT);
- } else
- irc |= rr ? ROFF_CONT : ROFF_IGN;
+ }
return irc;
}