=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.84 retrieving revision 1.88 diff -u -p -r1.84 -r1.88 --- mandoc/mdoc_macro.c 2010/06/29 19:24:14 1.84 +++ mandoc/mdoc_macro.c 2010/07/01 15:38:56 1.88 @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.84 2010/06/29 19:24:14 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.88 2010/07/01 15:38:56 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -52,7 +52,7 @@ static int append_delims(struct mdoc *, int, int *, char *); static enum mdoct lookup(enum mdoct, const char *); static enum mdoct lookup_raw(const char *); -static int make_pending(struct mdoc_node *, enum mdoc_type, +static int make_pending(struct mdoc_node *, enum mdoct, struct mdoc *, int, int); static int phrase(struct mdoc *, int, int, char *); static enum mdoct rew_alt(enum mdoct); @@ -97,7 +97,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ { blk_full, 0 }, /* Nd */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ + { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ { obsolete, 0 }, /* Ot */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ @@ -335,21 +335,44 @@ 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(MDOC_BLOCK == type && MDOC_EXPLICIT & mdoc_macros[tok].flags ? REWIND_ERROR : REWIND_NONE); + + /* + * When starting to rewind, skip plain text + * and nodes that have already been rewound. + */ if (MDOC_TEXT == p->type || MDOC_VALID & p->flags) 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(p->end ? REWIND_NONE : 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_Bl): if (MDOC_It == p->tok) @@ -369,6 +392,8 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type, if (MDOC_Op == p->tok) return(REWIND_MORE); break; + case (MDOC_Nm): + return(REWIND_NONE); case (MDOC_Nd): /* FALLTHROUGH */ case (MDOC_Ss): @@ -384,9 +409,27 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type, break; } - return(p->end || (MDOC_BLOCK == p->type && - ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) ? - REWIND_MORE : REWIND_LATER); + /* + * Default block rewinding rules. + * In particular, always skip block end markers, + * and let all blocks rewind Nm children. + */ + if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok || + (MDOC_BLOCK == p->type && + ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))) + return(REWIND_MORE); + + /* + * Partial blocks allow delayed rewinding by default. + */ + if (&blk_full != mdoc_macros[tok].fp) + return (REWIND_LATER); + + /* + * Full blocks can only be rewound when matching + * or when there is an explicit rule. + */ + return(REWIND_ERROR); } @@ -468,8 +511,9 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mdoc_vmsg(m, MANDOCERR_SCOPE, line, ppos, "%s breaks %s", - mdoc_macronames[tok], mdoc_macronames[broken->tok]); + mdoc_vmsg(m, MANDOCERR_SCOPENEST, line, ppos, + "%s breaks %s", mdoc_macronames[tok], + mdoc_macronames[broken->tok]); return(1); } @@ -503,7 +547,9 @@ rew_sub(enum mdoc_type t, struct mdoc *m, return(make_pending(n, tok, m, line, ppos)); case (REWIND_ERROR): /* XXX Make this non-fatal. */ - mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTNOSCOPE); + mdoc_vmsg(m, MANDOCERR_SCOPEFATAL, line, ppos, + "%s cannot break %s", mdoc_macronames[tok], + mdoc_macronames[n->tok]); return 0; } break; @@ -609,12 +655,12 @@ blk_exp_close(MACRO_PROT_ARGS) /* Remember the start of our own body. */ if (MDOC_BODY == n->type && atok == n->tok) { - if ( ! n->end) + if (ENDBODY_NOT == n->end) body = n; continue; } - if (MDOC_BLOCK != n->type) + if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok) continue; if (atok == n->tok) { assert(body); @@ -1251,8 +1297,8 @@ blk_part_imp(MACRO_PROT_ARGS) * is ugly behaviour nodding its head to OpenBSD's overwhelming * crufty use of `Op' breakage. */ - if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPE, line, ppos, - "%s broken", mdoc_macronames[tok])) + if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPENEST, + line, ppos, "%s broken", mdoc_macronames[tok])) return(0); if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) @@ -1608,7 +1654,9 @@ ctx_synopsis(MACRO_PROT_ARGS) * up formatting the block scope, then child nodes will inherit * the formatting. Be careful. */ - + if (MDOC_Nm == tok) + return(blk_full(m, tok, line, ppos, pos, buf)); + assert(MDOC_Vt == tok); return(blk_part_imp(m, tok, line, ppos, pos, buf)); }