=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.208 retrieving revision 1.222 diff -u -p -r1.208 -r1.222 --- mandoc/mdoc_macro.c 2016/08/20 15:58:21 1.208 +++ mandoc/mdoc_macro.c 2017/05/05 13:17:55 1.222 @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.208 2016/08/20 15:58:21 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.222 2017/05/05 13:17:55 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010, 2012-2015 Ingo Schwarze + * Copyright (c) 2010, 2012-2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -46,19 +46,21 @@ static void phrase_ta(MACRO_PROT_ARGS); static void append_delims(struct roff_man *, int, int *, char *); static void dword(struct roff_man *, int, int, const char *, enum mdelim, int); -static int find_pending(struct roff_man *, int, int, int, - struct roff_node *); +static int find_pending(struct roff_man *, enum roff_tok, + int, int, struct roff_node *); static int lookup(struct roff_man *, int, int, int, const char *); static int macro_or_word(MACRO_PROT_ARGS, int); -static int parse_rest(struct roff_man *, int, int, int *, char *); -static int rew_alt(int); -static void rew_elem(struct roff_man *, int); +static void break_intermediate(struct roff_node *, + struct roff_node *); +static int parse_rest(struct roff_man *, enum roff_tok, + int, int *, char *); +static enum roff_tok rew_alt(enum roff_tok); +static void rew_elem(struct roff_man *, enum roff_tok); static void rew_last(struct roff_man *, const struct roff_node *); static void rew_pending(struct roff_man *, const struct roff_node *); -const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ +const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = { { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */ @@ -74,6 +76,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ @@ -194,16 +197,13 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ { in_line_eoln, MDOC_JOIN }, /* %Q */ - { in_line_eoln, 0 }, /* br */ { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ - { in_line_eoln, MDOC_PROLOGUE }, /* ll */ }; +const struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd; -const struct mdoc_macro * const mdoc_macros = __mdoc_macros; - /* * This is called at the end of parsing. It must traverse up the tree, * closing out open [implicit] scopes. Obviously, open explicit scopes @@ -216,14 +216,14 @@ mdoc_endparse(struct roff_man *mdoc) /* Scan for open explicit scopes. */ - n = mdoc->last->flags & MDOC_VALID ? + n = mdoc->last->flags & NODE_VALID ? mdoc->last->parent : mdoc->last; for ( ; n; n = n->parent) if (n->type == ROFFT_BLOCK && mdoc_macros[n->tok].flags & MDOC_EXPLICIT) mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse, - n->line, n->pos, mdoc_macronames[n->tok]); + n->line, n->pos, roff_name[n->tok]); /* Rewind to the first. */ @@ -238,18 +238,18 @@ mdoc_endparse(struct roff_man *mdoc) static int lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p) { - int res; + enum roff_tok res; if (mdoc->flags & MDOC_PHRASEQF) { mdoc->flags &= ~MDOC_PHRASEQF; return TOKEN_NONE; } if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) { - res = mdoc_hash_find(p); + res = roffhash_find(mdoc->mdocmac, p, 0); if (res != TOKEN_NONE) { if (mdoc_macros[res].flags & MDOC_CALLABLE) return res; - if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll) + if (res != MDOC_sp) mandoc_msg(MANDOCERR_MACRO_CALL, mdoc->parse, line, ppos, p); } @@ -264,16 +264,16 @@ static void rew_last(struct roff_man *mdoc, const struct roff_node *to) { - if (to->flags & MDOC_VALID) + if (to->flags & NODE_VALID) return; while (mdoc->last != to) { mdoc_state(mdoc, mdoc->last); - mdoc->last->flags |= MDOC_VALID | MDOC_ENDED; + mdoc->last->flags |= NODE_VALID | NODE_ENDED; mdoc->last = mdoc->last->parent; } mdoc_state(mdoc, mdoc->last); - mdoc->last->flags |= MDOC_VALID | MDOC_ENDED; + mdoc->last->flags |= NODE_VALID | NODE_ENDED; mdoc->next = ROFF_NEXT_SIBLING; } @@ -298,7 +298,7 @@ rew_pending(struct roff_man *mdoc, const struct roff_n default: return; } - if ( ! (n->flags & MDOC_BROKEN)) + if ( ! (n->flags & NODE_BROKEN)) return; } else n = mdoc->last; @@ -309,7 +309,7 @@ rew_pending(struct roff_man *mdoc, const struct roff_n if (n->type == ROFFT_BLOCK || n->type == ROFFT_HEAD) { - if (n->flags & MDOC_ENDED) + if (n->flags & NODE_ENDED) break; else return; @@ -322,8 +322,8 @@ rew_pending(struct roff_man *mdoc, const struct roff_n * For a block closing macro, return the corresponding opening one. * Otherwise, return the macro itself. */ -static int -rew_alt(int tok) +static enum roff_tok +rew_alt(enum roff_tok tok) { switch (tok) { case MDOC_Ac: @@ -364,7 +364,7 @@ rew_alt(int tok) } static void -rew_elem(struct roff_man *mdoc, int tok) +rew_elem(struct roff_man *mdoc, enum roff_tok tok) { struct roff_node *n; @@ -376,38 +376,52 @@ rew_elem(struct roff_man *mdoc, int tok) rew_last(mdoc, n); } +static void +break_intermediate(struct roff_node *n, struct roff_node *breaker) +{ + if (n != breaker && + n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD && + (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) + n = n->parent; + while (n != breaker) { + if ( ! (n->flags & NODE_VALID)) + n->flags |= NODE_BROKEN; + n = n->parent; + } +} + /* * If there is an open sub-block of the target requiring * explicit close-out, postpone closing out the target until * the rew_pending() call closing out the sub-block. */ static int -find_pending(struct roff_man *mdoc, int tok, int line, int ppos, +find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos, struct roff_node *target) { struct roff_node *n; int irc; + if (target->flags & NODE_VALID) + return 0; + irc = 0; for (n = mdoc->last; n != NULL && n != target; n = n->parent) { - if (n->flags & MDOC_ENDED) { - if ( ! (n->flags & MDOC_VALID)) - n->flags |= MDOC_BROKEN; + if (n->flags & NODE_ENDED) continue; - } if (n->type == ROFFT_BLOCK && mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { irc = 1; - n->flags = MDOC_BROKEN; + break_intermediate(mdoc->last, target); if (target->type == ROFFT_HEAD) - target->flags = MDOC_ENDED; - else if ( ! (target->flags & MDOC_ENDED)) { + target->flags |= NODE_ENDED; + else if ( ! (target->flags & NODE_ENDED)) { mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, - "%s breaks %s", mdoc_macronames[tok], - mdoc_macronames[n->tok]); + "%s breaks %s", roff_name[tok], + roff_name[n->tok]); mdoc_endbody_alloc(mdoc, line, ppos, - tok, target, ENDBODY_NOSPACE); + tok, target); } } } @@ -444,11 +458,11 @@ dword(struct roff_man *mdoc, int line, int col, const */ if (d == DELIM_OPEN) - mdoc->last->flags |= MDOC_DELIMO; + mdoc->last->flags |= NODE_DELIMO; else if (d == DELIM_CLOSE && ! (mdoc->flags & MDOC_NODELIMC) && mdoc->last->parent->tok != MDOC_Fd) - mdoc->last->flags |= MDOC_DELIMC; + mdoc->last->flags |= NODE_DELIMC; mdoc->flags &= ~MDOC_NODELIMC; } @@ -481,7 +495,7 @@ append_delims(struct roff_man *mdoc, int line, int *po */ if (mandoc_eos(p, strlen(p))) - mdoc->last->flags |= MDOC_EOS; + mdoc->last->flags |= NODE_EOS; } } @@ -508,7 +522,8 @@ macro_or_word(MACRO_PROT_ARGS, int parsed) mdoc_macros[tok].flags & MDOC_JOIN); return 0; } else { - if (mdoc_macros[tok].fp == in_line_eoln) + if (tok != TOKEN_NONE && + mdoc_macros[tok].fp == in_line_eoln) rew_elem(mdoc, tok); mdoc_macro(mdoc, ntok, line, ppos, pos, buf); if (tok == TOKEN_NONE) @@ -532,7 +547,7 @@ blk_exp_close(MACRO_PROT_ARGS) int j, lastarg, maxargs, nl, pending; enum margserr ac; - int atok, ntok; + enum roff_tok atok, ntok; char *p; nl = MDOC_NEWLINE & mdoc->flags; @@ -549,30 +564,46 @@ blk_exp_close(MACRO_PROT_ARGS) break; } + /* Search backwards for the beginning of our own body. */ + + atok = rew_alt(tok); + body = NULL; + for (n = mdoc->last; n; n = n->parent) { + if (n->flags & NODE_ENDED || n->tok != atok || + n->type != ROFFT_BODY || n->end != ENDBODY_NOT) + continue; + body = n; + break; + } + /* * Search backwards for beginnings of blocks, * both of our own and of pending sub-blocks. */ - atok = rew_alt(tok); - body = endbody = itblk = later = NULL; + endbody = itblk = later = NULL; for (n = mdoc->last; n; n = n->parent) { - if (n->flags & MDOC_ENDED) { - if ( ! (n->flags & MDOC_VALID)) - n->flags |= MDOC_BROKEN; + if (n->flags & NODE_ENDED) continue; - } - /* Remember the start of our own body. */ + /* + * Mismatching end macros can never break anything + * and we only care about the breaking of BLOCKs. + */ - if (n->type == ROFFT_BODY && atok == n->tok) { - if (n->end == ENDBODY_NOT) - body = n; + if (body == NULL || n->type != ROFFT_BLOCK) continue; - } - if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm) + /* + * SYNOPSIS name blocks can not be broken themselves, + * but they do get broken together with a broken child. + */ + + if (n->tok == MDOC_Nm) { + if (later != NULL) + n->flags |= NODE_BROKEN | NODE_ENDED; continue; + } if (n->tok == MDOC_It) { itblk = n; @@ -580,7 +611,6 @@ blk_exp_close(MACRO_PROT_ARGS) } if (atok == n->tok) { - assert(body); /* * Found the start of our own block. @@ -602,14 +632,13 @@ blk_exp_close(MACRO_PROT_ARGS) mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, "%s breaks %s", - mdoc_macronames[atok], - mdoc_macronames[later->tok]); + roff_name[atok], roff_name[later->tok]); endbody = mdoc_endbody_alloc(mdoc, line, ppos, - atok, body, ENDBODY_SPACE); + atok, body); if (tok == MDOC_El) - itblk->flags |= MDOC_ENDED | MDOC_BROKEN; + itblk->flags |= NODE_ENDED | NODE_BROKEN; /* * If a block closing macro taking arguments @@ -622,32 +651,37 @@ blk_exp_close(MACRO_PROT_ARGS) break; } - /* Explicit blocks close out description lines. */ + /* + * Explicit blocks close out description lines, but + * even those can get broken together with a child. + */ if (n->tok == MDOC_Nd) { - rew_last(mdoc, n); + if (later != NULL) + n->flags |= NODE_BROKEN | NODE_ENDED; + else + rew_last(mdoc, n); continue; } /* Breaking an open sub block. */ - n->flags |= MDOC_BROKEN; + break_intermediate(mdoc->last, body); + n->flags |= NODE_BROKEN; if (later == NULL) later = n; } if (body == NULL) { mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse, - line, ppos, mdoc_macronames[tok]); - if (later != NULL) - later->flags &= ~MDOC_BROKEN; + line, ppos, roff_name[tok]); if (maxargs && endbody == NULL) { /* * Stray .Ec without previous .Eo: * Break the output line, keep the arguments. */ - roff_elem_alloc(mdoc, line, ppos, MDOC_br); - rew_elem(mdoc, MDOC_br); + roff_elem_alloc(mdoc, line, ppos, ROFF_br); + rew_elem(mdoc, ROFF_br); } } else if (endbody == NULL) { rew_last(mdoc, body); @@ -659,7 +693,7 @@ blk_exp_close(MACRO_PROT_ARGS) if (buf[*pos] != '\0') mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, line, ppos, - "%s %s", mdoc_macronames[tok], + "%s %s", roff_name[tok], buf + *pos); if (endbody == NULL && n != NULL) rew_pending(mdoc, n); @@ -697,15 +731,14 @@ blk_exp_close(MACRO_PROT_ARGS) } if (n != NULL) { - if (ntok != TOKEN_NONE && n->flags & MDOC_BROKEN) { + pending = 0; + if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN) { target = n; do target = target->parent; - while ( ! (target->flags & MDOC_ENDED)); - pending = find_pending(mdoc, ntok, line, ppos, - target); - } else - pending = 0; + while ( ! (target->flags & NODE_ENDED)); + pending = find_pending(mdoc, ntok, line, ppos, target); + } if ( ! pending) rew_pending(mdoc, n); } @@ -717,7 +750,7 @@ static void in_line(MACRO_PROT_ARGS) { int la, scope, cnt, firstarg, mayopen, nc, nl; - int ntok; + enum roff_tok ntok; enum margserr ac; enum mdelim d; struct mdoc_arg *arg; @@ -760,7 +793,7 @@ in_line(MACRO_PROT_ARGS) if (ac == ARGS_EOLN) { if (d == DELIM_OPEN) - mdoc->last->flags &= ~MDOC_DELIMO; + mdoc->last->flags &= ~NODE_DELIMO; break; } @@ -798,7 +831,7 @@ in_line(MACRO_PROT_ARGS) mdoc_argv_free(arg); mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, line, ppos, - mdoc_macronames[tok]); + roff_name[tok]); } mdoc_macro(mdoc, ntok, line, la, pos, buf); if (nl) @@ -846,7 +879,7 @@ in_line(MACRO_PROT_ARGS) } dword(mdoc, line, la, p, d, - MDOC_JOIN & mdoc_macros[tok].flags); + mdoc_macros[tok].flags & MDOC_JOIN); /* * If the first argument is a closing delimiter, @@ -854,7 +887,7 @@ in_line(MACRO_PROT_ARGS) */ if (firstarg && d == DELIM_CLOSE && !nc) - mdoc->last->flags &= ~MDOC_DELIMC; + mdoc->last->flags &= ~NODE_DELIMC; firstarg = 0; /* @@ -868,8 +901,10 @@ in_line(MACRO_PROT_ARGS) } } - if (scope) + if (scope && tok != MDOC_Lk) { rew_elem(mdoc, tok); + scope = 0; + } /* * If no elements have been collected and we're allowed to have @@ -884,11 +919,13 @@ in_line(MACRO_PROT_ARGS) } else { mdoc_argv_free(arg); mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, mdoc_macronames[tok]); + line, ppos, roff_name[tok]); } } if (nl) append_delims(mdoc, line, pos, buf); + if (scope) + rew_elem(mdoc, tok); } static void @@ -907,7 +944,7 @@ blk_full(MACRO_PROT_ARGS) if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, mdoc_macronames[tok]); + line, ppos, roff_name[tok]); return; } @@ -917,9 +954,9 @@ blk_full(MACRO_PROT_ARGS) blk = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->flags & MDOC_ENDED) { - if ( ! (n->flags & MDOC_VALID)) - n->flags |= MDOC_BROKEN; + if (n->flags & NODE_ENDED) { + if ( ! (n->flags & NODE_VALID)) + n->flags |= NODE_BROKEN; continue; } if (n->type != ROFFT_BLOCK) @@ -930,7 +967,7 @@ blk_full(MACRO_PROT_ARGS) mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, "It breaks %s", - mdoc_macronames[blk->tok]); + roff_name[blk->tok]); rew_pending(mdoc, blk); } break; @@ -942,9 +979,8 @@ blk_full(MACRO_PROT_ARGS) case MDOC_Ss: mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, - "%s breaks %s", - mdoc_macronames[tok], - mdoc_macronames[n->tok]); + "%s breaks %s", roff_name[tok], + roff_name[n->tok]); rew_pending(mdoc, n); n = mdoc->last; continue; @@ -970,15 +1006,14 @@ blk_full(MACRO_PROT_ARGS) if (blk != NULL) { mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, - "It breaks %s", - mdoc_macronames[blk->tok]); + "It breaks %s", roff_name[blk->tok]); rew_pending(mdoc, blk); blk = NULL; } /* Close out prior implicit scopes. */ - rew_last(mdoc, n); + rew_pending(mdoc, n); } /* Skip items outside lists. */ @@ -986,8 +1021,8 @@ blk_full(MACRO_PROT_ARGS) if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, line, ppos, "It %s", buf + *pos); - roff_elem_alloc(mdoc, line, ppos, MDOC_br); - rew_elem(mdoc, MDOC_br); + roff_elem_alloc(mdoc, line, ppos, ROFF_br); + rew_elem(mdoc, ROFF_br); return; } } @@ -1064,7 +1099,7 @@ blk_full(MACRO_PROT_ARGS) if (tok == MDOC_Bd || tok == MDOC_Bk) { mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, line, la, "%s ... %s", - mdoc_macronames[tok], buf + la); + roff_name[tok], buf + la); break; } if (tok == MDOC_Rs) { @@ -1120,7 +1155,7 @@ blk_full(MACRO_PROT_ARGS) break; } - if (blk->flags & MDOC_VALID) + if (blk->flags & NODE_VALID) return; if (head == NULL) head = roff_head_alloc(mdoc, line, ppos, tok); @@ -1272,7 +1307,7 @@ in_line_argn(MACRO_PROT_ARGS) struct mdoc_arg *arg; char *p; enum margserr ac; - int ntok; + enum roff_tok ntok; int state; /* arg#; -1: not yet open; -2: closed */ int la, maxargs, nl; @@ -1362,12 +1397,12 @@ in_line_argn(MACRO_PROT_ARGS) } dword(mdoc, line, la, p, DELIM_MAX, - MDOC_JOIN & mdoc_macros[tok].flags); + mdoc_macros[tok].flags & MDOC_JOIN); } if (state == -1) { mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, mdoc_macronames[tok]); + line, ppos, roff_name[tok]); return; } @@ -1395,9 +1430,9 @@ in_line_eoln(MACRO_PROT_ARGS) } if (buf[*pos] == '\0' && - (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) { + (tok == MDOC_Fd || *roff_name[tok] == '%')) { mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - line, ppos, mdoc_macronames[tok]); + line, ppos, roff_name[tok]); return; } @@ -1414,7 +1449,8 @@ in_line_eoln(MACRO_PROT_ARGS) * or until the next macro, call that macro, and return 1. */ static int -parse_rest(struct roff_man *mdoc, int tok, int line, int *pos, char *buf) +parse_rest(struct roff_man *mdoc, enum roff_tok tok, + int line, int *pos, char *buf) { int la; @@ -1455,7 +1491,7 @@ phrase_ta(MACRO_PROT_ARGS) body = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->flags & MDOC_ENDED) + if (n->flags & NODE_ENDED) continue; if (n->tok == MDOC_It && n->type == ROFFT_BODY) body = n;