]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdoc_validate.c
do not crash when a manpath directory contains a symbolic link
[mandoc.git] / mdoc_validate.c
index bae3d6b8c3e5b6ddbdfa85485c9ba9925d69a0b7..e1cd3ae1edcbff150170a061868c3013146f511b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mdoc_validate.c,v 1.380 2020/03/13 15:32:28 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.389 2021/07/18 11:41:23 schwarze Exp $ */
 /*
  * Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
 #include "mandoc.h"
 #include "mandoc_xr.h"
 #include "roff.h"
-#include "tag.h"
 #include "mdoc.h"
 #include "libmandoc.h"
 #include "roff_int.h"
 #include "libmdoc.h"
+#include "tag.h"
 
 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
 
@@ -92,11 +92,11 @@ static      void     post_es(POST_ARGS);
 static void     post_eoln(POST_ARGS);
 static void     post_ex(POST_ARGS);
 static void     post_fa(POST_ARGS);
+static void     post_fl(POST_ARGS);
 static void     post_fn(POST_ARGS);
 static void     post_fname(POST_ARGS);
 static void     post_fo(POST_ARGS);
 static void     post_hyph(POST_ARGS);
-static void     post_ignpar(POST_ARGS);
 static void     post_it(POST_ARGS);
 static void     post_lb(POST_ARGS);
 static void     post_nd(POST_ARGS);
@@ -109,6 +109,7 @@ static      void     post_prevpar(POST_ARGS);
 static void     post_root(POST_ARGS);
 static void     post_rs(POST_ARGS);
 static void     post_rv(POST_ARGS);
+static void     post_section(POST_ARGS);
 static void     post_sh(POST_ARGS);
 static void     post_sh_head(POST_ARGS);
 static void     post_sh_name(POST_ARGS);
@@ -129,7 +130,7 @@ static      const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
        post_dt,        /* Dt */
        post_os,        /* Os */
        post_sh,        /* Sh */
-       post_ignpar,    /* Ss */
+       post_section,   /* Ss */
        post_par,       /* Pp */
        post_display,   /* D1 */
        post_display,   /* Dl */
@@ -150,7 +151,7 @@ static      const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
        post_ex,        /* Ex */
        post_fa,        /* Fa */
        NULL,           /* Fd */
-       post_tag,       /* Fl */
+       post_fl,        /* Fl */
        post_fn,        /* Fn */
        post_delim_nb,  /* Ft */
        post_tag,       /* Ic */
@@ -163,7 +164,7 @@ static      const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
        post_defaults,  /* Pa */
        post_rv,        /* Rv */
        post_st,        /* St */
-       post_delim_nb,  /* Va */
+       post_tag,       /* Va */
        post_delim_nb,  /* Vt */
        post_xr,        /* Xr */
        NULL,           /* %A */
@@ -1105,6 +1106,7 @@ post_tg(POST_ARGS)
        struct roff_node *n;    /* The .Tg node. */
        struct roff_node *nch;  /* The first child of the .Tg node. */
        struct roff_node *nn;   /* The next node after the .Tg node. */
+       struct roff_node *np;   /* The parent of the next node. */
        struct roff_node *nt;   /* The TEXT node containing the tag. */
        size_t            len;  /* The number of bytes in the tag. */
 
@@ -1150,7 +1152,7 @@ post_tg(POST_ARGS)
        }
 
        /* By default, tag the .Tg node itself. */
-       if (nn == NULL)
+       if (nn == NULL || nn->flags & NODE_ID)
                nn = n;
 
        /* Explicit tagging of specific macros. */
@@ -1158,8 +1160,41 @@ post_tg(POST_ARGS)
        case MDOC_Sh:
        case MDOC_Ss:
        case MDOC_Fo:
-               nn = nn->head;
-               /* FALLTHROUGH */
+               nn = nn->head->child == NULL ? n : nn->head;
+               break;
+       case MDOC_It:
+               np = nn->parent;
+               while (np->tok != MDOC_Bl)
+                       np = np->parent;
+               switch (np->norm->Bl.type) {
+               case LIST_column:
+                       break;
+               case LIST_diag:
+               case LIST_hang:
+               case LIST_inset:
+               case LIST_ohang:
+               case LIST_tag:
+                       nn = nn->head;
+                       break;
+               case LIST_bullet:
+               case LIST_dash:
+               case LIST_enum:
+               case LIST_hyphen:
+               case LIST_item:
+                       nn = nn->body->child == NULL ? n : nn->body;
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       case MDOC_Bd:
+       case MDOC_Bl:
+       case MDOC_D1:
+       case MDOC_Dl:
+               nn = nn->body->child == NULL ? n : nn->body;
+               break;
+       case MDOC_Pp:
+               break;
        case MDOC_Cm:
        case MDOC_Dv:
        case MDOC_Em:
@@ -1172,9 +1207,9 @@ post_tg(POST_ARGS)
        case MDOC_Ms:
        case MDOC_No:
        case MDOC_Sy:
-               if (nn->child != NULL && (nn->flags & NODE_ID) == 0)
-                       break;
-               /* FALLTHROUGH */
+               if (nn->child == NULL)
+                       nn = n;
+               break;
        default:
                nn = n;
                break;
@@ -1593,6 +1628,29 @@ post_es(POST_ARGS)
        mdoc->last_es = mdoc->last;
 }
 
+static void
+post_fl(POST_ARGS)
+{
+       struct roff_node        *n;
+       char                    *cp;
+
+       /*
+        * Transform ".Fl Fl long" to ".Fl \-long",
+        * resulting for example in better HTML output.
+        */
+
+       n = mdoc->last;
+       if (n->prev != NULL && n->prev->tok == MDOC_Fl &&
+           n->prev->child == NULL && n->child != NULL &&
+           (n->flags & NODE_LINE) == 0) {
+               mandoc_asprintf(&cp, "\\-%s", n->child->string);
+               free(n->child->string);
+               n->child->string = cp;
+               roff_node_delete(mdoc, n->prev);
+       }
+       post_tag(mdoc);
+}
+
 static void
 post_xx(POST_ARGS)
 {
@@ -2164,10 +2222,11 @@ post_rs(POST_ARGS)
 static void
 post_hyph(POST_ARGS)
 {
-       struct roff_node        *nch;
+       struct roff_node        *n, *nch;
        char                    *cp;
 
-       for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
+       n = mdoc->last;
+       for (nch = n->child; nch != NULL; nch = nch->next) {
                if (nch->type != ROFFT_TEXT)
                        continue;
                cp = nch->string;
@@ -2176,8 +2235,11 @@ post_hyph(POST_ARGS)
                while (*(++cp) != '\0')
                        if (*cp == '-' &&
                            isalpha((unsigned char)cp[-1]) &&
-                           isalpha((unsigned char)cp[1]))
+                           isalpha((unsigned char)cp[1])) {
+                               if (n->tag == NULL && n->flags & NODE_ID)
+                                       n->tag = mandoc_strdup(nch->string);
                                *cp = ASCII_HYPH;
+                       }
        }
 }
 
@@ -2202,7 +2264,7 @@ post_sx(POST_ARGS)
 static void
 post_sh(POST_ARGS)
 {
-       post_ignpar(mdoc);
+       post_section(mdoc);
 
        switch (mdoc->last->type) {
        case ROFFT_HEAD:
@@ -2535,15 +2597,31 @@ post_xr(POST_ARGS)
 }
 
 static void
-post_ignpar(POST_ARGS)
+post_section(POST_ARGS)
 {
-       struct roff_node *np;
+       struct roff_node *n, *nch;
+       char             *cp, *tag;
 
-       switch (mdoc->last->type) {
+       n = mdoc->last;
+       switch (n->type) {
        case ROFFT_BLOCK:
                post_prevpar(mdoc);
                return;
        case ROFFT_HEAD:
+               tag = NULL;
+               deroff(&tag, n);
+               if (tag != NULL) {
+                       for (cp = tag; *cp != '\0'; cp++)
+                               if (*cp == ' ')
+                                       *cp = '_';
+                       if ((nch = n->child) != NULL &&
+                           nch->type == ROFFT_TEXT &&
+                           strcmp(nch->string, tag) == 0)
+                               tag_put(NULL, TAG_STRONG, n);
+                       else
+                               tag_put(tag, TAG_FALLBACK, n);
+                       free(tag);
+               }
                post_delim(mdoc);
                post_hyph(mdoc);
                return;
@@ -2552,23 +2630,21 @@ post_ignpar(POST_ARGS)
        default:
                return;
        }
-
-       if ((np = mdoc->last->child) != NULL)
-               if (np->tok == MDOC_Pp ||
-                   np->tok == ROFF_br || np->tok == ROFF_sp) {
-                       mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
-                           "%s after %s", roff_name[np->tok],
-                           roff_name[mdoc->last->tok]);
-                       roff_node_delete(mdoc, np);
-               }
-
-       if ((np = mdoc->last->last) != NULL)
-               if (np->tok == MDOC_Pp || np->tok == ROFF_br) {
-                       mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
-                           "%s at the end of %s", roff_name[np->tok],
-                           roff_name[mdoc->last->tok]);
-                       roff_node_delete(mdoc, np);
-               }
+       if ((nch = n->child) != NULL &&
+           (nch->tok == MDOC_Pp || nch->tok == ROFF_br ||
+            nch->tok == ROFF_sp)) {
+               mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos,
+                   "%s after %s", roff_name[nch->tok],
+                   roff_name[n->tok]);
+               roff_node_delete(mdoc, nch);
+       }
+       if ((nch = n->last) != NULL &&
+           (nch->tok == MDOC_Pp || nch->tok == ROFF_br)) {
+               mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos,
+                   "%s at the end of %s", roff_name[nch->tok],
+                   roff_name[n->tok]);
+               roff_node_delete(mdoc, nch);
+       }
 }
 
 static void
@@ -2713,8 +2789,14 @@ post_dt(POST_ARGS)
                mandoc_msg(MANDOCERR_MSEC_BAD,
                    nn->line, nn->pos, "Dt ... %s", nn->string);
                mdoc->meta.vol = mandoc_strdup(nn->string);
-       } else
+       } else {
                mdoc->meta.vol = mandoc_strdup(cp);
+               if (mdoc->filesec != '\0' &&
+                   mdoc->filesec != *nn->string &&
+                   *nn->string >= '1' && *nn->string <= '9')
+                       mandoc_msg(MANDOCERR_MSEC_FILE, nn->line, nn->pos,
+                           "*.%c vs Dt ... %c", mdoc->filesec, *nn->string);
+       }
 
        /* Optional third argument: architecture. */