The following commit has been merged in the master branch:
commit ccc26399f2f0e295da1206c5ce81fe81a5dc0e21
Author: Guillem Jover <[email protected]>
Date: Wed Sep 14 04:18:47 2011 +0200
libdpkg: Switch parseversion() to use dpkg_error
This allows to merge back the parseversion_lax() and
version_strict_check() functions into a single parseversion(), which
performs all the validation, but issues different types of dpkg_error
messages on error. Which simplifies parse_db_version() and will allow
for callers to distinguish the error conditions and handle them as
they see fit.
diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h
index 353183f..31b4c13 100644
--- a/lib/dpkg/dpkg-db.h
+++ b/lib/dpkg/dpkg-db.h
@@ -287,10 +287,13 @@ extern const struct namevalue statusinfos[];
extern const struct namevalue eflaginfos[];
extern const struct namevalue wantinfos[];
+#include <dpkg/error.h>
+
enum versiondisplayepochwhen { vdew_never, vdew_nonambig, vdew_always };
void varbufversion(struct varbuf*, const struct versionrevision*,
enum versiondisplayepochwhen);
-const char *parseversion(struct versionrevision *rversion, const char*);
+int parseversion(struct versionrevision *rversion, const char *,
+ struct dpkg_error *err);
const char *versiondescribe(const struct versionrevision*,
enum versiondisplayepochwhen);
diff --git a/lib/dpkg/parsehelp.c b/lib/dpkg/parsehelp.c
index 5121da6..6f4616e 100644
--- a/lib/dpkg/parsehelp.c
+++ b/lib/dpkg/parsehelp.c
@@ -30,6 +30,7 @@
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/string.h>
+#include <dpkg/error.h>
#include <dpkg/parsedump.h>
static const char *
@@ -184,14 +185,28 @@ const char *versiondescribe
return vb->buf;
}
-static const char *
-parseversion_lax(struct versionrevision *rversion, const char *string)
+/**
+ * Parse a version string and check for invalid syntax.
+ *
+ * Distinguish between lax (warnings) and strict (error) parsing.
+ *
+ * @param rversion The parsed version.
+ * @param string The version string to parse.
+ * @param err The warning or error message if any.
+ *
+ * @retval 0 On success.
+ * @retval -1 On failure, and err is set accordingly.
+ */
+int
+parseversion(struct versionrevision *rversion, const char *string,
+ struct dpkg_error *err)
{
char *hyphen, *colon, *eepochcolon;
const char *end, *ptr;
unsigned long epoch;
- if (!*string) return _("version string is empty");
+ if (!*string)
+ return dpkg_put_error(err, _("version string is empty"));
/* Trim leading and trailing space. */
while (*string && isblank(*string))
@@ -205,13 +220,16 @@ parseversion_lax(struct versionrevision *rversion, const
char *string)
ptr = end;
while (*ptr && isblank(*ptr))
ptr++;
- if (*ptr) return _("version string has embedded spaces");
+ if (*ptr)
+ return dpkg_put_error(err, _("version string has embedded spaces"));
colon= strchr(string,':');
if (colon) {
epoch= strtoul(string,&eepochcolon,10);
- if (colon != eepochcolon) return _("epoch in version is not number");
- if (!*++colon) return _("nothing after colon in version number");
+ if (colon != eepochcolon)
+ return dpkg_put_error(err, _("epoch in version is not number"));
+ if (!*++colon)
+ return dpkg_put_error(err, _("nothing after colon in version number"));
string= colon;
rversion->epoch= epoch;
} else {
@@ -223,50 +241,20 @@ parseversion_lax(struct versionrevision *rversion, const
char *string)
*hyphen++ = '\0';
rversion->revision= hyphen ? hyphen : "";
- return NULL;
-}
-
-/**
- * Check for invalid syntax in version structure.
- *
- * The rest of the syntax has been already checked in parseversion_lax(). So
- * we only do the stricter checks here.
- *
- * @param rversion The version to verify.
- *
- * @return An error string, or NULL if eveyrthing was ok.
- */
-static const char *
-version_strict_check(struct versionrevision *rversion)
-{
- const char *ptr;
-
/* XXX: Would be faster to use something like cisversion and cisrevision. */
ptr = rversion->version;
if (*ptr && !cisdigit(*ptr++))
- return _("version number does not start with digit");
+ return dpkg_put_warn(err, _("version number does not start with digit"));
for (; *ptr; ptr++) {
if (!cisdigit(*ptr) && !cisalpha(*ptr) && strchr(".-+~:", *ptr) == NULL)
- return _("invalid character in version number");
+ return dpkg_put_warn(err, _("invalid character in version number"));
}
for (ptr = rversion->revision; *ptr; ptr++) {
if (!cisdigit(*ptr) && !cisalpha(*ptr) && strchr(".+~", *ptr) == NULL)
- return _("invalid character in revision number");
+ return dpkg_put_warn(err, _("invalid character in revision number"));
}
- return NULL;
-}
-
-const char *
-parseversion(struct versionrevision *rversion, const char *string)
-{
- const char *emsg;
-
- emsg = parseversion_lax(rversion, string);
- if (emsg)
- return emsg;
-
- return version_strict_check(rversion);
+ return 0;
}
/**
@@ -284,29 +272,21 @@ void
parse_db_version(struct parsedb_state *ps, struct versionrevision *version,
const char *value, const char *fmt, ...)
{
- const char *msg;
- bool warn_msg = false;
-
- msg = parseversion_lax(version, value);
- if (msg == NULL) {
- msg = version_strict_check(version);
- if (ps->flags & pdb_lax_parser)
- warn_msg = true;
- }
+ struct dpkg_error err;
+ va_list args;
+ char buf[1000];
- if (msg) {
- va_list args;
- char buf[1000];
+ if (parseversion(version, value, &err) == 0)
+ return;
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
- if (warn_msg)
- parse_warn(ps, "%s: %.250s", buf, msg);
- else
- parse_error(ps, "%s: %.250s", buf, msg);
- }
+ if (err.type == DPKG_MSG_WARN && (ps->flags & pdb_lax_parser))
+ parse_warn(ps, "%s: %.250s", buf, err.str);
+ else
+ parse_error(ps, "%s: %.250s", buf, err.str);
}
void
diff --git a/lib/dpkg/test/t-version.c b/lib/dpkg/test/t-version.c
index 090ae23..cf99375 100644
--- a/lib/dpkg/test/t-version.c
+++ b/lib/dpkg/test/t-version.c
@@ -63,9 +63,21 @@ test_version_compare(void)
/* FIXME: Complete. */
}
+#define test_warn(e) \
+ do { \
+ test_pass((e).type == DPKG_MSG_WARN); \
+ dpkg_error_destroy(&(e)); \
+ } while (0)
+#define test_error(e) \
+ do { \
+ test_pass((e).type == DPKG_MSG_ERROR); \
+ dpkg_error_destroy(&(e)); \
+ } while (0)
+
static void
test_version_parse(void)
{
+ struct dpkg_error err;
struct versionrevision a, b;
const char *p;
char *verstr;
@@ -74,100 +86,109 @@ test_version_parse(void)
blankversion(&a);
b = version(0, "0", "");
- test_pass(parseversion(&a, "0") == NULL);
+ test_pass(parseversion(&a, "0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
- test_pass(parseversion(&a, "0:0") == NULL);
+ test_pass(parseversion(&a, "0:0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
- test_pass(parseversion(&a, "0:0-") == NULL);
+ test_pass(parseversion(&a, "0:0-", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
b = version(0, "0", "0");
- test_pass(parseversion(&a, "0:0-0") == NULL);
+ test_pass(parseversion(&a, "0:0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
b = version(0, "0.0", "0.0");
- test_pass(parseversion(&a, "0:0.0-0.0") == NULL);
+ test_pass(parseversion(&a, "0:0.0-0.0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test epoched versions. */
b = version(1, "0", "");
- test_pass(parseversion(&a, "1:0") == NULL);
+ test_pass(parseversion(&a, "1:0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
b = version(5, "1", "");
- test_pass(parseversion(&a, "5:1") == NULL);
+ test_pass(parseversion(&a, "5:1", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test multiple dashes. */
b = version(0, "0-0", "0");
- test_pass(parseversion(&a, "0:0-0-0") == NULL);
+ test_pass(parseversion(&a, "0:0-0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
b = version(0, "0-0-0", "0");
- test_pass(parseversion(&a, "0:0-0-0-0") == NULL);
+ test_pass(parseversion(&a, "0:0-0-0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test multiple colons. */
b = version(0, "0:0", "0");
- test_pass(parseversion(&a, "0:0:0-0") == NULL);
+ test_pass(parseversion(&a, "0:0:0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
b = version(0, "0:0:0", "0");
- test_pass(parseversion(&a, "0:0:0:0-0") == NULL);
+ test_pass(parseversion(&a, "0:0:0:0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test multiple dashes and colons. */
b = version(0, "0:0-0", "0");
- test_pass(parseversion(&a, "0:0:0-0-0") == NULL);
+ test_pass(parseversion(&a, "0:0:0-0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
b = version(0, "0-0:0", "0");
- test_pass(parseversion(&a, "0:0-0:0-0") == NULL);
+ test_pass(parseversion(&a, "0:0-0:0-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test valid characters in upstream version. */
b = version(0, "09azAZ.-+~:", "0");
- test_pass(parseversion(&a, "0:09azAZ.-+~:-0") == NULL);
+ test_pass(parseversion(&a, "0:09azAZ.-+~:-0", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test valid characters in revision. */
b = version(0, "0", "azAZ09.+~");
- test_pass(parseversion(&a, "0:0-azAZ09.+~") == NULL);
+ test_pass(parseversion(&a, "0:0-azAZ09.+~", NULL) == 0);
test_pass(versioncompare(&a, &b) == 0);
/* Test empty version. */
- test_fail(parseversion(&a, "") == NULL);
+ test_pass(parseversion(&a, "", &err) != 0);
+ test_error(err);
/* Test empty upstream version after epoch. */
- test_fail(parseversion(&a, "0:") == NULL);
+ test_fail(parseversion(&a, "0:", &err) == 0);
+ test_error(err);
/* Test version with embedded spaces. */
- test_fail(parseversion(&a, "0:0 0-1") == NULL);
+ test_fail(parseversion(&a, "0:0 0-1", &err) == 0);
+ test_error(err);
/* Test invalid characters in epoch. */
- test_fail(parseversion(&a, "a:0-0") == NULL);
- test_fail(parseversion(&a, "A:0-0") == NULL);
+ test_fail(parseversion(&a, "a:0-0", &err) == 0);
+ test_error(err);
+ test_fail(parseversion(&a, "A:0-0", &err) == 0);
+ test_error(err);
/* Test upstream version not starting with a digit */
- test_fail(parseversion(&a, "0:abc3-0") == NULL);
+ test_fail(parseversion(&a, "0:abc3-0", &err) == 0);
+ test_warn(err);
/* Test invalid characters in upstream version. */
verstr = m_strdup("0:0a-0");
for (p = "!#@$%&/|\\<>()[]{};,_=*^'"; *p; p++) {
verstr[3] = *p;
- test_fail(parseversion(&a, verstr) == NULL);
+ test_fail(parseversion(&a, verstr, &err) == 0);
+ test_warn(err);
}
free(verstr);
/* Test invalid characters in revision. */
- test_fail(parseversion(&a, "0:0-0:0") == NULL);
+ test_fail(parseversion(&a, "0:0-0:0", &err) == 0);
+ test_warn(err);
verstr = m_strdup("0:0-0");
for (p = "!#@$%&/|\\<>()[]{}:;,_=*^'"; *p; p++) {
verstr[4] = *p;
- test_fail(parseversion(&a, verstr) == NULL);
+ test_fail(parseversion(&a, verstr, &err) == 0);
+ test_warn(err);
}
free(verstr);
diff --git a/src/enquiry.c b/src/enquiry.c
index 40c3e73..54c0412 100644
--- a/src/enquiry.c
+++ b/src/enquiry.c
@@ -511,8 +511,8 @@ cmpversions(const char *const *argv)
};
const struct relationinfo *rip;
- const char *emsg;
struct versionrevision a, b;
+ struct dpkg_error err;
int r;
if (!argv[0] || !argv[1] || !argv[2] || argv[3])
@@ -524,16 +524,14 @@ cmpversions(const char *const *argv)
if (!rip->string) badusage(_("--compare-versions bad relation"));
if (*argv[0] && strcmp(argv[0],"<unknown>")) {
- emsg= parseversion(&a,argv[0]);
- if (emsg)
- ohshit(_("version '%s' has bad syntax: %s"), argv[0], emsg);
+ if (parseversion(&a, argv[0], &err) < 0)
+ ohshit(_("version '%s' has bad syntax: %s"), argv[0], err.str);
} else {
blankversion(&a);
}
if (*argv[2] && strcmp(argv[2],"<unknown>")) {
- emsg= parseversion(&b,argv[2]);
- if (emsg)
- ohshit(_("version '%s' has bad syntax: %s"), argv[2], emsg);
+ if (parseversion(&b, argv[2], &err) < 0)
+ ohshit(_("version '%s' has bad syntax: %s"), argv[2], err.str);
} else {
blankversion(&b);
}
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]