=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.3 retrieving revision 1.15 diff -u -p -r1.3 -r1.15 --- mandoc/mdoc_macro.c 2009/03/27 13:44:24 1.3 +++ mandoc/mdoc_macro.c 2009/07/06 09:21:24 1.15 @@ -1,20 +1,18 @@ -/* $Id: mdoc_macro.c,v 1.3 2009/03/27 13:44:24 kristaps Exp $ */ +/* $Id: mdoc_macro.c,v 1.15 2009/07/06 09:21:24 kristaps Exp $ */ /* - * Copyright (c) 2008, 2009 Kristaps Dzonsons + * Copyright (c) 2008, 2009 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the - * above copyright notice and this permission notice appear in all - * copies. + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include @@ -24,15 +22,8 @@ #include "libmdoc.h" -/* - * This has scanning/parsing routines, each of which extract a macro and - * its arguments and parameters, then know how to progress to the next - * macro. - */ - -/* FIXME: .Fl, .Ar, .Cd handling of `|'. */ - enum mwarn { + WIGNE, WIMPBRK, WMACPARM, WOBS @@ -81,7 +72,7 @@ static int swarn(struct mdoc *, enum mdoc_type, int, /* Central table of library: who gets parsed how. */ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { - { NULL, 0 }, /* \" */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */ { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */ @@ -96,7 +87,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { blk_exp_close, MDOC_EXPLICIT }, /* El */ { blk_full, MDOC_PARSED }, /* It */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ - { in_line, MDOC_PARSED }, /* An */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ { in_line_eoln, MDOC_CALLABLE }, /* Cd */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ @@ -108,9 +99,9 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, 0 }, /* Fd */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ - { in_line, MDOC_PARSED }, /* Ft */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ - { in_line_eoln, 0 }, /* In */ + { in_line_eoln, 0 }, /* In */ /* FIXME: historic usage! */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ { in_line_eoln, 0 }, /* Nd */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ @@ -152,7 +143,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */ { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ - { in_line, MDOC_PARSED }, /* Ms */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ @@ -188,10 +179,9 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { obsolete, 0 }, /* Fr */ { in_line_eoln, 0 }, /* Ud */ { in_line_eoln, 0 }, /* Lb */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */ { in_line, 0 }, /* Lp */ - { in_line, MDOC_PARSED }, /* Lk */ - { in_line, MDOC_PARSED }, /* Mt */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */ { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */ { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */ @@ -237,6 +227,9 @@ pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn p = NULL; switch (type) { + case (WIGNE): + p = "ignoring empty element"; + break; case (WIMPBRK): p = "crufty end-of-line scope violation"; break; @@ -248,7 +241,7 @@ pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn break; } assert(p); - return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, p)); + return(mdoc_pwarn(mdoc, line, pos, p)); } @@ -293,7 +286,7 @@ swarn(struct mdoc *mdoc, enum mdoc_type type, return(mdoc_perr(mdoc, line, pos, "%s scope breaks %s scope of %s", tt, t, n)); - return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, + return(mdoc_pwarn(mdoc, line, pos, "%s scope breaks %s scope of %s", tt, t, n)); } @@ -330,7 +323,7 @@ lookup(struct mdoc *mdoc, int line, int pos, int from, { int res; - res = mdoc_tokhash_find(mdoc->htab, p); + res = mdoc_hash_find(mdoc->htab, p); if (MDOC_PARSED & mdoc_macros[from].flags) return(res); if (MDOC_MAX == res) @@ -800,10 +793,33 @@ blk_exp_close(MACRO_PROT_ARGS) static int in_line(MACRO_PROT_ARGS) { - int la, lastpunct, c, w, cnt, d, call; + int la, lastpunct, c, w, cnt, d, nc; struct mdoc_arg *arg; char *p; + /* + * Whether we allow ignored elements (those without content, + * usually because of reserved words) to squeak by. + */ + switch (tok) { + case (MDOC_Lp): + /* FALLTHROUGH */ + case (MDOC_Pp): + /* FALLTHROUGH */ + case (MDOC_Nm): + /* FALLTHROUGH */ + case (MDOC_Fl): + /* FALLTHROUGH */ + case (MDOC_Lk): + /* FALLTHROUGH */ + case (MDOC_Ar): + nc = 1; + break; + default: + nc = 0; + break; + } + for (la = ppos, arg = NULL;; ) { la = *pos; c = mdoc_argv(mdoc, line, tok, &arg, pos, buf); @@ -821,7 +837,7 @@ in_line(MACRO_PROT_ARGS) return(0); } - for (call = cnt = 0, lastpunct = 1;; ) { + for (cnt = 0, lastpunct = 1;; ) { la = *pos; w = mdoc_args(mdoc, line, pos, buf, tok, &p); @@ -837,18 +853,26 @@ in_line(MACRO_PROT_ARGS) c = ARGS_QWORD == w ? MDOC_MAX : lookup(mdoc, line, la, tok, p); - /* MDOC_MAX (not a macro) or -1 (error). */ + /* + * In this case, we've located a submacro and must + * execute it. Close out scope, if open. If no + * elements have been generated, either create one (nc) + * or raise a warning. + */ if (MDOC_MAX != c && -1 != c) { if (0 == lastpunct && ! rew_elem(mdoc, tok)) return(0); - if (0 == cnt) { + if (nc && 0 == cnt) { if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); - if ( ! rew_elem(mdoc, tok)) + if ( ! rew_last(mdoc, mdoc->last)) return(0); - mdoc->next = MDOC_NEXT_SIBLING; + } else if ( ! nc && 0 == cnt) { + mdoc_argv_free(arg); + if ( ! pwarn(mdoc, line, ppos, WIGNE)) + return(0); } c = mdoc_macro(mdoc, c, line, la, pos, buf); if (0 == c) @@ -859,7 +883,11 @@ in_line(MACRO_PROT_ARGS) } else if (-1 == c) return(0); - /* Non-quote-enclosed punctuation. */ + /* + * Non-quote-enclosed punctuation. Set up our scope, if + * a word; rewind the scope, if a delimiter; then append + * the word. + */ d = mdoc_isdelim(p); @@ -884,13 +912,25 @@ in_line(MACRO_PROT_ARGS) if (0 == lastpunct && ! rew_elem(mdoc, tok)) return(0); - if (0 == cnt) { + + /* + * If no elements have been collected and we're allowed to have + * empties (nc), open a scope and close it out. Otherwise, + * raise a warning. + * + */ + if (nc && 0 == cnt) { c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg); if (0 == c) return(0); - if ( ! rew_elem(mdoc, tok)) + if ( ! rew_last(mdoc, mdoc->last)) return(0); + } else if ( ! nc && 0 == cnt) { + mdoc_argv_free(arg); + if ( ! pwarn(mdoc, line, ppos, WIGNE)) + return(0); } + if (ppos > 1) return(1); return(append_delims(mdoc, line, pos, buf)); @@ -1436,7 +1476,7 @@ phrase(struct mdoc *mdoc, int line, int ppos, char *bu */ c = quoted ? MDOC_MAX : - mdoc_tokhash_find(mdoc->htab, &buf[la]); + mdoc_hash_find(mdoc->htab, &buf[la]); if (MDOC_MAX != c) { if ( ! mdoc_macro(mdoc, c, line, la, &i, buf))