diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2022-04-28 10:26:37 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2022-04-28 10:26:37 +0000 |
commit | ae95bf4c9468b176445f464bec4255eb69978cfa (patch) | |
tree | ad0231e96a50139b4b21fbee7a8829e5846f11a4 /man.c | |
parent | b4c6ee8b16f890a5c4514c24d3fa9ee27cb0efe0 (diff) | |
download | mandoc-ae95bf4c9468b176445f464bec4255eb69978cfa.tar.gz |
Element next-line scopes may nest, so man_breakscope() may have to
break multiple element next-line scopes at the same time, similar to
what man_descope() already does for unconditional rewinding.
This fixes an assertion failure that tb@ found with afl(1), caused
by .SH .I .I .BI and similar sequences of macros without arguments.
Diffstat (limited to 'man.c')
-rw-r--r-- | man.c | 24 |
1 files changed, 18 insertions, 6 deletions
@@ -1,7 +1,7 @@ -/* $Id$ */ +/* $Id$ */ /* + * Copyright (c) 2013-2015,2017-2019,2022 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -70,6 +70,9 @@ man_hasc(char *start) return (ep - cp) % 2 ? NULL : ep; } +/* + * Rewind all open next-line scopes. + */ void man_descope(struct roff_man *man, int line, int offs, char *start) { @@ -274,6 +277,10 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs) return 1; } +/* + * Rewind open next-line scopes + * unless the tok request or macro is allowed inside them. + */ void man_breakscope(struct roff_man *man, int tok) { @@ -294,10 +301,15 @@ man_breakscope(struct roff_man *man, int tok) (man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED)) == MAN_NSCOPED) n = n->parent; - - mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, - "%s breaks %s", roff_name[tok], roff_name[n->tok]); - + for (;;) { + mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos, + "%s breaks %s", roff_name[tok], roff_name[n->tok]); + if (n->parent->type != ROFFT_ELEM || + (man_macro(n->parent->tok)->flags & + MAN_ESCOPED) == 0) + break; + n = n->parent; + } roff_node_delete(man, n); man->flags &= ~MAN_ELINE; } |