summaryrefslogtreecommitdiffstats
path: root/validate.c
diff options
context:
space:
mode:
Diffstat (limited to 'validate.c')
-rw-r--r--validate.c71
1 files changed, 56 insertions, 15 deletions
diff --git a/validate.c b/validate.c
index 6ed8b6f8..8841b738 100644
--- a/validate.c
+++ b/validate.c
@@ -91,6 +91,8 @@ static int bwarn_ge1(struct mdoc *);
static int ewarn_ge1(struct mdoc *);
static int ebool(struct mdoc *);
static int post_sh(struct mdoc *);
+static int post_sh_body(struct mdoc *);
+static int post_sh_head(struct mdoc *);
static int post_bl(struct mdoc *);
static int post_it(struct mdoc *);
static int post_ex(struct mdoc *);
@@ -717,7 +719,7 @@ static int
pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
{
- if (SEC_PROLOGUE != mdoc->sec_lastn)
+ if (SEC_PROLOGUE != mdoc->lastnamed)
return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
assert(MDOC_ELEM == node->type);
@@ -1060,39 +1062,78 @@ static int
post_root(struct mdoc *mdoc)
{
- if (NULL == mdoc->last->child)
+ if (NULL == mdoc->first->child)
return(mdoc_err(mdoc, "document has no data"));
- if (NULL == mdoc->meta.title)
- return(mdoc_err(mdoc, "document has incomplete prologue"));
- if (NULL == mdoc->meta.os)
- return(mdoc_err(mdoc, "document has incomplete prologue"));
- if (0 == mdoc->meta.date)
+ if (SEC_PROLOGUE == mdoc->lastnamed)
return(mdoc_err(mdoc, "document has incomplete prologue"));
+ if (MDOC_BLOCK != mdoc->first->child->type)
+ return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
+ if (MDOC_Sh != mdoc->first->child->tok)
+ return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
return(1);
}
-/* Warn if conventional sections are out of order. */
static int
post_sh(struct mdoc *mdoc)
{
+
+ if (MDOC_HEAD == mdoc->last->type)
+ return(post_sh_head(mdoc));
+ if (MDOC_BODY == mdoc->last->type)
+ return(post_sh_body(mdoc));
+ return(1);
+}
+
+
+static int
+post_sh_body(struct mdoc *mdoc)
+{
+ struct mdoc_node *n;
+
+ assert(MDOC_Sh == mdoc->last->tok);
+ if (SEC_NAME != mdoc->lastnamed)
+ return(1);
+
+ if (NULL == (n = mdoc->last->child))
+ return(mdoc_err(mdoc, "section NAME must contain %s as the first body child", mdoc_macronames[MDOC_Nm]));
+ if (MDOC_ELEM != n->type || MDOC_Nm != n->tok)
+ return(mdoc_err(mdoc, "section NAME must contain %s as the first body child", mdoc_macronames[MDOC_Nm]));
+ if (NULL == (n = n->next))
+ return(mdoc_err(mdoc, "section NAME must contain %s as the second body child", mdoc_macronames[MDOC_Nd]));
+ if (MDOC_ELEM != n->type || MDOC_Nd != n->tok)
+ return(mdoc_err(mdoc, "section NAME must contain %s as the second body child", mdoc_macronames[MDOC_Nd]));
+ if (NULL == (n = n->next))
+ return(1);
+
+ return(mdoc_warn(mdoc, WARN_SYNTAX, "section NAME usually limited to %s and %s body children",
+ mdoc_macronames[MDOC_Nm], mdoc_macronames[MDOC_Nd]));
+}
+
+
+static int
+post_sh_head(struct mdoc *mdoc)
+{
char buf[64];
enum mdoc_sec sec;
- if (MDOC_HEAD != mdoc->last->type)
- return(1);
assert(MDOC_Sh == mdoc->last->tok);
if ( ! xstrlcats(buf, mdoc->last->child, 64))
return(mdoc_err(mdoc, "macro parameters too long"));
- if (SEC_CUSTOM == (sec = mdoc_atosec(buf)))
- return(1);
- if (sec > mdoc->sec_lastn)
+ sec = mdoc_atosec(buf);
+
+ if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec)
+ return(mdoc_err(mdoc, "section NAME must be first"));
+ if (SEC_CUSTOM == sec)
return(1);
- if (sec == mdoc->sec_lastn)
+ if (sec == mdoc->lastnamed)
return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated"));
- return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
+ if (sec < mdoc->lastnamed)
+ return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
+
+ return(1);
}