static void post_vs(CHKARGS) { if (NULL != n->prev) return; switch (n->parent->tok) { case MAN_SH: /* FALLTHROUGH */ 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 MAN_MAX: /* * Don't warn about this because it occurs in pod2man * and would cause considerable (unfixable) warnage. */ man_node_delete(man, n); break; default: break; } }
static void check_par(CHKARGS) { switch (n->type) { case MAN_BLOCK: if (0 == n->body->nchild) man_node_delete(man, n); break; case MAN_BODY: if (0 == n->nchild) mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, "%s empty", man_macronames[n->tok]); break; case MAN_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; } }
static int post_vs(CHKARGS) { if (NULL != n->prev) return(1); switch (n->parent->tok) { case (MAN_SH): /* FALLTHROUGH */ case (MAN_SS): man_nmsg(man, n, MANDOCERR_IGNPAR); /* FALLTHROUGH */ case (MAN_MAX): /* * Don't warn about this because it occurs in pod2man * and would cause considerable (unfixable) warnage. */ man_node_delete(man, n); break; default: break; } return(1); }
void man_node_delete(struct man *man, struct man_node *p) { while (p->child) man_node_delete(man, p->child); man_node_unlink(man, p); man_node_free(p); }
static void man_free1(struct man *man) { if (man->first) man_node_delete(man, man->first); if (man->meta.title) free(man->meta.title); if (man->meta.source) free(man->meta.source); if (man->meta.date) free(man->meta.date); if (man->meta.vol) free(man->meta.vol); if (man->meta.msec) free(man->meta.msec); }
static int post_IP(CHKARGS) { switch (n->type) { case (MAN_BLOCK): if (0 == n->head->nchild && 0 == n->body->nchild) man_node_delete(man, n); break; case (MAN_BODY): if (0 == n->parent->head->nchild && 0 == n->nchild) man_nmsg(man, n, MANDOCERR_IGNPAR); break; default: break; } return(1); }
static void post_IP(CHKARGS) { switch (n->type) { case MAN_BLOCK: if (0 == n->head->nchild && 0 == n->body->nchild) man_node_delete(man, n); break; case MAN_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 int check_par(CHKARGS) { switch (n->type) { case (MAN_BLOCK): if (0 == n->body->nchild) man_node_delete(man, n); break; case (MAN_BODY): if (0 == n->nchild) man_nmsg(man, n, MANDOCERR_IGNPAR); break; case (MAN_HEAD): if (n->nchild) man_nmsg(man, n, MANDOCERR_ARGSLOST); break; default: break; } return(1); }
static int man_pmacro(struct man *man, int ln, char *buf, int offs) { int i, ppos; enum mant tok; char mac[5]; struct man_node *n; if ('"' == buf[offs]) { man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT); return(1); } else if ('\0' == buf[offs]) return(1); ppos = offs; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ i = 0; while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] && '\t' != buf[offs]) mac[i++] = buf[offs++]; mac[i] = '\0'; tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, ppos, "%s", buf + ppos - 1); return(1); } /* The macro is sane. Jump to the next word. */ while (buf[offs] && ' ' == buf[offs]) offs++; /* * 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[offs] && ' ' == buf[offs - 1]) man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * Remove prior ELINE macro, as it's being clobbered by a new * macro. Note that NSCOPED macros do not close out ELINE * macros---they don't print text---so we let those slip by. */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && man->flags & MAN_ELINE) { n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { n = man->last; /* Might be a text node like 8 in * .TP 8 * .SH foo */ if (MAN_TEXT == n->type) n = n->parent; /* Remove element that didn't end BLINE, if any. */ if ( ! (MAN_BSCOPE & man_macros[n->tok].flags)) n = n->parent; assert(MAN_HEAD == n->type); n = n->parent; assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_BLINE; } /* * Save the fact that we're in the next-line for a block. In * this way, embedded roff instructions can "remember" state * when they exit. */ if (MAN_BLINE & man->flags) man->flags |= MAN_BPLINE; /* Call to handler... */ assert(man_macros[tok].fp); if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) goto err; /* * We weren't in a block-line scope when entering the * above-parsed macro, so return. */ if ( ! (MAN_BPLINE & man->flags)) { man->flags &= ~MAN_ILINE; return(1); } man->flags &= ~MAN_BPLINE; /* * If we're in a block scope, then allow this macro to slip by * without closing scope around it. */ if (MAN_ILINE & man->flags) { man->flags &= ~MAN_ILINE; return(1); } /* * If we've opened a new next-line element scope, then return * now, as the next line will close out the block scope. */ if (MAN_ELINE & man->flags) return(1); /* Close out the block scope opened in the prior line. */ assert(MAN_BLINE & man->flags); man->flags &= ~MAN_BLINE; if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); return(man_body_alloc(man, ln, ppos, man->last->tok)); err: /* Error out. */ man->flags |= MAN_HALT; return(0); }
static int man_pmacro(struct man *man, int ln, char *buf, int offs) { char mac[5]; struct man_node *n; enum mant tok; int i, ppos; int bline; if ('"' == buf[offs]) { mandoc_msg(MANDOCERR_COMMENT_BAD, man->parse, ln, offs, NULL); return(1); } else if ('\0' == buf[offs]) return(1); ppos = offs; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ i = 0; while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] && '\t' != buf[offs]) mac[i++] = buf[offs++]; mac[i] = '\0'; tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { mandoc_msg(MANDOCERR_MACRO, man->parse, ln, ppos, buf + ppos - 1); return(1); } /* The macro is sane. Jump to the next word. */ while (buf[offs] && ' ' == buf[offs]) offs++; /* * 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[offs] && ' ' == buf[offs - 1]) mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, ln, offs - 1, NULL); /* * Remove prior ELINE macro, as it's being clobbered by a new * macro. Note that NSCOPED macros do not close out ELINE * macros---they don't print text---so we let those slip by. */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && man->flags & MAN_ELINE) { n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { n = man->last; /* Might be a text node like 8 in * .TP 8 * .SH foo */ if (MAN_TEXT == n->type) n = n->parent; /* Remove element that didn't end BLINE, if any. */ if ( ! (MAN_BSCOPE & man_macros[n->tok].flags)) n = n->parent; assert(MAN_HEAD == n->type); n = n->parent; assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_BLINE; } /* Remember whether we are in next-line scope for a block head. */ bline = man->flags & MAN_BLINE; /* Call to handler... */ assert(man_macros[tok].fp); if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) return(0); /* In quick mode (for mandocdb), abort after the NAME section. */ if (man->quick && MAN_SH == tok) { n = man->last; if (MAN_BODY == n->type && strcmp(n->prev->child->string, "NAME")) return(2); } /* * If we are in a next-line scope for a block head, * close it out now and switch to the body, * unless the next-line scope is allowed to continue. */ if ( ! bline || man->flags & MAN_ELINE || man_macros[tok].flags & MAN_NSCOPED) return(1); assert(MAN_BLINE & man->flags); man->flags &= ~MAN_BLINE; if ( ! man_unscope(man, man->last->parent)) return(0); return(man_body_alloc(man, ln, ppos, man->last->tok)); }
static void post_TH(CHKARGS) { struct man_node *nb; const char *p; free(man->meta.title); free(man->meta.vol); free(man->meta.source); free(man->meta.msec); free(man->meta.date); man->meta.title = man->meta.vol = man->meta.date = man->meta.msec = man->meta.source = NULL; nb = n; /* ->TITLE<- MSEC DATE SOURCE 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 SOURCE 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<- SOURCE 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 ->SOURCE<- VOL */ if (n && (n = n->next)) man->meta.source = mandoc_strdup(n->string); else if (man->defos != NULL) man->meta.source = mandoc_strdup(man->defos); /* TITLE MSEC DATE SOURCE ->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. */ man_node_delete(man, man->last); }
static int post_TH(CHKARGS) { const char *p; int line, pos; free(man->meta.title); free(man->meta.vol); free(man->meta.source); free(man->meta.msec); free(man->meta.date); line = n->line; pos = n->pos; man->meta.title = man->meta.vol = man->meta.date = man->meta.msec = man->meta.source = NULL; /* ->TITLE<- MSEC DATE SOURCE 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)) { man_nmsg(man, n, MANDOCERR_UPPERCASE); break; } } man->meta.title = mandoc_strdup(n->string); } else man->meta.title = mandoc_strdup(""); /* TITLE ->MSEC<- DATE SOURCE VOL */ if (n) n = n->next; if (n && n->string) man->meta.msec = mandoc_strdup(n->string); else man->meta.msec = mandoc_strdup(""); /* TITLE MSEC ->DATE<- SOURCE VOL */ if (n) n = n->next; if (n && n->string && '\0' != n->string[0]) { pos = n->pos; man->meta.date = mandoc_normdate (man->parse, n->string, line, pos); } else man->meta.date = mandoc_strdup(""); /* TITLE MSEC DATE ->SOURCE<- VOL */ if (n && (n = n->next)) man->meta.source = mandoc_strdup(n->string); /* TITLE MSEC DATE SOURCE ->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); /* * Remove the `TH' node after we've processed it for our * meta-data. */ man_node_delete(man, man->last); return(1); }