]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdoc_validate.c
In mdoc(7), don't mistreat negative .sp arguments as large positive ones.
[mandoc.git] / mdoc_validate.c
index 830e9e2717833d7b32cc84db081974168dd3fc44..eb531e82898753d0a611df49aa4b1b61ed0a16be 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_validate.c,v 1.276 2015/02/06 16:06:25 schwarze Exp $ */
+/*     $Id: mdoc_validate.c,v 1.283 2015/02/23 13:55:55 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
@@ -298,7 +298,8 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
 
        switch (n->type) {
        case MDOC_TEXT:
-               check_text(mdoc, n->line, n->pos, n->string);
+               if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
+                       check_text(mdoc, n->line, n->pos, n->string);
                /* FALLTHROUGH */
        case MDOC_TBL:
                /* FALLTHROUGH */
@@ -325,7 +326,7 @@ mdoc_valid_post(struct mdoc *mdoc)
        n = mdoc->last;
        if (n->flags & MDOC_VALID)
                return;
-       n->flags |= MDOC_VALID;
+       n->flags |= MDOC_VALID | MDOC_ENDED;
 
        switch (n->type) {
        case MDOC_TEXT:
@@ -416,24 +417,13 @@ pre_display(PRE_ARGS)
 static void
 pre_bl(PRE_ARGS)
 {
-       struct mdoc_node *np;
        struct mdoc_argv *argv, *wa;
        int               i;
        enum mdocargt     mdoclt;
        enum mdoc_list    lt;
 
-       if (MDOC_BLOCK != n->type) {
-               if (ENDBODY_NOT != n->end) {
-                       assert(n->pending);
-                       np = n->pending->parent;
-               } else
-                       np = n->parent;
-
-               assert(np);
-               assert(MDOC_BLOCK == np->type);
-               assert(MDOC_Bl == np->tok);
+       if (n->type != MDOC_BLOCK)
                return;
-       }
 
        /*
         * First figure out which kind of list to use: bind ourselves to
@@ -609,25 +599,14 @@ pre_bl(PRE_ARGS)
 static void
 pre_bd(PRE_ARGS)
 {
-       struct mdoc_node *np;
        struct mdoc_argv *argv;
        int               i;
        enum mdoc_disp    dt;
 
        pre_literal(mdoc, n);
 
-       if (MDOC_BLOCK != n->type) {
-               if (ENDBODY_NOT != n->end) {
-                       assert(n->pending);
-                       np = n->pending->parent;
-               } else
-                       np = n->parent;
-
-               assert(np);
-               assert(MDOC_BLOCK == np->type);
-               assert(MDOC_Bd == np->tok);
+       if (n->type != MDOC_BLOCK)
                return;
-       }
 
        for (i = 0; n->args && i < (int)n->args->argc; i++) {
                argv = n->args->argv + i;
@@ -797,22 +776,10 @@ post_bf(POST_ARGS)
         * element, which contains the goods.
         */
 
-       if (MDOC_HEAD != mdoc->last->type) {
-               if (ENDBODY_NOT != mdoc->last->end) {
-                       assert(mdoc->last->pending);
-                       np = mdoc->last->pending->parent->head;
-               } else if (MDOC_BLOCK != mdoc->last->type) {
-                       np = mdoc->last->parent->head;
-               } else
-                       np = mdoc->last->head;
-
-               assert(np);
-               assert(MDOC_HEAD == np->type);
-               assert(MDOC_Bf == np->tok);
+       np = mdoc->last;
+       if (MDOC_HEAD != np->type)
                return;
-       }
 
-       np = mdoc->last;
        assert(MDOC_BLOCK == np->parent->type);
        assert(MDOC_Bf == np->parent->tok);
 
@@ -872,7 +839,7 @@ post_lb(POST_ARGS)
 
        if (NULL == (stdlibname = mdoc_a2lib(n->string)))
                mandoc_asprintf(&libname,
-                   "library \\(lq%s\\(rq", n->string);
+                   "library \\(Lq%s\\(Rq", n->string);
        else
                libname = mandoc_strdup(stdlibname);
 
@@ -1781,41 +1748,45 @@ static void
 post_sh_name(POST_ARGS)
 {
        struct mdoc_node *n;
+       int hasnm, hasnd;
 
-       /*
-        * Warn if the NAME section doesn't contain the `Nm' and `Nd'
-        * macros (can have multiple `Nm' and one `Nd').  Note that the
-        * children of the BODY declaration can also be "text".
-        */
+       hasnm = hasnd = 0;
 
-       if (NULL == (n = mdoc->last->child)) {
-               mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
-                   mdoc->last->line, mdoc->last->pos, "empty");
-               return;
-       }
-
-       for ( ; n && n->next; n = n->next) {
-               if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
-                       continue;
-               if (MDOC_TEXT == n->type)
-                       continue;
-               mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
-                   n->line, n->pos, mdoc_macronames[n->tok]);
+       for (n = mdoc->last->child; n != NULL; n = n->next) {
+               switch (n->tok) {
+               case MDOC_Nm:
+                       hasnm = 1;
+                       break;
+               case MDOC_Nd:
+                       hasnd = 1;
+                       if (n->next != NULL)
+                               mandoc_msg(MANDOCERR_NAMESEC_ND,
+                                   mdoc->parse, n->line, n->pos, NULL);
+                       break;
+               case MDOC_MAX:
+                       if (hasnm)
+                               break;
+                       /* FALLTHROUGH */
+               default:
+                       mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
+                           n->line, n->pos, mdoc_macronames[n->tok]);
+                       break;
+               }
        }
 
-       assert(n);
-       if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
-               return;
-
-       mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
-           n->line, n->pos, mdoc_macronames[n->tok]);
+       if ( ! hasnm)
+               mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
+                   mdoc->last->line, mdoc->last->pos, NULL);
+       if ( ! hasnd)
+               mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
+                   mdoc->last->line, mdoc->last->pos, NULL);
 }
 
 static void
 post_sh_see_also(POST_ARGS)
 {
        const struct mdoc_node  *n;
-       const char              *name, *sec;
+       const char              *name, *sec;
        const char              *lastname, *lastsec, *lastpunct;
        int                      cmp;
 
@@ -2189,70 +2160,68 @@ post_dt(POST_ARGS)
        mdoc->meta.vol = NULL;
        mdoc->meta.arch = NULL;
 
-       /* First check that all characters are uppercase. */
-
-       if (NULL != (nn = n->child))
-               for (p = nn->string; *p; p++) {
-                       if (toupper((unsigned char)*p) == *p)
-                               continue;
-                       mandoc_vmsg(MANDOCERR_TITLE_CASE,
-                           mdoc->parse, nn->line,
-                           nn->pos + (p - nn->string),
-                           "Dt %s", nn->string);
-                       break;
-               }
-
-       /* No argument: msec and arch remain NULL. */
+       /* Mandatory first argument: title. */
 
-       if (NULL == (nn = n->child)) {
+       nn = n->child;
+       if (nn == NULL || *nn->string == '\0') {
                mandoc_msg(MANDOCERR_DT_NOTITLE,
                    mdoc->parse, n->line, n->pos, "Dt");
                mdoc->meta.title = mandoc_strdup("UNTITLED");
-               mdoc->meta.vol = mandoc_strdup("LOCAL");
-               goto out;
+       } else {
+               mdoc->meta.title = mandoc_strdup(nn->string);
+
+               /* Check that all characters are uppercase. */
+
+               for (p = nn->string; *p != '\0'; p++)
+                       if (islower((unsigned char)*p)) {
+                               mandoc_vmsg(MANDOCERR_TITLE_CASE,
+                                   mdoc->parse, nn->line,
+                                   nn->pos + (p - nn->string),
+                                   "Dt %s", nn->string);
+                               break;
+                       }
        }
 
-       /* One argument: msec and arch remain NULL. */
+       /* Mandatory second argument: section. */
 
-       mdoc->meta.title = mandoc_strdup(
-           '\0' == nn->string[0] ? "UNTITLED" : nn->string);
+       if (nn != NULL)
+               nn = nn->next;
 
-       if (NULL == (nn = nn->next)) {
+       if (nn == NULL) {
                mandoc_vmsg(MANDOCERR_MSEC_MISSING,
                    mdoc->parse, n->line, n->pos,
                    "Dt %s", mdoc->meta.title);
                mdoc->meta.vol = mandoc_strdup("LOCAL");
-               goto out;
+               goto out;  /* msec and arch remain NULL. */
        }
 
-       /* Handles: `.Dt TITLE SEC'
-        * title = TITLE,
-        * volume = SEC is msec ? format(msec) : SEC,
-        * msec = SEC is msec ? atoi(msec) : 0,
-        * arch = NULL
-        */
+       mdoc->meta.msec = mandoc_strdup(nn->string);
+
+       /* Infer volume title from section number. */
 
        cp = mandoc_a2msec(nn->string);
-       if (cp) {
-               mdoc->meta.vol = mandoc_strdup(cp);
-               mdoc->meta.msec = mandoc_strdup(nn->string);
-       } else {
+       if (cp == NULL) {
                mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
                    nn->line, nn->pos, "Dt ... %s", nn->string);
                mdoc->meta.vol = mandoc_strdup(nn->string);
-               mdoc->meta.msec = mandoc_strdup(nn->string);
-       }
+       } else
+               mdoc->meta.vol = mandoc_strdup(cp);
 
-       /* Handle an optional architecture */
+       /* Optional third argument: architecture. */
 
-       if ((nn = nn->next) != NULL) {
-               for (p = nn->string; *p; p++)
-                       *p = tolower((unsigned char)*p);
-               mdoc->meta.arch = mandoc_strdup(nn->string);
-       }
+       if ((nn = nn->next) == NULL)
+               goto out;
+
+       for (p = nn->string; *p != '\0'; p++)
+               *p = tolower((unsigned char)*p);
+       mdoc->meta.arch = mandoc_strdup(nn->string);
+
+       /* Ignore fourth and later arguments. */
+
+       if ((nn = nn->next) != NULL)
+               mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+                   nn->line, nn->pos, "Dt ... %s", nn->string);
 
-       /* Ignore any subsequent parameters... */
-       /* FIXME: warn about subsequent parameters. */
 out:
        mdoc_node_delete(mdoc, n);
 }