version 1.367, 2018/12/31 04:55:47 |
version 1.378, 2020/02/27 01:43:52 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010-2020 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 |
Line 64 static size_t macro2len(enum roff_tok); |
|
Line 64 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 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(POST_ARGS); |
static void post_an_norm(POST_ARGS); |
static void post_an_norm(POST_ARGS); |
static void post_at(POST_ARGS); |
static void post_at(POST_ARGS); |
Line 113 static void post_sm(POST_ARGS); |
|
Line 113 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_sx(POST_ARGS); |
|
static void post_tg(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 238 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
Line 239 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
NULL, /* %Q */ |
NULL, /* %Q */ |
NULL, /* %U */ |
NULL, /* %U */ |
NULL, /* Ta */ |
NULL, /* Ta */ |
|
post_tg, /* Tg */ |
}; |
}; |
|
|
#define RSORD_MAX 14 /* Number of `Rs' blocks. */ |
#define RSORD_MAX 14 /* Number of `Rs' blocks. */ |
Line 336 mdoc_validate(struct roff_man *mdoc) |
|
Line 338 mdoc_validate(struct roff_man *mdoc) |
|
if (n->sec != SEC_SYNOPSIS || |
if (n->sec != SEC_SYNOPSIS || |
(np->tok != MDOC_Cd && np->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 (np->tok != MDOC_Ql && np->tok != MDOC_Dl && |
if ((n->flags & NODE_NOFILL) == 0 && |
(np->tok != MDOC_Bd || |
|
(mdoc->flags & MDOC_LITERAL) == 0) && |
|
(np->tok != MDOC_It || np->type != ROFFT_HEAD || |
(np->tok != MDOC_It || np->type != ROFFT_HEAD || |
np->parent->parent->norm->Bl.type != LIST_diag)) |
np->parent->parent->norm->Bl.type != LIST_diag)) |
check_text_em(mdoc, n->line, n->pos, n->string); |
check_text_em(mdoc, n->line, n->pos, n->string); |
Line 411 check_text(struct roff_man *mdoc, int ln, int pos, cha |
|
Line 411 check_text(struct roff_man *mdoc, int ln, int pos, cha |
|
{ |
{ |
char *cp; |
char *cp; |
|
|
if (MDOC_LITERAL & mdoc->flags) |
if (mdoc->last->flags & NODE_NOFILL) |
return; |
return; |
|
|
for (cp = p; NULL != (p = strchr(p, '\t')); p++) |
for (cp = p; NULL != (p = strchr(p, '\t')); p++) |
Line 1092 post_st(POST_ARGS) |
|
Line 1092 post_st(POST_ARGS) |
|
} |
} |
|
|
static void |
static void |
|
post_tg(POST_ARGS) |
|
{ |
|
struct roff_node *n, *nch; |
|
size_t len; |
|
|
|
n = mdoc->last; |
|
nch = n->child; |
|
if (nch == NULL && n->next != NULL && |
|
n->next->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; |
|
} |
|
if (nch == NULL || *nch->string == '\0') { |
|
mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg"); |
|
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); |
|
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); |
|
} |
|
if (nch->string[len] != '\0') |
|
roff_node_delete(mdoc, n); |
|
} |
|
|
|
static void |
post_obsolete(POST_ARGS) |
post_obsolete(POST_ARGS) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
Line 1188 post_fname(POST_ARGS) |
|
Line 1223 post_fname(POST_ARGS) |
|
size_t pos; |
size_t pos; |
|
|
n = mdoc->last->child; |
n = mdoc->last->child; |
pos = strcspn(n->string, "()"); |
cp = n->string; |
cp = n->string + pos; |
if (*cp == '(') { |
if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) |
if (cp[strlen(cp + 1)] == ')') |
mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, |
return; |
"%s", n->string); |
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 |
static void |
Line 1583 post_it(POST_ARGS) |
|
Line 1624 post_it(POST_ARGS) |
|
mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos, |
mandoc_msg(MANDOCERR_BL_COL, nit->line, nit->pos, |
"%d columns, %d cells", cols, i); |
"%d columns, %d cells", cols, i); |
else if (nit->head->next->child != NULL && |
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, |
mandoc_msg(MANDOCERR_IT_NOARG, |
nit->line, nit->pos, "Bl -column It"); |
nit->line, nit->pos, "Bl -column It"); |
break; |
break; |
Line 1719 post_bl_head(POST_ARGS) |
|
Line 1760 post_bl_head(POST_ARGS) |
|
static void |
static void |
post_bl(POST_ARGS) |
post_bl(POST_ARGS) |
{ |
{ |
struct roff_node *nparent, *nprev; /* of the Bl block */ |
struct roff_node *nbody; /* of the Bl */ |
struct roff_node *nblock, *nbody; /* of the Bl */ |
|
struct roff_node *nchild, *nnext; /* of the Bl body */ |
struct roff_node *nchild, *nnext; /* of the Bl body */ |
const char *prev_Er; |
const char *prev_Er; |
int order; |
int order; |
Line 1741 post_bl(POST_ARGS) |
|
Line 1781 post_bl(POST_ARGS) |
|
if (nbody->end != ENDBODY_NOT) |
if (nbody->end != ENDBODY_NOT) |
return; |
return; |
|
|
nchild = nbody->child; |
/* |
if (nchild == NULL) { |
* Up to the first item, move nodes before the list, |
mandoc_msg(MANDOCERR_BLK_EMPTY, |
* but leave transparent nodes where they are |
nbody->line, nbody->pos, "Bl"); |
* if they precede an item. |
return; |
* 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) { |
while (nchild != NULL) { |
nnext = nchild->next; |
if (nchild->tok == MDOC_It) { |
if (nchild->tok == MDOC_It || |
nchild = roff_node_next(nchild); |
(nchild->tok == MDOC_Sm && |
|
nnext != NULL && nnext->tok == MDOC_It)) { |
|
nchild = nnext; |
|
continue; |
continue; |
} |
} |
|
nnext = nchild->next; |
/* |
mdoc->last = nchild->prev; |
* In .Bl -column, the first rows may be implicit, |
mdoc->next = ROFF_NEXT_SIBLING; |
* that is, they may not start with .It macros. |
roff_block_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); |
* Such rows may be followed by nodes generated on the |
roff_head_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); |
* roff level, for example .TS, which cannot be moved |
mdoc->next = ROFF_NEXT_SIBLING; |
* out of the list. In that case, wrap such roff nodes |
roff_body_alloc(mdoc, nchild->line, nchild->pos, MDOC_It); |
* into an implicit row. |
while (nchild->tok != MDOC_It) { |
*/ |
roff_node_relink(mdoc, nchild); |
|
if (nnext == NULL) |
if (nchild->prev != NULL) { |
break; |
mdoc->last = nchild; |
nchild = nnext; |
|
nnext = nchild->next; |
mdoc->next = ROFF_NEXT_SIBLING; |
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; |
|
} |
} |
|
mdoc->last = nbody; |
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; |
|
} |
} |
|
|
if (mdoc->meta.os_e != MANDOC_OS_NETBSD) |
if (mdoc->meta.os_e != MANDOC_OS_NETBSD) |
Line 1900 post_sm(POST_ARGS) |
|
Line 1925 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. */ |
|
|
if (mdoc->meta.date == NULL) |
if (mdoc->meta.date == NULL) |
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : |
mdoc->meta.date = mandoc_normdate(NULL, NULL); |
mandoc_normdate(mdoc, NULL, 0, 0); |
|
|
|
if (mdoc->meta.title == NULL) { |
if (mdoc->meta.title == NULL) { |
mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); |
mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); |
Line 1948 post_root(POST_ARGS) |
|
Line 1950 post_root(POST_ARGS) |
|
"(OpenBSD)" : "(NetBSD)"); |
"(OpenBSD)" : "(NetBSD)"); |
|
|
if (mdoc->meta.arch != NULL && |
if (mdoc->meta.arch != NULL && |
(arch = arches[mdoc->meta.os_e]) != NULL) { |
arch_valid(mdoc->meta.arch, mdoc->meta.os_e) == 0) { |
while (*arch != NULL && strcmp(*arch, mdoc->meta.arch)) |
n = mdoc->meta.first->child; |
arch++; |
while (n->tok != MDOC_Dt || |
if (*arch == NULL) { |
n->child == NULL || |
n = mdoc->meta.first->child; |
n->child->next == NULL || |
while (n->tok != MDOC_Dt || |
n->child->next->next == NULL) |
n->child == NULL || |
n = n->next; |
n->child->next == NULL || |
n = n->child->next->next; |
n->child->next->next == NULL) |
mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, |
n = n->next; |
"Dt ... %s %s", mdoc->meta.arch, |
n = n->child->next->next; |
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
mandoc_msg(MANDOCERR_ARCH_BAD, n->line, n->pos, |
"(OpenBSD)" : "(NetBSD)"); |
"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'. */ |
Line 2486 post_ignpar(POST_ARGS) |
|
Line 2484 post_ignpar(POST_ARGS) |
|
static void |
static void |
post_prevpar(POST_ARGS) |
post_prevpar(POST_ARGS) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n, *np; |
|
|
n = mdoc->last; |
n = mdoc->last; |
if (NULL == n->prev) |
|
return; |
|
if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) |
if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) |
return; |
return; |
|
if ((np = roff_node_prev(n)) == NULL) |
|
return; |
|
|
/* |
/* |
* Don't allow `Pp' prior to a paragraph-type |
* Don't allow `Pp' prior to a paragraph-type |
* block: `Pp' or non-compact `Bd' or `Bl'. |
* 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; |
return; |
if (n->tok == MDOC_Bl && n->norm->Bl.comp) |
if (n->tok == MDOC_Bl && n->norm->Bl.comp) |
return; |
return; |
Line 2508 post_prevpar(POST_ARGS) |
|
Line 2506 post_prevpar(POST_ARGS) |
|
if (n->tok == MDOC_It && n->parent->norm->Bl.comp) |
if (n->tok == MDOC_It && n->parent->norm->Bl.comp) |
return; |
return; |
|
|
mandoc_msg(MANDOCERR_PAR_SKIP, n->prev->line, n->prev->pos, |
mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, |
"%s before %s", roff_name[n->prev->tok], roff_name[n->tok]); |
"%s before %s", roff_name[np->tok], roff_name[n->tok]); |
roff_node_delete(mdoc, n->prev); |
roff_node_delete(mdoc, np); |
} |
} |
|
|
static void |
static void |
|
|
post_dd(POST_ARGS) |
post_dd(POST_ARGS) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
char *datestr; |
|
|
|
n = mdoc->last; |
n = mdoc->last; |
n->flags |= NODE_NOPRT; |
n->flags |= NODE_NOPRT; |
Line 2547 post_dd(POST_ARGS) |
|
Line 2544 post_dd(POST_ARGS) |
|
mandoc_msg(MANDOCERR_PROLOG_ORDER, |
mandoc_msg(MANDOCERR_PROLOG_ORDER, |
n->line, n->pos, "Dd after Os"); |
n->line, n->pos, "Dd after Os"); |
|
|
if (n->child == NULL || n->child->string[0] == '\0') { |
if (mdoc->quick && n != NULL) |
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : |
mdoc->meta.date = mandoc_strdup(""); |
mandoc_normdate(mdoc, NULL, n->line, n->pos); |
else |
return; |
mdoc->meta.date = mandoc_normdate(n->child, n); |
} |
|
|
|
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); |
|
} |
|
} |
} |
|
|
static void |
static void |