rpm  5.2.1
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 
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
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@*/
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')
158 
160  xx = mireSetCOptions(evr_tuple_mire, RPMMIRE_REGEX, 0, 0, NULL);
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 
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;
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 
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 }