Sanitize python object -> tag number exception handling
[platform/upstream/rpm.git] / lib / rpmvercmp.c
1 /** \ingroup rpmts
2  * \file lib/rpmvercmp.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/rpmlib.h>         /* rpmvercmp proto */
8 #include <rpm/rpmstring.h>
9
10 #include "debug.h"
11
12 /* compare alpha and numeric segments of two versions */
13 /* return 1: a is newer than b */
14 /*        0: a and b are the same version */
15 /*       -1: b is newer than a */
16 int rpmvercmp(const char * a, const char * b)
17 {
18     char oldch1, oldch2;
19     char abuf[strlen(a)+1], bbuf[strlen(b)+1];
20     char *str1 = abuf, *str2 = bbuf;
21     char * one, * two;
22     int rc;
23     int isnum;
24
25     /* easy comparison to see if versions are identical */
26     if (rstreq(a, b)) return 0;
27
28     strcpy(str1, a);
29     strcpy(str2, b);
30
31     one = str1;
32     two = str2;
33
34     /* loop through each version segment of str1 and str2 and compare them */
35     while (*one && *two) {
36         while (*one && !risalnum(*one)) one++;
37         while (*two && !risalnum(*two)) two++;
38
39         /* If we ran to the end of either, we are finished with the loop */
40         if (!(*one && *two)) break;
41
42         str1 = one;
43         str2 = two;
44
45         /* grab first completely alpha or completely numeric segment */
46         /* leave one and two pointing to the start of the alpha or numeric */
47         /* segment and walk str1 and str2 to end of segment */
48         if (risdigit(*str1)) {
49             while (*str1 && risdigit(*str1)) str1++;
50             while (*str2 && risdigit(*str2)) str2++;
51             isnum = 1;
52         } else {
53             while (*str1 && risalpha(*str1)) str1++;
54             while (*str2 && risalpha(*str2)) str2++;
55             isnum = 0;
56         }
57
58         /* save character at the end of the alpha or numeric segment */
59         /* so that they can be restored after the comparison */
60         oldch1 = *str1;
61         *str1 = '\0';
62         oldch2 = *str2;
63         *str2 = '\0';
64
65         /* this cannot happen, as we previously tested to make sure that */
66         /* the first string has a non-null segment */
67         if (one == str1) return -1;     /* arbitrary */
68
69         /* take care of the case where the two version segments are */
70         /* different types: one numeric, the other alpha (i.e. empty) */
71         /* numeric segments are always newer than alpha segments */
72         /* XXX See patch #60884 (and details) from bugzilla #50977. */
73         if (two == str2) return (isnum ? 1 : -1);
74
75         if (isnum) {
76             /* this used to be done by converting the digit segments */
77             /* to ints using atoi() - it's changed because long  */
78             /* digit segments can overflow an int - this should fix that. */
79
80             /* throw away any leading zeros - it's a number, right? */
81             while (*one == '0') one++;
82             while (*two == '0') two++;
83
84             /* whichever number has more digits wins */
85             if (strlen(one) > strlen(two)) return 1;
86             if (strlen(two) > strlen(one)) return -1;
87         }
88
89         /* strcmp will return which one is greater - even if the two */
90         /* segments are alpha or if they are numeric.  don't return  */
91         /* if they are equal because there might be more segments to */
92         /* compare */
93         rc = strcmp(one, two);
94         if (rc) return (rc < 1 ? -1 : 1);
95
96         /* restore character that was replaced by null above */
97         *str1 = oldch1;
98         one = str1;
99         *str2 = oldch2;
100         two = str2;
101     }
102
103     /* this catches the case where all numeric and alpha segments have */
104     /* compared identically but the segment sepparating characters were */
105     /* different */
106     if ((!*one) && (!*two)) return 0;
107
108     /* whichever version still has characters left over wins */
109     if (!*one) return -1; else return 1;
110 }