static int check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) { assert(n->parent); if ((MDOC_ROOT == t || tok == n->parent->tok) && (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]); return(0); }
static int swarn(struct mdoc *mdoc, enum mdoc_type type, int line, int pos, const struct mdoc_node *p) { const char *n, *t, *tt; enum mandocerr ec; n = t = "<root>"; tt = "block"; switch (type) { case (MDOC_BODY): tt = "multi-line"; break; case (MDOC_HEAD): tt = "line"; break; default: break; } switch (p->type) { case (MDOC_BLOCK): n = mdoc_macronames[p->tok]; t = "block"; break; case (MDOC_BODY): n = mdoc_macronames[p->tok]; t = "multi-line"; break; case (MDOC_HEAD): n = mdoc_macronames[p->tok]; t = "line"; break; default: break; } ec = (MDOC_IGN_SCOPE & mdoc->pflags) ? MANDOCERR_SCOPE : MANDOCERR_SYNTSCOPE; return(mdoc_vmsg(mdoc, ec, line, pos, "%s scope breaks %s of %s", tt, t, n)); }
static int check_count(struct mdoc *m, enum mdoc_type type, enum check_lvl lvl, enum check_ineq ineq, int val) { const char *p; enum mandocerr t; if (m->last->type != type) return(1); switch (ineq) { case (CHECK_LT): p = "less than "; if (m->last->nchild < val) return(1); break; case (CHECK_GT): p = "more than "; if (m->last->nchild > val) return(1); break; case (CHECK_EQ): p = ""; if (val == m->last->nchild) return(1); break; default: abort(); /* NOTREACHED */ } t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; return(mdoc_vmsg(m, t, m->last->line, m->last->pos, "want %s%d children (have %d)", p, val, m->last->nchild)); }
/* * Parse a macro line, that is, a line beginning with the control * character. */ static int mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) { enum mdoct tok; int i, j, sv; char mac[5]; struct mdoc_node *n; /* Empty lines are ignored. */ offs++; if ('\0' == buf[offs]) return(1); i = offs; /* Accept tabs/whitespace after the initial control char. */ if (' ' == buf[i] || '\t' == buf[i]) { i++; while (buf[i] && (' ' == buf[i] || '\t' == buf[i])) i++; if ('\0' == buf[i]) return(1); } sv = i; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ j = 0; while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i]) mac[j++] = buf[i++]; mac[j] = '\0'; tok = (j > 1 || j < 4) ? mdoc_hash_find(mac) : MDOC_MAX; if (MDOC_MAX == tok) { mdoc_vmsg(m, MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1); return(1); } /* Disregard the first trailing tab, if applicable. */ if ('\t' == buf[i]) i++; /* Jump to the next non-whitespace word. */ while (buf[i] && ' ' == buf[i]) i++; /* * Trailing whitespace. Note that tabs are allowed to be passed * into the parser as "text", so we only warn about spaces here. */ if ('\0' == buf[i] && ' ' == buf[i - 1]) mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE); /* * If an initial macro or a list invocation, divert directly * into macro processing. */ if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) goto err; return(1); } n = m->last; assert(m->last); /* * If the first macro of a `Bl -column', open an `It' block * context around the parsed macro. */ if (MDOC_Bl == n->tok && MDOC_BODY == n->type && LIST_column == n->norm->Bl.type) { m->flags |= MDOC_FREECOL; if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) goto err; return(1); } /* * If we're following a block-level `It' within a `Bl -column' * context (perhaps opened in the above block or in ptext()), * then open an `It' block context around the parsed macro. */ if (MDOC_It == n->tok && MDOC_BLOCK == n->type && NULL != n->parent && MDOC_Bl == n->parent->tok && LIST_column == n->parent->norm->Bl.type) { m->flags |= MDOC_FREECOL; if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) goto err; return(1); } /* Normal processing of a macro. */ if ( ! mdoc_macro(m, tok, ln, sv, &i, buf)) goto err; return(1); err: /* Error out. */ m->flags |= MDOC_HALT; return(0); }
static int post_it(POST_ARGS) { int i, cols, rc; enum mdoc_list lt; struct mdoc_node *n, *c; enum mandocerr er; if (MDOC_BLOCK != mdoc->last->type) return(1); n = mdoc->last->parent->parent; lt = n->norm->Bl.type; if (LIST__NONE == lt) { mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); return(1); } switch (lt) { case (LIST_tag): if (mdoc->last->head->child) break; /* FIXME: give this a dummy value. */ mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); break; case (LIST_hang): /* FALLTHROUGH */ case (LIST_ohang): /* FALLTHROUGH */ case (LIST_inset): /* FALLTHROUGH */ case (LIST_diag): if (NULL == mdoc->last->head->child) mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); break; case (LIST_bullet): /* FALLTHROUGH */ case (LIST_dash): /* FALLTHROUGH */ case (LIST_enum): /* FALLTHROUGH */ case (LIST_hyphen): if (NULL == mdoc->last->body->child) mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); /* FALLTHROUGH */ case (LIST_item): if (mdoc->last->head->child) mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); break; case (LIST_column): cols = (int)n->norm->Bl.ncols; assert(NULL == mdoc->last->head->child); if (NULL == mdoc->last->body->child) mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); for (i = 0, c = mdoc->last->child; c; c = c->next) if (MDOC_BODY == c->type) i++; if (i < cols) er = MANDOCERR_ARGCOUNT; else if (i == cols || i == cols + 1) break; else er = MANDOCERR_SYNTARGCOUNT; rc = mdoc_vmsg(mdoc, er, mdoc->last->line, mdoc->last->pos, "columns == %d (have %d)", cols, i); return(rc); default: break; } return(1); }