OSDN Git Service

Ignore spin wait requests with no designated referrer.
[mingw/mingw-get.git] / src / pkgspec.cpp
1 /*
2  * pkgspec.cpp
3  *
4  * $Id$
5  *
6  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7  * Copyright (C) 2009, 2010, 2011, MinGW Project
8  *
9  *
10  * Implementation for the "pkgTarName" class, as declared in header
11  * file "pkginfo.h".
12  *
13  *
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.
19  *
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.
26  *
27  */
28 #include "dmh.h"
29 #include "debug.h"
30
31 #include "pkginfo.h"
32 #include "pkgkeys.h"
33 #include "vercmp.h"
34
35 #include <string.h>
36
37 /* Constructors...
38  */
39 pkgSpecs::pkgSpecs( const char *tarname )
40 {
41   /* Parse the given tarball name, storing its constituent element
42    * decomposition within the class' local "pkginfo" array structure.
43    */
44   content = get_pkginfo( tarname ? tarname : "", specs );
45 }
46
47 pkgSpecs::pkgSpecs( pkgXmlNode *release )
48 {
49   /* Retrieve the "tarname" from an XML "release" specification,
50    * then construct the "pkgSpecs" as if it were specified directly.
51    */
52   const char *tarname = release ? release->GetPropVal( tarname_key, NULL ) : NULL;
53   content = get_pkginfo( tarname ? tarname : "", specs );
54 }
55
56 /* Copy constructor...
57  */
58 static
59 void *clone_specs( char *content, pkginfo_t const src, pkginfo_t dst )
60 {
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.
65    */
66   char *rtn;
67   int count = PACKAGE_TAG_COUNT;
68
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...
71    */
72   while( (count > 0) && (src[--count] == NULL) )
73     ;
74
75   /* ...whence we may compute the size of the buffer, and allocate
76    * a new buffer, into which to copy the data.
77    */
78   count = src[count] + strlen( src[count] ) - content;
79   if( (rtn = (char *)(malloc( count + 1))) != NULL )
80   {
81     /* On successful buffer allocation, copy the data,
82      * then walk the list of pointers...
83      */
84     rtn = (char *)(memcpy( rtn, content, count ));
85     for( count = 0; count < PACKAGE_TAG_COUNT; ++count )
86     {
87       if( src[count] == NULL )
88         /*
89          * ...propagating NULL pointers "as are"...
90          */
91         dst[count] = NULL;
92
93       else
94         /* ...and non-NULL adjusted, as necessary,
95          * to point into the copied data buffer...
96          */
97         dst[count] = (char *)(rtn) + (src[count] - content);
98     }
99   }
100   /* ...ultimately, returning the base address of the new buffer.
101    */
102   return (void *)(rtn);
103 }
104 /* Formal implementation of the copy constructor...
105  */
106 pkgSpecs::pkgSpecs( const pkgSpecs& src )
107 {
108   /* ...requires no more than a call to the local helper function.
109    */
110   content = clone_specs( (char *)(src.content), src.specs, specs );
111 }
112
113 /* Assignment operator...
114  */
115 pkgSpecs& pkgSpecs::operator=( const pkgSpecs& rhs )
116 {
117   /* Provided the lhs and rhs represent distinct objects...
118    */
119   if( this != &rhs )
120   {
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.
126      */
127     free( content );
128     content = clone_specs( (char *)(rhs.content), rhs.specs, specs );
129   }
130   return *this;
131 }
132
133 /* Destructor...
134  */
135 pkgSpecs::~pkgSpecs()
136 {
137   /* Need to free the dynamic memory associated with the "specs" array,
138    * and in which the actual tarname decomposition is stored.
139    */
140   free( content );
141 }
142
143 /* Comparison operators...
144  */
145 static inline bool
146 is_wildcard_spec( const char *version_number, const char *build_number )
147 {
148   /* Local helper to identify wildcard version specifications, so
149    * we may match them to anything within the version comparator.
150    */
151   register int result = false;
152   register const char *wildcard = build_number;
153   if( wildcard == NULL ) wildcard = version_number;
154   if( wildcard != NULL )
155     while( *wildcard )
156       result = (*wildcard++ == '*');
157   return result;
158 }
159
160 int pkgSpecs::VersionComparator( pkgSpecs& rhs )
161 {
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.
172    */
173   const char *lhs_version_spec = GetPackageVersion();
174   const char *lhs_build_spec = GetPackageBuild();
175
176   const char *rhs_version_spec = rhs.GetPackageVersion();
177   const char *rhs_build_spec = rhs.GetPackageBuild();
178
179   /* Initially, we compare just the package version itself...
180    */
181   pkgVersionInfo lhs_version( lhs_version_spec, lhs_build_spec );
182   pkgVersionInfo rhs_version( rhs_version_spec, rhs_build_spec );
183
184   /* ...returning immediately with an appropriate return value,
185    * if LHS and RHS versions are distinct.
186    */
187   if( lhs_version < rhs_version ) return -1;
188   if( lhs_version > rhs_version ) return +1;
189
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...
196    */
197   if( ! is_wildcard_spec( lhs_version_spec, lhs_build_spec )
198   &&  ! is_wildcard_spec( rhs_version_spec, rhs_build_spec )  )
199   {
200     /* ...we progress this only when there is no wildcard
201      * specification in effect.
202      */
203     const char *lhs_quality, *rhs_quality;
204     if( (lhs_quality = GetReleaseStatus()) != NULL )
205     {
206       /* The LHS entity is qualified as "alpha", "beta", ...
207        */
208       if( (rhs_quality = rhs.GetReleaseStatus()) == NULL )
209       {
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.
216          */
217         return -1;
218       }
219
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).
226        */
227       int chkval = *lhs_quality - *rhs_quality;
228       if( chkval != 0 ) return chkval;
229
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...
234        */
235       lhs_version.Reset( GetReleaseIndex() );
236       rhs_version.Reset( rhs.GetReleaseIndex() );
237       /*
238        * ...noting that these progress in the same manner as
239        * the package version number itself.
240        */
241       if( lhs_version < rhs_version ) return -1;
242       if( lhs_version > rhs_version ) return +1;
243     }
244
245     else if( rhs.GetReleaseStatus() != NULL )
246     {
247       /*
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.
255        */
256       return +1;
257     }
258   }
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...
264    */
265   lhs_version.Reset( GetSubSystemVersion(), GetSubSystemBuild() );
266   rhs_version.Reset( rhs.GetSubSystemVersion(), rhs.GetSubSystemBuild() );
267   /*
268    * ...so we may compare these, just as we did initially
269    * for the package version identification.
270    */
271   if( lhs_version < rhs_version ) return -1;
272   if( lhs_version > rhs_version ) return +1;
273
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.
278    */
279   return 0;
280 }
281
282 bool pkgSpecs::operator<( pkgSpecs& rhs )
283 {
284   /* Check if the given package release is less recent, as indicated
285    * by its version and build date/serial number, than another.
286    */
287   return VersionComparator( rhs ) < 0;
288 }
289
290 bool pkgSpecs::operator<=( pkgSpecs& rhs )
291 {
292   /* Check if the given package release is no more recent, as indicated
293    * by its version and build date/serial number, than another.
294    */
295   return VersionComparator( rhs ) <= 0;
296 }
297
298 bool pkgSpecs::operator>=( pkgSpecs& rhs )
299 {
300   /* Check if the given package release is no less recent, as indicated
301    * by its version and build date/serial number, than another.
302    */
303   return VersionComparator( rhs ) >= 0;
304 }
305
306 bool pkgSpecs::operator>( pkgSpecs& rhs )
307 {
308   /* Check if the given package release is more recent, as indicated
309    * by its version and build date/serial number, than another.
310    */
311   return VersionComparator( rhs ) > 0;
312 }
313
314 /* $RCSfile$: end of file */