- --queryformat '[%{*:xml}\n]' to dump header content in XML.
[platform/upstream/rpm.git] / lib / rpmvercmp.c
1 /** \ingroup rpmts
2  * \file lib/rpmvercmp.c
3  */
4
5 #include "system.h"
6
7 #include <rpmlib.h>
8
9 #include "debug.h"
10
11 /* compare alpha and numeric segments of two versions */
12 /* return 1: a is newer than b */
13 /*        0: a and b are the same version */
14 /*       -1: b is newer than a */
15 int rpmvercmp(const char * a, const char * b)
16 {
17     char oldch1, oldch2;
18     char * str1, * str2;
19     char * one, * two;
20     int rc;
21     int isnum;
22
23     /* easy comparison to see if versions are identical */
24     if (!strcmp(a, b)) return 0;
25
26     str1 = alloca(strlen(a) + 1);
27     str2 = alloca(strlen(b) + 1);
28
29     strcpy(str1, a);
30     strcpy(str2, b);
31
32     one = str1;
33     two = str2;
34
35     /* loop through each version segment of str1 and str2 and compare them */
36     /*@-branchstate@*/
37 /*@-boundsread@*/
38     while (*one && *two) {
39         while (*one && !xisalnum(*one)) one++;
40         while (*two && !xisalnum(*two)) two++;
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 (xisdigit(*str1)) {
49             while (*str1 && xisdigit(*str1)) str1++;
50             while (*str2 && xisdigit(*str2)) str2++;
51             isnum = 1;
52         } else {
53             while (*str1 && xisalpha(*str1)) str1++;
54             while (*str2 && xisalpha(*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 /*@-boundswrite@*/
61         oldch1 = *str1;
62         *str1 = '\0';
63         oldch2 = *str2;
64         *str2 = '\0';
65 /*@=boundswrite@*/
66
67         /* take care of the case where the two version segments are */
68         /* different types: one numeric, the other alpha (i.e. empty) */
69         if (one == str1) return -1;     /* arbitrary */
70         /* XXX See patch #60884 (and details) from bugzilla #50977. */
71         if (two == str2) return (isnum ? 1 : -1);
72
73         if (isnum) {
74             /* this used to be done by converting the digit segments */
75             /* to ints using atoi() - it's changed because long  */
76             /* digit segments can overflow an int - this should fix that. */
77
78             /* throw away any leading zeros - it's a number, right? */
79             while (*one == '0') one++;
80             while (*two == '0') two++;
81
82             /* whichever number has more digits wins */
83             if (strlen(one) > strlen(two)) return 1;
84             if (strlen(two) > strlen(one)) return -1;
85         }
86
87         /* strcmp will return which one is greater - even if the two */
88         /* segments are alpha or if they are numeric.  don't return  */
89         /* if they are equal because there might be more segments to */
90         /* compare */
91         rc = strcmp(one, two);
92         if (rc) return rc;
93
94         /* restore character that was replaced by null above */
95 /*@-boundswrite@*/
96         *str1 = oldch1;
97         one = str1;
98         *str2 = oldch2;
99         two = str2;
100 /*@=boundswrite@*/
101     }
102     /*@=branchstate@*/
103 /*@=boundsread@*/
104
105     /* this catches the case where all numeric and alpha segments have */
106     /* compared identically but the segment sepparating characters were */
107     /* different */
108 /*@-boundsread@*/
109     if ((!*one) && (!*two)) return 0;
110
111     /* whichever version still has characters left over wins */
112     if (!*one) return -1; else return 1;
113 /*@=boundsread@*/
114 }