rpm 5.3.7

rpmdb/rpmevr.c

Go to the documentation of this file.
00001 
00004 #include "system.h"
00005 
00006 #include <rpmiotypes.h>
00007 #include <rpmmacro.h>
00008 #define _MIRE_INTERNAL
00009 #include <mire.h>
00010 
00011 #include <rpmtag.h>
00012 #define _RPMEVR_INTERNAL
00013 #include <rpmevr.h>
00014 
00015 #include "debug.h"
00016 
00017 /*@unchecked@*/
00018 int _rpmevr_debug = 0;
00019 
00020 #if !defined(MAX)
00021 #define MAX(x, y) ( ((x)>(y))?(x):(y) )
00022 #endif
00023 
00024 EVR_t rpmEVRnew(uint32_t Flags, int initialize)
00025 {
00026     EVR_t evr = xcalloc(1, sizeof(*evr));
00027     evr->Flags = Flags;
00028     if (initialize) {
00029 /*@-observertrans -readonlytrans @*/
00030         evr->F[RPMEVR_E] = "0";
00031         evr->F[RPMEVR_V] = "";
00032         evr->F[RPMEVR_R] = "";
00033         evr->F[RPMEVR_D] = "";
00034 /*@=observertrans =readonlytrans @*/
00035     }
00036     return evr;
00037 }
00038 
00039 EVR_t rpmEVRfree(EVR_t evr)
00040 {
00041     if (evr != NULL) {
00042         evr->str = _free(evr->str);
00043         memset(evr, 0, sizeof(*evr));
00044         evr = _free(evr);
00045     }
00046     return NULL;
00047 }
00048 
00049 /* XXX Force digits to beat alphas. See bugzilla #50977. */
00050 /*@unchecked@*/
00051 #if defined(RPM_VENDOR_MANDRIVA) /* old-comparision-behaviour */
00052 static int _invert_digits_alphas_comparison = -1;
00053 #else
00054 static int _invert_digits_alphas_comparison = 1;
00055 #endif
00056 
00057 /* XXX Punctuation characters that are not treated as alphas */
00058 /*@unchecked@*/ /*@observer@*/
00059 static const char * _rpmnotalpha = ".:-";
00060 
00066 static inline int xisrpmalpha(int c)
00067         /*@*/
00068 {
00069     int rc = xisalpha(c);
00070     if (!rc)
00071         rc = xispunct(c);
00072     if (rc && _rpmnotalpha && *_rpmnotalpha)
00073         rc = (strchr(_rpmnotalpha, c) == NULL);
00074 /*@-globstate@*/
00075     return rc;
00076 /*@=globstate@*/
00077 }
00078 
00079 int rpmEVRcmp(const char * a, const char * b)
00080         /*@*/
00081 {
00082     const char * ae = NULL, * be = NULL;
00083     int rc = 0;         /* assume equal */
00084 
00085 assert(a != NULL);
00086 assert(b != NULL);
00087     /* Compare version strings segment by segment. */
00088     for (; *a && *b && rc == 0; a = ae, b = be) {
00089 
00090         /* Skip leading non-alpha, non-digit characters. */
00091         while (*a && !(xisdigit((int)*a) || xisrpmalpha((int)*a))) a++;
00092         while (*b && !(xisdigit((int)*b) || xisrpmalpha((int)*b))) b++;
00093 
00094         /* Wildcard comparison? */
00095         /* Note: limited to suffix-only wildcard matching at the moment. */
00096         if (a[0] == '*' && a[1] == '\0') {
00097             be = strchr(b, '\0');       /* XXX be = b + strlen(b); */
00098         } else
00099         if (b[0] == '*' && b[1] == '\0') {
00100             ae = strchr(a, '\0');       /* XXX ae = a + strlen(a); */
00101         } else
00102         /* Digit string comparison? */
00103         if (xisdigit((int)*a) || xisdigit((int)*b)) {
00104             /* Discard leading zeroes. */
00105             while (a[0] == '0' && xisdigit((int)a[1])) a++;
00106             while (b[0] == '0' && xisdigit((int)b[1])) b++;
00107 
00108             /* Find end of digit strings. */
00109             ae = a; while (xisdigit((int)*ae)) ae++;
00110             be = b; while (xisdigit((int)*be)) be++;
00111 
00112             /* Calculate digit comparison return code. */
00113             if (a == ae || b == be)
00114                 rc = (int)(*a - *b) * _invert_digits_alphas_comparison;
00115             else {
00116                 rc = (ae - a) - (be - b);
00117                 if (!rc)
00118                     rc = strncmp(a, b, (ae - a));
00119             }
00120         } else {
00121             /* Find end of alpha strings. */
00122             ae = a; while (xisrpmalpha((int)*ae)) ae++;
00123             be = b; while (xisrpmalpha((int)*be)) be++;
00124 
00125             /* Calculate alpha comparison return code. */
00126             rc = strncmp(a, b, MAX((ae - a), (be - b)));
00127         }
00128     }
00129 
00130     /* Longer string wins. */
00131     if (!rc)
00132         rc = (int)(*a - *b);
00133 
00134     /* Force strict -1, 0, 1 return. */
00135     rc = (rc > 0 ? 1
00136         : rc < 0 ? -1
00137         : 0);
00138     return rc;
00139 }
00140 
00141 /*@unchecked@*/ /*@observer@*/ /*@null@*/
00142 static const char * _evr_tuple_match =
00143         "^(?:([^:-]+):)?([^:-]+)(?:-([^:-]+))?(?::([^:-]+))?$";
00144 /*@unchecked@*/ /*@only@*/ /*@observer@*/ /*@null@*/
00145 const char * evr_tuple_match = NULL;
00146 /*@unchecked@*/ /*@refcounted@*/ /*@null@*/
00147 miRE evr_tuple_mire = NULL;
00148 
00149 static miRE rpmEVRmire(void)
00150         /*@*/
00151 {
00152 /*@-globs -internalglobs -mods @*/
00153     if (evr_tuple_mire == NULL) {
00154         int xx;
00155         evr_tuple_match = rpmExpand("%{?evr_tuple_match}", NULL);
00156         if (evr_tuple_match == NULL || evr_tuple_match[0] == '\0')
00157             evr_tuple_match = xstrdup(_evr_tuple_match);
00158 
00159         evr_tuple_mire = mireNew(RPMMIRE_REGEX, 0);
00160         xx = mireSetCOptions(evr_tuple_mire, RPMMIRE_REGEX, 0, 0, NULL);
00161         xx = mireRegcomp(evr_tuple_mire, evr_tuple_match);
00162 
00163     }
00164 /*@=globs =internalglobs =mods @*/
00165 assert(evr_tuple_match != NULL && evr_tuple_mire != NULL);
00166 /*@-globstate -retalias@*/
00167     return evr_tuple_mire;
00168 /*@=globstate =retalias@*/
00169 }
00170 
00171 int rpmEVRparse(const char * evrstr, EVR_t evr)
00172         /*@modifies evrstr, evr @*/
00173 {
00174     miRE mire = rpmEVRmire();
00175     int noffsets = 6 * 3;
00176     int offsets[6 * 3];
00177     size_t nb;
00178     int xx;
00179     int i;
00180 
00181     memset(evr, 0, sizeof(*evr));
00182     evr->str = xstrdup(evrstr);
00183     nb = strlen(evr->str);
00184 
00185     memset(offsets, -1, sizeof(offsets));
00186     xx = mireSetEOptions(mire, offsets, noffsets);
00187 
00188     xx = mireRegexec(mire, evr->str, strlen(evr->str));
00189 
00190     for (i = 0; i < noffsets; i += 2) {
00191         int ix;
00192 
00193         if (offsets[i] < 0)
00194             continue;
00195 
00196         switch (i/2) {
00197         default:
00198         case 0: continue;       /*@notreached@*/ /*@switchbreak@*/ break;
00199         case 1: ix = RPMEVR_E;  /*@switchbreak@*/break;
00200         case 2: ix = RPMEVR_V;  /*@switchbreak@*/break;
00201         case 3: ix = RPMEVR_R;  /*@switchbreak@*/break;
00202         case 4: ix = RPMEVR_D;  /*@switchbreak@*/break;
00203         }
00204 
00205 assert(offsets[i  ] >= 0 && offsets[i  ] <= (int)nb);
00206 assert(offsets[i+1] >= 0 && offsets[i+1] <= (int)nb);
00207         {   char * te = (char *) evr->str;
00208             evr->F[ix] = te + offsets[i];
00209             te += offsets[i+1];
00210             *te = '\0';
00211         }
00212 
00213     }
00214 
00215     /* XXX HACK: postpone committing to single "missing" value for now. */
00216 /*@-observertrans -readonlytrans@*/
00217     if (evr->F[RPMEVR_E] == NULL) evr->F[RPMEVR_E] = "0";
00218     if (evr->F[RPMEVR_V] == NULL) evr->F[RPMEVR_V] = "";
00219     if (evr->F[RPMEVR_R] == NULL) evr->F[RPMEVR_R] = "";
00220     if (evr->F[RPMEVR_D] == NULL) evr->F[RPMEVR_D] = "";
00221 /*@=observertrans =readonlytrans@*/
00222 
00223     evr->Elong = strtoul(evr->F[RPMEVR_E], NULL, 10);
00224 
00225     xx = mireSetEOptions(mire, NULL, 0);
00226 
00227     return 0;
00228 }
00229 
00236 static int compare_values(const char *a, const char *b)
00237         /*@*/
00238 {
00239     return rpmvercmp(a, b);
00240 }
00241 
00242 /*@unchecked@*/ /*@only@*/ /*@observer@*/ /*@null@*/
00243 static const char * evr_tuple_order = NULL;
00244 
00249 /*@observer@*/
00250 static const char * rpmEVRorder(void)
00251         /*@*/
00252 {
00253 /*@-globs -internalglobs -mods @*/
00254     if (evr_tuple_order == NULL) {
00255         evr_tuple_order = rpmExpand("%{?evr_tuple_order}", NULL);
00256         if (evr_tuple_order == NULL || evr_tuple_order[0] == '\0')
00257             evr_tuple_order = xstrdup("EVR");
00258     }
00259 /*@=globs =internalglobs =mods @*/
00260 assert(evr_tuple_order != NULL && evr_tuple_order[0] != '\0');
00261     return evr_tuple_order;
00262 }
00263 
00264 int rpmEVRcompare(const EVR_t a, const EVR_t b)
00265 {
00266     const char * s;
00267     int rc = 0;
00268 
00269 assert(a->F[RPMEVR_E] != NULL);
00270 assert(a->F[RPMEVR_V] != NULL);
00271 assert(a->F[RPMEVR_R] != NULL);
00272 assert(a->F[RPMEVR_D] != NULL);
00273 assert(b->F[RPMEVR_E] != NULL);
00274 assert(b->F[RPMEVR_V] != NULL);
00275 assert(b->F[RPMEVR_R] != NULL);
00276 assert(b->F[RPMEVR_D] != NULL);
00277 
00278     for (s = rpmEVRorder(); *s != '\0'; s++) {
00279         int ix;
00280 #if defined(RPM_VENDOR_MANDRIVA) /* mdvbz#55810 */
00281         if(*s == 'R' && (b->Flags & (~RPMSENSE_GREATER & RPMSENSE_EQUAL))
00282                                 && *(b->F[RPMEVR_R]) == '\0')
00283                             break;
00284 #endif
00285 
00286         switch ((int)*s) {
00287         default:        continue;       /*@notreached@*/ /*@switchbreak@*/break;
00288         case 'E':       ix = RPMEVR_E;  /*@switchbreak@*/break;
00289         case 'V':       ix = RPMEVR_V;  /*@switchbreak@*/break;
00290         case 'R':       ix = RPMEVR_R;  /*@switchbreak@*/break;
00291         case 'D':       ix = RPMEVR_D;  /*@switchbreak@*/break;
00292         }
00293         rc = compare_values(a->F[ix], b->F[ix]);
00294         if (rc)
00295             break;
00296     }
00297     return rc;
00298 }
00299 
00300 int rpmEVRoverlap(EVR_t a, EVR_t b)
00301 {
00302     rpmsenseFlags aF = a->Flags;
00303     rpmsenseFlags bF = b->Flags;
00304     int sense;
00305     int result;
00306 
00307     /* XXX HACK: postpone committing to single "missing" value for now. */
00308 /*@-mods -observertrans -readonlytrans @*/
00309     if (a->F[RPMEVR_E] == NULL) a->F[RPMEVR_E] = "0";
00310     if (b->F[RPMEVR_E] == NULL) b->F[RPMEVR_E] = "0";
00311     if (a->F[RPMEVR_V] == NULL) a->F[RPMEVR_V] = "";
00312     if (b->F[RPMEVR_V] == NULL) b->F[RPMEVR_V] = "";
00313     if (a->F[RPMEVR_R] == NULL) a->F[RPMEVR_R] = "";
00314     if (b->F[RPMEVR_R] == NULL) b->F[RPMEVR_R] = "";
00315     if (a->F[RPMEVR_D] == NULL) a->F[RPMEVR_D] = "";
00316     if (b->F[RPMEVR_D] == NULL) b->F[RPMEVR_D] = "";
00317 /*@=mods =observertrans =readonlytrans @*/
00318     sense = rpmEVRcompare(a, b);
00319 
00320     /* Detect overlap of {A,B} range. */
00321     if (aF == RPMSENSE_NOTEQUAL || bF == RPMSENSE_NOTEQUAL)
00322         result = (sense != 0);
00323     else if (sense < 0 && ((aF & RPMSENSE_GREATER) || (bF & RPMSENSE_LESS)))
00324         result = 1;
00325     else if (sense > 0 && ((aF & RPMSENSE_LESS) || (bF & RPMSENSE_GREATER)))
00326         result = 1;
00327     else if (sense == 0 &&
00328         (((aF & RPMSENSE_EQUAL) && (bF & RPMSENSE_EQUAL)) ||
00329          ((aF & RPMSENSE_LESS) && (bF & RPMSENSE_LESS)) ||
00330          ((aF & RPMSENSE_GREATER) && (bF & RPMSENSE_GREATER))))
00331         result = 1;
00332     else
00333         result = 0;
00334     return result;
00335 }
00336 
00337 /*@-redecl@*/
00338 int (*rpmvercmp) (const char *a, const char *b) = rpmEVRcmp;
00339 /*@=redecl@*/
00340 
00343 /*@unchecked@*/ /*@observer@*/
00344 static struct EVRop_s {
00345 /*@observer@*/ /*@null@*/
00346     const char * operator;
00347     rpmsenseFlags sense;
00348 } cops[] = {
00349     { "<=", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
00350     { "=<", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
00351 
00352     { "==", RPMSENSE_EQUAL},
00353     { "!=", RPMSENSE_NOTEQUAL},
00354     
00355     { ">=", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
00356     { "=>", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
00357 
00358     { "<", RPMSENSE_LESS},
00359     { "=", RPMSENSE_EQUAL},
00360     { ">", RPMSENSE_GREATER},
00361 
00362     { NULL, 0 },
00363 };
00364 
00365 rpmsenseFlags rpmEVRflags(const char *op, const char **end)
00366 {
00367     rpmsenseFlags Flags = 0;
00368     struct EVRop_s *cop;
00369 
00370     if (op == NULL || *op == '\0')
00371         Flags = RPMSENSE_EQUAL;
00372     else
00373     for (cop = cops; cop->operator != NULL; cop++) {
00374         if (strncmp(op, cop->operator, strlen(cop->operator)))
00375             continue;
00376         Flags = cop->sense;
00377         if (end)
00378             *end = op + strlen(cop->operator);
00379         break;
00380     }
00381     return Flags;
00382 }
00383 
00384 int rpmVersionCompare(Header A, Header B)
00385 {
00386     HE_t Ahe = memset(alloca(sizeof(*Ahe)), 0, sizeof(*Ahe));
00387     HE_t Bhe = memset(alloca(sizeof(*Bhe)), 0, sizeof(*Bhe));
00388     const char * one, * two;
00389     rpmuint32_t Eone, Etwo;
00390     const char * s;
00391     int rc = 0;
00392     int xx;
00393 
00394     for (s = rpmEVRorder(); *s != '\0'; s++) {
00395         switch ((int)*s) {
00396         default:        continue;       /*@notreached@*/ /*@switchbreak@*/break;
00397         case 'E':
00398             Ahe->tag = RPMTAG_EPOCH;
00399             xx = headerGet(A, Ahe, 0);
00400             Eone = (xx && Ahe->p.ui32p ? Ahe->p.ui32p[0] : 0);
00401             Bhe->tag = RPMTAG_EPOCH;
00402             xx = headerGet(B, Bhe, 0);
00403             Etwo = (xx && Bhe->p.ui32p ? Bhe->p.ui32p[0] : 0);
00404             if (Eone < Etwo)
00405                 rc = -1;
00406             else if (Eone > Etwo)
00407                 rc = 1;
00408             /*@switchbreak@*/ break;
00409         case 'V':
00410             Ahe->tag = RPMTAG_VERSION;
00411             xx = headerGet(A, Ahe, 0);
00412             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00413             Bhe->tag = RPMTAG_VERSION;
00414             xx = headerGet(B, Bhe, 0);
00415             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00416             rc = rpmvercmp(one, two);
00417             /*@switchbreak@*/ break;
00418         case 'R':
00419             Ahe->tag = RPMTAG_RELEASE;
00420             xx = headerGet(A, Ahe, 0);
00421             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00422             Bhe->tag = RPMTAG_RELEASE;
00423             xx = headerGet(B, Bhe, 0);
00424             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00425             rc = rpmvercmp(one, two);
00426             /*@switchbreak@*/ break;
00427         case 'D':
00428             Ahe->tag = RPMTAG_DISTEPOCH;
00429             xx = headerGet(A, Ahe, 0);
00430             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00431             Bhe->tag = RPMTAG_DISTEPOCH;
00432             xx = headerGet(B, Bhe, 0);
00433             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00434             rc = rpmvercmp(one, two);
00435             /*@switchbreak@*/ break;
00436         }
00437         Ahe->p.ptr = _free(Ahe->p.ptr);
00438         Bhe->p.ptr = _free(Bhe->p.ptr);
00439         if (rc)
00440             break;
00441     }
00442     return rc;
00443 }