=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.169 retrieving revision 1.177 diff -u -p -r1.169 -r1.177 --- mandoc/mdoc_macro.c 2015/02/02 19:23:23 1.169 +++ mandoc/mdoc_macro.c 2015/02/06 01:07:22 1.177 @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.169 2015/02/02 19:23:23 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.177 2015/02/06 01:07:22 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010, 2012-2015 Ingo Schwarze @@ -31,13 +31,6 @@ #include "libmdoc.h" #include "libmandoc.h" -enum rew { /* see rew_dohalt() */ - REWIND_NONE, - REWIND_THIS, - REWIND_MORE, - REWIND_FORCE -}; - static void blk_full(MACRO_PROT_ARGS); static void blk_exp_close(MACRO_PROT_ARGS); static void blk_part_exp(MACRO_PROT_ARGS); @@ -59,13 +52,9 @@ static void make_pending(struct mdoc *, struct mdoc_n static int parse_rest(struct mdoc *, enum mdoct, int, int *, char *); static enum mdoct rew_alt(enum mdoct); -static enum rew rew_dohalt(enum mdoct, enum mdoc_type, - const struct mdoc_node *); static void rew_elem(struct mdoc *, enum mdoct); static void rew_last(struct mdoc *, const struct mdoc_node *); static void rew_pending(struct mdoc *, const struct mdoc_node *); -static void rew_sub(enum mdoc_type, struct mdoc *, - enum mdoct, int, int); const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ @@ -273,9 +262,6 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to assert(to); mdoc->next = MDOC_NEXT_SIBLING; while (mdoc->last != to) { - if ( ! (mdoc->last->flags & MDOC_VALID)) - mdoc->last->lastline = to->lastline - - (mdoc->flags & MDOC_NEWLINE ? 1 : 0); /* * Save the parent here, because we may delete the * mdoc->last node in the post-validation phase and reset @@ -357,95 +343,6 @@ rew_alt(enum mdoct tok) /* NOTREACHED */ } -/* - * Rewinding to tok, how do we have to handle *p? - * REWIND_NONE: *p would delimit tok, but no tok scope is open - * inside *p, so there is no need to rewind anything at all. - * REWIND_THIS: *p matches tok, so rewind *p and nothing else. - * REWIND_MORE: *p is implicit, rewind it and keep searching for tok. - * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p. - */ -static enum rew -rew_dohalt(enum mdoct tok, enum mdoc_type type, - const struct mdoc_node *p) -{ - - /* - * No matching token, no delimiting block, no broken block. - * This can happen when full implicit macros are called for - * the first time but try to rewind their previous - * instance anyway. - */ - if (MDOC_ROOT == p->type) - return(REWIND_NONE); - - /* - * When starting to rewind, skip plain text - * and nodes that have already been rewound. - */ - if (p->type == MDOC_TEXT || p->flags & (MDOC_VALID | MDOC_BREAK)) - return(REWIND_MORE); - - /* - * The easiest case: Found a matching token. - * This applies to both blocks and elements. - */ - tok = rew_alt(tok); - if (tok == p->tok) - return(type == p->type ? REWIND_THIS : REWIND_MORE); - - /* - * While elements do require rewinding for themselves, - * they never affect rewinding of other nodes. - */ - if (MDOC_ELEM == p->type) - return(REWIND_MORE); - - /* - * Blocks delimited by our target token get REWIND_MORE. - * Blocks delimiting our target token get REWIND_NONE. - */ - switch (tok) { - case MDOC_It: - if (MDOC_BODY == p->type && MDOC_Bl == p->tok) - return(REWIND_NONE); - break; - case MDOC_Nm: - return(REWIND_NONE); - case MDOC_Nd: - /* FALLTHROUGH */ - case MDOC_Ss: - if (MDOC_BODY == p->type && MDOC_Sh == p->tok) - return(REWIND_NONE); - /* FALLTHROUGH */ - case MDOC_Sh: - if (MDOC_ROOT == p->parent->type) - return(REWIND_THIS); - if (MDOC_Nd == p->tok || MDOC_Ss == p->tok || - MDOC_Sh == p->tok) - return(REWIND_MORE); - break; - default: - break; - } - - /* - * Default block rewinding rules. - * In particular, let all blocks rewind Nm children. - * Do not warn again when closing a block, - * since closing the body already warned. - */ - if (MDOC_Nm == p->tok || - MDOC_BLOCK == type || MDOC_BLOCK == p->type) - return(REWIND_MORE); - - /* - * By default, closing out full blocks - * forces closing of broken explicit blocks. - */ - return (REWIND_FORCE); -} - static void rew_elem(struct mdoc *mdoc, enum mdoct tok) { @@ -531,45 +428,6 @@ make_pending(struct mdoc *mdoc, struct mdoc_node *brea breaker->body->flags |= MDOC_BREAK; } -static void -rew_sub(enum mdoc_type t, struct mdoc *mdoc, - enum mdoct tok, int line, int ppos) -{ - struct mdoc_node *n, *to; - - to = NULL; - n = mdoc->last; - while (n) { - switch (rew_dohalt(tok, t, n)) { - case REWIND_NONE: - if (to == NULL) - return; - n = to; - break; - case REWIND_THIS: - n->lastline = line - - (mdoc->flags & MDOC_NEWLINE && - ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)); - break; - case REWIND_FORCE: - mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, - line, ppos, "%s breaks %s", - mdoc_macronames[tok], - mdoc_macronames[n->tok]); - /* FALLTHROUGH */ - case REWIND_MORE: - n->lastline = line - - (mdoc->flags & MDOC_NEWLINE ? 1 : 0); - to = n; - n = n->parent; - continue; - } - break; - } - assert(n); - rew_pending(mdoc, n); -} - /* * Allocate a word and check whether it's punctuation or not. * Punctuation consists of those tokens found in mdoc_isdelim(). @@ -680,10 +538,11 @@ blk_exp_close(MACRO_PROT_ARGS) { struct mdoc_node *body; /* Our own body. */ struct mdoc_node *endbody; /* Our own end marker. */ + struct mdoc_node *itblk; /* An It block starting later. */ struct mdoc_node *later; /* A sub-block starting later. */ struct mdoc_node *n; /* Search back to our block. */ - int have_it, j, lastarg, maxargs, nl; + int j, lastarg, maxargs, nl; enum margserr ac; enum mdoct atok, ntok; char *p; @@ -707,9 +566,8 @@ blk_exp_close(MACRO_PROT_ARGS) * both of our own and of pending sub-blocks. */ - have_it = 0; atok = rew_alt(tok); - body = endbody = later = NULL; + body = endbody = itblk = later = NULL; for (n = mdoc->last; n; n = n->parent) { if (n->flags & (MDOC_VALID | MDOC_BREAK)) continue; @@ -717,10 +575,8 @@ blk_exp_close(MACRO_PROT_ARGS) /* Remember the start of our own body. */ if (n->type == MDOC_BODY && atok == n->tok) { - if (n->end == ENDBODY_NOT) { + if (n->end == ENDBODY_NOT) body = n; - n->lastline = line; - } continue; } @@ -728,12 +584,11 @@ blk_exp_close(MACRO_PROT_ARGS) continue; if (n->tok == MDOC_It) { - have_it = 1; + itblk = n; continue; } if (atok == n->tok) { - n->lastline = line; assert(body); /* @@ -743,7 +598,7 @@ blk_exp_close(MACRO_PROT_ARGS) */ if (later == NULL || - (tok == MDOC_El && !have_it)) + (tok == MDOC_El && itblk == NULL)) break; /* @@ -753,6 +608,8 @@ blk_exp_close(MACRO_PROT_ARGS) */ make_pending(mdoc, n, later, line, ppos); + if (tok == MDOC_El) + itblk->flags |= MDOC_BREAK; /* * Mark the place where the formatting - but not @@ -807,7 +664,7 @@ blk_exp_close(MACRO_PROT_ARGS) mdoc->parse, line, ppos, "%s %s", mdoc_macronames[tok], buf + *pos); - if (endbody == NULL) + if (endbody == NULL && n != NULL) rew_pending(mdoc, n); return; } @@ -915,7 +772,7 @@ in_line(MACRO_PROT_ARGS) */ if (ac == ARGS_PUNCT) { - if (cnt == 0 && nc == 0) + if (cnt == 0 && (nc == 0 || tok == MDOC_An)) mdoc->flags |= MDOC_NODELIMC; break; } @@ -1038,7 +895,7 @@ blk_full(MACRO_PROT_ARGS) { int la, nl, parsed; struct mdoc_arg *arg; - struct mdoc_node *blk; /* Our own block. */ + struct mdoc_node *blk; /* Our own or a broken block. */ struct mdoc_node *head; /* Our own head. */ struct mdoc_node *body; /* Our own body. */ struct mdoc_node *n; @@ -1047,14 +904,80 @@ blk_full(MACRO_PROT_ARGS) nl = MDOC_NEWLINE & mdoc->flags; - /* Skip items outside lists. */ + if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + line, ppos, mdoc_macronames[tok]); + return; + } - if (tok == MDOC_It) { - for (n = mdoc->last; n; n = n->parent) - if (n->tok == MDOC_Bl && n->type == MDOC_BLOCK && - ! (n->flags & (MDOC_VALID | MDOC_BREAK))) + if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) { + + /* Here, tok is one of Sh Ss Nm Nd It. */ + + blk = NULL; + for (n = mdoc->last; n != NULL; n = n->parent) { + if (n->flags & (MDOC_VALID | MDOC_BREAK) || + n->type != MDOC_BLOCK) + continue; + if (tok == MDOC_It && n->tok == MDOC_Bl) { + if (blk != NULL) { + mandoc_vmsg(MANDOCERR_BLK_BROKEN, + mdoc->parse, line, ppos, + "It breaks %s", + mdoc_macronames[blk->tok]); + rew_pending(mdoc, blk); + } break; - if (n == NULL) { + } + + if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { + switch (tok) { + case MDOC_Sh: + /* FALLTHROUGH */ + case MDOC_Ss: + mandoc_vmsg(MANDOCERR_BLK_BROKEN, + mdoc->parse, line, ppos, + "%s breaks %s", + mdoc_macronames[tok], + mdoc_macronames[n->tok]); + rew_pending(mdoc, n); + continue; + case MDOC_It: + /* Delay in case it's astray. */ + blk = n; + continue; + default: + break; + } + break; + } + + /* Here, n is one of Sh Ss Nm Nd It. */ + + if (tok != MDOC_Sh && (n->tok == MDOC_Sh || + (tok != MDOC_Ss && (n->tok == MDOC_Ss || + (tok != MDOC_It && n->tok == MDOC_It))))) + break; + + /* Item breaking an explicit block. */ + + if (blk != NULL) { + mandoc_vmsg(MANDOCERR_BLK_BROKEN, + mdoc->parse, line, ppos, + "It breaks %s", + mdoc_macronames[blk->tok]); + rew_pending(mdoc, blk); + blk = NULL; + } + + /* Close out prior implicit scopes. */ + + rew_last(mdoc, n); + } + + /* Skip items outside lists. */ + + if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, line, ppos, "It %s", buf + *pos); mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL); @@ -1063,13 +986,6 @@ blk_full(MACRO_PROT_ARGS) } } - /* Close out prior implicit scope. */ - - if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) { - rew_sub(MDOC_BODY, mdoc, tok, line, ppos); - rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos); - } - /* * This routine accommodates implicitly- and explicitly-scoped * macro openings. Implicit ones first close out prior scope @@ -1111,8 +1027,6 @@ blk_full(MACRO_PROT_ARGS) la = *pos; lac = ac; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); - if (ac == ARGS_PUNCT) - break; if (ac == ARGS_EOLN) { if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE) break; @@ -1128,6 +1042,19 @@ blk_full(MACRO_PROT_ARGS) body = mdoc_body_alloc(mdoc, line, ppos, tok); break; } + if (tok == MDOC_Bd || tok == MDOC_Bk) { + mandoc_vmsg(MANDOCERR_ARG_EXCESS, + mdoc->parse, line, la, "%s ... %s", + mdoc_macronames[tok], buf + la); + break; + } + if (tok == MDOC_Rs) { + mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, + line, la, "Rs %s", buf + la); + break; + } + if (ac == ARGS_PUNCT) + break; /* * Emit leading punctuation (i.e., punctuation before @@ -1184,7 +1111,7 @@ blk_full(MACRO_PROT_ARGS) return; if (head == NULL) head = mdoc_head_alloc(mdoc, line, ppos, tok); - if (nl) + if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs) append_delims(mdoc, line, pos, buf); if (body != NULL) goto out; @@ -1446,6 +1373,11 @@ in_line_argn(MACRO_PROT_ARGS) } if (j == 0) { + if (tok == MDOC_In || tok == MDOC_St || tok == MDOC_Xr) { + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + line, ppos, mdoc_macronames[tok]); + return; + } mdoc_elem_alloc(mdoc, line, ppos, tok, arg); if (ac == ARGS_PUNCT && tok == MDOC_Pf) append_delims(mdoc, line, pos, buf); @@ -1459,10 +1391,17 @@ in_line_argn(MACRO_PROT_ARGS) static void in_line_eoln(MACRO_PROT_ARGS) { - struct mdoc_arg *arg; + struct mdoc_node *n; + struct mdoc_arg *arg; - if (tok == MDOC_Pp) - rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos); + if ((tok == MDOC_Pp || tok == MDOC_Lp) && + ! (mdoc->flags & MDOC_SYNOPSIS)) { + n = mdoc->last; + if (mdoc->next == MDOC_NEXT_SIBLING) + n = n->parent; + if (n->tok == MDOC_Nm) + rew_last(mdoc, mdoc->last->parent); + } mdoc_argv(mdoc, line, tok, &arg, pos, buf); mdoc_elem_alloc(mdoc, line, ppos, tok, arg);