Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2807 - (show annotations) (download)
Wed Sep 3 11:53:06 2014 UTC (9 years, 7 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 /*
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 }