7 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
8 * Copyright (C) 2009, 2010, 2011, MinGW Project
11 * Implementation of package version comparator module.
14 * This is free software. Permission is granted to copy, modify and
15 * redistribute this software, under the provisions of the GNU General
16 * Public License, Version 3, (or, at your option, any later version),
17 * as published by the Free Software Foundation; see the file COPYING
18 * for licensing details.
20 * Note, in particular, that this software is provided "as is", in the
21 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
22 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
23 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
24 * MinGW Project, accept liability for any damages, however caused,
25 * arising from the use of this software.
31 void pkgVersionInfo::Parse( const char* version, const char* build )
33 /* Delegated constructor/reconstructor implementation...
34 * Decompose given version number and build serial number strings,
35 * storing components within the specified class structure.
37 * Note that the strings to be parsed are invariant, (and it is
38 * necessary that they be so), but we need to create modifiable
39 * copies to facilitate decomposition...
41 char *wildcard = build_string = NULL;
42 char *p = version_string = strdup( version ? version : "" );
44 /* Walking over all version number constituent elements...
46 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
48 /* ...initialise default element value to zero.
50 unsigned long value = 0L;
52 /* When appropriate...
54 if( (index == SNAPSHOT_DATE) && (*p == '\0') && (build != NULL) )
56 * ...select second argument for parsing.
58 p = build_string = strdup( build );
60 /* When parsing an explicitly specified numeric argument...
62 while( (*p >= '0') && ((*p - '0') < 10) )
64 /* ...accumulate its ultimate value, and clear any prior
65 * "wildcard" matching request which may have been carried
66 * forward from the preceding field specification.
68 value = *p++ - '0' + 10 * value;
72 /* Store it, note the presence of any suffix, and establish
73 * the control state for a possible "wildcard" match.
75 version_elements[index].value = value;
76 version_elements[index].suffix = p;
77 if( (value == 0L) && (*p == '*') )
80 /* Skip forward to next element field delimiter, clearing any
81 * active "wildcard" matching request, if the "suffix" doesn't
82 * represent a pure "wildcard" designator.
84 while( *p && (*p != '.') && (*p != '-') )
85 if( *p++ != '*' ) wildcard = NULL;
87 /* Evaluate the current field delimiter, to identify the type
88 * of the following field (if any)...
90 if( (*p == '-') || ((*p == '\0') && (build != NULL)) )
92 * ...and, if we hit the end of the version number,
93 * before we filled out all of its possible elements,
94 * then zero the remainder, (while preserving "wildcard"
95 * matching state), before we progress to capture the
96 * build serial number.
98 while( index < VERSION_PATCHLEVEL )
100 version_elements[++index].value = 0L;
101 version_elements[index].suffix = wildcard ? wildcard : p;
104 /* If "wildcard" matching is in the active state, by the time
105 * we get to here, then it may have been activated for this field,
106 * or it may have been passed forward from a preceding field...
110 * ...we don't know which applies, so we unconditionally adjust
111 * the "suffix" pointer, to ensure that the state is recorded.
113 version_elements[index].suffix = wildcard;
115 /* Step over any delimiter, which demarcates the current
116 * version number or build serial number element field, while
117 * ensuring that the decomposed field is properly terminated.
119 if( *p ) *p++ = '\0';
123 long pkgVersionInfo::Compare( const pkgVersionInfo& rhs, int index )
125 /* Compare a given element of a package version specification with the
126 * corresponding element of a reference (rhs) version specification; return
127 * <0L, 0L or >0L for less than, equal to or greater than rhs respectively.
130 if( (cmpval = rhs.version_elements[index].value) == 0L )
132 /* In the special case where the reference value is zero...
134 const char *p = rhs.version_elements[index].suffix;
135 if( (p != NULL) && (p[0] == '*') && (p[1] == '\0') )
137 /* ...and where it has an explicit suffix which is identically
138 * equal to the string "*", then it represents a "wildcard" match,
139 * which unconditionally matches everything as "equal".
145 /* When we didn't match a "wildcard"...
146 * we fall through to here, and proceed with a normal comparison.
148 if( (cmpval = version_elements[index].value - cmpval) == 0L )
150 /* The specified element values are identically equal;
151 * discriminate on suffixes, if any...
153 const char *p = version_elements[index].suffix;
154 const char *r = rhs.version_elements[index].suffix;
156 /* Check that both version specifications include a suffix;
157 * ( p == r implies both are NULL, hence neither has a suffix );
158 * if only one has, then that is the greater...
160 if( p == r ) return 0L;
161 if( p == NULL ) return 1L;
162 if( r == NULL ) return -1L;
164 /* Both DO have suffixes...
166 while( *p && *r && (*p == *r) && (*p != '.') && (*p != '-') )
168 /* ...scan both, until we find a mismatched character,
169 * or the terminal delimiter for either.
174 /* Compute return value based on difference between the
175 * mismatched characters, representing delimiters as NUL.
177 cmpval = (*p && (*p != '.') && (*p != '-')) ? (long)(*p) : 0L;
178 cmpval -= (*r && (*r != '.') && (*r != '-')) ? (long)(*r) : 0L;
183 bool pkgVersionInfo::operator<( const pkgVersionInfo& rhs )
185 /* Comparison operator...
186 * Does the version number under consideration represent a less
187 * recent release than the specified reference version number.
190 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
191 if( (cmp = Compare( rhs, index )) != 0L ) return (cmp < 0L);
193 /* If we get to here, lhs and rhs versions are identically equal,
194 * and hence fail the lhs < rhs comparison.
199 bool pkgVersionInfo::operator<=( const pkgVersionInfo& rhs )
201 /* Comparison operator...
202 * Does the version number under consideration represent the same, or
203 * a less recent release than the specified reference version number.
206 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
207 if( (cmp = Compare( rhs, index )) != 0L ) return (cmp < 0L);
209 /* If we get to here, lhs and rhs versions are identically equal,
210 * and hence satisfy the lhs <= rhs comparison.
215 bool pkgVersionInfo::operator==( const pkgVersionInfo& rhs )
217 /* Comparison operator...
218 * Does the version number under consideration exactly match
219 * the specified reference version number.
221 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
222 if( Compare( rhs, index ) != 0L ) return false;
224 /* If we get to here, lhs and rhs versions are identically equal,
225 * which is what we require to satisfy the lhs == rhs comparison.
230 bool pkgVersionInfo::operator!=( const pkgVersionInfo& rhs )
232 /* Comparison operator...
233 * Does the version number under consideration differ from
234 * the specified reference version number.
236 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
237 if( Compare( rhs, index ) != 0L ) return true;
239 /* If we get to here, lhs and rhs versions are identically equal,
240 * which is the sole condition to fail the lhs != rhs comparison.
245 bool pkgVersionInfo::operator>=( const pkgVersionInfo& rhs )
247 /* Comparison operator...
248 * Does the version number under consideration represent the same, or
249 * a more recent release than the specified reference version number.
252 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
253 if( (cmp = Compare( rhs, index )) != 0L ) return (cmp > 0L);
255 /* If we get to here, lhs and rhs versions are identically equal,
256 * and hence satisfy the lhs >= rhs comparison.
261 bool pkgVersionInfo::operator>( const pkgVersionInfo& rhs )
263 /* Comparison operator...
264 * Does the version number under consideration represent a more
265 * recent release than the specified reference version number.
268 for( int index = VERSION_MAJOR; index < VERSION_ELEMENT_COUNT; index++ )
269 if( (cmp = Compare( rhs, index )) != 0L ) return (cmp > 0L);
271 /* If we get to here, lhs and rhs versions are identically equal,
272 * and hence fail the lhs > rhs comparison.
277 /* $RCSfile$: end of file */