=================================================================== RCS file: /cvs/mandoc/mdoc.c,v retrieving revision 1.78 retrieving revision 1.89 diff -u -p -r1.78 -r1.89 --- mandoc/mdoc.c 2009/06/15 09:55:43 1.78 +++ mandoc/mdoc.c 2009/07/07 09:29:15 1.89 @@ -1,4 +1,4 @@ -/* $Id: mdoc.c,v 1.78 2009/06/15 09:55:43 kristaps Exp $ */ +/* $Id: mdoc.c,v 1.89 2009/07/07 09:29:15 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -23,18 +23,66 @@ #include "libmdoc.h" -enum merr { - ENOCALL, - EBODYPROL, - EPROLBODY, - ESPACE, - ETEXTPROL, - ENOBLANK, - EMALLOC +const char *const __mdoc_merrnames[MERRMAX] = { + "trailing whitespace", /* ETAILWS */ + "empty last list column", /* ECOLEMPTY */ + "argument-like parameter", /* EARGVPARM */ + "unexpected quoted parameter", /* EQUOTPARM */ + "unterminated quoted parameter", /* EQUOTTERM */ + "system: malloc error", /* EMALLOC */ + "argument parameter suggested", /* EARGVAL */ + "macro not callable", /* ENOCALL */ + "macro disallowed in prologue", /* EBODYPROL */ + "macro disallowed in body", /* EPROLBODY */ + "text disallowed in prologue", /* ETEXTPROL */ + "blank line disallowed", /* ENOBLANK */ + "text parameter too long", /* ETOOLONG */ + "invalid escape sequence", /* EESCAPE */ + "invalid character", /* EPRINT */ + "document has no body", /* ENODAT */ + "document has no prologue", /* ENOPROLOGUE */ + "expected line arguments", /* ELINE */ + "invalid AT&T argument", /* EATT */ + "default name not yet set", /* ENAME */ + "missing list type", /* ELISTTYPE */ + "missing display type", /* EDISPTYPE */ + "too many display types", /* EMULTIDISP */ + "too many list types", /* EMULTILIST */ + "NAME section must be first", /* ESECNAME */ + "badly-formed NAME section", /* ENAMESECINC */ + "argument repeated", /* EARGREP */ + "expected boolean parameter", /* EBOOL */ + "inconsistent column syntax", /* ECOLMIS */ + "nested display invalid", /* ENESTDISP */ + "width argument missing", /* EMISSWIDTH */ + "invalid section for this manual section", /* EWRONGMSEC */ + "section out of conventional order", /* ESECOOO */ + "section repeated", /* ESECREP */ + "invalid standard argument", /* EBADSTAND */ + "multi-line arguments discouraged", /* ENOMULTILINE */ + "multi-line arguments suggested", /* EMULTILINE */ + "line arguments discouraged", /* ENOLINE */ + "prologue macro out of conventional order", /* EPROLOOO */ + "prologue macro repeated", /* EPROLREP */ + "invalid manual section", /* EBADMSEC */ + "invalid section", /* EBADSEC */ + "invalid font mode", /* EFONT */ + "invalid date syntax", /* EBADDATE */ + "invalid number format", /* ENUMFMT */ + "superfluous width argument", /* ENOWIDTH */ + "system: utsname error", /* EUTSNAME */ + "obsolete macro", /* EOBS */ + "macro-like parameter", /* EMACPARM */ + "end-of-line scope violation", /* EIMPBRK */ + "empty macro ignored", /* EIGNE */ + "unclosed explicit scope", /* EOPEN */ + "unterminated quoted phrase", /* EQUOTPHR */ + "closure macro without prior context", /* ENOCTX */ + "invalid whitespace after control character", /* ESPACE */ }; const char *const __mdoc_macronames[MDOC_MAX] = { - "\\\"", "Dd", "Dt", "Os", + "Ap", "Dd", "Dt", "Os", "Sh", "Ss", "Pp", "D1", "Dl", "Bd", "Ed", "Bl", "El", "It", "Ad", "An", @@ -63,12 +111,12 @@ const char *const __mdoc_macronames[MDOC_MAX] = { "Tn", "Ux", "Xc", "Xo", "Fo", "Fc", "Oo", "Oc", "Bk", "Ek", "Bt", "Hf", - "Fr", "Ud", "Lb", "Ap", - "Lp", "Lk", "Mt", "Brq", + "Fr", "Ud", "Lb", "Lp", + "Lk", "Mt", "Brq", "Bro", /* LINTED */ - "Bro", "Brc", "\%C", "Es", + "Brc", "\%C", "Es", "En", /* LINTED */ - "En", "Dx", "\%Q" + "Dx", "\%Q" }; const char *const __mdoc_argnames[MDOC_ARG_MAX] = { @@ -95,13 +143,8 @@ static int node_append(struct mdoc *, static int parsetext(struct mdoc *, int, char *); static int parsemacro(struct mdoc *, int, char *); static int macrowarn(struct mdoc *, int, const char *); -static int perr(struct mdoc *, int, int, enum merr); -#define verr(m, t) perr((m), (m)->last->line, (m)->last->pos, (t)) -/* - * Get the first (root) node of the parse tree. - */ const struct mdoc_node * mdoc_node(const struct mdoc *m) { @@ -118,6 +161,9 @@ mdoc_meta(const struct mdoc *m) } +/* + * Frees volatile resources (parse tree, meta-data, fields). + */ static void mdoc_free1(struct mdoc *mdoc) { @@ -137,13 +183,16 @@ mdoc_free1(struct mdoc *mdoc) } +/* + * Allocate all volatile resources (parse tree, meta-data, fields). + */ static int mdoc_alloc1(struct mdoc *mdoc) { bzero(&mdoc->meta, sizeof(struct mdoc_meta)); mdoc->flags = 0; - mdoc->lastnamed = mdoc->lastsec = 0; + mdoc->lastnamed = mdoc->lastsec = SEC_NONE; mdoc->last = calloc(1, sizeof(struct mdoc_node)); if (NULL == mdoc->last) return(0); @@ -156,9 +205,10 @@ mdoc_alloc1(struct mdoc *mdoc) /* - * Free up all resources contributed by a parse: the node tree, - * meta-data and so on. Then reallocate the root node for another - * parse. + * Free up volatile resources (see mdoc_free1()) then re-initialises the + * data with mdoc_alloc1(). After invocation, parse data has been reset + * and the parser is ready for re-invocation on a new tree; however, + * cross-parse non-volatile data is kept intact. */ int mdoc_reset(struct mdoc *mdoc) @@ -170,7 +220,8 @@ mdoc_reset(struct mdoc *mdoc) /* - * Completely free up all resources. + * Completely free up all volatile and non-volatile parse resources. + * After invocation, the pointer is no longer usable. */ void mdoc_free(struct mdoc *mdoc) @@ -183,6 +234,9 @@ mdoc_free(struct mdoc *mdoc) } +/* + * Allocate volatile and non-volatile parse resources. + */ struct mdoc * mdoc_alloc(void *data, int pflags, const struct mdoc_cb *cb) { @@ -209,7 +263,7 @@ mdoc_alloc(void *data, int pflags, const struct mdoc_c /* * Climb back up the parse tree, validating open scopes. Mostly calls - * through to macro_end in macro.c. + * through to macro_end() in macro.c. */ int mdoc_endparse(struct mdoc *m) @@ -226,14 +280,12 @@ mdoc_endparse(struct mdoc *m) /* * Main parse routine. Parses a single line -- really just hands off to - * the macro or text parser. + * the macro (parsemacro()) or text parser (parsetext()). */ int mdoc_parseln(struct mdoc *m, int ln, char *buf) { - /* If in error-mode, then we parse no more. */ - if (MDOC_HALT & m->flags) return(0); @@ -242,22 +294,6 @@ mdoc_parseln(struct mdoc *m, int ln, char *buf) } -void -mdoc_vmsg(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_msg) - return; - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - (*mdoc->cb.mdoc_msg)(mdoc->data, ln, pos, buf); -} - - int mdoc_verr(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...) @@ -271,13 +307,13 @@ mdoc_verr(struct mdoc *mdoc, int ln, int pos, va_start(ap, fmt); (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); va_end(ap); + return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf)); } int -mdoc_vwarn(struct mdoc *mdoc, int ln, int pos, - enum mdoc_warn type, const char *fmt, ...) +mdoc_vwarn(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...) { char buf[256]; va_list ap; @@ -288,199 +324,46 @@ mdoc_vwarn(struct mdoc *mdoc, int ln, int pos, va_start(ap, fmt); (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); va_end(ap); - return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, type, buf)); -} - -int -mdoc_nwarn(struct mdoc *mdoc, const struct mdoc_node *node, enum mdoc_warn type, - const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_warn) - return(0); - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - return((*mdoc->cb.mdoc_warn)(mdoc->data, node->line, node->pos, type, - buf)); + return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, buf)); } -int -mdoc_nerr(struct mdoc *mdoc, const struct mdoc_node *node, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - if (NULL == mdoc->cb.mdoc_err) - return(0); - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - return((*mdoc->cb.mdoc_err)(mdoc->data, node->line, node->pos, buf)); -} - - int -mdoc_warn(struct mdoc *mdoc, enum mdoc_warn type, const char *fmt, ...) +mdoc_err(struct mdoc *m, int line, int pos, int iserr, enum merr type) { - char buf[256]; - va_list ap; + const char *p; - if (NULL == mdoc->cb.mdoc_warn) - return(0); + p = __mdoc_merrnames[(int)type]; + assert(p); - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - return((*mdoc->cb.mdoc_warn)(mdoc->data, mdoc->last->line, - mdoc->last->pos, type, buf)); -} + if (iserr) + return(mdoc_verr(m, line, pos, p)); - -int -mdoc_err(struct mdoc *mdoc, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_err) - return(0); - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - return((*mdoc->cb.mdoc_err)(mdoc->data, mdoc->last->line, - mdoc->last->pos, buf)); + return(mdoc_vwarn(m, line, pos, p)); } -void -mdoc_msg(struct mdoc *mdoc, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_msg) - return; - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - (*mdoc->cb.mdoc_msg)(mdoc->data, mdoc->last->line, mdoc->last->pos, - buf); -} - - -void -mdoc_pmsg(struct mdoc *mdoc, int line, int pos, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_msg) - return; - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - (*mdoc->cb.mdoc_msg)(mdoc->data, line, pos, buf); -} - - int -mdoc_pwarn(struct mdoc *mdoc, int line, int pos, enum mdoc_warn type, - const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_warn) - return(0); - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - return((*mdoc->cb.mdoc_warn)(mdoc->data, line, pos, type, buf)); -} - -int -mdoc_perr(struct mdoc *mdoc, int line, int pos, const char *fmt, ...) -{ - char buf[256]; - va_list ap; - - if (NULL == mdoc->cb.mdoc_err) - return(0); - - va_start(ap, fmt); - (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); - va_end(ap); - return((*mdoc->cb.mdoc_err)(mdoc->data, line, pos, buf)); -} - - -int mdoc_macro(struct mdoc *m, int tok, int ln, int pp, int *pos, char *buf) { - /* FIXME - these should happen during validation. */ - if (MDOC_PROLOGUE & mdoc_macros[tok].flags && - SEC_PROLOGUE != m->lastnamed) - return(perr(m, ln, pp, EPROLBODY)); - + MDOC_PBODY & m->flags) + return(mdoc_perr(m, ln, pp, EPROLBODY)); if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && - SEC_PROLOGUE == m->lastnamed) - return(perr(m, ln, pp, EBODYPROL)); + ! (MDOC_PBODY & m->flags)) + return(mdoc_perr(m, ln, pp, EBODYPROL)); if (1 != pp && ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) - return(perr(m, ln, pp, ENOCALL)); + return(mdoc_perr(m, ln, pp, ENOCALL)); return((*mdoc_macros[tok].fp)(m, tok, ln, pp, pos, buf)); } static int -perr(struct mdoc *m, int line, int pos, enum merr type) -{ - char *p; - - p = NULL; - switch (type) { - case (ENOCALL): - p = "not callable"; - break; - case (EPROLBODY): - p = "macro disallowed in document body"; - break; - case (EBODYPROL): - p = "macro disallowed in document prologue"; - break; - case (EMALLOC): - p = "memory exhausted"; - break; - case (ETEXTPROL): - p = "text disallowed in document prologue"; - break; - case (ENOBLANK): - p = "blank lines disallowed in non-literal contexts"; - break; - case (ESPACE): - p = "whitespace disallowed after delimiter"; - break; - } - assert(p); - return(mdoc_perr(m, line, pos, p)); -} - - -static int node_append(struct mdoc *mdoc, struct mdoc_node *p) { @@ -503,6 +386,8 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) /* NOTREACHED */ } + p->parent->nchild++; + if ( ! mdoc_valid_pre(mdoc, p)) return(0); if ( ! mdoc_action_pre(mdoc, p)) @@ -549,7 +434,7 @@ node_alloc(struct mdoc *mdoc, int line, struct mdoc_node *p; if (NULL == (p = calloc(1, sizeof(struct mdoc_node)))) { - (void)verr(mdoc, EMALLOC); + (void)mdoc_nerr(mdoc, mdoc->last, EMALLOC); return(NULL); } @@ -645,9 +530,10 @@ mdoc_word_alloc(struct mdoc *mdoc, if (NULL == p) return(0); if (NULL == (p->string = strdup(word))) { - (void)verr(mdoc, EMALLOC); + (void)mdoc_nerr(mdoc, mdoc->last, EMALLOC); return(0); } + return(node_append(mdoc, p)); } @@ -656,6 +542,8 @@ void mdoc_node_free(struct mdoc_node *p) { + if (p->parent) + p->parent->nchild--; if (p->string) free(p->string); if (p->args) @@ -673,6 +561,7 @@ mdoc_node_freelist(struct mdoc_node *p) if (p->next) mdoc_node_freelist(p->next); + assert(0 == p->nchild); mdoc_node_free(p); } @@ -685,11 +574,11 @@ static int parsetext(struct mdoc *m, int line, char *buf) { - if (SEC_PROLOGUE == m->lastnamed) - return(perr(m, line, 0, ETEXTPROL)); + if (SEC_NONE == m->lastnamed) + return(mdoc_perr(m, line, 0, ETEXTPROL)); if (0 == buf[0] && ! (MDOC_LITERAL & m->flags)) - return(perr(m, line, 0, ENOBLANK)); + return(mdoc_perr(m, line, 0, ENOBLANK)); if ( ! mdoc_word_alloc(m, line, 0, buf)) return(0); @@ -703,16 +592,14 @@ static int macrowarn(struct mdoc *m, int ln, const char *buf) { if ( ! (MDOC_IGN_MACRO & m->pflags)) - return(mdoc_perr(m, ln, 1, + return(mdoc_verr(m, ln, 1, "unknown macro: %s%s", buf, strlen(buf) > 3 ? "..." : "")); - return(mdoc_pwarn(m, ln, 1, WARN_SYNTAX, - "unknown macro: %s%s", + return(mdoc_vwarn(m, ln, 1, "unknown macro: %s%s", buf, strlen(buf) > 3 ? "..." : "")); } - /* * Parse a macro line, that is, a line beginning with the control * character. @@ -723,7 +610,7 @@ parsemacro(struct mdoc *m, int ln, char *buf) int i, c; char mac[5]; - /* Comments and empties are quickly ignored. */ + /* Empty lines are ignored. */ if (0 == buf[1]) return(1); @@ -734,12 +621,8 @@ parsemacro(struct mdoc *m, int ln, char *buf) i++; if (0 == buf[i]) return(1); - return(perr(m, ln, 1, ESPACE)); + return(mdoc_perr(m, ln, 1, ESPACE)); } - - if (buf[1] && '\\' == buf[1]) - if (buf[2] && '\"' == buf[2]) - return(1); /* Copy the first word into a nil-terminated buffer. */