diff options
author | Kristaps Dzonsons <kristaps@bsd.lv> | 2009-03-23 14:22:11 +0000 |
---|---|---|
committer | Kristaps Dzonsons <kristaps@bsd.lv> | 2009-03-23 14:22:11 +0000 |
commit | dc4e5ca1c9fd9bd34e243dcdb884af02102c9389 (patch) | |
tree | 78f2d3ac00100e778e6832933da1ace2dab9e080 /macro.c | |
parent | d4dba4479e3ed55fdc52b75eab00afe7ad78d5f0 (diff) | |
download | mandoc-dc4e5ca1c9fd9bd34e243dcdb884af02102c9389.tar.gz |
First addition of -man macro support.
Abstraction of mdoc.
Diffstat (limited to 'macro.c')
-rw-r--r-- | macro.c | 1446 |
1 files changed, 0 insertions, 1446 deletions
diff --git a/macro.c b/macro.c deleted file mode 100644 index 830b5e87..00000000 --- a/macro.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* $Id$ */ -/* - * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org> - * - * 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. - * - * 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 <assert.h> -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "private.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 { - WIMPBRK, - WMACPARM, - WOBS -}; - -enum merr { - EOPEN, - EQUOT, - ENOCTX, - ENOPARMS -}; - -#define REWIND_REWIND (1 << 0) -#define REWIND_NOHALT (1 << 1) -#define REWIND_HALT (1 << 2) - -static int obsolete(MACRO_PROT_ARGS); -static int blk_part_exp(MACRO_PROT_ARGS); -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 blk_full(MACRO_PROT_ARGS); -static int blk_exp_close(MACRO_PROT_ARGS); -static int blk_part_imp(MACRO_PROT_ARGS); - -static int phrase(struct mdoc *, int, int, char *); -static int rew_dohalt(int, enum mdoc_type, - const struct mdoc_node *); -static int rew_alt(int); -static int rew_dobreak(int, const struct mdoc_node *); -static int rew_elem(struct mdoc *, int); -static int rew_impblock(struct mdoc *, int, int, int); -static int rew_expblock(struct mdoc *, int, int, int); -static int rew_subblock(enum mdoc_type, - struct mdoc *, int, int, int); -static int rew_last(struct mdoc *, struct mdoc_node *); -static int append_delims(struct mdoc *, int, int *, char *); -static int lookup(struct mdoc *, int, int, int, const char *); -static int pwarn(struct mdoc *, int, int, enum mwarn); -static int perr(struct mdoc *, int, int, enum merr); -static int swarn(struct mdoc *, enum mdoc_type, int, int, - const struct mdoc_node *); - -#define nerr(m, n, t) perr((m), (n)->line, (n)->pos, (t)) - -/* Central table of library: who gets parsed how. */ - -const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { - { NULL, 0 }, /* \" */ - { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ - { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ - { in_line_eoln, MDOC_PROLOGUE }, /* Os */ - { blk_full, 0 }, /* Sh */ - { blk_full, 0 }, /* Ss */ - { in_line, 0 }, /* Pp */ - { blk_part_imp, MDOC_PARSED }, /* D1 */ - { blk_part_imp, MDOC_PARSED }, /* Dl */ - { blk_full, MDOC_EXPLICIT }, /* Bd */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ed */ - { blk_full, MDOC_EXPLICIT }, /* Bl */ - { 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 }, /* Ar */ - { in_line_eoln, MDOC_CALLABLE }, /* Cd */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ - { in_line_eoln, 0 }, /* Ex */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ - { 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 }, /* Ic */ - { in_line_eoln, 0 }, /* In */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ - { in_line_eoln, 0 }, /* Nd */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ - { obsolete, 0 }, /* Ot */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ - { in_line_eoln, 0 }, /* Rv */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ - { in_line_eoln, 0 }, /* %A */ - { in_line_eoln, 0 }, /* %B */ - { in_line_eoln, 0 }, /* %D */ - { in_line_eoln, 0 }, /* %I */ - { in_line_eoln, 0 }, /* %J */ - { in_line_eoln, 0 }, /* %N */ - { in_line_eoln, 0 }, /* %O */ - { in_line_eoln, 0 }, /* %P */ - { in_line_eoln, 0 }, /* %R */ - { in_line_eoln, 0 }, /* %T */ - { in_line_eoln, 0 }, /* %V */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */ - { blk_full, MDOC_EXPLICIT }, /* Bf */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */ - { in_line_eoln, 0 }, /* Db */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ef */ - { 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_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */ - { in_line_argn, MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */ - { blk_exp_close, MDOC_EXPLICIT }, /* Re */ - { blk_full, MDOC_EXPLICIT }, /* Rs */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */ - { in_line_eoln, 0 }, /* Sm */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */ - { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */ - { blk_full, MDOC_EXPLICIT }, /* Bk */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ek */ - { in_line_eoln, 0 }, /* Bt */ - { in_line_eoln, 0 }, /* Hf */ - { 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 */ - { 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 */ - { in_line_eoln, 0 }, /* %C */ - { obsolete, 0 }, /* Es */ - { obsolete, 0 }, /* En */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ - { in_line_eoln, 0 }, /* %Q */ -}; - -const struct mdoc_macro * const mdoc_macros = __mdoc_macros; - - -static int -perr(struct mdoc *mdoc, int line, int pos, enum merr type) -{ - char *p; - - p = NULL; - switch (type) { - case (EOPEN): - p = "explicit scope still open on exit"; - break; - case (EQUOT): - p = "unterminated quotation"; - break; - case (ENOCTX): - p = "closure has no prior context"; - break; - case (ENOPARMS): - p = "unexpect line arguments"; - break; - } - assert(p); - return(mdoc_perr(mdoc, line, pos, p)); -} - - -static int -pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn type) -{ - char *p; - - p = NULL; - switch (type) { - case (WIMPBRK): - p = "crufty end-of-line scope violation"; - break; - case (WMACPARM): - p = "macro-like parameter"; - break; - case (WOBS): - p = "macro marked obsolete"; - break; - } - assert(p); - return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, p)); -} - - -static int -swarn(struct mdoc *mdoc, enum mdoc_type type, - int line, int pos, const struct mdoc_node *p) -{ - const char *n, *t, *tt; - - n = t = "<root>"; - tt = "block"; - - switch (type) { - case (MDOC_BODY): - tt = "multi-line"; - break; - case (MDOC_HEAD): - tt = "line"; - break; - default: - break; - } - - switch (p->type) { - case (MDOC_BLOCK): - n = mdoc_macronames[p->tok]; - t = "block"; - break; - case (MDOC_BODY): - n = mdoc_macronames[p->tok]; - t = "multi-line"; - break; - case (MDOC_HEAD): - n = mdoc_macronames[p->tok]; - t = "line"; - break; - default: - break; - } - - if ( ! (MDOC_IGN_SCOPE & mdoc->pflags)) - return(mdoc_perr(mdoc, line, pos, - "%s scope breaks %s scope of %s", - tt, t, n)); - return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, - "%s scope breaks %s scope of %s", - tt, t, n)); -} - - -/* - * This is called at the end of parsing. It must traverse up the tree, - * closing out open [implicit] scopes. Obviously, open explicit scopes - * are errors. - */ -int -macro_end(struct mdoc *mdoc) -{ - struct mdoc_node *n; - - assert(mdoc->first); - assert(mdoc->last); - - /* Scan for open explicit scopes. */ - - n = MDOC_VALID & mdoc->last->flags ? - mdoc->last->parent : mdoc->last; - - for ( ; n; n = n->parent) { - if (MDOC_BLOCK != n->type) - continue; - if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags)) - continue; - return(nerr(mdoc, n, EOPEN)); - } - - return(rew_last(mdoc, mdoc->first)); -} - -static int -lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p) -{ - int res; - - res = mdoc_tokhash_find(mdoc->htab, p); - if (MDOC_PARSED & mdoc_macros[from].flags) - return(res); - if (MDOC_MAX == res) - return(res); - if ( ! pwarn(mdoc, line, pos, WMACPARM)) - return(-1); - return(MDOC_MAX); -} - - -static int -rew_last(struct mdoc *mdoc, struct mdoc_node *to) -{ - - assert(to); - mdoc->next = MDOC_NEXT_SIBLING; - - /* LINTED */ - while (mdoc->last != to) { - if ( ! mdoc_valid_post(mdoc)) - return(0); - if ( ! mdoc_action_post(mdoc)) - return(0); - mdoc->last = mdoc->last->parent; - assert(mdoc->last); - } - - if ( ! mdoc_valid_post(mdoc)) - return(0); - return(mdoc_action_post(mdoc)); -} - - -static int -rew_alt(int tok) -{ - switch (tok) { - case (MDOC_Ac): - return(MDOC_Ao); - case (MDOC_Bc): - return(MDOC_Bo); - case (MDOC_Brc): - return(MDOC_Bro); - case (MDOC_Dc): - return(MDOC_Do); - case (MDOC_Ec): - return(MDOC_Eo); - case (MDOC_Ed): - return(MDOC_Bd); - case (MDOC_Ef): - return(MDOC_Bf); - case (MDOC_Ek): - return(MDOC_Bk); - case (MDOC_El): - return(MDOC_Bl); - case (MDOC_Fc): - return(MDOC_Fo); - case (MDOC_Oc): - return(MDOC_Oo); - case (MDOC_Pc): - return(MDOC_Po); - case (MDOC_Qc): - return(MDOC_Qo); - case (MDOC_Re): - return(MDOC_Rs); - case (MDOC_Sc): - return(MDOC_So); - case (MDOC_Xc): - return(MDOC_Xo); - default: - break; - } - abort(); - /* NOTREACHED */ -} - - -/* - * Rewind rules. This indicates whether to stop rewinding - * (REWIND_HALT) without touching our current scope, stop rewinding and - * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT). - * The scope-closing and so on occurs in the various rew_* routines. - */ -static int -rew_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p) -{ - - if (MDOC_ROOT == p->type) - return(REWIND_HALT); - if (MDOC_VALID & p->flags) - return(REWIND_NOHALT); - - switch (tok) { - case (MDOC_Aq): - /* FALLTHROUGH */ - case (MDOC_Bq): - /* FALLTHROUGH */ - case (MDOC_Brq): - /* FALLTHROUGH */ - case (MDOC_D1): - /* FALLTHROUGH */ - case (MDOC_Dl): - /* FALLTHROUGH */ - case (MDOC_Dq): - /* FALLTHROUGH */ - case (MDOC_Op): - /* FALLTHROUGH */ - case (MDOC_Pq): - /* FALLTHROUGH */ - case (MDOC_Ql): - /* FALLTHROUGH */ - case (MDOC_Qq): - /* FALLTHROUGH */ - case (MDOC_Sq): - assert(MDOC_HEAD != type); - assert(MDOC_TAIL != type); - if (type == p->type && tok == p->tok) - return(REWIND_REWIND); - break; - case (MDOC_It): - assert(MDOC_TAIL != type); - if (type == p->type && tok == p->tok) - return(REWIND_REWIND); - if (MDOC_BODY == p->type && MDOC_Bl == p->tok) - return(REWIND_HALT); - break; - case (MDOC_Sh): - if (type == p->type && tok == p->tok) - return(REWIND_REWIND); - break; - case (MDOC_Ss): - assert(MDOC_TAIL != type); - if (type == p->type && tok == p->tok) - return(REWIND_REWIND); - if (MDOC_BODY == p->type && MDOC_Sh == p->tok) - return(REWIND_HALT); - break; - case (MDOC_Ao): - /* FALLTHROUGH */ - case (MDOC_Bd): - /* FALLTHROUGH */ - case (MDOC_Bf): - /* FALLTHROUGH */ - case (MDOC_Bk): - /* FALLTHROUGH */ - case (MDOC_Bl): - /* FALLTHROUGH */ - case (MDOC_Bo): - /* FALLTHROUGH */ - case (MDOC_Bro): - /* FALLTHROUGH */ - case (MDOC_Do): - /* FALLTHROUGH */ - case (MDOC_Eo): - /* FALLTHROUGH */ - case (MDOC_Fo): - /* FALLTHROUGH */ - case (MDOC_Oo): - /* FALLTHROUGH */ - case (MDOC_Po): - /* FALLTHROUGH */ - case (MDOC_Qo): - /* FALLTHROUGH */ - case (MDOC_Rs): - /* FALLTHROUGH */ - case (MDOC_So): - /* FALLTHROUGH */ - case (MDOC_Xo): - if (type == p->type && tok == p->tok) - return(REWIND_REWIND); - break; - - /* Multi-line explicit scope close. */ - case (MDOC_Ac): - /* FALLTHROUGH */ - case (MDOC_Bc): - /* FALLTHROUGH */ - case (MDOC_Brc): - /* FALLTHROUGH */ - case (MDOC_Dc): - /* FALLTHROUGH */ - case (MDOC_Ec): - /* FALLTHROUGH */ - case (MDOC_Ed): - /* FALLTHROUGH */ - case (MDOC_Ek): - /* FALLTHROUGH */ - case (MDOC_El): - /* FALLTHROUGH */ - case (MDOC_Fc): - /* FALLTHROUGH */ - case (MDOC_Ef): - /* FALLTHROUGH */ - case (MDOC_Oc): - /* FALLTHROUGH */ - case (MDOC_Pc): - /* FALLTHROUGH */ - case (MDOC_Qc): - /* FALLTHROUGH */ - case (MDOC_Re): - /* FALLTHROUGH */ - case (MDOC_Sc): - /* FALLTHROUGH */ - case (MDOC_Xc): - if (type == p->type && rew_alt(tok) == p->tok) - return(REWIND_REWIND); - break; - default: - abort(); - /* NOTREACHED */ - } - - return(REWIND_NOHALT); -} - - -/* - * See if we can break an encountered scope (the rew_dohalt has returned - * REWIND_NOHALT). - */ -static int -rew_dobreak(int tok, const struct mdoc_node *p) -{ - - assert(MDOC_ROOT != p->type); - if (MDOC_ELEM == p->type) - return(1); - if (MDOC_TEXT == p->type) - return(1); - if (MDOC_VALID & p->flags) - return(1); - - switch (tok) { - case (MDOC_It): - return(MDOC_It == p->tok); - case (MDOC_Ss): - return(MDOC_Ss == p->tok); - case (MDOC_Sh): - if (MDOC_Ss == p->tok) - return(1); - return(MDOC_Sh == p->tok); - case (MDOC_El): - if (MDOC_It == p->tok) - return(1); - break; - case (MDOC_Oc): - /* XXX - experimental! */ - if (MDOC_Op == p->tok) - return(1); - break; - default: - break; - } - - if (MDOC_EXPLICIT & mdoc_macros[tok].flags) - return(p->tok == rew_alt(tok)); - else if (MDOC_BLOCK == p->type) - return(1); - - return(tok == p->tok); -} - - -static int -rew_elem(struct mdoc *mdoc, int tok) -{ - struct mdoc_node *n; - - n = mdoc->last; - if (MDOC_ELEM != n->type) - n = n->parent; - assert(MDOC_ELEM == n->type); - assert(tok == n->tok); - - return(rew_last(mdoc, n)); -} - - -static int -rew_subblock(enum mdoc_type type, struct mdoc *mdoc, - int tok, int line, int ppos) -{ - struct mdoc_node *n; - int c; - - /* LINTED */ - for (n = mdoc->last; n; n = n->parent) { - c = rew_dohalt(tok, type, n); - if (REWIND_HALT == c) - return(1); - if (REWIND_REWIND == c) - break; - else if (rew_dobreak(tok, n)) - continue; - if ( ! swarn(mdoc, type, line, ppos, n)) - return(0); - } - - assert(n); - return(rew_last(mdoc, n)); -} - - -static int -rew_expblock(struct mdoc *mdoc, int tok, int line, int ppos) -{ - struct mdoc_node *n; - int c; - - /* LINTED */ - for (n = mdoc->last; n; n = n->parent) { - c = rew_dohalt(tok, MDOC_BLOCK, n); - if (REWIND_HALT == c) - return(perr(mdoc, line, ppos, ENOCTX)); - if (REWIND_REWIND == c) - break; - else if (rew_dobreak(tok, n)) - continue; - if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n)) - return(0); - } - - assert(n); - return(rew_last(mdoc, n)); -} - - -static int -rew_impblock(struct mdoc *mdoc, int tok, int line, int ppos) -{ - struct mdoc_node *n; - int c; - - /* LINTED */ - for (n = mdoc->last; n; n = n->parent) { - c = rew_dohalt(tok, MDOC_BLOCK, n); - if (REWIND_HALT == c) - return(1); - else if (REWIND_REWIND == c) - break; - else if (rew_dobreak(tok, n)) - continue; - if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n)) - return(0); - } - - assert(n); - return(rew_last(mdoc, n)); -} - - -static int -append_delims(struct mdoc *mdoc, int line, int *pos, char *buf) -{ - int c, lastarg; - char *p; - - if (0 == buf[*pos]) - return(1); - - for (;;) { - lastarg = *pos; - c = mdoc_args(mdoc, line, pos, buf, 0, &p); - assert(ARGS_PHRASE != c); - - if (ARGS_ERROR == c) - return(0); - else if (ARGS_EOLN == c) - break; - assert(mdoc_isdelim(p)); - if ( ! mdoc_word_alloc(mdoc, line, lastarg, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - return(1); -} - - -/* - * Close out block partial/full explicit. - */ -static int -blk_exp_close(MACRO_PROT_ARGS) -{ - int j, c, lastarg, maxargs, flushed; - char *p; - - switch (tok) { - case (MDOC_Ec): - maxargs = 1; - break; - default: - maxargs = 0; - break; - } - - if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { - if (0 == buf[*pos]) { - if ( ! rew_subblock(MDOC_BODY, mdoc, - tok, line, ppos)) - return(0); - return(rew_expblock(mdoc, tok, line, ppos)); - } - return(perr(mdoc, line, ppos, ENOPARMS)); - } - - if ( ! rew_subblock(MDOC_BODY, mdoc, tok, line, ppos)) - return(0); - - if (maxargs > 0) { - if ( ! mdoc_tail_alloc(mdoc, line, - ppos, rew_alt(tok))) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - } - - for (lastarg = ppos, flushed = j = 0; ; j++) { - lastarg = *pos; - - if (j == maxargs && ! flushed) { - if ( ! rew_expblock(mdoc, tok, line, ppos)) - return(0); - flushed = 1; - } - - c = mdoc_args(mdoc, line, pos, buf, tok, &p); - - if (ARGS_ERROR == c) - return(0); - if (ARGS_PUNCT == c) - break; - if (ARGS_EOLN == c) - break; - - if (-1 == (c = lookup(mdoc, line, lastarg, tok, p))) - return(0); - else if (MDOC_MAX != c) { - if ( ! flushed) { - if ( ! rew_expblock(mdoc, tok, - line, ppos)) - return(0); - flushed = 1; - } - if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf)) - return(0); - break; - } - - if ( ! mdoc_word_alloc(mdoc, line, lastarg, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - if ( ! flushed && ! rew_expblock(mdoc, tok, line, ppos)) - return(0); - - if (ppos > 1) - return(1); - return(append_delims(mdoc, line, pos, buf)); -} - - -/* - * In-line macros where reserved words cause scope close-reopen. - */ -static int -in_line(MACRO_PROT_ARGS) -{ - int la, lastpunct, c, w; - struct mdoc_arg *arg; - char *p; - - for (la = ppos, arg = NULL;; ) { - la = *pos; - c = mdoc_argv(mdoc, line, tok, &arg, pos, buf); - - if (ARGV_WORD == c) { - *pos = la; - break; - } - - if (ARGV_EOLN == c) - break; - if (ARGV_ARG == c) - continue; - - mdoc_argv_free(arg); - return(0); - } - - if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - - for (lastpunct = 0;; ) { - la = *pos; - w = mdoc_args(mdoc, line, pos, buf, tok, &p); - - if (ARGS_ERROR == w) - return(0); - if (ARGS_EOLN == w) - break; - if (ARGS_PUNCT == w) - break; - - /* Quoted words shouldn't be looked-up. */ - - c = ARGS_QWORD == w ? MDOC_MAX : - lookup(mdoc, line, la, tok, p); - - /* MDOC_MAX (not a macro) or -1 (error). */ - - if (MDOC_MAX != c && -1 != c) { - if (0 == lastpunct && ! rew_elem(mdoc, tok)) - return(0); - c = mdoc_macro(mdoc, c, line, la, pos, buf); - if (0 == c) - return(0); - if (ppos > 1) - return(1); - return(append_delims(mdoc, line, pos, buf)); - } else if (-1 == c) - return(0); - - /* Non-quote-enclosed punctuation. */ - - if (ARGS_QWORD != w && mdoc_isdelim(p)) { - if (0 == lastpunct && ! rew_elem(mdoc, tok)) - return(0); - lastpunct = 1; - } else if (lastpunct) { - c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg); - - if (0 == c) - return(0); - - mdoc->next = MDOC_NEXT_CHILD; - lastpunct = 0; - } - - if ( ! mdoc_word_alloc(mdoc, line, la, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - if (0 == lastpunct && ! rew_elem(mdoc, tok)) - return(0); - if (ppos > 1) - return(1); - return(append_delims(mdoc, line, pos, buf)); -} - - -/* - * Block full-explicit and full-implicit. - */ -static int -blk_full(MACRO_PROT_ARGS) -{ - int c, lastarg, reopen; - struct mdoc_arg *arg; - char *p; - - if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { - if ( ! rew_subblock(MDOC_BODY, mdoc, - tok, line, ppos)) - return(0); - if ( ! rew_impblock(mdoc, tok, line, ppos)) - return(0); - } - - for (arg = NULL;; ) { - lastarg = *pos; - c = mdoc_argv(mdoc, line, tok, &arg, pos, buf); - - if (ARGV_WORD == c) { - *pos = lastarg; - break; - } - - if (ARGV_EOLN == c) - break; - if (ARGV_ARG == c) - continue; - - mdoc_argv_free(arg); - return(0); - } - - if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - - if (0 == buf[*pos]) { - if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) - return(0); - if ( ! rew_subblock(MDOC_HEAD, mdoc, - tok, line, ppos)) - return(0); - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - return(1); - } - - if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - - for (reopen = 0;; ) { - lastarg = *pos; - c = mdoc_args(mdoc, line, pos, buf, tok, &p); - - if (ARGS_ERROR == c) - return(0); - if (ARGS_EOLN == c) - break; - if (ARGS_PHRASE == c) { - if (reopen && ! mdoc_head_alloc - (mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - /* - * Phrases are self-contained macro phrases used - * in the columnar output of a macro. They need - * special handling. - */ - if ( ! phrase(mdoc, line, lastarg, buf)) - return(0); - if ( ! rew_subblock(MDOC_HEAD, mdoc, - tok, line, ppos)) - return(0); - - reopen = 1; - continue; - } - - if (-1 == (c = lookup(mdoc, line, lastarg, tok, p))) - return(0); - - if (MDOC_MAX == c) { - if ( ! mdoc_word_alloc(mdoc, line, lastarg, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - continue; - } - - if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf)) - return(0); - break; - } - - if (1 == ppos && ! append_delims(mdoc, line, pos, buf)) - return(0); - if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos)) - return(0); - - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - - return(1); -} - - -/* - * Block partial-imnplicit scope. - */ -static int -blk_part_imp(MACRO_PROT_ARGS) -{ - int lastarg, c; - char *p; - struct mdoc_node *blk, *body, *n; - - if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - blk = mdoc->last; - - if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - body = mdoc->last; - - /* XXX - no known argument macros. */ - - for (lastarg = ppos;; ) { - lastarg = *pos; - c = mdoc_args(mdoc, line, pos, buf, tok, &p); - assert(ARGS_PHRASE != c); - - if (ARGS_ERROR == c) - return(0); - if (ARGS_PUNCT == c) - break; - if (ARGS_EOLN == c) - break; - - if (-1 == (c = lookup(mdoc, line, lastarg, tok, p))) - return(0); - else if (MDOC_MAX == c) { - if ( ! mdoc_word_alloc(mdoc, line, lastarg, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - continue; - } - - if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf)) - return(0); - break; - } - - /* - * Since we know what our context is, we can rewind directly to - * it. This allows us to accomodate for our scope being - * violated by another token. - */ - - for (n = mdoc->last; n; n = n->parent) - if (body == n) - break; - - if (NULL == n && ! pwarn(mdoc, body->line, body->pos, WIMPBRK)) - return(0); - - if (n && ! rew_last(mdoc, body)) - return(0); - - if (1 == ppos && ! append_delims(mdoc, line, pos, buf)) - return(0); - - if (n && ! rew_last(mdoc, blk)) - return(0); - - return(1); -} - - -/* - * Block partial-explicit macros. - */ -static int -blk_part_exp(MACRO_PROT_ARGS) -{ - int lastarg, flushed, j, c, maxargs; - char *p; - - lastarg = ppos; - flushed = 0; - - /* - * Number of arguments (head arguments). Only `Eo' has these, - */ - - switch (tok) { - case (MDOC_Eo): - maxargs = 1; - break; - default: - maxargs = 0; - break; - } - - if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - - if (0 == maxargs) { - if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) - return(0); - if ( ! rew_subblock(MDOC_HEAD, mdoc, - tok, line, ppos)) - return(0); - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - flushed = 1; - } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) - return(0); - - mdoc->next = MDOC_NEXT_CHILD; - - for (j = 0; ; j++) { - lastarg = *pos; - if (j == maxargs && ! flushed) { - if ( ! rew_subblock(MDOC_HEAD, mdoc, - tok, line, ppos)) - return(0); - flushed = 1; - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - } - - c = mdoc_args(mdoc, line, pos, buf, tok, &p); - assert(ARGS_PHRASE != c); - - if (ARGS_ERROR == c) - return(0); - if (ARGS_PUNCT == c) - break; - if (ARGS_EOLN == c) - break; - - if (-1 == (c = lookup(mdoc, line, lastarg, tok, p))) - return(0); - else if (MDOC_MAX != c) { - if ( ! flushed) { - if ( ! rew_subblock(MDOC_HEAD, mdoc, - tok, line, ppos)) - return(0); - flushed = 1; - if ( ! mdoc_body_alloc(mdoc, line, - ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - } - if ( ! mdoc_macro(mdoc, c, line, lastarg, - pos, buf)) - return(0); - break; - } - - if ( ! flushed && mdoc_isdelim(p)) { - if ( ! rew_subblock(MDOC_HEAD, mdoc, - tok, line, ppos)) - return(0); - flushed = 1; - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - } - - if ( ! mdoc_word_alloc(mdoc, line, lastarg, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - if ( ! flushed) { - if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos)) - return(0); - if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - } - - if (ppos > 1) - return(1); - return(append_delims(mdoc, line, pos, buf)); -} - - -/* - * In-line macros where reserved words signal closure of the macro. - * Macros also have a fixed number of arguments. - */ -static int -in_line_argn(MACRO_PROT_ARGS) -{ - int lastarg, flushed, j, c, maxargs; - struct mdoc_arg *arg; - char *p; - - - /* - * Fixed maximum arguments per macro. Some of these have none - * and close as soon as the invocation is parsed. - */ - - switch (tok) { - case (MDOC_Ap): - /* FALLTHROUGH */ - case (MDOC_No): - /* FALLTHROUGH */ - case (MDOC_Ns): - /* FALLTHROUGH */ - case (MDOC_Ux): - maxargs = 0; - break; - default: - maxargs = 1; - break; - } - - for (lastarg = ppos, arg = NULL;; ) { - lastarg = *pos; - c = mdoc_argv(mdoc, line, tok, &arg, pos, buf); - - if (ARGV_WORD == c) { - *pos = lastarg; - break; - } - - if (ARGV_EOLN == c) - break; - if (ARGV_ARG == c) - continue; - - mdoc_argv_free(arg); - return(0); - } - - if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) - return(0); - mdoc->next = MDOC_NEXT_CHILD; - - for (flushed = j = 0; ; j++) { - lastarg = *pos; - - if (j == maxargs && ! flushed) { - if ( ! rew_elem(mdoc, tok)) - return(0); - flushed = 1; - } - - c = mdoc_args(mdoc, line, pos, buf, tok, &p); - - if (ARGS_ERROR == c) - return(0); - if (ARGS_PUNCT == c) - break; - if (ARGS_EOLN == c) - break; - - if (-1 == (c = lookup(mdoc, line, lastarg, tok, p))) - return(0); - else if (MDOC_MAX != c) { - if ( ! flushed && ! rew_elem(mdoc, tok)) - return(0); - flushed = 1; - if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf)) - return(0); - break; - } - - if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && - ! flushed && mdoc_isdelim(p)) { - if ( ! rew_elem(mdoc, tok)) - return(0); - flushed = 1; - } - - if ( ! mdoc_word_alloc(mdoc, line, lastarg, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - if ( ! flushed && ! rew_elem(mdoc, tok)) - return(0); - - if (ppos > 1) - return(1); - return(append_delims(mdoc, line, pos, buf)); -} - - -/* - * In-line macro that spans an entire line. May be callable, but has no - * subsequent parsed arguments. - */ -static int -in_line_eoln(MACRO_PROT_ARGS) -{ - int c, w, la; - struct mdoc_arg *arg; - char *p; - - assert( ! (MDOC_PARSED & mdoc_macros[tok].flags)); - - arg = NULL; - - for (;;) { - la = *pos; - c = mdoc_argv(mdoc, line, tok, &arg, pos, buf); - - if (ARGV_WORD == c) { - *pos = la; - break; - } - if (ARGV_EOLN == c) - break; - if (ARGV_ARG == c) - continue; - - mdoc_argv_free(arg); - return(0); - } - - if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) - return(0); - - mdoc->next = MDOC_NEXT_CHILD; - - for (;;) { - la = *pos; - w = mdoc_args(mdoc, line, pos, buf, tok, &p); - - if (ARGS_ERROR == w) - return(0); - if (ARGS_EOLN == w) - break; - - c = ARGS_QWORD == w ? MDOC_MAX : - lookup(mdoc, line, la, tok, p); - - if (MDOC_MAX != c && -1 != c) { - if ( ! rew_elem(mdoc, tok)) - return(0); - return(mdoc_macro(mdoc, c, line, la, pos, buf)); - } else if (-1 == c) - return(0); - - if ( ! mdoc_word_alloc(mdoc, line, la, p)) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - return(rew_elem(mdoc, tok)); -} - - -/* ARGSUSED */ -static int -obsolete(MACRO_PROT_ARGS) -{ - - return(pwarn(mdoc, line, ppos, WOBS)); -} - - -static int -phrase(struct mdoc *mdoc, int line, int ppos, char *buf) -{ - int i, la, c, quoted; - - /* - * Parse over words in a phrase. We have to handle this - * specially because we assume no calling context -- in normal - * circumstances, we switch argument parsing based on whether - * the parent macro accepts quotes, tabs, etc. Here, anything - * goes. - */ - - for (i = ppos; buf[i]; ) { - assert(' ' != buf[i]); - la = i; - quoted = 0; - - /* - * Read to next token. If quoted (check not escaped), - * scan ahead to next unescaped quote. If not quoted or - * escape-quoted, then scan ahead to next space. - */ - - if ((i && '\"' == buf[i] && '\\' != buf[i - 1]) || - (0 == i && '\"' == buf[i])) { - for (la = ++i; buf[i]; i++) - if ('\"' != buf[i]) - continue; - else if ('\\' != buf[i - 1]) - break; - if (0 == buf[i]) - return(perr(mdoc, line, la, EQUOT)); - quoted = 1; - } else - for ( ; buf[i]; i++) - if (i && ' ' == buf[i]) { - if ('\\' != buf[i - 1]) - break; - } else if (' ' == buf[i]) - break; - - /* If not end-of-line, terminate argument. */ - - if (buf[i]) - buf[i++] = 0; - - /* Read to next argument. */ - - for ( ; buf[i] && ' ' == buf[i]; i++) - /* Spin. */ ; - - /* - * If we're a non-quoted string, try to look up the - * value as a macro and execute it, if found. - */ - - c = quoted ? MDOC_MAX : - mdoc_tokhash_find(mdoc->htab, &buf[la]); - - if (MDOC_MAX != c) { - if ( ! mdoc_macro(mdoc, c, line, la, &i, buf)) - return(0); - return(append_delims(mdoc, line, &i, buf)); - } - - /* A regular word or quoted string. */ - - if ( ! mdoc_word_alloc(mdoc, line, la, &buf[la])) - return(0); - mdoc->next = MDOC_NEXT_SIBLING; - } - - return(1); -} |