6 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7 * Copyright (C) 2009, 2010, 2011, MinGW Project
10 * Implementation for the non-inherited components of the pkgXmlNode
11 * class, as declared in file "pkgdesc.h"; fundamentally, these are
12 * the accessors for package "tarname" properties, as specified in
13 * XML nodes identified as "release" elements.
16 * This is free software. Permission is granted to copy, modify and
17 * redistribute this software, under the provisions of the GNU General
18 * Public License, Version 3, (or, at your option, any later version),
19 * as published by the Free Software Foundation; see the file COPYING
20 * for licensing details.
22 * Note, in particular, that this software is provided "as is", in the
23 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
24 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
25 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
26 * MinGW Project, accept liability for any damages, however caused,
27 * arising from the use of this software.
41 const char *pkgArchiveName( pkgXmlNode *rel, const char *tag, unsigned opt )
43 /* Local helper to establish actual release file names...
44 * applicable only to XML "release" elements.
46 if( ! rel->IsElementOfType( release_key ) )
48 /* The XML element type name is not "release"; identify it...
51 if( (reftype = rel->GetName()) == NULL )
53 * ...or classify as "unknown", when given a NULL element.
55 reftype = value_unknown;
57 /* Complain that this XML element type is invalid, in this context...
59 dmh_control( DMH_BEGIN_DIGEST );
60 dmh_notify( DMH_ERROR, PKGMSG_SPECIFICATION_ERROR );
61 dmh_notify( DMH_ERROR, "can't get 'tarname' for non-release element %s\n", reftype );
62 dmh_notify( DMH_ERROR, "please report this to the package maintainer\n" );
63 dmh_control( DMH_END_DIGEST );
65 /* ...and bail out, telling the caller that no archive name is available...
70 /* Given a package release specification...
71 * First check that it relates to a real package, rather than to
72 * a virtual "meta-package"; such meta-packages exist solely as
73 * containers for requirements specifications, and have no
76 pkgXmlNode *pkg = rel->GetParent();
77 while( (pkg != NULL) && ! pkg->IsElementOfType( package_key ) )
78 pkg = pkg->GetParent();
80 /* FIXME: we should probably provide some error handling here,
81 * to diagnose release elements without any package association;
82 * (these would be identified by pkg == NULL).
86 /* We found the package association...
87 * Check its 'class' attribute, if any, and if classified as
88 * 'virtual', return the archive association as "none".
90 const char *package_class = pkg->GetPropVal( class_key, NULL );
91 if( (package_class != NULL) && (strcmp( package_class, value_virtual ) == 0) )
95 /* The given release specification relates to a real package...
96 * Determine the archive name for the tarball to be processed; this
97 * is retrieved from a child XML element with name specified by "tag";
98 * by default, if "opt" is non-zero, it is the canonical "tarname"
99 * assigned to the release element itself, unless an alternative
100 * specification is provided; if "opt" is zero, no default is
101 * assumed, and the return value is NULL if no alternative
102 * specification is provided.
104 unsigned matched = 0;
105 pkgXmlNode *dl = rel->GetChildren();
108 /* Visit all children of the release specification element,
109 * checking for the presence of an expected specification...
111 if( dl->IsElementOfType( tag ) )
113 /* Found one; ensure it is the only one...
117 * ...else emit a warning, and ignore this one...
119 dmh_notify( DMH_WARNING, "%s: archive name reassignment ignored\n",
120 rel->GetPropVal( tarname_key, value_unknown )
123 /* ...ok; this is the first "tag" specification,
124 * accept it as the non-default source of the release's
125 * "tarname" property.
129 /* Continue, until all children have been visited.
133 /* "rel" now points to the XML element having the appropriate
134 * "tarname" specification; return a pointer to it's value.
136 return (opt || matched) ? rel->GetPropVal( tarname_key, NULL ) : NULL;
139 EXTERN_C const char *pkgAssociateName( const char *, const char * );
142 const char *pkgResolvedName( pkgXmlNode *rel, const char *tag, const char *ext )
144 /* Local helper function to resolve the mapping from a released
145 * package name, as identified from the XML release element "rel",
146 * to its corresponding source or licence package name, according
147 * to the selection of "source" or "licence" specified by "tag",
148 * with "ext" passed a "src" or "lic" respectively.
151 const char *retname = NULL;
153 /* First, we retrieve the released package name...
155 if( (refname = pkgArchiveName( rel, release_key, 1 )) != NULL )
157 /* ...and if successful, look for an explicit reference to
158 * the source or licence package, embedded within the release
159 * specification itself.
161 if( (retname = pkgArchiveName( rel, tag, 0 )) == NULL )
163 /* When this fails to identify the required mapping,
164 * then we look for a generic reference, defined for
165 * the containing package.
167 pkgXmlNode *enc = rel->GetParent();
169 /* A generic reference may be placed at any nesting
170 * level, between the enclosing package element and
171 * the release to which it relates; thus, starting
172 * at the first enclosing level...
177 /* ...enumerate reference specifications of the
178 * appropriate type, examining all children of
179 * the enclosing element.
181 unsigned matched = 0;
182 pkgXmlNode *child = enc->GetChildren();
183 while( child != NULL )
185 /* We have a child, which we have not examined...
187 if( child->IsElementOfType( tag ) )
189 /* ...and it is of the required "tag" type.
193 * We already had a candidate match, so we
194 * diagnose but otherwise this duplicate...
196 dmh_notify( DMH_WARNING,
197 "redundant %s specification ignored\n", tag
201 /* This is the first candidate match found,
206 /* Continue examining child elements, until no more
207 * are present at the current nesting level.
209 child = child->GetNext();
212 /* When we've completed the examination of all children
213 * at a given nesting level, without finding a matching
214 * specification, and that level is still within the
215 * enclosing package element...
217 if( (rel == NULL) && ! enc->IsElementOfType( package_key ) )
219 * ...then we extend the search to the next enclosing
220 * level of nesting...
222 enc = enc->GetParent();
225 /* ...otherwise, we abandon the search.
230 /* If we've searched all available nesting levels,
231 * and failed to locate the requisite specification...
235 /* ...then we assume that the requisite tarname
236 * is identical to the release tarname, with the
237 * appropriate "ext" substitution for the package
238 * class identification...
240 pkgSpecs resolved( refname );
241 resolved.SetComponentClass( ext );
243 * ...so, having made the substitution,
244 * we return the resultant tarname, noting
245 * that this automatically allocates space
246 * on the heap, for the returned string.
248 return resolved.GetTarName();
251 /* We did find a mappingspecification, so we
252 * extract a tarname template from it.
254 retname = rel->GetPropVal( tarname_key, NULL );
256 else if( strcmp( retname, value_none ) == 0 )
258 * The package is virtual, or an explicit mapping
259 * specification indicates that there is no related
260 * source or licence package; return NULL to advise
261 * the caller of this.
265 /* If we get to here, we found a mapping specification;
266 * it may be a template, so resolve any substitutions which
267 * it must inherit from the released package tarname, again
268 * noting that this allocates heap memory for the result.
270 retname = pkgAssociateName( retname, refname );
273 /* Finally, how ever we resolved the mapping, we return
279 const char *pkgXmlNode::SourceArchiveName( unsigned long category )
281 /* Applicable only for XML nodes designated as "release".
283 * Retrieve the source tarball name, if specified, from the
284 * "tarname" property of the contained "source" element, within
285 * an XML node designated as a "release" element.
287 * Returns a pointer to the text of the "tarname" property of the
288 * contained "source" element, or NULL if the containing node does
289 * not represent a "release", or if it does not have a contained
290 * "source" element specifying a "tarname" property.
292 const char *tag = "lic";
293 if( category != ACTION_LICENCE )
295 /* We may have been asked to explicitly override the "source"
296 * mapping, returning the "licence" reference instead; where
297 * this special exception is NOT requested, then we enforce
300 category = ACTION_SOURCE;
304 /* In either case, pkgResolvedName() determines the appropriate
305 * archive name, which it automatically returns on the heap.
307 return pkgResolvedName( this, action_name( category ), tag );
310 const char *pkgXmlNode::ArchiveName()
312 /* Applicable only for XML nodes designated as "release".
314 * Retrieve the actual tarball name, if specified, from the
315 * "tarname" property of a contained "download" element, within
316 * an XML node designated as a "release" element.
318 * Returns a pointer to the text of the "tarname" property of the
319 * contained "download" element, or to the "tarname" property of
320 * the containing "release" element, if it does not contain an
321 * alternative specification within a "download" element; if
322 * unresolved to either of these, returns NULL.
324 return pkgArchiveName( this, download_key, 1 );
327 /* $RCSfile$: end of file */