A few final changes for the 3.0.6 release
[pacman.git] / lib / libalpm / versioncmp.c
blob7e22ec9c5d76286e873b645ef60f7ed210d6b7e6
1 /*
2 * versioncmp.c
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>
7 *
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,
21 * USA.
24 #include "config.h"
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <libintl.h>
32 /* libalpm */
33 #include "versioncmp.h"
34 #include "alpm_list.h"
35 #include "alpm.h"
36 #include "log.h"
37 #include "util.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
61 02111-1307 USA. */
63 /* states: S_N: normal, S_I: comparing integral part, S_F: comparing
64 fractionnal parts, S_Z: idem but with leading Zeroes only */
65 #define S_N 0x0
66 #define S_I 0x4
67 #define S_F 0x8
68 #define S_Z 0xC
70 /* result_type: CMP: return diff; LEN: compare using len_diff/diff */
71 #define CMP 2
72 #define LEN 3
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)
80 const char *s1;
81 const char *s2;
83 const unsigned char *p1 = (const unsigned char *) s1;
84 const unsigned char *p2 = (const unsigned char *) s2;
85 unsigned char c1, c2;
86 int state;
87 int diff;
89 /* Symbol(s) 0 [1-9] others (padding)
90 Transition (10) 0 (01) d (00) x (11) - */
91 static const unsigned int next_state[] =
93 /* state x d 0 - */
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,
112 -1, CMP, CMP, CMP
115 if (p1 == p2)
116 return 0;
118 c1 = *p1++;
119 c2 = *p2++;
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];
126 c1 = *p1++;
127 c2 = *p2++;
128 state |= (c1 == '0') + (isdigit (c1) != 0);
131 state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
133 switch (state)
135 case CMP:
136 return diff;
138 case LEN:
139 while (isdigit (*p1++))
140 if (!isdigit (*p2++))
141 return 1;
143 return isdigit (*p2) ? -1 : diff;
145 default:
146 return state;
150 #endif
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];
156 char *ptr1, *ptr2;
157 char *one, *two;
158 char *rel1 = NULL, *rel2 = NULL;
159 char oldch1, oldch2;
160 int is1num, is2num;
161 int rc;
163 ALPM_LOG_FUNC;
165 if(!strcmp(a,b)) {
166 return(0);
169 strncpy(str1, a, 64);
170 str1[63] = 0;
171 strncpy(str2, b, 64);
172 str2[63] = 0;
174 /* lose the release number */
175 for(one = str1; *one && *one != '-'; one++);
176 if(one) {
177 *one = '\0';
178 rel1 = ++one;
180 for(two = str2; *two && *two != '-'; two++);
181 if(two) {
182 *two = '\0';
183 rel2 = ++two;
186 one = str1;
187 two = str2;
189 while(*one || *two) {
190 while(*one && !isalnum((int)*one)) one++;
191 while(*two && !isalnum((int)*two)) two++;
193 ptr1 = one;
194 ptr2 = two;
196 /* find the next segment for each string */
197 if(isdigit((int)*ptr1)) {
198 is1num = 1;
199 while(*ptr1 && isdigit((int)*ptr1)) ptr1++;
200 } else {
201 is1num = 0;
202 while(*ptr1 && isalpha((int)*ptr1)) ptr1++;
204 if(isdigit((int)*ptr2)) {
205 is2num = 1;
206 while(*ptr2 && isdigit((int)*ptr2)) ptr2++;
207 } else {
208 is2num = 0;
209 while(*ptr2 && isalpha((int)*ptr2)) ptr2++;
212 oldch1 = *ptr1;
213 *ptr1 = '\0';
214 oldch2 = *ptr2;
215 *ptr2 = '\0';
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);
233 if(rc) return(rc);
235 *ptr1 = oldch1;
236 *ptr2 = oldch2;
237 one = ptr1;
238 two = ptr2;
241 if((!*one) && (!*two)) {
242 /* compare release numbers */
243 if(rel1 && rel2 && strlen(rel1) && strlen(rel2)) return(_alpm_versioncmp(rel1, rel2));
244 return(0);
247 return(*one ? 1 : -1);
250 int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
252 int equal = 0;
254 ALPM_LOG_FUNC;
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) {
259 equal = 1;
260 } else {
261 int cmp = _alpm_versioncmp(alpm_pkg_get_version(pkg), dep->version);
262 switch(dep->mod) {
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;
270 char *mod = "~=";
271 switch(dep->mod) {
272 case PM_DEP_MOD_EQ: mod = "=="; break;
273 case PM_DEP_MOD_GE: mod = ">="; break;
274 case PM_DEP_MOD_LE: mod = "<="; break;
275 default: 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"));
283 } else {
284 _alpm_log(PM_LOG_DEBUG, _("depcmp: %s-%s %s %s => %s"),
285 alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg),
286 mod, dep->name,
287 (equal ? "match" : "no match"));
291 return equal;
295 /* vim: set ts=2 sw=2 noet: */