From 488b183811fc25c1ae49b4730491accf1adf518e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 2 Nov 2016 16:24:58 +0100 Subject: [PATCH] common: Improve compare_string_versions. * common/stringhelp.c: Include limits.h. (compare_version_strings): Change semantics to behave like strcmp. Include the patch lebel in the comparison. Allow checking a single version string. * common/t-stringhelp.c (test_compare_version_strings): Adjust test vectors and a few new vectors. * g10/call-agent.c (warn_version_mismatch): Adjust to new sematics. * g10/call-dirmngr.c (warn_version_mismatch): Ditto. * sm/call-agent.c (warn_version_mismatch): Ditto. * sm/call-dirmngr.c (warn_version_mismatch): Ditto. Signed-off-by: Werner Koch --- common/stringhelp.c | 57 ++++++++++++++++++++++++++-------------- common/t-stringhelp.c | 61 ++++++++++++++++++++++++++++--------------- g10/call-agent.c | 2 +- g10/call-dirmngr.c | 2 +- sm/call-agent.c | 2 +- sm/call-dirmngr.c | 2 +- 6 files changed, 82 insertions(+), 44 deletions(-) diff --git a/common/stringhelp.c b/common/stringhelp.c index b5d9f4cf6..f494bc5ad 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -49,6 +49,7 @@ # include #endif #include +#include #include "util.h" #include "common-defs.h" @@ -1356,9 +1357,9 @@ parse_version_number (const char *s, int *number) /* This function breaks up the complete string-representation of the version number S, which is of the following struture: ... The major, - minor and micro number components will be stored in *MAJOR, *MINOR - and *MICRO. + number>.[.]. The major, + minor, and micro number components will be stored in *MAJOR, *MINOR + and *MICRO. If MICRO is not given 0 is used instead. On success, the last component, the patch level, will be returned; in failure, NULL will be returned. */ @@ -1385,32 +1386,50 @@ parse_version_string (const char *s, int *major, int *minor, int *micro) } -/* Check that the version string MY_VERSION is greater or equal than - REQ_VERSION. Returns true if the condition is satisfied or false - if not. This works with 3 part and two part version strings; for a - two part version string the micor part is assumed to be 0. */ +/* Compare the version string MY_VERSION to the version string + * REQ_VERSION. Returns -1, 0, or 1 if MY_VERSION is found, + * respectively, to be less than, to match, or be greater than + * REQ_VERSION. This function works for three and two part version + * strings; for a two part version string the micro part is assumed to + * be 0. Patch levels are compared as strings. If a version number + * is invalid INT_MIN is returned. If REQ_VERSION is given as NULL + * the function returns 0 if MY_VERSION is parsable version string. */ int compare_version_strings (const char *my_version, const char *req_version) { int my_major, my_minor, my_micro; int rq_major, rq_minor, rq_micro; + const char *my_patch, *rq_patch; + int result; - if (!my_version || !req_version) - return 0; + if (!my_version) + return INT_MIN; - if (!parse_version_string (my_version, &my_major, &my_minor, &my_micro)) - return 0; - if (!parse_version_string(req_version, &rq_major, &rq_minor, &rq_micro)) - return 0; + my_patch = parse_version_string (my_version, &my_major, &my_minor, &my_micro); + if (!my_patch) + return INT_MIN; + if (!req_version) + return 0; /* MY_VERSION can be parsed. */ + rq_patch = parse_version_string (req_version, &rq_major, &rq_minor,&rq_micro); + if (!rq_patch) + return INT_MIN; - if (my_major > rq_major - || (my_major == rq_major && my_minor > rq_minor) - || (my_major == rq_major && my_minor == rq_minor - && my_micro >= rq_micro)) + if (my_major == rq_major) { - return 1; + if (my_minor == rq_minor) + { + if (my_micro == rq_micro) + result = strcmp (my_patch, rq_patch); + else + result = my_micro - rq_micro; + } + else + result = my_minor - rq_minor; } - return 0; + else + result = my_major - rq_major; + + return !result? 0 : result < 0 ? -1 : 1; } diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c index ccadf0222..93b014ae1 100644 --- a/common/t-stringhelp.c +++ b/common/t-stringhelp.c @@ -40,6 +40,7 @@ #endif #include #include +#include #include "t-support.h" #include "stringhelp.h" @@ -903,45 +904,63 @@ static void test_compare_version_strings (void) { struct { const char *a; const char *b; int okay; } tests[] = { - { "1.0.0", "1.0.0", 1 }, + { "1.0.0", "1.0.0", 0 }, { "1.0.0-", "1.0.0", 1 }, { "1.0.0-1", "1.0.0", 1 }, { "1.0.0.1", "1.0.0", 1 }, - { "1.0.0", "1.0.1", 0 }, - { "1.0.0-", "1.0.1", 0 }, - { "1.0.0-1", "1.0.1", 0 }, - { "1.0.0.1", "1.0.1", 0 }, - { "1.0.0", "1.1.0", 0 }, - { "1.0.0-", "1.1.0", 0 }, - { "1.0.0-1", "1.1.0", 0 }, - { "1.0.0.1", "1.1.0", 0 }, + { "1.0.0", "1.0.1", -1 }, + { "1.0.0-", "1.0.1", -1 }, + { "1.0.0-1", "1.0.1", -1 }, + { "1.0.0.1", "1.0.1", -1 }, + { "1.0.0", "1.1.0", -1 }, + { "1.0.0-", "1.1.0", -1 }, + { "1.0.0-1", "1.1.0", -1 }, + { "1.0.0.1", "1.1.0", -1 }, - { "1.0.0", "1.0.0-", 1 }, - { "1.0.0", "1.0.0-1", 1 }, - { "1.0.0", "1.0.0.1", 1 }, + { "1.0.0", "1.0.0-", -1 }, + { "1.0.0", "1.0.0-1", -1 }, + { "1.0.0", "1.0.0.1", -1 }, { "1.1.0", "1.0.0", 1 }, { "1.1.1", "1.1.0", 1 }, - { "1.1.2", "1.1.2", 1 }, + { "1.1.2", "1.1.2", 0 }, { "1.1.2", "1.0.2", 1 }, { "1.1.2", "0.0.2", 1 }, - { "1.1.2", "1.1.3", 0 }, + { "1.1.2", "1.1.3", -1 }, { "0.99.1", "0.9.9", 1 }, - { "0.9.1", "0.91.0", 0 }, + { "0.9.1", "0.91.0", -1 }, { "1.5.3", "1.5", 1 }, - { "1.5.0", "1.5", 1 }, - { "1.4.99", "1.5", 0 }, + { "1.5.0", "1.5", 0 }, + { "1.4.99", "1.5", -1 }, { "1.5", "1.4.99", 1 }, - { "1.5", "1.5.0", 1 }, - { "1.5", "1.5.1", 0 }, + { "1.5", "1.5.0", 0 }, + { "1.5", "1.5.1", -1 }, { "1.5.3-x17", "1.5-23", 1 }, { "1.5.3a", "1.5.3", 1 }, - { "1.5.3a", "1.5.3b", 1 }, + { "1.5.3a", "1.5.3b", -1 }, - { NULL, NULL, 0 } + { "3.1.4-ab", "3.1.4-ab", 0 }, + { "3.1.4-ab", "3.1.4-ac", -1 }, + { "3.1.4-ac", "3.1.4-ab", 1 }, + { "3.1.4-ab", "3.1.4-abb", -1 }, + { "3.1.4-abb", "3.1.4-ab", 1 }, + + { "", "", INT_MIN }, + { NULL, "", INT_MIN }, + { "1.2.3", "", INT_MIN }, + { "1.2.3", "2", INT_MIN }, + + /* Test cases for validity of A. */ + { "", NULL, INT_MIN }, + { "1", NULL, INT_MIN }, + { "1.", NULL, 0 }, + { "1.0", NULL, 0 }, + { "1.0.", NULL, 0 }, + { "a1.2", NULL, INT_MIN }, + { NULL, NULL, INT_MIN } }; int idx; int res; diff --git a/g10/call-agent.c b/g10/call-agent.c index b17a80f11..eeea7bf97 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -195,7 +195,7 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode) if (err) log_error (_("error getting version from '%s': %s\n"), servername, gpg_strerror (err)); - else if (!compare_version_strings (serverversion, myversion)) + else if (compare_version_strings (serverversion, myversion) < 0) { char *warn; diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index f7398333c..66db357db 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -145,7 +145,7 @@ warn_version_mismatch (assuan_context_t ctx, const char *servername) if (err) log_error (_("error getting version from '%s': %s\n"), servername, gpg_strerror (err)); - else if (!compare_version_strings (serverversion, myversion)) + else if (compare_version_strings (serverversion, myversion) < 0) { char *warn; diff --git a/sm/call-agent.c b/sm/call-agent.c index c0a2081fe..c9a210fa5 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -97,7 +97,7 @@ warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx, if (err) log_error (_("error getting version from '%s': %s\n"), servername, gpg_strerror (err)); - else if (!compare_version_strings (serverversion, myversion)) + else if (compare_version_strings (serverversion, myversion) < 0) { char *warn; diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 03c9a6833..6d7053c54 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -163,7 +163,7 @@ warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx, if (err) log_error (_("error getting version from '%s': %s\n"), servername, gpg_strerror (err)); - else if (!compare_version_strings (serverversion, myversion)) + else if (compare_version_strings (serverversion, myversion) < 0) { char *warn;