version 1.377, 2020/01/19 18:02:00 |
version 1.381, 2020/04/01 20:21:08 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
|
* Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org> |
|
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* 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 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
* |
|
* Validation module for mdoc(7) syntax trees used by mandoc(1). |
*/ |
*/ |
#include "config.h" |
#include "config.h" |
|
|
|
|
#include "mandoc.h" |
#include "mandoc.h" |
#include "mandoc_xr.h" |
#include "mandoc_xr.h" |
#include "roff.h" |
#include "roff.h" |
|
#include "tag.h" |
#include "mdoc.h" |
#include "mdoc.h" |
#include "libmandoc.h" |
#include "libmandoc.h" |
#include "roff_int.h" |
#include "roff_int.h" |
Line 82 static void post_dd(POST_ARGS); |
|
Line 85 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_delim_nb(POST_ARGS); |
static void post_dt(POST_ARGS); |
static void post_dt(POST_ARGS); |
|
static void post_em(POST_ARGS); |
static void post_en(POST_ARGS); |
static void post_en(POST_ARGS); |
|
static void post_er(POST_ARGS); |
static void post_es(POST_ARGS); |
static void post_es(POST_ARGS); |
static void post_eoln(POST_ARGS); |
static void post_eoln(POST_ARGS); |
static void post_ex(POST_ARGS); |
static void post_ex(POST_ARGS); |
Line 91 static void post_fn(POST_ARGS); |
|
Line 96 static void post_fn(POST_ARGS); |
|
static void post_fname(POST_ARGS); |
static void post_fname(POST_ARGS); |
static void post_fo(POST_ARGS); |
static void post_fo(POST_ARGS); |
static void post_hyph(POST_ARGS); |
static void post_hyph(POST_ARGS); |
static void post_ignpar(POST_ARGS); |
|
static void post_it(POST_ARGS); |
static void post_it(POST_ARGS); |
static void post_lb(POST_ARGS); |
static void post_lb(POST_ARGS); |
static void post_nd(POST_ARGS); |
static void post_nd(POST_ARGS); |
Line 104 static void post_prevpar(POST_ARGS); |
|
Line 108 static void post_prevpar(POST_ARGS); |
|
static void post_root(POST_ARGS); |
static void post_root(POST_ARGS); |
static void post_rs(POST_ARGS); |
static void post_rs(POST_ARGS); |
static void post_rv(POST_ARGS); |
static void post_rv(POST_ARGS); |
|
static void post_section(POST_ARGS); |
static void post_sh(POST_ARGS); |
static void post_sh(POST_ARGS); |
static void post_sh_head(POST_ARGS); |
static void post_sh_head(POST_ARGS); |
static void post_sh_name(POST_ARGS); |
static void post_sh_name(POST_ARGS); |
Line 113 static void post_sm(POST_ARGS); |
|
Line 118 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_tag(POST_ARGS); |
static void post_tg(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); |
Line 123 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
Line 129 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
post_dt, /* Dt */ |
post_dt, /* Dt */ |
post_os, /* Os */ |
post_os, /* Os */ |
post_sh, /* Sh */ |
post_sh, /* Sh */ |
post_ignpar, /* Ss */ |
post_section, /* Ss */ |
post_par, /* Pp */ |
post_par, /* Pp */ |
post_display, /* D1 */ |
post_display, /* D1 */ |
post_display, /* Dl */ |
post_display, /* Dl */ |
Line 137 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
Line 143 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
NULL, /* Ap */ |
NULL, /* Ap */ |
post_defaults, /* Ar */ |
post_defaults, /* Ar */ |
NULL, /* Cd */ |
NULL, /* Cd */ |
post_delim_nb, /* Cm */ |
post_tag, /* Cm */ |
post_delim_nb, /* Dv */ |
post_tag, /* Dv */ |
post_delim_nb, /* Er */ |
post_er, /* Er */ |
post_delim_nb, /* Ev */ |
post_tag, /* Ev */ |
post_ex, /* Ex */ |
post_ex, /* Ex */ |
post_fa, /* Fa */ |
post_fa, /* Fa */ |
NULL, /* Fd */ |
NULL, /* Fd */ |
post_delim_nb, /* Fl */ |
post_tag, /* Fl */ |
post_fn, /* Fn */ |
post_fn, /* Fn */ |
post_delim_nb, /* Ft */ |
post_delim_nb, /* Ft */ |
post_delim_nb, /* Ic */ |
post_tag, /* Ic */ |
post_delim_nb, /* In */ |
post_delim_nb, /* In */ |
post_defaults, /* Li */ |
post_tag, /* Li */ |
post_nd, /* Nd */ |
post_nd, /* Nd */ |
post_nm, /* Nm */ |
post_nm, /* Nm */ |
post_delim_nb, /* Op */ |
post_delim_nb, /* Op */ |
Line 187 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
Line 193 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
NULL, /* Dq */ |
NULL, /* Dq */ |
NULL, /* Ec */ |
NULL, /* Ec */ |
NULL, /* Ef */ |
NULL, /* Ef */ |
post_delim_nb, /* Em */ |
post_em, /* Em */ |
NULL, /* Eo */ |
NULL, /* Eo */ |
post_xx, /* Fx */ |
post_xx, /* Fx */ |
post_delim_nb, /* Ms */ |
post_tag, /* Ms */ |
NULL, /* No */ |
post_tag, /* No */ |
post_ns, /* Ns */ |
post_ns, /* Ns */ |
post_xx, /* Nx */ |
post_xx, /* Nx */ |
post_xx, /* Ox */ |
post_xx, /* Ox */ |
Line 210 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
Line 216 static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = |
|
post_delim_nb, /* Sq */ |
post_delim_nb, /* Sq */ |
post_sm, /* Sm */ |
post_sm, /* Sm */ |
post_sx, /* Sx */ |
post_sx, /* Sx */ |
post_delim_nb, /* Sy */ |
post_em, /* Sy */ |
post_useless, /* Tn */ |
post_useless, /* Tn */ |
post_xx, /* Ux */ |
post_xx, /* Ux */ |
NULL, /* Xc */ |
NULL, /* Xc */ |
Line 287 static const char * const secnames[SEC__MAX] = { |
|
Line 293 static const char * const secnames[SEC__MAX] = { |
|
NULL |
NULL |
}; |
}; |
|
|
|
static int fn_prio = TAG_STRONG; |
|
|
|
|
/* Validate the subtree rooted at mdoc->last. */ |
/* Validate the subtree rooted at mdoc->last. */ |
void |
void |
mdoc_validate(struct roff_man *mdoc) |
mdoc_validate(struct roff_man *mdoc) |
Line 1094 post_st(POST_ARGS) |
|
Line 1102 post_st(POST_ARGS) |
|
static void |
static void |
post_tg(POST_ARGS) |
post_tg(POST_ARGS) |
{ |
{ |
struct roff_node *n, *nch; |
struct roff_node *n; /* The .Tg node. */ |
size_t len; |
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 *nt; /* The TEXT node containing the tag. */ |
|
size_t len; /* The number of bytes in the tag. */ |
|
|
|
/* Find the next node. */ |
n = mdoc->last; |
n = mdoc->last; |
nch = n->child; |
for (nn = n; nn != NULL; nn = nn->parent) { |
if (nch == NULL && n->next != NULL && |
if (nn->next != NULL) { |
n->next->child->type == ROFFT_TEXT) { |
nn = nn->next; |
mdoc->next = ROFF_NEXT_CHILD; |
break; |
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') { |
|
|
/* Find the tag. */ |
|
nt = nch = n->child; |
|
if (nch == NULL && nn != NULL && nn->child != NULL && |
|
nn->child->type == ROFFT_TEXT) |
|
nt = nn->child; |
|
|
|
/* Validate the tag. */ |
|
if (nt == NULL || *nt->string == '\0') |
mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg"); |
mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg"); |
|
if (nt == NULL) { |
roff_node_delete(mdoc, n); |
roff_node_delete(mdoc, n); |
return; |
return; |
} |
} |
len = strcspn(nch->string, " \t"); |
len = strcspn(nt->string, " \t\\"); |
if (nch->string[len] != '\0') |
if (nt->string[len] != '\0') |
mandoc_msg(MANDOCERR_TG_SPC, nch->line, nch->pos + len + 1, |
mandoc_msg(MANDOCERR_TG_SPC, nt->line, |
"Tg %s", nch->string); |
nt->pos + len, "Tg %s", nt->string); |
if (nch->next != NULL) { |
|
|
/* Keep only the first argument. */ |
|
if (nch != NULL && nch->next != NULL) { |
mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line, |
mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line, |
nch->next->pos, "Tg ... %s", nch->next->string); |
nch->next->pos, "Tg ... %s", nch->next->string); |
while (nch->next != NULL) |
while (nch->next != NULL) |
roff_node_delete(mdoc, nch->next); |
roff_node_delete(mdoc, nch->next); |
} |
} |
if (nch->string[len] != '\0') |
|
|
/* Drop the macro if the first argument is invalid. */ |
|
if (len == 0 || nt->string[len] != '\0') { |
roff_node_delete(mdoc, n); |
roff_node_delete(mdoc, n); |
|
return; |
|
} |
|
|
|
/* By default, tag the .Tg node itself. */ |
|
if (nn == NULL) |
|
nn = n; |
|
|
|
/* Explicit tagging of specific macros. */ |
|
switch (nn->tok) { |
|
case MDOC_Sh: |
|
case MDOC_Ss: |
|
case MDOC_Fo: |
|
nn = nn->head; |
|
/* FALLTHROUGH */ |
|
case MDOC_Cm: |
|
case MDOC_Dv: |
|
case MDOC_Em: |
|
case MDOC_Er: |
|
case MDOC_Ev: |
|
case MDOC_Fl: |
|
case MDOC_Fn: |
|
case MDOC_Ic: |
|
case MDOC_Li: |
|
case MDOC_Ms: |
|
case MDOC_No: |
|
case MDOC_Sy: |
|
if (nn->child != NULL && (nn->flags & NODE_ID) == 0) |
|
break; |
|
/* FALLTHROUGH */ |
|
default: |
|
nn = n; |
|
break; |
|
} |
|
tag_put(nt->string, TAG_MANUAL, nn); |
|
if (nn != n) |
|
n->flags |= NODE_NOPRT; |
} |
} |
|
|
static void |
static void |
Line 1218 post_bf(POST_ARGS) |
|
Line 1276 post_bf(POST_ARGS) |
|
static void |
static void |
post_fname(POST_ARGS) |
post_fname(POST_ARGS) |
{ |
{ |
const struct roff_node *n; |
struct roff_node *n, *nch; |
const char *cp; |
const char *cp; |
size_t pos; |
size_t pos; |
|
|
n = mdoc->last->child; |
n = mdoc->last; |
cp = n->string; |
nch = n->child; |
|
cp = nch->string; |
if (*cp == '(') { |
if (*cp == '(') { |
if (cp[strlen(cp + 1)] == ')') |
if (cp[strlen(cp + 1)] == ')') |
return; |
return; |
pos = 0; |
pos = 0; |
} else { |
} else { |
pos = strcspn(cp, "()"); |
pos = strcspn(cp, "()"); |
if (cp[pos] == '\0') |
if (cp[pos] == '\0') { |
|
if (n->sec == SEC_DESCRIPTION || |
|
n->sec == SEC_CUSTOM) |
|
tag_put(NULL, fn_prio++, n); |
return; |
return; |
|
} |
} |
} |
mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos, "%s", cp); |
mandoc_msg(MANDOCERR_FN_PAREN, nch->line, nch->pos + pos, "%s", cp); |
} |
} |
|
|
static void |
static void |
post_fn(POST_ARGS) |
post_fn(POST_ARGS) |
{ |
{ |
|
|
post_fname(mdoc); |
post_fname(mdoc); |
post_fa(mdoc); |
post_fa(mdoc); |
} |
} |
Line 1403 post_display(POST_ARGS) |
|
Line 1465 post_display(POST_ARGS) |
|
static void |
static void |
post_defaults(POST_ARGS) |
post_defaults(POST_ARGS) |
{ |
{ |
struct roff_node *nn; |
struct roff_node *n; |
|
|
if (mdoc->last->child != NULL) { |
n = mdoc->last; |
|
if (n->child != NULL) { |
post_delim_nb(mdoc); |
post_delim_nb(mdoc); |
return; |
return; |
} |
} |
|
mdoc->next = ROFF_NEXT_CHILD; |
/* |
switch (n->tok) { |
* The `Ar' defaults to "file ..." if no value is provided as an |
|
* argument; the `Mt' and `Pa' macros use "~"; the `Li' just |
|
* gets an empty string. |
|
*/ |
|
|
|
nn = mdoc->last; |
|
switch (nn->tok) { |
|
case MDOC_Ar: |
case MDOC_Ar: |
mdoc->next = ROFF_NEXT_CHILD; |
roff_word_alloc(mdoc, n->line, n->pos, "file"); |
roff_word_alloc(mdoc, nn->line, nn->pos, "file"); |
|
mdoc->last->flags |= NODE_NOSRC; |
mdoc->last->flags |= NODE_NOSRC; |
roff_word_alloc(mdoc, nn->line, nn->pos, "..."); |
roff_word_alloc(mdoc, n->line, n->pos, "..."); |
mdoc->last->flags |= NODE_NOSRC; |
|
break; |
break; |
case MDOC_Pa: |
case MDOC_Pa: |
case MDOC_Mt: |
case MDOC_Mt: |
mdoc->next = ROFF_NEXT_CHILD; |
roff_word_alloc(mdoc, n->line, n->pos, "~"); |
roff_word_alloc(mdoc, nn->line, nn->pos, "~"); |
|
mdoc->last->flags |= NODE_NOSRC; |
|
break; |
break; |
default: |
default: |
abort(); |
abort(); |
} |
} |
mdoc->last = nn; |
mdoc->last->flags |= NODE_NOSRC; |
|
mdoc->last = n; |
} |
} |
|
|
static void |
static void |
Line 1488 post_an(POST_ARGS) |
|
Line 1541 post_an(POST_ARGS) |
|
} |
} |
|
|
static void |
static void |
post_en(POST_ARGS) |
post_em(POST_ARGS) |
{ |
{ |
|
post_tag(mdoc); |
|
tag_put(NULL, TAG_FALLBACK, mdoc->last); |
|
} |
|
|
|
static void |
|
post_en(POST_ARGS) |
|
{ |
post_obsolete(mdoc); |
post_obsolete(mdoc); |
if (mdoc->last->type == ROFFT_BLOCK) |
if (mdoc->last->type == ROFFT_BLOCK) |
mdoc->last->norm->Es = mdoc->last_es; |
mdoc->last->norm->Es = mdoc->last_es; |
} |
} |
|
|
static void |
static void |
post_es(POST_ARGS) |
post_er(POST_ARGS) |
{ |
{ |
|
struct roff_node *n; |
|
|
|
n = mdoc->last; |
|
if (n->sec == SEC_ERRORS && |
|
(n->parent->tok == MDOC_It || |
|
(n->parent->tok == MDOC_Bq && |
|
n->parent->parent->parent->tok == MDOC_It))) |
|
tag_put(NULL, TAG_STRONG, n); |
|
post_delim_nb(mdoc); |
|
} |
|
|
|
static void |
|
post_tag(POST_ARGS) |
|
{ |
|
struct roff_node *n; |
|
|
|
n = mdoc->last; |
|
if ((n->prev == NULL || |
|
(n->prev->type == ROFFT_TEXT && |
|
strcmp(n->prev->string, "|") == 0)) && |
|
(n->parent->tok == MDOC_It || |
|
(n->parent->tok == MDOC_Xo && |
|
n->parent->parent->prev == NULL && |
|
n->parent->parent->parent->tok == MDOC_It))) |
|
tag_put(NULL, TAG_STRONG, n); |
|
post_delim_nb(mdoc); |
|
} |
|
|
|
static void |
|
post_es(POST_ARGS) |
|
{ |
post_obsolete(mdoc); |
post_obsolete(mdoc); |
mdoc->last_es = mdoc->last; |
mdoc->last_es = mdoc->last; |
} |
} |
Line 1596 post_it(POST_ARGS) |
|
Line 1685 post_it(POST_ARGS) |
|
if ((nch = nit->head->child) != NULL) |
if ((nch = nit->head->child) != NULL) |
mandoc_msg(MANDOCERR_ARG_SKIP, |
mandoc_msg(MANDOCERR_ARG_SKIP, |
nit->line, nit->pos, "It %s", |
nit->line, nit->pos, "It %s", |
nch->string == NULL ? roff_name[nch->tok] : |
nch->type == ROFFT_TEXT ? nch->string : |
nch->string); |
roff_name[nch->tok]); |
break; |
break; |
case LIST_column: |
case LIST_column: |
cols = (int)nbl->norm->Bl.ncols; |
cols = (int)nbl->norm->Bl.ncols; |
Line 1760 post_bl_head(POST_ARGS) |
|
Line 1849 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 1782 post_bl(POST_ARGS) |
|
Line 1870 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 || nchild->tok == MDOC_Tg) && |
|
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 2129 post_sx(POST_ARGS) |
|
Line 2202 post_sx(POST_ARGS) |
|
static void |
static void |
post_sh(POST_ARGS) |
post_sh(POST_ARGS) |
{ |
{ |
|
post_section(mdoc); |
|
|
post_ignpar(mdoc); |
|
|
|
switch (mdoc->last->type) { |
switch (mdoc->last->type) { |
case ROFFT_HEAD: |
case ROFFT_HEAD: |
post_sh_head(mdoc); |
post_sh_head(mdoc); |
Line 2361 post_sh_head(POST_ARGS) |
|
Line 2433 post_sh_head(POST_ARGS) |
|
roff_setreg(mdoc->roff, "nS", 0, '='); |
roff_setreg(mdoc->roff, "nS", 0, '='); |
mdoc->flags &= ~MDOC_SYNOPSIS; |
mdoc->flags &= ~MDOC_SYNOPSIS; |
} |
} |
|
if (sec == SEC_DESCRIPTION) |
|
fn_prio = TAG_STRONG; |
|
|
/* Mark our last section. */ |
/* Mark our last section. */ |
|
|
Line 2461 post_xr(POST_ARGS) |
|
Line 2535 post_xr(POST_ARGS) |
|
} |
} |
|
|
static void |
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: |
case ROFFT_BLOCK: |
post_prevpar(mdoc); |
post_prevpar(mdoc); |
return; |
return; |
case ROFFT_HEAD: |
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_WEAK, n); |
|
else |
|
tag_put(tag, TAG_FALLBACK, n); |
|
free(tag); |
|
} |
post_delim(mdoc); |
post_delim(mdoc); |
post_hyph(mdoc); |
post_hyph(mdoc); |
return; |
return; |
Line 2478 post_ignpar(POST_ARGS) |
|
Line 2568 post_ignpar(POST_ARGS) |
|
default: |
default: |
return; |
return; |
} |
} |
|
if ((nch = n->child) != NULL && |
if ((np = mdoc->last->child) != NULL) |
(nch->tok == MDOC_Pp || nch->tok == ROFF_br || |
if (np->tok == MDOC_Pp || |
nch->tok == ROFF_sp)) { |
np->tok == ROFF_br || np->tok == ROFF_sp) { |
mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos, |
mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, |
"%s after %s", roff_name[nch->tok], |
"%s after %s", roff_name[np->tok], |
roff_name[n->tok]); |
roff_name[mdoc->last->tok]); |
roff_node_delete(mdoc, nch); |
roff_node_delete(mdoc, np); |
} |
} |
if ((nch = n->last) != NULL && |
|
(nch->tok == MDOC_Pp || nch->tok == ROFF_br)) { |
if ((np = mdoc->last->last) != NULL) |
mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos, |
if (np->tok == MDOC_Pp || np->tok == ROFF_br) { |
"%s at the end of %s", roff_name[nch->tok], |
mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, |
roff_name[n->tok]); |
"%s at the end of %s", roff_name[np->tok], |
roff_node_delete(mdoc, nch); |
roff_name[mdoc->last->tok]); |
} |
roff_node_delete(mdoc, np); |
|
} |
|
} |
} |
|
|
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 2522 post_prevpar(POST_ARGS) |
|
Line 2610 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 |
Line 2532 post_par(POST_ARGS) |
|
Line 2620 post_par(POST_ARGS) |
|
{ |
{ |
struct roff_node *np; |
struct roff_node *np; |
|
|
|
fn_prio = TAG_STRONG; |
post_prevpar(mdoc); |
post_prevpar(mdoc); |
|
|
np = mdoc->last; |
np = mdoc->last; |