diff options
-rw-r--r-- | libmdoc.h | 5 | ||||
-rw-r--r-- | mdoc.c | 34 | ||||
-rw-r--r-- | mdoc.h | 64 | ||||
-rw-r--r-- | mdoc_action.c | 2 | ||||
-rw-r--r-- | mdoc_strings.c | 60 | ||||
-rw-r--r-- | mdoc_validate.c | 49 |
6 files changed, 103 insertions, 111 deletions
@@ -29,8 +29,9 @@ struct mdoc { struct mdoc_cb cb; void *htab; int flags; -#define MDOC_HALT (1 << 0) -#define MDOC_LITERAL (1 << 1) +#define MDOC_HALT (1 << 0) /* Error in parse. Halt. */ +#define MDOC_LITERAL (1 << 1) /* In a literal scope. */ +#define MDOC_PBODY (1 << 2) /* In the document body. */ int pflags; enum mdoc_next next; struct mdoc_node *last; @@ -113,6 +113,9 @@ mdoc_meta(const struct mdoc *m) } +/* + * Frees volatile resources (parse tree, meta-data, fields). + */ static void mdoc_free1(struct mdoc *mdoc) { @@ -132,13 +135,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); @@ -151,9 +157,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) @@ -165,7 +172,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) @@ -178,6 +186,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) { @@ -204,7 +215,7 @@ mdoc_alloc(void *data, int pflags, const struct mdoc_cb *cb) /* * 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) @@ -221,7 +232,7 @@ 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) @@ -360,14 +371,11 @@ 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) + MDOC_PBODY & m->flags) return(perr(m, ln, pp, EPROLBODY)); - if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && - SEC_PROLOGUE == m->lastnamed) + ! (MDOC_PBODY & m->flags)) return(perr(m, ln, pp, EBODYPROL)); if (1 != pp && ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) @@ -618,7 +626,7 @@ static int parsetext(struct mdoc *m, int line, char *buf) { - if (SEC_PROLOGUE == m->lastnamed) + if (SEC_NONE == m->lastnamed) return(perr(m, line, 0, ETEXTPROL)); if (0 == buf[0] && ! (MDOC_LITERAL & m->flags)) @@ -198,27 +198,26 @@ enum mdoc_type { /* Section (named/unnamed) of `Sh'. */ enum mdoc_sec { - SEC_PROLOGUE = 0, - SEC_BODY = 1, - SEC_NAME = 2, - SEC_LIBRARY = 3, - SEC_SYNOPSIS = 4, - SEC_DESCRIPTION = 5, - SEC_IMPLEMENTATION = 6, - SEC_RETURN_VALUES = 7, - SEC_ENVIRONMENT = 8, - SEC_FILES = 9, - SEC_EXAMPLES = 10, - SEC_DIAGNOSTICS = 11, - SEC_COMPATIBILITY = 12, - SEC_ERRORS = 13, - SEC_SEE_ALSO = 14, - SEC_STANDARDS = 15, - SEC_HISTORY = 16, - SEC_AUTHORS = 17, - SEC_CAVEATS = 18, - SEC_BUGS = 19, - SEC_CUSTOM + SEC_NONE, /* No section, yet. */ + SEC_NAME, + SEC_LIBRARY, + SEC_SYNOPSIS, + SEC_DESCRIPTION, + SEC_IMPLEMENTATION, + SEC_RETURN_VALUES, + SEC_ENVIRONMENT, + SEC_FILES, + SEC_EXAMPLES, + SEC_DIAGNOSTICS, + SEC_COMPATIBILITY, + SEC_ERRORS, + SEC_SEE_ALSO, + SEC_STANDARDS, + SEC_HISTORY, + SEC_AUTHORS, + SEC_CAVEATS, + SEC_BUGS, + SEC_CUSTOM /* User-defined. */ }; /* Information from prologue. */ @@ -276,45 +275,32 @@ struct mdoc_node { #define MDOC_IGN_CHARS (1 << 3) /* Ignore disallowed chars. */ /* Call-backs for parse messages. */ +/* FIXME: unify somehow with man_cb. */ struct mdoc_cb { int (*mdoc_err)(void *, int, int, const char *); int (*mdoc_warn)(void *, int, int, enum mdoc_warn, const char *); }; -/* Global table of macro names (`Bd', `Ed', etc.). */ -extern const char *const *mdoc_macronames; +/* See mdoc.3 for documentation. */ -/* Global table of argument names (`column', `tag', etc.). */ +extern const char *const *mdoc_macronames; extern const char *const *mdoc_argnames; __BEGIN_DECLS struct mdoc; -/* Free memory allocated with mdoc_alloc. */ -void mdoc_free(struct mdoc *); +/* See mdoc.3 for documentation. */ -/* Allocate a new parser instance. */ +void mdoc_free(struct mdoc *); struct mdoc *mdoc_alloc(void *, int, const struct mdoc_cb *); - -/* Gets system ready for another parse. */ int mdoc_reset(struct mdoc *); - -/* Parse a single line in a stream (boolean retval). */ int mdoc_parseln(struct mdoc *, int, char *buf); - -/* Get result first node (after mdoc_endparse!). */ const struct mdoc_node *mdoc_node(const struct mdoc *); - -/* Get result meta-information (after mdoc_endparse!). */ const struct mdoc_meta *mdoc_meta(const struct mdoc *); - -/* Signal end of parse sequence (boolean retval). */ int mdoc_endparse(struct mdoc *); -/* The following are utility functions. */ - const char *mdoc_a2att(const char *); const char *mdoc_a2lib(const char *); const char *mdoc_a2st(const char *); diff --git a/mdoc_action.c b/mdoc_action.c index 4a314905..0b7face0 100644 --- a/mdoc_action.c +++ b/mdoc_action.c @@ -515,8 +515,8 @@ post_os(POST_ARGS) if (NULL == (m->meta.os = strdup(buf))) return(verr(m, EMALLOC)); - m->lastnamed = m->lastsec = SEC_BODY; + m->flags |= MDOC_PBODY; return(post_prol(m)); } diff --git a/mdoc_strings.c b/mdoc_strings.c index d1781a98..25711de7 100644 --- a/mdoc_strings.c +++ b/mdoc_strings.c @@ -24,36 +24,34 @@ #include "libmdoc.h" +/* FIXME: this file is poorly named. */ + struct mdoc_secname { const char *name; /* Name of section. */ - int flag; -#define MSECNAME_META (1 << 0)/* Logical section (not real). */ + enum mdoc_sec sec; /* Corresponding section. */ }; -/* Section names corresponding to mdoc_sec. */ +#define SECNAME_MAX (18) -static const struct mdoc_secname secnames[] = { - { "PROLOGUE", MSECNAME_META }, - { "BODY", MSECNAME_META }, - { "NAME", 0 }, - { "LIBRARY", 0 }, - { "SYNOPSIS", 0 }, - { "DESCRIPTION", 0 }, - { "IMPLEMENTATION NOTES", 0 }, - { "RETURN VALUES", 0 }, - { "ENVIRONMENT", 0 }, - { "FILES", 0 }, - { "EXAMPLES", 0 }, - { "DIAGNOSTICS", 0 }, - { "COMPATIBILITY", 0 }, - { "ERRORS", 0 }, - { "SEE ALSO", 0 }, - { "STANDARDS", 0 }, - { "HISTORY", 0 }, - { "AUTHORS", 0 }, - { "CAVEATS", 0 }, - { "BUGS", 0 }, - { NULL, 0 } +static const struct mdoc_secname secnames[SECNAME_MAX] = { + { "NAME", SEC_NAME }, + { "LIBRARY", SEC_LIBRARY }, + { "SYNOPSIS", SEC_SYNOPSIS }, + { "DESCRIPTION", SEC_DESCRIPTION }, + { "IMPLEMENTATION NOTES", SEC_IMPLEMENTATION }, + { "RETURN VALUES", SEC_RETURN_VALUES }, + { "ENVIRONMENT", SEC_ENVIRONMENT }, + { "FILES", SEC_FILES }, + { "EXAMPLES", SEC_EXAMPLES }, + { "DIAGNOSTICS", SEC_DIAGNOSTICS }, + { "COMPATIBILITY", SEC_COMPATIBILITY }, + { "ERRORS", SEC_ERRORS }, + { "SEE ALSO", SEC_SEE_ALSO }, + { "STANDARDS", SEC_STANDARDS }, + { "HISTORY", SEC_HISTORY }, + { "AUTHORS", SEC_AUTHORS }, + { "CAVEATS", SEC_CAVEATS }, + { "BUGS", SEC_BUGS }, }; #ifdef __linux__ @@ -191,13 +189,11 @@ mdoc_isdelim(const char *p) enum mdoc_sec mdoc_atosec(const char *p) { - const struct mdoc_secname *n; - int i; + int i; - for (i = 0, n = secnames; n->name; n++, i++) - if ( ! (n->flag & MSECNAME_META)) - if (0 == strcmp(p, n->name)) - return((enum mdoc_sec)i); + for (i = 0; i < SECNAME_MAX; i++) + if (0 == strcmp(p, secnames[i].name)) + return(secnames[i].sec); return(SEC_CUSTOM); } @@ -209,7 +205,7 @@ mdoc_atotime(const char *p) struct tm tm; char *pp; - (void)memset(&tm, 0, sizeof(struct tm)); + bzero(&tm, sizeof(struct tm)); if (0 == strcmp(p, "$" "Mdocdate$")) return(time(NULL)); diff --git a/mdoc_validate.c b/mdoc_validate.c index ac42fe45..edc03a41 100644 --- a/mdoc_validate.c +++ b/mdoc_validate.c @@ -42,6 +42,7 @@ enum merr { ELISTTYPE, EDISPTYPE, EMULTIDISP, + ESECNAME, EMULTILIST, EARGREP, EBOOL, @@ -116,7 +117,6 @@ static int pre_fd(PRE_ARGS); static int pre_it(PRE_ARGS); static int pre_lb(PRE_ARGS); static int pre_os(PRE_ARGS); -static int pre_prologue(PRE_ARGS); static int pre_rv(PRE_ARGS); static int pre_sh(PRE_ARGS); static int pre_ss(PRE_ARGS); @@ -155,15 +155,15 @@ static v_pre pres_an[] = { pre_an, NULL }; static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; static v_pre pres_bl[] = { pre_bl, NULL }; static v_pre pres_cd[] = { pre_cd, NULL }; -static v_pre pres_dd[] = { pre_prologue, pre_dd, NULL }; +static v_pre pres_dd[] = { pre_dd, NULL }; static v_pre pres_d1[] = { pre_display, NULL }; -static v_pre pres_dt[] = { pre_prologue, pre_dt, NULL }; +static v_pre pres_dt[] = { pre_dt, NULL }; static v_pre pres_er[] = { pre_er, NULL }; static v_pre pres_ex[] = { pre_ex, NULL }; static v_pre pres_fd[] = { pre_fd, NULL }; static v_pre pres_it[] = { pre_it, NULL }; static v_pre pres_lb[] = { pre_lb, NULL }; -static v_pre pres_os[] = { pre_prologue, pre_os, NULL }; +static v_pre pres_os[] = { pre_os, NULL }; static v_pre pres_rv[] = { pre_rv, NULL }; static v_pre pres_sh[] = { pre_sh, NULL }; static v_pre pres_ss[] = { pre_ss, NULL }; @@ -413,6 +413,9 @@ perr(struct mdoc *m, int line, int pos, enum merr type) case (EDISPTYPE): p = "missing display type"; break; + case (ESECNAME): + p = "the NAME section must come first"; + break; case (ELINE): p = "expected line arguments"; break; @@ -1019,14 +1022,6 @@ pre_cd(PRE_ARGS) static int -pre_prologue(PRE_ARGS) -{ - - return(check_sec(mdoc, n, SEC_PROLOGUE, SEC_CUSTOM)); -} - - -static int pre_dt(PRE_ARGS) { @@ -1077,8 +1072,12 @@ post_bf(POST_ARGS) if (MDOC_BLOCK != mdoc->last->type) return(1); + /* FIXME: clean-up .*/ + head = mdoc->last->head; + if (mdoc->last->args && head->child) + if (NULL == mdoc->last->args) { if (NULL == head->child || MDOC_TEXT != head->child->type) @@ -1313,7 +1312,7 @@ post_root(POST_ARGS) if (NULL == mdoc->first->child) return(verr(mdoc, ENODATA)); - if (SEC_PROLOGUE == mdoc->lastnamed) + if ( ! (MDOC_PBODY & mdoc->flags)) return(verr(mdoc, ENOPROLOGUE)); if (MDOC_BLOCK != mdoc->first->child->type) @@ -1394,13 +1393,12 @@ post_sh_head(POST_ARGS) * certain manual sections. */ - assert(MDOC_Sh == mdoc->last->tok); - - /* This is just concat() inlined, which is irritating. */ - buf[0] = 0; + for (n = mdoc->last->child; n; n = n->next) { + /* XXX - copied from compact(). */ assert(MDOC_TEXT == n->type); + if (strlcat(buf, n->string, 64) >= 64) return(nerr(mdoc, n, ETOOLONG)); if (NULL == n->next) @@ -1411,21 +1409,24 @@ post_sh_head(POST_ARGS) sec = mdoc_atosec(buf); - /* The NAME section should always be first. */ + /* + * Check: NAME should always be first, CUSTOM has no roles, + * non-CUSTOM has a conventional order to be followed. + */ - if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec) - return(vwarn(mdoc, WSECOOO)); + if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) + return(verr(mdoc, ESECNAME)); if (SEC_CUSTOM == sec) return(1); - - /* Check for repeated or out-of-order sections. */ - if (sec == mdoc->lastnamed) return(vwarn(mdoc, WSECREP)); if (sec < mdoc->lastnamed) return(vwarn(mdoc, WSECOOO)); - /* Check particular section/manual section conventions. */ + /* + * Check particular section/manual conventions. LIBRARY can + * only occur in msec 2, 3 (TODO: are there more of these?). + */ switch (sec) { case (SEC_LIBRARY): |