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