OSDN Git Service

39a810b5eb0644ee74bd86320fc5deb64d692810
[mingw/mingw-get.git] / src / pkgbase.h
1 #ifndef PKGBASE_H
2 /*
3  * pkgbase.h
4  *
5  * $Id$
6  *
7  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
8  * Copyright (C) 2009, 2010, 2011, MinGW Project
9  *
10  *
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.
14  *
15  *
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.
21  *
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.
28  *
29  */
30 #define PKGBASE_H  1
31
32 #include <tinyxml.h>
33 #include <tinystr.h>
34
35 #ifndef EXTERN_C
36 # ifdef __cplusplus
37 #  define EXTERN_C extern "C"
38 # else
39 #  define EXTERN_C
40 # endif
41 #endif
42
43 /* Adopt sensible defaults for matching subsystem and file names...
44  */
45 #ifdef _WIN32
46   /*
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...
50    */
51 # ifndef CASE_INSENSITIVE_SUBSYSTEMS
52 #  define CASE_INSENSITIVE_SUBSYSTEMS  1
53 # endif
54 # ifndef CASE_INSENSITIVE_FILESYSTEM
55 #  define CASE_INSENSITIVE_FILESYSTEM  1
56 # endif
57   /*
58    * The preferred name for MS-Windows' case insensitive string
59    * matching function, equivalent to POSIX strcasecmp().
60    */
61 # define strcasecmp  stricmp
62 #else
63   /* On other systems, we prefer to adopt case sensitive matching
64    * strategies for subsystem and file names.
65    */
66 # ifndef CASE_INSENSITIVE_SUBSYSTEMS
67 #  define CASE_INSENSITIVE_SUBSYSTEMS  0
68 # endif
69 # ifndef CASE_INSENSITIVE_FILESYSTEM
70 #  define CASE_INSENSITIVE_FILESYSTEM  0
71 # endif
72 #endif
73
74 class pkgSpecs;
75
76 class pkgXmlNode : public TiXmlElement
77 {
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.
81    */
82   public:
83     /* Constructors...
84      */
85     inline pkgXmlNode( const char* name ):TiXmlElement( name ){}
86     inline pkgXmlNode( const pkgXmlNode& src ):TiXmlElement( src ){}
87
88     /* Accessors...
89      *
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.
93      */
94     inline const char* GetName()
95     {
96       /* Retrieve the identifying name of the XML tag;
97        * tinyxml calls this the element "value"...
98        */
99       return this ? Value() : NULL;
100     }
101     inline pkgXmlNode* GetParent()
102     {
103       /* wxXmlNode provides this equivalant of tinyxml's
104        * Parent() method.
105        */
106       return this ? (pkgXmlNode*)(Parent()) : NULL;
107     }
108     inline pkgXmlNode* GetChildren()
109     {
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.
113        */
114       return this ? (pkgXmlNode*)(FirstChild()) : NULL;
115     }
116     inline pkgXmlNode* GetNext()
117     {
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().
121        */
122       return this ? (pkgXmlNode*)(NextSibling()) : NULL;
123     }
124     inline const char* GetPropVal( const char* name, const char* subst )
125     {
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.
129        */
130       const char* retval = this ? Attribute( name ) : subst;
131       return retval ? retval : subst;
132     }
133     inline pkgXmlNode* AddChild( TiXmlNode *child )
134     {
135       /* This is wxXmlNode's method for adding a child node, it is
136        * equivalent to tinyxml's LinkEndChild() method.
137        */
138       return this ? (pkgXmlNode*)(LinkEndChild( child )) : NULL;
139     }
140     inline bool DeleteChild( pkgXmlNode *child )
141     {
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'.
146        */
147       return this ? RemoveChild( child ) : false;
148     }
149
150     /* Additional methods specific to the application.
151      */
152     inline pkgXmlNode *GetDocumentRoot()
153     {
154       /* Convenience method to retrieve a pointer to the document root.
155        */
156       return this ? (pkgXmlNode*)(GetDocument()->RootElement()) : NULL;
157     }
158     inline bool IsElementOfType( const char* tagname )
159     {
160       /* Confirm if the owner XML node represents a data element
161        * with the specified "tagname".
162        */
163       return this ? strcmp( GetName(), tagname ) == 0 : false;
164     }
165
166     /* Methods for retrieving the system root management records
167      * for a specified installed subsystem.
168      */
169     pkgXmlNode *GetSysRoot( const char* );
170     pkgXmlNode *GetInstallationRecord( const char* );
171
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.
175      */
176     pkgXmlNode* FindFirstAssociate( const char* );
177     pkgXmlNode* FindNextAssociate( const char* );
178
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.
183      */
184     const char* ArchiveName();
185     const char* SourceArchiveName( unsigned long );
186
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.
191      */
192     const char *GetContainerAttribute( const char*, const char* = NULL );
193
194     /* Any package may have associated scripts; the following
195      * method invokes them on demand.
196      */
197     inline int InvokeScript( const char *context )
198     {
199       /* The actual implementation is delegated to the following
200        * (private) overloaded method.
201        */
202       return InvokeScript( 0, context );
203     }
204
205   private:
206     /* Helpers used to implement the preceding InvokeScript() method.
207      */
208     int InvokeScript( int, const char* );
209     int DispatchScript( int, const char*, const char*, pkgXmlNode* );
210 };
211
212 enum { to_remove = 0, to_install, selection_types };
213
214 class pkgActionItem
215 {
216   /* A class implementing a bi-directionally linked list of
217    * "action" descriptors, which is to be associated with the
218    * pkgXmlDocument class, specifying actions to be performed
219    * on the managed software installation.
220    */
221   private:
222     /* Pointers to predecessor and successor in the linked list
223      * comprising the schedule of action items.
224      */
225     pkgActionItem* prev;
226     pkgActionItem* next;
227
228     /* Flags define the specific action associated with this item.
229      */
230     unsigned long flags;
231
232     /* Criteria for selection of package versions associated with
233      * this action item.
234      */
235     const char* min_wanted;
236     const char* max_wanted;
237
238     /* Pointers to the XML database entries for the package selected
239      * for processing by this action.
240      */
241     pkgXmlNode* selection[ selection_types ];
242
243     /* Method to display the URI whence a package may be downloaded.
244      */
245     void PrintURI( const char* );
246
247     /* Methods for retrieving packages from a distribution server.
248      */
249     void DownloadArchiveFiles( pkgActionItem* );
250     void DownloadSingleArchive( const char*, const char* );
251
252   public:
253     /* Constructor...
254      */
255     pkgActionItem( pkgActionItem* = NULL, pkgActionItem* = NULL );
256
257     /* Methods for assembling action items into a linked list.
258      */
259     pkgActionItem* Append( pkgActionItem* = NULL );
260     pkgActionItem* Insert( pkgActionItem* = NULL );
261
262     /* Methods for compiling the schedule of actions.
263      */
264     unsigned long SetAuthorities( pkgActionItem* );
265     inline unsigned long HasAttribute( unsigned long required )
266     {
267       return flags & required;
268     }
269     pkgActionItem* GetReference( pkgActionItem& );
270     pkgActionItem* Schedule( unsigned long, pkgActionItem& );
271     inline void SetPrimary( pkgActionItem* );
272
273     /* Methods for defining the selection criteria for
274      * packages to be processed.
275      */
276     pkgXmlNode* SelectIfMostRecentFit( pkgXmlNode* );
277     const char* SetRequirements( pkgXmlNode*, pkgSpecs* );
278     inline void SelectPackage( pkgXmlNode *pkg, int opt = to_install )
279     {
280       /* Mark a package as the selection for a specified action.
281        */
282       selection[ opt ] = pkg;
283     }
284     inline pkgXmlNode* Selection( int mode = to_install )
285     {
286       /* Retrieve the package selection for a specified action.
287        */
288       return selection[ mode ];
289     }
290     void ConfirmInstallationStatus();
291
292     /* Methods to download and unpack one or more source archives.
293      */
294     void GetSourceArchive( pkgXmlNode*, unsigned long );
295     void GetScheduledSourceArchives( unsigned long );
296
297     /* Method for processing all scheduled actions.
298      */
299     void Execute();
300
301     /* Destructor...
302      */
303     ~pkgActionItem();
304 };
305
306 class pkgXmlDocument : public TiXmlDocument
307 {
308   /* Minimal emulation of the wxXmlDocument class, founded on
309    * the tinyxml implementation of the TiXmlDocument class.
310    */
311   public:
312     /* Constructors...
313      */
314     inline pkgXmlDocument(){}
315     inline pkgXmlDocument( const char* name )
316     {
317       /* tinyxml has a similar constructor, but unlike wxXmlDocument,
318        * it DOES NOT automatically load the document; force it.
319        */
320       LoadFile( name );
321
322       /* Always begin with an empty actions list.
323        */
324       actions = NULL;
325     }
326
327     /* Accessors...
328      */
329     inline bool IsOk()
330     {
331       /* tinyxml doesn't have this, but instead provides a complementary
332        * `Error()' indicator, so to simulate `IsOk()'...
333        */
334       return ! Error();
335     }
336     inline pkgXmlNode* GetRoot()
337     {
338       /* This is wxXmlDocument's method for locating the document root;
339        * it is equivalent to tinyxml's RootElement() method.
340        */
341       return (pkgXmlNode *)(RootElement());
342     }
343     inline void AddDeclaration
344     ( const char *version, const char *encoding, const char *standalone )
345     {
346       /* Not a standard method of either wxXmlDocumemnt or TiXmlDocument;
347        * this is a convenience method for setting up a new XML database.
348        */
349       LinkEndChild( new TiXmlDeclaration( version, encoding, standalone ) );
350     }
351     inline void SetRoot( TiXmlNode* root )
352     {
353       /* tinyxml has no direct equivalent for this wxXmlDocument method;
354        * to emulate it, we must first explicitly delete an existing root
355        * node, if any, then link the new root node as a document child.
356        */
357       pkgXmlNode *oldroot;
358       if( (oldroot = GetRoot()) != NULL )
359         delete oldroot;
360       LinkEndChild( root );
361     }
362     inline bool Save( const char *filename )
363     {
364       /* This wxXmlDocument method for saving the database is equivalent
365        * to the corresponding tinyxml SaveFile( const char* ) method.
366        */
367       return SaveFile( filename );
368     }
369
370   private:
371     /* Properties specifying the schedule of actions.
372      */
373     unsigned long request;
374     pkgActionItem* actions;
375
376   public:
377     /* Method to synchronise the state of the local package manifest
378      * with the master copy held on the distribution server.
379      */
380     void SyncRepository( const char*, pkgXmlNode* );
381
382     /* Method to merge content from repository-specific package lists
383      * into the central XML package database.
384      */
385     pkgXmlNode* BindRepositories( bool );
386
387     /* Method to load the system map, and the lists of installed
388      * packages associated with each specified sysroot.
389      */
390     void LoadSystemMap();
391
392     /* Complementary method, to update the saved sysroot data associated
393      * with the active system map.
394      */
395     void UpdateSystemMap();
396
397     /* Method to locate the XML database entry for a named package.
398      */
399     pkgXmlNode* FindPackageByName( const char*, const char* = NULL );
400
401     /* Method to display information about packages.
402      */
403     void DisplayPackageInfo( int, char** );
404
405     /* Method to resolve the dependencies of a specified package,
406      * by walking the chain of references specified by "requires"
407      * elements in the respective package database entries.
408      */
409     void ResolveDependencies( pkgXmlNode*, pkgActionItem* = NULL );
410
411     /* Methods for compiling a schedule of actions.
412      */
413     void Schedule( unsigned long, const char* );
414     pkgActionItem* Schedule( unsigned long, pkgActionItem&, pkgActionItem* = NULL );
415     void RescheduleInstalledPackages( unsigned long );
416
417     /* Method to execute a sequence of scheduled actions.
418      */
419     inline void ExecuteActions(){ actions->Execute(); }
420
421     /* Methods to retrieve and optionally extract source archives
422      * for a collection of dependent packages.
423      */
424     void GetSourceArchive( const char*, unsigned long );
425     inline void GetScheduledSourceArchives( unsigned long category )
426     {
427       actions->GetScheduledSourceArchives( category );
428     }
429 };
430
431 EXTERN_C const char *xmlfile( const char*, const char* = NULL );
432 EXTERN_C int has_keyword( const char*, const char* );
433
434 typedef int (*strcmp_function)( const char *, const char * );
435
436 static inline
437 bool safe_strcmp( strcmp_function strcmp, const char *value, const char *proto )
438 {
439   /* Helper to compare a pair of "C" strings for equality,
440    * accepting NULL as a match for anything; for non-NULL matches,
441    * case sensitivity is determined by choice of strcmp function.
442    *
443    * N.B. Unlike the 'strcmp' function which this calls, this is
444    * a boolean function, returning TRUE when the 'strcmp' result
445    * is zero, (i.e. the sense of the result is inverted).
446    */
447   return (value == NULL) || (proto == NULL) || (strcmp( value, proto ) == 0);
448 }
449
450 /* Define a safe_strcmp() alias for an explicitly case sensitive match.
451  */
452 #define match_if_explicit( A, B )  safe_strcmp( strcmp, (A), (B) )
453
454 /* Further safe_strcmp() aliases provide for matching subsystem names,
455  * with implementation dependent case sensitivity...
456  */
457 #if CASE_INSENSITIVE_SUBSYSTEMS
458 # define subsystem_strcmp( A, B )  safe_strcmp( strcasecmp, (A), (B) )
459 #else
460 # define subsystem_strcmp( A, B )  safe_strcmp( strcmp, (A), (B) )
461 #endif
462
463 /* ...and similarly, for matching of file names.
464  */
465 #if CASE_INSENSITIVE_FILESYSTEM
466 # define pkg_strcmp( A, B )  safe_strcmp( strcasecmp, (A), (B) )
467 #else
468 # define pkg_strcmp( A, B )  safe_strcmp( strcmp, (A), (B) )
469 #endif
470
471 #endif /* PKGBASE_H: $RCSfile$: end of file */