Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2807 - (hide annotations) (download)
Wed Sep 3 11:53:06 2014 UTC (9 years, 8 months ago) by niro
File MIME type: text/plain
File size: 9348 byte(s)
-moved some common package functions to package.c/package.h
1 niro 2807 /*
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     #include "package.h"
24    
25     /**
26     * Some functions in this file have been adopted from the rpm source, notably
27     * 'rpmvercmp' located at lib/rpmvercmp.c and 'parseEVR' located at
28     * lib/rpmds.c. It was most recently updated against rpm version 4.8.1. Small
29     * modifications have been made to make it more consistent with the libalpm
30     * coding style.
31     */
32    
33     /**
34     * Split EVR into epoch, version, and release components.
35     * @param evr [epoch:]version[-release] string
36     * @retval *ep pointer to epoch
37     * @retval *vp pointer to version
38     * @retval *rp pointer to release
39     */
40     static void parseEVR(char *evr, const char **ep, const char **vp,
41     const char **rp)
42     {
43     const char *epoch;
44     const char *version;
45     const char *release;
46     char *s, *se;
47    
48     s = evr;
49     /* s points to epoch terminator */
50     while (*s && isdigit(*s)) s++;
51     /* se points to version terminator */
52     se = strrchr(s, '-');
53    
54     if(*s == ':') {
55     epoch = evr;
56     *s++ = '\0';
57     version = s;
58     if(*epoch == '\0') {
59     epoch = "0";
60     }
61     } else {
62     /* different from RPM- always assume 0 epoch */
63     epoch = "0";
64     version = evr;
65     }
66     if(se) {
67     *se++ = '\0';
68     release = se;
69     } else {
70     release = NULL;
71     }
72    
73     if(ep) *ep = epoch;
74     if(vp) *vp = version;
75     if(rp) *rp = release;
76     }
77    
78     /**
79     * Compare alpha and numeric segments of two versions.
80     * return 1: a is newer than b
81     * 0: a and b are the same version
82     * -1: b is newer than a
83     */
84     static int rpmvercmp(const char *a, const char *b)
85     {
86     char oldch1, oldch2;
87     char *str1, *str2;
88     char *ptr1, *ptr2;
89     char *one, *two;
90     int rc;
91     int isnum;
92     int ret = 0;
93    
94     /* easy comparison to see if versions are identical */
95     if(strcmp(a, b) == 0) return 0;
96    
97     str1 = strdup(a);
98     str2 = strdup(b);
99    
100     one = ptr1 = str1;
101     two = ptr2 = str2;
102    
103     /* loop through each version segment of str1 and str2 and compare them */
104     while (*one && *two) {
105     while (*one && !isalnum((int)*one)) one++;
106     while (*two && !isalnum((int)*two)) two++;
107    
108     /* If we ran to the end of either, we are finished with the loop */
109     if (!(*one && *two)) break;
110    
111     /* If the separator lengths were different, we are also finished */
112     if ((one - ptr1) != (two - ptr2)) {
113     return (one - ptr1) < (two - ptr2) ? -1 : 1;
114     }
115    
116     ptr1 = one;
117     ptr2 = two;
118    
119     /* grab first completely alpha or completely numeric segment */
120     /* leave one and two pointing to the start of the alpha or numeric */
121     /* segment and walk ptr1 and ptr2 to end of segment */
122     if (isdigit((int)*ptr1)) {
123     while (*ptr1 && isdigit((int)*ptr1)) ptr1++;
124     while (*ptr2 && isdigit((int)*ptr2)) ptr2++;
125     isnum = 1;
126     } else {
127     while (*ptr1 && isalpha((int)*ptr1)) ptr1++;
128     while (*ptr2 && isalpha((int)*ptr2)) ptr2++;
129     isnum = 0;
130     }
131    
132     /* save character at the end of the alpha or numeric segment */
133     /* so that they can be restored after the comparison */
134     oldch1 = *ptr1;
135     *ptr1 = '\0';
136     oldch2 = *ptr2;
137     *ptr2 = '\0';
138    
139     /* this cannot happen, as we previously tested to make sure that */
140     /* the first string has a non-null segment */
141     if (one == ptr1) {
142     ret = -1; /* arbitrary */
143     goto cleanup;
144     }
145    
146     /* take care of the case where the two version segments are */
147     /* different types: one numeric, the other alpha (i.e. empty) */
148     /* numeric segments are always newer than alpha segments */
149     /* XXX See patch #60884 (and details) from bugzilla #50977. */
150     if (two == ptr2) {
151     ret = isnum ? 1 : -1;
152     goto cleanup;
153     }
154    
155     if (isnum) {
156     /* this used to be done by converting the digit segments */
157     /* to ints using atoi() - it's changed because long */
158     /* digit segments can overflow an int - this should fix that. */
159    
160     /* throw away any leading zeros - it's a number, right? */
161     while (*one == '0') one++;
162     while (*two == '0') two++;
163    
164     /* whichever number has more digits wins */
165     if (strlen(one) > strlen(two)) {
166     ret = 1;
167     goto cleanup;
168     }
169     if (strlen(two) > strlen(one)) {
170     ret = -1;
171     goto cleanup;
172     }
173     }
174    
175     /* strcmp will return which one is greater - even if the two */
176     /* segments are alpha or if they are numeric. don't return */
177     /* if they are equal because there might be more segments to */
178     /* compare */
179     rc = strcmp(one, two);
180     if (rc) {
181     ret = rc < 1 ? -1 : 1;
182     goto cleanup;
183     }
184    
185     /* restore character that was replaced by null above */
186     *ptr1 = oldch1;
187     one = ptr1;
188     *ptr2 = oldch2;
189     two = ptr2;
190     }
191    
192     /* this catches the case where all numeric and alpha segments have */
193     /* compared identically but the segment separating characters were */
194     /* different */
195     if ((!*one) && (!*two)) {
196     ret = 0;
197     goto cleanup;
198     }
199    
200     /* the final showdown. we never want a remaining alpha string to
201     * beat an empty string. the logic is a bit weird, but:
202     * - if one is empty and two is not an alpha, two is newer.
203     * - if one is an alpha, two is newer.
204     * - otherwise one is newer.
205     * */
206     if ( (!*one && !isalpha((int)*two))
207     || isalpha((int)*one) ) {
208     ret = -1;
209     } else {
210     ret = 1;
211     }
212    
213     cleanup:
214     free(str1);
215     free(str2);
216     return ret;
217     }
218    
219     /** Compare two version strings and determine which one is 'newer'.
220     * Returns a value comparable to the way strcmp works. Returns 1
221     * if a is newer than b, 0 if a and b are the same version, or -1
222     * if b is newer than a.
223     *
224     * Different epoch values for version strings will override any further
225     * comparison. If no epoch is provided, 0 is assumed.
226     *
227     * Keep in mind that the pkgrel is only compared if it is available
228     * on both versions handed to this function. For example, comparing
229     * 1.5-1 and 1.5 will yield 0; comparing 1.5-1 and 1.5-2 will yield
230     * -1 as expected. This is mainly for supporting versioned dependencies
231     * that do not include the pkgrel.
232     */
233     int alpm_pkg_vercmp(const char *a, const char *b)
234     {
235     char *full1, *full2;
236     const char *epoch1, *ver1, *rel1;
237     const char *epoch2, *ver2, *rel2;
238     int ret;
239    
240     /* ensure our strings are not null */
241     if(!a && !b) {
242     return 0;
243     } else if(!a) {
244     return -1;
245     } else if(!b) {
246     return 1;
247     }
248     /* another quick shortcut- if full version specs are equal */
249     if(strcmp(a, b) == 0) {
250     return 0;
251     }
252    
253     /* Parse both versions into [epoch:]version[-release] triplets. We probably
254     * don't need epoch and release to support all the same magic, but it is
255     * easier to just run it all through the same code. */
256     full1 = strdup(a);
257     full2 = strdup(b);
258    
259     /* parseEVR modifies passed in version, so have to dupe it first */
260     parseEVR(full1, &epoch1, &ver1, &rel1);
261     parseEVR(full2, &epoch2, &ver2, &rel2);
262    
263     ret = rpmvercmp(epoch1, epoch2);
264     if(ret == 0) {
265     ret = rpmvercmp(ver1, ver2);
266     if(ret == 0 && rel1 && rel2) {
267     ret = rpmvercmp(rel1, rel2);
268     }
269     }
270    
271     free(full1);
272     free(full2);
273     return ret;
274     }
275    
276     char *strip_chars(char *string, char *chars)
277     {
278     char * newstr = malloc(strlen(string) + 1);
279     int counter = 0;
280    
281     for ( ; *string; string++) {
282     if (!strchr(chars, *string)) {
283     newstr[ counter ] = *string;
284     ++ counter;
285     }
286     }
287    
288     newstr[counter] = 0;
289     return newstr;
290     }
291    
292     int check_stable_package(char *magefile)
293     {
294     FILE *fp;
295     char *line = NULL;
296     char *ptr = NULL;
297     char *tmp = NULL;
298     char *state = NULL;
299     char *distribution = NULL;
300     size_t len = 0;
301     ssize_t read;
302     int ret = -1;
303    
304     // get distribution
305     distribution = getenv("MAGE_DISTRIBUTION");
306     if (strlen(distribution) > 0 ) {
307     //printf("distribution: %s\n", distribution);
308     }
309     else {
310     printf("Environment variable MAGE_DISTRIBUTION not set.\n");
311     return (ret);
312     }
313    
314     fp = fopen(magefile, "r");
315     if (fp == NULL)
316     return(ret);
317    
318     while ((read = getline(&line, &len, fp)) != -1) {
319     if (strstr(line,"STATE=")) {
320     ptr = strtok(line, "=");
321     while (ptr != NULL) {
322     // remove \n
323     tmp = strip_chars(ptr, "\n");
324     // remove \" too
325     state = strip_chars(tmp, "\"");
326     ptr = strtok(NULL, "=");
327     }
328     }
329     }
330     fclose(fp);
331     if (strlen(state) > 0 ) {
332     if (strcmp(distribution,"unstable") == 0) {
333     if(strcmp(state,"unstable") == 0) {
334     ret = 0;
335     }
336     if(strcmp(state,"testing") == 0) {
337     ret = 0;
338     }
339     if(strcmp(state,"stable") == 0) {
340     ret = 0;
341     }
342     }
343    
344     if (strcmp(distribution,"testing") == 0) {
345     if(strcmp(state,"unstable") == 0) {
346     ret = 1;
347     }
348     if(strcmp(state,"testing") == 0) {
349     ret = 0;
350     }
351     if(strcmp(state,"stable") == 0) {
352     ret = 0;
353     }
354     }
355    
356     if (strcmp(distribution, "stable") == 0) {
357     if(strcmp(state,"unstable") == 0) {
358     ret = 1;
359     }
360     if(strcmp(state,"testing") == 0) {
361     ret = 1;
362     }
363     if(strcmp(state,"stable") == 0) {
364     ret = 0;
365     }
366     }
367     }
368     else {
369     ret = -1;
370     }
371    
372     free(line);
373     free(ptr);
374     free(tmp);
375     free(state);
376     //free(distribution); //no free() required
377    
378     return(ret);
379     }