common: Improve compare_string_versions.
authorWerner Koch <wk@gnupg.org>
Wed, 2 Nov 2016 15:24:58 +0000 (16:24 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 2 Nov 2016 16:58:11 +0000 (17:58 +0100)
* 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 <wk@gnupg.org>
common/stringhelp.c
common/t-stringhelp.c
g10/call-agent.c
g10/call-dirmngr.c
sm/call-agent.c
sm/call-dirmngr.c

index b5d9f4c..f494bc5 100644 (file)
@@ -49,6 +49,7 @@
 # include <windows.h>
 #endif
 #include <assert.h>
+#include <limits.h>
 
 #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: <major
-   number>.<minor number>.<micro number><patch level>.  The major,
-   minor and micro number components will be stored in *MAJOR, *MINOR
-   and *MICRO.
+   number>.<minor number>[.<micro number>]<patch level>.  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;
-
-  if (!my_version || !req_version)
-    return 0;
-
-  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;
-
-  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))
+  const char *my_patch, *rq_patch;
+  int result;
+
+  if (!my_version)
+    return INT_MIN;
+
+  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)
     {
-      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;
 }
 
 
index ccadf02..93b014a 100644 (file)
@@ -40,6 +40,7 @@
 #endif
 #include <unistd.h>
 #include <sys/types.h>
+#include <limits.h>
 
 #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.0-", 1 },
-    { "1.0.0",   "1.0.0-1", 1 },
-    { "1.0.0",   "1.0.0.1", 1 },
+    { "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.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 },
-
-    { NULL, NULL, 0 }
+    { "1.5.3a",   "1.5.3b",  -1 },
+
+    { "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;
index b17a80f..eeea7bf 100644 (file)
@@ -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;
 
index f739833..66db357 100644 (file)
@@ -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;
 
index c0a2081..c9a210f 100644 (file)
@@ -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;
 
index 03c9a68..6d7053c 100644 (file)
@@ -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;