=================================================================== RCS file: /cvs/mandoc/mdoc_validate.c,v retrieving revision 1.267 retrieving revision 1.286 diff -u -p -r1.267 -r1.286 --- mandoc/mdoc_validate.c 2015/02/04 16:38:56 1.267 +++ mandoc/mdoc_validate.c 2015/04/18 16:06:41 1.286 @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.267 2015/02/04 16:38:56 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.286 2015/04/18 16:06:41 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2015 Ingo Schwarze @@ -8,9 +8,9 @@ * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF @@ -31,16 +31,17 @@ #include #include -#include "mdoc.h" -#include "mandoc.h" #include "mandoc_aux.h" -#include "libmdoc.h" +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" #include "libmandoc.h" +#include "libmdoc.h" /* FIXME: .Bl -diag can't have non-text children in HEAD. */ -#define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n -#define POST_ARGS struct mdoc *mdoc +#define PRE_ARGS struct roff_man *mdoc, struct roff_node *n +#define POST_ARGS struct roff_man *mdoc enum check_ineq { CHECK_LT, @@ -56,22 +57,15 @@ struct valids { v_post post; }; -static void check_count(struct mdoc *, enum mdoc_type, - enum check_ineq, int); -static void check_text(struct mdoc *, int, int, char *); -static void check_argv(struct mdoc *, - struct mdoc_node *, struct mdoc_argv *); -static void check_args(struct mdoc *, struct mdoc_node *); -static int child_an(const struct mdoc_node *); -static enum mdoc_sec a2sec(const char *); -static size_t macro2len(enum mdoct); +static void check_text(struct roff_man *, int, int, char *); +static void check_argv(struct roff_man *, + struct roff_node *, struct mdoc_argv *); +static void check_args(struct roff_man *, struct roff_node *); +static int child_an(const struct roff_node *); +static enum roff_sec a2sec(const char *); +static size_t macro2len(int); static void rewrite_macro2len(char **); -static void bwarn_ge1(POST_ARGS); -static void ewarn_eq1(POST_ARGS); -static void ewarn_ge1(POST_ARGS); -static void hwarn_eq0(POST_ARGS); - static void post_an(POST_ARGS); static void post_at(POST_ARGS); static void post_bf(POST_ARGS); @@ -94,7 +88,6 @@ static void post_fn(POST_ARGS); static void post_fname(POST_ARGS); static void post_fo(POST_ARGS); static void post_hyph(POST_ARGS); -static void post_hyphtext(POST_ARGS); static void post_ignpar(POST_ARGS); static void post_it(POST_ARGS); static void post_lb(POST_ARGS); @@ -152,12 +145,12 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ev */ { pre_std, post_ex }, /* Ex */ { NULL, post_fa }, /* Fa */ - { NULL, ewarn_ge1 }, /* Fd */ + { NULL, NULL }, /* Fd */ { NULL, NULL }, /* Fl */ { NULL, post_fn }, /* Fn */ { NULL, NULL }, /* Ft */ { NULL, NULL }, /* Ic */ - { NULL, ewarn_eq1 }, /* In */ + { NULL, NULL }, /* In */ { NULL, post_defaults }, /* Li */ { NULL, post_nd }, /* Nd */ { NULL, post_nm }, /* Nm */ @@ -168,18 +161,18 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, post_st }, /* St */ { NULL, NULL }, /* Va */ { NULL, post_vt }, /* Vt */ - { NULL, ewarn_ge1 }, /* Xr */ - { NULL, ewarn_ge1 }, /* %A */ - { NULL, post_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ - { NULL, ewarn_ge1 }, /* %D */ - { NULL, ewarn_ge1 }, /* %I */ - { NULL, ewarn_ge1 }, /* %J */ - { NULL, post_hyphtext }, /* %N */ - { NULL, post_hyphtext }, /* %O */ - { NULL, ewarn_ge1 }, /* %P */ - { NULL, post_hyphtext }, /* %R */ - { NULL, post_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ - { NULL, ewarn_ge1 }, /* %V */ + { NULL, NULL }, /* Xr */ + { NULL, NULL }, /* %A */ + { NULL, post_hyph }, /* %B */ /* FIXME: can be used outside Rs/Re. */ + { NULL, NULL }, /* %D */ + { NULL, NULL }, /* %I */ + { NULL, NULL }, /* %J */ + { NULL, post_hyph }, /* %N */ + { NULL, post_hyph }, /* %O */ + { NULL, NULL }, /* %P */ + { NULL, post_hyph }, /* %R */ + { NULL, post_hyph }, /* %T */ /* FIXME: can be used outside Rs/Re. */ + { NULL, NULL }, /* %V */ { NULL, NULL }, /* Ac */ { NULL, NULL }, /* Ao */ { NULL, NULL }, /* Aq */ @@ -241,21 +234,21 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Brq */ { NULL, NULL }, /* Bro */ { NULL, NULL }, /* Brc */ - { NULL, ewarn_ge1 }, /* %C */ + { NULL, NULL }, /* %C */ { pre_obsolete, post_es }, /* Es */ { pre_obsolete, post_en }, /* En */ { NULL, NULL }, /* Dx */ - { NULL, ewarn_ge1 }, /* %Q */ + { NULL, NULL }, /* %Q */ { NULL, post_par }, /* br */ { NULL, post_par }, /* sp */ - { NULL, ewarn_eq1 }, /* %U */ + { NULL, NULL }, /* %U */ { NULL, NULL }, /* Ta */ { NULL, NULL }, /* ll */ }; #define RSORD_MAX 14 /* Number of `Rs' blocks. */ -static const enum mdoct rsord[RSORD_MAX] = { +static const int rsord[RSORD_MAX] = { MDOC__A, MDOC__T, MDOC__B, @@ -300,19 +293,20 @@ static const char * const secnames[SEC__MAX] = { void -mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) +mdoc_valid_pre(struct roff_man *mdoc, struct roff_node *n) { v_pre p; switch (n->type) { - case MDOC_TEXT: - check_text(mdoc, n->line, n->pos, n->string); + case ROFFT_TEXT: + if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd) + check_text(mdoc, n->line, n->pos, n->string); /* FALLTHROUGH */ - case MDOC_TBL: + case ROFFT_TBL: /* FALLTHROUGH */ - case MDOC_EQN: + case ROFFT_EQN: /* FALLTHROUGH */ - case MDOC_ROOT: + case ROFFT_ROOT: return; default: break; @@ -325,24 +319,24 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) } void -mdoc_valid_post(struct mdoc *mdoc) +mdoc_valid_post(struct roff_man *mdoc) { - struct mdoc_node *n; + struct roff_node *n; v_post p; n = mdoc->last; if (n->flags & MDOC_VALID) return; - n->flags |= MDOC_VALID; + n->flags |= MDOC_VALID | MDOC_ENDED; switch (n->type) { - case MDOC_TEXT: + case ROFFT_TEXT: /* FALLTHROUGH */ - case MDOC_EQN: + case ROFFT_EQN: /* FALLTHROUGH */ - case MDOC_TBL: + case ROFFT_TBL: break; - case MDOC_ROOT: + case ROFFT_ROOT: post_root(mdoc); break; default: @@ -368,67 +362,8 @@ mdoc_valid_post(struct mdoc *mdoc) } static void -check_count(struct mdoc *mdoc, enum mdoc_type type, - enum check_ineq ineq, int val) +check_args(struct roff_man *mdoc, struct roff_node *n) { - const char *p; - - if (mdoc->last->type != type) - return; - - switch (ineq) { - case CHECK_LT: - p = "less than "; - if (mdoc->last->nchild < val) - return; - break; - case CHECK_GT: - p = "more than "; - if (mdoc->last->nchild > val) - return; - break; - case CHECK_EQ: - p = ""; - if (val == mdoc->last->nchild) - return; - break; - default: - abort(); - /* NOTREACHED */ - } - - mandoc_vmsg(MANDOCERR_ARGCWARN, mdoc->parse, mdoc->last->line, - mdoc->last->pos, "want %s%d children (have %d)", - p, val, mdoc->last->nchild); -} - -static void -bwarn_ge1(POST_ARGS) -{ - check_count(mdoc, MDOC_BODY, CHECK_GT, 0); -} - -static void -ewarn_eq1(POST_ARGS) -{ - check_count(mdoc, MDOC_ELEM, CHECK_EQ, 1); -} - -static void -ewarn_ge1(POST_ARGS) -{ - check_count(mdoc, MDOC_ELEM, CHECK_GT, 0); -} - -static void -hwarn_eq0(POST_ARGS) -{ - check_count(mdoc, MDOC_HEAD, CHECK_EQ, 0); -} - -static void -check_args(struct mdoc *mdoc, struct mdoc_node *n) -{ int i; if (NULL == n->args) @@ -440,7 +375,7 @@ check_args(struct mdoc *mdoc, struct mdoc_node *n) } static void -check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) +check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v) { int i; @@ -449,7 +384,7 @@ check_argv(struct mdoc *mdoc, struct mdoc_node *n, str } static void -check_text(struct mdoc *mdoc, int ln, int pos, char *p) +check_text(struct roff_man *mdoc, int ln, int pos, char *p) { char *cp; @@ -464,13 +399,13 @@ check_text(struct mdoc *mdoc, int ln, int pos, char *p static void pre_display(PRE_ARGS) { - struct mdoc_node *node; + struct roff_node *node; - if (MDOC_BLOCK != n->type) + if (n->type != ROFFT_BLOCK) return; for (node = mdoc->last->parent; node; node = node->parent) - if (MDOC_BLOCK == node->type) + if (node->type == ROFFT_BLOCK) if (MDOC_Bd == node->tok) break; @@ -483,24 +418,13 @@ pre_display(PRE_ARGS) static void pre_bl(PRE_ARGS) { - struct mdoc_node *np; struct mdoc_argv *argv, *wa; int i; enum mdocargt mdoclt; enum mdoc_list lt; - if (MDOC_BLOCK != n->type) { - if (ENDBODY_NOT != n->end) { - assert(n->pending); - np = n->pending->parent; - } else - np = n->parent; - - assert(np); - assert(MDOC_BLOCK == np->type); - assert(MDOC_Bl == np->tok); + if (n->type != ROFFT_BLOCK) return; - } /* * First figure out which kind of list to use: bind ourselves to @@ -676,25 +600,14 @@ pre_bl(PRE_ARGS) static void pre_bd(PRE_ARGS) { - struct mdoc_node *np; struct mdoc_argv *argv; int i; enum mdoc_disp dt; pre_literal(mdoc, n); - if (MDOC_BLOCK != n->type) { - if (ENDBODY_NOT != n->end) { - assert(n->pending); - np = n->pending->parent; - } else - np = n->parent; - - assert(np); - assert(MDOC_BLOCK == np->type); - assert(MDOC_Bd == np->tok); + if (n->type != ROFFT_BLOCK) return; - } for (i = 0; n->args && i < (int)n->args->argc; i++) { argv = n->args->argv + i; @@ -806,7 +719,7 @@ static void pre_obsolete(PRE_ARGS) { - if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type) + if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, n->line, n->pos, mdoc_macronames[n->tok]); } @@ -856,7 +769,7 @@ pre_dd(PRE_ARGS) static void post_bf(POST_ARGS) { - struct mdoc_node *np, *nch; + struct roff_node *np, *nch; enum mdocargt arg; /* @@ -864,23 +777,11 @@ post_bf(POST_ARGS) * element, which contains the goods. */ - if (MDOC_HEAD != mdoc->last->type) { - if (ENDBODY_NOT != mdoc->last->end) { - assert(mdoc->last->pending); - np = mdoc->last->pending->parent->head; - } else if (MDOC_BLOCK != mdoc->last->type) { - np = mdoc->last->parent->head; - } else - np = mdoc->last->head; - - assert(np); - assert(MDOC_HEAD == np->type); - assert(MDOC_Bf == np->tok); + np = mdoc->last; + if (np->type != ROFFT_HEAD) return; - } - np = mdoc->last; - assert(MDOC_BLOCK == np->parent->type); + assert(np->parent->type == ROFFT_BLOCK); assert(MDOC_Bf == np->parent->tok); /* Check the number of arguments. */ @@ -930,17 +831,16 @@ post_bf(POST_ARGS) static void post_lb(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; const char *stdlibname; char *libname; - check_count(mdoc, MDOC_ELEM, CHECK_EQ, 1); n = mdoc->last->child; - assert(MDOC_TEXT == n->type); + assert(n->type == ROFFT_TEXT); if (NULL == (stdlibname = mdoc_a2lib(n->string))) mandoc_asprintf(&libname, - "library \\(lq%s\\(rq", n->string); + "library \\(Lq%s\\(Rq", n->string); else libname = mandoc_strdup(stdlibname); @@ -951,7 +851,7 @@ post_lb(POST_ARGS) static void post_eoln(POST_ARGS) { - const struct mdoc_node *n; + const struct roff_node *n; n = mdoc->last; if (n->child) @@ -964,7 +864,7 @@ post_eoln(POST_ARGS) static void post_fname(POST_ARGS) { - const struct mdoc_node *n; + const struct roff_node *n; const char *cp; size_t pos; @@ -987,17 +887,33 @@ post_fn(POST_ARGS) static void post_fo(POST_ARGS) { + const struct roff_node *n; - check_count(mdoc, MDOC_HEAD, CHECK_EQ, 1); - bwarn_ge1(mdoc); - if (mdoc->last->type == MDOC_HEAD && mdoc->last->nchild) - post_fname(mdoc); + n = mdoc->last; + + if (n->type != ROFFT_HEAD) + return; + + if (n->child == NULL) { + mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse, + n->line, n->pos, "Fo"); + return; + } + if (n->child != n->last) { + mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + n->child->next->line, n->child->next->pos, + "Fo ... %s", n->child->next->string); + while (n->child != n->last) + mdoc_node_delete(mdoc, n->last); + } + + post_fname(mdoc); } static void post_fa(POST_ARGS) { - const struct mdoc_node *n; + const struct roff_node *n; const char *cp; for (n = mdoc->last->child; n != NULL; n = n->next) { @@ -1018,7 +934,7 @@ post_fa(POST_ARGS) static void post_vt(POST_ARGS) { - const struct mdoc_node *n; + const struct roff_node *n; /* * The Vt macro comes in both ELEM and BLOCK form, both of which @@ -1028,11 +944,11 @@ post_vt(POST_ARGS) * specifically the BODY, should only have TEXT children. */ - if (MDOC_BODY != mdoc->last->type) + if (mdoc->last->type != ROFFT_BODY) return; for (n = mdoc->last->child; n; n = n->next) - if (MDOC_TEXT != n->type) + if (n->type != ROFFT_TEXT) mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse, n->line, n->pos, mdoc_macronames[n->tok]); } @@ -1040,7 +956,7 @@ post_vt(POST_ARGS) static void post_nm(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; n = mdoc->last; @@ -1062,11 +978,11 @@ post_nm(POST_ARGS) static void post_nd(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; n = mdoc->last; - if (n->type != MDOC_BODY) + if (n->type != ROFFT_BODY) return; if (n->child == NULL) @@ -1079,34 +995,46 @@ post_nd(POST_ARGS) static void post_d1(POST_ARGS) { + struct roff_node *n; - bwarn_ge1(mdoc); + n = mdoc->last; + + if (n->type != ROFFT_BODY) + return; + + if (n->child == NULL) + mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, + n->line, n->pos, "D1"); + post_hyph(mdoc); } static void post_literal(POST_ARGS) { + struct roff_node *n; - if (mdoc->last->tok == MDOC_Bd) - hwarn_eq0(mdoc); - bwarn_ge1(mdoc); + n = mdoc->last; - /* - * The `Dl' (note "el" not "one") and `Bd' macros unset the - * MDOC_LITERAL flag as they leave. Note that `Bd' only sets - * this in literal mode, but it doesn't hurt to just switch it - * off in general since displays can't be nested. - */ + if (n->type != ROFFT_BODY) + return; - if (MDOC_BODY == mdoc->last->type) - mdoc->flags &= ~MDOC_LITERAL; + if (n->child == NULL) + mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, + n->line, n->pos, mdoc_macronames[n->tok]); + + if (n->tok == MDOC_Bd && + n->norm->Bd.type != DISP_literal && + n->norm->Bd.type != DISP_unfilled) + return; + + mdoc->flags &= ~MDOC_LITERAL; } static void post_defaults(POST_ARGS) { - struct mdoc_node *nn; + struct roff_node *nn; /* * The `Ar' defaults to "file ..." if no value is provided as an @@ -1118,7 +1046,7 @@ post_defaults(POST_ARGS) return; nn = mdoc->last; - mdoc->next = MDOC_NEXT_CHILD; + mdoc->next = ROFF_NEXT_CHILD; switch (nn->tok) { case MDOC_Ar: @@ -1140,13 +1068,13 @@ post_defaults(POST_ARGS) static void post_at(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; const char *std_att; char *att; n = mdoc->last; if (n->child == NULL) { - mdoc->next = MDOC_NEXT_CHILD; + mdoc->next = ROFF_NEXT_CHILD; mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"); mdoc->last = n; return; @@ -1159,7 +1087,7 @@ post_at(POST_ARGS) */ n = n->child; - assert(MDOC_TEXT == n->type); + assert(n->type == ROFFT_TEXT); if (NULL == (std_att = mdoc_a2att(n->string))) { mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse, n->line, n->pos, "At %s", n->string); @@ -1174,21 +1102,24 @@ post_at(POST_ARGS) static void post_an(POST_ARGS) { - struct mdoc_node *np; + struct roff_node *np, *nch; np = mdoc->last; - if (AUTH__NONE == np->norm->An.auth) { - if (0 == np->child) - check_count(mdoc, MDOC_ELEM, CHECK_GT, 0); - } else if (np->child) - check_count(mdoc, MDOC_ELEM, CHECK_EQ, 0); + nch = np->child; + if (np->norm->An.auth == AUTH__NONE) { + if (nch == NULL) + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + np->line, np->pos, "An"); + } else if (nch != NULL) + mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + nch->line, nch->pos, "An ... %s", nch->string); } static void post_en(POST_ARGS) { - if (MDOC_BLOCK == mdoc->last->type) + if (mdoc->last->type == ROFFT_BLOCK) mdoc->last->norm->Es = mdoc->last_es; } @@ -1202,12 +1133,12 @@ post_es(POST_ARGS) static void post_it(POST_ARGS) { + struct roff_node *nbl, *nit, *nch; int i, cols; enum mdoc_list lt; - struct mdoc_node *nbl, *nit, *nch; nit = mdoc->last; - if (nit->type != MDOC_BLOCK) + if (nit->type != ROFFT_BLOCK) return; nbl = nit->parent->parent; @@ -1254,13 +1185,13 @@ post_it(POST_ARGS) assert(nit->head->child == NULL); for (i = 0, nch = nit->child; nch; nch = nch->next) - if (nch->type == MDOC_BODY) + if (nch->type == ROFFT_BODY) i++; if (i < cols || i > cols + 1) - mandoc_vmsg(MANDOCERR_ARGCOUNT, + mandoc_vmsg(MANDOCERR_BL_COL, mdoc->parse, nit->line, nit->pos, - "columns == %d (have %d)", cols, i); + "%d columns, %d cells", cols, i); break; default: abort(); @@ -1270,7 +1201,7 @@ post_it(POST_ARGS) static void post_bl_block(POST_ARGS) { - struct mdoc_node *n, *ni, *nc; + struct roff_node *n, *ni, *nc; /* * These are fairly complicated, so we've broken them into two @@ -1331,7 +1262,7 @@ void rewrite_macro2len(char **arg) { size_t width; - enum mdoct tok; + int tok; if (*arg == NULL) return; @@ -1349,7 +1280,7 @@ rewrite_macro2len(char **arg) static void post_bl_block_tag(POST_ARGS) { - struct mdoc_node *n, *nn; + struct roff_node *n, *nn; size_t sz, ssz; int i; char buf[24]; @@ -1368,13 +1299,13 @@ post_bl_block_tag(POST_ARGS) if (MDOC_It != nn->tok) continue; - assert(MDOC_BLOCK == nn->type); + assert(nn->type == ROFFT_BLOCK); nn = nn->head->child; if (nn == NULL) break; - if (MDOC_TEXT == nn->type) { + if (nn->type == ROFFT_TEXT) { sz = strlen(nn->string) + 1; break; } @@ -1414,13 +1345,21 @@ post_bl_block_tag(POST_ARGS) static void post_bl_head(POST_ARGS) { - struct mdoc_node *np, *nn, *nnp; + struct roff_node *nbl, *nh, *nch, *nnext; struct mdoc_argv *argv; int i, j; - if (LIST_column != mdoc->last->norm->Bl.type) { - /* FIXME: this should be ERROR class... */ - hwarn_eq0(mdoc); + nh = mdoc->last; + + if (nh->norm->Bl.type != LIST_column) { + if ((nch = nh->child) == NULL) + return; + mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + nch->line, nch->pos, "Bl ... %s", nch->string); + while (nch != NULL) { + mdoc_node_delete(mdoc, nch); + nch = nh->child; + } return; } @@ -1430,17 +1369,15 @@ post_bl_head(POST_ARGS) * lists where they're argument values following -column. */ - if (mdoc->last->child == NULL) + if (nh->child == NULL) return; - np = mdoc->last->parent; - assert(np->args); - - for (j = 0; j < (int)np->args->argc; j++) - if (MDOC_Column == np->args->argv[j].arg) + nbl = nh->parent; + for (j = 0; j < (int)nbl->args->argc; j++) + if (nbl->args->argv[j].arg == MDOC_Column) break; - assert(j < (int)np->args->argc); + assert(j < (int)nbl->args->argc); /* * Accommodate for new-style groff column syntax. Shuffle the @@ -1448,52 +1385,53 @@ post_bl_head(POST_ARGS) * column field. Then, delete the head children. */ - argv = np->args->argv + j; + argv = nbl->args->argv + j; i = argv->sz; - argv->sz += mdoc->last->nchild; + argv->sz += nh->nchild; argv->value = mandoc_reallocarray(argv->value, argv->sz, sizeof(char *)); - mdoc->last->norm->Bl.ncols = argv->sz; - mdoc->last->norm->Bl.cols = (void *)argv->value; + nh->norm->Bl.ncols = argv->sz; + nh->norm->Bl.cols = (void *)argv->value; - for (nn = mdoc->last->child; nn; i++) { - argv->value[i] = nn->string; - nn->string = NULL; - nnp = nn; - nn = nn->next; - mdoc_node_delete(NULL, nnp); + for (nch = nh->child; nch != NULL; nch = nnext) { + argv->value[i++] = nch->string; + nch->string = NULL; + nnext = nch->next; + mdoc_node_delete(NULL, nch); } - - mdoc->last->nchild = 0; - mdoc->last->child = NULL; + nh->nchild = 0; + nh->child = NULL; } static void post_bl(POST_ARGS) { - struct mdoc_node *nparent, *nprev; /* of the Bl block */ - struct mdoc_node *nblock, *nbody; /* of the Bl */ - struct mdoc_node *nchild, *nnext; /* of the Bl body */ + struct roff_node *nparent, *nprev; /* of the Bl block */ + struct roff_node *nblock, *nbody; /* of the Bl */ + struct roff_node *nchild, *nnext; /* of the Bl body */ nbody = mdoc->last; switch (nbody->type) { - case MDOC_BLOCK: + case ROFFT_BLOCK: post_bl_block(mdoc); return; - case MDOC_HEAD: + case ROFFT_HEAD: post_bl_head(mdoc); return; - case MDOC_BODY: + case ROFFT_BODY: break; default: return; } - bwarn_ge1(mdoc); - nchild = nbody->child; - while (NULL != nchild) { + if (nchild == NULL) { + mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, + nbody->line, nbody->pos, "Bl"); + return; + } + while (nchild != NULL) { if (nchild->tok == MDOC_It || (nchild->tok == MDOC_Sm && nchild->next != NULL && @@ -1552,15 +1490,21 @@ post_bl(POST_ARGS) static void post_bk(POST_ARGS) { + struct roff_node *n; - hwarn_eq0(mdoc); - bwarn_ge1(mdoc); + n = mdoc->last; + + if (n->type == ROFFT_BLOCK && n->body->child == NULL) { + mandoc_msg(MANDOCERR_BLK_EMPTY, + mdoc->parse, n->line, n->pos, "Bk"); + mdoc_node_delete(mdoc, n); + } } static void -post_sm(struct mdoc *mdoc) +post_sm(struct roff_man *mdoc) { - struct mdoc_node *nch; + struct roff_node *nch; nch = mdoc->last->child; @@ -1569,7 +1513,7 @@ post_sm(struct mdoc *mdoc) return; } - assert(nch->type == MDOC_TEXT); + assert(nch->type == ROFFT_TEXT); if ( ! strcmp(nch->string, "on")) { mdoc->flags &= ~MDOC_SMOFF; @@ -1590,7 +1534,7 @@ post_sm(struct mdoc *mdoc) static void post_root(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; /* Add missing prologue data. */ @@ -1630,21 +1574,14 @@ post_root(POST_ARGS) static void post_st(POST_ARGS) { - struct mdoc_node *n, *nch; + struct roff_node *n, *nch; const char *p; n = mdoc->last; nch = n->child; - if (NULL == nch) { - mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, - n->line, n->pos, mdoc_macronames[n->tok]); - mdoc_node_delete(mdoc, n); - return; - } + assert(nch->type == ROFFT_TEXT); - assert(MDOC_TEXT == nch->type); - if (NULL == (p = mdoc_a2st(nch->string))) { mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse, nch->line, nch->pos, "St %s", nch->string); @@ -1658,20 +1595,18 @@ post_st(POST_ARGS) static void post_rs(POST_ARGS) { - struct mdoc_node *nn, *next, *prev; + struct roff_node *np, *nch, *next, *prev; int i, j; - switch (mdoc->last->type) { - case MDOC_HEAD: - check_count(mdoc, MDOC_HEAD, CHECK_EQ, 0); + np = mdoc->last; + + if (np->type != ROFFT_BODY) return; - case MDOC_BODY: - if (mdoc->last->child) - break; - check_count(mdoc, MDOC_BODY, CHECK_GT, 0); + + if (np->child == NULL) { + mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse, + np->line, np->pos, "Rs"); return; - default: - return; } /* @@ -1681,38 +1616,38 @@ post_rs(POST_ARGS) */ next = NULL; - for (nn = mdoc->last->child->next; nn; nn = next) { - /* Determine order of `nn'. */ + for (nch = np->child->next; nch != NULL; nch = next) { + /* Determine order number of this child. */ for (i = 0; i < RSORD_MAX; i++) - if (rsord[i] == nn->tok) + if (rsord[i] == nch->tok) break; if (i == RSORD_MAX) { mandoc_msg(MANDOCERR_RS_BAD, - mdoc->parse, nn->line, nn->pos, - mdoc_macronames[nn->tok]); + mdoc->parse, nch->line, nch->pos, + mdoc_macronames[nch->tok]); i = -1; - } else if (MDOC__J == nn->tok || MDOC__B == nn->tok) - mdoc->last->norm->Rs.quote_T++; + } else if (nch->tok == MDOC__J || nch->tok == MDOC__B) + np->norm->Rs.quote_T++; /* - * Remove `nn' from the chain. This somewhat + * Remove this child from the chain. This somewhat * repeats mdoc_node_unlink(), but since we're * just re-ordering, there's no need for the * full unlink process. */ - if (NULL != (next = nn->next)) - next->prev = nn->prev; + if ((next = nch->next) != NULL) + next->prev = nch->prev; - if (NULL != (prev = nn->prev)) - prev->next = nn->next; + if ((prev = nch->prev) != NULL) + prev->next = nch->next; - nn->prev = nn->next = NULL; + nch->prev = nch->next = NULL; /* * Scan back until we reach a node that's - * ordered before `nn'. + * to be ordered before this child. */ for ( ; prev ; prev = prev->prev) { @@ -1728,21 +1663,21 @@ post_rs(POST_ARGS) } /* - * Set `nn' back into its correct place in front - * of the `prev' node. + * Set this child back into its correct place + * in front of the `prev' node. */ - nn->prev = prev; + nch->prev = prev; - if (prev) { - if (prev->next) - prev->next->prev = nn; - nn->next = prev->next; - prev->next = nn; + if (prev == NULL) { + np->child->prev = nch; + nch->next = np->child; + np->child = nch; } else { - mdoc->last->child->prev = nn; - nn->next = mdoc->last->child; - mdoc->last->child = nn; + if (prev->next) + prev->next->prev = nch; + nch->next = prev->next; + prev->next = nch; } } } @@ -1754,33 +1689,17 @@ post_rs(POST_ARGS) static void post_hyph(POST_ARGS) { - struct mdoc_node *n, *nch; + struct roff_node *nch; char *cp; - n = mdoc->last; - switch (n->type) { - case MDOC_HEAD: - if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) - break; - return; - case MDOC_BODY: - if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) - break; - return; - case MDOC_ELEM: - break; - default: - return; - } - - for (nch = n->child; nch; nch = nch->next) { - if (MDOC_TEXT != nch->type) + for (nch = mdoc->last->child; nch != NULL; nch = nch->next) { + if (nch->type != ROFFT_TEXT) continue; cp = nch->string; - if ('\0' == *cp) + if (*cp == '\0') continue; - while ('\0' != *(++cp)) - if ('-' == *cp && + while (*(++cp) != '\0') + if (*cp == '-' && isalpha((unsigned char)cp[-1]) && isalpha((unsigned char)cp[1])) *cp = ASCII_HYPH; @@ -1788,14 +1707,6 @@ post_hyph(POST_ARGS) } static void -post_hyphtext(POST_ARGS) -{ - - ewarn_ge1(mdoc); - post_hyph(mdoc); -} - -static void post_ns(POST_ARGS) { @@ -1811,10 +1722,10 @@ post_sh(POST_ARGS) post_ignpar(mdoc); switch (mdoc->last->type) { - case MDOC_HEAD: + case ROFFT_HEAD: post_sh_head(mdoc); break; - case MDOC_BODY: + case ROFFT_BODY: switch (mdoc->lastsec) { case SEC_NAME: post_sh_name(mdoc); @@ -1837,42 +1748,46 @@ post_sh(POST_ARGS) static void post_sh_name(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; + int hasnm, hasnd; - /* - * Warn if the NAME section doesn't contain the `Nm' and `Nd' - * macros (can have multiple `Nm' and one `Nd'). Note that the - * children of the BODY declaration can also be "text". - */ + hasnm = hasnd = 0; - if (NULL == (n = mdoc->last->child)) { - mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, - mdoc->last->line, mdoc->last->pos, "empty"); - return; + for (n = mdoc->last->child; n != NULL; n = n->next) { + switch (n->tok) { + case MDOC_Nm: + hasnm = 1; + break; + case MDOC_Nd: + hasnd = 1; + if (n->next != NULL) + mandoc_msg(MANDOCERR_NAMESEC_ND, + mdoc->parse, n->line, n->pos, NULL); + break; + case MDOC_MAX: + if (hasnm) + break; + /* FALLTHROUGH */ + default: + mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, + n->line, n->pos, mdoc_macronames[n->tok]); + break; + } } - for ( ; n && n->next; n = n->next) { - if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) - continue; - if (MDOC_TEXT == n->type) - continue; - mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, - n->line, n->pos, mdoc_macronames[n->tok]); - } - - assert(n); - if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) - return; - - mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, - n->line, n->pos, mdoc_macronames[n->tok]); + if ( ! hasnm) + mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse, + mdoc->last->line, mdoc->last->pos, NULL); + if ( ! hasnd) + mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse, + mdoc->last->line, mdoc->last->pos, NULL); } static void post_sh_see_also(POST_ARGS) { - const struct mdoc_node *n; - const char *name, *sec; + const struct roff_node *n; + const char *name, *sec; const char *lastname, *lastsec, *lastpunct; int cmp; @@ -1916,7 +1831,7 @@ post_sh_see_also(POST_ARGS) lastpunct = "none"; continue; } - if (n->type != MDOC_TEXT) + if (n->type != ROFFT_TEXT) break; for (name = n->string; *name != '\0'; name++) if (isalpha((const unsigned char)*name)) @@ -1931,7 +1846,7 @@ post_sh_see_also(POST_ARGS) } static int -child_an(const struct mdoc_node *n) +child_an(const struct roff_node *n) { for (n = n->child; n != NULL; n = n->next) @@ -1952,10 +1867,10 @@ post_sh_authors(POST_ARGS) static void post_sh_head(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; const char *goodsec; char *secname; - enum mdoc_sec sec; + enum roff_sec sec; /* * Process a new section. Sections are either "named" or @@ -2072,13 +1987,17 @@ post_sh_head(POST_ARGS) static void post_ignpar(POST_ARGS) { - struct mdoc_node *np; + struct roff_node *np; - check_count(mdoc, MDOC_HEAD, CHECK_GT, 0); - post_hyph(mdoc); - - if (MDOC_BODY != mdoc->last->type) + switch (mdoc->last->type) { + case ROFFT_HEAD: + post_hyph(mdoc); return; + case ROFFT_BODY: + break; + default: + return; + } if (NULL != (np = mdoc->last->child)) if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { @@ -2105,7 +2024,7 @@ pre_par(PRE_ARGS) if (NULL == mdoc->last) return; - if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) + if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK) return; /* @@ -2134,16 +2053,19 @@ pre_par(PRE_ARGS) static void post_par(POST_ARGS) { - struct mdoc_node *np; + struct roff_node *np; - if (mdoc->last->tok == MDOC_sp) - check_count(mdoc, MDOC_ELEM, CHECK_LT, 2); - else - check_count(mdoc, MDOC_ELEM, CHECK_EQ, 0); + np = mdoc->last; - if (MDOC_ELEM != mdoc->last->type && - MDOC_BLOCK != mdoc->last->type) - return; + if (np->tok == MDOC_sp) { + if (np->nchild > 1) + mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + np->child->next->line, np->child->next->pos, + "sp ... %s", np->child->next->string); + } else if (np->child != NULL) + mandoc_vmsg(MANDOCERR_ARG_SKIP, + mdoc->parse, np->line, np->pos, "%s %s", + mdoc_macronames[np->tok], np->child->string); if (NULL == (np = mdoc->last->prev)) { np = mdoc->last->parent; @@ -2167,7 +2089,7 @@ pre_literal(PRE_ARGS) pre_display(mdoc, n); - if (MDOC_BODY != n->type) + if (n->type != ROFFT_BODY) return; /* @@ -2194,7 +2116,7 @@ pre_literal(PRE_ARGS) static void post_dd(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; char *datestr; if (mdoc->meta.date) @@ -2223,7 +2145,7 @@ out: static void post_dt(POST_ARGS) { - struct mdoc_node *nn, *n; + struct roff_node *nn, *n; const char *cp; char *p; @@ -2239,70 +2161,68 @@ post_dt(POST_ARGS) mdoc->meta.vol = NULL; mdoc->meta.arch = NULL; - /* First check that all characters are uppercase. */ + /* Mandatory first argument: title. */ - if (NULL != (nn = n->child)) - for (p = nn->string; *p; p++) { - if (toupper((unsigned char)*p) == *p) - continue; - mandoc_vmsg(MANDOCERR_TITLE_CASE, - mdoc->parse, nn->line, - nn->pos + (p - nn->string), - "Dt %s", nn->string); - break; - } - - /* No argument: msec and arch remain NULL. */ - - if (NULL == (nn = n->child)) { + nn = n->child; + if (nn == NULL || *nn->string == '\0') { mandoc_msg(MANDOCERR_DT_NOTITLE, mdoc->parse, n->line, n->pos, "Dt"); mdoc->meta.title = mandoc_strdup("UNTITLED"); - mdoc->meta.vol = mandoc_strdup("LOCAL"); - goto out; + } else { + mdoc->meta.title = mandoc_strdup(nn->string); + + /* Check that all characters are uppercase. */ + + for (p = nn->string; *p != '\0'; p++) + if (islower((unsigned char)*p)) { + mandoc_vmsg(MANDOCERR_TITLE_CASE, + mdoc->parse, nn->line, + nn->pos + (p - nn->string), + "Dt %s", nn->string); + break; + } } - /* One argument: msec and arch remain NULL. */ + /* Mandatory second argument: section. */ - mdoc->meta.title = mandoc_strdup( - '\0' == nn->string[0] ? "UNTITLED" : nn->string); + if (nn != NULL) + nn = nn->next; - if (NULL == (nn = nn->next)) { + if (nn == NULL) { mandoc_vmsg(MANDOCERR_MSEC_MISSING, mdoc->parse, n->line, n->pos, "Dt %s", mdoc->meta.title); mdoc->meta.vol = mandoc_strdup("LOCAL"); - goto out; + goto out; /* msec and arch remain NULL. */ } - /* Handles: `.Dt TITLE SEC' - * title = TITLE, - * volume = SEC is msec ? format(msec) : SEC, - * msec = SEC is msec ? atoi(msec) : 0, - * arch = NULL - */ + mdoc->meta.msec = mandoc_strdup(nn->string); + /* Infer volume title from section number. */ + cp = mandoc_a2msec(nn->string); - if (cp) { - mdoc->meta.vol = mandoc_strdup(cp); - mdoc->meta.msec = mandoc_strdup(nn->string); - } else { + if (cp == NULL) { mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse, nn->line, nn->pos, "Dt ... %s", nn->string); mdoc->meta.vol = mandoc_strdup(nn->string); - mdoc->meta.msec = mandoc_strdup(nn->string); - } + } else + mdoc->meta.vol = mandoc_strdup(cp); - /* Handle an optional architecture */ + /* Optional third argument: architecture. */ - if ((nn = nn->next) != NULL) { - for (p = nn->string; *p; p++) - *p = tolower((unsigned char)*p); - mdoc->meta.arch = mandoc_strdup(nn->string); - } + if ((nn = nn->next) == NULL) + goto out; - /* Ignore any subsequent parameters... */ - /* FIXME: warn about subsequent parameters. */ + for (p = nn->string; *p != '\0'; p++) + *p = tolower((unsigned char)*p); + mdoc->meta.arch = mandoc_strdup(nn->string); + + /* Ignore fourth and later arguments. */ + + if ((nn = nn->next) != NULL) + mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, + nn->line, nn->pos, "Dt ... %s", nn->string); + out: mdoc_node_delete(mdoc, n); } @@ -2310,7 +2230,7 @@ out: static void post_bx(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; /* * Make `Bx's second argument always start with an uppercase @@ -2330,7 +2250,7 @@ post_os(POST_ARGS) struct utsname utsname; static char *defbuf; #endif - struct mdoc_node *n; + struct roff_node *n; n = mdoc->last; @@ -2380,7 +2300,7 @@ out: static void post_ex(POST_ARGS) { - struct mdoc_node *n; + struct roff_node *n; n = mdoc->last; @@ -2393,25 +2313,25 @@ post_ex(POST_ARGS) return; } - mdoc->next = MDOC_NEXT_CHILD; + mdoc->next = ROFF_NEXT_CHILD; mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); mdoc->last = n; } -static enum mdoc_sec +static enum roff_sec a2sec(const char *p) { int i; for (i = 0; i < (int)SEC__MAX; i++) if (secnames[i] && 0 == strcmp(p, secnames[i])) - return((enum mdoc_sec)i); + return((enum roff_sec)i); return(SEC_CUSTOM); } static size_t -macro2len(enum mdoct macro) +macro2len(int macro) { switch (macro) {