return (0);
}
+/* --- @versioncmp@ --- *
+ *
+ * Arguments: @const char *va, *vb@ = two version strings
+ *
+ * Returns: Less than, equal to, or greater than zero, according to
+ * whether @va@ is less than, equal to, or greater than @vb@.
+ *
+ * Use: Compares version number strings.
+ *
+ * The algorithm is an extension of the Debian version
+ * comparison algorithm. A version number consists of three
+ * components:
+ *
+ * [EPOCH :] MAIN [- SUB]
+ *
+ * The MAIN part may contain colons or hyphens if there is an
+ * EPOCH or SUB, respectively. Version strings are compared
+ * componentwise: first epochs, then main parts, and finally
+ * subparts.
+ *
+ * The component comparison is done as follows. First, the
+ * initial subsequence of nondigit characters is extracted from
+ * each string, and these are compared lexicographically, using
+ * ASCII ordering, except that letters precede non-letters. If
+ * both are the same, an initial sequence of digits is extracted
+ * from the remaining parts of the version strings, and these
+ * are compared numerically (an empty sequence being considered
+ * to have the value zero). This process is repeated until we
+ * have a winner or until both strings are exhausted.
+ */
+
+struct vinfo {
+ const char *e, *el;
+ const char *m, *ml;
+ const char *s, *sl;
+};
+
+static int vint(const char **vv, const char *vl)
+{
+ int n = 0;
+ const char *v = *vv;
+ int ch;
+
+ while (v < vl) {
+ ch = *v;
+ if (!isdigit((unsigned char)ch))
+ break;
+ v++;
+ n = n * 10 + (ch - '0');
+ }
+ *vv = v;
+ return (n);
+}
+
+static const char *vchr(const char **vv, const char *vl)
+{
+ const char *v = *vv;
+ const char *b = v;
+ int ch;
+
+ while (v < vl) {
+ ch = *v;
+ if (isdigit((unsigned char)ch))
+ break;
+ v++;
+ }
+ *vv = v;
+ return (b);
+}
+
+#define CMP(x, y) ((x) < (y) ? -1 : +1)
+
+static int vcmp(const char *va, const char *val,
+ const char *vb, const char *vbl)
+{
+ const char *pa, *pb;
+ int ia, ib;
+
+ for (;;) {
+
+ /* --- See if we're done --- */
+
+ if (va == val && vb == vbl)
+ return (0);
+
+ /* --- Compare nondigit portions --- */
+
+ pa = vchr(&va, val); pb = vchr(&vb, vbl);
+ for (;;) {
+ if (pa == va && pb == vb)
+ break;
+ else if (pa == va)
+ return (-1);
+ else if (pb == vb)
+ return (+1);
+ else if (*pa == *pb) {
+ pa++; pb++;
+ continue;
+ } else if (isalpha((unsigned char)*pa) == isalpha((unsigned char)*pb))
+ return (CMP(*pa, *pb));
+ else if (isalpha((unsigned char)*pa))
+ return (-1);
+ else
+ return (+1);
+ }
+
+ /* --- Compare digit portions --- */
+
+ ia = vint(&va, val); ib = vint(&vb, vbl);
+ if (ia != ib)
+ return (CMP(ia, ib));
+ }
+}
+
+static void vsplit(const char *v, struct vinfo *vi)
+{
+ const char *p;
+ size_t n;
+
+ if ((p = strchr(v, ':')) == 0)
+ vi->e = vi->el = 0;
+ else {
+ vi->e = v;
+ vi->el = p;
+ v = p + 1;
+ }
+
+ n = strlen(v);
+ if ((p = strrchr(v, '-')) == 0)
+ vi->s = vi->sl = 0;
+ else {
+ vi->s = p + 1;
+ vi->sl = v + n;
+ n = p - v;
+ }
+
+ vi->m = v;
+ vi->ml = v + n;
+}
+
+int versioncmp(const char *va, const char *vb)
+{
+ struct vinfo via, vib;
+ int rc;
+
+ vsplit(va, &via); vsplit(vb, &vib);
+ if ((rc = vcmp(via.e, via.el, vib.e, vib.el)) != 0 ||
+ (rc = vcmp(via.m, via.ml, vib.m, vib.ml)) != 0 ||
+ (rc = vcmp(via.s, via.sl, vib.s, vib.sl)) != 0)
+ return (rc);
+ return (0);
+}
+
/*----- That's all, folks -------------------------------------------------*/