=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.132 retrieving revision 1.148 diff -u -p -r1.132 -r1.148 --- mandoc/mdoc_macro.c 2014/07/02 03:48:07 1.132 +++ mandoc/mdoc_macro.c 2014/11/27 22:27:56 1.148 @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.132 2014/07/02 03:48:07 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.148 2014/11/27 22:27:56 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010, 2012, 2013 Ingo Schwarze + * Copyright (c) 2010, 2012, 2013, 2014 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 @@ -15,10 +15,10 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif +#include + #include #include #include @@ -147,9 +147,8 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ + { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | - MDOC_IGNDELIM | MDOC_JOIN }, /* No */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ @@ -172,7 +171,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT | MDOC_JOIN }, /* So */ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */ - { in_line_eoln, 0 }, /* Sm */ + { in_line_argn, 0 }, /* Sm */ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ @@ -210,7 +209,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ - { in_line_eoln, 0 }, /* ll */ + { in_line_eoln, MDOC_PROLOGUE }, /* ll */ }; const struct mdoc_macro * const mdoc_macros = __mdoc_macros; @@ -234,7 +233,8 @@ mdoc_macroend(struct mdoc *mdoc) for ( ; n; n = n->parent) if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags) - mdoc_nmsg(mdoc, n, MANDOCERR_SCOPEEXIT); + mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse, + n->line, n->pos, mdoc_macronames[n->tok]); /* Rewind to the first. */ @@ -423,6 +423,8 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type, 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); @@ -435,9 +437,11 @@ rew_dohalt(enum mdoct tok, enum mdoc_type type, * Default block rewinding rules. * In particular, always skip block end markers, * and let all blocks rewind Nm children. + * Do not warn again when closing a block, + * since closing the body already warned. */ if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok || - (MDOC_BLOCK == p->type && + MDOC_BLOCK == type || (MDOC_BLOCK == p->type && ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))) return(REWIND_MORE); @@ -528,7 +532,7 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, + mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[broken->tok]); return(1); @@ -558,7 +562,7 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc, ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)); break; case REWIND_FORCE: - mandoc_vmsg(MANDOCERR_SCOPEBROKEN, mdoc->parse, + mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[n->tok]); @@ -574,7 +578,9 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc, return(1); /* FALLTHROUGH */ case REWIND_ERROR: - mdoc_pmsg(mdoc, line, ppos, MANDOCERR_NOSCOPE); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, + mdoc->parse, line, ppos, + mdoc_macronames[tok]); return(1); } break; @@ -622,24 +628,22 @@ dword(struct mdoc *mdoc, int line, int col, const char if ( ! mdoc_word_alloc(mdoc, line, col, p)) return(0); - if (DELIM_OPEN == d) - mdoc->last->flags |= MDOC_DELIMO; - /* - * Closing delimiters only suppress the preceding space - * when they follow something, not when they start a new - * block or element, and not when they follow `No'. - * - * XXX Explicitly special-casing MDOC_No here feels - * like a layering violation. Find a better way - * and solve this in the code related to `No'! + * If the word consists of a bare delimiter, + * flag the new node accordingly, + * unless doing so was vetoed by the invoking macro. + * Always clear the veto, it is only valid for one word. */ - else if (DELIM_CLOSE == d && mdoc->last->prev && - mdoc->last->prev->tok != MDOC_No && + if (d == DELIM_OPEN) + mdoc->last->flags |= MDOC_DELIMO; + else if (d == DELIM_CLOSE && + ! (mdoc->flags & MDOC_NODELIMC) && mdoc->last->parent->tok != MDOC_Fd) mdoc->last->flags |= MDOC_DELIMC; + mdoc->flags &= ~MDOC_NODELIMC; + return(1); } @@ -689,6 +693,7 @@ static int blk_exp_close(MACRO_PROT_ARGS) { struct mdoc_node *body; /* Our own body. */ + struct mdoc_node *endbody; /* Our own end marker. */ struct mdoc_node *later; /* A sub-block starting later. */ struct mdoc_node *n; /* For searching backwards. */ @@ -715,7 +720,7 @@ blk_exp_close(MACRO_PROT_ARGS) * both of our own and of pending sub-blocks. */ atok = rew_alt(tok); - body = later = NULL; + body = endbody = later = NULL; for (n = mdoc->last; n; n = n->parent) { if (MDOC_VALID & n->flags) continue; @@ -754,6 +759,10 @@ blk_exp_close(MACRO_PROT_ARGS) if ( ! mdoc_endbody_alloc(mdoc, line, ppos, atok, body, ENDBODY_SPACE)) return(0); + if (maxargs) { + endbody = mdoc->last; + mdoc->next = MDOC_NEXT_CHILD; + } break; } @@ -769,11 +778,12 @@ blk_exp_close(MACRO_PROT_ARGS) later = n; } - if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { - /* FIXME: do this in validate */ - if (buf[*pos]) - mdoc_pmsg(mdoc, line, ppos, MANDOCERR_ARGSLOST); - + if ( ! (MDOC_PARSED & mdoc_macros[tok].flags)) { + if ('\0' != buf[*pos]) + mandoc_vmsg(MANDOCERR_ARG_SKIP, + mdoc->parse, line, ppos, + "%s %s", mdoc_macronames[tok], + buf + *pos); if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); return(rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)); @@ -782,15 +792,28 @@ blk_exp_close(MACRO_PROT_ARGS) if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if (NULL == later && maxargs > 0) - if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok))) + if (maxargs && endbody == NULL) { + if (n == NULL) { + /* + * Stray .Ec without previous .Eo: + * Break the output line, ignore any arguments. + */ + if ( ! mdoc_elem_alloc(mdoc, line, ppos, + MDOC_br, NULL)) + return(0); + if ( ! rew_elem(mdoc, MDOC_br)) + return(0); + } else if ( ! mdoc_tail_alloc(mdoc, line, ppos, atok)) return(0); + } - for (flushed = j = 0; ; j++) { + flushed = n == NULL; + for (j = 0; ; j++) { lastarg = *pos; if (j == maxargs && ! flushed) { - if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) + if ( ! (endbody != NULL ? rew_last(mdoc, endbody) : + rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))) return(0); flushed = 1; } @@ -814,7 +837,8 @@ blk_exp_close(MACRO_PROT_ARGS) } if ( ! flushed) { - if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) + if ( ! (endbody != NULL ? rew_last(mdoc, endbody) : + rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))) return(0); flushed = 1; } @@ -826,7 +850,8 @@ blk_exp_close(MACRO_PROT_ARGS) break; } - if ( ! flushed && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) + if ( ! flushed && ! (endbody != NULL ? rew_last(mdoc, endbody) : + rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))) return(0); if ( ! nl) @@ -837,7 +862,7 @@ blk_exp_close(MACRO_PROT_ARGS) static int in_line(MACRO_PROT_ARGS) { - int la, scope, cnt, nc, nl; + int la, scope, cnt, firstarg, mayopen, nc, nl; enum margverr av; enum mdoct ntok; enum margserr ac; @@ -888,18 +913,43 @@ in_line(MACRO_PROT_ARGS) return(0); } + d = DELIM_NONE; + firstarg = 1; + mayopen = 1; for (cnt = scope = 0;; ) { la = *pos; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); - if (ARGS_ERROR == ac) + if (ac == ARGS_ERROR) return(0); - if (ARGS_EOLN == ac) + + /* + * At the end of a macro line, + * opening delimiters do not suppress spacing. + */ + + if (ac == ARGS_EOLN) { + if (d == DELIM_OPEN) + mdoc->last->flags &= ~MDOC_DELIMO; break; - if (ARGS_PUNCT == ac) + } + + /* + * The rest of the macro line is only punctuation, + * to be handled by append_delims(). + * If there were no other arguments, + * do not allow the first one to suppress spacing, + * even if it turns out to be a closing one. + */ + + if (ac == ARGS_PUNCT) { + if (cnt == 0 && nc == 0) + mdoc->flags |= MDOC_NODELIMC; break; + } - ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); + ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ? + MDOC_MAX : lookup(tok, p); /* * In this case, we've located a submacro and must @@ -919,8 +969,9 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - mdoc_pmsg(mdoc, line, ppos, - MANDOCERR_MACROEMPTY); + mandoc_msg(MANDOCERR_MACRO_EMPTY, + mdoc->parse, line, ppos, + mdoc_macronames[tok]); } if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) @@ -941,21 +992,20 @@ in_line(MACRO_PROT_ARGS) if (DELIM_NONE != d) { /* * If we encounter closing punctuation, no word - * has been omitted, no scope is open, and we're + * has been emitted, no scope is open, and we're * allowed to have an empty element, then start - * a new scope. `Ar', `Fl', and `Li', only do - * this once per invocation. There may be more - * of these (all of them?). + * a new scope. */ - if (0 == cnt && (nc || MDOC_Li == tok) && - DELIM_CLOSE == d && ! scope) { + if ((d == DELIM_CLOSE || + (d == DELIM_MIDDLE && tok == MDOC_Fl)) && + !cnt && !scope && nc && mayopen) { if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); - if (MDOC_Ar == tok || MDOC_Li == tok || - MDOC_Fl == tok) - cnt++; scope = 1; + cnt++; + if (MDOC_Nm == tok) + mayopen = 0; } /* * Close out our scope, if one is open, before @@ -964,20 +1014,29 @@ in_line(MACRO_PROT_ARGS) if (scope && ! rew_elem(mdoc, tok)) return(0); scope = 0; - } else if ( ! scope) { + if (tok == MDOC_Fn) + mayopen = 0; + } else if (mayopen && !scope) { if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); scope = 1; + cnt++; } - if (DELIM_NONE == d) - cnt++; - if ( ! dword(mdoc, line, la, p, d, MDOC_JOIN & mdoc_macros[tok].flags)) return(0); /* + * If the first argument is a closing delimiter, + * do not suppress spacing before it. + */ + + if (firstarg && d == DELIM_CLOSE && !nc) + mdoc->last->flags &= ~MDOC_DELIMC; + firstarg = 0; + + /* * `Fl' macros have their scope re-opened with each new * word so that the `-' can be added to each one without * having to parse out spaces. @@ -1005,7 +1064,8 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROEMPTY); + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + line, ppos, mdoc_macronames[tok]); } if ( ! nl) @@ -1029,6 +1089,23 @@ blk_full(MACRO_PROT_ARGS) nl = MDOC_NEWLINE & mdoc->flags; + /* Skip items outside lists. */ + + if (tok == MDOC_It) { + for (n = mdoc->last; n; n = n->parent) + if (n->tok == MDOC_Bl && + ! (n->flags & MDOC_VALID)) + break; + if (n == NULL) { + mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, + line, ppos, "It %s", buf + *pos); + if ( ! mdoc_elem_alloc(mdoc, line, ppos, + MDOC_br, NULL)) + return(0); + return(rew_elem(mdoc, MDOC_br)); + } + } + /* Close out prior implicit scope. */ if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { @@ -1354,18 +1431,9 @@ blk_part_imp(MACRO_PROT_ARGS) return(1); } } + assert(n == body); - /* - * If we can't rewind to our body, then our scope has already - * been closed by another macro (like `Oc' closing `Op'). This - * is ugly behaviour nodding its head to OpenBSD's overwhelming - * crufty use of `Op' breakage. - */ - if (n != body) - mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, - ppos, "%s broken", mdoc_macronames[tok]); - - if (n && ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); /* Standard appending of delimiters. */ @@ -1375,7 +1443,7 @@ blk_part_imp(MACRO_PROT_ARGS) /* Rewind scope, if applicable. */ - if (n && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); /* Move trailing .Ns out of scope. */ @@ -1518,8 +1586,6 @@ in_line_argn(MACRO_PROT_ARGS) switch (tok) { case MDOC_Ap: /* FALLTHROUGH */ - case MDOC_No: - /* FALLTHROUGH */ case MDOC_Ns: /* FALLTHROUGH */ case MDOC_Ux: @@ -1573,7 +1639,7 @@ in_line_argn(MACRO_PROT_ARGS) return(0); continue; } else if (0 == j) - if ( ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); if (j == maxargs && ! flushed) { @@ -1609,7 +1675,7 @@ in_line_argn(MACRO_PROT_ARGS) j++; } - if (0 == j && ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) + if (0 == j && ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); /* Close out in a consistent state. */ @@ -1769,7 +1835,8 @@ phrase_ta(MACRO_PROT_ARGS) while (NULL != n && MDOC_Bl != n->tok) n = n->parent; if (NULL == n || LIST_column != n->norm->Bl.type) { - mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA); + mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse, + line, ppos, "Ta"); return(1); }