=================================================================== RCS file: /cvs/mandoc/mdoc_validate.c,v retrieving revision 1.366 retrieving revision 1.379 diff -u -p -r1.366 -r1.379 --- mandoc/mdoc_validate.c 2018/12/30 00:49:55 1.366 +++ mandoc/mdoc_validate.c 2020/02/27 21:43:44 1.379 @@ -1,7 +1,7 @@ -/* $Id: mdoc_validate.c,v 1.366 2018/12/30 00:49:55 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.379 2020/02/27 21:43:44 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010-2018 Ingo Schwarze + * Copyright (c) 2010-2020 Ingo Schwarze * Copyright (c) 2010 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any @@ -64,7 +64,7 @@ static size_t macro2len(enum roff_tok); static void rewrite_macro2len(struct roff_man *, char **); static int similar(const char *, const char *); -static void post_abort(POST_ARGS); +static void post_abort(POST_ARGS) __attribute__((__noreturn__)); static void post_an(POST_ARGS); static void post_an_norm(POST_ARGS); static void post_at(POST_ARGS); @@ -113,6 +113,7 @@ static void post_sm(POST_ARGS); static void post_st(POST_ARGS); static void post_std(POST_ARGS); static void post_sx(POST_ARGS); +static void post_tg(POST_ARGS); static void post_useless(POST_ARGS); static void post_xr(POST_ARGS); static void post_xx(POST_ARGS); @@ -238,6 +239,7 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = NULL, /* %Q */ NULL, /* %U */ NULL, /* Ta */ + post_tg, /* Tg */ }; #define RSORD_MAX 14 /* Number of `Rs' blocks. */ @@ -288,7 +290,7 @@ static const char * const secnames[SEC__MAX] = { /* Validate the subtree rooted at mdoc->last. */ void -mdoc_node_validate(struct roff_man *mdoc) +mdoc_validate(struct roff_man *mdoc) { struct roff_node *n, *np; const v_post *p; @@ -319,7 +321,7 @@ mdoc_node_validate(struct roff_man *mdoc) mdoc->last = mdoc->last->child; while (mdoc->last != NULL) { - mdoc_node_validate(mdoc); + mdoc_validate(mdoc); if (mdoc->last == n) mdoc->last = mdoc->last->child; else @@ -336,9 +338,7 @@ mdoc_node_validate(struct roff_man *mdoc) if (n->sec != SEC_SYNOPSIS || (np->tok != MDOC_Cd && np->tok != MDOC_Fd)) check_text(mdoc, n->line, n->pos, n->string); - if (np->tok != MDOC_Ql && np->tok != MDOC_Dl && - (np->tok != MDOC_Bd || - (mdoc->flags & MDOC_LITERAL) == 0) && + if ((n->flags & NODE_NOFILL) == 0 && (np->tok != MDOC_It || np->type != ROFFT_HEAD || np->parent->parent->norm->Bl.type != LIST_diag)) check_text_em(mdoc, n->line, n->pos, n->string); @@ -411,7 +411,7 @@ check_text(struct roff_man *mdoc, int ln, int pos, cha { char *cp; - if (MDOC_LITERAL & mdoc->flags) + if (mdoc->last->flags & NODE_NOFILL) return; for (cp = p; NULL != (p = strchr(p, '\t')); p++) @@ -1092,6 +1092,80 @@ post_st(POST_ARGS) } static void +post_tg(POST_ARGS) +{ + struct roff_node *n, *nch, *nn; + size_t len; + + /* Find the next node. */ + n = mdoc->last; + for (nn = n; nn != NULL; nn = nn->parent) { + if (nn->next != NULL) { + nn = nn->next; + break; + } + } + + /* Add the default argument, if needed. */ + nch = n->child; + if (nch == NULL && nn != NULL && nn->child->type == ROFFT_TEXT) { + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->line, n->pos, n->next->child->string); + nch = mdoc->last; + nch->flags |= NODE_NOSRC; + mdoc->last = n; + } + + /* Validate the first argument. */ + if (nch == NULL || *nch->string == '\0') + mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg"); + if (nch == NULL) { + roff_node_delete(mdoc, n); + return; + } + len = strcspn(nch->string, " \t"); + if (nch->string[len] != '\0') + mandoc_msg(MANDOCERR_TG_SPC, nch->line, nch->pos + len + 1, + "Tg %s", nch->string); + + /* Keep only the first argument. */ + if (nch->next != NULL) { + mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line, + nch->next->pos, "Tg ... %s", nch->next->string); + while (nch->next != NULL) + roff_node_delete(mdoc, nch->next); + } + + /* Drop the macro if the first argument is invalid. */ + if (len == 0 || nch->string[len] != '\0') { + roff_node_delete(mdoc, n); + return; + } + + /* By default, write a element. */ + n->flags |= NODE_ID; + if (nn == NULL) + return; + + /* Explicit tagging of specific macros. */ + switch (nn->tok) { + case MDOC_Sh: + case MDOC_Ss: + if (nn->head->flags & NODE_ID || nn->head->child == NULL) + break; + n->flags |= NODE_NOPRT; + nn->head->flags |= NODE_ID | NODE_HREF; + assert(nn->head->string == NULL); + nn->head->string = mandoc_strdup(nch->string); + break; + default: + break; + } + if (n->flags & NODE_NOPRT) + n->flags &= ~NODE_ID; +} + +static void post_obsolete(POST_ARGS) { struct roff_node *n; @@ -1188,11 +1262,17 @@ post_fname(POST_ARGS) size_t pos; n = mdoc->last->child; - pos = strcspn(n->string, "()"); - cp = n->string + pos; - if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) - mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, - "%s", n->string); + cp = n->string; + if (*cp == '(') { + if (cp[strlen(cp + 1)] == ')') + return; + pos = 0; + } else { + pos = strcspn(cp, "()"); + if (cp[pos] == '\0') + return; + } + mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, "%s", cp); } static void @@ -1583,7 +1663,7 @@ post_it(POST_ARGS) mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos, "%d columns, %d cells", cols, i); else if (nit->head->next->child != NULL && - nit->head->next->child->line > nit->line) + nit->head->next->child->flags & NODE_LINE) mandoc_msg(MANDOCERR_IT_NOARG, nit->line, nit->pos, "Bl -column It"); break; @@ -1719,8 +1799,7 @@ post_bl_head(POST_ARGS) static void post_bl(POST_ARGS) { - struct roff_node *nparent, *nprev; /* of the Bl block */ - struct roff_node *nblock, *nbody; /* of the Bl */ + struct roff_node *nbody; /* of the Bl */ struct roff_node *nchild, *nnext; /* of the Bl body */ const char *prev_Er; int order; @@ -1741,88 +1820,73 @@ post_bl(POST_ARGS) if (nbody->end != ENDBODY_NOT) return; - nchild = nbody->child; - if (nchild == NULL) { - mandoc_msg(MANDOCERR_BLK_EMPTY, - nbody->line, nbody->pos, "Bl"); - return; + /* + * Up to the first item, move nodes before the list, + * but leave transparent nodes where they are + * if they precede an item. + * The next non-transparent node is kept in nchild. + * It only needs to be updated after a non-transparent + * node was moved out, and at the very beginning + * when no node at all was moved yet. + */ + + nchild = mdoc->last; + for (;;) { + if (nchild == mdoc->last) + nchild = roff_node_child(nbody); + if (nchild == NULL) { + mdoc->last = nbody; + mandoc_msg(MANDOCERR_BLK_EMPTY, + nbody->line, nbody->pos, "Bl"); + return; + } + if (nchild->tok == MDOC_It) { + mdoc->last = nbody; + break; + } + mandoc_msg(MANDOCERR_BL_MOVE, nbody->child->line, + nbody->child->pos, "%s", roff_name[nbody->child->tok]); + if (nbody->parent->prev == NULL) { + mdoc->last = nbody->parent->parent; + mdoc->next = ROFF_NEXT_CHILD; + } else { + mdoc->last = nbody->parent->prev; + mdoc->next = ROFF_NEXT_SIBLING; + } + roff_node_relink(mdoc, nbody->child); } + + /* + * We have reached the first item, + * so moving nodes out is no longer possible. + * But in .Bl -column, the first rows may be implicit, + * that is, they may not start with .It macros. + * Such rows may be followed by nodes generated on the + * roff level, for example .TS. + * Wrap such roff nodes into an implicit row. + */ + while (nchild != NULL) { - nnext = nchild->next; - if (nchild->tok == MDOC_It || - (nchild->tok == MDOC_Sm && - nnext != NULL && nnext->tok == MDOC_It)) { - nchild = nnext; + if (nchild->tok == MDOC_It) { + nchild = roff_node_next(nchild); continue; } - - /* - * In .Bl -column, the first rows may be implicit, - * that is, they may not start with .It macros. - * Such rows may be followed by nodes generated on the - * roff level, for example .TS, which cannot be moved - * out of the list. In that case, wrap such roff nodes - * into an implicit row. - */ - - if (nchild->prev != NULL) { - mdoc->last = nchild; + nnext = nchild->next; + mdoc->last = nchild->prev; + mdoc->next = ROFF_NEXT_SIBLING; + roff_block_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); + roff_head_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); + mdoc->next = ROFF_NEXT_SIBLING; + roff_body_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); + while (nchild->tok != MDOC_It) { + roff_node_relink(mdoc, nchild); + if (nnext == NULL) + break; + nchild = nnext; + nnext = nchild->next; mdoc->next = ROFF_NEXT_SIBLING; - roff_block_alloc(mdoc, nchild->line, - nchild->pos, MDOC_It); - roff_head_alloc(mdoc, nchild->line, - nchild->pos, MDOC_It); - mdoc->next = ROFF_NEXT_SIBLING; - roff_body_alloc(mdoc, nchild->line, - nchild->pos, MDOC_It); - while (nchild->tok != MDOC_It) { - roff_node_relink(mdoc, nchild); - if ((nchild = nnext) == NULL) - break; - nnext = nchild->next; - mdoc->next = ROFF_NEXT_SIBLING; - } - mdoc->last = nbody; - continue; } - - mandoc_msg(MANDOCERR_BL_MOVE, nchild->line, nchild->pos, - "%s", roff_name[nchild->tok]); - - /* - * Move the node out of the Bl block. - * First, collect all required node pointers. - */ - - nblock = nbody->parent; - nprev = nblock->prev; - nparent = nblock->parent; - - /* - * Unlink this child. - */ - - nbody->child = nnext; - if (nnext == NULL) - nbody->last = NULL; - else - nnext->prev = NULL; - - /* - * Relink this child. - */ - - nchild->parent = nparent; - nchild->prev = nprev; - nchild->next = nblock; - - nblock->prev = nchild; - if (nprev == NULL) - nparent->child = nchild; - else - nprev->next = nchild; - - nchild = nnext; + mdoc->last = nbody; } if (mdoc->meta.os_e != MANDOC_OS_NETBSD) @@ -1900,35 +1964,12 @@ post_sm(POST_ARGS) static void post_root(POST_ARGS) { - const char *openbsd_arch[] = { - "alpha", "amd64", "arm64", "armv7", "hppa", "i386", - "landisk", "loongson", "luna88k", "macppc", "mips64", - "octeon", "sgi", "socppc", "sparc64", NULL - }; - const char *netbsd_arch[] = { - "acorn26", "acorn32", "algor", "alpha", "amiga", - "arc", "atari", - "bebox", "cats", "cesfic", "cobalt", "dreamcast", - "emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5", - "hp300", "hpcarm", "hpcmips", "hpcsh", "hppa", - "i386", "ibmnws", "luna68k", - "mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc", - "netwinder", "news68k", "newsmips", "next68k", - "pc532", "playstation2", "pmax", "pmppc", "prep", - "sandpoint", "sbmips", "sgimips", "shark", - "sparc", "sparc64", "sun2", "sun3", - "vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL - }; - const char **arches[] = { NULL, netbsd_arch, openbsd_arch }; - struct roff_node *n; - const char **arch; /* Add missing prologue data. */ if (mdoc->meta.date == NULL) - mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : - mandoc_normdate(mdoc, NULL, 0, 0); + mdoc->meta.date = mandoc_normdate(NULL, NULL); if (mdoc->meta.title == NULL) { mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); @@ -1948,22 +1989,18 @@ post_root(POST_ARGS) "(OpenBSD)" : "(NetBSD)"); if (mdoc->meta.arch != NULL && - (arch = arches[mdoc->meta.os_e]) != NULL) { - while (*arch != NULL && strcmp(*arch, mdoc->meta.arch)) - arch++; - if (*arch == NULL) { - n = mdoc->meta.first->child; - while (n->tok != MDOC_Dt || - n->child == NULL || - n->child->next == NULL || - n->child->next->next == NULL) - n = n->next; - n = n->child->next->next; - mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, - "Dt ... %s %s", mdoc->meta.arch, - mdoc->meta.os_e == MANDOC_OS_OPENBSD ? - "(OpenBSD)" : "(NetBSD)"); - } + arch_valid(mdoc->meta.arch, mdoc->meta.os_e) == 0) { + n = mdoc->meta.first->child; + while (n->tok != MDOC_Dt || + n->child == NULL || + n->child->next == NULL || + n->child->next->next == NULL) + n = n->next; + n = n->child->next->next; + mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, + "Dt ... %s %s", mdoc->meta.arch, + mdoc->meta.os_e == MANDOC_OS_OPENBSD ? + "(OpenBSD)" : "(NetBSD)"); } /* Check that we begin with a proper `Sh'. */ @@ -2486,20 +2523,20 @@ post_ignpar(POST_ARGS) static void post_prevpar(POST_ARGS) { - struct roff_node *n; + struct roff_node *n, *np; n = mdoc->last; - if (NULL == n->prev) - return; if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) return; + if ((np = roff_node_prev(n)) == NULL) + return; /* * Don't allow `Pp' prior to a paragraph-type * block: `Pp' or non-compact `Bd' or `Bl'. */ - if (n->prev->tok != MDOC_Pp && n->prev->tok != ROFF_br) + if (np->tok != MDOC_Pp && np->tok != ROFF_br) return; if (n->tok == MDOC_Bl && n->norm->Bl.comp) return; @@ -2508,9 +2545,9 @@ post_prevpar(POST_ARGS) if (n->tok == MDOC_It && n->parent->norm->Bl.comp) return; - mandoc_msg(MANDOCERR_PAR_SKIP, n->prev->line, n->prev->pos, - "%s before %s", roff_name[n->prev->tok], roff_name[n->tok]); - roff_node_delete(mdoc, n->prev); + mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, + "%s before %s", roff_name[np->tok], roff_name[n->tok]); + roff_node_delete(mdoc, np); } static void @@ -2530,7 +2567,6 @@ static void post_dd(POST_ARGS) { struct roff_node *n; - char *datestr; n = mdoc->last; n->flags |= NODE_NOPRT; @@ -2547,21 +2583,10 @@ post_dd(POST_ARGS) mandoc_msg(MANDOCERR_PROLOG_ORDER, n->line, n->pos, "Dd after Os"); - if (n->child == NULL || n->child->string[0] == '\0') { - mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : - mandoc_normdate(mdoc, NULL, n->line, n->pos); - return; - } - - datestr = NULL; - deroff(&datestr, n); - if (mdoc->quick) - mdoc->meta.date = datestr; - else { - mdoc->meta.date = mandoc_normdate(mdoc, - datestr, n->line, n->pos); - free(datestr); - } + if (mdoc->quick && n != NULL) + mdoc->meta.date = mandoc_strdup(""); + else + mdoc->meta.date = mandoc_normdate(n->child, n); } static void