rpm 5.3.12
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) || defined(RPMVERCMP_DIGITS_BEAT_ALPHA) /* 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 = 0;
00280 
00281         switch ((int)*s) {
00282         default:        continue;       /*@notreached@*/ /*@switchbreak@*/break;
00283         case 'E':       ix = RPMEVR_E;  /*@switchbreak@*/break;
00284         case 'V':       ix = RPMEVR_V;  /*@switchbreak@*/break;
00285         case 'R':       ix = RPMEVR_R;  /*@switchbreak@*/break;
00286         case 'D':       ix = RPMEVR_D;  /*@switchbreak@*/break;
00287         }
00288 #if defined(RPM_VENDOR_MANDRIVA) /* mdvbz#55810 */
00289         if(ix >= RPMEVR_R && (b->Flags & (~RPMSENSE_GREATER & RPMSENSE_EQUAL))
00290                                 && *(b->F[ix]) == '\0')
00291                             break;
00292 #endif
00293 
00294         rc = compare_values(a->F[ix], b->F[ix]);
00295         if (rc)
00296             break;
00297     }
00298     return rc;
00299 }
00300 
00301 int rpmEVRoverlap(EVR_t a, EVR_t b)
00302 {
00303     rpmsenseFlags aF = a->Flags;
00304     rpmsenseFlags bF = b->Flags;
00305     int sense;
00306     int result;
00307 
00308     /* XXX HACK: postpone committing to single "missing" value for now. */
00309 /*@-mods -observertrans -readonlytrans @*/
00310     if (a->F[RPMEVR_E] == NULL) a->F[RPMEVR_E] = "0";
00311     if (b->F[RPMEVR_E] == NULL) b->F[RPMEVR_E] = "0";
00312     if (a->F[RPMEVR_V] == NULL) a->F[RPMEVR_V] = "";
00313     if (b->F[RPMEVR_V] == NULL) b->F[RPMEVR_V] = "";
00314     if (a->F[RPMEVR_R] == NULL) a->F[RPMEVR_R] = "";
00315     if (b->F[RPMEVR_R] == NULL) b->F[RPMEVR_R] = "";
00316     if (a->F[RPMEVR_D] == NULL) a->F[RPMEVR_D] = "";
00317     if (b->F[RPMEVR_D] == NULL) b->F[RPMEVR_D] = "";
00318 /*@=mods =observertrans =readonlytrans @*/
00319     sense = rpmEVRcompare(a, b);
00320 
00321     /* Detect overlap of {A,B} range. */
00322     if (aF == RPMSENSE_NOTEQUAL || bF == RPMSENSE_NOTEQUAL)
00323         result = (sense != 0);
00324     else if (sense < 0 && ((aF & RPMSENSE_GREATER) || (bF & RPMSENSE_LESS)))
00325         result = 1;
00326     else if (sense > 0 && ((aF & RPMSENSE_LESS) || (bF & RPMSENSE_GREATER)))
00327         result = 1;
00328     else if (sense == 0 &&
00329         (((aF & RPMSENSE_EQUAL) && (bF & RPMSENSE_EQUAL)) ||
00330          ((aF & RPMSENSE_LESS) && (bF & RPMSENSE_LESS)) ||
00331          ((aF & RPMSENSE_GREATER) && (bF & RPMSENSE_GREATER))))
00332         result = 1;
00333     else
00334         result = 0;
00335     return result;
00336 }
00337 
00338 /*@-redecl@*/
00339 int (*rpmvercmp) (const char *a, const char *b) = rpmEVRcmp;
00340 /*@=redecl@*/
00341 
00344 /*@unchecked@*/ /*@observer@*/
00345 static struct EVRop_s {
00346 /*@observer@*/ /*@null@*/
00347     const char * operator;
00348     rpmsenseFlags sense;
00349 } cops[] = {
00350     { "<=", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
00351     { "=<", RPMSENSE_LESS ^ RPMSENSE_EQUAL},
00352 
00353     { "==", RPMSENSE_EQUAL},
00354     { "!=", RPMSENSE_NOTEQUAL},
00355     
00356     { ">=", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
00357     { "=>", RPMSENSE_GREATER ^ RPMSENSE_EQUAL},
00358 
00359     { "<", RPMSENSE_LESS},
00360     { "=", RPMSENSE_EQUAL},
00361     { ">", RPMSENSE_GREATER},
00362 
00363     { NULL, 0 },
00364 };
00365 
00366 rpmsenseFlags rpmEVRflags(const char *op, const char **end)
00367 {
00368     rpmsenseFlags Flags = 0;
00369     struct EVRop_s *cop;
00370 
00371     if (op == NULL || *op == '\0')
00372         Flags = RPMSENSE_EQUAL;
00373     else
00374     for (cop = cops; cop->operator != NULL; cop++) {
00375         if (strncmp(op, cop->operator, strlen(cop->operator)))
00376             continue;
00377         Flags = cop->sense;
00378         if (end)
00379             *end = op + strlen(cop->operator);
00380         break;
00381     }
00382     return Flags;
00383 }
00384 
00385 int rpmVersionCompare(Header A, Header B)
00386 {
00387     HE_t Ahe = memset(alloca(sizeof(*Ahe)), 0, sizeof(*Ahe));
00388     HE_t Bhe = memset(alloca(sizeof(*Bhe)), 0, sizeof(*Bhe));
00389     const char * one, * two;
00390     rpmuint32_t Eone, Etwo;
00391     const char * s;
00392     int rc = 0;
00393     int xx;
00394 
00395     for (s = rpmEVRorder(); *s != '\0'; s++) {
00396         switch ((int)*s) {
00397         default:        continue;       /*@notreached@*/ /*@switchbreak@*/break;
00398         case 'E':
00399             Ahe->tag = RPMTAG_EPOCH;
00400             xx = headerGet(A, Ahe, 0);
00401             Eone = (xx && Ahe->p.ui32p ? Ahe->p.ui32p[0] : 0);
00402             Bhe->tag = RPMTAG_EPOCH;
00403             xx = headerGet(B, Bhe, 0);
00404             Etwo = (xx && Bhe->p.ui32p ? Bhe->p.ui32p[0] : 0);
00405             if (Eone < Etwo)
00406                 rc = -1;
00407             else if (Eone > Etwo)
00408                 rc = 1;
00409             /*@switchbreak@*/ break;
00410         case 'V':
00411             Ahe->tag = RPMTAG_VERSION;
00412             xx = headerGet(A, Ahe, 0);
00413             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00414             Bhe->tag = RPMTAG_VERSION;
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 'R':
00420             Ahe->tag = RPMTAG_RELEASE;
00421             xx = headerGet(A, Ahe, 0);
00422             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00423             Bhe->tag = RPMTAG_RELEASE;
00424             xx = headerGet(B, Bhe, 0);
00425             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00426             rc = rpmvercmp(one, two);
00427             /*@switchbreak@*/ break;
00428         case 'D':
00429             Ahe->tag = RPMTAG_DISTEPOCH;
00430             xx = headerGet(A, Ahe, 0);
00431             one = (xx && Ahe->p.str ? Ahe->p.str : "");
00432             Bhe->tag = RPMTAG_DISTEPOCH;
00433             xx = headerGet(B, Bhe, 0);
00434             two = (xx && Bhe->p.str ? Bhe->p.str : "");
00435             rc = rpmvercmp(one, two);
00436             /*@switchbreak@*/ break;
00437         }
00438         Ahe->p.ptr = _free(Ahe->p.ptr);
00439         Bhe->p.ptr = _free(Bhe->p.ptr);
00440         if (rc)
00441             break;
00442     }
00443     return rc;
00444 }