]> cygwin.com Git - cygwin-apps/setup.git/blob - csu_util/version_compare.cc
2004-12-26 Max Bowsher <maxb@ukf.net>
[cygwin-apps/setup.git] / csu_util / version_compare.cc
1 /*
2 * Copyright (c) 2004 Max Bowsher
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Max Bowsher
13 */
14
15 #include "version_compare.h"
16
17 using namespace std;
18
19 static inline bool isdigit(char c) { return (c >= '0' && c <= '9'); }
20
21 /* Sort two version numbers, comparing equivalently seperated strings of
22 * digits numerically.
23 *
24 * Returns a positive number if (a > b)
25 * Returns a negative number if (a < b)
26 * Returns zero if (a == b)
27 *
28 * Inspired but not equivalent to rpmvercmp().
29 */
30 int version_compare (string a, string b)
31 {
32 if (a == b) return 0;
33
34 size_t apos1, apos2 = 0, bpos1, bpos2 = 0;
35 size_t alen = a.length(), blen = b.length();
36 bool isnum;
37 int cval;
38
39 while (apos2 < alen && bpos2 < blen)
40 {
41 apos1 = apos2;
42 bpos1 = bpos2;
43
44 if (isdigit(a[apos2]))
45 {
46 while (apos2 < alen && isdigit(a[apos2])) apos2++;
47 while (bpos2 < blen && isdigit(b[bpos2])) bpos2++;
48 isnum = true;
49 }
50 else
51 {
52 while (apos2 < alen && !isdigit(a[apos2])) apos2++;
53 while (bpos2 < blen && !isdigit(b[bpos2])) bpos2++;
54 isnum = false;
55 }
56
57 /* if (apos1 == apos2) { a logical impossibility has happened; } */
58
59 /* isdigit(a[0]) != isdigit(b[0])
60 * arbitrarily sort the non-digit first */
61 if (bpos1 == bpos2) return (isnum ? 1 : -1);
62
63 if (isnum)
64 {
65 /* skip numeric leading zeros */
66 while (apos1 < alen && a[apos1] == '0') apos1++;
67 while (bpos1 < blen && b[bpos1] == '0') bpos1++;
68
69 /* if one number has more digits, it is greater */
70 if (apos2-apos1 > bpos2-bpos1) return 1;
71 if (apos2-apos1 < bpos2-bpos1) return -1;
72 }
73
74 /* do an ordinary lexicographic string comparison */
75 cval = a.compare(apos1, apos2-apos1, b, bpos1, bpos2-bpos1);
76 if (cval) return (cval < 1 ? -1 : 1);
77 }
78
79 /* ran out of characters in one string, without finding a difference */
80
81 /* maybe they were the same version, but with different leading zeros */
82 if (apos2 == alen && bpos2 == blen) return 0;
83
84 /* the version with a suffix remaining is greater */
85 return (apos2 < alen ? 1 : -1);
86 }
87
88 #ifdef TESTING_VERSION_COMPARE
89
90 #include <iostream>
91 #include <iomanip>
92 using namespace std;
93
94 struct version_pair
95 {
96 const char *a;
97 const char *b;
98 };
99
100 static version_pair test_data[] =
101 {
102 { "1.0.0", "2.0.0" },
103 { ".0.0", "2.0.0" },
104 { "alpha", "beta" },
105 { "1.0", "1.0.0" },
106 { "2.456", "2.1000" },
107 { "2.1000", "3.111" },
108 { "2.001", "2.1" },
109 { "2.34", "2.34" },
110 { NULL, NULL }
111 };
112
113 int main(int argc, char* argv[])
114 {
115 version_pair *i = test_data;
116
117 while (i->a)
118 {
119 cout << setw(10) << i->a << ", " << setw(10) << i->b << " : "
120 << version_compare(i->a, i->b) << ", " << version_compare(i->b, i->a)
121 << endl;
122 i++;
123 }
124
125 return 0;
126 }
127
128 #endif
This page took 0.040875 seconds and 5 git commands to generate.