Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / xpcom / glue / nsVersionComparator.cpp
blob42a13bbd777c44cab453f5b315651aefc41d7e8e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is Mozilla XPCOM.
16 * The Initial Developer of the Original Code is
17 * Benjamin Smedberg <benjamin@smedbergs.us>.
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsVersionComparator.h"
40 #include <stdlib.h>
41 #include <string.h>
42 #ifdef XP_WIN
43 #include <wchar.h>
44 #include "nsStringGlue.h"
45 #endif
47 struct VersionPart {
48 PRInt32 numA;
50 const char *strB; // NOT null-terminated, can be a null pointer
51 PRUint32 strBlen;
53 PRInt32 numC;
55 char *extraD; // null-terminated
58 #ifdef XP_WIN
59 struct VersionPartW {
60 PRInt32 numA;
62 const PRUnichar *strB; // NOT null-terminated, can be a null pointer
63 PRUint32 strBlen;
65 PRInt32 numC;
67 PRUnichar *extraD; // null-terminated
70 #endif
72 /**
73 * Parse a version part into a number and "extra text".
75 * @returns A pointer to the next versionpart, or null if none.
77 static char*
78 ParseVP(char *part, VersionPart &result)
80 char *dot;
82 result.numA = 0;
83 result.strB = nsnull;
84 result.strBlen = 0;
85 result.numC = 0;
86 result.extraD = nsnull;
88 if (!part)
89 return part;
91 dot = strchr(part, '.');
92 if (dot)
93 *dot = '\0';
95 if (part[0] == '*' && part[1] == '\0') {
96 result.numA = PR_INT32_MAX;
97 result.strB = "";
99 else {
100 result.numA = strtol(part, const_cast<char**>(&result.strB), 10);
103 if (!*result.strB) {
104 result.strB = nsnull;
105 result.strBlen = 0;
107 else {
108 if (result.strB[0] == '+') {
109 static const char kPre[] = "pre";
111 ++result.numA;
112 result.strB = kPre;
113 result.strBlen = sizeof(kPre) - 1;
115 else {
116 const char *numstart = strpbrk(result.strB, "0123456789+-");
117 if (!numstart) {
118 result.strBlen = strlen(result.strB);
120 else {
121 result.strBlen = numstart - result.strB;
123 result.numC = strtol(numstart, &result.extraD, 10);
124 if (!*result.extraD)
125 result.extraD = nsnull;
130 if (dot) {
131 ++dot;
133 if (!*dot)
134 dot = nsnull;
137 return dot;
142 * Parse a version part into a number and "extra text".
144 * @returns A pointer to the next versionpart, or null if none.
146 #ifdef XP_WIN
147 static PRUnichar*
148 ParseVP(PRUnichar *part, VersionPartW &result)
151 PRUnichar *dot;
153 result.numA = 0;
154 result.strB = nsnull;
155 result.strBlen = 0;
156 result.numC = 0;
157 result.extraD = nsnull;
159 if (!part)
160 return part;
162 dot = wcschr(part, '.');
163 if (dot)
164 *dot = '\0';
166 if (part[0] == '*' && part[1] == '\0') {
167 result.numA = PR_INT32_MAX;
168 result.strB = L"";
170 else {
171 result.numA = wcstol(part, const_cast<PRUnichar**>(&result.strB), 10);
174 if (!*result.strB) {
175 result.strB = nsnull;
176 result.strBlen = 0;
178 else {
179 if (result.strB[0] == '+') {
180 static const PRUnichar kPre[] = L"pre";
182 ++result.numA;
183 result.strB = kPre;
184 result.strBlen = sizeof(kPre) - 1;
186 else {
187 const PRUnichar *numstart = wcspbrk(result.strB, L"0123456789+-");
188 if (!numstart) {
189 result.strBlen = wcslen(result.strB);
191 else {
192 result.strBlen = numstart - result.strB;
194 result.numC = wcstol(numstart, &result.extraD, 10);
195 if (!*result.extraD)
196 result.extraD = nsnull;
201 if (dot) {
202 ++dot;
204 if (!*dot)
205 dot = nsnull;
208 return dot;
210 #endif
212 // compare two null-terminated strings, which may be null pointers
213 static PRInt32
214 ns_strcmp(const char *str1, const char *str2)
216 // any string is *before* no string
217 if (!str1)
218 return str2 != 0;
220 if (!str2)
221 return -1;
223 return strcmp(str1, str2);
226 // compare two length-specified string, which may be null pointers
227 static PRInt32
228 ns_strnncmp(const char *str1, PRUint32 len1, const char *str2, PRUint32 len2)
230 // any string is *before* no string
231 if (!str1)
232 return str2 != 0;
234 if (!str2)
235 return -1;
237 for (; len1 && len2; --len1, --len2, ++str1, ++str2) {
238 if (*str1 < *str2)
239 return -1;
241 if (*str1 > *str2)
242 return 1;
245 if (len1 == 0)
246 return len2 == 0 ? 0 : -1;
248 return 1;
251 // compare two PRInt32
252 static PRInt32
253 ns_cmp(PRInt32 n1, PRInt32 n2)
255 if (n1 < n2)
256 return -1;
258 return n1 != n2;
262 * Compares two VersionParts
264 static PRInt32
265 CompareVP(VersionPart &v1, VersionPart &v2)
267 PRInt32 r = ns_cmp(v1.numA, v2.numA);
268 if (r)
269 return r;
271 r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen);
272 if (r)
273 return r;
275 r = ns_cmp(v1.numC, v2.numC);
276 if (r)
277 return r;
279 return ns_strcmp(v1.extraD, v2.extraD);
283 * Compares two VersionParts
285 #ifdef XP_WIN
286 static PRInt32
287 CompareVP(VersionPartW &v1, VersionPartW &v2)
289 PRInt32 r = ns_cmp(v1.numA, v2.numA);
290 if (r)
291 return r;
293 r = wcsncmp(v1.strB, v2.strB, PR_MIN(v1.strBlen,v2.strBlen));
294 if (r)
295 return r;
297 r = ns_cmp(v1.numC, v2.numC);
298 if (r)
299 return r;
301 return wcscmp(v1.extraD, v2.extraD);
305 PRInt32
306 NS_CompareVersions(const PRUnichar *A, const PRUnichar *B)
308 PRUnichar *A2 = wcsdup(A);
309 if (!A2)
310 return 1;
312 PRUnichar *B2 = wcsdup(B);
313 if (!B2) {
314 free(A2);
315 return 1;
318 PRInt32 result;
319 PRUnichar *a = A2, *b = B2;
321 do {
322 VersionPartW va, vb;
324 a = ParseVP(a, va);
325 b = ParseVP(b, vb);
327 result = CompareVP(va, vb);
328 if (result)
329 break;
331 } while (a || b);
333 free(A2);
334 free(B2);
336 return result;
338 #endif
340 PRInt32
341 NS_CompareVersions(const char *A, const char *B)
343 char *A2 = strdup(A);
344 if (!A2)
345 return 1;
347 char *B2 = strdup(B);
348 if (!B2) {
349 free(A2);
350 return 1;
353 PRInt32 result;
354 char *a = A2, *b = B2;
356 do {
357 VersionPart va, vb;
359 a = ParseVP(a, va);
360 b = ParseVP(b, vb);
362 result = CompareVP(va, vb);
363 if (result)
364 break;
366 } while (a || b);
368 free(A2);
369 free(B2);
371 return result;