Back to index

lightning-sunbird  0.9+nobinonly
nsVersionComparator.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla XPCOM.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Benjamin Smedberg <benjamin@smedbergs.us>.
00018  *
00019  * Portions created by the Initial Developer are Copyright (C) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsVersionComparator.h"
00039 
00040 #include <stdlib.h>
00041 #include <string.h>
00042 
00043 struct VersionPart {
00044   PRInt32     numA;
00045 
00046   const char *strB;    // NOT null-terminated, can be a null pointer
00047   PRUint32    strBlen;
00048 
00049   PRInt32     numC;
00050 
00051   char       *extraD;  // null-terminated
00052 };
00053 
00059 static char*
00060 ParseVP(char *part, VersionPart &result)
00061 {
00062   char *dot;
00063 
00064   result.numA = 0;
00065   result.strB = nsnull;
00066   result.strBlen = 0;
00067   result.numC = 0;
00068   result.extraD = nsnull;
00069 
00070   if (!part)
00071     return part;
00072 
00073   dot = strchr(part, '.');
00074   if (dot)
00075     *dot = '\0';
00076 
00077   if (part[0] == '*' && part[1] == '\0') {
00078     result.numA = PR_INT32_MAX;
00079     result.strB = "";
00080   }
00081   else {
00082     result.numA = strtol(part, NS_CONST_CAST(char**, &result.strB), 10);
00083   }
00084 
00085   if (!*result.strB) {
00086     result.strB = nsnull;
00087     result.strBlen = 0;
00088   }
00089   else {
00090     if (result.strB[0] == '+') {
00091       static const char kPre[] = "pre";
00092 
00093       ++result.numA;
00094       result.strB = kPre;
00095       result.strBlen = sizeof(kPre) - 1;
00096     }
00097     else {
00098       const char *numstart = strpbrk(result.strB, "0123456789+-");
00099       if (!numstart) {
00100        result.strBlen = strlen(result.strB);
00101       }
00102       else {
00103        result.strBlen = numstart - result.strB;
00104 
00105        result.numC = strtol(numstart, &result.extraD, 10);
00106        if (!*result.extraD)
00107          result.extraD = nsnull;
00108       }
00109     }
00110   }
00111 
00112   if (dot) {
00113     ++dot;
00114 
00115     if (!*dot)
00116       dot = nsnull;
00117   }
00118 
00119   return dot;
00120 }
00121 
00122 // compare two null-terminated strings, which may be null pointers
00123 static PRInt32
00124 ns_strcmp(const char *str1, const char *str2)
00125 {
00126   // any string is *before* no string
00127   if (!str1)
00128     return str2 != 0;
00129 
00130   if (!str2)
00131     return -1;
00132 
00133   return strcmp(str1, str2);
00134 }
00135 
00136 // compare two length-specified string, which may be null pointers
00137 static PRInt32
00138 ns_strnncmp(const char *str1, PRUint32 len1, const char *str2, PRUint32 len2)
00139 {
00140   // any string is *before* no string
00141   if (!str1)
00142     return str2 != 0;
00143 
00144   if (!str2)
00145     return -1;
00146 
00147   for (; len1 && len2; --len1, --len2, ++str1, ++str2) {
00148     if (*str1 < *str2)
00149       return -1;
00150 
00151     if (*str1 > *str2)
00152       return 1;
00153   }
00154 
00155   if (len1 == 0)
00156     return len2 == 0 ? 0 : -1;
00157 
00158   return 1;
00159 }
00160 
00161 // compare two PRInt32
00162 static PRInt32
00163 ns_cmp(PRInt32 n1, PRInt32 n2)
00164 {
00165   if (n1 < n2)
00166     return -1;
00167 
00168   return n1 != n2;
00169 }
00170 
00174 static PRInt32
00175 CompareVP(VersionPart &v1, VersionPart &v2)
00176 {
00177   PRInt32 r = ns_cmp(v1.numA, v2.numA);
00178   if (r)
00179     return r;
00180 
00181   r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen);
00182   if (r)
00183     return r;
00184 
00185   r = ns_cmp(v1.numC, v2.numC);
00186   if (r)
00187     return r;
00188 
00189   return ns_strcmp(v1.extraD, v2.extraD);
00190 }
00191 
00192 PRInt32
00193 NS_CompareVersions(const char *A, const char *B)
00194 {
00195   char *A2 = strdup(A);
00196   if (!A2)
00197     return 1;
00198 
00199   char *B2 = strdup(B);
00200   if (!B2) {
00201     free(A2);
00202     return 1;
00203   }
00204 
00205   PRInt32 result;
00206   char *a = A2, *b = B2;
00207 
00208   do {
00209     VersionPart va, vb;
00210 
00211     a = ParseVP(a, va);
00212     b = ParseVP(b, vb);
00213 
00214     result = CompareVP(va, vb);
00215     if (result)
00216       break;
00217 
00218   } while (a || b);
00219 
00220   free(A2);
00221   free(B2);
00222 
00223   return result;
00224 }
00225