summaryrefslogtreecommitdiffstats
path: root/macro.c
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2009-03-23 14:22:11 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2009-03-23 14:22:11 +0000
commitdc4e5ca1c9fd9bd34e243dcdb884af02102c9389 (patch)
tree78f2d3ac00100e778e6832933da1ace2dab9e080 /macro.c
parentd4dba4479e3ed55fdc52b75eab00afe7ad78d5f0 (diff)
downloadmandoc-dc4e5ca1c9fd9bd34e243dcdb884af02102c9389.tar.gz
First addition of -man macro support.
Abstraction of mdoc.
Diffstat (limited to 'macro.c')
-rw-r--r--macro.c1446
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);
-}