summaryrefslogtreecommitdiffstats
path: root/lib/dpkg/version.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dpkg/version.c')
-rw-r--r--lib/dpkg/version.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/lib/dpkg/version.c b/lib/dpkg/version.c
new file mode 100644
index 0000000..e9bc4bb
--- /dev/null
+++ b/lib/dpkg/version.c
@@ -0,0 +1,198 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * version.c - version handling functions
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <dpkg/c-ctype.h>
+#include <dpkg/ehandle.h>
+#include <dpkg/string.h>
+#include <dpkg/version.h>
+
+/**
+ * Turn the passed version into an empty version.
+ *
+ * This can be used to ensure the version is properly initialized.
+ *
+ * @param version The version to clear.
+ */
+void
+dpkg_version_blank(struct dpkg_version *version)
+{
+ version->epoch = 0;
+ version->version = NULL;
+ version->revision = NULL;
+}
+
+/**
+ * Test if a version is not empty.
+ *
+ * @param version The version to test.
+ *
+ * @retval true If the version is informative (i.e. not an empty version).
+ * @retval false If the version is empty.
+ */
+bool
+dpkg_version_is_informative(const struct dpkg_version *version)
+{
+ return (version->epoch ||
+ str_is_set(version->version) ||
+ str_is_set(version->revision));
+}
+
+/**
+ * Give a weight to the character to order in the version comparison.
+ *
+ * @param c An ASCII character.
+ */
+static int
+order(int c)
+{
+ if (c_isdigit(c))
+ return 0;
+ else if (c_isalpha(c))
+ return c;
+ else if (c == '~')
+ return -1;
+ else if (c)
+ return c + 256;
+ else
+ return 0;
+}
+
+static int
+verrevcmp(const char *a, const char *b)
+{
+ if (a == NULL)
+ a = "";
+ if (b == NULL)
+ b = "";
+
+ while (*a || *b) {
+ int first_diff = 0;
+
+ while ((*a && !c_isdigit(*a)) || (*b && !c_isdigit(*b))) {
+ int ac = order(*a);
+ int bc = order(*b);
+
+ if (ac != bc)
+ return ac - bc;
+
+ a++;
+ b++;
+ }
+ while (*a == '0')
+ a++;
+ while (*b == '0')
+ b++;
+ while (c_isdigit(*a) && c_isdigit(*b)) {
+ if (!first_diff)
+ first_diff = *a - *b;
+ a++;
+ b++;
+ }
+
+ if (c_isdigit(*a))
+ return 1;
+ if (c_isdigit(*b))
+ return -1;
+ if (first_diff)
+ return first_diff;
+ }
+
+ return 0;
+}
+
+/**
+ * Compares two Debian versions.
+ *
+ * This function follows the convention of the comparator functions used by
+ * qsort().
+ *
+ * @see deb-version(5)
+ *
+ * @param a The first version.
+ * @param b The second version.
+ *
+ * @retval 0 If a and b are equal.
+ * @retval <0 If a is smaller than b.
+ * @retval >0 If a is greater than b.
+ */
+int
+dpkg_version_compare(const struct dpkg_version *a,
+ const struct dpkg_version *b)
+{
+ int rc;
+
+ if (a->epoch > b->epoch)
+ return 1;
+ if (a->epoch < b->epoch)
+ return -1;
+
+ rc = verrevcmp(a->version, b->version);
+ if (rc)
+ return rc;
+
+ return verrevcmp(a->revision, b->revision);
+}
+
+/**
+ * Check if two versions have a certain relation.
+ *
+ * @param a The first version.
+ * @param rel The relation.
+ * @param b The second version.
+ *
+ * @retval true If rel is #DPKG_RELATION_NONE or the expression “a rel b” is
+ * true.
+ * @retval false Otherwise.
+ *
+ * @warning If rel is not a valid relation, this function will terminate
+ * the program.
+ */
+bool
+dpkg_version_relate(const struct dpkg_version *a,
+ enum dpkg_relation rel,
+ const struct dpkg_version *b)
+{
+ int rc;
+
+ if (rel == DPKG_RELATION_NONE)
+ return true;
+
+ rc = dpkg_version_compare(a, b);
+
+ switch (rel) {
+ case DPKG_RELATION_EQ:
+ return rc == 0;
+ case DPKG_RELATION_LT:
+ return rc < 0;
+ case DPKG_RELATION_LE:
+ return rc <= 0;
+ case DPKG_RELATION_GT:
+ return rc > 0;
+ case DPKG_RELATION_GE:
+ return rc >= 0;
+ default:
+ internerr("unknown dpkg_relation %d", rel);
+ }
+ return false;
+}