6 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7 * Copyright (C) 2009, 2010, 2011, MinGW Project
10 * Implementation for the "pkgTarName" class, as declared in header
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.
39 pkgSpecs::pkgSpecs( const char *tarname )
41 /* Parse the given tarball name, storing its constituent element
42 * decomposition within the class' local "pkginfo" array structure.
44 content = get_pkginfo( tarname ? tarname : "", specs );
47 pkgSpecs::pkgSpecs( pkgXmlNode *release )
49 /* Retrieve the "tarname" from an XML "release" specification,
50 * then construct the "pkgSpecs" as if it were specified directly.
52 const char *tarname = release ? release->GetPropVal( tarname_key, NULL ) : NULL;
53 content = get_pkginfo( tarname ? tarname : "", specs );
56 /* Copy constructor...
59 void *clone_specs( char *content, pkginfo_t const src, pkginfo_t dst )
61 /* Local helper function performs a deep copy of the "content" buffer,
62 * and assigns the "specs" pointers to refer to it; this is the action
63 * required to implement the copy constructor, and it is also used by
64 * the assignment operator implentation.
67 int count = PACKAGE_TAG_COUNT;
69 /* Find the last allocated pointer in the source "specs" list; this
70 * tells us where to find the last string in the "content" buffer...
72 while( (count > 0) && (src[--count] == NULL) )
75 /* ...whence we may compute the size of the buffer, and allocate
76 * a new buffer, into which to copy the data.
78 count = src[count] + strlen( src[count] ) - content;
79 if( (rtn = (char *)(malloc( count + 1))) != NULL )
81 /* On successful buffer allocation, copy the data,
82 * then walk the list of pointers...
84 rtn = (char *)(memcpy( rtn, content, count ));
85 for( count = 0; count < PACKAGE_TAG_COUNT; ++count )
87 if( src[count] == NULL )
89 * ...propagating NULL pointers "as are"...
94 /* ...and non-NULL adjusted, as necessary,
95 * to point into the copied data buffer...
97 dst[count] = (char *)(rtn) + (src[count] - content);
100 /* ...ultimately, returning the base address of the new buffer.
102 return (void *)(rtn);
104 /* Formal implementation of the copy constructor...
106 pkgSpecs::pkgSpecs( const pkgSpecs& src )
108 /* ...requires no more than a call to the local helper function.
110 content = clone_specs( (char *)(src.content), src.specs, specs );
113 /* Assignment operator...
115 pkgSpecs& pkgSpecs::operator=( const pkgSpecs& rhs )
117 /* Provided the lhs and rhs represent distinct objects...
121 /* ...this is much the same as the copy constructor, except that,
122 * while the constructor is guaranteed to be creating a new object,
123 * assignment may be replacing an existing lhs object; this will
124 * own a dynamically allocated data buffer, which must be freed,
125 * to avoid leaking memory.
128 content = clone_specs( (char *)(rhs.content), rhs.specs, specs );
135 pkgSpecs::~pkgSpecs()
137 /* Need to free the dynamic memory associated with the "specs" array,
138 * and in which the actual tarname decomposition is stored.
143 /* Comparison operators...
146 is_wildcard_spec( const char *version_number, const char *build_number )
148 /* Local helper to identify wildcard version specifications, so
149 * we may match them to anything within the version comparator.
151 register int result = false;
152 register const char *wildcard = build_number;
153 if( wildcard == NULL ) wildcard = version_number;
154 if( wildcard != NULL )
156 result = (*wildcard++ == '*');
160 int pkgSpecs::VersionComparator( pkgSpecs& rhs )
162 /* Private helper method, used to facilitate implementation
163 * of the comparison operator methods. It considers the "this"
164 * pointer as a reference to the entity on the left hand side of
165 * the comparison operator, and the single argument as a reference
166 * to the entity on the right hand side. The integer return value
167 * is zero if the two entities compare as equal, (i.e. representing
168 * identically the same package version), less than zero if the LHS
169 * entity represents a "lesser" (i.e. an earlier) version than the
170 * RHS, or greater than zero if the LHS represents a "greater"
171 * (i.e. a more recent) version than the RHS.
173 const char *lhs_version_spec = GetPackageVersion();
174 const char *lhs_build_spec = GetPackageBuild();
176 const char *rhs_version_spec = rhs.GetPackageVersion();
177 const char *rhs_build_spec = rhs.GetPackageBuild();
179 /* Initially, we compare just the package version itself...
181 pkgVersionInfo lhs_version( lhs_version_spec, lhs_build_spec );
182 pkgVersionInfo rhs_version( rhs_version_spec, rhs_build_spec );
184 /* ...returning immediately with an appropriate return value,
185 * if LHS and RHS versions are distinct.
187 if( lhs_version < rhs_version ) return -1;
188 if( lhs_version > rhs_version ) return +1;
190 /* If we get to here, then the package versions of LHS and RHS
191 * are effectively matched; however, unless there is a wildcard
192 * specification in effect, (in which case we have an automatic
193 * match), we may still be able to differentiate between them,
194 * by comparing their respective development (release) status
195 * qualifiers; thus...
197 if( ! is_wildcard_spec( lhs_version_spec, lhs_build_spec )
198 && ! is_wildcard_spec( rhs_version_spec, rhs_build_spec ) )
200 /* ...we progress this only when there is no wildcard
201 * specification in effect.
203 const char *lhs_quality, *rhs_quality;
204 if( (lhs_quality = GetReleaseStatus()) != NULL )
206 /* The LHS entity is qualified as "alpha", "beta", ...
208 if( (rhs_quality = rhs.GetReleaseStatus()) == NULL )
210 /* ...but the RHS entity is not; we always consider an
211 * unqualified version to implicitly represent "stable",
212 * which is always compared as "more recent" than any
213 * "alpha", "beta" or "rc" qualified release at the
214 * same package version point, so we may immediately
215 * confirm the LHS as the "lesser" release.
220 /* If we still haven't differentiated them, then both LHS
221 * and RHS must be qualified. Check if we can resolve the
222 * deadlock on the basis of progression of development from
223 * "alpha" through "beta" and "rc" to "stable" phases; (note
224 * that simply checking the initial character of the phase
225 * qualifier indicates the appropriate progression).
227 int chkval = *lhs_quality - *rhs_quality;
228 if( chkval != 0 ) return chkval;
230 /* If we still can't resolve the deadlock, then both LHS
231 * and LHS must be qualified as being in identically the
232 * same development phase, so we must now differentiate
233 * on the basis of progression of the release index...
235 lhs_version.Reset( GetReleaseIndex() );
236 rhs_version.Reset( rhs.GetReleaseIndex() );
238 * ...noting that these progress in the same manner as
239 * the package version number itself.
241 if( lhs_version < rhs_version ) return -1;
242 if( lhs_version > rhs_version ) return +1;
245 else if( rhs.GetReleaseStatus() != NULL )
248 * In this case, the RHS entity is qualified as "alpha",
249 * "beta", ..., but the LHS is not. Since we've already
250 * determined that both represent the same version of the
251 * package, we may infer that the LHS represents a stable
252 * derivative of the qualified RHS, and thus corresponds
253 * to a more recent release, so return the appropriate
254 * value to indicate LHS > RHS.
259 /* If we get to here, then LHS and RHS represent the same
260 * version of the package, at the same phase of development;
261 * the only remaining determinant, which may differentiate
262 * them, is that one has been released for a more recent
263 * version of the host subsystem...
265 lhs_version.Reset( GetSubSystemVersion(), GetSubSystemBuild() );
266 rhs_version.Reset( rhs.GetSubSystemVersion(), rhs.GetSubSystemBuild() );
268 * ...so we may compare these, just as we did initially
269 * for the package version identification.
271 if( lhs_version < rhs_version ) return -1;
272 if( lhs_version > rhs_version ) return +1;
274 /* Finally, if we get past all of the preceding comparisons,
275 * then the LHS and RHS cannot be differentiated on the basis
276 * of any package version comparison, so we may return zero
277 * to assert their equality.
282 bool pkgSpecs::operator<( pkgSpecs& rhs )
284 /* Check if the given package release is less recent, as indicated
285 * by its version and build date/serial number, than another.
287 return VersionComparator( rhs ) < 0;
290 bool pkgSpecs::operator<=( pkgSpecs& rhs )
292 /* Check if the given package release is no more recent, as indicated
293 * by its version and build date/serial number, than another.
295 return VersionComparator( rhs ) <= 0;
298 bool pkgSpecs::operator>=( pkgSpecs& rhs )
300 /* Check if the given package release is no less recent, as indicated
301 * by its version and build date/serial number, than another.
303 return VersionComparator( rhs ) >= 0;
306 bool pkgSpecs::operator>( pkgSpecs& rhs )
308 /* Check if the given package release is more recent, as indicated
309 * by its version and build date/serial number, than another.
311 return VersionComparator( rhs ) > 0;
314 /* $RCSfile$: end of file */