=================================================================== RCS file: /cvs/mandoc/mdoc_validate.c,v retrieving revision 1.345 retrieving revision 1.354 diff -u -p -r1.345 -r1.354 --- mandoc/mdoc_validate.c 2017/06/29 15:22:17 1.345 +++ mandoc/mdoc_validate.c 2018/02/06 16:29:57 1.354 @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.345 2017/06/29 15:22:17 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.354 2018/02/06 16:29:57 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2017 Ingo Schwarze @@ -33,6 +33,7 @@ #include "mandoc_aux.h" #include "mandoc.h" +#include "mandoc_xr.h" #include "roff.h" #include "mdoc.h" #include "libmandoc.h" @@ -77,6 +78,7 @@ static void post_defaults(POST_ARGS); static void post_display(POST_ARGS); static void post_dd(POST_ARGS); static void post_delim(POST_ARGS); +static void post_delim_nb(POST_ARGS); static void post_dt(POST_ARGS); static void post_en(POST_ARGS); static void post_es(POST_ARGS); @@ -108,6 +110,7 @@ static void post_sh_authors(POST_ARGS); 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_useless(POST_ARGS); static void post_xr(POST_ARGS); static void post_xx(POST_ARGS); @@ -126,33 +129,33 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] post_bl, /* Bl */ NULL, /* El */ post_it, /* It */ - post_delim, /* Ad */ + post_delim_nb, /* Ad */ post_an, /* An */ NULL, /* Ap */ post_defaults, /* Ar */ NULL, /* Cd */ - post_delim, /* Cm */ - post_delim, /* Dv */ - post_delim, /* Er */ - post_delim, /* Ev */ + post_delim_nb, /* Cm */ + post_delim_nb, /* Dv */ + post_delim_nb, /* Er */ + post_delim_nb, /* Ev */ post_ex, /* Ex */ post_fa, /* Fa */ NULL, /* Fd */ - post_delim, /* Fl */ + post_delim_nb, /* Fl */ post_fn, /* Fn */ - post_delim, /* Ft */ - post_delim, /* Ic */ - post_delim, /* In */ + post_delim_nb, /* Ft */ + post_delim_nb, /* Ic */ + post_delim_nb, /* In */ post_defaults, /* Li */ post_nd, /* Nd */ post_nm, /* Nm */ - post_delim, /* Op */ + post_delim_nb, /* Op */ post_obsolete, /* Ot */ post_defaults, /* Pa */ post_rv, /* Rv */ post_st, /* St */ - post_delim, /* Va */ - post_delim, /* Vt */ + post_delim_nb, /* Va */ + post_delim_nb, /* Vt */ post_xr, /* Xr */ NULL, /* %A */ post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ @@ -166,12 +169,12 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ NULL, /* %V */ NULL, /* Ac */ - post_delim, /* Ao */ - post_delim, /* Aq */ + NULL, /* Ao */ + post_delim_nb, /* Aq */ post_at, /* At */ NULL, /* Bc */ post_bf, /* Bf */ - post_delim, /* Bo */ + NULL, /* Bo */ NULL, /* Bq */ post_xx, /* Bsx */ post_bx, /* Bx */ @@ -181,37 +184,37 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] NULL, /* Dq */ NULL, /* Ec */ NULL, /* Ef */ - post_delim, /* Em */ + post_delim_nb, /* Em */ NULL, /* Eo */ post_xx, /* Fx */ - post_delim, /* Ms */ + post_delim_nb, /* Ms */ NULL, /* No */ post_ns, /* Ns */ post_xx, /* Nx */ post_xx, /* Ox */ NULL, /* Pc */ NULL, /* Pf */ - post_delim, /* Po */ - post_delim, /* Pq */ + NULL, /* Po */ + post_delim_nb, /* Pq */ NULL, /* Qc */ - post_delim, /* Ql */ - post_delim, /* Qo */ - post_delim, /* Qq */ + post_delim_nb, /* Ql */ + NULL, /* Qo */ + post_delim_nb, /* Qq */ NULL, /* Re */ post_rs, /* Rs */ NULL, /* Sc */ - post_delim, /* So */ - post_delim, /* Sq */ + NULL, /* So */ + post_delim_nb, /* Sq */ post_sm, /* Sm */ - post_hyph, /* Sx */ - post_delim, /* Sy */ + post_sx, /* Sx */ + post_delim_nb, /* Sy */ post_useless, /* Tn */ post_xx, /* Ux */ NULL, /* Xc */ NULL, /* Xo */ post_fo, /* Fo */ NULL, /* Fc */ - post_delim, /* Oo */ + NULL, /* Oo */ NULL, /* Oc */ post_bk, /* Bk */ NULL, /* Ek */ @@ -221,10 +224,10 @@ static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] post_eoln, /* Ud */ post_lb, /* Lb */ post_par, /* Lp */ - post_delim, /* Lk */ + post_delim_nb, /* Lk */ post_defaults, /* Mt */ - post_delim, /* Brq */ - post_delim, /* Bro */ + post_delim_nb, /* Brq */ + NULL, /* Bro */ NULL, /* Brc */ NULL, /* %C */ post_es, /* Es */ @@ -430,6 +433,34 @@ static void post_delim(POST_ARGS) { const struct roff_node *nch; + const char *lc; + enum mdelim delim; + enum roff_tok tok; + + tok = mdoc->last->tok; + nch = mdoc->last->last; + if (nch == NULL || nch->type != ROFFT_TEXT) + return; + lc = strchr(nch->string, '\0') - 1; + if (lc < nch->string) + return; + delim = mdoc_isdelim(lc); + if (delim == DELIM_NONE || delim == DELIM_OPEN) + return; + if (*lc == ')' && (tok == MDOC_Nd || tok == MDOC_Sh || + tok == MDOC_Ss || tok == MDOC_Fo)) + return; + + mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, + nch->line, nch->pos + (lc - nch->string), + "%s%s %s", roff_name[tok], + nch == mdoc->last->child ? "" : " ...", nch->string); +} + +static void +post_delim_nb(POST_ARGS) +{ + const struct roff_node *nch; const char *lc, *cp; int nw; enum mdelim delim; @@ -499,8 +530,7 @@ post_delim(POST_ARGS) /* At least three alphabetic words with a sentence ending. */ if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || - tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq || - tok == MDOC_Sy)) { + tok == MDOC_Li || tok == MDOC_Pq || tok == MDOC_Sy)) { nw = 0; for (cp = lc - 1; cp >= nch->string; cp--) { if (*cp == ' ') { @@ -515,7 +545,7 @@ post_delim(POST_ARGS) } } - mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, + mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse, nch->line, nch->pos + (lc - nch->string), "%s%s %s", roff_name[tok], nch == mdoc->last->child ? "" : " ...", nch->string); @@ -669,7 +699,7 @@ post_bl_norm(POST_ARGS) switch (n->norm->Bl.type) { case LIST_tag: - if (NULL == n->norm->Bl.width) + if (n->norm->Bl.width == NULL) mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, n->line, n->pos, "Bl -tag"); break; @@ -678,19 +708,20 @@ post_bl_norm(POST_ARGS) case LIST_ohang: case LIST_inset: case LIST_item: - if (n->norm->Bl.width) + if (n->norm->Bl.width != NULL) mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, wa->line, wa->pos, "Bl -%s", mdoc_argnames[mdoclt]); + n->norm->Bl.width = NULL; break; case LIST_bullet: case LIST_dash: case LIST_hyphen: - if (NULL == n->norm->Bl.width) + if (n->norm->Bl.width == NULL) n->norm->Bl.width = "2n"; break; case LIST_enum: - if (NULL == n->norm->Bl.width) + if (n->norm->Bl.width == NULL) n->norm->Bl.width = "3n"; break; default: @@ -896,7 +927,7 @@ post_lb(POST_ARGS) struct roff_node *n; const char *p; - post_delim(mdoc); + post_delim_nb(mdoc); n = mdoc->last; assert(n->child->type == ROFFT_TEXT); @@ -967,6 +998,8 @@ post_std(POST_ARGS) { struct roff_node *n; + post_delim(mdoc); + n = mdoc->last; if (n->args && n->args->argc == 1) if (n->args->argv[0].arg == MDOC_Std) @@ -1134,7 +1167,8 @@ post_fo(POST_ARGS) "Fo ... %s", n->child->next->string); while (n->child != n->last) roff_node_delete(mdoc, n->last); - } + } else + post_delim(mdoc); post_fname(mdoc); } @@ -1158,7 +1192,7 @@ post_fa(POST_ARGS) break; } } - post_delim(mdoc); + post_delim_nb(mdoc); } static void @@ -1168,6 +1202,10 @@ post_nm(POST_ARGS) n = mdoc->last; + if (n->sec == SEC_NAME && n->child != NULL && + n->child->type == ROFFT_TEXT && mdoc->meta.msec != NULL) + mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1); + if (n->last != NULL && (n->last->tok == MDOC_Pp || n->last->tok == MDOC_Lp)) @@ -1181,11 +1219,18 @@ post_nm(POST_ARGS) mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, n->line, n->pos, "Nm"); - if (n->type == ROFFT_ELEM) + switch (n->type) { + case ROFFT_ELEM: + post_delim_nb(mdoc); + break; + case ROFFT_HEAD: post_delim(mdoc); + break; + default: + return; + } - if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || - (n->child != NULL && n->child->type == ROFFT_TEXT) || + if ((n->child != NULL && n->child->type == ROFFT_TEXT) || mdoc->meta.name == NULL) return; @@ -1199,7 +1244,6 @@ static void post_nd(POST_ARGS) { struct roff_node *n; - size_t sz; n = mdoc->last; @@ -1213,11 +1257,8 @@ post_nd(POST_ARGS) if (n->child == NULL) mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, n->line, n->pos, "Nd"); - else if (n->last->type == ROFFT_TEXT && - (sz = strlen(n->last->string)) != 0 && - n->last->string[sz - 1] == '.') - mandoc_msg(MANDOCERR_ND_DOT, mdoc->parse, - n->last->line, n->last->pos + sz - 1, NULL); + else + post_delim(mdoc); post_hyph(mdoc); } @@ -1275,7 +1316,7 @@ post_defaults(POST_ARGS) struct roff_node *nn; if (mdoc->last->child != NULL) { - post_delim(mdoc); + post_delim_nb(mdoc); return; } @@ -1350,7 +1391,7 @@ post_an(POST_ARGS) mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, np->line, np->pos, "An"); else - post_delim(mdoc); + post_delim_nb(mdoc); } else if (nch != NULL) mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, nch->line, nch->pos, "An ... %s", nch->string); @@ -1378,8 +1419,9 @@ post_xx(POST_ARGS) { struct roff_node *n; const char *os; + char *v; - post_delim(mdoc); + post_delim_nb(mdoc); n = mdoc->last; switch (n->tok) { @@ -1394,6 +1436,20 @@ post_xx(POST_ARGS) break; case MDOC_Nx: os = "NetBSD"; + if (n->child == NULL) + break; + v = n->child->string; + if ((v[0] != '0' && v[0] != '1') || v[1] != '.' || + v[2] < '0' || v[2] > '9' || + v[3] < 'a' || v[3] > 'z' || v[4] != '\0') + break; + n->child->flags |= NODE_NOPRT; + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->child->line, n->child->pos, v); + v = mdoc->last->string; + v[3] = toupper((unsigned char)v[3]); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; break; case MDOC_Ox: os = "OpenBSD"; @@ -1857,7 +1913,10 @@ post_root(POST_ARGS) arch++; if (*arch == NULL) { n = mdoc->first->child; - while (n->tok != MDOC_Dt) + 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_vmsg(MANDOCERR_ARCH_BAD, @@ -1871,7 +1930,7 @@ post_root(POST_ARGS) /* Check that we begin with a proper `Sh'. */ n = mdoc->first->child; - while (n != NULL && n->tok != TOKEN_NONE && + while (n != NULL && n->tok >= MDOC_Dd && mdoc_macros[n->tok].flags & MDOC_PROLOGUE) n = n->next; @@ -2008,6 +2067,13 @@ post_ns(POST_ARGS) } static void +post_sx(POST_ARGS) +{ + post_delim(mdoc); + post_hyph(mdoc); +} + +static void post_sh(POST_ARGS) { @@ -2336,9 +2402,15 @@ post_xr(POST_ARGS) if (nch->next == NULL) { mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, n->line, n->pos, "Xr %s", nch->string); - } else + } else { assert(nch->next == n->last); - post_delim(mdoc); + if(mandoc_xr_add(nch->next->string, nch->string, + nch->line, nch->pos)) + mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse, + nch->line, nch->pos, "Xr %s %s", + nch->string, nch->next->string); + } + post_delim_nb(mdoc); } static void @@ -2351,6 +2423,7 @@ post_ignpar(POST_ARGS) post_prevpar(mdoc); return; case ROFFT_HEAD: + post_delim(mdoc); post_hyph(mdoc); return; case ROFFT_BODY: @@ -2587,7 +2660,7 @@ post_bx(POST_ARGS) struct roff_node *n, *nch; const char *macro; - post_delim(mdoc); + post_delim_nb(mdoc); n = mdoc->last; nch = n->child; @@ -2652,6 +2725,8 @@ post_os(POST_ARGS) else if (mdoc->flags & MDOC_PBODY) mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, n->line, n->pos, "Os"); + + post_delim(mdoc); /* * Set the operating system by way of the `Os' macro.