7 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
8 * Copyright (C) 2009, 2010, 2011, MinGW Project
11 * Public interface for the package directory management routines;
12 * declares the XML data structures, and their associated class APIs,
13 * which are used to describe packages and their interdependencies.
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.
37 # define EXTERN_C extern "C"
43 /* Adopt sensible defaults for matching subsystem and file names...
47 * The MS-Windows file system is intrinsically case insensitive,
48 * so we prefer to match both subsystem and file names in a case
49 * insensitive manner...
51 # ifndef CASE_INSENSITIVE_SUBSYSTEMS
52 # define CASE_INSENSITIVE_SUBSYSTEMS 1
54 # ifndef CASE_INSENSITIVE_FILESYSTEM
55 # define CASE_INSENSITIVE_FILESYSTEM 1
58 * The preferred name for MS-Windows' case insensitive string
59 * matching function, equivalent to POSIX strcasecmp().
61 # define strcasecmp stricmp
63 /* On other systems, we prefer to adopt case sensitive matching
64 * strategies for subsystem and file names.
66 # ifndef CASE_INSENSITIVE_SUBSYSTEMS
67 # define CASE_INSENSITIVE_SUBSYSTEMS 0
69 # ifndef CASE_INSENSITIVE_FILESYSTEM
70 # define CASE_INSENSITIVE_FILESYSTEM 0
76 class pkgXmlNode : public TiXmlElement
78 /* A minimal emulation of the wxXmlNode class, founded on
79 * the tinyxml implementation of the TiXmlElement class, and
80 * subsequently extended by application specific features.
85 inline pkgXmlNode( const char* name ):TiXmlElement( name ){}
86 inline pkgXmlNode( const pkgXmlNode& src ):TiXmlElement( src ){}
90 * Note that tinyxml is generally careless about checking for
91 * possible dereferencing of NULL pointers; thus, many of these
92 * wrappers include appropriate checks, to prevent this.
94 inline const char* GetName()
96 /* Retrieve the identifying name of the XML tag;
97 * tinyxml calls this the element "value"...
99 return this ? Value() : NULL;
101 inline pkgXmlNode* GetParent()
103 /* wxXmlNode provides this equivalant of tinyxml's
106 return this ? (pkgXmlNode*)(Parent()) : NULL;
108 inline pkgXmlNode* GetChildren()
110 /* wxXmlNode provides only this one method to access
111 * the children of an element; it is equivalent to the
112 * FirstChild() method in tinyxml's arsenal.
114 return this ? (pkgXmlNode*)(FirstChild()) : NULL;
116 inline pkgXmlNode* GetNext()
118 /* This is wxXmlNode's method for visiting other children
119 * of an element, after the first found by GetChildren();
120 * it is equivalent to tinyxml's NextSibling().
122 return this ? (pkgXmlNode*)(NextSibling()) : NULL;
124 inline const char* GetPropVal( const char* name, const char* subst )
126 /* tinyxml has no direct equivalent for this wxXmlNode method,
127 * (which substitutes default "subst" text for an omitted property),
128 * but it may be trivially emulated, using the Attribute() method.
130 const char* retval = this ? Attribute( name ) : subst;
131 return retval ? retval : subst;
133 inline pkgXmlNode* AddChild( TiXmlNode *child )
135 /* This is wxXmlNode's method for adding a child node, it is
136 * equivalent to tinyxml's LinkEndChild() method.
138 return this ? (pkgXmlNode*)(LinkEndChild( child )) : NULL;
140 inline bool DeleteChild( pkgXmlNode *child )
142 /* Both TiXmlNode and wxXmlNode have RemoveChild methods, but the
143 * implementations are semantically different; for tinyxml, we may
144 * simply use the RemoveChild method here, where for wxXmlNode, we
145 * would use RemoveChild followed by `delete child'.
147 return this ? RemoveChild( child ) : false;
150 /* Additional methods specific to the application.
152 inline pkgXmlNode *GetDocumentRoot()
154 /* Convenience method to retrieve a pointer to the document root.
156 return this ? (pkgXmlNode*)(GetDocument()->RootElement()) : NULL;
158 inline bool IsElementOfType( const char* tagname )
160 /* Confirm if the owner XML node represents a data element
161 * with the specified "tagname".
163 return this ? strcmp( GetName(), tagname ) == 0 : false;
166 /* Methods for retrieving the system root management records
167 * for a specified installed subsystem.
169 pkgXmlNode *GetSysRoot( const char* );
170 pkgXmlNode *GetInstallationRecord( const char* );
172 /* The following pair of methods provide an iterator
173 * for enumerating the contained nodes, within the owner,
174 * which themselves exhibit a specified tagname.
176 pkgXmlNode* FindFirstAssociate( const char* );
177 pkgXmlNode* FindNextAssociate( const char* );
179 /* Specific to XML node elements of type "release",
180 * the following pair of methods retrieve the actual name of
181 * the release tarball, and its associated source code tarball,
182 * as they are named on the project download servers.
184 const char* ArchiveName();
185 const char* SourceArchiveName();
187 /* The following retrieves an attribute which may have been
188 * specified on an ancestor (container) node; typically used to
189 * retrieve the package name or alias attributes which are to
190 * be associated with a release.
192 const char *GetContainerAttribute( const char*, const char* = NULL );
195 enum { to_remove = 0, to_install, selection_types };
199 /* A class implementing a bi-directionally linked list of
200 * "action" descriptors, which is to be associated with the
201 * pkgXmlDocument class, specifying actions to be performed
202 * on the managed software installation.
205 /* Pointers to predecessor and successor in the linked list
206 * comprising the schedule of action items.
211 /* Flags define the specific action associated with this item.
215 /* Criteria for selection of package versions associated with
218 const char* min_wanted;
219 const char* max_wanted;
221 /* Pointers to the XML database entries for the package selected
222 * for processing by this action.
224 pkgXmlNode* selection[ selection_types ];
226 /* Method for retrieving packages from a distribution server.
228 void DownloadArchiveFiles( pkgActionItem* );
233 pkgActionItem( pkgActionItem* = NULL, pkgActionItem* = NULL );
235 /* Methods for assembling action items into a linked list.
237 pkgActionItem* Append( pkgActionItem* = NULL );
238 pkgActionItem* Insert( pkgActionItem* = NULL );
240 /* Methods for compiling the schedule of actions.
242 int SetAuthorities( pkgActionItem* );
243 pkgActionItem* GetReference( pkgActionItem& );
244 pkgActionItem* Schedule( unsigned long, pkgActionItem& );
245 inline void SetPrimary( pkgActionItem* );
247 /* Methods for defining the selection criteria for
248 * packages to be processed.
250 pkgXmlNode* SelectIfMostRecentFit( pkgXmlNode* );
251 const char* SetRequirements( pkgXmlNode*, pkgSpecs* );
252 inline void SelectPackage( pkgXmlNode *pkg, int opt = to_install )
254 /* Mark a package as the selection for a specified action.
256 selection[ opt ] = pkg;
258 inline pkgXmlNode* Selection( int mode = to_install )
260 /* Retrieve the package selection for a specified action.
262 return selection[ mode ];
264 void ConfirmInstallationStatus();
266 /* Method for processing all scheduled actions.
275 class pkgXmlDocument : public TiXmlDocument
277 /* Minimal emulation of the wxXmlDocument class, founded on
278 * the tinyxml implementation of the TiXmlDocument class.
283 inline pkgXmlDocument(){}
284 inline pkgXmlDocument( const char* name )
286 /* tinyxml has a similar constructor, but unlike wxXmlDocument,
287 * it DOES NOT automatically load the document; force it.
291 /* Always begin with an empty actions list.
300 /* tinyxml doesn't have this, but instead provides a complementary
301 * `Error()' indicator, so to simulate `IsOk()'...
305 inline pkgXmlNode* GetRoot()
307 /* This is wxXmlDocument's method for locating the document root;
308 * it is equivalent to tinyxml's RootElement() method.
310 return (pkgXmlNode *)(RootElement());
312 inline void AddDeclaration
313 ( const char *version, const char *encoding, const char *standalone )
315 /* Not a standard method of either wxXmlDocumemnt or TiXmlDocument;
316 * this is a convenience method for setting up a new XML database.
318 LinkEndChild( new TiXmlDeclaration( version, encoding, standalone ) );
320 inline void SetRoot( TiXmlNode* root )
322 /* tinyxml has no direct equivalent for this wxXmlDocument method;
323 * to emulate it, we must first explicitly delete an existing root
324 * node, if any, then link the new root node as a document child.
327 if( (oldroot = GetRoot()) != NULL )
329 LinkEndChild( root );
331 inline bool Save( const char *filename )
333 /* This wxXmlDocument method for saving the database is equivalent
334 * to the corresponding tinyxml SaveFile( const char* ) method.
336 return SaveFile( filename );
340 /* Properties specifying the schedule of actions.
342 unsigned long request;
343 pkgActionItem* actions;
346 /* Method to synchronise the state of the local package manifest
347 * with the master copy held on the distribution server.
349 void SyncRepository( const char*, pkgXmlNode* );
351 /* Method to merge content from repository-specific package lists
352 * into the central XML package database.
354 pkgXmlNode* BindRepositories( bool );
356 /* Method to load the system map, and the lists of installed
357 * packages associated with each specified sysroot.
359 void LoadSystemMap();
361 /* Complementary method, to update the saved sysroot data associated
362 * with the active system map.
364 void UpdateSystemMap();
366 /* Method to locate the XML database entry for a named package.
368 pkgXmlNode* FindPackageByName( const char*, const char* = NULL );
370 /* Method to display information about packages.
372 void DisplayPackageInfo( int, char** );
374 /* Method to resolve the dependencies of a specified package,
375 * by walking the chain of references specified by "requires"
376 * elements in the respective package database entries.
378 void ResolveDependencies( pkgXmlNode*, pkgActionItem* = NULL );
380 /* Methods for compiling a schedule of actions.
382 void Schedule( unsigned long, const char* );
383 pkgActionItem* Schedule( unsigned long, pkgActionItem&, pkgActionItem* = NULL );
385 /* Method to execute a sequence of scheduled actions.
387 inline void ExecuteActions(){ actions->Execute(); }
390 EXTERN_C const char *xmlfile( const char*, const char* = NULL );
391 EXTERN_C int has_keyword( const char*, const char* );
393 typedef int (*strcmp_function)( const char *, const char * );
396 bool safe_strcmp( strcmp_function strcmp, const char *value, const char *proto )
398 /* Helper to compare a pair of "C" strings for equality,
399 * accepting NULL as a match for anything; for non-NULL matches,
400 * case sensitivity is determined by choice of strcmp function.
402 * N.B. Unlike the 'strcmp' function which this calls, this is
403 * a boolean function, returning TRUE when the 'strcmp' result
404 * is zero, (i.e. the sense of the result is inverted).
406 return (value == NULL) || (proto == NULL) || (strcmp( value, proto ) == 0);
409 /* Define a safe_strcmp() alias for an explicitly case sensitive match.
411 #define match_if_explicit( A, B ) safe_strcmp( strcmp, (A), (B) )
413 /* Further safe_strcmp() aliases provide for matching subsystem names,
414 * with implementation dependent case sensitivity...
416 #if CASE_INSENSITIVE_SUBSYSTEMS
417 # define subsystem_strcmp( A, B ) safe_strcmp( strcasecmp, (A), (B) )
419 # define subsystem_strcmp( A, B ) safe_strcmp( strcmp, (A), (B) )
422 /* ...and similarly, for matching of file names.
424 #if CASE_INSENSITIVE_FILESYSTEM
425 # define pkg_strcmp( A, B ) safe_strcmp( strcasecmp, (A), (B) )
427 # define pkg_strcmp( A, B ) safe_strcmp( strcmp, (A), (B) )
430 #endif /* PKGBASE_H: $RCSfile$: end of file */