Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

lib/rpmvercmp.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmlib.h"
00008 
00009 #include "debug.h"
00010 
00011 /* compare alpha and numeric segments of two versions */
00012 /* return 1: a is newer than b */
00013 /*        0: a and b are the same version */
00014 /*       -1: b is newer than a */
00015 int rpmvercmp(const char * a, const char * b)
00016 {
00017     char oldch1, oldch2;
00018     char * str1, * str2;
00019     char * one, * two;
00020     int rc;
00021     int isnum;
00022 
00023     /* easy comparison to see if versions are identical */
00024     if (!strcmp(a, b)) return 0;
00025 
00026     str1 = alloca(strlen(a) + 1);
00027     str2 = alloca(strlen(b) + 1);
00028 
00029     strcpy(str1, a);
00030     strcpy(str2, b);
00031 
00032     one = str1;
00033     two = str2;
00034 
00035     /* loop through each version segment of str1 and str2 and compare them */
00036     while (*one && *two) {
00037         while (*one && !xisalnum(*one)) one++;
00038         while (*two && !xisalnum(*two)) two++;
00039 
00040         if ( !*one && !*two )
00041                 return 0;
00042 
00043         str1 = one;
00044         str2 = two;
00045 
00046         /* grab first completely alpha or completely numeric segment */
00047         /* leave one and two pointing to the start of the alpha or numeric */
00048         /* segment and walk str1 and str2 to end of segment */
00049         /* Also take care of the case where the two version segments are */
00050         /* different types: one numeric and one alpha */
00051         if (xisdigit(*str1)) {
00052             if ( xisalpha(*str2) ) return -1;
00053             while (*str1 && xisdigit(*str1)) str1++;
00054             while (*str2 && xisdigit(*str2)) str2++;
00055             isnum = 1;
00056         } else {
00057             while (*str1 && xisalpha(*str1)) str1++;
00058             while (*str2 && xisalpha(*str2)) str2++;
00059             isnum = 0;
00060         }
00061 
00062         /* Again, take care of the case where the two version segments are */
00063         /* different types: one numeric and one alpha */
00064         if (one == str1) return -1;
00065         if (two == str2) return 1;
00066 
00067         /* save character at the end of the alpha or numeric segment */
00068         /* so that they can be restored after the comparison */
00069         oldch1 = *str1;
00070         *str1 = '\0';
00071         oldch2 = *str2;
00072         *str2 = '\0';
00073 
00074         if (isnum) {
00075             /* this used to be done by converting the digit segments */
00076             /* to ints using atoi() - it's changed because long  */
00077             /* digit segments can overflow an int - this should fix that. */
00078 
00079             /* throw away any leading zeros - it's a number, right? */
00080             while (*one == '0') one++;
00081             while (*two == '0') two++;
00082 
00083             /* whichever number has more digits wins */
00084             if (strlen(one) > strlen(two)) return 1;
00085             if (strlen(two) > strlen(one)) return -1;
00086         }
00087 
00088         /* strcmp will return which one is greater - even if the two */
00089         /* segments are alpha or if they are numeric.  don't return  */
00090         /* if they are equal because there might be more segments to */
00091         /* compare */
00092         rc = strcmp(one, two);
00093         if (rc) return rc;
00094 
00095         /* restore character that was replaced by null above */
00096         *str1 = oldch1;
00097         one = str1;
00098         *str2 = oldch2;
00099         two = str2;
00100     }
00101 
00102     /* this catches the case where all numeric and alpha segments have */
00103     /* compared identically but the segment sepparating characters were */
00104     /* different */
00105     if ((!*one) && (!*two)) return 0;
00106 
00107     /* whichever version still has characters left over wins */
00108     if (!*one) return -1; else return 1;
00109 }
00110 
00111 /* Moved from depends.c, because we use it in other places, too. */
00119 void parseEVR(char * evr,
00120                 /*@exposed@*/ /*@out@*/ const char ** ep,
00121                 /*@exposed@*/ /*@out@*/ const char ** vp,
00122                 /*@exposed@*/ /*@out@*/ const char ** rp)
00123         /*@modifies *ep, *vp, *rp @*/
00124 {
00125     const char *epoch;
00126     const char *version;                /* assume only version is present */
00127     const char *release;
00128     char *s, *se;
00129 
00130     s = evr;
00131     while (*s && xisdigit(*s)) s++;     /* s points to epoch terminator */
00132     se = strrchr(s, '-');               /* se points to version terminator */
00133 
00134     if (*s == ':') {
00135         epoch = evr;
00136         *s++ = '\0';
00137         version = s;
00138         if (*epoch == '\0') epoch = "0";
00139     } else {
00140         epoch = NULL;   /* XXX disable epoch compare if missing */
00141         version = evr;
00142     }
00143     if (se) {
00144         *se++ = '\0';
00145         release = se;
00146     } else {
00147         release = NULL;
00148     }
00149 
00150     if (ep) *ep = epoch;
00151     if (vp) *vp = version;
00152     if (rp) *rp = release;
00153 }
00154 
00155 /* Compare {A,B} [epoch:]version[-release] */
00156 int 
00157 rpmEVRcmp(const char * const aE, const char * const aV, const char * const aR,
00158           const char * const aDepend,
00159           const char * const bE, const char * const bV, const char * const bR,
00160           const char * const bDepend)
00161 {
00162     int sense = 0;
00163 
00164     rpmMessage(RPMMESS_DEBUG, "cmp e=%s, v=%s, r=%s\n and e=%s, v=%s, r=%s\n ",
00165                aE, aV, aR, bE, bV, bR);
00166 
00167 
00168     if (aE && *aE && bE && *bE)
00169         sense = rpmvercmp(aE, bE);
00170     else if (aE && *aE && atol(aE) > 0) {
00171         /* XXX legacy epoch-less requires/conflicts compatibility */
00172         rpmMessage(RPMMESS_DEBUG, _("the \"B\" dependency needs an epoch (assuming same as \"A\")\n\tA %s\tB %s\n"),
00173                 aDepend, bDepend);
00174         sense = 0;
00175     } else if (bE && *bE && atol(bE) > 0)
00176         sense = -1;
00177 
00178     if (sense == 0) {
00179         sense = rpmvercmp(aV, bV);
00180         if (sense == 0 && aR && *aR && bR && *bR) {
00181             sense = rpmvercmp(aR, bR);
00182         }
00183     }
00184 
00185     return sense;
00186 }
00187 
00188 int isChangeNameMoreFresh(const char * const head, 
00189                           const char * const tail[3]) 
00190 {
00191   int result;
00192   const char * evr[3];
00193   const char * wordAfterEmail;
00194   char * copy;
00195 
00196   rpmMessage(RPMMESS_DEBUG, "test: is '%s' more fresh than e=%s, v=%s, r=%s?\n",
00197              head, tail[0], tail[1], tail[2]);
00198   /* find the next to <email> word begin */
00199   if ( (wordAfterEmail = strrchr(head, '>')) )
00200     ++wordAfterEmail;
00201   else
00202     wordAfterEmail = head;
00203   while ( *wordAfterEmail && xisspace(*wordAfterEmail) )
00204     ++wordAfterEmail; 
00205   /* found. */
00206   copy = xstrdup(wordAfterEmail);
00207   parseEVR(copy, &evr[0],  &evr[1],  &evr[2]);
00208   /* The order of two argument groups is important: 
00209      if evr[] (passed as B on the second place) has no epoch, 
00210      rpmEVRcmp() assumes the same as in tail[];
00211      This fits our needs: the epoch may be omitted in a changelog entry (evr[])
00212      but there are no problems in specifying it in the format (tail[]). */
00213   result = rpmEVRcmp(tail[0], tail[1], tail[2], "",
00214                      evr[0], evr[1], evr[2], "") < 0;
00215   _free(copy);
00216   return result;
00217 }
00218 

Generated on Sun Feb 2 23:32:03 2003 for rpm by doxygen1.2.18