3 * Compare version numbers using the Debian algorithm
5 * (c) 2007 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * mLib is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
34 #include "versioncmp.h"
36 /*----- Main code ---------------------------------------------------------*/
38 /* --- @versioncmp@ --- *
40 * Arguments: @const char *va, *vb@ = two version strings
42 * Returns: Less than, equal to, or greater than zero, according to
43 * whether @va@ is less than, equal to, or greater than @vb@.
45 * Use: Compares version number strings.
47 * The algorithm is an extension of the Debian version
48 * comparison algorithm. A version number consists of three
51 * [EPOCH :] MAIN [- SUB]
53 * The MAIN part may contain colons or hyphens if there is an
54 * EPOCH or SUB, respectively. Version strings are compared
55 * componentwise: first epochs, then main parts, and finally
58 * The component comparison is done as follows. First, the
59 * initial subsequence of nondigit characters is extracted from
60 * each string, and these are compared lexicographically, using
61 * ASCII ordering, except that letters precede non-letters. If
62 * both are the same, an initial sequence of digits is extracted
63 * from the remaining parts of the version strings, and these
64 * are compared numerically (an empty sequence being considered
65 * to have the value zero). This process is repeated until we
66 * have a winner or until both strings are exhausted.
75 static int vint(const char **vv, const char *vl)
86 n = n * 10 + (ch - '0');
92 static const char *vchr(const char **vv, const char *vl)
108 #define CMP(x, y) ((x) < (y) ? -1 : +1)
110 static int vcmp(const char *va, const char *val,
111 const char *vb, const char *vbl)
118 /* --- See if we're done --- */
120 if (va == val && vb == vbl)
123 /* --- Compare nondigit portions --- */
125 pa = vchr(&va, val); pb = vchr(&vb, vbl);
127 if (pa == va) ia = 1;
128 else if (ISALPHA(*pa)) ia = 2;
129 else if (*pa == '~') ia = 0;
132 if (pb == vb) ib = 1;
133 else if (ISALPHA(*pb)) ib = 2;
134 else if (*pb == '~') ib = 0;
137 if (ia != ib) return (CMP(ia, ib));
138 else if (pa == va && pb == vb) break;
139 else if (*pa != *pb) return (CMP(*pa, *pb));
143 /* --- Compare digit portions --- */
145 ia = vint(&va, val); ib = vint(&vb, vbl);
146 if (ia != ib) return (CMP(ia, ib));
150 static void vsplit(const char *v, struct vinfo *vi)
155 if ((p = strchr(v, ':')) == 0)
164 if ((p = strrchr(v, '-')) == 0)
176 int versioncmp(const char *va, const char *vb)
178 struct vinfo via, vib;
181 vsplit(va, &via); vsplit(vb, &vib);
182 if ((rc = vcmp(via.e, via.el, vib.e, vib.el)) != 0 ||
183 (rc = vcmp(via.m, via.ml, vib.m, vib.ml)) != 0 ||
184 (rc = vcmp(via.s, via.sl, vib.s, vib.sl)) != 0)
189 /*----- That's all, folks -------------------------------------------------*/