• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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(rpmuint32_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     if (evr->F[RPMEVR_E] == NULL) evr->F[RPMEVR_E] = "0";
00217     if (evr->F[RPMEVR_V] == NULL) evr->F[RPMEVR_V] = "";
00218     if (evr->F[RPMEVR_R] == NULL) evr->F[RPMEVR_R] = "";
00219     if (evr->F[RPMEVR_D] == NULL) evr->F[RPMEVR_D] = "";
00220 
00221     evr->Elong = strtoul(evr->F[RPMEVR_E], NULL, 10);
00222 
00223     xx = mireSetEOptions(mire, NULL, 0);
00224 
00225     return 0;
00226 }
00227 
00234 static int compare_values(const char *a, const char *b)
00235         /*@*/
00236 {
00237     return rpmvercmp(a, b);
00238 }
00239 
00240 /*@unchecked@*/ /*@only@*/ /*@observer@*/ /*@null@*/
00241 static const char * evr_tuple_order = NULL;
00242 
00247 /*@observer@*/
00248 static const char * rpmEVRorder(void)
00249         /*@*/
00250 {
00251 /*@-globs -internalglobs -mods @*/
00252     if (evr_tuple_order == NULL) {
00253         evr_tuple_order = rpmExpand("%{?evr_tuple_order}", NULL);
00254         if (evr_tuple_order == NULL || evr_tuple_order[0] == '\0')
00255             evr_tuple_order = xstrdup("EVR");
00256     }
00257 /*@=globs =internalglobs =mods @*/
00258 assert(evr_tuple_order != NULL && evr_tuple_order[0] != '\0');
00259     return evr_tuple_order;
00260 }
00261 
00262 int rpmEVRcompare(const EVR_t a, const EVR_t b)
00263 {
00264     const char * s;
00265     int rc = 0;
00266 
00267 assert(a->F[RPMEVR_E] != NULL);
00268 assert(a->F[RPMEVR_V] != NULL);
00269 assert(a->F[RPMEVR_R] != NULL);
00270 assert(a->F[RPMEVR_D] != NULL);
00271 assert(b->F[RPMEVR_E] != NULL);
00272 assert(b->F[RPMEVR_V] != NULL);
00273 assert(b->F[RPMEVR_R] != NULL);
00274 assert(b->F[RPMEVR_D] != NULL);
00275 
00276     for (s = rpmEVRorder(); *s != '\0'; s++) {
00277         int ix;
00278         switch ((int)*s) {
00279         default:        continue;       /*@notreached@*/ /*@switchbreak@*/break;
00280         case 'E':       ix = RPMEVR_E;  /*@switchbreak@*/break;
00281         case 'V':       ix = RPMEVR_V;  /*@switchbreak@*/break;
00282         case 'R':       ix = RPMEVR_R;  /*@switchbreak@*/break;
00283         case 'D':       ix = RPMEVR_D;  /*@switchbreak@*/break;
00284         }
00285         rc = compare_values(a->F[ix], b->F[ix]);
00286         if (rc)
00287             break;
00288     }
00289     return rc;
00290 }
00291 
00292 int rpmEVRoverlap(EVR_t a, EVR_t b)
00293 {
00294     rpmsenseFlags aF = a->Flags;
00295     rpmsenseFlags bF = b->Flags;
00296     int sense;
00297     int result;
00298 
00299     /* XXX HACK: postpone committing to single "missing" value for now. */
00300 /*@-mods -observertrans -readonlytrans @*/
00301     if (a->F[RPMEVR_E] == NULL) a->F[RPMEVR_E] = "0";
00302     if (b->F[RPMEVR_E] == NULL) b->F[RPMEVR_E] = "0";
00303     if (a->F[RPMEVR_V] == NULL) a->F[RPMEVR_V] = "";
00304     if (b->F[RPMEVR_V] == NULL) b->F[RPMEVR_V] = "";
00305     if (a->F[RPMEVR_R] == NULL) a->F[RPMEVR_R] = "";
00306     if (b->F[RPMEVR_R] == NULL) b->F[RPMEVR_R] = "";
00307     if (a->F[RPMEVR_D] == NULL) a->F[RPMEVR_D] = "";
00308     if (b->F[RPMEVR_D] == NULL) b->F[RPMEVR_D] = "";
00309 /*@=mods =observertrans =readonlytrans @*/
00310     sense = rpmEVRcompare(a, b);
00311 
00312     /* Detect overlap of {A,B} range. */
00313     if (aF == RPMSENSE_NOTEQUAL || bF == RPMSENSE_NOTEQUAL)
00314         result = (sense != 0);
00315     else if (sense < 0 && ((aF & RPMSENSE_GREATER) || (bF & RPMSENSE_LESS)))
00316         result = 1;
00317     else if (sense > 0 && ((aF & RPMSENSE_LESS) || (bF & RPMSENSE_GREATER)))
00318         result = 1;
00319     else if (sense == 0 &&
00320         (((aF & RPMSENSE_EQUAL) && (bF & RPMSENSE_EQUAL)) ||
00321          ((aF & RPMSENSE_LESS) && (bF & RPMSENSE_LESS)) ||
00322          ((aF & RPMSENSE_GREATER) && (bF & RPMSENSE_GREATER))))
00323         result = 1;
00324     else
00325         result = 0;
00326     return result;
00327 }
00328 
00329 /*@-redecl@*/
00330 int (*rpmvercmp) (const char *a, const char *b) = rpmEVRcmp;
00331 /*@=redecl@*/
00332 
00335 /*@unchecked@*/ /*@observer@*/
00336 static struct EVRop_s {
00337 /*@observer@*/ /*@null@*/
00338     const char * operator;
00339     rpmsenseFlags sense;
00340 } cops[] = {
00341     { "<=", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
00342     { "=<", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
00343 
00344     { "==", RPMSENSE_EQUAL},
00345     { "!=", RPMSENSE_NOTEQUAL},
00346     
00347     { ">=", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
00348     { "=>", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
00349 
00350     { "<", RPMSENSE_LESS},
00351     { "=", RPMSENSE_EQUAL},
00352     { ">", RPMSENSE_GREATER},
00353 
00354     { NULL, 0 },
00355 };
00356 
00357 rpmsenseFlags rpmEVRflags(const char *op, const char **end)
00358 {
00359     rpmsenseFlags Flags = 0;
00360     struct EVRop_s *cop;
00361 
00362     if (op == NULL || *op == '\0')
00363         Flags = RPMSENSE_EQUAL;
00364     else
00365     for (cop = cops; cop->operator != NULL; cop++) {
00366         if (strncmp(op, cop->operator, strlen(cop->operator)))
00367             continue;
00368         Flags = cop->sense;
00369         if (end)
00370             *end = op + strlen(cop->operator);
00371         break;
00372     }
00373     return Flags;
00374 }
00375 
00376 int rpmVersionCompare(Header A, Header B)
00377 {
00378     HE_t Ahe = memset(alloca(sizeof(*Ahe)), 0, sizeof(*Ahe));
00379     HE_t Bhe = memset(alloca(sizeof(*Bhe)), 0, sizeof(*Bhe));
00380     const char * one, * two;
00381     rpmuint32_t Eone, Etwo;
00382     const char * s;
00383     int rc = 0;
00384     int xx;
00385 
00386     for (s = rpmEVRorder(); *s != '\0'; s++) {
00387         switch ((int)*s) {
00388         default:        continue;       /*@notreached@*/ /*@switchbreak@*/break;
00389         case 'E':
00390             Ahe->tag = RPMTAG_EPOCH;
00391             xx = headerGet(A, Ahe, 0);
00392             Eone = (xx && Ahe->p.ui32p ? Ahe->p.ui32p[0] : 0);
00393             Bhe->tag = RPMTAG_EPOCH;
00394             xx = headerGet(B, Bhe, 0);
00395             Etwo = (xx && Bhe->p.ui32p ? Bhe->p.ui32p[0] : 0);
00396             if (Eone < Etwo)
00397                 rc = -1;
00398             else if (Eone > Etwo)
00399                 rc = 1;
00400             /*@switchbreak@*/ break;
00401         case 'V':
00402             Ahe->tag = RPMTAG_VERSION;
00403             xx = headerGet(A, Ahe, 0);
00404             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00405             Bhe->tag = RPMTAG_VERSION;
00406             xx = headerGet(B, Bhe, 0);
00407             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00408             rc = rpmvercmp(one, two);
00409             /*@switchbreak@*/ break;
00410         case 'R':
00411             Ahe->tag = RPMTAG_RELEASE;
00412             xx = headerGet(A, Ahe, 0);
00413             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00414             Bhe->tag = RPMTAG_RELEASE;
00415             xx = headerGet(B, Bhe, 0);
00416             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00417             rc = rpmvercmp(one, two);
00418             /*@switchbreak@*/ break;
00419         case 'D':
00420             Ahe->tag = RPMTAG_DISTEPOCH;
00421             xx = headerGet(A, Ahe, 0);
00422             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00423             Bhe->tag = RPMTAG_DISTEPOCH;
00424             xx = headerGet(B, Bhe, 0);
00425             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00426             rc = rpmvercmp(one, two);
00427             /*@switchbreak@*/ break;
00428         }
00429         Ahe->p.ptr = _free(Ahe->p.ptr);
00430         Bhe->p.ptr = _free(Bhe->p.ptr);
00431         if (rc)
00432             break;
00433     }
00434     return rc;
00435 }

Generated on Fri Dec 3 2010 20:54:11 for rpm by  doxygen 1.7.2