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 }