4 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
5 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
6 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33 #include "versioncmp.h"
34 #include "alpm_list.h"
39 #ifndef HAVE_STRVERSCMP
40 /* GNU's strverscmp() function, taken from glibc 2.3.2 sources
43 /* Compare strings while treating digits characters numerically.
44 Copyright (C) 1997, 2002 Free Software Foundation, Inc.
45 This file is part of the GNU C Library.
46 Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
48 The GNU C Library is free software; you can redistribute it and/or
49 modify it under the terms of the GNU Lesser General Public
50 License as published by the Free Software Foundation; either
51 version 2.1 of the License, or (at your option) any later version.
53 The GNU C Library is distributed in the hope that it will be useful,
54 but WITHOUT ANY WARRANTY; without even the implied warranty of
55 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
56 Lesser General Public License for more details.
58 You should have received a copy of the GNU Lesser General Public
59 License along with the GNU C Library; if not, write to the Free
60 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
63 /* states: S_N: normal, S_I: comparing integral part, S_F: comparing
64 fractionnal parts, S_Z: idem but with leading Zeroes only */
70 /* result_type: CMP: return diff; LEN: compare using len_diff/diff */
74 /* Compare S1 and S2 as strings holding indices/version numbers,
75 returning less than, equal to or greater than zero if S1 is less than,
76 equal to or greater than S2 (for more info, see the texinfo doc).
79 static int strverscmp (s1
, s2
)
83 const unsigned char *p1
= (const unsigned char *) s1
;
84 const unsigned char *p2
= (const unsigned char *) s2
;
89 /* Symbol(s) 0 [1-9] others (padding)
90 Transition (10) 0 (01) d (00) x (11) - */
91 static const unsigned int next_state
[] =
94 /* S_N */ S_N
, S_I
, S_Z
, S_N
,
95 /* S_I */ S_N
, S_I
, S_I
, S_I
,
96 /* S_F */ S_N
, S_F
, S_F
, S_F
,
97 /* S_Z */ S_N
, S_F
, S_Z
, S_Z
100 static const int result_type
[] =
102 /* state x/x x/d x/0 x/- d/x d/d d/0 d/-
103 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
105 /* S_N */ CMP
, CMP
, CMP
, CMP
, CMP
, LEN
, CMP
, CMP
,
106 CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
,
107 /* S_I */ CMP
, -1, -1, CMP
, +1, LEN
, LEN
, CMP
,
108 +1, LEN
, LEN
, CMP
, CMP
, CMP
, CMP
, CMP
,
109 /* S_F */ CMP
, CMP
, CMP
, CMP
, CMP
, LEN
, CMP
, CMP
,
110 CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
,
111 /* S_Z */ CMP
, +1, +1, CMP
, -1, CMP
, CMP
, CMP
,
120 /* Hint: '0' is a digit too. */
121 state
= S_N
| ((c1
== '0') + (isdigit (c1
) != 0));
123 while ((diff
= c1
- c2
) == 0 && c1
!= '\0')
125 state
= next_state
[state
];
128 state
|= (c1
== '0') + (isdigit (c1
) != 0);
131 state
= result_type
[state
<< 2 | (((c2
== '0') + (isdigit (c2
) != 0)))];
139 while (isdigit (*p1
++))
140 if (!isdigit (*p2
++))
143 return isdigit (*p2
) ? -1 : diff
;
152 /* this function was taken from rpm 4.0.4 and rewritten */
153 int _alpm_versioncmp(const char *a
, const char *b
)
155 char str1
[64], str2
[64];
158 char *rel1
= NULL
, *rel2
= NULL
;
169 strncpy(str1
, a
, 64);
171 strncpy(str2
, b
, 64);
174 /* lose the release number */
175 for(one
= str1
; *one
&& *one
!= '-'; one
++);
180 for(two
= str2
; *two
&& *two
!= '-'; two
++);
189 while(*one
|| *two
) {
190 while(*one
&& !isalnum((int)*one
)) one
++;
191 while(*two
&& !isalnum((int)*two
)) two
++;
196 /* find the next segment for each string */
197 if(isdigit((int)*ptr1
)) {
199 while(*ptr1
&& isdigit((int)*ptr1
)) ptr1
++;
202 while(*ptr1
&& isalpha((int)*ptr1
)) ptr1
++;
204 if(isdigit((int)*ptr2
)) {
206 while(*ptr2
&& isdigit((int)*ptr2
)) ptr2
++;
209 while(*ptr2
&& isalpha((int)*ptr2
)) ptr2
++;
217 /* see if we ran out of segments on one string */
218 if(one
== ptr1
&& two
!= ptr2
) {
219 return(is2num
? -1 : 1);
221 if(one
!= ptr1
&& two
== ptr2
) {
222 return(is1num
? 1 : -1);
225 /* see if we have a type mismatch (ie, one is alpha and one is digits) */
226 if(is1num
&& !is2num
) return(1);
227 if(!is1num
&& is2num
) return(-1);
229 if(is1num
) while(*one
== '0') one
++;
230 if(is2num
) while(*two
== '0') two
++;
232 rc
= strverscmp(one
, two
);
241 if((!*one
) && (!*two
)) {
242 /* compare release numbers */
243 if(rel1
&& rel2
&& strlen(rel1
) && strlen(rel2
)) return(_alpm_versioncmp(rel1
, rel2
));
247 return(*one
? 1 : -1);
250 int SYMEXPORT
alpm_depcmp(pmpkg_t
*pkg
, pmdepend_t
*dep
)
256 if(strcmp(pkg
->name
, dep
->name
) == 0
257 || alpm_list_find_str(alpm_pkg_get_provides(pkg
), dep
->name
)) {
258 if(dep
->mod
== PM_DEP_MOD_ANY
) {
261 int cmp
= _alpm_versioncmp(alpm_pkg_get_version(pkg
), dep
->version
);
263 case PM_DEP_MOD_EQ
: equal
= (cmp
== 0); break;
264 case PM_DEP_MOD_GE
: equal
= (cmp
>= 0); break;
265 case PM_DEP_MOD_LE
: equal
= (cmp
<= 0); break;
266 default: equal
= 1; break;
272 case PM_DEP_MOD_EQ
: mod
= "=="; break;
273 case PM_DEP_MOD_GE
: mod
= ">="; break;
274 case PM_DEP_MOD_LE
: mod
= "<="; break;
278 if(strlen(dep
->version
) > 0) {
279 _alpm_log(PM_LOG_DEBUG
, _("depcmp: %s-%s %s %s-%s => %s"),
280 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
),
281 mod
, dep
->name
, dep
->version
,
282 (equal
? "match" : "no match"));
284 _alpm_log(PM_LOG_DEBUG
, _("depcmp: %s-%s %s %s => %s"),
285 alpm_pkg_get_name(pkg
), alpm_pkg_get_version(pkg
),
287 (equal
? "match" : "no match"));
295 /* vim: set ts=2 sw=2 noet: */