summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2017-05-01 19:16:44 +0100
committerRichard Hughes <richard@hughsie.com>2017-05-02 07:59:47 +0100
commitccec0538498cf1f8171efea92c9eaa43d4875894 (patch)
treed54bb8b983febee5b6a3059e6e15ba6191cf8675
parentd54e56034feb0c2f51cbb37cf506788f680cc53c (diff)
downloadappstream-glib-ccec0538498cf1f8171efea92c9eaa43d4875894.tar.gz
Support non-numeric version numbers correctly
Fall back to strcmp when both sections are non-numeric. Also add a 'vercmp' command to appstream-util to allow us to use this on the command line.
-rw-r--r--client/as-util.c40
-rw-r--r--libappstream-glib/as-self-test.c9
-rw-r--r--libappstream-glib/as-utils.c30
3 files changed, 70 insertions, 9 deletions
diff --git a/client/as-util.c b/client/as-util.c
index 20ddb7b..fea9a64 100644
--- a/client/as-util.c
+++ b/client/as-util.c
@@ -4129,6 +4129,40 @@ as_util_markup_import (AsUtilPrivate *priv, gchar **values, GError **error)
return TRUE;
}
+static gboolean
+as_util_vercmp (AsUtilPrivate *priv, gchar **values, GError **error)
+{
+ gint rc;
+
+ /* check args */
+ if (g_strv_length (values) != 2) {
+ g_set_error_literal (error,
+ AS_ERROR,
+ AS_ERROR_INVALID_ARGUMENTS,
+ "expected VERSION1 VERSION2");
+ return FALSE;
+ }
+
+ /* compare */
+ rc = as_utils_vercmp (values[0], values[1]);
+ if (rc == G_MAXINT) {
+ g_set_error_literal (error,
+ AS_ERROR,
+ AS_ERROR_INVALID_ARGUMENTS,
+ "failed to compare version numbers");
+ return FALSE;
+ }
+
+ /* print results */
+ if (rc == 0)
+ g_print ("%s = %s\n", values[0], values[1]);
+ else if (rc < 0)
+ g_print ("%s < %s\n", values[0], values[1]);
+ else if (rc > 0)
+ g_print ("%s > %s\n", values[0], values[1]);
+ return TRUE;
+}
+
static void
as_util_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level,
const gchar *message, gpointer user_data)
@@ -4414,6 +4448,12 @@ main (int argc, char *argv[])
/* TRANSLATORS: command description */
_("Watch AppStream locations for changes"),
as_util_watch);
+ as_util_add (priv->cmd_array,
+ "vercmp",
+ NULL,
+ /* TRANSLATORS: command description */
+ _("Compare version numbers"),
+ as_util_vercmp);
/* sort by command name */
g_ptr_array_sort (priv->cmd_array,
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index 48a4ba2..93935e4 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -4959,11 +4959,16 @@ as_test_utils_vercmp_func (void)
g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.3.1"), <, 0);
g_assert_cmpint (as_utils_vercmp ("1.2.3.1", "1.2.4"), <, 0);
- /* non-numeric */
+ /* mixed-alpha-numeric */
g_assert_cmpint (as_utils_vercmp ("1.2xxx.3", "1.2.3"), ==, G_MAXINT);
- g_assert_cmpint (as_utils_vercmp ("1.2a.3", "1.2b.3"), ==, G_MAXINT);
+ g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2xxx.3"), ==, G_MAXINT);
g_assert_cmpint (as_utils_vercmp ("1.2.-3", "1.2.3"), ==, G_MAXINT);
+ /* alpha-compare */
+ g_assert_cmpint (as_utils_vercmp ("1.2a.3", "1.2a.3"), ==, 0);
+ g_assert_cmpint (as_utils_vercmp ("1.2a.3", "1.2b.3"), <, 0);
+ g_assert_cmpint (as_utils_vercmp ("1.2b.3", "1.2a.3"), >, 0);
+
/* invalid */
g_assert_cmpint (as_utils_vercmp ("1", NULL), ==, G_MAXINT);
g_assert_cmpint (as_utils_vercmp (NULL, "1"), ==, G_MAXINT);
diff --git a/libappstream-glib/as-utils.c b/libappstream-glib/as-utils.c
index 76e4dd6..6303ac3 100644
--- a/libappstream-glib/as-utils.c
+++ b/libappstream-glib/as-utils.c
@@ -1378,6 +1378,8 @@ as_utils_vercmp (const gchar *version_a, const gchar *version_b)
split_b = g_strsplit (str_b, ".", -1);
longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b));
for (i = 0; i < longest_split; i++) {
+ gboolean isnum_a = TRUE;
+ gboolean isnum_b = TRUE;
/* we lost or gained a dot */
if (split_a[i] == NULL)
@@ -1388,18 +1390,32 @@ as_utils_vercmp (const gchar *version_a, const gchar *version_b)
/* compare integers */
ver_a = g_ascii_strtoll (split_a[i], &endptr, 10);
if (endptr != NULL && endptr[0] != '\0')
- return G_MAXINT;
+ isnum_a = FALSE;
if (ver_a < 0)
- return G_MAXINT;
+ isnum_a = FALSE;
ver_b = g_ascii_strtoll (split_b[i], &endptr, 10);
if (endptr != NULL && endptr[0] != '\0')
- return G_MAXINT;
+ isnum_b = FALSE;
if (ver_b < 0)
+ isnum_b = FALSE;
+
+ /* can't compare integer with string */
+ if (isnum_a != isnum_b)
return G_MAXINT;
- if (ver_a < ver_b)
- return -1;
- if (ver_a > ver_b)
- return 1;
+
+ /* compare strings */
+ if (!isnum_a) {
+ gint rc = g_strcmp0 (split_a[i], split_b[i]);
+ if (rc != 0)
+ return rc;
+
+ /* compare integers */
+ } else {
+ if (ver_a < ver_b)
+ return -1;
+ if (ver_a > ver_b)
+ return 1;
+ }
}
/* we really shouldn't get here */