Changeset 25005 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Nov 26, 2009 2:42:59 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 55314
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/string/strversion.cpp
r24894 r25005 37 37 38 38 #include <iprt/assert.h> 39 #include <iprt/ctype.h> 39 40 #include <iprt/err.h> 40 #include <iprt/mem.h>41 41 42 42 43 43 /******************************************************************************* 44 * Defined Constants 44 * Defined Constants And Macros * 45 45 *******************************************************************************/ 46 #define ISDIGIT(c) ((c) >= '0' && (c) <= '9') 46 #define RTSTRVER_IS_PUNCTUACTION(ch) \ 47 ( (ch) == '_' || (ch) == '-' || (ch) == '+' || RT_C_IS_PUNCT(ch) ) 47 48 48 49 49 /******************************************************************************* 50 * Internal Functions * 51 *******************************************************************************/ 52 static uint16_t RTStrVersionGetBlockCount(const char *pszVer) 50 /** 51 * Parses a out the next block from a version string. 52 * 53 * @returns true if numeric, false if not. 54 * @param ppszVer The string cursor, IN/OUT. 55 * @param pu32Value Where to return the value if numeric. 56 * @param pcchBlock Where to return the block length. 57 */ 58 static bool rtStrVersionParseBlock(const char **ppszVer, uint32_t *pu32Value, size_t *pcchBlock) 53 59 { 54 uint16_t l = 0; 55 const char *pszCur = pszVer; 56 while (pszCur = RTStrStr(pszCur, ".")) 60 const char *psz = *ppszVer; 61 62 /* Check for end-of-string. */ 63 if (!*psz) 57 64 { 58 if (pszCur == NULL) 59 break; 60 l++; 61 pszCur++; 65 *pu32Value = 0; 66 *pcchBlock = 0; 67 return false; 62 68 } 63 /* Adjust block count to also count in the very first block */ 64 if (*pszVer != '\0') 65 l++; 66 return l; 69 70 bool fNumeric = RT_C_IS_DIGIT(*psz); 71 if (fNumeric) 72 { 73 do 74 psz++; 75 while (*psz && RT_C_IS_DIGIT(*psz)); 76 77 char *pszNext; 78 int rc = RTStrToUInt32Ex(*ppszVer, &pszNext, 10, pu32Value); 79 AssertRC(rc); 80 Assert(pszNext == psz); 81 if (RT_FAILURE(rc) || rc == VWRN_NUMBER_TOO_BIG) 82 { 83 fNumeric = false; 84 *pu32Value = 0; 85 } 86 } 87 else 88 { 89 do 90 psz++; 91 while (*psz && !RT_C_IS_DIGIT(*psz) && !RTSTRVER_IS_PUNCTUACTION(*psz)); 92 *pu32Value = 0; 93 } 94 *pcchBlock = psz - *ppszVer; 95 96 /* skip punctuation */ 97 if (RTSTRVER_IS_PUNCTUACTION(*psz)) 98 psz++; 99 *ppszVer = psz; 100 101 return fNumeric; 67 102 } 68 103 69 104 70 static int RTStrVersionGetUInt32(const char *pszVer, uint16_t u16Block, uint32_t *pu32) 71 { 72 /* First make a copy of the version string so that we can modify it */ 73 char *pszString; 74 int rc = RTStrDupEx(&pszString, pszVer); 75 if (RT_FAILURE(rc)) 76 return rc; 77 78 /* Go to the beginning of the block we want to parse */ 79 char *pszCur = pszString; 80 for (uint16_t i = 0; i < u16Block; i++) 81 { 82 pszCur = RTStrStr(pszCur, "."); 83 if (pszCur == NULL) 84 break; 85 if (*pszCur != '\0') 86 pszCur++; 87 } 88 89 if (pszCur != NULL && *pszCur != '\0') 90 { 91 /* Skip trailing non-digits at the start of the block */ 92 while (pszCur && *pszCur != '\0') 93 { 94 if (ISDIGIT(*pszCur)) 95 break; 96 pszCur++; 97 } 98 99 /* Mark ending of the block */ 100 char *pszEnd = RTStrStr(pszCur, "."); 101 if (NULL != pszEnd) 102 *pszEnd = '\0'; 103 104 /* Convert to number */ 105 rc = RTStrToUInt32Ex(pszCur, NULL /* ppszNext */, 10 /* Base */, pu32); 106 /* Skip trailing warnings */ 107 if ( rc == VWRN_TRAILING_CHARS 108 || rc == VWRN_TRAILING_SPACES) 109 rc = VINF_SUCCESS; 110 } 111 else 112 rc = VERR_NOT_FOUND; 113 114 RTStrFree(pszString); 115 return rc; 116 } 117 118 119 /** 120 * Compares two version strings and returns the result. The version string has 121 * to be made of at least one number section, each section delimited by a ".", 122 * e.g. "123.45.67". Trailing zeros at the beginning and non-digits in a section 123 * will be skipped, so "12.foo006" becomes "12.6". 124 * 125 * @returns iprt status code. 126 * Warnings are used to indicate convertion problems. 127 * @retval VWRN_NUMBER_TOO_BIG 128 * @retval VWRN_TRAILING_CHARS 129 * @retval VWRN_TRAILING_SPACES 130 * @retval VINF_SUCCESS 131 * @retval VERR_NO_MEMORY 132 * @retval VERR_NO_DIGITS 133 * 134 * @param pszVer1 First version string to compare. 135 * @param pszVer2 First version string to compare. 136 * @param pui8Res Pointer uint8_t value where to store the comparison result: 137 * 0 if equal, 1 if pszVer1 is greater, 2 if pszVer2 is greater. 138 */ 139 int RTStrVersionCompare(const char *pszVer1, const char *pszVer2, uint8_t *pui8Res) 105 RTDECL(int) RTStrVersionCompare(const char *pszVer1, const char *pszVer2) 140 106 { 141 107 AssertPtr(pszVer1); 142 108 AssertPtr(pszVer2); 143 109 144 uint16_t len1 = RTStrVersionGetBlockCount(pszVer1); 145 uint16_t len2 = RTStrVersionGetBlockCount(pszVer2); 110 /* 111 * Do a parallel parse of the strings. 112 */ 113 int iRes = 0; 114 while (*pszVer1 || *pszVer2) 115 { 116 const char *pszBlock1 = pszVer1; 117 size_t cchBlock1; 118 uint32_t uVal1; 119 bool fNumeric1 = rtStrVersionParseBlock(&pszVer1, &uVal1, &cchBlock1); 146 120 147 int rc = 0; 148 if (len1 > 0 && len2 > 0) 149 { 150 /* Figure out which version string is longer and set the corresponding 151 * pointers */ 152 uint16_t range; 153 uint16_t padding; 154 const char *pszShorter, *pszLonger; 155 if (len1 >= len2) 121 const char *pszBlock2 = pszVer2; 122 size_t cchBlock2; 123 uint32_t uVal2; 124 bool fNumeric2 = rtStrVersionParseBlock(&pszVer2, &uVal2, &cchBlock2); 125 126 if (fNumeric1 && fNumeric2) 156 127 { 157 range = len1; 158 padding = len1 - len2; 159 pszLonger = pszVer1; 160 pszShorter = pszVer2; 128 if (uVal1 != uVal2) 129 { 130 iRes = uVal1 > uVal2 ? 1 : 2; 131 break; 132 } 161 133 } 162 else if (len2 > len1) 134 else if ( !fNumeric1 && fNumeric2 && uVal2 == 0 && cchBlock1 == 0 135 || !fNumeric2 && fNumeric1 && uVal1 == 0 && cchBlock2 == 0 136 ) 163 137 { 164 range = len2; 165 padding = len2 - len1; 166 pszLonger = pszVer2; 167 pszShorter = pszVer1; 138 /* 1.0 == 1.0.0.0.0. */; 168 139 } 169 170 /* Now process each section (delimited by a ".") */ 171 AssertPtr(pszShorter); 172 AssertPtr(pszLonger); 173 AssertPtr(pui8Res); 174 *pui8Res = 0; 175 uint32_t val1, val2; 176 for (uint16_t i = 0; i < range 177 && *pui8Res == 0 178 && RT_SUCCESS(rc) 179 ; i++) 140 else 180 141 { 181 rc = RTStrVersionGetUInt32(pszLonger, i, &val1); 182 if (RT_SUCCESS(rc)) 142 int iDiff = RTStrNICmp(pszBlock1, pszBlock2, RT_MIN(cchBlock1, cchBlock2)); 143 if (!iDiff && cchBlock1 != cchBlock2) 144 iDiff = cchBlock1 < cchBlock2 ? -1 : 1; 145 if (iDiff) 183 146 { 184 if (i >= range - padding) 185 { 186 /* If we're in the padding range, there are no numbers left 187 * to compare with anymore, so just assume "0" then */ 188 val2 = 0; 189 } 190 else 191 { 192 rc = RTStrVersionGetUInt32(pszShorter, i, &val2); 193 } 194 } 195 196 if (RT_SUCCESS(rc)) 197 { 198 if (val1 > val2) 199 { 200 *pui8Res = (pszLonger == pszVer1) ? 1 : 2; 201 break; 202 } 203 else if (val2 > val1) 204 { 205 *pui8Res = (pszShorter == pszVer1) ? 1 : 2; 206 break; 207 } 147 iRes = iDiff > 0 ? 1 : 2; 148 break; 208 149 } 209 150 } 210 151 } 211 else 212 { 213 rc = VERR_NO_DIGITS; 214 } 215 216 if (RT_FAILURE(rc)) 217 *pui8Res = 0; /* Zero out value */ 218 return rc; 152 return iRes; 219 153 } 220 154 RT_EXPORT_SYMBOL(RTStrVersionCompare);
Note:
See TracChangeset
for help on using the changeset viewer.