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_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 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 post_vs(CHKARGS) { if (NULL != n->prev) return; switch (n->parent->tok) { case MAN_SH: case MAN_SS: mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, "%s after %s", man_macronames[n->tok], man_macronames[n->parent->tok]); /* FALLTHROUGH */ case TOKEN_NONE: /* * Don't warn about this because it occurs in pod2man * and would cause considerable (unfixable) warnage. */ roff_node_delete(man, n); break; default: break; } }
static void check_par(CHKARGS) { switch (n->type) { case ROFFT_BLOCK: if (0 == n->body->nchild) roff_node_delete(man, n); break; case ROFFT_BODY: if (0 == n->nchild) mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, "%s empty", man_macronames[n->tok]); break; case ROFFT_HEAD: if (n->nchild) mandoc_vmsg(MANDOCERR_ARG_SKIP, man->parse, n->line, n->pos, "%s %s%s", man_macronames[n->tok], n->child->string, n->nchild > 1 ? " ..." : ""); break; default: break; } }
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; }
static void roff_valid_sp(ROFF_VALID_ARGS) { struct roff_node *np; if ((np = n->prev) == NULL) return; switch (np->tok) { case ROFF_br: mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos, "br before sp"); roff_node_delete(man, np); break; case MDOC_Pp: mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "sp after Pp"); roff_node_delete(man, n); break; default: break; } }
static void roff_valid_ft(ROFF_VALID_ARGS) { const char *cp; if (n->child == NULL) { man->next = ROFF_NEXT_CHILD; roff_word_alloc(man, n->line, n->pos, "P"); man->last = n; return; } cp = n->child->string; if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR) return; mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp); roff_node_delete(man, n); }
static void post_IP(CHKARGS) { switch (n->type) { case ROFFT_BLOCK: if (n->head->child == NULL && n->body->child == NULL) roff_node_delete(man, n); break; case ROFFT_BODY: if (n->parent->head->child == NULL && n->child == NULL) mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos, "%s empty", roff_name[n->tok]); break; default: break; } }
static void post_IP(CHKARGS) { switch (n->type) { case ROFFT_BLOCK: if (0 == n->head->nchild && 0 == n->body->nchild) roff_node_delete(man, n); break; case ROFFT_BODY: if (0 == n->parent->head->nchild && 0 == n->nchild) mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, "%s empty", man_macronames[n->tok]); break; default: break; } }
static void post_TH(CHKARGS) { struct roff_node *nb; const char *p; free(man->meta.title); free(man->meta.vol); free(man->meta.os); free(man->meta.msec); free(man->meta.date); man->meta.title = man->meta.vol = man->meta.date = man->meta.msec = man->meta.os = NULL; nb = n; /* ->TITLE<- MSEC DATE OS VOL */ n = n->child; if (n && n->string) { for (p = n->string; '\0' != *p; p++) { /* Only warn about this once... */ if (isalpha((unsigned char)*p) && ! isupper((unsigned char)*p)) { mandoc_vmsg(MANDOCERR_TITLE_CASE, man->parse, n->line, n->pos + (p - n->string), "TH %s", n->string); break; } } man->meta.title = mandoc_strdup(n->string); } else { man->meta.title = mandoc_strdup(""); mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, nb->line, nb->pos, "TH"); } /* TITLE ->MSEC<- DATE OS VOL */ if (n) n = n->next; if (n && n->string) man->meta.msec = mandoc_strdup(n->string); else { man->meta.msec = mandoc_strdup(""); mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse, nb->line, nb->pos, "TH %s", man->meta.title); } /* TITLE MSEC ->DATE<- OS VOL */ if (n) n = n->next; if (n && n->string && '\0' != n->string[0]) { man->meta.date = man->quick ? mandoc_strdup(n->string) : mandoc_normdate(man->parse, n->string, n->line, n->pos); } else { man->meta.date = mandoc_strdup(""); mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, n ? n->line : nb->line, n ? n->pos : nb->pos, "TH"); } /* TITLE MSEC DATE ->OS<- VOL */ if (n && (n = n->next)) man->meta.os = mandoc_strdup(n->string); else if (man->defos != NULL) man->meta.os = mandoc_strdup(man->defos); /* TITLE MSEC DATE OS ->VOL<- */ /* If missing, use the default VOL name for MSEC. */ if (n && (n = n->next)) man->meta.vol = mandoc_strdup(n->string); else if ('\0' != man->meta.msec[0] && (NULL != (p = mandoc_a2msec(man->meta.msec)))) man->meta.vol = mandoc_strdup(p); if (n != NULL && (n = n->next) != NULL) mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, n->line, n->pos, "TH ... %s", n->string); /* * Remove the `TH' node after we've processed it for our * meta-data. */ roff_node_delete(man, man->last); }
void man_breakscope(struct roff_man *man, int tok) { struct roff_node *n; /* * An element next line scope is open, * and the new macro is not allowed inside elements. * Delete the element that is being broken. */ if (man->flags & MAN_ELINE && (tok < MAN_TH || ! (man_macros[tok].flags & MAN_NSCOPED))) { n = man->last; assert(n->type != ROFFT_TEXT); if (man_macros[n->tok].flags & MAN_NSCOPED) n = n->parent; mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", roff_name[tok], roff_name[n->tok]); roff_node_delete(man, n); man->flags &= ~MAN_ELINE; } /* * Weird special case: * Switching fill mode closes section headers. */ if (man->flags & MAN_BLINE && (tok == MAN_nf || tok == MAN_fi) && (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) { n = man->last; man_unscope(man, n); roff_body_alloc(man, n->line, n->pos, n->tok); man->flags &= ~MAN_BLINE; } /* * A block header next line scope is open, * and the new macro is not allowed inside block headers. * Delete the block that is being broken. */ if (man->flags & MAN_BLINE && (tok < MAN_TH || man_macros[tok].flags & MAN_BSCOPE)) { n = man->last; if (n->type == ROFFT_TEXT) n = n->parent; if ( ! (man_macros[n->tok].flags & MAN_BSCOPE)) n = n->parent; assert(n->type == ROFFT_HEAD); n = n->parent; assert(n->type == ROFFT_BLOCK); assert(man_macros[n->tok].flags & MAN_SCOPED); mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", roff_name[tok], roff_name[n->tok]); roff_node_delete(man, n); man->flags &= ~MAN_BLINE; } }