VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strversion.cpp@ 24893

Last change on this file since 24893 was 24893, checked in by vboxsync, 15 years ago

IPRT: Improved RTStrVersionCompare() + testcase.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.9 KB
Line 
1/* $Id: strversion.cpp 24893 2009-11-24 12:09:03Z vboxsync $ */
2/** @file
3 * IPRT - Version String Parsing.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/string.h>
36#include "internal/iprt.h"
37
38#include <iprt/assert.h>
39#include <iprt/err.h>
40#include <iprt/mem.h>
41
42
43/*******************************************************************************
44* Defined Constants *
45*******************************************************************************/
46#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
47
48
49/*******************************************************************************
50* Internal Functions *
51*******************************************************************************/
52static uint16_t RTStrVersionGetBlockCount(const char *pszVer)
53{
54 uint16_t l = 0;
55 const char *pszCur = pszVer;
56 while (pszCur = RTStrStr(pszCur, "."))
57 {
58 if (pszCur == NULL)
59 break;
60 l++;
61 pszCur++;
62 }
63 /* Adjust block count to also count in the very first block */
64 if (*pszVer != '\0')
65 l++;
66 return l;
67}
68
69
70static 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 * @todo Deal with prefixes and suffixes!
135 * @param pszVer1 First version string to compare.
136 * @param pszVer2 First version string to compare.*
137 * @param pui8Res Pointer uint8_t value where to store the comparison result:
138 * 0 if equal, 1 if pszVer1 is greater, 2 if pszVer2 is greater.
139 */
140int RTStrVersionCompare(const char *pszVer1, const char *pszVer2, uint8_t *pui8Res)
141{
142 AssertPtr(pszVer1);
143 AssertPtr(pszVer2);
144
145 uint16_t len1 = RTStrVersionGetBlockCount(pszVer1);
146 uint16_t len2 = RTStrVersionGetBlockCount(pszVer2);
147
148 int rc = 0;
149 if (len1 > 0 && len2 > 0)
150 {
151 /* Figure out which version string is longer and set the corresponding
152 * pointers */
153 uint16_t range;
154 uint16_t padding;
155 const char *pszShorter, *pszLonger;
156 if (len1 >= len2)
157 {
158 range = len1;
159 padding = len1 - len2;
160 pszLonger = pszVer1;
161 pszShorter = pszVer2;
162 }
163 else if (len2 > len1)
164 {
165 range = len2;
166 padding = len2 - len1;
167 pszLonger = pszVer2;
168 pszShorter = pszVer1;
169 }
170
171 /* Now process each section (delimited by a ".") */
172 AssertPtr(pszShorter);
173 AssertPtr(pszLonger);
174 AssertPtr(pui8Res);
175 *pui8Res = 0;
176 uint32_t val1, val2;
177 for (uint16_t i = 0; i < range
178 && *pui8Res == 0
179 && RT_SUCCESS(rc)
180 ; i++)
181 {
182 rc = RTStrVersionGetUInt32(pszLonger, i, &val1);
183 if (RT_SUCCESS(rc))
184 {
185 if (i >= range - padding)
186 {
187 /* If we're in the padding range, there are no numbers left
188 * to compare with anymore, so just assume "0" then */
189 val2 = 0;
190 }
191 else
192 {
193 rc = RTStrVersionGetUInt32(pszShorter, i, &val2);
194 }
195 }
196
197 if (RT_SUCCESS(rc))
198 {
199 if (val1 > val2)
200 {
201 *pui8Res = (pszLonger == pszVer1) ? 1 : 2;
202 break;
203 }
204 else if (val2 > val1)
205 {
206 *pui8Res = (pszShorter == pszVer1) ? 1 : 2;
207 break;
208 }
209 }
210 }
211 }
212 else
213 {
214 rc = VERR_NO_DIGITS;
215 }
216
217 if (RT_FAILURE(rc))
218 *pui8Res = 0; /* Zero out value */
219 return rc;
220}
221RT_EXPORT_SYMBOL(RTStrVersionCompare);
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette