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 ------------------------------------------------------*/
33 #include "versioncmp.h"
35 /*----- Main code ---------------------------------------------------------*/
37 /* --- @versioncmp@ --- *
39 * Arguments: @const char *va, *vb@ = two version strings
41 * Returns: Less than, equal to, or greater than zero, according to
42 * whether @va@ is less than, equal to, or greater than @vb@.
44 * Use: Compares version number strings.
46 * The algorithm is an extension of the Debian version
47 * comparison algorithm. A version number consists of three
50 * [EPOCH :] MAIN [- SUB]
52 * The MAIN part may contain colons or hyphens if there is an
53 * EPOCH or SUB, respectively. Version strings are compared
54 * componentwise: first epochs, then main parts, and finally
57 * The component comparison is done as follows. First, the
58 * initial subsequence of nondigit characters is extracted from
59 * each string, and these are compared lexicographically, using
60 * ASCII ordering, except that letters precede non-letters. If
61 * both are the same, an initial sequence of digits is extracted
62 * from the remaining parts of the version strings, and these
63 * are compared numerically (an empty sequence being considered
64 * to have the value zero). This process is repeated until we
65 * have a winner or until both strings are exhausted.
74 static int vint(const char **vv
, const char *vl
)
82 if (!isdigit((unsigned char)ch
))
85 n
= n
* 10 + (ch
- '0');
91 static const char *vchr(const char **vv
, const char *vl
)
99 if (isdigit((unsigned char)ch
))
107 #define CMP(x, y) ((x) < (y) ? -1 : +1)
109 static int vcmp(const char *va
, const char *val
,
110 const char *vb
, const char *vbl
)
117 /* --- See if we're done --- */
119 if (va
== val
&& vb
== vbl
)
122 /* --- Compare nondigit portions --- */
124 pa
= vchr(&va
, val
); pb
= vchr(&vb
, vbl
);
126 if (pa
== va
) ia
= 1;
127 else if (isalpha((unsigned char)*pa
)) ia
= 2;
128 else if (*pa
== '~') ia
= 0;
131 if (pb
== vb
) ib
= 1;
132 else if (isalpha((unsigned char)*pb
)) ib
= 2;
133 else if (*pb
== '~') ib
= 0;
136 if (ia
!= ib
) return (CMP(ia
, ib
));
137 else if (pa
== va
&& pb
== vb
) break;
138 else if (*pa
!= *pb
) return (CMP(*pa
, *pb
));
142 /* --- Compare digit portions --- */
144 ia
= vint(&va
, val
); ib
= vint(&vb
, vbl
);
145 if (ia
!= ib
) return (CMP(ia
, ib
));
149 static void vsplit(const char *v
, struct vinfo
*vi
)
154 if ((p
= strchr(v
, ':')) == 0)
163 if ((p
= strrchr(v
, '-')) == 0)
175 int versioncmp(const char *va
, const char *vb
)
177 struct vinfo via
, vib
;
180 vsplit(va
, &via
); vsplit(vb
, &vib
);
181 if ((rc
= vcmp(via
.e
, via
.el
, vib
.e
, vib
.el
)) != 0 ||
182 (rc
= vcmp(via
.m
, via
.ml
, vib
.m
, vib
.ml
)) != 0 ||
183 (rc
= vcmp(via
.s
, via
.sl
, vib
.s
, vib
.sl
)) != 0)
188 /*----- That's all, folks -------------------------------------------------*/