static void post_SH(CHKARGS) { struct roff_node *nc; if (n->type != ROFFT_BODY || (nc = n->child) == NULL) return; if (nc->tok == MAN_PP && nc->body->child != NULL) { while (nc->body->last != NULL) { man->next = ROFF_NEXT_CHILD; roff_node_relink(man, nc->body->last); man->last = n; } } if (nc->tok == MAN_PP || nc->tok == ROFF_sp || nc->tok == ROFF_br) { mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos, "%s after %s", roff_name[nc->tok], roff_name[n->tok]); roff_node_delete(man, nc); } /* * Trailing PP is empty, so it is deleted by check_par(). * Trailing sp is significant. */ if ((nc = n->last) != NULL && nc->tok == ROFF_br) { mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos, "%s at the end of %s", roff_name[nc->tok], roff_name[n->tok]); roff_node_delete(man, nc); } }
static void roff_valid_br(ROFF_VALID_ARGS) { struct roff_node *np; if (n->next != NULL && n->next->type == ROFFT_TEXT && *n->next->string == ' ') { mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "br before text line with leading blank"); roff_node_delete(man, n); return; } if ((np = n->prev) == NULL) return; switch (np->tok) { case ROFF_br: case ROFF_sp: case MDOC_Pp: mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "br after %s", roff_name[np->tok]); roff_node_delete(man, n); break; default: break; } }
static void check_root(CHKARGS) { assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0); if (NULL == man->first->child) mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse, n->line, n->pos, NULL); else man->meta.hasbody = 1; if (NULL == man->meta.title) { mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, n->line, n->pos, NULL); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ man->meta.title = mandoc_strdup(""); man->meta.msec = mandoc_strdup(""); man->meta.date = man->quick ? mandoc_strdup("") : mandoc_normdate(man->parse, NULL, n->line, n->pos); } }
void man_state(struct roff_man *man, struct roff_node *n) { switch(n->tok) { case MAN_nf: case MAN_EX: if (man->flags & MAN_LITERAL && ! (n->flags & NODE_VALID)) mandoc_msg(MANDOCERR_NF_SKIP, man->parse, n->line, n->pos, "nf"); man->flags |= MAN_LITERAL; break; case MAN_fi: case MAN_EE: if ( ! (man->flags & MAN_LITERAL) && ! (n->flags & NODE_VALID)) mandoc_msg(MANDOCERR_FI_SKIP, man->parse, n->line, n->pos, "fi"); man->flags &= ~MAN_LITERAL; break; default: break; } man->last->flags |= NODE_VALID; }
static void check_par(CHKARGS) { switch (n->type) { case ROFFT_BLOCK: if (n->body->child == NULL) roff_node_delete(man, n); break; case ROFFT_BODY: if (n->child != NULL && (n->child->tok == ROFF_sp || n->child->tok == ROFF_br)) { mandoc_msg(MANDOCERR_PAR_SKIP, n->child->line, n->child->pos, "%s after %s", roff_name[n->child->tok], roff_name[n->tok]); roff_node_delete(man, n->child); } if (n->child == NULL) mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "%s empty", roff_name[n->tok]); break; case ROFFT_HEAD: if (n->child != NULL) mandoc_msg(MANDOCERR_ARG_SKIP, n->line, n->pos, "%s %s%s", roff_name[n->tok], n->child->string, n->child->next != NULL ? " ..." : ""); break; default: break; } }
static void check_root(CHKARGS) { assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0); if (n->last == NULL || n->last->type == ROFFT_COMMENT) mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL); else man->meta.hasbody = 1; if (NULL == man->meta.title) { mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ man->meta.title = mandoc_strdup(""); man->meta.msec = mandoc_strdup(""); man->meta.date = man->quick ? mandoc_strdup("") : mandoc_normdate(man, NULL, n->line, n->pos); } if (man->meta.os_e && (man->meta.rcsids & (1 << man->meta.os_e)) == 0) mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0, man->meta.os_e == MANDOC_OS_OPENBSD ? "(OpenBSD)" : "(NetBSD)"); }
/* ARGSUSED */ static enum rofferr roff_ccond(ROFF_ARGS) { if (NULL == r->last) { mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } switch (r->last->tok) { case (ROFF_el): /* FALLTHROUGH */ case (ROFF_ie): /* FALLTHROUGH */ case (ROFF_if): break; default: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if (r->last->endspan > -1) { mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); return(ROFF_IGN); }
static void cell(struct tbl_node *tbl, struct tbl_row *rp, int ln, const char *p, int *pos) { int i; enum tbl_cellt c; /* Handle leading vertical lines */ while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') { if (p[*pos] == '|') { if (rp->vert < 2) rp->vert++; else mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, tbl->parse, ln, *pos, NULL); } (*pos)++; } again: while (p[*pos] == ' ' || p[*pos] == '\t') (*pos)++; if (p[*pos] == '.' || p[*pos] == '\0') return; /* Parse the column position (`c', `l', `r', ...). */ for (i = 0; i < KEYS_MAX; i++) if (tolower((unsigned char)p[*pos]) == keys[i].name) break; if (i == KEYS_MAX) { mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, ln, *pos, "%c", p[*pos]); (*pos)++; goto again; } c = keys[i].key; /* Special cases of spanners. */ if (c == TBL_CELL_SPAN) { if (rp->last == NULL) mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, tbl->parse, ln, *pos, NULL); else if (rp->last->pos == TBL_CELL_HORIZ || rp->last->pos == TBL_CELL_DHORIZ) c = rp->last->pos; } else if (c == TBL_CELL_DOWN && rp == tbl->first_row) mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, tbl->parse, ln, *pos, NULL); (*pos)++; /* Allocate cell then parse its modifiers. */ mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos); }
static void post_OP(CHKARGS) { if (n->child == NULL) mandoc_msg(MANDOCERR_OP_EMPTY, n->line, n->pos, "OP"); else if (n->child->next != NULL && n->child->next->next != NULL) { n = n->child->next->next; mandoc_msg(MANDOCERR_ARG_EXCESS, n->line, n->pos, "OP ... %s", n->string); } }
void tbl_restart(int line, int pos, struct tbl_node *tbl) { if (TBL_PART_CDATA == tbl->part) mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, tbl->line, tbl->pos, NULL); tbl->part = TBL_PART_LAYOUT; tbl->line = line; tbl->pos = pos; if (NULL == tbl->first_span || NULL == tbl->first_span->first) mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, tbl->line, tbl->pos, NULL); }
void tbl_end(struct tbl_node *tbl) { if (NULL == tbl->first_span || NULL == tbl->first_span->first) mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, tbl->line, tbl->pos, NULL); if (tbl->last_span) tbl->last_span->flags |= TBL_SPAN_LAST; if (TBL_PART_CDATA == tbl->part) mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, tbl->line, tbl->pos, NULL); }
/* * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. * They're unusual because they're basically free-form text until a * macro is encountered. */ static void phrase_ta(MACRO_PROT_ARGS) { struct roff_node *body, *n; /* Make sure we are in a column list or ignore this macro. */ body = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { if (n->flags & MDOC_ENDED) continue; if (n->tok == MDOC_It && n->type == ROFFT_BODY) body = n; if (n->tok == MDOC_Bl) break; } if (n == NULL || n->norm->Bl.type != LIST_column) { mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse, line, ppos, "Ta"); return; } /* Advance to the next column. */ rew_last(mdoc, body); roff_body_alloc(mdoc, line, ppos, MDOC_It); parse_rest(mdoc, TOKEN_NONE, line, pos, buf); }
static void mparse_end(struct mparse *curp) { if (MANDOCLEVEL_FATAL <= curp->file_status) return; if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { assert(MANDOCLEVEL_FATAL <= curp->file_status); return; } if (curp->man && ! man_endparse(curp->man)) { assert(MANDOCLEVEL_FATAL <= curp->file_status); return; } if ( ! (curp->man || curp->mdoc)) { mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL); curp->file_status = MANDOCLEVEL_FATAL; return; } roff_endparse(curp->roff); }
int mparse_open(struct mparse *curp, const char *file) { char *cp; int fd; curp->file = file; cp = strrchr(file, '.'); curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz")); /* First try to use the filename as it is. */ if ((fd = open(file, O_RDONLY)) != -1) return fd; /* * If that doesn't work and the filename doesn't * already end in .gz, try appending .gz. */ if ( ! curp->gzip) { mandoc_asprintf(&cp, "%s.gz", file); fd = open(cp, O_RDONLY); free(cp); if (fd != -1) { curp->gzip = 1; return fd; } } /* Neither worked, give up. */ mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno)); return -1; }
static void in_line_eoln(MACRO_PROT_ARGS) { struct roff_node *n; struct mdoc_arg *arg; if ((tok == MDOC_Pp || tok == MDOC_Lp) && ! (mdoc->flags & MDOC_SYNOPSIS)) { n = mdoc->last; if (mdoc->next == ROFF_NEXT_SIBLING) n = n->parent; if (n->tok == MDOC_Nm) rew_last(mdoc, n->parent); } if (buf[*pos] == '\0' && (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) { mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, line, ppos, mdoc_macronames[tok]); return; } mdoc_argv(mdoc, line, tok, &arg, pos, buf); mdoc_elem_alloc(mdoc, line, ppos, tok, arg); if (parse_rest(mdoc, tok, line, pos, buf)) return; rew_elem(mdoc, tok); }
static char * roff_getname(struct roff *r, char **cpp, int ln, int pos) { char *name, *cp; name = *cpp; if ('\0' == *name) return(name); /* Read until end of name. */ for (cp = name; '\0' != *cp && ' ' != *cp; cp++) { if ('\\' != *cp) continue; cp++; if ('\\' == *cp) continue; mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL); *cp = '\0'; name = cp; } /* Nil-terminate name. */ if ('\0' != *cp) *(cp++) = '\0'; /* Read past spaces. */ while (' ' == *cp) cp++; *cpp = cp; return(name); }
/* ARGSUSED */ static enum rofferr roff_EN(ROFF_ARGS) { mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); }
void man_unscope(struct roff_man *man, const struct roff_node *to) { struct roff_node *n; to = to->parent; n = man->last; while (n != to) { /* Reached the end of the document? */ if (to == NULL && ! (n->flags & MAN_VALID)) { if (man->flags & (MAN_BLINE | MAN_ELINE) && man_macros[n->tok].flags & MAN_SCOPED) { mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "EOF breaks %s", man_macronames[n->tok]); if (man->flags & MAN_ELINE) man->flags &= ~MAN_ELINE; else { assert(n->type == ROFFT_HEAD); n = n->parent; man->flags &= ~MAN_BLINE; } man->last = n; n = n->parent; roff_node_delete(man, man->last); continue; } if (n->type == ROFFT_BLOCK && man_macros[n->tok].fp == blk_exp) mandoc_msg(MANDOCERR_BLK_NOEND, man->parse, n->line, n->pos, man_macronames[n->tok]); } /* * We might delete the man->last node * in the post-validation phase. * Save a pointer to the parent such that * we know where to continue the iteration. */ man->last = n; n = n->parent; man->last->flags |= MAN_VALID; } /* * If we ended up at the parent of the node we were * supposed to rewind to, that means the target node * got deleted, so add the next node we parse as a child * of the parent instead of as a sibling of the target. */ man->next = (man->last == to) ? ROFF_NEXT_CHILD : ROFF_NEXT_SIBLING; }
/* * Close out a generic explicit macro. */ void blk_close(MACRO_PROT_ARGS) { int ntok; const struct roff_node *nn; char *p; int nrew, target; nrew = 1; switch (tok) { case MAN_RE: ntok = MAN_RS; if ( ! man_args(man, line, pos, buf, &p)) break; for (nn = man->last->parent; nn; nn = nn->parent) if (nn->tok == ntok && nn->type == ROFFT_BLOCK) nrew++; target = strtol(p, &p, 10); if (*p != '\0') mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line, p - buf, "RE ... %s", p); if (target == 0) target = 1; nrew -= target; if (nrew < 1) { mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse, line, ppos, "RE %d", target); return; } break; case MAN_UE: ntok = MAN_UR; break; default: abort(); } for (nn = man->last->parent; nn; nn = nn->parent) if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew) break; if (nn == NULL) { mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse, line, ppos, man_macronames[tok]); rew_scope(man, MAN_PP); } else { line = man->last->line; ppos = man->last->pos; ntok = man->last->tok; man_unscope(man, nn); /* Move a trailing paragraph behind the block. */ if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) { *pos = strlen(buf); blk_imp(man, ntok, line, ppos, pos, buf); } } }
static void post_UR(CHKARGS) { if (n->type == ROFFT_HEAD && n->child == NULL) mandoc_msg(MANDOCERR_UR_NOHEAD, n->line, n->pos, "%s", roff_name[n->tok]); check_part(man, n); }
static void check_part(CHKARGS) { if (n->type == MAN_BODY && n->child == NULL) mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse, n->line, n->pos, man_macronames[n->tok]); }
static void check_part(CHKARGS) { if (n->type == ROFFT_BODY && n->child == NULL) mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos, "%s", roff_name[n->tok]); }
/* ARGSUSED */ static enum rofferr roff_line_ignore(ROFF_ARGS) { if (ROFF_it == tok) mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); return(ROFF_IGN); }
static void post_fi(CHKARGS) { if ( ! (MAN_LITERAL & man->flags)) mandoc_msg(MANDOCERR_FI_SKIP, man->parse, n->line, n->pos, "fi"); man->flags &= ~MAN_LITERAL; }
static void post_nf(CHKARGS) { if (man->flags & MAN_LITERAL) mandoc_msg(MANDOCERR_NF_SKIP, man->parse, n->line, n->pos, "nf"); man->flags |= MAN_LITERAL; }
static int check_part(CHKARGS) { if (MAN_BODY == n->type && 0 == n->nchild) mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line, n->pos, "want children (have none)"); return(1); }
void roff_endparse(struct roff *r) { if (r->last) mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->last->line, r->last->col, NULL); if (r->eqn) { mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->eqn->eqn.ln, r->eqn->eqn.pos, NULL); eqn_end(&r->eqn); } if (r->tbl) { mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->tbl->line, r->tbl->pos, NULL); tbl_end(&r->tbl); } }
char * mandoc_normdate(struct mparse *parse, char *in, int ln, int pos) { char *out; time_t t; if (NULL == in || '\0' == *in || 0 == strcmp(in, "$" "Mdocdate$")) { mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL); time(&t); } else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) && !a2time(&t, "%b %d, %Y", in) && !a2time(&t, "%Y-%m-%d", in)) { mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL); t = 0; } out = t ? time2a(t) : NULL; return(out ? out : mandoc_strdup(in)); }
/* ARGSUSED */ static enum rofferr roff_T_(ROFF_ARGS) { if (NULL == r->tbl) mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); else tbl_restart(ppos, ln, r->tbl); return(ROFF_IGN); }
/* ARGSUSED */ static enum rofferr roff_cblock(ROFF_ARGS) { /* * A block-close `..' should only be invoked as a child of an * ignore macro, otherwise raise a warning and just ignore it. */ if (NULL == r->last) { mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } switch (r->last->tok) { case (ROFF_am): /* FALLTHROUGH */ case (ROFF_ami): /* FALLTHROUGH */ case (ROFF_am1): /* FALLTHROUGH */ case (ROFF_de): /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ /* FALLTHROUGH */ case (ROFF_dei): /* FALLTHROUGH */ case (ROFF_ig): break; default: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); return(ROFF_IGN); }