OSDN Git Service

Refactor API to facilitate implementation of GUI ListView hooks.
[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, 2012, 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 /* Define an API for registering environment variables.
75  */
76 EXTERN_C int pkgPutEnv( int, char* );
77
78 #define PKG_PUTENV_DIRSEP_MSW           (0x01)
79 #define PKG_PUTENV_DIRSEP_POSIX         (0x02)
80 #define PKG_PUTENV_SCAN_VARNAME         (0x04)
81 #define PKG_PUTENV_NAME_TOUPPER         (0x08)
82
83 #define PKG_PUTENV_FLAGS_MASK           (0x0F)
84
85 /* Begin class declarations.
86  */
87 class pkgSpecs;
88 class pkgDirectory;
89
90 class pkgXmlNode : public TiXmlElement
91 {
92   /* A minimal emulation of the wxXmlNode class, founded on
93    * the tinyxml implementation of the TiXmlElement class, and
94    * subsequently extended by application specific features.
95    */
96   public:
97     /* Constructors...
98      */
99     inline pkgXmlNode( const char* name ):TiXmlElement( name ){}
100     inline pkgXmlNode( const pkgXmlNode& src ):TiXmlElement( src ){}
101
102     /* Accessors...
103      *
104      * Note that tinyxml is generally careless about checking for
105      * possible dereferencing of NULL pointers; thus, many of these
106      * wrappers include appropriate checks, to prevent this.
107      */
108     inline const char* GetName()
109     {
110       /* Retrieve the identifying name of the XML tag;
111        * tinyxml calls this the element "value"...
112        */
113       return this ? Value() : NULL;
114     }
115     inline pkgXmlNode* GetParent()
116     {
117       /* wxXmlNode provides this equivalant of tinyxml's
118        * Parent() method.
119        */
120       return this ? (pkgXmlNode*)(Parent()) : NULL;
121     }
122     inline pkgXmlNode* GetChildren()
123     {
124       /* wxXmlNode provides only this one method to access
125        * the children of an element; it is equivalent to the
126        * FirstChild() method in tinyxml's arsenal.
127        */
128       return this ? (pkgXmlNode*)(FirstChild()) : NULL;
129     }
130     inline pkgXmlNode* GetNext()
131     {
132       /* This is wxXmlNode's method for visiting other children
133        * of an element, after the first found by GetChildren();
134        * it is equivalent to tinyxml's NextSibling().
135        */
136       return this ? (pkgXmlNode*)(NextSibling()) : NULL;
137     }
138     inline const char* GetPropVal( const char* name, const char* subst )
139     {
140       /* tinyxml has no direct equivalent for this wxXmlNode method,
141        * (which substitutes default "subst" text for an omitted property),
142        * but it may be trivially emulated, using the Attribute() method.
143        */
144       const char* retval = this ? Attribute( name ) : subst;
145       return retval ? retval : subst;
146     }
147     inline pkgXmlNode* AddChild( TiXmlNode *child )
148     {
149       /* This is wxXmlNode's method for adding a child node, it is
150        * equivalent to tinyxml's LinkEndChild() method.
151        */
152       return this ? (pkgXmlNode*)(LinkEndChild( child )) : NULL;
153     }
154     inline bool DeleteChild( pkgXmlNode *child )
155     {
156       /* Both TiXmlNode and wxXmlNode have RemoveChild methods, but the
157        * implementations are semantically different; for tinyxml, we may
158        * simply use the RemoveChild method here, where for wxXmlNode, we
159        * would use RemoveChild followed by `delete child'.
160        */
161       return this ? RemoveChild( child ) : false;
162     }
163
164     /* Additional methods specific to the application.
165      */
166     inline pkgXmlNode *GetDocumentRoot()
167     {
168       /* Convenience method to retrieve a pointer to the document root.
169        */
170       return this ? (pkgXmlNode*)(GetDocument()->RootElement()) : NULL;
171     }
172     inline bool IsElementOfType( const char* tagname )
173     {
174       /* Confirm if the owner XML node represents a data element
175        * with the specified "tagname".
176        */
177       return this ? strcmp( GetName(), tagname ) == 0 : false;
178     }
179
180     /* Methods for retrieving the system root management records
181      * for a specified installed subsystem.
182      */
183     pkgXmlNode *GetSysRoot( const char* );
184     pkgXmlNode *GetInstallationRecord( const char* );
185
186     /* The following pair of methods provide an iterator
187      * for enumerating the contained nodes, within the owner,
188      * which themselves exhibit a specified tagname.
189      */
190     pkgXmlNode* FindFirstAssociate( const char* );
191     pkgXmlNode* FindNextAssociate( const char* );
192
193     /* Specific to XML node elements of type "release",
194      * the following pair of methods retrieve the actual name of
195      * the release tarball, and its associated source code tarball,
196      * as they are named on the project download servers.
197      */
198     const char* ArchiveName();
199     const char* SourceArchiveName( unsigned long );
200
201     /* The following retrieves an attribute which may have been
202      * specified on an ancestor (container) node; typically used to
203      * retrieve the package name or alias attributes which are to
204      * be associated with a release.
205      */
206     const char *GetContainerAttribute( const char*, const char* = NULL );
207
208     /* Any package may have associated scripts; the following
209      * method invokes them on demand.
210      */
211     inline int InvokeScript( const char *context )
212     {
213       /* The actual implementation is delegated to the following
214        * (private) overloaded method.
215        */
216       return InvokeScript( 0, context );
217     }
218
219   private:
220     /* Helpers used to implement the preceding InvokeScript() method.
221      */
222     int InvokeScript( int, const char* );
223     int DispatchScript( int, const char*, const char*, pkgXmlNode* );
224 };
225
226 enum { to_remove = 0, to_install, selection_types };
227
228 class pkgActionItem
229 {
230   /* A class implementing a bi-directionally linked list of
231    * "action" descriptors, which is to be associated with the
232    * pkgXmlDocument class, specifying actions to be performed
233    * on the managed software installation.
234    */
235   private:
236     /* Pointers to predecessor and successor in the linked list
237      * comprising the schedule of action items.
238      */
239     pkgActionItem* prev;
240     pkgActionItem* next;
241
242     /* Flags define the specific action associated with this item.
243      */
244     unsigned long flags;
245
246     /* Criteria for selection of package versions associated with
247      * this action item.
248      */
249     const char* min_wanted;
250     const char* max_wanted;
251
252     /* Pointers to the XML database entries for the package selected
253      * for processing by this action.
254      */
255     pkgXmlNode* selection[ selection_types ];
256
257     /* Method to display the URI whence a package may be downloaded.
258      */
259     void PrintURI( const char* );
260
261     /* Methods for retrieving packages from a distribution server.
262      */
263     void DownloadArchiveFiles( pkgActionItem* );
264     void DownloadSingleArchive( const char*, const char* );
265
266   public:
267     /* Constructor...
268      */
269     pkgActionItem( pkgActionItem* = NULL, pkgActionItem* = NULL );
270
271     /* Methods for assembling action items into a linked list.
272      */
273     pkgActionItem* Append( pkgActionItem* = NULL );
274     pkgActionItem* Insert( pkgActionItem* = NULL );
275
276     /* Methods for compiling the schedule of actions.
277      */
278     unsigned long SetAuthorities( pkgActionItem* );
279     inline unsigned long HasAttribute( unsigned long required )
280     {
281       return flags & required;
282     }
283     pkgActionItem* GetReference( pkgActionItem& );
284     pkgActionItem* Schedule( unsigned long, pkgActionItem& );
285     inline void SetPrimary( pkgActionItem* );
286
287     /* Methods for defining the selection criteria for
288      * packages to be processed.
289      */
290     void ApplyBounds( pkgXmlNode *, const char * );
291     pkgXmlNode* SelectIfMostRecentFit( pkgXmlNode* );
292     const char* SetRequirements( pkgXmlNode*, pkgSpecs* );
293     inline void SelectPackage( pkgXmlNode *pkg, int opt = to_install )
294     {
295       /* Mark a package as the selection for a specified action.
296        */
297       selection[ opt ] = pkg;
298     }
299     inline pkgXmlNode* Selection( int mode = to_install )
300     {
301       /* Retrieve the package selection for a specified action.
302        */
303       return selection[ mode ];
304     }
305     void ConfirmInstallationStatus();
306
307     /* Methods to download and unpack one or more source archives.
308      */
309     void GetSourceArchive( pkgXmlNode*, unsigned long );
310     void GetScheduledSourceArchives( unsigned long );
311
312     /* Method for processing all scheduled actions.
313      */
314     void Execute();
315
316     /* Destructor...
317      */
318     ~pkgActionItem();
319 };
320
321 class pkgXmlDocument : public TiXmlDocument
322 {
323   /* Minimal emulation of the wxXmlDocument class, founded on
324    * the tinyxml implementation of the TiXmlDocument class.
325    */
326   public:
327     /* Constructors...
328      */
329     inline pkgXmlDocument(){}
330     inline pkgXmlDocument( const char* name )
331     {
332       /* tinyxml has a similar constructor, but unlike wxXmlDocument,
333        * it DOES NOT automatically load the document; force it.
334        */
335       LoadFile( name );
336
337       /* Always begin with an empty actions list.
338        */
339       actions = NULL;
340     }
341
342     /* Accessors...
343      */
344     inline bool IsOk()
345     {
346       /* tinyxml doesn't have this, but instead provides a complementary
347        * `Error()' indicator, so to simulate `IsOk()'...
348        */
349       return ! Error();
350     }
351     inline pkgXmlNode* GetRoot()
352     {
353       /* This is wxXmlDocument's method for locating the document root;
354        * it is equivalent to tinyxml's RootElement() method.
355        */
356       return (pkgXmlNode *)(RootElement());
357     }
358     inline void AddDeclaration
359     ( const char *version, const char *encoding, const char *standalone )
360     {
361       /* Not a standard method of either wxXmlDocumemnt or TiXmlDocument;
362        * this is a convenience method for setting up a new XML database.
363        */
364       LinkEndChild( new TiXmlDeclaration( version, encoding, standalone ) );
365     }
366     inline void SetRoot( TiXmlNode* root )
367     {
368       /* tinyxml has no direct equivalent for this wxXmlDocument method;
369        * to emulate it, we must first explicitly delete an existing root
370        * node, if any, then link the new root node as a document child.
371        */
372       pkgXmlNode *oldroot;
373       if( (oldroot = GetRoot()) != NULL )
374         delete oldroot;
375       LinkEndChild( root );
376     }
377     inline bool Save( const char *filename )
378     {
379       /* This wxXmlDocument method for saving the database is equivalent
380        * to the corresponding tinyxml SaveFile( const char* ) method.
381        */
382       return SaveFile( filename );
383     }
384
385   private:
386     /* Properties specifying the schedule of actions.
387      */
388     unsigned long request;
389     pkgActionItem* actions;
390
391   public:
392     /* Method to interpret user preferences for mingw-get processing
393      * options, which are specified within profile.xml rather than on
394      * the command line.
395      */
396     void EstablishPreferences();
397
398     /* Method to synchronise the state of the local package manifest
399      * with the master copy held on the distribution server.
400      */
401     void SyncRepository( const char*, pkgXmlNode* );
402
403     /* Method to merge content from repository-specific package lists
404      * into the central XML package database.
405      */
406     pkgXmlNode* BindRepositories( bool );
407
408     /* Method to load the system map, and the lists of installed
409      * packages associated with each specified sysroot.
410      */
411     void LoadSystemMap();
412
413     /* Complementary method, to update the saved sysroot data associated
414      * with the active system map.
415      */
416     void UpdateSystemMap();
417
418     /* Method to locate the XML database entry for a named package.
419      */
420     pkgXmlNode* FindPackageByName( const char*, const char* = NULL );
421
422     /* Methods to retrieve and display information about packages.
423      */
424     pkgDirectory *CatalogueAllPackages();
425     void DisplayPackageInfo( int, char** );
426
427     /* Method to resolve the dependencies of a specified package,
428      * by walking the chain of references specified by "requires"
429      * elements in the respective package database entries.
430      */
431     void ResolveDependencies( pkgXmlNode*, pkgActionItem* = NULL );
432
433     /* Methods for compiling a schedule of actions.
434      */
435     void Schedule( unsigned long, const char* );
436     pkgActionItem* Schedule( unsigned long, pkgActionItem&, pkgActionItem* = NULL );
437     void RescheduleInstalledPackages( unsigned long );
438
439     /* Method to execute a sequence of scheduled actions.
440      */
441     inline void ExecuteActions(){ actions->Execute(); }
442
443     /* Methods to retrieve and optionally extract source archives
444      * for a collection of dependent packages.
445      */
446     void GetSourceArchive( const char*, unsigned long );
447     inline void GetScheduledSourceArchives( unsigned long category )
448     {
449       actions->GetScheduledSourceArchives( category );
450     }
451 };
452
453 EXTERN_C const char *xmlfile( const char*, const char* = NULL );
454 EXTERN_C int has_keyword( const char*, const char* );
455
456 typedef int (*strcmp_function)( const char *, const char * );
457
458 static inline
459 bool safe_strcmp( strcmp_function strcmp, const char *value, const char *proto )
460 {
461   /* Helper to compare a pair of "C" strings for equality,
462    * accepting NULL as a match for anything; for non-NULL matches,
463    * case sensitivity is determined by choice of strcmp function.
464    *
465    * N.B. Unlike the 'strcmp' function which this calls, this is
466    * a boolean function, returning TRUE when the 'strcmp' result
467    * is zero, (i.e. the sense of the result is inverted).
468    */
469   return (value == NULL) || (proto == NULL) || (strcmp( value, proto ) == 0);
470 }
471
472 /* Define a safe_strcmp() alias for an explicitly case sensitive match.
473  */
474 #define match_if_explicit( A, B )  safe_strcmp( strcmp, (A), (B) )
475
476 /* Further safe_strcmp() aliases provide for matching subsystem names,
477  * with implementation dependent case sensitivity...
478  */
479 #if CASE_INSENSITIVE_SUBSYSTEMS
480 # define subsystem_strcmp( A, B )  safe_strcmp( strcasecmp, (A), (B) )
481 #else
482 # define subsystem_strcmp( A, B )  safe_strcmp( strcmp, (A), (B) )
483 #endif
484
485 /* ...and similarly, for matching of file names.
486  */
487 #if CASE_INSENSITIVE_FILESYSTEM
488 # define pkg_strcmp( A, B )  safe_strcmp( strcasecmp, (A), (B) )
489 #else
490 # define pkg_strcmp( A, B )  safe_strcmp( strcmp, (A), (B) )
491 #endif
492
493 #endif /* PKGBASE_H: $RCSfile$: end of file */