version 1.337, 2017/06/11 19:37:01 |
version 1.359, 2018/08/01 13:46:15 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> |
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
|
|
|
|
#include "mandoc_aux.h" |
#include "mandoc_aux.h" |
#include "mandoc.h" |
#include "mandoc.h" |
|
#include "mandoc_xr.h" |
#include "roff.h" |
#include "roff.h" |
#include "mdoc.h" |
#include "mdoc.h" |
#include "libmandoc.h" |
#include "libmandoc.h" |
Line 52 enum check_ineq { |
|
Line 53 enum check_ineq { |
|
typedef void (*v_post)(POST_ARGS); |
typedef void (*v_post)(POST_ARGS); |
|
|
static int build_list(struct roff_man *, int); |
static int build_list(struct roff_man *, int); |
static void check_text(struct roff_man *, int, int, char *); |
|
static void check_argv(struct roff_man *, |
static void check_argv(struct roff_man *, |
struct roff_node *, struct mdoc_argv *); |
struct roff_node *, struct mdoc_argv *); |
static void check_args(struct roff_man *, struct roff_node *); |
static void check_args(struct roff_man *, struct roff_node *); |
|
static void check_text(struct roff_man *, int, int, char *); |
|
static void check_text_em(struct roff_man *, int, int, char *); |
static void check_toptext(struct roff_man *, int, int, const char *); |
static void check_toptext(struct roff_man *, int, int, const char *); |
static int child_an(const struct roff_node *); |
static int child_an(const struct roff_node *); |
static size_t macro2len(enum roff_tok); |
static size_t macro2len(enum roff_tok); |
static void rewrite_macro2len(struct roff_man *, char **); |
static void rewrite_macro2len(struct roff_man *, char **); |
|
static int similar(const char *, const char *); |
|
|
static void post_an(POST_ARGS); |
static void post_an(POST_ARGS); |
static void post_an_norm(POST_ARGS); |
static void post_an_norm(POST_ARGS); |
Line 76 static void post_defaults(POST_ARGS); |
|
Line 79 static void post_defaults(POST_ARGS); |
|
static void post_display(POST_ARGS); |
static void post_display(POST_ARGS); |
static void post_dd(POST_ARGS); |
static void post_dd(POST_ARGS); |
static void post_delim(POST_ARGS); |
static void post_delim(POST_ARGS); |
|
static void post_delim_nb(POST_ARGS); |
static void post_dt(POST_ARGS); |
static void post_dt(POST_ARGS); |
static void post_en(POST_ARGS); |
static void post_en(POST_ARGS); |
static void post_es(POST_ARGS); |
static void post_es(POST_ARGS); |
Line 107 static void post_sh_authors(POST_ARGS); |
|
Line 111 static void post_sh_authors(POST_ARGS); |
|
static void post_sm(POST_ARGS); |
static void post_sm(POST_ARGS); |
static void post_st(POST_ARGS); |
static void post_st(POST_ARGS); |
static void post_std(POST_ARGS); |
static void post_std(POST_ARGS); |
|
static void post_sx(POST_ARGS); |
static void post_useless(POST_ARGS); |
static void post_useless(POST_ARGS); |
static void post_xr(POST_ARGS); |
static void post_xr(POST_ARGS); |
static void post_xx(POST_ARGS); |
static void post_xx(POST_ARGS); |
Line 125 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 130 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
post_bl, /* Bl */ |
post_bl, /* Bl */ |
NULL, /* El */ |
NULL, /* El */ |
post_it, /* It */ |
post_it, /* It */ |
post_delim, /* Ad */ |
post_delim_nb, /* Ad */ |
post_an, /* An */ |
post_an, /* An */ |
NULL, /* Ap */ |
NULL, /* Ap */ |
post_defaults, /* Ar */ |
post_defaults, /* Ar */ |
NULL, /* Cd */ |
NULL, /* Cd */ |
post_delim, /* Cm */ |
post_delim_nb, /* Cm */ |
post_delim, /* Dv */ |
post_delim_nb, /* Dv */ |
post_delim, /* Er */ |
post_delim_nb, /* Er */ |
post_delim, /* Ev */ |
post_delim_nb, /* Ev */ |
post_ex, /* Ex */ |
post_ex, /* Ex */ |
post_fa, /* Fa */ |
post_fa, /* Fa */ |
NULL, /* Fd */ |
NULL, /* Fd */ |
post_delim, /* Fl */ |
post_delim_nb, /* Fl */ |
post_fn, /* Fn */ |
post_fn, /* Fn */ |
post_delim, /* Ft */ |
post_delim_nb, /* Ft */ |
post_delim, /* Ic */ |
post_delim_nb, /* Ic */ |
post_delim, /* In */ |
post_delim_nb, /* In */ |
post_defaults, /* Li */ |
post_defaults, /* Li */ |
post_nd, /* Nd */ |
post_nd, /* Nd */ |
post_nm, /* Nm */ |
post_nm, /* Nm */ |
post_delim, /* Op */ |
post_delim_nb, /* Op */ |
post_obsolete, /* Ot */ |
post_obsolete, /* Ot */ |
post_defaults, /* Pa */ |
post_defaults, /* Pa */ |
post_rv, /* Rv */ |
post_rv, /* Rv */ |
post_st, /* St */ |
post_st, /* St */ |
post_delim, /* Va */ |
post_delim_nb, /* Va */ |
post_delim, /* Vt */ |
post_delim_nb, /* Vt */ |
post_xr, /* Xr */ |
post_xr, /* Xr */ |
NULL, /* %A */ |
NULL, /* %A */ |
post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ |
post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ |
Line 165 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 170 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ |
post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ |
NULL, /* %V */ |
NULL, /* %V */ |
NULL, /* Ac */ |
NULL, /* Ac */ |
post_delim, /* Ao */ |
NULL, /* Ao */ |
post_delim, /* Aq */ |
post_delim_nb, /* Aq */ |
post_at, /* At */ |
post_at, /* At */ |
NULL, /* Bc */ |
NULL, /* Bc */ |
post_bf, /* Bf */ |
post_bf, /* Bf */ |
post_delim, /* Bo */ |
NULL, /* Bo */ |
NULL, /* Bq */ |
NULL, /* Bq */ |
post_xx, /* Bsx */ |
post_xx, /* Bsx */ |
post_bx, /* Bx */ |
post_bx, /* Bx */ |
Line 180 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 185 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
NULL, /* Dq */ |
NULL, /* Dq */ |
NULL, /* Ec */ |
NULL, /* Ec */ |
NULL, /* Ef */ |
NULL, /* Ef */ |
post_delim, /* Em */ |
post_delim_nb, /* Em */ |
NULL, /* Eo */ |
NULL, /* Eo */ |
post_xx, /* Fx */ |
post_xx, /* Fx */ |
post_delim, /* Ms */ |
post_delim_nb, /* Ms */ |
NULL, /* No */ |
NULL, /* No */ |
post_ns, /* Ns */ |
post_ns, /* Ns */ |
post_xx, /* Nx */ |
post_xx, /* Nx */ |
post_xx, /* Ox */ |
post_xx, /* Ox */ |
NULL, /* Pc */ |
NULL, /* Pc */ |
NULL, /* Pf */ |
NULL, /* Pf */ |
post_delim, /* Po */ |
NULL, /* Po */ |
post_delim, /* Pq */ |
post_delim_nb, /* Pq */ |
NULL, /* Qc */ |
NULL, /* Qc */ |
post_delim, /* Ql */ |
post_delim_nb, /* Ql */ |
post_delim, /* Qo */ |
NULL, /* Qo */ |
post_delim, /* Qq */ |
post_delim_nb, /* Qq */ |
NULL, /* Re */ |
NULL, /* Re */ |
post_rs, /* Rs */ |
post_rs, /* Rs */ |
NULL, /* Sc */ |
NULL, /* Sc */ |
post_delim, /* So */ |
NULL, /* So */ |
post_delim, /* Sq */ |
post_delim_nb, /* Sq */ |
post_sm, /* Sm */ |
post_sm, /* Sm */ |
post_hyph, /* Sx */ |
post_sx, /* Sx */ |
post_delim, /* Sy */ |
post_delim_nb, /* Sy */ |
post_useless, /* Tn */ |
post_useless, /* Tn */ |
post_xx, /* Ux */ |
post_xx, /* Ux */ |
NULL, /* Xc */ |
NULL, /* Xc */ |
NULL, /* Xo */ |
NULL, /* Xo */ |
post_fo, /* Fo */ |
post_fo, /* Fo */ |
NULL, /* Fc */ |
NULL, /* Fc */ |
post_delim, /* Oo */ |
NULL, /* Oo */ |
NULL, /* Oc */ |
NULL, /* Oc */ |
post_bk, /* Bk */ |
post_bk, /* Bk */ |
NULL, /* Ek */ |
NULL, /* Ek */ |
Line 220 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 225 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
post_eoln, /* Ud */ |
post_eoln, /* Ud */ |
post_lb, /* Lb */ |
post_lb, /* Lb */ |
post_par, /* Lp */ |
post_par, /* Lp */ |
post_delim, /* Lk */ |
post_delim_nb, /* Lk */ |
post_defaults, /* Mt */ |
post_defaults, /* Mt */ |
post_delim, /* Brq */ |
post_delim_nb, /* Brq */ |
post_delim, /* Bro */ |
NULL, /* Bro */ |
NULL, /* Brc */ |
NULL, /* Brc */ |
NULL, /* %C */ |
NULL, /* %C */ |
post_es, /* Es */ |
post_es, /* Es */ |
Line 284 static const char * const secnames[SEC__MAX] = { |
|
Line 289 static const char * const secnames[SEC__MAX] = { |
|
void |
void |
mdoc_node_validate(struct roff_man *mdoc) |
mdoc_node_validate(struct roff_man *mdoc) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n, *np; |
const v_post *p; |
const v_post *p; |
|
|
n = mdoc->last; |
n = mdoc->last; |
Line 301 mdoc_node_validate(struct roff_man *mdoc) |
|
Line 306 mdoc_node_validate(struct roff_man *mdoc) |
|
mdoc->next = ROFF_NEXT_SIBLING; |
mdoc->next = ROFF_NEXT_SIBLING; |
switch (n->type) { |
switch (n->type) { |
case ROFFT_TEXT: |
case ROFFT_TEXT: |
|
np = n->parent; |
if (n->sec != SEC_SYNOPSIS || |
if (n->sec != SEC_SYNOPSIS || |
(n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) |
(np->tok != MDOC_Cd && np->tok != MDOC_Fd)) |
check_text(mdoc, n->line, n->pos, n->string); |
check_text(mdoc, n->line, n->pos, n->string); |
if (n->parent->tok == MDOC_It || |
if (np->tok != MDOC_Ql && np->tok != MDOC_Dl && |
(n->parent->type == ROFFT_BODY && |
(np->tok != MDOC_Bd || |
(n->parent->tok == MDOC_Sh || |
(mdoc->flags & MDOC_LITERAL) == 0) && |
n->parent->tok == MDOC_Ss))) |
(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); |
|
if (np->tok == MDOC_It || (np->type == ROFFT_BODY && |
|
(np->tok == MDOC_Sh || np->tok == MDOC_Ss))) |
check_toptext(mdoc, n->line, n->pos, n->string); |
check_toptext(mdoc, n->line, n->pos, n->string); |
break; |
break; |
|
case ROFFT_COMMENT: |
case ROFFT_EQN: |
case ROFFT_EQN: |
case ROFFT_TBL: |
case ROFFT_TBL: |
break; |
break; |
Line 391 check_text(struct roff_man *mdoc, int ln, int pos, cha |
|
Line 402 check_text(struct roff_man *mdoc, int ln, int pos, cha |
|
} |
} |
|
|
static void |
static void |
|
check_text_em(struct roff_man *mdoc, int ln, int pos, char *p) |
|
{ |
|
const struct roff_node *np, *nn; |
|
char *cp; |
|
|
|
np = mdoc->last->prev; |
|
nn = mdoc->last->next; |
|
|
|
/* Look for em-dashes wrongly encoded as "--". */ |
|
|
|
for (cp = p; *cp != '\0'; cp++) { |
|
if (cp[0] != '-' || cp[1] != '-') |
|
continue; |
|
cp++; |
|
|
|
/* Skip input sequences of more than two '-'. */ |
|
|
|
if (cp[1] == '-') { |
|
while (cp[1] == '-') |
|
cp++; |
|
continue; |
|
} |
|
|
|
/* Skip "--" directly attached to something else. */ |
|
|
|
if ((cp - p > 1 && cp[-2] != ' ') || |
|
(cp[1] != '\0' && cp[1] != ' ')) |
|
continue; |
|
|
|
/* Require a letter right before or right afterwards. */ |
|
|
|
if ((cp - p > 2 ? |
|
isalpha((unsigned char)cp[-3]) : |
|
np != NULL && |
|
np->type == ROFFT_TEXT && |
|
np->string != '\0' && |
|
isalpha((unsigned char)np->string[ |
|
strlen(np->string) - 1])) || |
|
(cp[1] != '\0' && cp[2] != '\0' ? |
|
isalpha((unsigned char)cp[2]) : |
|
nn != NULL && |
|
nn->type == ROFFT_TEXT && |
|
nn->string != '\0' && |
|
isalpha((unsigned char)*nn->string))) { |
|
mandoc_msg(MANDOCERR_DASHDASH, mdoc->parse, |
|
ln, pos + (int)(cp - p) - 1, NULL); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
static void |
check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) |
check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) |
{ |
{ |
const char *cp, *cpr; |
const char *cp, *cpr; |
|
|
post_delim(POST_ARGS) |
post_delim(POST_ARGS) |
{ |
{ |
const struct roff_node *nch; |
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; |
const char *lc, *cp; |
int nw; |
int nw; |
enum mdelim delim; |
enum mdelim delim; |
Line 498 post_delim(POST_ARGS) |
|
Line 589 post_delim(POST_ARGS) |
|
|
|
/* At least three alphabetic words with a sentence ending. */ |
/* At least three alphabetic words with a sentence ending. */ |
if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || |
if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || |
tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq || |
tok == MDOC_Li || tok == MDOC_Pq || tok == MDOC_Sy)) { |
tok == MDOC_Sy)) { |
|
nw = 0; |
nw = 0; |
for (cp = lc - 1; cp >= nch->string; cp--) { |
for (cp = lc - 1; cp >= nch->string; cp--) { |
if (*cp == ' ') { |
if (*cp == ' ') { |
Line 514 post_delim(POST_ARGS) |
|
Line 604 post_delim(POST_ARGS) |
|
} |
} |
} |
} |
|
|
mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, |
mandoc_vmsg(MANDOCERR_DELIM_NB, mdoc->parse, |
nch->line, nch->pos + (lc - nch->string), |
nch->line, nch->pos + (lc - nch->string), |
"%s%s %s", roff_name[tok], |
"%s%s %s", roff_name[tok], |
nch == mdoc->last->child ? "" : " ...", nch->string); |
nch == mdoc->last->child ? "" : " ...", nch->string); |
Line 668 post_bl_norm(POST_ARGS) |
|
Line 758 post_bl_norm(POST_ARGS) |
|
|
|
switch (n->norm->Bl.type) { |
switch (n->norm->Bl.type) { |
case LIST_tag: |
case LIST_tag: |
if (NULL == n->norm->Bl.width) |
if (n->norm->Bl.width == NULL) |
mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, |
mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse, |
n->line, n->pos, "Bl -tag"); |
n->line, n->pos, "Bl -tag"); |
break; |
break; |
Line 677 post_bl_norm(POST_ARGS) |
|
Line 767 post_bl_norm(POST_ARGS) |
|
case LIST_ohang: |
case LIST_ohang: |
case LIST_inset: |
case LIST_inset: |
case LIST_item: |
case LIST_item: |
if (n->norm->Bl.width) |
if (n->norm->Bl.width != NULL) |
mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, |
mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse, |
wa->line, wa->pos, "Bl -%s", |
wa->line, wa->pos, "Bl -%s", |
mdoc_argnames[mdoclt]); |
mdoc_argnames[mdoclt]); |
|
n->norm->Bl.width = NULL; |
break; |
break; |
case LIST_bullet: |
case LIST_bullet: |
case LIST_dash: |
case LIST_dash: |
case LIST_hyphen: |
case LIST_hyphen: |
if (NULL == n->norm->Bl.width) |
if (n->norm->Bl.width == NULL) |
n->norm->Bl.width = "2n"; |
n->norm->Bl.width = "2n"; |
break; |
break; |
case LIST_enum: |
case LIST_enum: |
if (NULL == n->norm->Bl.width) |
if (n->norm->Bl.width == NULL) |
n->norm->Bl.width = "3n"; |
n->norm->Bl.width = "3n"; |
break; |
break; |
default: |
default: |
Line 895 post_lb(POST_ARGS) |
|
Line 986 post_lb(POST_ARGS) |
|
struct roff_node *n; |
struct roff_node *n; |
const char *p; |
const char *p; |
|
|
post_delim(mdoc); |
post_delim_nb(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
assert(n->child->type == ROFFT_TEXT); |
assert(n->child->type == ROFFT_TEXT); |
Line 914 post_lb(POST_ARGS) |
|
Line 1005 post_lb(POST_ARGS) |
|
|
|
roff_word_alloc(mdoc, n->line, n->pos, "library"); |
roff_word_alloc(mdoc, n->line, n->pos, "library"); |
mdoc->last->flags = NODE_NOSRC; |
mdoc->last->flags = NODE_NOSRC; |
roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); |
roff_word_alloc(mdoc, n->line, n->pos, "\\(lq"); |
mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; |
mdoc->last->flags = NODE_DELIMO | NODE_NOSRC; |
mdoc->last = mdoc->last->next; |
mdoc->last = mdoc->last->next; |
roff_word_alloc(mdoc, n->line, n->pos, "\\(Rq"); |
roff_word_alloc(mdoc, n->line, n->pos, "\\(rq"); |
mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; |
mdoc->last->flags = NODE_DELIMC | NODE_NOSRC; |
mdoc->last = n; |
mdoc->last = n; |
} |
} |
Line 966 post_std(POST_ARGS) |
|
Line 1057 post_std(POST_ARGS) |
|
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
|
|
|
post_delim(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
if (n->args && n->args->argc == 1) |
if (n->args && n->args->argc == 1) |
if (n->args->argv[0].arg == MDOC_Std) |
if (n->args->argv[0].arg == MDOC_Std) |
Line 1133 post_fo(POST_ARGS) |
|
Line 1226 post_fo(POST_ARGS) |
|
"Fo ... %s", n->child->next->string); |
"Fo ... %s", n->child->next->string); |
while (n->child != n->last) |
while (n->child != n->last) |
roff_node_delete(mdoc, n->last); |
roff_node_delete(mdoc, n->last); |
} |
} else |
|
post_delim(mdoc); |
|
|
post_fname(mdoc); |
post_fname(mdoc); |
} |
} |
Line 1157 post_fa(POST_ARGS) |
|
Line 1251 post_fa(POST_ARGS) |
|
break; |
break; |
} |
} |
} |
} |
post_delim(mdoc); |
post_delim_nb(mdoc); |
} |
} |
|
|
static void |
static void |
Line 1167 post_nm(POST_ARGS) |
|
Line 1261 post_nm(POST_ARGS) |
|
|
|
n = mdoc->last; |
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 && |
if (n->last != NULL && |
(n->last->tok == MDOC_Pp || |
(n->last->tok == MDOC_Pp || |
n->last->tok == MDOC_Lp)) |
n->last->tok == MDOC_Lp)) |
Line 1180 post_nm(POST_ARGS) |
|
Line 1278 post_nm(POST_ARGS) |
|
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, |
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, |
n->line, n->pos, "Nm"); |
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); |
post_delim(mdoc); |
|
break; |
|
default: |
|
return; |
|
} |
|
|
if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || |
if ((n->child != NULL && n->child->type == ROFFT_TEXT) || |
(n->child != NULL && n->child->type == ROFFT_TEXT) || |
|
mdoc->meta.name == NULL) |
mdoc->meta.name == NULL) |
return; |
return; |
|
|
|
|
post_nd(POST_ARGS) |
post_nd(POST_ARGS) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
size_t sz; |
|
|
|
n = mdoc->last; |
n = mdoc->last; |
|
|
Line 1212 post_nd(POST_ARGS) |
|
Line 1316 post_nd(POST_ARGS) |
|
if (n->child == NULL) |
if (n->child == NULL) |
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, |
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, |
n->line, n->pos, "Nd"); |
n->line, n->pos, "Nd"); |
else if (n->last->type == ROFFT_TEXT && |
else |
(sz = strlen(n->last->string)) != 0 && |
post_delim(mdoc); |
n->last->string[sz - 1] == '.') |
|
mandoc_msg(MANDOCERR_ND_DOT, mdoc->parse, |
|
n->last->line, n->last->pos + sz - 1, NULL); |
|
|
|
post_hyph(mdoc); |
post_hyph(mdoc); |
} |
} |
Line 1274 post_defaults(POST_ARGS) |
|
Line 1375 post_defaults(POST_ARGS) |
|
struct roff_node *nn; |
struct roff_node *nn; |
|
|
if (mdoc->last->child != NULL) { |
if (mdoc->last->child != NULL) { |
post_delim(mdoc); |
post_delim_nb(mdoc); |
return; |
return; |
} |
} |
|
|
Line 1349 post_an(POST_ARGS) |
|
Line 1450 post_an(POST_ARGS) |
|
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, |
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, |
np->line, np->pos, "An"); |
np->line, np->pos, "An"); |
else |
else |
post_delim(mdoc); |
post_delim_nb(mdoc); |
} else if (nch != NULL) |
} else if (nch != NULL) |
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, |
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, |
nch->line, nch->pos, "An ... %s", nch->string); |
nch->line, nch->pos, "An ... %s", nch->string); |
Line 1377 post_xx(POST_ARGS) |
|
Line 1478 post_xx(POST_ARGS) |
|
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
const char *os; |
const char *os; |
|
char *v; |
|
|
post_delim(mdoc); |
post_delim_nb(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
switch (n->tok) { |
switch (n->tok) { |
Line 1393 post_xx(POST_ARGS) |
|
Line 1495 post_xx(POST_ARGS) |
|
break; |
break; |
case MDOC_Nx: |
case MDOC_Nx: |
os = "NetBSD"; |
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; |
break; |
case MDOC_Ox: |
case MDOC_Ox: |
os = "OpenBSD"; |
os = "OpenBSD"; |
Line 1459 post_it(POST_ARGS) |
|
Line 1575 post_it(POST_ARGS) |
|
|
|
assert(nit->head->child == NULL); |
assert(nit->head->child == NULL); |
|
|
i = 0; |
if (nit->head->next->child == NULL && |
for (nch = nit->child; nch != NULL; nch = nch->next) |
nit->head->next->next == NULL) { |
if (nch->type == ROFFT_BODY) |
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, |
i++; |
nit->line, nit->pos, "It"); |
|
roff_node_delete(mdoc, nit); |
|
break; |
|
} |
|
|
|
i = 0; |
|
for (nch = nit->child; nch != NULL; nch = nch->next) { |
|
if (nch->type != ROFFT_BODY) |
|
continue; |
|
if (i++ && nch->flags & NODE_LINE) |
|
mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse, |
|
nch->line, nch->pos, "Ta"); |
|
} |
if (i < cols || i > cols + 1) |
if (i < cols || i > cols + 1) |
mandoc_vmsg(MANDOCERR_BL_COL, |
mandoc_vmsg(MANDOCERR_BL_COL, |
mdoc->parse, nit->line, nit->pos, |
mdoc->parse, nit->line, nit->pos, |
"%d columns, %d cells", cols, i); |
"%d columns, %d cells", cols, i); |
|
else if (nit->head->next->child != NULL && |
|
nit->head->next->child->line > nit->line) |
|
mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse, |
|
nit->line, nit->pos, "Bl -column It"); |
break; |
break; |
default: |
default: |
abort(); |
abort(); |
Line 1709 post_bl(POST_ARGS) |
|
Line 1840 post_bl(POST_ARGS) |
|
nchild = nnext; |
nchild = nnext; |
} |
} |
|
|
if (mdoc->meta.os_e != MDOC_OS_NETBSD) |
if (mdoc->meta.os_e != MANDOC_OS_NETBSD) |
return; |
return; |
|
|
prev_Er = NULL; |
prev_Er = NULL; |
Line 1728 post_bl(POST_ARGS) |
|
Line 1859 post_bl(POST_ARGS) |
|
if (order > 0) |
if (order > 0) |
mandoc_vmsg(MANDOCERR_ER_ORDER, |
mandoc_vmsg(MANDOCERR_ER_ORDER, |
mdoc->parse, nnext->line, nnext->pos, |
mdoc->parse, nnext->line, nnext->pos, |
"Er %s %s", prev_Er, nnext->string); |
"Er %s %s (NetBSD)", |
|
prev_Er, nnext->string); |
else if (order == 0) |
else if (order == 0) |
mandoc_vmsg(MANDOCERR_ER_REP, |
mandoc_vmsg(MANDOCERR_ER_REP, |
mdoc->parse, nnext->line, nnext->pos, |
mdoc->parse, nnext->line, nnext->pos, |
"Er %s", prev_Er); |
"Er %s (NetBSD)", prev_Er); |
} |
} |
prev_Er = nnext->string; |
prev_Er = nnext->string; |
} |
} |
Line 1785 post_sm(POST_ARGS) |
|
Line 1917 post_sm(POST_ARGS) |
|
static void |
static void |
post_root(POST_ARGS) |
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; |
struct roff_node *n; |
|
const char **arch; |
|
|
/* Add missing prologue data. */ |
/* Add missing prologue data. */ |
|
|
Line 1806 post_root(POST_ARGS) |
|
Line 1960 post_root(POST_ARGS) |
|
mandoc_msg(MANDOCERR_OS_MISSING, |
mandoc_msg(MANDOCERR_OS_MISSING, |
mdoc->parse, 0, 0, NULL); |
mdoc->parse, 0, 0, NULL); |
mdoc->meta.os = mandoc_strdup(""); |
mdoc->meta.os = mandoc_strdup(""); |
|
} else if (mdoc->meta.os_e && |
|
(mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) |
|
mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0, |
|
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
|
"(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->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_vmsg(MANDOCERR_ARCH_BAD, |
|
mdoc->parse, 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'. */ |
/* Check that we begin with a proper `Sh'. */ |
|
|
n = mdoc->first->child; |
n = mdoc->first->child; |
while (n != NULL && n->tok != TOKEN_NONE && |
while (n != NULL && |
mdoc_macros[n->tok].flags & MDOC_PROLOGUE) |
(n->type == ROFFT_COMMENT || |
|
(n->tok >= MDOC_Dd && |
|
mdoc_macros[n->tok].flags & MDOC_PROLOGUE))) |
n = n->next; |
n = n->next; |
|
|
if (n == NULL) |
if (n == NULL) |
Line 1938 post_hyph(POST_ARGS) |
|
Line 2118 post_hyph(POST_ARGS) |
|
static void |
static void |
post_ns(POST_ARGS) |
post_ns(POST_ARGS) |
{ |
{ |
|
struct roff_node *n; |
|
|
if (mdoc->last->flags & NODE_LINE) |
n = mdoc->last; |
|
if (n->flags & NODE_LINE || |
|
(n->next != NULL && n->next->flags & NODE_DELIMC)) |
mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, |
mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, |
mdoc->last->line, mdoc->last->pos, NULL); |
n->line, n->pos, NULL); |
} |
} |
|
|
static void |
static void |
|
post_sx(POST_ARGS) |
|
{ |
|
post_delim(mdoc); |
|
post_hyph(mdoc); |
|
} |
|
|
|
static void |
post_sh(POST_ARGS) |
post_sh(POST_ARGS) |
{ |
{ |
|
|
Line 2104 post_sh_authors(POST_ARGS) |
|
Line 2294 post_sh_authors(POST_ARGS) |
|
mdoc->last->line, mdoc->last->pos, NULL); |
mdoc->last->line, mdoc->last->pos, NULL); |
} |
} |
|
|
|
/* |
|
* Return an upper bound for the string distance (allowing |
|
* transpositions). Not a full Levenshtein implementation |
|
* because Levenshtein is quadratic in the string length |
|
* and this function is called for every standard name, |
|
* so the check for each custom name would be cubic. |
|
* The following crude heuristics is linear, resulting |
|
* in quadratic behaviour for checking one custom name, |
|
* which does not cause measurable slowdown. |
|
*/ |
|
static int |
|
similar(const char *s1, const char *s2) |
|
{ |
|
const int maxdist = 3; |
|
int dist = 0; |
|
|
|
while (s1[0] != '\0' && s2[0] != '\0') { |
|
if (s1[0] == s2[0]) { |
|
s1++; |
|
s2++; |
|
continue; |
|
} |
|
if (++dist > maxdist) |
|
return INT_MAX; |
|
if (s1[1] == s2[1]) { /* replacement */ |
|
s1++; |
|
s2++; |
|
} else if (s1[0] == s2[1] && s1[1] == s2[0]) { |
|
s1 += 2; /* transposition */ |
|
s2 += 2; |
|
} else if (s1[0] == s2[1]) /* insertion */ |
|
s2++; |
|
else if (s1[1] == s2[0]) /* deletion */ |
|
s1++; |
|
else |
|
return INT_MAX; |
|
} |
|
dist += strlen(s1) + strlen(s2); |
|
return dist > maxdist ? INT_MAX : dist; |
|
} |
|
|
static void |
static void |
post_sh_head(POST_ARGS) |
post_sh_head(POST_ARGS) |
{ |
{ |
struct roff_node *nch; |
struct roff_node *nch; |
const char *goodsec; |
const char *goodsec; |
|
const char *const *testsec; |
|
int dist, mindist; |
enum roff_sec sec; |
enum roff_sec sec; |
|
|
/* |
/* |
Line 2146 post_sh_head(POST_ARGS) |
|
Line 2379 post_sh_head(POST_ARGS) |
|
|
|
/* We don't care about custom sections after this. */ |
/* We don't care about custom sections after this. */ |
|
|
if (sec == SEC_CUSTOM) |
if (sec == SEC_CUSTOM) { |
|
if ((nch = mdoc->last->child) == NULL || |
|
nch->type != ROFFT_TEXT || nch->next != NULL) |
|
return; |
|
goodsec = NULL; |
|
mindist = INT_MAX; |
|
for (testsec = secnames + 1; *testsec != NULL; testsec++) { |
|
dist = similar(nch->string, *testsec); |
|
if (dist < mindist) { |
|
goodsec = *testsec; |
|
mindist = dist; |
|
} |
|
} |
|
if (goodsec != NULL) |
|
mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse, |
|
nch->line, nch->pos, "Sh %s instead of %s", |
|
nch->string, goodsec); |
return; |
return; |
|
} |
|
|
/* |
/* |
* Check whether our non-custom section is being repeated or is |
* Check whether our non-custom section is being repeated or is |
Line 2213 post_xr(POST_ARGS) |
|
Line 2463 post_xr(POST_ARGS) |
|
if (nch->next == NULL) { |
if (nch->next == NULL) { |
mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, |
mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, |
n->line, n->pos, "Xr %s", nch->string); |
n->line, n->pos, "Xr %s", nch->string); |
} else |
} else { |
assert(nch->next == n->last); |
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 |
static void |
Line 2228 post_ignpar(POST_ARGS) |
|
Line 2484 post_ignpar(POST_ARGS) |
|
post_prevpar(mdoc); |
post_prevpar(mdoc); |
return; |
return; |
case ROFFT_HEAD: |
case ROFFT_HEAD: |
|
post_delim(mdoc); |
post_hyph(mdoc); |
post_hyph(mdoc); |
return; |
return; |
case ROFFT_BODY: |
case ROFFT_BODY: |
Line 2464 post_bx(POST_ARGS) |
|
Line 2721 post_bx(POST_ARGS) |
|
struct roff_node *n, *nch; |
struct roff_node *n, *nch; |
const char *macro; |
const char *macro; |
|
|
post_delim(mdoc); |
post_delim_nb(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
nch = n->child; |
nch = n->child; |
Line 2530 post_os(POST_ARGS) |
|
Line 2787 post_os(POST_ARGS) |
|
mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, |
mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse, |
n->line, n->pos, "Os"); |
n->line, n->pos, "Os"); |
|
|
|
post_delim(mdoc); |
|
|
/* |
/* |
* Set the operating system by way of the `Os' macro. |
* Set the operating system by way of the `Os' macro. |
* The order of precedence is: |
* The order of precedence is: |
Line 2545 post_os(POST_ARGS) |
|
Line 2804 post_os(POST_ARGS) |
|
if (mdoc->meta.os) |
if (mdoc->meta.os) |
goto out; |
goto out; |
|
|
if (mdoc->defos) { |
if (mdoc->os_s != NULL) { |
mdoc->meta.os = mandoc_strdup(mdoc->defos); |
mdoc->meta.os = mandoc_strdup(mdoc->os_s); |
goto out; |
goto out; |
} |
} |
|
|
Line 2565 post_os(POST_ARGS) |
|
Line 2824 post_os(POST_ARGS) |
|
mdoc->meta.os = mandoc_strdup(defbuf); |
mdoc->meta.os = mandoc_strdup(defbuf); |
#endif /*!OSNAME*/ |
#endif /*!OSNAME*/ |
|
|
out: mdoc->meta.os_e = strstr(mdoc->meta.os, "OpenBSD") != NULL ? |
out: |
MDOC_OS_OPENBSD : strstr(mdoc->meta.os, "NetBSD") != NULL ? |
if (mdoc->meta.os_e == MANDOC_OS_OTHER) { |
MDOC_OS_NETBSD : MDOC_OS_OTHER; |
if (strstr(mdoc->meta.os, "OpenBSD") != NULL) |
|
mdoc->meta.os_e = MANDOC_OS_OPENBSD; |
|
else if (strstr(mdoc->meta.os, "NetBSD") != NULL) |
|
mdoc->meta.os_e = MANDOC_OS_NETBSD; |
|
} |
|
|
/* |
/* |
* This is the earliest point where we can check |
* This is the earliest point where we can check |
Line 2575 out: mdoc->meta.os_e = strstr(mdoc->meta.os, "OpenBSD" |
|
Line 2838 out: mdoc->meta.os_e = strstr(mdoc->meta.os, "OpenBSD" |
|
* the operating system earlier. |
* the operating system earlier. |
*/ |
*/ |
|
|
|
if (n->child != NULL) |
|
mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse, |
|
n->child->line, n->child->pos, |
|
"Os %s (%s)", n->child->string, |
|
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
|
"OpenBSD" : "NetBSD"); |
|
|
while (n->tok != MDOC_Dd) |
while (n->tok != MDOC_Dd) |
if ((n = n->prev) == NULL) |
if ((n = n->prev) == NULL) |
return; |
return; |
if ((n = n->child) == NULL) |
if ((n = n->child) == NULL) |
return; |
return; |
if (strcmp(n->string, "$" "Mdocdate")) { |
if (strncmp(n->string, "$" "Mdocdate", 9)) { |
if (mdoc->meta.os_e == MDOC_OS_OPENBSD) |
if (mdoc->meta.os_e == MANDOC_OS_OPENBSD) |
mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING, |
mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING, |
mdoc->parse, n->line, n->pos, |
mdoc->parse, n->line, n->pos, |
"Dd %s", n->string); |
"Dd %s (OpenBSD)", n->string); |
} else { |
} else { |
if (mdoc->meta.os_e == MDOC_OS_NETBSD) |
if (mdoc->meta.os_e == MANDOC_OS_NETBSD) |
mandoc_vmsg(MANDOCERR_MDOCDATE, |
mandoc_vmsg(MANDOCERR_MDOCDATE, |
mdoc->parse, n->line, n->pos, |
mdoc->parse, n->line, n->pos, |
"Dd %s", n->string); |
"Dd %s (NetBSD)", n->string); |
} |
} |
} |
} |
|
|