rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmevr.c
Go to the documentation of this file.
1
4 #include "system.h"
5
6 #include <rpmiotypes.h>
7 #include <rpmmacro.h>
8 #define _MIRE_INTERNAL
9 #include <mire.h>
10
11 #include <rpmtag.h>
12 #define _RPMEVR_INTERNAL
13 #include <rpmevr.h>
14
15 #include "debug.h"
16
17 /*@unchecked@*/
18 int _rpmevr_debug = 0;
19
20 #if !defined(MAX)
21 #define MAX(x, y) ( ((x)>(y))?(x):(y) )
22 #endif
23
24 EVR_t rpmEVRnew(rpmuint32_t Flags, int initialize)
25 {
26 EVR_t evr = xcalloc(1, sizeof(*evr));
27 evr->Flags = Flags;
28 if (initialize) {
29 /*@-observertrans -readonlytrans @*/
30 evr->F[RPMEVR_E] = "0";
31 evr->F[RPMEVR_V] = "";
32 evr->F[RPMEVR_R] = "";
33 evr->F[RPMEVR_D] = "";
34 /*@=observertrans =readonlytrans @*/
35 }
36 return evr;
37 }
38
39 EVR_t rpmEVRfree(EVR_t evr)
40 {
41 if (evr != NULL) {
42 evr->str = _free(evr->str);
43 memset(evr, 0, sizeof(*evr));
44 evr = _free(evr);
45 }
46 return NULL;
47 }
48
49 /* XXX Force digits to beat alphas. See bugzilla #50977. */
50 /*@unchecked@*/
51 #if defined(RPM_VENDOR_MANDRIVA) /* old-comparision-behaviour */
52 static int _invert_digits_alphas_comparison = -1;
53 #else
54 static int _invert_digits_alphas_comparison = 1;
55 #endif
56
57 /* XXX Punctuation characters that are not treated as alphas */
58 /*@unchecked@*/ /*@observer@*/
59 static const char * _rpmnotalpha = ".:-";
60
66 static inline int xisrpmalpha(int c)
67 /*@*/
68 {
69 int rc = xisalpha(c);
70 if (!rc)
71 rc = xispunct(c);
72 if (rc && _rpmnotalpha && *_rpmnotalpha)
73 rc = (strchr(_rpmnotalpha, c) == NULL);
74 /*@-globstate@*/
75 return rc;
76 /*@=globstate@*/
77 }
78
79 int rpmEVRcmp(const char * a, const char * b)
80 /*@*/
81 {
82 const char * ae = NULL, * be = NULL;
83 int rc = 0; /* assume equal */
84
85 assert(a != NULL);
86 assert(b != NULL);
87 /* Compare version strings segment by segment. */
88 for (; *a && *b && rc == 0; a = ae, b = be) {
89
90 /* Skip leading non-alpha, non-digit characters. */
91 while (*a && !(xisdigit((int)*a) || xisrpmalpha((int)*a))) a++;
92 while (*b && !(xisdigit((int)*b) || xisrpmalpha((int)*b))) b++;
93
94 /* Wildcard comparison? */
95 /* Note: limited to suffix-only wildcard matching at the moment. */
96 if (a[0] == '*' && a[1] == '\0') {
97 be = strchr(b, '\0'); /* XXX be = b + strlen(b); */
98 } else
99 if (b[0] == '*' && b[1] == '\0') {
100 ae = strchr(a, '\0'); /* XXX ae = a + strlen(a); */
101 } else
102 /* Digit string comparison? */
103 if (xisdigit((int)*a) || xisdigit((int)*b)) {
104 /* Discard leading zeroes. */
105 while (a[0] == '0' && xisdigit((int)a[1])) a++;
106 while (b[0] == '0' && xisdigit((int)b[1])) b++;
107
108 /* Find end of digit strings. */
109 ae = a; while (xisdigit((int)*ae)) ae++;
110 be = b; while (xisdigit((int)*be)) be++;
111
112 /* Calculate digit comparison return code. */
113 if (a == ae || b == be)
114 rc = (int)(*a - *b) * _invert_digits_alphas_comparison;
115 else {
116 rc = (ae - a) - (be - b);
117 if (!rc)
118 rc = strncmp(a, b, (ae - a));
119 }
120 } else {
121 /* Find end of alpha strings. */
122 ae = a; while (xisrpmalpha((int)*ae)) ae++;
123 be = b; while (xisrpmalpha((int)*be)) be++;
124
125 /* Calculate alpha comparison return code. */
126 rc = strncmp(a, b, MAX((ae - a), (be - b)));
127 }
128 }
129
130 /* Longer string wins. */
131 if (!rc)
132 rc = (int)(*a - *b);
133
134 /* Force strict -1, 0, 1 return. */
135 rc = (rc > 0 ? 1
136 : rc < 0 ? -1
137 : 0);
138 return rc;
139 }
140
141 /*@unchecked@*/ /*@observer@*/ /*@null@*/
142 static const char * _evr_tuple_match =
143 "^(?:([^:-]+):)?([^:-]+)(?:-([^:-]+))?(?::([^:-]+))?$";
144 /*@unchecked@*/ /*@only@*/ /*@observer@*/ /*@null@*/
145 const char * evr_tuple_match = NULL;
146 /*@unchecked@*/ /*@refcounted@*/ /*@null@*/
147 miRE evr_tuple_mire = NULL;
148
149 static miRE rpmEVRmire(void)
150 /*@*/
151 {
152 /*@-globs -internalglobs -mods @*/
153 if (evr_tuple_mire == NULL) {
154 int xx;
155 evr_tuple_match = rpmExpand("%{?evr_tuple_match}", NULL);
156 if (evr_tuple_match == NULL || evr_tuple_match[0] == '\0')
157 evr_tuple_match = xstrdup(_evr_tuple_match);
158
159 evr_tuple_mire = mireNew(RPMMIRE_REGEX, 0);
160 xx = mireSetCOptions(evr_tuple_mire, RPMMIRE_REGEX, 0, 0, NULL);
161 xx = mireRegcomp(evr_tuple_mire, evr_tuple_match);
162
163 }
164 /*@=globs =internalglobs =mods @*/
165 assert(evr_tuple_match != NULL && evr_tuple_mire != NULL);
166 /*@-globstate -retalias@*/
167 return evr_tuple_mire;
168 /*@=globstate =retalias@*/
169 }
170
171 int rpmEVRparse(const char * evrstr, EVR_t evr)
172 /*@modifies evrstr, evr @*/
173 {
174 miRE mire = rpmEVRmire();
175 int noffsets = 6 * 3;
176 int offsets[6 * 3];
177 size_t nb;
178 int xx;
179 int i;
180
181 memset(evr, 0, sizeof(*evr));
182 evr->str = xstrdup(evrstr);
183 nb = strlen(evr->str);
184
185 memset(offsets, -1, sizeof(offsets));
186 xx = mireSetEOptions(mire, offsets, noffsets);
187
188 xx = mireRegexec(mire, evr->str, strlen(evr->str));
189
190 for (i = 0; i < noffsets; i += 2) {
191 int ix;
192
193 if (offsets[i] < 0)
194 continue;
195
196 switch (i/2) {
197 default:
198 case 0: continue; /*@notreached@*/ /*@switchbreak@*/ break;
199 case 1: ix = RPMEVR_E; /*@switchbreak@*/break;
200 case 2: ix = RPMEVR_V; /*@switchbreak@*/break;
201 case 3: ix = RPMEVR_R; /*@switchbreak@*/break;
202 case 4: ix = RPMEVR_D; /*@switchbreak@*/break;
203 }
204
205 assert(offsets[i ] >= 0 && offsets[i ] <= (int)nb);
206 assert(offsets[i+1] >= 0 && offsets[i+1] <= (int)nb);
207 { char * te = (char *) evr->str;
208 evr->F[ix] = te + offsets[i];
209 te += offsets[i+1];
210 *te = '\0';
211 }
212
213 }
214
215 /* XXX HACK: postpone committing to single "missing" value for now. */
216 if (evr->F[RPMEVR_E] == NULL) evr->F[RPMEVR_E] = "0";
217 if (evr->F[RPMEVR_V] == NULL) evr->F[RPMEVR_V] = "";
218 if (evr->F[RPMEVR_R] == NULL) evr->F[RPMEVR_R] = "";
219 if (evr->F[RPMEVR_D] == NULL) evr->F[RPMEVR_D] = "";
220
221 evr->Elong = strtoul(evr->F[RPMEVR_E], NULL, 10);
222
223 xx = mireSetEOptions(mire, NULL, 0);
224
225 return 0;
226 }
227
234 static int compare_values(const char *a, const char *b)
235 /*@*/
236 {
237 return rpmvercmp(a, b);
238 }
239
240 /*@unchecked@*/ /*@only@*/ /*@observer@*/ /*@null@*/
241 static const char * evr_tuple_order = NULL;
242
247 /*@observer@*/
248 static const char * rpmEVRorder(void)
249 /*@*/
250 {
251 /*@-globs -internalglobs -mods @*/
252 if (evr_tuple_order == NULL) {
253 evr_tuple_order = rpmExpand("%{?evr_tuple_order}", NULL);
254 if (evr_tuple_order == NULL || evr_tuple_order[0] == '\0')
255 evr_tuple_order = xstrdup("EVR");
256 }
257 /*@=globs =internalglobs =mods @*/
258 assert(evr_tuple_order != NULL && evr_tuple_order[0] != '\0');
259 return evr_tuple_order;
260 }
261
262 int rpmEVRcompare(const EVR_t a, const EVR_t b)
263 {
264 const char * s;
265 int rc = 0;
266
267 assert(a->F[RPMEVR_E] != NULL);
268 assert(a->F[RPMEVR_V] != NULL);
269 assert(a->F[RPMEVR_R] != NULL);
270 assert(a->F[RPMEVR_D] != NULL);
271 assert(b->F[RPMEVR_E] != NULL);
272 assert(b->F[RPMEVR_V] != NULL);
273 assert(b->F[RPMEVR_R] != NULL);
274 assert(b->F[RPMEVR_D] != NULL);
275
276 for (s = rpmEVRorder(); *s != '\0'; s++) {
277 int ix;
278 switch ((int)*s) {
279 default: continue; /*@notreached@*/ /*@switchbreak@*/break;
280 case 'E': ix = RPMEVR_E; /*@switchbreak@*/break;
281 case 'V': ix = RPMEVR_V; /*@switchbreak@*/break;
282 case 'R': ix = RPMEVR_R; /*@switchbreak@*/break;
283 case 'D': ix = RPMEVR_D; /*@switchbreak@*/break;
284 }
285 rc = compare_values(a->F[ix], b->F[ix]);
286 if (rc)
287 break;
288 }
289 return rc;
290 }
291
292 int rpmEVRoverlap(EVR_t a, EVR_t b)
293 {
294 rpmsenseFlags aF = a->Flags;
295 rpmsenseFlags bF = b->Flags;
296 int sense;
297 int result;
298
299 /* XXX HACK: postpone committing to single "missing" value for now. */
300 /*@-mods -observertrans -readonlytrans @*/
301 if (a->F[RPMEVR_E] == NULL) a->F[RPMEVR_E] = "0";
302 if (b->F[RPMEVR_E] == NULL) b->F[RPMEVR_E] = "0";
303 if (a->F[RPMEVR_V] == NULL) a->F[RPMEVR_V] = "";
304 if (b->F[RPMEVR_V] == NULL) b->F[RPMEVR_V] = "";
305 if (a->F[RPMEVR_R] == NULL) a->F[RPMEVR_R] = "";
306 if (b->F[RPMEVR_R] == NULL) b->F[RPMEVR_R] = "";
307 if (a->F[RPMEVR_D] == NULL) a->F[RPMEVR_D] = "";
308 if (b->F[RPMEVR_D] == NULL) b->F[RPMEVR_D] = "";
309 /*@=mods =observertrans =readonlytrans @*/
310 sense = rpmEVRcompare(a, b);
311
312 /* Detect overlap of {A,B} range. */
313 if (aF == RPMSENSE_NOTEQUAL || bF == RPMSENSE_NOTEQUAL)
314 result = (sense != 0);
315 else if (sense < 0 && ((aF & RPMSENSE_GREATER) || (bF & RPMSENSE_LESS)))
316 result = 1;
317 else if (sense > 0 && ((aF & RPMSENSE_LESS) || (bF & RPMSENSE_GREATER)))
318 result = 1;
319 else if (sense == 0 &&
320 (((aF & RPMSENSE_EQUAL) && (bF & RPMSENSE_EQUAL)) ||
321 ((aF & RPMSENSE_LESS) && (bF & RPMSENSE_LESS)) ||
322 ((aF & RPMSENSE_GREATER) && (bF & RPMSENSE_GREATER))))
323 result = 1;
324 else
325 result = 0;
326 return result;
327 }
328
329 /*@-redecl@*/
330 int (*rpmvercmp) (const char *a, const char *b) = rpmEVRcmp;
331 /*@=redecl@*/
332
335 /*@unchecked@*/ /*@observer@*/
336 static struct EVRop_s {
337 /*@observer@*/ /*@null@*/
338 const char * operator;
339 rpmsenseFlags sense;
340 } cops[] = {
341 { "<=", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
342 { "=<", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
343
344 { "==", RPMSENSE_EQUAL},
345 { "!=", RPMSENSE_NOTEQUAL},
346
347 { ">=", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
348 { "=>", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
349
350 { "<", RPMSENSE_LESS},
351 { "=", RPMSENSE_EQUAL},
352 { ">", RPMSENSE_GREATER},
353
354 { NULL, 0 },
355 };
356
357 rpmsenseFlags rpmEVRflags(const char *op, const char **end)
358 {
359 rpmsenseFlags Flags = 0;
360 struct EVRop_s *cop;
361
362 if (op == NULL || *op == '\0')
363 Flags = RPMSENSE_EQUAL;
364 else
365 for (cop = cops; cop->operator != NULL; cop++) {
366 if (strncmp(op, cop->operator, strlen(cop->operator)))
367 continue;
368 Flags = cop->sense;
369 if (end)
370 *end = op + strlen(cop->operator);
371 break;
372 }
373 return Flags;
374 }
375
376 int rpmVersionCompare(Header A, Header B)
377 {
378 HE_t Ahe = memset(alloca(sizeof(*Ahe)), 0, sizeof(*Ahe));
379 HE_t Bhe = memset(alloca(sizeof(*Bhe)), 0, sizeof(*Bhe));
380 const char * one, * two;
381 rpmuint32_t Eone, Etwo;
382 const char * s;
383 int rc = 0;
384 int xx;
385
386 for (s = rpmEVRorder(); *s != '\0'; s++) {
387 switch ((int)*s) {
388 default: continue; /*@notreached@*/ /*@switchbreak@*/break;
389 case 'E':
390 Ahe->tag = RPMTAG_EPOCH;
391 xx = headerGet(A, Ahe, 0);
392 Eone = (xx && Ahe->p.ui32p ? Ahe->p.ui32p[0] : 0);
393 Bhe->tag = RPMTAG_EPOCH;
394 xx = headerGet(B, Bhe, 0);
395 Etwo = (xx && Bhe->p.ui32p ? Bhe->p.ui32p[0] : 0);
396 if (Eone < Etwo)
397 rc = -1;
398 else if (Eone > Etwo)
399 rc = 1;
400 /*@switchbreak@*/ break;
401 case 'V':
402 Ahe->tag = RPMTAG_VERSION;
403 xx = headerGet(A, Ahe, 0);
404 one = (xx && Ahe->p.str ? Ahe->p.str : "");
405 Bhe->tag = RPMTAG_VERSION;
406 xx = headerGet(B, Bhe, 0);
407 two = (xx && Bhe->p.str ? Bhe->p.str : "");
408 rc = rpmvercmp(one, two);
409 /*@switchbreak@*/ break;
410 case 'R':
411 Ahe->tag = RPMTAG_RELEASE;
412 xx = headerGet(A, Ahe, 0);
413 one = (xx && Ahe->p.str ? Ahe->p.str : "");
414 Bhe->tag = RPMTAG_RELEASE;
415 xx = headerGet(B, Bhe, 0);
416 two = (xx && Bhe->p.str ? Bhe->p.str : "");
417 rc = rpmvercmp(one, two);
418 /*@switchbreak@*/ break;
419 case 'D':
420 Ahe->tag = RPMTAG_DISTEPOCH;
421 xx = headerGet(A, Ahe, 0);
422 one = (xx && Ahe->p.str ? Ahe->p.str : "");
423 Bhe->tag = RPMTAG_DISTEPOCH;
424 xx = headerGet(B, Bhe, 0);
425 two = (xx && Bhe->p.str ? Bhe->p.str : "");
426 rc = rpmvercmp(one, two);
427 /*@switchbreak@*/ break;
428 }
429 Ahe->p.ptr = _free(Ahe->p.ptr);
430 Bhe->p.ptr = _free(Bhe->p.ptr);
431 if (rc)
432 break;
433 }
434 return rc;
435 }