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