diff options
author | Kristaps Dzonsons <kristaps@bsd.lv> | 2009-02-24 11:43:13 +0000 |
---|---|---|
committer | Kristaps Dzonsons <kristaps@bsd.lv> | 2009-02-24 11:43:13 +0000 |
commit | 9e0f9f2ee7f854665c6fbf442ea8339bbce17ecb (patch) | |
tree | c5b5201797d9e59ac3a378e66b6411e1b2610d7a | |
parent | 6229c59e2536a1921c81abefed1a37bfd01790b0 (diff) | |
download | mandoc-9e0f9f2ee7f854665c6fbf442ea8339bbce17ecb.tar.gz |
Escape-sequence validation in place (for nodes).
-rw-r--r-- | Makefile | 13 | ||||
-rw-r--r-- | argv.c | 6 | ||||
-rw-r--r-- | private.h | 1 | ||||
-rw-r--r-- | regress/test.escape.00 | 20 | ||||
-rw-r--r-- | regress/test.escape.01 | 20 | ||||
-rw-r--r-- | regress/test.escape.02 | 20 | ||||
-rw-r--r-- | regress/test.escape.03 | 20 | ||||
-rw-r--r-- | regress/test.escape.04 | 20 | ||||
-rw-r--r-- | regress/test.list.05 | 2 | ||||
-rw-r--r-- | strings.c | 44 | ||||
-rw-r--r-- | validate.c | 78 |
11 files changed, 220 insertions, 24 deletions
@@ -78,9 +78,11 @@ FAIL = regress/test.empty \ regress/test.prologue.31 \ regress/test.prologue.32 \ regress/test.prologue.33 \ - regress/test.sh.01 \ - regress/test.sh.02 \ - regress/test.sh.03 + regress/test.sh.03 \ + regress/test.escape.01 \ + regress/test.escape.02 \ + regress/test.escape.03 \ + regress/test.escape.04 SUCCEED = regress/test.prologue.05 \ regress/test.prologue.07 \ @@ -103,7 +105,10 @@ SUCCEED = regress/test.prologue.05 \ regress/test.list.03 \ regress/test.list.04 \ regress/test.list.05 \ - regress/test.list.06 + regress/test.list.06 \ + regress/test.sh.01 \ + regress/test.sh.02 \ + regress/test.escape.00 REGRESS = $(FAIL) $(SUCCEED) @@ -35,7 +35,7 @@ #define ARGS_DELIM (1 << 1) #define ARGS_TABSEP (1 << 2) -static int lookup(int, const char *); +static int argv_a2arg(int, const char *); static int args(struct mdoc *, int, int *, char *, int, char **); static int argv(struct mdoc *, int, @@ -466,7 +466,7 @@ args(struct mdoc *mdoc, int line, static int -lookup(int tok, const char *argv) +argv_a2arg(int tok, const char *argv) { switch (tok) { @@ -747,7 +747,7 @@ mdoc_argv(struct mdoc *mdoc, int line, int tok, if (buf[*pos]) buf[(*pos)++] = 0; - if (MDOC_ARG_MAX == (v->arg = lookup(tok, p))) { + if (MDOC_ARG_MAX == (v->arg = argv_a2arg(tok, p))) { if ( ! pwarn(mdoc, line, i, WARGVPARM)) return(ARGV_ERROR); return(ARGV_WORD); @@ -125,6 +125,7 @@ void *mdoc_tokhash_alloc(void); int mdoc_tokhash_find(const void *, const char *); void mdoc_tokhash_free(void *); int mdoc_iscdelim(char); +size_t mdoc_isescape(const char *); enum mdoc_sec mdoc_atosec(const char *); enum mdoc_msec mdoc_atomsec(const char *); enum mdoc_vol mdoc_atovol(const char *); diff --git a/regress/test.escape.00 b/regress/test.escape.00 new file mode 100644 index 00000000..28df79e5 --- /dev/null +++ b/regress/test.escape.00 @@ -0,0 +1,20 @@ +.\" +.Dd $Mdocdate$ +.Dt mdoc 3 +.Os +.\" +.Sh NAME +.Nm mdoc_free +.Nd mdoc macro compiler library +.\" +.Sh SYNOPSIS +Valid escape: \(ab +Valid escape: \[d] +Valid escape: \[dsdfajsdflaksjfhalksjdfh__----] +Valid escape: \\ +Valid escape: \e +Valid escape: \` +Valid escape: \' +Valid escape: \. +Valid escape: \- +Valid escape: \ diff --git a/regress/test.escape.01 b/regress/test.escape.01 new file mode 100644 index 00000000..2bf37cf6 --- /dev/null +++ b/regress/test.escape.01 @@ -0,0 +1,20 @@ +.\" +.Dd $Mdocdate$ +.Dt mdoc 3 +.Os +.\" +.Sh NAME +.Nm mdoc_free +.Nd mdoc macro compiler library +.\" +.Sh SYNOPSIS +Valid escape: \(ab +Valid escape: \[d] +Valid escape: \[dsdfajsdflaksjfhalksjdfh__----] +Valid escape: \\ +Valid escape: \e +Valid escape: \` +Valid escape: \' +Valid escape: \. +Valid escape: \- +Invalid escape: \" diff --git a/regress/test.escape.02 b/regress/test.escape.02 new file mode 100644 index 00000000..1c727a8f --- /dev/null +++ b/regress/test.escape.02 @@ -0,0 +1,20 @@ +.\" +.Dd $Mdocdate$ +.Dt mdoc 3 +.Os +.\" +.Sh NAME +.Nm mdoc_free +.Nd mdoc macro compiler library +.\" +.Sh SYNOPSIS +Valid escape: \(ab +Valid escape: \[d] +Valid escape: \[dsdfajsdflaksjfhalksjdfh__----] +Valid escape: \\ +Valid escape: \e +Valid escape: \` +Valid escape: \' +Valid escape: \. +Valid escape: \- +Invalid escape: \( diff --git a/regress/test.escape.03 b/regress/test.escape.03 new file mode 100644 index 00000000..7fa92ecd --- /dev/null +++ b/regress/test.escape.03 @@ -0,0 +1,20 @@ +.\" +.Dd $Mdocdate$ +.Dt mdoc 3 +.Os +.\" +.Sh NAME +.Nm mdoc_free +.Nd mdoc macro compiler library +.\" +.Sh SYNOPSIS +Valid escape: \(ab +Valid escape: \[d] +Valid escape: \[dsdfajsdflaksjfhalksjdfh__----] +Valid escape: \\ +Valid escape: \e +Valid escape: \` +Valid escape: \' +Valid escape: \. +Valid escape: \- +Invalid escape: \ diff --git a/regress/test.escape.04 b/regress/test.escape.04 new file mode 100644 index 00000000..a393ab83 --- /dev/null +++ b/regress/test.escape.04 @@ -0,0 +1,20 @@ +.\" +.Dd $Mdocdate$ +.Dt mdoc 3 +.Os +.\" +.Sh NAME +.Nm mdoc_free +.Nd mdoc macro compiler library +.\" +.Sh SYNOPSIS +Valid escape: \(ab +Valid escape: \[d] +Valid escape: \[dsdfajsdflaksjfhalksjdfh__----] +Valid escape: \\ +Valid escape: \e +Valid escape: \` +Valid escape: \' +Valid escape: \. +Valid escape: \- +Invalid escape: \[ diff --git a/regress/test.list.05 b/regress/test.list.05 index 18540423..08954e84 100644 --- a/regress/test.list.05 +++ b/regress/test.list.05 @@ -6,5 +6,5 @@ .Nd description .Sh DESCRIPTION .Bl -column "xxxxx" "xxxxx" -.It d \ e f +.It d \ e f .El @@ -35,6 +35,50 @@ extern char *strptime(const char *, const char *, struct tm *); #endif + +size_t +mdoc_isescape(const char *p) +{ + size_t c; + + if ('\\' != *p++) + return(0); + + switch (*p) { + case ('\\'): + /* FALLTHROUGH */ + case ('\''): + /* FALLTHROUGH */ + case ('`'): + /* FALLTHROUGH */ + case ('-'): + /* FALLTHROUGH */ + case (' '): + /* FALLTHROUGH */ + case ('.'): + /* FALLTHROUGH */ + case ('e'): + return(2); + case ('('): + if (0 == *++p) + return(0); + if (0 == *++p) + return(0); + return(4); + case ('['): + break; + default: + return(0); + } + + for (c = 3, p++; *p && ']' != *p; p++, c++) + if (isspace(*p)) + break; + + return(*p == ']' ? c : 0); +} + + int mdoc_iscdelim(char p) { @@ -35,7 +35,6 @@ typedef int (*v_post)(struct mdoc *); /* FIXME: some sections should only occur in specific msecs. */ /* FIXME: ignoring Pp. */ /* FIXME: math symbols. */ -/* FIXME: valid character-escape checks. */ /* FIXME: .Fd only in synopsis section. */ struct valids { @@ -109,6 +108,7 @@ static int post_xr(struct mdoc *); static int post_nm(struct mdoc *); static int post_bf(struct mdoc *); static int post_root(struct mdoc *); +static int pre_text(struct mdoc *, const struct mdoc_node *); /* Collections of pre-child-parse routines. */ @@ -386,6 +386,22 @@ check_msec(struct mdoc *mdoc, struct mdoc_node *node, static int +check_parent(struct mdoc *mdoc, struct mdoc_node *n, + int tok, enum mdoc_type t) +{ + + assert(n->parent); + if ((MDOC_ROOT == t || tok == n->parent->tok) && + (t == n->parent->type)) + return(1); + + return(mdoc_nerr(mdoc, n, "require parent %s", + MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok])); +} + + + +static int pre_display(struct mdoc *mdoc, struct mdoc_node *node) { struct mdoc_node *n; @@ -922,6 +938,26 @@ ebool(struct mdoc *mdoc) static int +pre_text(struct mdoc *mdoc, const struct mdoc_node *n) +{ + size_t c; + const char *p; + + for (p = n->data.text.string; *p; p++) { + if ('\\' != *p) + continue; + if ((c = mdoc_isescape(p))) { + p += (c - 1); + continue; + } + return(mdoc_nerr(mdoc, n, "bad escape sequence")); + } + + return(1); +} + + +static int post_root(struct mdoc *mdoc) { @@ -931,10 +967,10 @@ post_root(struct mdoc *mdoc) return(mdoc_err(mdoc, "document lacks prologue")); if (MDOC_BLOCK != mdoc->first->child->type) - return(mdoc_err(mdoc, "lacking post-prologue `%s'", + return(mdoc_err(mdoc, "lacking post-prologue %s", mdoc_macronames[MDOC_Sh])); if (MDOC_Sh != mdoc->first->child->tok) - return(mdoc_err(mdoc, "lacking post-prologue `%s'", + return(mdoc_err(mdoc, "lacking post-prologue %s", mdoc_macronames[MDOC_Sh])); return(1); @@ -969,8 +1005,8 @@ post_sh_body(struct mdoc *mdoc) */ if (NULL == (n = mdoc->last->child)) - return(mdoc_warn(mdoc, WARN_COMPAT, "section NAME " - "should contain %s and %s", + return(mdoc_warn(mdoc, WARN_SYNTAX, + "section should have %s and %s", mdoc_macronames[MDOC_Nm], mdoc_macronames[MDOC_Nd])); @@ -979,9 +1015,8 @@ post_sh_body(struct mdoc *mdoc) continue; if (MDOC_TEXT == n->type) continue; - if ( ! (mdoc_nwarn(mdoc, n, WARN_COMPAT, "section " - "NAME should contain %s as " - "initial body child", + if ( ! (mdoc_nwarn(mdoc, n, WARN_SYNTAX, + "section should have %s first", mdoc_macronames[MDOC_Nm]))) return(0); } @@ -989,8 +1024,8 @@ post_sh_body(struct mdoc *mdoc) if (MDOC_ELEM == n->type && MDOC_Nd == n->tok) return(1); - return(mdoc_warn(mdoc, WARN_COMPAT, "section NAME should " - "contain %s as the last child", + return(mdoc_warn(mdoc, WARN_SYNTAX, + "section should have %s last", mdoc_macronames[MDOC_Nd])); } @@ -1003,19 +1038,22 @@ post_sh_head(struct mdoc *mdoc) assert(MDOC_Sh == mdoc->last->tok); - if ( ! xstrlcats(buf, mdoc->last->child, 64)) - return(mdoc_err(mdoc, "macro parameters too long")); + if ( ! xstrlcats(buf, mdoc->last->child, sizeof(buf))) + return(mdoc_err(mdoc, "argument too long")); sec = mdoc_atosec(buf); if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec) - return(mdoc_err(mdoc, "section NAME must be first")); + return(mdoc_warn(mdoc, WARN_SYNTAX, + "section NAME should be first")); if (SEC_CUSTOM == sec) return(1); if (sec == mdoc->lastnamed) - return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated")); + return(mdoc_warn(mdoc, WARN_SYNTAX, + "section repeated")); if (sec < mdoc->lastnamed) - return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order")); + return(mdoc_warn(mdoc, WARN_SYNTAX, + "section out of order")); return(1); } @@ -1027,7 +1065,7 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node) v_pre *p; if (MDOC_TEXT == node->type) - return(1); + return(pre_text(mdoc, node)); assert(MDOC_ROOT != node->type); if (NULL == mdoc_valids[node->tok].pre) @@ -1044,6 +1082,14 @@ mdoc_valid_post(struct mdoc *mdoc) { v_post *p; + /* + * This check occurs after the macro's children have been filled + * in: postfix validation. Since this happens when we're + * rewinding the scope tree, it's possible to have multiple + * invocations (as by design, for now), we set bit MDOC_VALID to + * indicate that we've validated. + */ + if (MDOC_VALID & mdoc->last->flags) return(1); mdoc->last->flags |= MDOC_VALID; |