diff options
-rw-r--r-- | action.c | 4 | ||||
-rw-r--r-- | argv.c | 19 | ||||
-rw-r--r-- | macro.c | 97 | ||||
-rw-r--r-- | mdoc.c | 2 | ||||
-rw-r--r-- | mdoc.h | 3 | ||||
-rw-r--r-- | validate.c | 79 |
6 files changed, 108 insertions, 96 deletions
@@ -298,6 +298,10 @@ int mdoc_action_post(struct mdoc *mdoc) { + if (MDOC_ACTED & mdoc->last->flags) + return(1); + mdoc->last->flags |= MDOC_ACTED; + if (MDOC_TEXT == mdoc->last->type) return(1); if (MDOC_ROOT == mdoc->last->type) @@ -78,7 +78,8 @@ mdoc_args(struct mdoc *mdoc, int line, int *pos, char *buf, int fl, char **v) /* Parse routine for non-quoted string. */ - if ('\"' != buf[*pos]) { + assert(*pos > 0); + if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) { *v = &buf[*pos]; /* FIXME: UGLY tab-sep processing. */ @@ -98,9 +99,14 @@ mdoc_args(struct mdoc *mdoc, int line, int *pos, char *buf, int fl, char **v) } (*pos)++; } - else - while (buf[*pos] && ! isspace(buf[*pos])) + else { + while (buf[*pos]) { + if (isspace(buf[*pos])) + if ('\\' != buf[*pos - 1]) + break; (*pos)++; + } + } if (0 == buf[*pos]) return(ARGS_WORD); @@ -451,8 +457,13 @@ mdoc_argv(struct mdoc *mdoc, int line, int tok, v->line = line; v->pos = *pos; - while (buf[*pos] && ! isspace(buf[*pos])) + assert(*pos > 0); + while (buf[*pos]) { + if (isspace(buf[*pos])) + if ('\\' != buf[*pos - 1]) + break; (*pos)++; + } if (buf[*pos]) buf[(*pos)++] = 0; @@ -70,24 +70,19 @@ rewind_last(struct mdoc *mdoc, struct mdoc_node *to) assert(to); mdoc->next = MDOC_NEXT_SIBLING; - if (mdoc->last == to) { + + while (mdoc->last != to) { if ( ! mdoc_valid_post(mdoc)) return(0); if ( ! mdoc_action_post(mdoc)) return(0); - return(1); - } - - do { mdoc->last = mdoc->last->parent; assert(mdoc->last); - if ( ! mdoc_valid_post(mdoc)) - return(0); - if ( ! mdoc_action_post(mdoc)) - return(0); - } while (mdoc->last != to); + } - return(1); + if ( ! mdoc_valid_post(mdoc)) + return(0); + return(mdoc_action_post(mdoc)); } @@ -139,9 +134,7 @@ rewind_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p) if (MDOC_ROOT == p->type) return(REWIND_HALT); - if (MDOC_TEXT == p->type) - return(REWIND_NOHALT); - if (MDOC_ELEM == p->type) + if (MDOC_VALID & p->flags) return(REWIND_NOHALT); switch (tok) { @@ -276,6 +269,8 @@ rewind_dobreak(int tok, const struct mdoc_node *p) return(1); if (MDOC_TEXT == p->type) return(1); + if (MDOC_VALID & p->flags) + return(1); switch (tok) { /* Implicit rules. */ @@ -328,14 +323,8 @@ rewind_subblock(enum mdoc_type type, struct mdoc *mdoc, struct mdoc_node *n; int c; - c = rewind_dohalt(tok, type, mdoc->last); - if (REWIND_HALT == c) - return(1); - if (REWIND_REWIND == c) - return(rewind_last(mdoc, mdoc->last)); - /* LINTED */ - for (n = mdoc->last->parent; n; n = n->parent) { + for (n = mdoc->last; n; n = n->parent) { c = rewind_dohalt(tok, type, n); if (REWIND_HALT == c) return(1); @@ -357,14 +346,8 @@ rewind_expblock(struct mdoc *mdoc, int tok, int line, int ppos) struct mdoc_node *n; int c; - c = rewind_dohalt(tok, MDOC_BLOCK, mdoc->last); - if (REWIND_HALT == c) - return(mdoc_perr(mdoc, line, ppos, "closing macro has no context")); - if (REWIND_REWIND == c) - return(rewind_last(mdoc, mdoc->last)); - /* LINTED */ - for (n = mdoc->last->parent; n; n = n->parent) { + for (n = mdoc->last; n; n = n->parent) { c = rewind_dohalt(tok, MDOC_BLOCK, n); if (REWIND_HALT == c) return(mdoc_perr(mdoc, line, ppos, "closing macro has no context")); @@ -386,14 +369,8 @@ rewind_impblock(struct mdoc *mdoc, int tok, int line, int ppos) struct mdoc_node *n; int c; - c = rewind_dohalt(tok, MDOC_BLOCK, mdoc->last); - if (REWIND_HALT == c) - return(1); - if (REWIND_REWIND == c) - return(rewind_last(mdoc, mdoc->last)); - /* LINTED */ - for (n = mdoc->last->parent; n; n = n->parent) { + for (n = mdoc->last; n; n = n->parent) { c = rewind_dohalt(tok, MDOC_BLOCK, n); if (REWIND_HALT == c) return(1); @@ -435,7 +412,6 @@ append_delims(struct mdoc *mdoc, int line, int *pos, char *buf) } -/* ARGSUSED */ int macro_scoped_close(MACRO_PROT_ARGS) { @@ -521,15 +497,6 @@ macro_scoped_close(MACRO_PROT_ARGS) } -/* - * A general text domain macro. When invoked, this opens a scope that - * accepts words until either end-of-line, only-punctuation, or a - * callable macro. If the word is punctuation (not only-punctuation), - * then the scope is closed out, the punctuation appended, then the - * scope opened again. If any terminating conditions are met, the scope - * is closed out. If this is the first macro in the line and - * only-punctuation remains, this punctuation is flushed. - */ int macro_text(MACRO_PROT_ARGS) { @@ -636,9 +603,6 @@ macro_text(MACRO_PROT_ARGS) } -/* - * Implicit- or explicit-end multi-line scoped macro. - */ int macro_scoped(MACRO_PROT_ARGS) { @@ -740,11 +704,6 @@ macro_scoped(MACRO_PROT_ARGS) } -/* - * When scoped to a line, a macro encompasses all of the contents. This - * differs from constants or text macros, where a new macro will - * terminate the existing context. - */ int macro_scoped_line(MACRO_PROT_ARGS) { @@ -798,10 +757,6 @@ macro_scoped_line(MACRO_PROT_ARGS) } -/* - * Constant-scope macros accept a fixed number of arguments and behave - * like constant macros except that they're scoped across lines. - */ int macro_constant_scoped(MACRO_PROT_ARGS) { @@ -901,12 +856,6 @@ macro_constant_scoped(MACRO_PROT_ARGS) } -/* - * Delimited macros are like text macros except that, should punctuation - * be encountered, the macro isn't re-started with remaining tokens - * (it's only emitted once). Delimited macros can have a maximum number - * of arguments. - */ int macro_constant_delimited(MACRO_PROT_ARGS) { @@ -1000,7 +949,7 @@ macro_constant_delimited(MACRO_PROT_ARGS) mdoc->next = MDOC_NEXT_SIBLING; } - if ( ! flushed && rewind_elem(mdoc, tok)) + if ( ! flushed && ! rewind_elem(mdoc, tok)) return(0); if (ppos > 1) @@ -1009,10 +958,6 @@ macro_constant_delimited(MACRO_PROT_ARGS) } -/* - * Constant macros span an entire line: they constitute a macro and all - * of its arguments and child data. - */ int macro_constant(MACRO_PROT_ARGS) { @@ -1090,8 +1035,24 @@ macro_obsolete(MACRO_PROT_ARGS) int macro_end(struct mdoc *mdoc) { + struct mdoc_node *n; assert(mdoc->first); assert(mdoc->last); + + /* Scan for open explicit scopes. */ + + n = MDOC_VALID & mdoc->last->flags ? + mdoc->last->parent : mdoc->last; + + for ( ; n; n = n->parent) { + if (MDOC_BLOCK != n->type) + continue; + if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags)) + continue; + mdoc_nerr(mdoc, n, "macro scope still open on exit"); + return(0); + } + return(rewind_last(mdoc, mdoc->first)); } @@ -725,6 +725,7 @@ argdup(size_t argsz, const struct mdoc_arg *args) } +/* FIXME: deprecate. */ char * mdoc_node2a(struct mdoc_node *node) { @@ -741,6 +742,7 @@ mdoc_node2a(struct mdoc_node *node) (void)xstrlcat(buf, node->data.text.string, 64); else (void)xstrlcat(buf, mdoc_macronames[node->tok], 64); + (void)xstrlcat(buf, "'", 64); return(buf); } @@ -385,6 +385,9 @@ struct mdoc_node { int line; int pos; int tok; + int flags; +#define MDOC_VALID (1 << 0) +#define MDOC_ACTED (1 << 1) enum mdoc_type type; union mdoc_data data; }; @@ -29,6 +29,7 @@ typedef int (*v_post)(struct mdoc *); /* FIXME: math symbols. */ /* FIXME: make sure prologue is complete. */ /* FIXME: valid character-escape checks. */ +/* FIXME: make sure required sections are included (NAME, ...). */ struct valids { v_pre *pre; @@ -45,7 +46,9 @@ static int pre_check_stdarg(struct mdoc *, struct mdoc_node *); static int post_check_children_count(struct mdoc *); static int post_check_children_lt(struct mdoc *, int); static int post_check_children_gt(struct mdoc *, int); +static int post_check_children_wgt(struct mdoc *, int); static int post_check_children_eq(struct mdoc *, int); +static int post_check_children_weq(struct mdoc *, int); /* Specific pre-child-parse routines. */ @@ -76,6 +79,7 @@ static int eerr_le2(struct mdoc *); static int eerr_eq1(struct mdoc *); static int eerr_ge1(struct mdoc *); static int ewarn_eq0(struct mdoc *); +static int ewarn_eq1(struct mdoc *); static int bwarn_ge1(struct mdoc *); static int berr_eq0(struct mdoc *); static int ewarn_ge1(struct mdoc *); @@ -117,6 +121,7 @@ static v_post posts_wline[] = { hwarn_ge1, berr_eq0, NULL }; static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; static v_post posts_bl[] = { herr_eq0, bwarn_ge1, post_bl, NULL }; static v_post posts_it[] = { post_it, NULL }; +static v_post posts_in[] = { ewarn_eq1, NULL }; static v_post posts_ss[] = { herr_ge1, NULL }; static v_post posts_pp[] = { ewarn_eq0, NULL }; static v_post posts_d1[] = { herr_ge1, NULL }; @@ -155,12 +160,12 @@ const struct valids mdoc_valids[MDOC_MAX] = { { pres_ex, posts_ex }, /* Ex */ { NULL, posts_text }, /* Fa */ /* FIXME: only in SYNOPSIS section. */ - { NULL, NULL }, /* Fd */ + { NULL, posts_wtext }, /* Fd */ { NULL, NULL }, /* Fl */ { NULL, posts_text }, /* Fn */ - { NULL, NULL }, /* Ft */ + { NULL, posts_wtext }, /* Ft */ { NULL, posts_text }, /* Ic */ - { NULL, posts_wtext }, /* In */ + { NULL, posts_in }, /* In */ { NULL, posts_text }, /* Li */ { NULL, posts_wtext }, /* Nd */ { NULL, posts_nm }, /* Nm */ @@ -188,7 +193,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_wline }, /* Aq */ { NULL, posts_at }, /* At */ { NULL, NULL }, /* Bc */ - { NULL, NULL }, /* Bf */ + { NULL, NULL }, /* Bf */ /* FIXME */ { NULL, NULL }, /* Bo */ { NULL, posts_wline }, /* Bq */ { NULL, NULL }, /* Bsx */ @@ -253,6 +258,18 @@ post_check_children_count(struct mdoc *mdoc) static int +post_check_children_wgt(struct mdoc *mdoc, int sz) +{ + int i; + + if ((i = post_check_children_count(mdoc)) > sz) + return(1); + return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests more " + "than %d parameters (has %d)", sz, i)); +} + + +static int post_check_children_gt(struct mdoc *mdoc, int sz) { int i; @@ -260,7 +277,19 @@ post_check_children_gt(struct mdoc *mdoc, int sz) if ((i = post_check_children_count(mdoc)) > sz) return(1); return(mdoc_err(mdoc, "macro requires more than %d " - "parameters (have %d)", sz, i)); + "parameters (has %d)", sz, i)); +} + + +static int +post_check_children_weq(struct mdoc *mdoc, int sz) +{ + int i; + + if ((i = post_check_children_count(mdoc)) == sz) + return(1); + return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests %d " + "parameters (has %d)", sz, i)); } @@ -338,9 +367,7 @@ berr_eq0(struct mdoc *mdoc) if (MDOC_BODY != mdoc->last->type) return(1); - if (NULL == mdoc->last->child) - return(1); - return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no body children")); + return(post_check_children_eq(mdoc, 0)); } @@ -350,9 +377,16 @@ bwarn_ge1(struct mdoc *mdoc) if (MDOC_BODY != mdoc->last->type) return(1); - if (mdoc->last->child) - return(1); - return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests one or more body children")); + return(post_check_children_wgt(mdoc, 0)); +} + + +static int +ewarn_eq1(struct mdoc *mdoc) +{ + + assert(MDOC_ELEM == mdoc->last->type); + return(post_check_children_weq(mdoc, 1)); } @@ -361,10 +395,7 @@ ewarn_eq0(struct mdoc *mdoc) { assert(MDOC_ELEM == mdoc->last->type); - if (NULL == mdoc->last->child) - return(1); - return(mdoc_pwarn(mdoc, mdoc->last->child->line, - mdoc->last->child->pos, WARN_SYNTAX, "macro suggests no parameters")); + return(post_check_children_weq(mdoc, 0)); } @@ -373,9 +404,7 @@ ewarn_ge1(struct mdoc *mdoc) { assert(MDOC_ELEM == mdoc->last->type); - if (mdoc->last->child) - return(1); - return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests one or more parameters")); + return(post_check_children_wgt(mdoc, 0)); } @@ -440,9 +469,7 @@ hwarn_ge1(struct mdoc *mdoc) if (MDOC_HEAD != mdoc->last->type) return(1); - if (mdoc->last->child) - return(1); - return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests one or more parameters")); + return(post_check_children_wgt(mdoc, 0)); } @@ -1003,11 +1030,11 @@ post_root(struct mdoc *mdoc) if (NULL == mdoc->last->child) return(mdoc_err(mdoc, "document has no data")); if (NULL == mdoc->meta.title) - return(mdoc_err(mdoc, "document has no incomplete prologue")); + return(mdoc_err(mdoc, "document has incomplete prologue")); if (NULL == mdoc->meta.os) - return(mdoc_err(mdoc, "document has no incomplete prologue")); + return(mdoc_err(mdoc, "document has incomplete prologue")); if (0 == mdoc->meta.date) - return(mdoc_err(mdoc, "document has no incomplete prologue")); + return(mdoc_err(mdoc, "document has incomplete prologue")); return(1); } @@ -1059,6 +1086,10 @@ mdoc_valid_post(struct mdoc *mdoc) { v_post *p; + if (MDOC_VALID & mdoc->last->flags) + return(1); + mdoc->last->flags |= MDOC_VALID; + if (MDOC_TEXT == mdoc->last->type) return(1); if (MDOC_ROOT == mdoc->last->type) |