rpm  4.5
rpmevr.c
Go to the documentation of this file.
1 
4 #include "system.h"
5 
6 #include <rpmio.h>
7 
8 #define _RPMEVR_INTERNAL
9 #include <rpmevr.h>
10 
11 #include "debug.h"
12 
13 /*@unchecked@*/
14 int _rpmevr_debug = 0;
15 
16 #if !defined(MAX)
17 #define MAX(x, y) ( ((x)>(y))?(x):(y) )
18 #endif
19 
20 /* XXX Force digits to beat alphas. See bugzilla #50977. */
21 #if defined(RPM_VENDOR_MANDRIVA)
22 /*@unchecked@*/
24 #else
25 /*@unchecked@*/
27 #endif
28 
29 /* XXX Punctuation characters that are not treated as alphas */
30 /*@unchecked@*/ /*@observer@*/
31 static const char * _rpmnotalpha = ".:-";
32 
38 static inline int xisrpmalpha(int c)
39  /*@*/
40 {
41  int rc = xisalpha(c);
42  if (!rc)
43  rc = xispunct(c);
44  if (rc && _rpmnotalpha && *_rpmnotalpha)
45  rc = (strchr(_rpmnotalpha, c) == NULL);
46  return rc;
47 }
48 
49 int rpmEVRcmp(const char * a, const char * b)
50  /*@*/
51 {
52  const char * ae, * be;
53  int rc = 0;
54 
55  /* Compare version strings segment by segment. */
56  for (; *a && *b && rc == 0; a = ae, b = be) {
57 
58  /* Skip leading non-alpha, non-digit characters. */
59  while (*a && !(xisdigit(*a) || xisrpmalpha(*a))) a++;
60  while (*b && !(xisdigit(*b) || xisrpmalpha(*b))) b++;
61 
62  /* Digit string comparison? */
63  if (xisdigit(*a) || xisdigit(*b)) {
64  /* Discard leading zeroes. */
65  while (a[0] == '0' && xisdigit(a[1])) a++;
66  while (b[0] == '0' && xisdigit(b[1])) b++;
67 
68  /* Find end of digit strings. */
69  ae = a; while (xisdigit(*ae)) ae++;
70  be = b; while (xisdigit(*be)) be++;
71 
72  /* Calculate digit comparison return code. */
73  if (a == ae || b == be)
74  rc = (*b - *a) * _invert_digits_alphas_comparison;
75  else {
76  rc = (ae - a) - (be - b);
77  if (!rc)
78  rc = strncmp(a, b, (ae - a));
79  }
80  } else {
81  /* Find end of alpha strings. */
82  ae = a; while (xisrpmalpha(*ae)) ae++;
83  be = b; while (xisrpmalpha(*be)) be++;
84 
85  /* Calculate alpha comparison return code. */
86  rc = strncmp(a, b, MAX((ae - a), (be - b)));
87  }
88  }
89 
90  /* Longer string wins. */
91  if (!rc)
92  rc = (*a - *b);
93 
94  /* Force strict -1, 0, 1 return. */
95  rc = (rc > 0 ? 1
96  : rc < 0 ? -1
97  : 0);
98  return rc;
99 }
100 
101 int rpmEVRparse(const char * evrstr, EVR_t evr)
102  /*@modifies evrstr, evr @*/
103 {
104  char *s = xstrdup(evrstr);
105  char *se;
106 
107  evr->str = se = s;
108  while (*se && xisdigit(*se)) se++; /* se points to epoch terminator */
109 
110  if (*se == ':') {
111  evr->E = s;
112  *se++ = '\0';
113  evr->V = se;
114 /*@-branchstate@*/
115  if (*evr->E == '\0') evr->E = "0";
116 /*@=branchstate@*/
117  evr->Elong = strtoul(evr->E, NULL, 10);
118  } else {
119  evr->E = NULL; /* XXX disable epoch compare if missing */
120  evr->V = s;
121  evr->Elong = 0;
122  }
123  se = strrchr(se, '-'); /* se points to version terminator */
124  if (se) {
125  *se++ = '\0';
126  evr->R = se;
127  } else {
128  evr->R = NULL;
129  }
130  return 0;
131 }
132 
139 static int compare_values(const char *a, const char *b)
140  /*@*/
141 {
142  return rpmvercmp(a, b);
143 }
144 
145 int rpmEVRcompare(const EVR_t a, const EVR_t b)
146 {
147  int rc = 0;
148 
149  if (!rc)
150  rc = compare_values(a->E, b->E);
151  if (!rc)
152  rc = compare_values(a->V, b->V);
153  if (!rc)
154  rc = compare_values(a->R, b->R);
155  return rc;
156 }
157 
158 int (*rpmvercmp) (const char *a, const char *b) = rpmEVRcmp;
159 
162 /*@unchecked@*/ /*@observer@*/
163 static struct EVRop_s {
164 /*@observer@*/ /*@null@*/
165  const char * operator;
167 } cops[] = {
168  { "<=", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
169  { "=<", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
170 
171  { "==", RPMSENSE_EQUAL},
172  { "!=", RPMSENSE_NOTEQUAL},
173 
174  { ">=", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
175  { "=>", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
176 
177  { "<", RPMSENSE_LESS},
178  { "=", RPMSENSE_EQUAL},
179  { ">", RPMSENSE_GREATER},
180 
181  { NULL, 0 },
182 };
183 
184 rpmsenseFlags rpmEVRflags(const char *op, const char **end)
185 {
186  rpmsenseFlags Flags = 0;
187  struct EVRop_s *cop;
188 
189  if (op == NULL || *op == '\0')
190  Flags = RPMSENSE_EQUAL;
191  else
192  for (cop = cops; cop->operator != NULL; cop++) {
193  if (strncmp(op, cop->operator, strlen(cop->operator)))
194  continue;
195  Flags = cop->sense;
196  if (end)
197  *end = op + strlen(cop->operator);
198  break;
199  }
200  return Flags;
201 }