=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.363 retrieving revision 1.365 diff -u -p -r1.363 -r1.365 --- mandoc/roff.c 2019/02/06 21:11:43 1.363 +++ mandoc/roff.c 2019/04/21 23:51:21 1.365 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.363 2019/02/06 21:11:43 schwarze Exp $ */ +/* $Id: roff.c,v 1.365 2019/04/21 23:51:21 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze @@ -133,15 +133,18 @@ struct roff { char escape; /* escape character */ }; +/* + * A macro definition, condition, or ignored block. + */ struct roffnode { enum roff_tok tok; /* type of node */ struct roffnode *parent; /* up one in stack */ int line; /* parse line */ int col; /* parse col */ char *name; /* node name, e.g. macro name */ - char *end; /* end-rules: custom token */ - int endspan; /* end-rules: next-line or infty */ - int rule; /* current evaluation rule */ + char *end; /* custom end macro of the block */ + int endspan; /* scope to: 1=eol 2=next line -1=\} */ + int rule; /* content is: 1=evaluated 0=skipped */ }; #define ROFF_ARGS struct roff *r, /* parse ctx */ \ @@ -181,6 +184,7 @@ static int roff_als(ROFF_ARGS); static int roff_block(ROFF_ARGS); static int roff_block_text(ROFF_ARGS); static int roff_block_sub(ROFF_ARGS); +static int roff_break(ROFF_ARGS); static int roff_cblock(ROFF_ARGS); static int roff_cc(ROFF_ARGS); static int roff_ccond(struct roff *, int, int); @@ -400,7 +404,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* boxa */ { roff_line_ignore, NULL, NULL, 0 }, /* bp */ { roff_unsupp, NULL, NULL, 0 }, /* BP */ - { roff_unsupp, NULL, NULL, 0 }, /* break */ + { roff_break, NULL, NULL, 0 }, /* break */ { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ { roff_noarg, NULL, NULL, 0 }, /* brp */ @@ -685,7 +689,7 @@ roffhash_find(struct ohash *htab, const char *name, si /* * Pop the current node off of the stack of roff instructions currently - * pending. + * pending. Return 1 if it is a loop or 0 otherwise. */ static int roffnode_pop(struct roff *r) @@ -2002,6 +2006,10 @@ roff_cblock(ROFF_ARGS) } +/* + * Pop all nodes ending at the end of the current input line. + * Return the number of loops ended. + */ static int roffnode_cleanscope(struct roff *r) { @@ -2016,6 +2024,11 @@ roffnode_cleanscope(struct roff *r) return inloop; } +/* + * Handle the closing \} of a conditional block. + * Apart from generating warnings, this only pops nodes. + * Return the number of loops ended. + */ static int roff_ccond(struct roff *r, int ln, int ppos) { @@ -2235,6 +2248,7 @@ roff_block_text(ROFF_ARGS) static int roff_cond_sub(ROFF_ARGS) { + struct roffnode *bl; char *ep; int endloop, irc, rr; enum roff_tok t; @@ -2282,9 +2296,21 @@ roff_cond_sub(ROFF_ARGS) */ t = roff_parse(r, buf->buf, &pos, ln, ppos); - irc |= t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) ? - (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : - rr ? ROFF_CONT : ROFF_IGN; + if (t == ROFF_break) { + if (irc & ROFF_LOOPMASK) + irc = ROFF_IGN | ROFF_LOOPEXIT; + else if (rr) { + for (bl = r->last; bl != NULL; bl = bl->parent) { + bl->rule = 0; + if (bl->tok == ROFF_while) + break; + } + } + } else if (t != TOKEN_NONE && + (rr || roffs[t].flags & ROFFMAC_STRUCT)) + irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); + else + irc |= rr ? ROFF_CONT : ROFF_IGN; return irc; } @@ -3482,7 +3508,18 @@ roff_als(ROFF_ARGS) return ROFF_IGN; } +/* + * The .break request only makes sense inside conditionals, + * and that case is already handled in roff_cond_sub(). + */ static int +roff_break(ROFF_ARGS) +{ + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, pos, "break"); + return ROFF_IGN; +} + +static int roff_cc(ROFF_ARGS) { const char *p; @@ -3804,6 +3841,11 @@ roff_userdef(ROFF_ARGS) char *arg, *ap, *dst, *src; size_t sz; + /* If the macro is empty, ignore it altogether. */ + + if (*r->current_string == '\0') + return ROFF_IGN; + /* Initialize a new macro stack context. */ if (++r->mstackpos == r->mstacksz) { @@ -3851,7 +3893,7 @@ roff_userdef(ROFF_ARGS) buf->sz = strlen(buf->buf) + 1; *offs = 0; - return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? + return buf->buf[buf->sz - 2] == '\n' ? ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND; }