rpm 5.2.1

- 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 }