Return to validate.c CVS log | Up to [cvsweb.bsd.lv] / mandoc |
version 1.22, 2009/01/09 15:07:04 | version 1.29, 2009/01/15 15:46:45 | ||
---|---|---|---|
|
|
||
struct valids { | struct valids { | ||
v_pre pre; | v_pre *pre; | ||
v_post *post; | v_post *post; | ||
}; | }; | ||
static int pre_display(struct mdoc *, struct mdoc_node *); | |||
static int pre_bd(struct mdoc *, struct mdoc_node *); | |||
static int pre_bl(struct mdoc *, struct mdoc_node *); | |||
static int pre_it(struct mdoc *, struct mdoc_node *); | |||
static int pre_prologue(struct mdoc *, struct mdoc_node *); | static int pre_prologue(struct mdoc *, struct mdoc_node *); | ||
static int pre_prologue(struct mdoc *, struct mdoc_node *); | static int pre_prologue(struct mdoc *, struct mdoc_node *); | ||
static int pre_prologue(struct mdoc *, struct mdoc_node *); | static int pre_prologue(struct mdoc *, struct mdoc_node *); | ||
static int post_headchild_err_ge1(struct mdoc *); | |||
static int post_elemchild_err_ge1(struct mdoc *); | static int headchild_err_ge1(struct mdoc *); | ||
static int post_elemchild_warn_eq0(struct mdoc *); | static int headchild_warn_ge1(struct mdoc *); | ||
static int post_bodychild_warn_ge1(struct mdoc *); | static int headchild_err_eq0(struct mdoc *); | ||
static int elemchild_err_eq0(struct mdoc *); | |||
static int elemchild_err_ge1(struct mdoc *); | |||
static int elemchild_warn_eq0(struct mdoc *); | |||
static int bodychild_warn_ge1(struct mdoc *); | |||
static int bodychild_err_eq0(struct mdoc *); | |||
static int elemchild_warn_ge1(struct mdoc *); | |||
static int post_sh(struct mdoc *); | static int post_sh(struct mdoc *); | ||
static int post_bl(struct mdoc *); | |||
static int post_it(struct mdoc *); | |||
static v_post posts_sh[] = { post_headchild_err_ge1, | static v_pre pres_prologue[] = { pre_prologue, NULL }; | ||
post_bodychild_warn_ge1, post_sh, NULL }; | static v_pre pres_d1[] = { pre_display, NULL }; | ||
static v_post posts_ss[] = { post_headchild_err_ge1, NULL }; | static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; | ||
static v_post posts_pp[] = { post_elemchild_warn_eq0, NULL }; | static v_pre pres_bl[] = { pre_bl, NULL }; | ||
static v_post posts_dd[] = { post_elemchild_err_ge1, NULL }; | static v_pre pres_it[] = { pre_it, NULL }; | ||
static v_post posts_bd[] = { headchild_err_eq0, bodychild_warn_ge1, NULL }; | |||
static v_post posts_text[] = { elemchild_err_ge1, NULL }; | |||
static v_post posts_wtext[] = { elemchild_warn_ge1, NULL }; | |||
static v_post posts_notext[] = { elemchild_err_eq0, NULL }; | |||
static v_post posts_wline[] = { headchild_warn_ge1, bodychild_err_eq0, NULL }; | |||
static v_post posts_sh[] = { headchild_err_ge1, bodychild_warn_ge1, post_sh, NULL }; | |||
static v_post posts_bl[] = { headchild_err_eq0, bodychild_warn_ge1, post_bl, NULL }; | |||
static v_post posts_it[] = { post_it, NULL }; | |||
static v_post posts_ss[] = { headchild_err_ge1, NULL }; | |||
static v_post posts_pp[] = { elemchild_warn_eq0, NULL }; | |||
static v_post posts_d1[] = { headchild_err_ge1, NULL }; | |||
const struct valids mdoc_valids[MDOC_MAX] = { | const struct valids mdoc_valids[MDOC_MAX] = { | ||
{ NULL, NULL }, /* \" */ | { NULL, NULL }, /* \" */ | ||
{ pre_prologue, posts_dd }, /* Dd */ | { pres_prologue, posts_text }, /* Dd */ | ||
{ pre_prologue, NULL }, /* Dt */ | { pres_prologue, NULL }, /* Dt */ | ||
{ pre_prologue, NULL }, /* Os */ | { pres_prologue, NULL }, /* Os */ | ||
{ NULL, posts_sh }, /* Sh */ /* FIXME: preceding Pp. */ | /* FIXME: preceding Pp. */ | ||
{ NULL, posts_ss }, /* Ss */ /* FIXME: preceding Pp. */ | /* FIXME: NAME section internal ordering. */ | ||
{ NULL, posts_pp }, /* Pp */ /* FIXME: proceeding... */ | /* FIXME: can only be a child of root. */ | ||
{ NULL, NULL }, /* D1 */ | { NULL, posts_sh }, /* Sh */ | ||
{ NULL, NULL }, /* Dl */ | /* FIXME: preceding Pp. */ | ||
{ NULL, NULL }, /* Bd */ /* FIXME: preceding Pp. */ | /* FIXME: can only be a child of Sh. */ | ||
{ NULL, posts_ss }, /* Ss */ | |||
/* FIXME: proceeding... */ | |||
{ NULL, posts_pp }, /* Pp */ | |||
{ pres_d1, posts_d1 }, /* D1 */ | |||
{ pres_d1, posts_d1 }, /* Dl */ | |||
/* FIXME: preceding Pp. */ | |||
{ pres_bd, posts_bd }, /* Bd */ | |||
{ NULL, NULL }, /* Ed */ | { NULL, NULL }, /* Ed */ | ||
{ NULL, NULL }, /* Bl */ /* FIXME: preceding Pp. */ | /* FIXME: preceding Pp. */ | ||
{ pres_bl, posts_bl }, /* Bl */ | |||
{ NULL, NULL }, /* El */ | { NULL, NULL }, /* El */ | ||
{ NULL, NULL }, /* It */ | { pres_it, posts_it }, /* It */ | ||
{ NULL, NULL }, /* Ad */ | { NULL, posts_text }, /* Ad */ | ||
{ NULL, NULL }, /* An */ | /* FIXME */ | ||
{ NULL, NULL }, /* An */ | |||
{ NULL, NULL }, /* Ar */ | { NULL, NULL }, /* Ar */ | ||
{ NULL, NULL }, /* Cd */ | |||
{ NULL, posts_text }, /* Cd */ /* FIXME: section 4 only. */ | |||
{ NULL, NULL }, /* Cm */ | { NULL, NULL }, /* Cm */ | ||
{ NULL, NULL }, /* Dv */ | { NULL, posts_text }, /* Dv */ | ||
{ NULL, NULL }, /* Er */ | { NULL, posts_text }, /* Er */ /* FIXME: section 2 only. */ | ||
{ NULL, NULL }, /* Ev */ | { NULL, posts_text }, /* Ev */ | ||
{ NULL, NULL }, /* Ex */ | { NULL, posts_notext }, /* Ex */ /* FIXME: sections 1,6,8 only. */ /* -std required */ | ||
{ NULL, NULL }, /* Fa */ | { NULL, posts_text }, /* Fa */ | ||
{ NULL, NULL }, /* Fd */ | { NULL, NULL }, /* Fd */ /* FIXME: SYNOPSIS section. */ | ||
{ NULL, NULL }, /* Fl */ | { NULL, NULL }, /* Fl */ | ||
{ NULL, NULL }, /* Fn */ | { NULL, posts_text }, /* Fn */ | ||
{ NULL, NULL }, /* Ft */ | { NULL, NULL }, /* Ft */ | ||
{ NULL, NULL }, /* Ic */ | { NULL, posts_text }, /* Ic */ | ||
{ NULL, NULL }, /* In */ | { NULL, posts_wtext }, /* In */ | ||
{ NULL, NULL }, /* Li */ | { NULL, posts_text }, /* Li */ | ||
{ NULL, NULL }, /* Nd */ | { NULL, posts_wtext }, /* Nd */ | ||
{ NULL, NULL }, /* Nm */ | { NULL, NULL }, /* Nm */ /* FIXME: If name not set? */ | ||
{ NULL, NULL }, /* Op */ | { NULL, posts_wline }, /* Op */ | ||
{ NULL, NULL }, /* Ot */ | { NULL, NULL }, /* Ot */ | ||
{ NULL, NULL }, /* Pa */ | { NULL, NULL }, /* Pa */ | ||
{ NULL, NULL }, /* Rv */ | { NULL, posts_notext }, /* Rv */ /* -std required */ | ||
{ NULL, NULL }, /* St */ | { NULL, posts_notext }, /* St */ /* arg required */ | ||
{ NULL, NULL }, /* Va */ | { NULL, posts_text }, /* Va */ | ||
{ NULL, NULL }, /* Vt */ | { NULL, posts_text }, /* Vt */ | ||
{ NULL, NULL }, /* Xr */ | { NULL, NULL }, /* Xr */ /* FIXME */ | ||
{ NULL, NULL }, /* %A */ | { NULL, posts_text }, /* %A */ | ||
{ NULL, NULL }, /* %B */ | { NULL, posts_text }, /* %B */ | ||
{ NULL, NULL }, /* %D */ | { NULL, posts_text }, /* %D */ | ||
{ NULL, NULL }, /* %I */ | { NULL, posts_text }, /* %I */ | ||
{ NULL, NULL }, /* %J */ | { NULL, posts_text }, /* %J */ | ||
{ NULL, NULL }, /* %N */ | { NULL, posts_text }, /* %N */ | ||
{ NULL, NULL }, /* %O */ | { NULL, posts_text }, /* %O */ | ||
{ NULL, NULL }, /* %P */ | { NULL, posts_text }, /* %P */ | ||
{ NULL, NULL }, /* %R */ | { NULL, posts_text }, /* %R */ | ||
{ NULL, NULL }, /* %T */ | { NULL, posts_text }, /* %T */ | ||
{ NULL, NULL }, /* %V */ | { NULL, posts_text }, /* %V */ | ||
{ NULL, NULL }, /* Ac */ | { NULL, NULL }, /* Ac */ | ||
{ NULL, NULL }, /* Ao */ | { NULL, NULL }, /* Ao */ | ||
{ NULL, NULL }, /* Aq */ | { NULL, posts_wline }, /* Aq */ | ||
{ NULL, NULL }, /* At */ /* FIXME */ | { NULL, NULL }, /* At */ /* FIXME */ | ||
{ NULL, NULL }, /* Bc */ | { NULL, NULL }, /* Bc */ | ||
{ NULL, NULL }, /* Bf */ | { NULL, NULL }, /* Bf */ | ||
{ NULL, NULL }, /* Bo */ | { NULL, NULL }, /* Bo */ | ||
{ NULL, NULL }, /* Bq */ | { NULL, posts_wline }, /* Bq */ | ||
{ NULL, NULL }, /* Bsx */ | { NULL, NULL }, /* Bsx */ | ||
{ NULL, NULL }, /* Bx */ | { NULL, NULL }, /* Bx */ | ||
{ NULL, NULL }, /* Db */ | { NULL, NULL }, /* Db */ /* FIXME: boolean */ | ||
{ NULL, NULL }, /* Dc */ | { NULL, NULL }, /* Dc */ | ||
{ NULL, NULL }, /* Do */ | { NULL, NULL }, /* Do */ | ||
{ NULL, NULL }, /* Dq */ | { NULL, posts_wline }, /* Dq */ | ||
{ NULL, NULL }, /* Ec */ | { NULL, NULL }, /* Ec */ | ||
{ NULL, NULL }, /* Ef */ /* -symbolic, etc. */ | { NULL, NULL }, /* Ef */ /* -symbolic, etc. */ | ||
{ NULL, NULL }, /* Em */ | { NULL, posts_text }, /* Em */ | ||
{ NULL, NULL }, /* Eo */ | { NULL, NULL }, /* Eo */ | ||
{ NULL, NULL }, /* Fx */ | { NULL, NULL }, /* Fx */ | ||
{ NULL, NULL }, /* Ms */ | { NULL, posts_text }, /* Ms */ /* FIXME: which symbols? */ | ||
{ NULL, NULL }, /* No */ | { NULL, posts_notext }, /* No */ | ||
{ NULL, NULL }, /* Ns */ | { NULL, posts_notext }, /* Ns */ | ||
{ NULL, NULL }, /* Nx */ | { NULL, NULL }, /* Nx */ | ||
{ NULL, NULL }, /* Ox */ | { NULL, NULL }, /* Ox */ | ||
{ NULL, NULL }, /* Pc */ | { NULL, NULL }, /* Pc */ | ||
{ NULL, NULL }, /* Pf */ /* 2 or more arguments */ | { NULL, NULL }, /* Pf */ /* FIXME: 2 or more arguments */ | ||
{ NULL, NULL }, /* Po */ | { NULL, NULL }, /* Po */ | ||
{ NULL, NULL }, /* Pq */ /* FIXME: ignore following Sh/Ss */ | { NULL, posts_wline }, /* Pq */ /* FIXME: ignore following Sh/Ss */ | ||
{ NULL, NULL }, /* Qc */ | { NULL, NULL }, /* Qc */ | ||
{ NULL, NULL }, /* Ql */ | { NULL, posts_wline }, /* Ql */ | ||
{ NULL, NULL }, /* Qo */ | { NULL, NULL }, /* Qo */ | ||
{ NULL, NULL }, /* Qq */ | { NULL, posts_wline }, /* Qq */ | ||
{ NULL, NULL }, /* Re */ | { NULL, NULL }, /* Re */ | ||
{ NULL, NULL }, /* Rs */ | { NULL, NULL }, /* Rs */ | ||
{ NULL, NULL }, /* Sc */ | { NULL, NULL }, /* Sc */ | ||
{ NULL, NULL }, /* So */ | { NULL, NULL }, /* So */ | ||
{ NULL, NULL }, /* Sq */ | { NULL, posts_wline }, /* Sq */ | ||
{ NULL, NULL }, /* Sm */ | { NULL, NULL }, /* Sm */ /* FIXME: boolean */ | ||
{ NULL, NULL }, /* Sx */ | { NULL, posts_text }, /* Sx */ | ||
{ NULL, NULL }, /* Sy */ | { NULL, posts_text }, /* Sy */ | ||
{ NULL, NULL }, /* Tn */ | { NULL, posts_text }, /* Tn */ | ||
{ NULL, NULL }, /* Ux */ | { NULL, NULL }, /* Ux */ | ||
{ NULL, NULL }, /* Xc */ | { NULL, NULL }, /* Xc */ | ||
{ NULL, NULL }, /* Xo */ | { NULL, NULL }, /* Xo */ | ||
|
|
||
{ NULL, NULL }, /* Oc */ | { NULL, NULL }, /* Oc */ | ||
{ NULL, NULL }, /* Bk */ | { NULL, NULL }, /* Bk */ | ||
{ NULL, NULL }, /* Ek */ | { NULL, NULL }, /* Ek */ | ||
{ NULL, NULL }, /* Bt */ | { NULL, posts_notext }, /* Bt */ | ||
{ NULL, NULL }, /* Hf */ | { NULL, NULL }, /* Hf */ | ||
{ NULL, NULL }, /* Fr */ | { NULL, NULL }, /* Fr */ | ||
{ NULL, NULL }, /* Ud */ | { NULL, posts_notext }, /* Ud */ | ||
}; | }; | ||
static int | static int | ||
post_bodychild_warn_ge1(struct mdoc *mdoc) | bodychild_err_eq0(struct mdoc *mdoc) | ||
{ | { | ||
if (MDOC_BODY != mdoc->last->type) | if (MDOC_BODY != mdoc->last->type) | ||
return(1); | return(1); | ||
if (NULL == mdoc->last->child) | |||
return(1); | |||
return(mdoc_warn(mdoc, WARN_ARGS_EQ0)); | |||
} | |||
static int | |||
bodychild_warn_ge1(struct mdoc *mdoc) | |||
{ | |||
if (MDOC_BODY != mdoc->last->type) | |||
return(1); | |||
if (mdoc->last->child) | if (mdoc->last->child) | ||
return(1); | return(1); | ||
return(mdoc_warn(mdoc, WARN_ARGS_GE1)); | |||
} | |||
static int | |||
elemchild_warn_eq0(struct mdoc *mdoc) | |||
{ | |||
assert(MDOC_ELEM == mdoc->last->type); | |||
if (NULL == mdoc->last->child) | |||
return(1); | |||
return(mdoc_pwarn(mdoc, mdoc->last->child->line, | |||
mdoc->last->child->pos, WARN_ARGS_EQ0)); | |||
} | |||
static int | |||
elemchild_warn_ge1(struct mdoc *mdoc) | |||
{ | |||
assert(MDOC_ELEM == mdoc->last->type); | |||
if (mdoc->last->child) | |||
return(1); | |||
return(mdoc_warn(mdoc, WARN_ARGS_GE1)); | return(mdoc_warn(mdoc, WARN_ARGS_GE1)); | ||
} | } | ||
static int | static int | ||
post_elemchild_warn_eq0(struct mdoc *mdoc) | elemchild_err_eq0(struct mdoc *mdoc) | ||
{ | { | ||
assert(MDOC_ELEM == mdoc->last->type); | assert(MDOC_ELEM == mdoc->last->type); | ||
if (NULL == mdoc->last->child) | if (NULL == mdoc->last->child) | ||
return(1); | return(1); | ||
return(mdoc_warn(mdoc, WARN_ARGS_EQ0)); | return(mdoc_err(mdoc, ERR_ARGS_EQ0)); | ||
} | } | ||
static int | static int | ||
post_elemchild_err_ge1(struct mdoc *mdoc) | elemchild_err_ge1(struct mdoc *mdoc) | ||
{ | { | ||
assert(MDOC_ELEM == mdoc->last->type); | assert(MDOC_ELEM == mdoc->last->type); | ||
|
|
||
static int | static int | ||
post_headchild_err_ge1(struct mdoc *mdoc) | headchild_err_eq0(struct mdoc *mdoc) | ||
{ | { | ||
if (MDOC_HEAD != mdoc->last->type) | if (MDOC_HEAD != mdoc->last->type) | ||
return(1); | return(1); | ||
if (NULL == mdoc->last->child) | |||
return(1); | |||
return(mdoc_perr(mdoc, mdoc->last->child->line, | |||
mdoc->last->child->pos, ERR_ARGS_EQ0)); | |||
} | |||
static int | |||
headchild_warn_ge1(struct mdoc *mdoc) | |||
{ | |||
if (MDOC_HEAD != mdoc->last->type) | |||
return(1); | |||
if (mdoc->last->child) | if (mdoc->last->child) | ||
return(1); | return(1); | ||
return(mdoc_warn(mdoc, WARN_ARGS_GE1)); | |||
} | |||
static int | |||
headchild_err_ge1(struct mdoc *mdoc) | |||
{ | |||
if (MDOC_HEAD != mdoc->last->type) | |||
return(1); | |||
if (mdoc->last->child) | |||
return(1); | |||
return(mdoc_err(mdoc, ERR_ARGS_GE1)); | return(mdoc_err(mdoc, ERR_ARGS_GE1)); | ||
} | } | ||
static int | static int | ||
pre_display(struct mdoc *mdoc, struct mdoc_node *node) | |||
{ | |||
struct mdoc_node *n; | |||
if (MDOC_BLOCK != node->type) | |||
return(1); | |||
for (n = mdoc->last; n; n = n->parent) | |||
if (MDOC_BLOCK == n->type) | |||
if (MDOC_Bd == n->tok) | |||
break; | |||
if (NULL == n) | |||
return(1); | |||
return(mdoc_verr(mdoc, node, ERR_SCOPE_NONEST)); | |||
} | |||
static int | |||
pre_bl(struct mdoc *mdoc, struct mdoc_node *node) | |||
{ | |||
int type, err; | |||
struct mdoc_arg *argv; | |||
size_t i, argc; | |||
if (MDOC_BLOCK != node->type) | |||
return(1); | |||
assert(MDOC_Bl == node->tok); | |||
argv = NULL; | |||
argc = node->data.block.argc; | |||
for (i = type = err = 0; i < argc; i++) { | |||
argv = &node->data.block.argv[(int)i]; | |||
assert(argv); | |||
switch (argv->arg) { | |||
case (MDOC_Bullet): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Dash): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Enum): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Hyphen): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Item): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Tag): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Diag): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Hang): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Ohang): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Inset): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Column): | |||
if (type) | |||
err++; | |||
type++; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
if (0 == type) | |||
return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS)); | |||
if (0 == err) | |||
return(1); | |||
assert(argv); | |||
return(mdoc_perr(mdoc, argv->line, | |||
argv->pos, ERR_SYNTAX_ARGBAD)); | |||
} | |||
static int | |||
pre_bd(struct mdoc *mdoc, struct mdoc_node *node) | |||
{ | |||
int type, err; | |||
struct mdoc_arg *argv; | |||
size_t i, argc; | |||
if (MDOC_BLOCK != node->type) | |||
return(1); | |||
assert(MDOC_Bd == node->tok); | |||
argv = NULL; | |||
argc = node->data.block.argc; | |||
for (err = i = type = 0; 0 == err && i < argc; i++) { | |||
argv = &node->data.block.argv[(int)i]; | |||
assert(argv); | |||
switch (argv->arg) { | |||
case (MDOC_Ragged): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Unfilled): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Filled): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Literal): | |||
/* FALLTHROUGH */ | |||
case (MDOC_File): | |||
if (type) | |||
err++; | |||
type++; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
if (0 == type) | |||
return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS)); | |||
if (0 == err) | |||
return(1); | |||
assert(argv); | |||
return(mdoc_perr(mdoc, argv->line, | |||
argv->pos, ERR_SYNTAX_ARGBAD)); | |||
} | |||
static int | |||
pre_it(struct mdoc *mdoc, struct mdoc_node *node) | |||
{ | |||
if (MDOC_BLOCK != mdoc->last->type) | |||
return(1); | |||
assert(MDOC_It == mdoc->last->tok); | |||
if (MDOC_BODY != mdoc->last->parent->type) | |||
return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD)); | |||
if (MDOC_Bl != mdoc->last->parent->tok) | |||
return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD)); | |||
return(1); | |||
} | |||
static int | |||
pre_prologue(struct mdoc *mdoc, struct mdoc_node *node) | pre_prologue(struct mdoc *mdoc, struct mdoc_node *node) | ||
{ | { | ||
|
|
||
/* Check for ordering. */ | /* Check for ordering. */ | ||
switch (node->data.elem.tok) { | switch (node->tok) { | ||
case (MDOC_Os): | case (MDOC_Os): | ||
if (mdoc->meta.title[0] && mdoc->meta.date) | if (mdoc->meta.title[0] && mdoc->meta.date) | ||
break; | break; | ||
|
|
||
/* Check for repetition. */ | /* Check for repetition. */ | ||
switch (node->data.elem.tok) { | switch (node->tok) { | ||
case (MDOC_Os): | case (MDOC_Os): | ||
if (0 == mdoc->meta.os[0]) | if (0 == mdoc->meta.os[0]) | ||
return(1); | return(1); | ||
|
|
||
} | } | ||
/* | /* Warn if `Bl' type-specific syntax isn't reflected in items. */ | ||
* Warn if sections (those that are with a known title, such as NAME, | |||
* DESCRIPTION, and so forth) are out of the conventional order. | |||
*/ | |||
static int | static int | ||
post_it(struct mdoc *mdoc) | |||
{ | |||
int type, sv; | |||
#define TYPE_NONE (0) | |||
#define TYPE_BODY (1) | |||
#define TYPE_HEAD (2) | |||
size_t i, argc; | |||
struct mdoc_node *n; | |||
if (MDOC_BLOCK != mdoc->last->type) | |||
return(1); | |||
assert(MDOC_It == mdoc->last->tok); | |||
n = mdoc->last->parent; | |||
assert(n); | |||
assert(MDOC_Bl == n->tok); | |||
n = n->parent; | |||
assert(MDOC_BLOCK == n->type); | |||
assert(MDOC_Bl == n->tok); | |||
argc = n->data.block.argc; | |||
type = TYPE_NONE; | |||
/* Some types require block-head, some not. */ | |||
for (i = 0; TYPE_NONE == type && i < argc; i++) | |||
switch (n->data.block.argv[(int)i].arg) { | |||
case (MDOC_Tag): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Diag): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Hang): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Ohang): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Inset): | |||
type = TYPE_HEAD; | |||
sv = n->data.block.argv[(int)i].arg; | |||
break; | |||
case (MDOC_Bullet): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Dash): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Enum): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Hyphen): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Item): | |||
/* FALLTHROUGH */ | |||
case (MDOC_Column): | |||
type = TYPE_BODY; | |||
sv = n->data.block.argv[(int)i].arg; | |||
break; | |||
default: | |||
break; | |||
} | |||
assert(TYPE_NONE != type); | |||
if (TYPE_HEAD == type) { | |||
if (NULL == (n = mdoc->last->data.block.head)) { | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD)) | |||
return(0); | |||
} else if (NULL == n->child) | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD)) | |||
return(0); | |||
if (NULL == (n = mdoc->last->data.block.body)) { | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY)) | |||
return(0); | |||
} else if (NULL == n->child) | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY)) | |||
return(0); | |||
return(1); | |||
} | |||
if (NULL == (n = mdoc->last->data.block.head)) { | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD)) | |||
return(0); | |||
} else if (NULL == n->child) | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD)) | |||
return(0); | |||
if ((n = mdoc->last->data.block.body) && n->child) | |||
if ( ! mdoc_warn(mdoc, WARN_SYNTAX_NOBODY)) | |||
return(0); | |||
if (MDOC_Column != sv) | |||
return(1); | |||
/* Make sure the number of columns is sane. */ | |||
sv = mdoc->last->parent->parent->data.block.argv->sz; | |||
n = mdoc->last->data.block.head->child; | |||
for (i = 0; n; n = n->next) | |||
i++; | |||
if (i == (size_t)sv) | |||
return(1); | |||
return(mdoc_err(mdoc, ERR_SYNTAX_ARGFORM)); | |||
#undef TYPE_NONE | |||
#undef TYPE_BODY | |||
#undef TYPE_HEAD | |||
} | |||
/* Make sure that only `It' macros are our body-children. */ | |||
static int | |||
post_bl(struct mdoc *mdoc) | |||
{ | |||
struct mdoc_node *n; | |||
if (MDOC_BODY != mdoc->last->type) | |||
return(1); | |||
assert(MDOC_Bl == mdoc->last->tok); | |||
for (n = mdoc->last->child; n; n = n->next) { | |||
if (MDOC_BLOCK == n->type) | |||
if (MDOC_It == n->tok) | |||
continue; | |||
break; | |||
} | |||
if (NULL == n) | |||
return(1); | |||
return(mdoc_verr(mdoc, n, ERR_SYNTAX_CHILDBAD)); | |||
} | |||
/* Warn if conventional sections are out of order. */ | |||
static int | |||
post_sh(struct mdoc *mdoc) | post_sh(struct mdoc *mdoc) | ||
{ | { | ||
enum mdoc_sec sec; | enum mdoc_sec sec; | ||
|
|
||
if (MDOC_HEAD != mdoc->last->type) | if (MDOC_HEAD != mdoc->last->type) | ||
return(1); | return(1); | ||
assert(MDOC_Sh == mdoc->last->data.head.tok); | assert(MDOC_Sh == mdoc->last->tok); | ||
n = mdoc->last->child; | n = mdoc->last->child; | ||
assert(n); | assert(n); | ||
|
|
||
int | int | ||
mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node) | mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node) | ||
{ | { | ||
int t; | v_pre *p; | ||
switch (node->type) { | /* TODO: character-escape checks. */ | ||
case (MDOC_BODY): | |||
t = node->data.body.tok; | if (MDOC_TEXT == node->type) | ||
break; | |||
case (MDOC_ELEM): | |||
t = node->data.elem.tok; | |||
break; | |||
case (MDOC_BLOCK): | |||
t = node->data.block.tok; | |||
break; | |||
case (MDOC_HEAD): | |||
t = node->data.head.tok; | |||
break; | |||
default: | |||
return(1); | return(1); | ||
} | assert(MDOC_ROOT != node->type); | ||
if (NULL == mdoc_valids[t].pre) | if (NULL == mdoc_valids[node->tok].pre) | ||
return(1); | return(1); | ||
return((*mdoc_valids[t].pre)(mdoc, node)); | for (p = mdoc_valids[node->tok].pre; *p; p++) | ||
if ( ! (*p)(mdoc, node)) | |||
return(0); | |||
return(1); | |||
} | } | ||
|
|
||
mdoc_valid_post(struct mdoc *mdoc) | mdoc_valid_post(struct mdoc *mdoc) | ||
{ | { | ||
v_post *p; | v_post *p; | ||
int t; | |||
switch (mdoc->last->type) { | if (MDOC_TEXT == mdoc->last->type) | ||
case (MDOC_BODY): | |||
t = mdoc->last->data.body.tok; | |||
break; | |||
case (MDOC_ELEM): | |||
t = mdoc->last->data.elem.tok; | |||
break; | |||
case (MDOC_BLOCK): | |||
t = mdoc->last->data.block.tok; | |||
break; | |||
case (MDOC_HEAD): | |||
t = mdoc->last->data.head.tok; | |||
break; | |||
default: | |||
return(1); | return(1); | ||
} | if (MDOC_ROOT == mdoc->last->type) | ||
if (NULL == mdoc_valids[t].post) | |||
return(1); | return(1); | ||
for (p = mdoc_valids[t].post; *p; p++) | if (NULL == mdoc_valids[mdoc->last->tok].post) | ||
return(1); | |||
for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) | |||
if ( ! (*p)(mdoc)) | if ( ! (*p)(mdoc)) | ||
return(0); | return(0); | ||