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     /*@-branchstate@*/
00037 /*@-boundsread@*/
00038     while (*one && *two) {
00039         while (*one && !xisalnum(*one)) one++;
00040         while (*two && !xisalnum(*two)) two++;
00041 
00042         /* If we ran to the end of either, we are finished with the loop */
00043         if (!(*one && *two)) break;
00044 
00045         str1 = one;
00046         str2 = two;
00047 
00048         /* grab first completely alpha or completely numeric segment */
00049         /* leave one and two pointing to the start of the alpha or numeric */
00050         /* segment and walk str1 and str2 to end of segment */
00051         if (xisdigit(*str1)) {
00052             while (*str1 && xisdigit(*str1)) str1++;
00053             while (*str2 && xisdigit(*str2)) str2++;
00054             isnum = 1;
00055         } else {
00056             while (*str1 && xisalpha(*str1)) str1++;
00057             while (*str2 && xisalpha(*str2)) str2++;
00058             isnum = 0;
00059         }
00060 
00061         /* save character at the end of the alpha or numeric segment */
00062         /* so that they can be restored after the comparison */
00063 /*@-boundswrite@*/
00064         oldch1 = *str1;
00065         *str1 = '\0';
00066         oldch2 = *str2;
00067         *str2 = '\0';
00068 /*@=boundswrite@*/
00069 
00070         /* this cannot happen, as we previously tested to make sure that */
00071         /* the first string has a non-null segment */
00072         if (one == str1) return -1;     /* arbitrary */
00073 
00074         /* take care of the case where the two version segments are */
00075         /* different types: one numeric, the other alpha (i.e. empty) */
00076         /* numeric segments are always newer than alpha segments */
00077         /* XXX See patch #60884 (and details) from bugzilla #50977. */
00078         if (two == str2) return (isnum ? 1 : -1);
00079 
00080         if (isnum) {
00081             /* this used to be done by converting the digit segments */
00082             /* to ints using atoi() - it's changed because long  */
00083             /* digit segments can overflow an int - this should fix that. */
00084 
00085             /* throw away any leading zeros - it's a number, right? */
00086             while (*one == '0') one++;
00087             while (*two == '0') two++;
00088 
00089             /* whichever number has more digits wins */
00090             if (strlen(one) > strlen(two)) return 1;
00091             if (strlen(two) > strlen(one)) return -1;
00092         }
00093 
00094         /* strcmp will return which one is greater - even if the two */
00095         /* segments are alpha or if they are numeric.  don't return  */
00096         /* if they are equal because there might be more segments to */
00097         /* compare */
00098         rc = strcmp(one, two);
00099         if (rc) return (rc < 1 ? -1 : 1);
00100 
00101         /* restore character that was replaced by null above */
00102 /*@-boundswrite@*/
00103         *str1 = oldch1;
00104         one = str1;
00105         *str2 = oldch2;
00106         two = str2;
00107 /*@=boundswrite@*/
00108     }
00109     /*@=branchstate@*/
00110 /*@=boundsread@*/
00111 
00112     /* this catches the case where all numeric and alpha segments have */
00113     /* compared identically but the segment sepparating characters were */
00114     /* different */
00115 /*@-boundsread@*/
00116     if ((!*one) && (!*two)) return 0;
00117 
00118     /* whichever version still has characters left over wins */
00119     if (!*one) return -1; else return 1;
00120 /*@=boundsread@*/
00121 }

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2