=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.67 retrieving revision 1.76 diff -u -p -r1.67 -r1.76 --- mandoc/mdoc_macro.c 2010/05/15 08:54:04 1.67 +++ mandoc/mdoc_macro.c 2010/05/31 11:52:06 1.76 @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.67 2010/05/15 08:54:04 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.76 2010/05/31 11:52:06 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -25,6 +25,7 @@ #include #include +#include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" @@ -43,13 +44,13 @@ static int in_line_eoln(MACRO_PROT_ARGS); static int in_line_argn(MACRO_PROT_ARGS); static int in_line(MACRO_PROT_ARGS); static int obsolete(MACRO_PROT_ARGS); +static int phrase_ta(MACRO_PROT_ARGS); 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 phrase(struct mdoc *, int, int, - char *, enum margserr); +static int phrase(struct mdoc *, int, int, char *); static enum mdoct rew_alt(enum mdoct); static int rew_dobreak(enum mdoct, const struct mdoc_node *); @@ -170,7 +171,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, 0 }, /* Hf */ { obsolete, 0 }, /* Fr */ { in_line_eoln, 0 }, /* Ud */ - { in_line_eoln, 0 }, /* Lb */ + { in_line, 0 }, /* Lb */ { in_line_eoln, 0 }, /* Lp */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ @@ -185,6 +186,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, 0 }, /* br */ { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ + { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ }; const struct mdoc_macro * const mdoc_macros = __mdoc_macros; @@ -195,6 +197,7 @@ swarn(struct mdoc *mdoc, enum mdoc_type type, int line, int pos, const struct mdoc_node *p) { const char *n, *t, *tt; + enum mandocerr ec; n = t = ""; tt = "block"; @@ -227,13 +230,12 @@ swarn(struct mdoc *mdoc, enum mdoc_type type, break; } - if ( ! (MDOC_IGN_SCOPE & mdoc->pflags)) - return(mdoc_verr(mdoc, line, pos, - "%s scope breaks %s scope of %s", + ec = (MDOC_IGN_SCOPE & mdoc->pflags) ? + MANDOCERR_SCOPE : MANDOCERR_SYNTSCOPE; + + return(mdoc_vmsg(mdoc, ec, line, pos, + "%s scope breaks %s of %s", tt, t, n)); - return(mdoc_vwarn(mdoc, line, pos, - "%s scope breaks %s scope of %s", - tt, t, n)); } @@ -256,7 +258,8 @@ mdoc_macroend(struct mdoc *m) continue; if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags)) continue; - return(mdoc_nerr(m, n, EOPEN)); + mdoc_nmsg(m, n, MANDOCERR_SYNTSCOPE); + return(0); } /* Rewind to the first. */ @@ -588,7 +591,9 @@ rew_sub(enum mdoc_type t, struct mdoc *m, return(1); if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) return(1); - return(mdoc_perr(m, line, ppos, ENOCTX)); + /* FIXME: shouldn't raise an error */ + mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTNOSCOPE); + return(0); } if (REWIND_REWIND == c) break; @@ -686,8 +691,9 @@ blk_exp_close(MACRO_PROT_ARGS) } if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { + /* FIXME: do this in validate */ if (buf[*pos]) - if ( ! mdoc_pwarn(m, line, ppos, ENOLINE)) + if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST)) return(0); if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) @@ -750,7 +756,7 @@ blk_exp_close(MACRO_PROT_ARGS) static int in_line(MACRO_PROT_ARGS) { - int la, lastpunct, cnt, nc, nl; + int la, scope, cnt, nc, nl; enum margverr av; enum mdoct ntok; enum margserr ac; @@ -801,7 +807,7 @@ in_line(MACRO_PROT_ARGS) return(0); } - for (cnt = 0, lastpunct = 1;; ) { + for (cnt = scope = 0;; ) { la = *pos; ac = mdoc_args(m, line, pos, buf, tok, &p); @@ -822,7 +828,7 @@ in_line(MACRO_PROT_ARGS) */ if (MDOC_MAX != ntok) { - if (0 == lastpunct && ! rew_elem(m, tok)) + if (scope && ! rew_elem(m, tok)) return(0); if (nc && 0 == cnt) { if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) @@ -831,7 +837,7 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - if ( ! mdoc_pwarn(m, line, ppos, EIGNE)) + if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY)) return(0); } if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) @@ -849,14 +855,35 @@ in_line(MACRO_PROT_ARGS) d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p); - if (ARGS_QWORD != ac && DELIM_NONE != d) { - if (0 == lastpunct && ! rew_elem(m, tok)) + if (DELIM_NONE != d) { + /* + * If we encounter closing punctuation, no word + * has been omitted, 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?). + */ + if (0 == cnt && (nc || MDOC_Li == tok) && + DELIM_CLOSE == d && ! scope) { + if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + return(0); + if (MDOC_Ar == tok || MDOC_Li == tok || + MDOC_Fl == tok) + cnt++; + scope = 1; + } + /* + * Close out our scope, if one is open, before + * any punctuation. + */ + if (scope && ! rew_elem(m, tok)) return(0); - lastpunct = 1; - } else if (lastpunct) { + scope = 0; + } else if ( ! scope) { if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) return(0); - lastpunct = 0; + scope = 1; } if (DELIM_NONE == d) @@ -869,14 +896,14 @@ in_line(MACRO_PROT_ARGS) * word so that the `-' can be added to each one without * having to parse out spaces. */ - if (0 == lastpunct && MDOC_Fl == tok) { + if (scope && MDOC_Fl == tok) { if ( ! rew_elem(m, tok)) return(0); - lastpunct = 1; + scope = 0; } } - if (0 == lastpunct && ! rew_elem(m, tok)) + if (scope && ! rew_elem(m, tok)) return(0); /* @@ -892,7 +919,7 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - if ( ! mdoc_pwarn(m, line, ppos, EIGNE)) + if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY)) return(0); } @@ -912,6 +939,7 @@ blk_full(MACRO_PROT_ARGS) #ifdef UGLY struct mdoc_node *n; #endif + enum mdoc_type mtt; enum mdoct ntok; enum margserr ac, lac; enum margverr av; @@ -980,24 +1008,38 @@ blk_full(MACRO_PROT_ARGS) for ( ; ; ) { la = *pos; - lac = ac; + /* Initialise last-phrase-type with ARGS_PEND. */ + lac = ARGS_ERROR == ac ? ARGS_PEND : ac; ac = mdoc_args(m, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); - if (ARGS_EOLN == ac) - break; - if (ARGS_PEND == ac) { - if (ARGS_PPHRASE == lac) - ac = ARGS_PPHRASE; - else - ac = ARGS_PHRASE; + if (ARGS_EOLN == ac) { + if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac) + break; + /* + * This is necessary: if the last token on a + * line is a `Ta' or tab, then we'll get + * ARGS_EOLN, so we must be smart enough to + * reopen our scope if the last parse was a + * phrase or partial phrase. + */ + if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + return(0); + if ( ! mdoc_body_alloc(m, line, ppos, tok)) + return(0); + body = m->last; + break; } - /* Don't emit leading punct. for phrases. */ + /* + * Emit leading punctuation (i.e., punctuation before + * the MDOC_HEAD) for non-phrase types. + */ if (NULL == head && + ARGS_PEND != ac && ARGS_PHRASE != ac && ARGS_PPHRASE != ac && ARGS_QWORD != ac && @@ -1007,24 +1049,47 @@ blk_full(MACRO_PROT_ARGS) continue; } - /* Always re-open head for phrases. */ + /* Open a head if one hasn't been opened. */ - if (NULL == head || - ARGS_PHRASE == ac || - ARGS_PPHRASE == ac) { + if (NULL == head) { if ( ! mdoc_head_alloc(m, line, ppos, tok)) return(0); head = m->last; } - if (ARGS_PHRASE == ac || ARGS_PPHRASE == ac) { + if (ARGS_PHRASE == ac || + ARGS_PEND == ac || + ARGS_PPHRASE == ac) { + /* + * If we haven't opened a body yet, rewind the + * head; if we have, rewind that instead. + */ + + mtt = body ? MDOC_BODY : MDOC_HEAD; + if ( ! rew_sub(mtt, m, tok, line, ppos)) + return(0); + + /* Then allocate our body context. */ + + if ( ! mdoc_body_alloc(m, line, ppos, tok)) + return(0); + body = m->last; + + /* + * Process phrases: set whether we're in a + * partial-phrase (this effects line handling) + * then call down into the phrase parser. + */ + if (ARGS_PPHRASE == ac) m->flags |= MDOC_PPHRASE; - if ( ! phrase(m, line, la, buf, ac)) + if (ARGS_PEND == ac && ARGS_PPHRASE == lac) + m->flags |= MDOC_PPHRASE; + + if ( ! phrase(m, line, la, buf)) return(0); + m->flags &= ~MDOC_PPHRASE; - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) - return(0); continue; } @@ -1198,7 +1263,7 @@ blk_part_imp(MACRO_PROT_ARGS) if (body == n) break; - if (NULL == n && ! mdoc_nwarn(m, body, EIMPBRK)) + if (NULL == n && ! mdoc_nmsg(m, body, MANDOCERR_SCOPE)) return(0); if (n && ! rew_last(m, body)) @@ -1564,7 +1629,7 @@ static int obsolete(MACRO_PROT_ARGS) { - return(mdoc_pwarn(m, line, ppos, EOBS)); + return(mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS)); } @@ -1574,26 +1639,24 @@ obsolete(MACRO_PROT_ARGS) * macro is encountered. */ static int -phrase(struct mdoc *m, int line, int ppos, char *buf, enum margserr ac) +phrase(struct mdoc *m, int line, int ppos, char *buf) { int la, pos; - enum margserr aac; + enum margserr ac; enum mdoct ntok; char *p; - assert(ARGS_PHRASE == ac || ARGS_PPHRASE == ac); - for (pos = ppos; ; ) { la = pos; - aac = mdoc_zargs(m, line, &pos, buf, 0, &p); + ac = mdoc_zargs(m, line, &pos, buf, 0, &p); - if (ARGS_ERROR == aac) + if (ARGS_ERROR == ac) return(0); - if (ARGS_EOLN == aac) + if (ARGS_EOLN == ac) break; - ntok = ARGS_QWORD == aac ? MDOC_MAX : lookup_raw(p); + ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { if ( ! mdoc_word_alloc(m, line, la, p)) @@ -1610,3 +1673,67 @@ phrase(struct mdoc *m, int line, int ppos, char *buf, } +static int +phrase_ta(MACRO_PROT_ARGS) +{ + int la; + enum mdoct ntok; + enum margserr ac; + struct mdoc_node *n; + char *p; + + /* + * FIXME: this is overly restrictive: if the `Ta' is unexpected, + * it should simply error out with ARGSLOST. + */ + + n = m->last; + if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos)) + return(0); + + /* + * FIXME: this is necessary in bogus constructions like + * .Bl -column foo bar + * .Sy foo Ta bar + * It is, however, an ugly way to do it. + * + * XXX; remove this when the above construct builds an implied + * `It' marker. + */ + if (NULL == m->last || + MDOC_BODY != m->last->type || + MDOC_It != m->last->tok || + NULL == m->last->parent->parent || + MDOC_Bl != m->last->parent->parent->tok || + LIST_column != m->last->parent->parent->data.list) { + swarn(m, tok, line, ppos, n); + return(0); + } + + if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It)) + return(0); + + for (;;) { + la = *pos; + ac = mdoc_zargs(m, line, pos, buf, 0, &p); + + if (ARGS_ERROR == ac) + return(0); + if (ARGS_EOLN == ac) + break; + + ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); + + if (MDOC_MAX == ntok) { + if ( ! mdoc_word_alloc(m, line, la, p)) + return(0); + continue; + } + + if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + return(0); + return(append_delims(m, line, pos, buf)); + } + + return(1); +}