OSDN Git Service

e87c0dfd0972c82c3ec2e645089b5546bc977858
[mingw/mingw-get.git] / src / pkgbase.h
1 #ifndef PKGBASE_H
2 /*
3  * pkgbase.h
4  *
5  * $Id$
6  *
7  * Written by Keith Marshall <keith@users.osdn.me>
8  * Copyright (C) 2009-2013, 2020, MinGW.org 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 #include "pkgimpl.h"
31 #if IMPLEMENTATION_LEVEL == PACKAGE_BASE_COMPONENT
32 #define PKGBASE_H  1
33
34 #include <tinyxml.h>
35 #include <tinystr.h>
36
37 /* Define an API for registering environment variables.
38  */
39 EXTERN_C int pkgPutEnv( int, char* );
40
41 #define PKG_PUTENV_DIRSEP_MSW           (0x01)
42 #define PKG_PUTENV_DIRSEP_POSIX         (0x02)
43 #define PKG_PUTENV_SCAN_VARNAME         (0x04)
44 #define PKG_PUTENV_NAME_TOUPPER         (0x08)
45
46 #define PKG_PUTENV_FLAGS_MASK           (0x0F)
47
48 /* Begin class declarations.
49  */
50 class pkgSpecs;
51 class pkgDirectory;
52
53 class pkgProgressMeter
54 {
55   /* An abstract base class, from which the controller class
56    * for a progress meter dialogue window may be derived.
57    */
58   public:
59     virtual void SetValue( int ) = 0;
60     virtual void SetRange( int, int ) = 0;
61     virtual int Annotate( const char *, ... ) = 0;
62 };
63
64 class pkgXmlNode : public TiXmlElement
65 {
66   /* A minimal emulation of the wxXmlNode class, founded on
67    * the tinyxml implementation of the TiXmlElement class, and
68    * subsequently extended by application specific features.
69    */
70   public:
71     /* Constructors...
72      */
73     inline pkgXmlNode( const char* name ):TiXmlElement( name ){}
74     inline pkgXmlNode( const pkgXmlNode& src ):TiXmlElement( src ){}
75
76     /* Accessors...
77      */
78     inline const char* GetName()
79     {
80       /* Retrieve the identifying name of the XML tag;
81        * tinyxml calls this the element "value"...
82        */
83       return Value();
84     }
85     inline pkgXmlNode* GetParent()
86     {
87       /* wxXmlNode provides this equivalant of tinyxml's
88        * Parent() method.
89        */
90       return (pkgXmlNode*)(Parent());
91     }
92     inline pkgXmlNode* GetChildren()
93     {
94       /* wxXmlNode provides only this one method to access
95        * the children of an element; it is equivalent to the
96        * FirstChild() method in tinyxml's arsenal.
97        */
98       return (pkgXmlNode*)(FirstChild());
99     }
100     inline pkgXmlNode* GetNext()
101     {
102       /* This is wxXmlNode's method for visiting other children
103        * of an element, after the first found by GetChildren();
104        * it is equivalent to tinyxml's NextSibling().
105        */
106       return (pkgXmlNode*)(NextSibling());
107     }
108     inline const char* GetPropVal( const char* name, const char* subst )
109     {
110       /* tinyxml has no direct equivalent for this wxXmlNode method,
111        * (which substitutes default "subst" text for an omitted property),
112        * but it may be trivially emulated, using the Attribute() method.
113        */
114       const char *retval;
115       if( (retval = Attribute( name )) == NULL ) return subst;
116       return retval;
117     }
118     inline pkgXmlNode* AddChild( TiXmlNode *child )
119     {
120       /* This is wxXmlNode's method for adding a child node, it is
121        * equivalent to tinyxml's LinkEndChild() method.
122        */
123       return (pkgXmlNode*)(LinkEndChild( child ));
124     }
125     inline bool DeleteChild( pkgXmlNode *child )
126     {
127       /* Both TiXmlNode and wxXmlNode have RemoveChild methods, but the
128        * implementations are semantically different; for tinyxml, we may
129        * simply use the RemoveChild method here, where for wxXmlNode, we
130        * would use RemoveChild followed by `delete child'.
131        */
132       return RemoveChild( child );
133     }
134
135     /* Additional methods specific to the application.
136      */
137     inline pkgXmlNode *GetDocumentRoot()
138     {
139       /* Convenience method to retrieve a pointer to the document root.
140        */
141       return (pkgXmlNode*)(GetDocument()->RootElement());
142     }
143     inline bool IsElementOfType( const char* tagname )
144     {
145       /* Confirm if the owner XML node represents a data element
146        * with the specified "tagname".
147        */
148       return strcmp( GetName(), tagname ) == 0;
149     }
150
151     /* Methods to determine which packages should be displayed
152      * in the package list pane of the GUI client.
153      */
154     inline bool IsVisibleGroupMember();
155     inline bool IsVisibleClass();
156
157     /* Methods for retrieving the system root management records
158      * for a specified installed subsystem.
159      */
160     pkgXmlNode *GetSysRoot( const char* );
161     pkgXmlNode *GetInstallationRecord( const char* );
162
163     /* Methods for mapping the package group hierarchy.
164      */
165     inline void SetPackageGroupHierarchyMapper();
166     inline void MapPackageGroupHierarchy( pkgXmlNode* );
167
168     /* Type definition for a helper function, which must be assigned
169      * to the package group hierarchy mapper, in order to enable it.
170      */
171     typedef void (*GroupHierarchyMapper)( pkgXmlNode*, pkgXmlNode* );
172
173     /* The following pair of methods provide an iterator
174      * for enumerating the contained nodes, within the owner,
175      * which themselves exhibit a specified tagname.
176      */
177     pkgXmlNode* FindFirstAssociate( const char* );
178     pkgXmlNode* FindNextAssociate( const char* );
179
180     /* Specific to XML node elements of type "release",
181      * the following pair of methods retrieve the actual name of
182      * the release tarball, and its associated source code tarball,
183      * as they are named on the project download servers.
184      */
185     const char* ArchiveName();
186     const char* SourceArchiveName( unsigned long );
187
188     /* The following retrieves an attribute which may have been
189      * specified on an ancestor (container) node; typically used to
190      * retrieve the package name or alias attributes which are to
191      * be associated with a release.
192      */
193     const char *GetContainerAttribute( const char*, const char* = NULL );
194
195     /* Any package may have associated scripts; the following
196      * method invokes them on demand.
197      */
198     inline int InvokeScript( const char *context )
199     {
200       /* The actual implementation is delegated to the following
201        * (private) overloaded method.
202        */
203       return InvokeScript( 0, context );
204     }
205
206   private:
207     /* Helpers used to implement the preceding InvokeScript() method.
208      */
209     int InvokeScript( int, const char* );
210     int DispatchScript( int, const char*, const char*, pkgXmlNode* );
211
212     /* Hook via which the requisite helper function is attached
213      * to the package group hierarchy mapper.
214      */
215     static GroupHierarchyMapper PackageGroupHierarchyMapper;
216 };
217
218 enum { to_remove = 0, to_install, selection_types };
219
220 class pkgActionItem
221 {
222   /* A class implementing a bi-directionally linked list of
223    * "action" descriptors, which is to be associated with the
224    * pkgXmlDocument class, specifying actions to be performed
225    * on the managed software installation.
226    */
227   private:
228     /* Pointers to predecessor and successor in the linked list
229      * comprising the schedule of action items.
230      */
231     pkgActionItem* prev;
232     pkgActionItem* next;
233
234     /* Flags define the specific action associated with this item.
235      */
236     unsigned long flags;
237
238     /* Criteria for selection of package versions associated with
239      * this action item.
240      */
241     const char* min_wanted;
242     const char* max_wanted;
243
244     /* Pointers to the XML database entries for the package selected
245      * for processing by this action.
246      */
247     pkgXmlNode* selection[ selection_types ];
248
249     /* Methods for retrieving packages from a distribution server.
250      */
251     void DownloadArchiveFiles( pkgActionItem* );
252     void DownloadSingleArchive( const char*, const char* );
253
254   public:
255     /* Constructor...
256      */
257     pkgActionItem( pkgActionItem* = NULL, pkgActionItem* = NULL );
258
259     /* Methods for assembling action items into a linked list.
260      */
261     pkgActionItem* Append( pkgActionItem* = NULL );
262     pkgActionItem* Insert( pkgActionItem* = NULL );
263
264     /* Methods for compiling the schedule of actions.
265      */
266     unsigned long SetAuthorities( pkgActionItem* );
267     inline unsigned long HasAttribute( unsigned long required )
268     {
269       return flags & required;
270     }
271     pkgActionItem* GetReference( pkgXmlNode* );
272     pkgActionItem* GetReference( pkgActionItem& );
273     pkgActionItem* Schedule( unsigned long, pkgActionItem& );
274     inline pkgActionItem* SuppressRedundantUpgrades( void );
275     inline void CancelScheduledAction( void );
276     inline void SetPrimary( pkgActionItem* );
277
278     /* Method to enumerate and identify pending changes,
279      * and/or check for residual unapplied changes.
280      */
281     unsigned long EnumeratePendingActions( int = 0 );
282
283     /* Methods for defining the selection criteria for
284      * packages to be processed.
285      */
286     void ApplyBounds( pkgXmlNode *, const char * );
287     pkgXmlNode* SelectIfMostRecentFit( pkgXmlNode* );
288     const char* SetRequirements( pkgXmlNode*, pkgSpecs* );
289     inline void SelectPackage( pkgXmlNode *pkg, int opt = to_install )
290     {
291       /* Mark a package as the selection for a specified action.
292        */
293       selection[ opt ] = pkg;
294     }
295     inline pkgXmlNode* Selection( int mode = to_install )
296     {
297       /* Retrieve the package selection for a specified action.
298        */
299       return selection[ mode ];
300     }
301     void ConfirmInstallationStatus();
302
303     /* Method to display the URI whence a package may be downloaded.
304      */
305     void PrintURI( const char*, int (*)( const char* ) = puts );
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     /* Methods for processing all scheduled actions.
313      */
314     void Execute( bool = true );
315     inline void DownloadArchiveFiles( void );
316
317     /* Method to manipulate error trapping, control, and state
318      * flags for the schedule of actions.
319      */
320     void Assert( unsigned long, unsigned long = ~0UL, pkgActionItem* = NULL );
321
322     /* Method to filter actions from an action list: the default is to
323      * clear ALL entries; specify a value of ACTION_MASK for the second
324      * argument, to filter out entries with no assigned action.
325      */
326     pkgActionItem *Clear( pkgActionItem* = NULL, unsigned long = 0UL );
327     pkgActionItem *Clear( unsigned long mask ){ return Clear( this, mask ); }
328
329     /* Destructor...
330      */
331     ~pkgActionItem();
332 };
333
334 class pkgXmlDocument : public TiXmlDocument
335 {
336   /* Minimal emulation of the wxXmlDocument class, founded on
337    * the tinyxml implementation of the TiXmlDocument class.
338    */
339   public:
340     /* Constructors...
341      */
342     inline pkgXmlDocument(): progress_meter( NULL ){}
343     inline pkgXmlDocument( const char* name ): progress_meter( NULL )
344     {
345       /* tinyxml has a similar constructor, but unlike wxXmlDocument,
346        * it DOES NOT automatically load the document; force it.
347        */
348       LoadFile( name );
349
350       /* Always begin with an empty actions list.
351        */
352       actions = NULL;
353     }
354
355     /* Accessors...
356      */
357     inline bool IsOk()
358     {
359       /* tinyxml doesn't have this, but instead provides a complementary
360        * `Error()' indicator, so to simulate `IsOk()'...
361        */
362       return ! Error();
363     }
364     inline pkgXmlNode* GetRoot()
365     {
366       /* This is wxXmlDocument's method for locating the document root;
367        * it is equivalent to tinyxml's RootElement() method.
368        */
369       return (pkgXmlNode *)(RootElement());
370     }
371     inline void AddDeclaration
372     ( const char *version, const char *encoding, const char *standalone )
373     {
374       /* Not a standard method of either wxXmlDocumemnt or TiXmlDocument;
375        * this is a convenience method for setting up a new XML database.
376        */
377       LinkEndChild( new TiXmlDeclaration( version, encoding, standalone ) );
378     }
379     inline void SetRoot( TiXmlNode* root )
380     {
381       /* tinyxml has no direct equivalent for this wxXmlDocument method;
382        * to emulate it, we must first explicitly delete an existing root
383        * node, if any, then link the new root node as a document child.
384        */
385       pkgXmlNode *oldroot;
386       if( (oldroot = GetRoot()) != NULL )
387         delete oldroot;
388       LinkEndChild( root );
389     }
390     inline bool Save( const char *filename )
391     {
392       /* This wxXmlDocument method for saving the database is equivalent
393        * to the corresponding tinyxml SaveFile( const char* ) method.
394        */
395       return SaveFile( filename );
396     }
397
398   private:
399     /* Properties specifying the schedule of actions.
400      */
401     unsigned long request;
402     pkgActionItem* actions;
403
404   public:
405     /* Method to interpret user preferences for mingw-get processing
406      * options, which are specified within profile.xml rather than on
407      * the command line.
408      */
409     void EstablishPreferences( const char* = NULL );
410
411     /* Method to synchronise the state of the local package manifest
412      * with the master copy held on the distribution server.
413      */
414     void SyncRepository( const char*, pkgXmlNode* );
415
416     /* Method to merge content from repository-specific package lists
417      * into the central XML package database.
418      */
419     pkgXmlNode* BindRepositories( bool );
420
421     /* Method to load the system map, and the lists of installed
422      * packages associated with each specified sysroot.
423      */
424     void LoadSystemMap();
425
426     /* Complementary method, to update the saved sysroot data associated
427      * with the active system map.
428      */
429     void UpdateSystemMap();
430
431     /* Method to locate the XML database entry for a named package.
432      */
433     pkgXmlNode* FindPackageByName( const char*, const char* = NULL );
434
435     /* Methods to retrieve and display information about packages.
436      */
437     pkgDirectory *CatalogueAllPackages();
438     void DisplayPackageInfo( int, char** );
439
440     /* Method to resolve the dependencies of a specified package,
441      * by walking the chain of references specified by "requires"
442      * elements in the respective package database entries.
443      */
444     void ResolveDependencies( pkgXmlNode*, pkgActionItem* = NULL );
445
446     /* Methods for compiling a schedule of actions.
447      */
448     pkgActionItem* Schedule( unsigned long = 0UL, const char* = NULL );
449     pkgActionItem* Schedule( unsigned long, pkgActionItem&, pkgActionItem* = NULL );
450     void RescheduleInstalledPackages( unsigned long );
451
452     /* Method to execute a sequence of scheduled actions.
453      */
454     inline void ExecuteActions(){ if( actions ) actions->Execute(); }
455
456     /* Method to clear the list of scheduled actions.
457      */
458     inline pkgActionItem* ClearScheduledActions( unsigned long mask = 0UL )
459     {
460       return actions = actions->Clear( mask );
461     }
462
463     /* Methods to retrieve and optionally extract source archives
464      * for a collection of dependent packages.
465      */
466     void GetSourceArchive( const char*, unsigned long );
467     inline void GetScheduledSourceArchives( unsigned long category )
468     {
469       actions->GetScheduledSourceArchives( category );
470     }
471
472   /* Facility for monitoring of XML document processing operations.
473    */
474   private:
475     pkgProgressMeter* progress_meter;
476
477   public:
478     inline pkgProgressMeter *ProgressMeter( void )
479     {
480       return progress_meter;
481     }
482     inline pkgProgressMeter *AttachProgressMeter( pkgProgressMeter *attachment )
483     {
484       if( progress_meter == NULL )
485         progress_meter = attachment;
486       return progress_meter;
487     }
488     inline void DetachProgressMeter( pkgProgressMeter *attachment )
489     {
490       if( attachment == progress_meter )
491         progress_meter = NULL;
492     }
493 };
494
495 EXTERN_C const char *xmlfile( const char*, const char* = NULL );
496 EXTERN_C int has_keyword( const char*, const char* );
497
498 #undef  USES_SAFE_STRCMP
499 #define USES_SAFE_STRCMP  1
500
501 #endif /* PACKAGE_BASE_COMPONENT */
502
503 #if USES_SAFE_STRCMP && ! HAVE_SAFE_STRCMP
504
505 typedef int (*strcmp_function)( const char *, const char * );
506
507 static inline
508 bool safe_strcmp( strcmp_function strcmp, const char *value, const char *proto )
509 {
510   /* Helper to compare a pair of "C" strings for equality,
511    * accepting NULL as a match for anything; for non-NULL matches,
512    * case sensitivity is determined by choice of strcmp function.
513    *
514    * N.B. Unlike the 'strcmp' function which this calls, this is
515    * a boolean function, returning TRUE when the 'strcmp' result
516    * is zero, (i.e. the sense of the result is inverted).
517    */
518   return (value == NULL) || (proto == NULL) || (strcmp( value, proto ) == 0);
519 }
520
521 /* Define a safe_strcmp() alias for an explicitly case sensitive match.
522  */
523 #define match_if_explicit( A, B )  safe_strcmp( strcmp, (A), (B) )
524
525 /* Further safe_strcmp() aliases provide for matching subsystem names,
526  * with implementation dependent case sensitivity...
527  */
528 #ifdef _WIN32
529   /* The MS-Windows file system is intrinsically case insensitive,
530    * so we prefer to match both subsystem and file names in a case
531    * insensitive manner...
532    */
533 # ifndef CASE_INSENSITIVE_SUBSYSTEMS
534 #  define CASE_INSENSITIVE_SUBSYSTEMS  1
535 # endif
536 # ifndef CASE_INSENSITIVE_FILESYSTEM
537 #  define CASE_INSENSITIVE_FILESYSTEM  1
538 # endif
539 # ifndef __MINGW32__
540   /* The preferred name for MS-Windows' case insensitive string
541    * matching function, equivalent to POSIX strcasecmp(); MinGW's
542    * string.h will have established this mapping already, so we
543    * don't introduce a (possibly incompatible) redefinition.
544    */
545 #  define strcasecmp _stricmp
546 # endif
547 #else
548   /* On other systems, we prefer to adopt case sensitive matching
549    * strategies for subsystem and file names.
550    */
551 # ifndef CASE_INSENSITIVE_SUBSYSTEMS
552 #  define CASE_INSENSITIVE_SUBSYSTEMS  0
553 # endif
554 # ifndef CASE_INSENSITIVE_FILESYSTEM
555 #  define CASE_INSENSITIVE_FILESYSTEM  0
556 # endif
557 #endif
558
559 #if CASE_INSENSITIVE_SUBSYSTEMS
560 # define subsystem_strcmp( A, B )  safe_strcmp( strcasecmp, (A), (B) )
561 #else
562 # define subsystem_strcmp( A, B )  safe_strcmp( strcmp, (A), (B) )
563 #endif
564
565 /* ...and similarly, for matching of file names.
566  */
567 #if CASE_INSENSITIVE_FILESYSTEM
568 # define pkg_strcmp( A, B )  safe_strcmp( strcasecmp, (A), (B) )
569 #else
570 # define pkg_strcmp( A, B )  safe_strcmp( strcmp, (A), (B) )
571 #endif
572
573 #undef  HAVE_SAFE_STRCMP
574 #define HAVE_SAFE_STRCMP  1
575 #endif
576
577
578 #endif /* PKGBASE_H: $RCSfile$: end of file */