-/* $Id: mdoc_validate.c,v 1.139 2010/12/09 10:32:22 kristaps Exp $ */
+/* $Id: mdoc_validate.c,v 1.168 2011/04/13 09:57:08 kristaps Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <string.h>
#include <time.h>
+#include "mdoc.h"
#include "mandoc.h"
#include "libmdoc.h"
#include "libmandoc.h"
enum check_lvl {
CHECK_WARN,
CHECK_ERROR,
- CHECK_FATAL
};
typedef int (*v_pre)(PRE_ARGS);
static int concat(struct mdoc *, char *,
const struct mdoc_node *, size_t);
+static enum mdoc_sec a2sec(const char *);
+static size_t macro2len(enum mdoct);
static int ebool(POST_ARGS);
static int berr_ge1(POST_ARGS);
static int bwarn_ge1(POST_ARGS);
-static int eerr_eq0(POST_ARGS);
-static int eerr_eq1(POST_ARGS);
-static int eerr_ge1(POST_ARGS);
-static int eerr_le1(POST_ARGS);
static int ewarn_eq0(POST_ARGS);
+static int ewarn_eq1(POST_ARGS);
static int ewarn_ge1(POST_ARGS);
-static int herr_eq0(POST_ARGS);
-static int herr_ge1(POST_ARGS);
+static int ewarn_le1(POST_ARGS);
static int hwarn_eq0(POST_ARGS);
static int hwarn_eq1(POST_ARGS);
+static int hwarn_ge1(POST_ARGS);
static int hwarn_le1(POST_ARGS);
static int post_an(POST_ARGS);
static int post_bl_block_width(POST_ARGS);
static int post_bl_block_tag(POST_ARGS);
static int post_bl_head(POST_ARGS);
+static int post_bx(POST_ARGS);
static int post_dd(POST_ARGS);
static int post_dt(POST_ARGS);
static int post_defaults(POST_ARGS);
static int post_it(POST_ARGS);
static int post_lb(POST_ARGS);
static int post_nm(POST_ARGS);
+static int post_ns(POST_ARGS);
static int post_os(POST_ARGS);
+static int post_ignpar(POST_ARGS);
static int post_prol(POST_ARGS);
static int post_root(POST_ARGS);
static int post_rs(POST_ARGS);
static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
-static v_post posts_bool[] = { eerr_eq1, ebool, NULL };
+static v_post posts_bx[] = { post_bx, NULL };
+static v_post posts_bool[] = { ebool, NULL };
static v_post posts_eoln[] = { post_eoln, NULL };
static v_post posts_defaults[] = { post_defaults, NULL };
-static v_post posts_dd[] = { ewarn_ge1, post_dd, post_prol, NULL };
-static v_post posts_dl[] = { post_literal, bwarn_ge1, herr_eq0, NULL };
+static v_post posts_dd[] = { post_dd, post_prol, NULL };
+static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
static v_post posts_dt[] = { post_dt, post_prol, NULL };
static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
static v_post posts_it[] = { post_it, NULL };
-static v_post posts_lb[] = { eerr_eq1, post_lb, NULL };
+static v_post posts_lb[] = { post_lb, NULL };
static v_post posts_nd[] = { berr_ge1, NULL };
static v_post posts_nm[] = { post_nm, NULL };
static v_post posts_notext[] = { ewarn_eq0, NULL };
+static v_post posts_ns[] = { post_ns, NULL };
static v_post posts_os[] = { post_os, post_prol, NULL };
-static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL };
-static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
-static v_post posts_sp[] = { eerr_le1, NULL };
-static v_post posts_ss[] = { herr_ge1, NULL };
-static v_post posts_st[] = { eerr_eq1, post_st, NULL };
+static v_post posts_rs[] = { post_rs, NULL };
+static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
+static v_post posts_sp[] = { ewarn_le1, NULL };
+static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
+static v_post posts_st[] = { post_st, NULL };
static v_post posts_std[] = { post_std, NULL };
-static v_post posts_text[] = { eerr_ge1, NULL };
-static v_post posts_text1[] = { eerr_eq1, NULL };
+static v_post posts_text[] = { ewarn_ge1, NULL };
+static v_post posts_text1[] = { ewarn_eq1, NULL };
static v_post posts_vt[] = { post_vt, NULL };
-static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
-static v_post posts_wtext[] = { ewarn_ge1, NULL };
+static v_post posts_wline[] = { bwarn_ge1, NULL };
static v_pre pres_an[] = { pre_an, NULL };
static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
static v_pre pres_dt[] = { pre_dt, NULL };
static v_pre pres_er[] = { NULL, NULL };
static v_pre pres_fd[] = { NULL, NULL };
-static v_pre pres_it[] = { pre_it, NULL };
+static v_pre pres_it[] = { pre_it, pre_par, NULL };
static v_pre pres_os[] = { pre_os, NULL };
static v_pre pres_pp[] = { pre_par, NULL };
static v_pre pres_sh[] = { pre_sh, NULL };
static v_pre pres_ss[] = { pre_ss, NULL };
static v_pre pres_std[] = { pre_std, NULL };
-const struct valids mdoc_valids[MDOC_MAX] = {
+static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Ap */
{ pres_dd, posts_dd }, /* Dd */
{ pres_dt, posts_dt }, /* Dt */
{ pres_bl, posts_bl }, /* Bl */
{ NULL, NULL }, /* El */
{ pres_it, posts_it }, /* It */
- { NULL, posts_text }, /* Ad */
+ { NULL, NULL }, /* Ad */
{ pres_an, posts_an }, /* An */
{ NULL, posts_defaults }, /* Ar */
- { NULL, posts_text }, /* Cd */
+ { NULL, NULL }, /* Cd */
{ NULL, NULL }, /* Cm */
{ NULL, NULL }, /* Dv */
- { pres_er, posts_text }, /* Er */
+ { pres_er, NULL }, /* Er */
{ NULL, NULL }, /* Ev */
{ pres_std, posts_std }, /* Ex */
{ NULL, NULL }, /* Fa */
- { pres_fd, posts_wtext }, /* Fd */
+ { pres_fd, posts_text }, /* Fd */
{ NULL, NULL }, /* Fl */
- { NULL, posts_text }, /* Fn */
- { NULL, posts_wtext }, /* Ft */
- { NULL, posts_text }, /* Ic */
+ { NULL, NULL }, /* Fn */
+ { NULL, NULL }, /* Ft */
+ { NULL, NULL }, /* Ic */
{ NULL, posts_text1 }, /* In */
{ NULL, posts_defaults }, /* Li */
{ NULL, posts_nd }, /* Nd */
{ NULL, posts_st }, /* St */
{ NULL, NULL }, /* Va */
{ NULL, posts_vt }, /* Vt */
- { NULL, posts_wtext }, /* Xr */
+ { NULL, posts_text }, /* Xr */
{ NULL, posts_text }, /* %A */
{ NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */
- { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */
+ { NULL, posts_text }, /* %D */
{ NULL, posts_text }, /* %I */
{ NULL, posts_text }, /* %J */
{ NULL, posts_text }, /* %N */
{ NULL, NULL }, /* Bo */
{ NULL, NULL }, /* Bq */
{ NULL, NULL }, /* Bsx */
- { NULL, NULL }, /* Bx */
+ { NULL, posts_bx }, /* Bx */
{ NULL, posts_bool }, /* Db */
{ NULL, NULL }, /* Dc */
{ NULL, NULL }, /* Do */
{ NULL, NULL }, /* Em */
{ NULL, NULL }, /* Eo */
{ NULL, NULL }, /* Fx */
- { NULL, posts_text }, /* Ms */
+ { NULL, NULL }, /* Ms */
{ NULL, posts_notext }, /* No */
- { NULL, posts_notext }, /* Ns */
+ { NULL, posts_ns }, /* Ns */
{ NULL, NULL }, /* Nx */
{ NULL, NULL }, /* Ox */
{ NULL, NULL }, /* Pc */
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
{ NULL, posts_bool }, /* Sm */
- { NULL, posts_text }, /* Sx */
- { NULL, posts_text }, /* Sy */
- { NULL, posts_text }, /* Tn */
+ { NULL, NULL }, /* Sx */
+ { NULL, NULL }, /* Sy */
+ { NULL, NULL }, /* Tn */
{ NULL, NULL }, /* Ux */
{ NULL, NULL }, /* Xc */
{ NULL, NULL }, /* Xo */
{ NULL, posts_eoln }, /* Ud */
{ NULL, posts_lb }, /* Lb */
{ NULL, posts_notext }, /* Lp */
- { NULL, posts_text }, /* Lk */
+ { NULL, NULL }, /* Lk */
{ NULL, posts_defaults }, /* Mt */
{ NULL, NULL }, /* Brq */
{ NULL, NULL }, /* Bro */
MDOC__U
};
+static const char * const secnames[SEC__MAX] = {
+ NULL,
+ "NAME",
+ "LIBRARY",
+ "SYNOPSIS",
+ "DESCRIPTION",
+ "IMPLEMENTATION NOTES",
+ "RETURN VALUES",
+ "ENVIRONMENT",
+ "FILES",
+ "EXIT STATUS",
+ "EXAMPLES",
+ "DIAGNOSTICS",
+ "COMPATIBILITY",
+ "ERRORS",
+ "SEE ALSO",
+ "STANDARDS",
+ "HISTORY",
+ "AUTHORS",
+ "CAVEATS",
+ "BUGS",
+ "SECURITY CONSIDERATIONS",
+ NULL
+};
int
mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
int line, pos;
char *tp;
- if (MDOC_TEXT == n->type) {
+ switch (n->type) {
+ case (MDOC_TEXT):
tp = n->string;
line = n->line;
pos = n->pos;
check_text(mdoc, line, pos, tp);
+ /* FALLTHROUGH */
+ case (MDOC_TBL):
+ /* FALLTHROUGH */
+ case (MDOC_EQN):
+ /* FALLTHROUGH */
+ case (MDOC_ROOT):
return(1);
+ default:
+ break;
}
check_args(mdoc, n);
return(1);
mdoc->last->flags |= MDOC_VALID;
- if (MDOC_TEXT == mdoc->last->type)
+ switch (mdoc->last->type) {
+ case (MDOC_TEXT):
+ /* FALLTHROUGH */
+ case (MDOC_EQN):
+ /* FALLTHROUGH */
+ case (MDOC_TBL):
return(1);
- if (MDOC_ROOT == mdoc->last->type)
+ case (MDOC_ROOT):
return(post_root(mdoc));
+ default:
+ break;
+ }
if (NULL == mdoc_valids[mdoc->last->tok].post)
return(1);
enum check_lvl lvl, enum check_ineq ineq, int val)
{
const char *p;
+ enum mandocerr t;
if (m->last->type != type)
return(1);
return(1);
break;
case (CHECK_GT):
- p = "greater than ";
+ p = "more than ";
if (m->last->nchild > val)
return(1);
break;
/* NOTREACHED */
}
- if (CHECK_WARN == lvl) {
- return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT,
- m->last->line, m->last->pos,
- "want %s%d children (have %d)",
- p, val, m->last->nchild));
- }
-
- /* FIXME: THIS IS THE SAME AS THE ABOVE. */
-
- return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT,
- m->last->line, m->last->pos,
- "require %s%d children (have %d)",
- p, val, m->last->nchild));
+ t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
+ mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
+ "want %s%d children (have %d)",
+ p, val, m->last->nchild);
+ return(1);
}
static int
berr_ge1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_BODY, CHECK_FATAL, CHECK_GT, 0));
+ return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
}
static int
return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
}
-static int
-eerr_eq0(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_EQ, 0));
-}
-
-static int
-eerr_eq1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_EQ, 1));
-}
-
-static int
-eerr_ge1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_GT, 0));
-}
-
-static int
-eerr_le1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_LT, 2));
-}
-
static int
ewarn_eq0(POST_ARGS)
{
}
static int
-ewarn_ge1(POST_ARGS)
+ewarn_eq1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
+ return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
}
static int
-herr_eq0(POST_ARGS)
+ewarn_ge1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_HEAD, CHECK_FATAL, CHECK_EQ, 0));
+ return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
}
static int
-herr_ge1(POST_ARGS)
+ewarn_le1(POST_ARGS)
{
- return(check_count(mdoc, MDOC_HEAD, CHECK_FATAL, CHECK_GT, 0));
+ return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
}
static int
return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
}
+static int
+hwarn_ge1(POST_ARGS)
+{
+ return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
+}
+
static int
hwarn_le1(POST_ARGS)
{
static void
check_text(struct mdoc *m, int ln, int pos, char *p)
{
- int c;
+ char *cpp, *pp;
size_t sz;
- for ( ; *p; p++, pos++) {
+ while ('\0' != *p) {
sz = strcspn(p, "\t\\");
- p += (int)sz;
-
- if ('\0' == *p)
- break;
+ p += (int)sz;
pos += (int)sz;
if ('\t' == *p) {
if ( ! (MDOC_LITERAL & m->flags))
mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB);
+ p++;
+ pos++;
continue;
- }
+ } else if ('\0' == *p)
+ break;
+
+ pos++;
+ pp = ++p;
- if (0 == (c = mandoc_special(p))) {
+ if (ESCAPE_ERROR == mandoc_escape
+ ((const char **)&pp, NULL, NULL)) {
mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE);
- continue;
+ break;
}
- p += c - 1;
- pos += c - 1;
+ cpp = p;
+ while (NULL != (cpp = memchr(cpp, ASCII_HYPH, pp - cpp)))
+ *cpp = '-';
+
+ pos += pp - p;
+ p = pp;
}
}
(t == n->parent->type))
return(1);
- mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD,
- n->line, n->pos, "want parent %s",
- MDOC_ROOT == t ? "<root>" :
- mdoc_macronames[tok]);
+ mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
+ n->pos, "want parent %s", MDOC_ROOT == t ?
+ "<root>" : mdoc_macronames[tok]);
return(0);
}
assert(np);
assert(MDOC_BLOCK == np->type);
assert(MDOC_Bl == np->tok);
- assert(np->data.Bl);
- n->data.Bl = np->data.Bl;
return(1);
}
* ones. If we find no list type, we default to LIST_item.
*/
- assert(NULL == n->data.Bl);
- n->data.Bl = mandoc_calloc(1, sizeof(struct mdoc_bl));
-
/* LINTED */
for (i = 0; n->args && i < (int)n->args->argc; i++) {
lt = LIST__NONE;
break;
/* Set list arguments. */
case (MDOC_Compact):
- dup = n->data.Bl->comp;
+ dup = n->norm->Bl.comp;
comp = 1;
break;
case (MDOC_Width):
- dup = (NULL != n->data.Bl->width);
+ dup = (NULL != n->norm->Bl.width);
width = n->args->argv[i].value[0];
break;
case (MDOC_Offset):
/* NB: this can be empty! */
if (n->args->argv[i].sz) {
offs = n->args->argv[i].value[0];
- dup = (NULL != n->data.Bl->offs);
+ dup = (NULL != n->norm->Bl.offs);
break;
}
mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
if (comp && ! dup)
- n->data.Bl->comp = comp;
+ n->norm->Bl.comp = comp;
if (offs && ! dup)
- n->data.Bl->offs = offs;
+ n->norm->Bl.offs = offs;
if (width && ! dup)
- n->data.Bl->width = width;
+ n->norm->Bl.width = width;
/* Check: multiple list types. */
- if (LIST__NONE != lt && n->data.Bl->type != LIST__NONE)
+ if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
/* Assign list type. */
- if (LIST__NONE != lt && n->data.Bl->type == LIST__NONE) {
- n->data.Bl->type = lt;
+ if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
+ n->norm->Bl.type = lt;
/* Set column information, too. */
if (LIST_column == lt) {
- n->data.Bl->ncols =
+ n->norm->Bl.ncols =
n->args->argv[i].sz;
- n->data.Bl->cols = (const char **)
+ n->norm->Bl.cols = (const char **)
n->args->argv[i].value;
}
}
/* The list type should come first. */
- if (n->data.Bl->type == LIST__NONE)
- if (n->data.Bl->width ||
- n->data.Bl->offs ||
- n->data.Bl->comp)
+ if (n->norm->Bl.type == LIST__NONE)
+ if (n->norm->Bl.width ||
+ n->norm->Bl.offs ||
+ n->norm->Bl.comp)
mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
continue;
/* Allow lists to default to LIST_item. */
- if (LIST__NONE == n->data.Bl->type) {
+ if (LIST__NONE == n->norm->Bl.type) {
mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
- n->data.Bl->type = LIST_item;
+ n->norm->Bl.type = LIST_item;
}
/*
* and must also be warned.
*/
- switch (n->data.Bl->type) {
+ switch (n->norm->Bl.type) {
case (LIST_tag):
- if (n->data.Bl->width)
+ if (n->norm->Bl.width)
break;
mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
break;
case (LIST_inset):
/* FALLTHROUGH */
case (LIST_item):
- if (n->data.Bl->width)
+ if (n->norm->Bl.width)
mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
break;
default:
assert(np);
assert(MDOC_BLOCK == np->type);
assert(MDOC_Bd == np->tok);
- assert(np->data.Bd);
- n->data.Bd = np->data.Bd;
return(1);
}
- assert(NULL == n->data.Bd);
- n->data.Bd = mandoc_calloc(1, sizeof(struct mdoc_bd));
-
/* LINTED */
for (i = 0; n->args && i < (int)n->args->argc; i++) {
dt = DISP__NONE;
/* NB: this can be empty! */
if (n->args->argv[i].sz) {
offs = n->args->argv[i].value[0];
- dup = (NULL != n->data.Bd->offs);
+ dup = (NULL != n->norm->Bd.offs);
break;
}
mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
break;
case (MDOC_Compact):
comp = 1;
- dup = n->data.Bd->comp;
+ dup = n->norm->Bd.comp;
break;
default:
abort();
/* Make our auxiliary assignments. */
if (offs && ! dup)
- n->data.Bd->offs = offs;
+ n->norm->Bd.offs = offs;
if (comp && ! dup)
- n->data.Bd->comp = comp;
+ n->norm->Bd.comp = comp;
/* Check whether a type has already been assigned. */
- if (DISP__NONE != dt && n->data.Bd->type != DISP__NONE)
+ if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
/* Make our type assignment. */
- if (DISP__NONE != dt && n->data.Bd->type == DISP__NONE)
- n->data.Bd->type = dt;
+ if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
+ n->norm->Bd.type = dt;
}
- if (DISP__NONE == n->data.Bd->type) {
+ if (DISP__NONE == n->norm->Bd.type) {
mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
- n->data.Bd->type = DISP_ragged;
+ n->norm->Bd.type = DISP_ragged;
}
return(1);
if (MDOC_BLOCK != n->type)
return(1);
- /*
- * FIXME: this can probably be lifted if we make the It into
- * something else on-the-fly?
- */
return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
}
n->args->argv[i].pos, MANDOCERR_IGNARGV);
if (MDOC_Split == n->args->argv[0].arg)
- n->data.An.auth = AUTH_split;
+ n->norm->An.auth = AUTH_split;
else if (MDOC_Nosplit == n->args->argv[0].arg)
- n->data.An.auth = AUTH_nosplit;
+ n->norm->An.auth = AUTH_nosplit;
else
abort();
pre_dt(PRE_ARGS)
{
- if (0 == mdoc->meta.date || mdoc->meta.os)
+ if (NULL == mdoc->meta.date || mdoc->meta.os)
mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
if (mdoc->meta.title)
pre_os(PRE_ARGS)
{
- if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
+ if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
if (mdoc->meta.os)
assert(np);
assert(MDOC_HEAD == np->type);
assert(MDOC_Bf == np->tok);
- assert(np->data.Bf);
- mdoc->last->data.Bf = np->data.Bf;
return(1);
}
np = mdoc->last;
assert(MDOC_BLOCK == np->parent->type);
assert(MDOC_Bf == np->parent->tok);
- np->data.Bf = mandoc_calloc(1, sizeof(struct mdoc_bf));
/*
* Cannot have both argument and parameter.
if (np->parent->args) {
arg = np->parent->args->argv[0].arg;
if (MDOC_Emphasis == arg)
- np->data.Bf->font = FONT_Em;
+ np->norm->Bf.font = FONT_Em;
else if (MDOC_Literal == arg)
- np->data.Bf->font = FONT_Li;
+ np->norm->Bf.font = FONT_Li;
else if (MDOC_Symbolic == arg)
- np->data.Bf->font = FONT_Sy;
+ np->norm->Bf.font = FONT_Sy;
else
abort();
return(1);
/* Extract parameter into data. */
if (0 == strcmp(np->child->string, "Em"))
- np->data.Bf->font = FONT_Em;
+ np->norm->Bf.font = FONT_Em;
else if (0 == strcmp(np->child->string, "Li"))
- np->data.Bf->font = FONT_Li;
+ np->norm->Bf.font = FONT_Li;
else if (0 == strcmp(np->child->string, "Sy"))
- np->data.Bf->font = FONT_Sy;
+ np->norm->Bf.font = FONT_Sy;
else
mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
char *buf;
size_t sz;
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
+
assert(mdoc->last->child);
assert(MDOC_TEXT == mdoc->last->child->type);
/*
* The Vt macro comes in both ELEM and BLOCK form, both of which
* have different syntaxes (yet more context-sensitive
- * behaviour). ELEM types must have a child; BLOCK types,
+ * behaviour). ELEM types must have a child, which is already
+ * guaranteed by the in_line parsing routine; BLOCK types,
* specifically the BODY, should only have TEXT children.
*/
- if (MDOC_ELEM == mdoc->last->type)
- return(eerr_ge1(mdoc));
if (MDOC_BODY != mdoc->last->type)
return(1);
struct mdoc_node *np;
np = mdoc->last;
- if (AUTH__NONE != np->data.An.auth && np->child)
- return(eerr_eq0(mdoc));
+ if (AUTH__NONE == np->norm->An.auth) {
+ if (0 == np->child)
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
+ } else if (np->child)
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
- /*
- * FIXME: make this ewarn and make sure that the front-ends
- * don't print the arguments.
- */
- if (AUTH__NONE != np->data.An.auth || np->child)
- return(1);
-
- mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS);
return(1);
}
static int
post_it(POST_ARGS)
{
- int i, cols, rc;
+ int i, cols;
enum mdoc_list lt;
struct mdoc_node *n, *c;
enum mandocerr er;
return(1);
n = mdoc->last->parent->parent;
- assert(n->data.Bl);
- lt = n->data.Bl->type;
+ lt = n->norm->Bl.type;
if (LIST__NONE == lt) {
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
break;
case (LIST_column):
- cols = (int)n->data.Bl->ncols;
+ cols = (int)n->norm->Bl.ncols;
assert(NULL == mdoc->last->head->child);
else
er = MANDOCERR_SYNTARGCOUNT;
- rc = mdoc_vmsg(mdoc, er,
- mdoc->last->line, mdoc->last->pos,
+ mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
+ mdoc->last->pos,
"columns == %d (have %d)", cols, i);
- return(rc);
+ return(MANDOCERR_ARGCOUNT == er);
default:
break;
}
n = mdoc->last;
- if (LIST_tag == n->data.Bl->type &&
- NULL == n->data.Bl->width) {
+ if (LIST_tag == n->norm->Bl.type &&
+ NULL == n->norm->Bl.width) {
if ( ! post_bl_block_tag(mdoc))
return(0);
- } else if (NULL != n->data.Bl->width) {
+ } else if (NULL != n->norm->Bl.width) {
if ( ! post_bl_block_width(mdoc))
return(0);
} else
return(1);
- assert(n->data.Bl->width);
+ assert(n->norm->Bl.width);
return(1);
}
* the macro's width as set in share/tmac/mdoc/doc-common.
*/
- if (0 == strcmp(n->data.Bl->width, "Ds"))
+ if (0 == strcmp(n->norm->Bl.width, "Ds"))
width = 6;
- else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width)))
+ else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
return(1);
- else if (0 == (width = mdoc_macro2len(tok))) {
+ else if (0 == (width = macro2len(tok))) {
mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
return(1);
}
n->args->argv[i].value[0] = mandoc_strdup(buf);
/* Set our width! */
- n->data.Bl->width = n->args->argv[i].value[0];
+ n->norm->Bl.width = n->args->argv[i].value[0];
return(1);
}
break;
}
- if (0 != (ssz = mdoc_macro2len(nn->tok)))
+ if (0 != (ssz = macro2len(nn->tok)))
sz = ssz;
break;
n->args->argv[i].value[0] = mandoc_strdup(buf);
/* Set our width! */
- n->data.Bl->width = n->args->argv[i].value[0];
+ n->norm->Bl.width = n->args->argv[i].value[0];
return(1);
}
struct mdoc_node *np, *nn, *nnp;
int i, j;
- if (LIST_column != mdoc->last->data.Bl->type)
+ if (LIST_column != mdoc->last->norm->Bl.type)
/* FIXME: this should be ERROR class... */
return(hwarn_eq0(mdoc));
* lists, but I'll leave that for another day.
*/
- if (mdoc->last->data.Bl->ncols && mdoc->last->nchild) {
+ if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
return(0);
} else if (NULL == mdoc->last->child)
np->args->argv[j].value = mandoc_malloc
((size_t)mdoc->last->nchild * sizeof(char *));
- mdoc->last->data.Bl->ncols = np->args->argv[j].sz;
- mdoc->last->data.Bl->cols = (const char **)np->args->argv[j].value;
+ mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
+ mdoc->last->norm->Bl.cols = (const char **)np->args->argv[j].value;
for (i = 0, nn = mdoc->last->child; nn; i++) {
np->args->argv[j].value[i] = nn->string;
return(post_bl_block(mdoc));
if (MDOC_BODY != mdoc->last->type)
return(1);
- if (NULL == mdoc->last->child)
- return(1);
- /*
- * We only allow certain children of `Bl'. This is usually on
- * `It', but apparently `Sm' occurs here and there, so we let
- * that one through, too.
- */
-
- /* LINTED */
for (n = mdoc->last->child; n; n = n->next) {
- if (MDOC_BLOCK == n->type && MDOC_It == n->tok)
- continue;
- if (MDOC_Sm == n->tok)
+ switch (n->tok) {
+ case (MDOC_Lp):
+ /* FALLTHROUGH */
+ case (MDOC_Pp):
+ mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
+ /* FALLTHROUGH */
+ case (MDOC_It):
+ /* FALLTHROUGH */
+ case (MDOC_Sm):
continue;
+ default:
+ break;
+ }
+
mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
return(0);
}
ebool(struct mdoc *mdoc)
{
- if (NULL == mdoc->last->child)
+ if (NULL == mdoc->last->child) {
+ mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
+ mdoc_node_delete(mdoc, mdoc->last);
return(1);
+ }
+ check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
assert(MDOC_TEXT == mdoc->last->child->type);
static int
post_st(POST_ARGS)
{
- const char *p;
+ struct mdoc_node *ch;
+ const char *p;
- assert(MDOC_TEXT == mdoc->last->child->type);
+ if (NULL == (ch = mdoc->last->child)) {
+ mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
+ mdoc_node_delete(mdoc, mdoc->last);
+ return(1);
+ }
- p = mdoc_a2st(mdoc->last->child->string);
+ assert(MDOC_TEXT == ch->type);
- if (p == NULL) {
+ if (NULL == (p = mdoc_a2st(ch->string))) {
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
mdoc_node_delete(mdoc, mdoc->last);
} else {
- free(mdoc->last->child->string);
- mdoc->last->child->string = mandoc_strdup(p);
+ free(ch->string);
+ ch->string = mandoc_strdup(p);
}
return(1);
struct mdoc_node *nn, *next, *prev;
int i, j;
- if (MDOC_BODY != mdoc->last->type)
+ switch (mdoc->last->type) {
+ case (MDOC_HEAD):
+ check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
+ return(1);
+ case (MDOC_BODY):
+ if (mdoc->last->child)
+ break;
+ check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
return(1);
+ default:
+ return(1);
+ }
/*
* Make sure only certain types of nodes are allowed within the
break;
if (i < RSORD_MAX) {
+ if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
+ mdoc->last->norm->Rs.quote_T++;
next = nn->next;
continue;
}
return(1);
}
+static int
+post_ns(POST_ARGS)
+{
+
+ if (MDOC_LINE & mdoc->last->flags)
+ mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
+ return(1);
+}
+
static int
post_sh(POST_ARGS)
{
if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ))
return(0);
- sec = mdoc_str2sec(buf);
+ sec = a2sec(buf);
/* The NAME should be first. */
return(1);
}
+static int
+post_ignpar(POST_ARGS)
+{
+ struct mdoc_node *np;
+
+ if (MDOC_BODY != mdoc->last->type)
+ return(1);
+
+ if (NULL != (np = mdoc->last->child))
+ if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
+ mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
+ mdoc_node_delete(mdoc, np);
+ }
+
+ if (NULL != (np = mdoc->last->last))
+ if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
+ mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
+ mdoc_node_delete(mdoc, np);
+ }
+
+ return(1);
+}
+
static int
pre_par(PRE_ARGS)
{
if (NULL == mdoc->last)
return(1);
+ if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
+ return(1);
/*
* Don't allow prior `Lp' or `Pp' prior to a paragraph-type
if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)
return(1);
-
- if (MDOC_Bl == n->tok && n->data.Bl->comp)
+ if (MDOC_Bl == n->tok && n->norm->Bl.comp)
+ return(1);
+ if (MDOC_Bd == n->tok && n->norm->Bd.comp)
return(1);
- if (MDOC_Bd == n->tok && n->data.Bd->comp)
+ if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
return(1);
mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
mdoc->flags |= MDOC_LITERAL;
break;
case (MDOC_Bd):
- assert(n->data.Bd);
- if (DISP_literal == n->data.Bd->type)
+ if (DISP_literal == n->norm->Bd.type)
mdoc->flags |= MDOC_LITERAL;
- if (DISP_unfilled == n->data.Bd->type)
+ if (DISP_unfilled == n->norm->Bd.type)
mdoc->flags |= MDOC_LITERAL;
break;
default:
char buf[DATESIZE];
struct mdoc_node *n;
- n = mdoc->last;
+ if (mdoc->meta.date)
+ free(mdoc->meta.date);
- if (NULL == n->child) {
- mdoc->meta.date = time(NULL);
+ n = mdoc->last;
+ if (NULL == n->child || '\0' == n->child->string[0]) {
+ mdoc->meta.date = mandoc_normdate
+ (mdoc->parse, NULL, n->line, n->pos);
return(1);
}
if ( ! concat(mdoc, buf, n->child, DATESIZE))
return(0);
- mdoc->meta.date = mandoc_a2time
- (MTIME_MDOCDATE | MTIME_CANONICAL, buf);
-
- if (0 == mdoc->meta.date) {
- mdoc_nmsg(mdoc, n, MANDOCERR_BADDATE);
- mdoc->meta.date = time(NULL);
- }
+ mdoc->meta.date = mandoc_normdate
+ (mdoc->parse, buf, n->line, n->pos);
return(1);
}
return(1);
}
+static int
+post_bx(POST_ARGS)
+{
+ struct mdoc_node *n;
+
+ /*
+ * Make `Bx's second argument always start with an uppercase
+ * letter. Groff checks if it's an "accepted" term, but we just
+ * uppercase blindly.
+ */
+
+ n = mdoc->last->child;
+ if (n && NULL != (n = n->next))
+ *n->string = (char)toupper
+ ((unsigned char)*n->string);
+
+ return(1);
+}
+
static int
post_os(POST_ARGS)
{
return(0);
}
#else /*!OSNAME */
- if (uname(&utsname)) {
+ if (-1 == uname(&utsname)) {
mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
mdoc->meta.os = mandoc_strdup("UNKNOWN");
return(post_prol(mdoc));
return(1);
}
+static enum mdoc_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(SEC_CUSTOM);
+}
+
+static size_t
+macro2len(enum mdoct macro)
+{
+
+ switch (macro) {
+ case(MDOC_Ad):
+ return(12);
+ case(MDOC_Ao):
+ return(12);
+ case(MDOC_An):
+ return(12);
+ case(MDOC_Aq):
+ return(12);
+ case(MDOC_Ar):
+ return(12);
+ case(MDOC_Bo):
+ return(12);
+ case(MDOC_Bq):
+ return(12);
+ case(MDOC_Cd):
+ return(12);
+ case(MDOC_Cm):
+ return(10);
+ case(MDOC_Do):
+ return(10);
+ case(MDOC_Dq):
+ return(12);
+ case(MDOC_Dv):
+ return(12);
+ case(MDOC_Eo):
+ return(12);
+ case(MDOC_Em):
+ return(10);
+ case(MDOC_Er):
+ return(17);
+ case(MDOC_Ev):
+ return(15);
+ case(MDOC_Fa):
+ return(12);
+ case(MDOC_Fl):
+ return(10);
+ case(MDOC_Fo):
+ return(16);
+ case(MDOC_Fn):
+ return(16);
+ case(MDOC_Ic):
+ return(10);
+ case(MDOC_Li):
+ return(16);
+ case(MDOC_Ms):
+ return(6);
+ case(MDOC_Nm):
+ return(10);
+ case(MDOC_No):
+ return(12);
+ case(MDOC_Oo):
+ return(10);
+ case(MDOC_Op):
+ return(14);
+ case(MDOC_Pa):
+ return(32);
+ case(MDOC_Pf):
+ return(12);
+ case(MDOC_Po):
+ return(12);
+ case(MDOC_Pq):
+ return(12);
+ case(MDOC_Ql):
+ return(16);
+ case(MDOC_Qo):
+ return(12);
+ case(MDOC_So):
+ return(12);
+ case(MDOC_Sq):
+ return(12);
+ case(MDOC_Sy):
+ return(6);
+ case(MDOC_Sx):
+ return(16);
+ case(MDOC_Tn):
+ return(10);
+ case(MDOC_Va):
+ return(12);
+ case(MDOC_Vt):
+ return(12);
+ case(MDOC_Xr):
+ return(10);
+ default:
+ break;
+ };
+ return(0);
+}