Magellan Linux

Annotation of /branches/mage-next/src/highestver.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2630 - (hide annotations) (download)
Wed Mar 5 09:08:30 2014 UTC (10 years, 2 months ago) by niro
File MIME type: text/plain
File size: 8412 byte(s)
-free the memory of var saved
1 niro 2585 /*
2     * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
3     *
4     * This program is free software; you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation; either version 2 of the License, or
7     * (at your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with this program. If not, see <http://www.gnu.org/licenses/>.
16     */
17    
18     #include <stdlib.h>
19     #include <stdio.h> /* printf */
20     #include <string.h>
21     #include <ctype.h>
22    
23     /**
24     * Some functions in this file have been adopted from the rpm source, notably
25     * 'rpmvercmp' located at lib/rpmvercmp.c and 'parseEVR' located at
26     * lib/rpmds.c. It was most recently updated against rpm version 4.8.1. Small
27     * modifications have been made to make it more consistent with the libalpm
28     * coding style.
29     */
30    
31     /**
32     * Split EVR into epoch, version, and release components.
33     * @param evr [epoch:]version[-release] string
34     * @retval *ep pointer to epoch
35     * @retval *vp pointer to version
36     * @retval *rp pointer to release
37     */
38     static void parseEVR(char *evr, const char **ep, const char **vp,
39     const char **rp)
40     {
41     const char *epoch;
42     const char *version;
43     const char *release;
44     char *s, *se;
45    
46     s = evr;
47     /* s points to epoch terminator */
48     while (*s && isdigit(*s)) s++;
49     /* se points to version terminator */
50     se = strrchr(s, '-');
51    
52     if(*s == ':') {
53     epoch = evr;
54     *s++ = '\0';
55     version = s;
56     if(*epoch == '\0') {
57     epoch = "0";
58     }
59     } else {
60     /* different from RPM- always assume 0 epoch */
61     epoch = "0";
62     version = evr;
63     }
64     if(se) {
65     *se++ = '\0';
66     release = se;
67     } else {
68     release = NULL;
69     }
70    
71     if(ep) *ep = epoch;
72     if(vp) *vp = version;
73     if(rp) *rp = release;
74     }
75    
76     /**
77     * Compare alpha and numeric segments of two versions.
78     * return 1: a is newer than b
79     * 0: a and b are the same version
80     * -1: b is newer than a
81     */
82     static int rpmvercmp(const char *a, const char *b)
83     {
84     char oldch1, oldch2;
85     char *str1, *str2;
86     char *ptr1, *ptr2;
87     char *one, *two;
88     int rc;
89     int isnum;
90     int ret = 0;
91    
92     /* easy comparison to see if versions are identical */
93     if(strcmp(a, b) == 0) return 0;
94    
95     str1 = strdup(a);
96     str2 = strdup(b);
97    
98     one = ptr1 = str1;
99     two = ptr2 = str2;
100    
101     /* loop through each version segment of str1 and str2 and compare them */
102     while (*one && *two) {
103     while (*one && !isalnum((int)*one)) one++;
104     while (*two && !isalnum((int)*two)) two++;
105    
106     /* If we ran to the end of either, we are finished with the loop */
107     if (!(*one && *two)) break;
108    
109     /* If the separator lengths were different, we are also finished */
110     if ((one - ptr1) != (two - ptr2)) {
111     return (one - ptr1) < (two - ptr2) ? -1 : 1;
112     }
113    
114     ptr1 = one;
115     ptr2 = two;
116    
117     /* grab first completely alpha or completely numeric segment */
118     /* leave one and two pointing to the start of the alpha or numeric */
119     /* segment and walk ptr1 and ptr2 to end of segment */
120     if (isdigit((int)*ptr1)) {
121     while (*ptr1 && isdigit((int)*ptr1)) ptr1++;
122     while (*ptr2 && isdigit((int)*ptr2)) ptr2++;
123     isnum = 1;
124     } else {
125     while (*ptr1 && isalpha((int)*ptr1)) ptr1++;
126     while (*ptr2 && isalpha((int)*ptr2)) ptr2++;
127     isnum = 0;
128     }
129    
130     /* save character at the end of the alpha or numeric segment */
131     /* so that they can be restored after the comparison */
132     oldch1 = *ptr1;
133     *ptr1 = '\0';
134     oldch2 = *ptr2;
135     *ptr2 = '\0';
136    
137     /* this cannot happen, as we previously tested to make sure that */
138     /* the first string has a non-null segment */
139     if (one == ptr1) {
140     ret = -1; /* arbitrary */
141     goto cleanup;
142     }
143    
144     /* take care of the case where the two version segments are */
145     /* different types: one numeric, the other alpha (i.e. empty) */
146     /* numeric segments are always newer than alpha segments */
147     /* XXX See patch #60884 (and details) from bugzilla #50977. */
148     if (two == ptr2) {
149     ret = isnum ? 1 : -1;
150     goto cleanup;
151     }
152    
153     if (isnum) {
154     /* this used to be done by converting the digit segments */
155     /* to ints using atoi() - it's changed because long */
156     /* digit segments can overflow an int - this should fix that. */
157    
158     /* throw away any leading zeros - it's a number, right? */
159     while (*one == '0') one++;
160     while (*two == '0') two++;
161    
162     /* whichever number has more digits wins */
163     if (strlen(one) > strlen(two)) {
164     ret = 1;
165     goto cleanup;
166     }
167     if (strlen(two) > strlen(one)) {
168     ret = -1;
169     goto cleanup;
170     }
171     }
172    
173     /* strcmp will return which one is greater - even if the two */
174     /* segments are alpha or if they are numeric. don't return */
175     /* if they are equal because there might be more segments to */
176     /* compare */
177     rc = strcmp(one, two);
178     if (rc) {
179     ret = rc < 1 ? -1 : 1;
180     goto cleanup;
181     }
182    
183     /* restore character that was replaced by null above */
184     *ptr1 = oldch1;
185     one = ptr1;
186     *ptr2 = oldch2;
187     two = ptr2;
188     }
189    
190     /* this catches the case where all numeric and alpha segments have */
191     /* compared identically but the segment separating characters were */
192     /* different */
193     if ((!*one) && (!*two)) {
194     ret = 0;
195     goto cleanup;
196     }
197    
198     /* the final showdown. we never want a remaining alpha string to
199     * beat an empty string. the logic is a bit weird, but:
200     * - if one is empty and two is not an alpha, two is newer.
201     * - if one is an alpha, two is newer.
202     * - otherwise one is newer.
203     * */
204     if ( (!*one && !isalpha((int)*two))
205     || isalpha((int)*one) ) {
206     ret = -1;
207     } else {
208     ret = 1;
209     }
210    
211     cleanup:
212     free(str1);
213     free(str2);
214     return ret;
215     }
216    
217     /** Compare two version strings and determine which one is 'newer'.
218     * Returns a value comparable to the way strcmp works. Returns 1
219     * if a is newer than b, 0 if a and b are the same version, or -1
220     * if b is newer than a.
221     *
222     * Different epoch values for version strings will override any further
223     * comparison. If no epoch is provided, 0 is assumed.
224     *
225     * Keep in mind that the pkgrel is only compared if it is available
226     * on both versions handed to this function. For example, comparing
227     * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield
228     * -1 as expected. This is mainly for supporting versioned dependencies
229     * that do not include the pkgrel.
230     */
231     int alpm_pkg_vercmp(const char *a, const char *b)
232     {
233     char *full1, *full2;
234     const char *epoch1, *ver1, *rel1;
235     const char *epoch2, *ver2, *rel2;
236     int ret;
237    
238     /* ensure our strings are not null */
239     if(!a && !b) {
240     return 0;
241     } else if(!a) {
242     return -1;
243     } else if(!b) {
244     return 1;
245     }
246     /* another quick shortcut- if full version specs are equal */
247     if(strcmp(a, b) == 0) {
248     return 0;
249     }
250    
251     /* Parse both versions into [epoch:]version[-release] triplets. We probably
252     * don't need epoch and release to support all the same magic, but it is
253     * easier to just run it all through the same code. */
254     full1 = strdup(a);
255     full2 = strdup(b);
256    
257     /* parseEVR modifies passed in version, so have to dupe it first */
258     parseEVR(full1, &epoch1, &ver1, &rel1);
259     parseEVR(full2, &epoch2, &ver2, &rel2);
260    
261     ret = rpmvercmp(epoch1, epoch2);
262     if(ret == 0) {
263     ret = rpmvercmp(ver1, ver2);
264     if(ret == 0 && rel1 && rel2) {
265     ret = rpmvercmp(rel1, rel2);
266     }
267     }
268    
269     free(full1);
270     free(full2);
271     return ret;
272     }
273    
274     #define BASENAME "highestver"
275    
276     static void usage(void)
277     {
278     fprintf(stderr, "usage: %s <ver1> <ver2> ... <verN>\n", BASENAME);
279     fprintf(stderr, "prints the highest version.\n");
280     }
281    
282     int main(int argc, char *argv[])
283     {
284     int i;
285     int ret;
286     char *saved;
287    
288     if(argc == 1) {
289     usage();
290     return 2;
291     }
292    
293     // only one argument given, that is the highest one
294     if(argc == 2) {
295 niro 2629 saved = strdup(argv[1]);
296 niro 2585 }
297    
298     // fasten things up
299     if(argc == 3) {
300     ret = alpm_pkg_vercmp(argv[1], argv[2]);
301     if(ret < 0) {
302 niro 2629 saved = strdup(argv[2]);
303 niro 2585 }
304     if(ret == 0) {
305 niro 2629 saved = strdup(argv[1]);
306 niro 2585 }
307     if(ret > 0) {
308 niro 2629 saved = strdup(argv[1]);
309 niro 2585 }
310     }
311    
312     if(argc > 3) {
313     for(i=1; i < argc; i++) {
314     if (i == 1) {
315 niro 2629 saved = strdup(argv[i]);
316 niro 2585 }
317     ret = alpm_pkg_vercmp(saved, argv[i+1]);
318     // retval >0 or 0 means saved i the higher on, no need to strcmp
319     if(ret < 0) {
320 niro 2629 saved = strdup(argv[i+1]);
321 niro 2585 }
322     }
323     }
324    
325     if(strlen(saved) > 0) {
326     printf("%s\n", saved);
327     }
328    
329 niro 2630 free(saved);
330 niro 2585 return EXIT_SUCCESS;
331     }