subsystems/library_manager.hpp

    1: #ifndef STLPLUS_LIBRARY_MANAGER
    2: #define STLPLUS_LIBRARY_MANAGER
    3: ////////////////////////////////////////////////////////////////////////////////
    4: 
    5: //   Author:    Andy Rushton
    6: //   Copyright: (c) Andy Rushton, 2007
    7: //   License:   BSD License, see ../docs/license.html
    8: 
    9: //   Generalised library manager.
   10: 
   11: //   Manages library units in a set of library directories. A unit is both a file
   12: //   on-disk and a data-structure in memory. To use the library manager, you need
   13: //   to:
   14: 
   15: //     - design a type based on lm_unit with serialising functions read/write 
   16: //     - decide on a file extension for the type
   17: //     - decide on a description of the type
   18: //     - write a create callback for this type
   19: //     - register the file extension, description and callback with the library manager
   20: 
   21: ////////////////////////////////////////////////////////////////////////////////
   22: #include "subsystems_fixes.hpp"
   23: #include "ini_manager.hpp"
   24: #include "smart_ptr.hpp"
   25: #include <iostream>
   26: #include <string>
   27: #include <vector>
   28: #include <list>
   29: #include <map>
   30: #include <time.h>
   31: 
   32: namespace stlplus
   33: {
   34: 
   35:   ////////////////////////////////////////////////////////////////////////////////
   36:   // Internals
   37:   ////////////////////////////////////////////////////////////////////////////////
   38: 
   39:   class lm_library;
   40:   class library_manager;
   41: 
   42:   ////////////////////////////////////////////////////////////////////////////////
   43:   // unit names
   44:   ////////////////////////////////////////////////////////////////////////////////
   45: 
   46:   class lm_unit_name
   47:   {
   48:   public:
   49:     lm_unit_name(const std::string& name = std::string(), const std::string& type = std::string());
   50:     ~lm_unit_name(void);
   51: 
   52:     const std::string& name(void) const;
   53:     void set_name(const std::string& name);
   54:     void lowercase(void);
   55: 
   56:     const std::string& type(void) const;
   57:     void set_type(const std::string& type);
   58: 
   59:     bool write(std::ostream& context) const;
   60:     bool read(std::istream& context);
   61: 
   62:     std::string to_string(void) const;
   63:     bool print(std::ostream&) const;
   64: 
   65:   private:
   66:     std::string m_name;
   67:     std::string m_type;
   68:   };
   69: 
   70:   std::ostream& operator << (std::ostream&, const lm_unit_name&);
   71:   bool operator == (const lm_unit_name& l, const lm_unit_name& r);
   72:   bool operator < (const lm_unit_name& l, const lm_unit_name& r);
   73: 
   74:   ////////////////////////////////////////////////////////////////////////////////
   75:   // dependencies
   76:   ////////////////////////////////////////////////////////////////////////////////
   77: 
   78:   // dependencies on external files
   79: 
   80:   class lm_file_dependency
   81:   {
   82:   public:
   83:     lm_file_dependency(void);
   84:     lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line = 0, unsigned column = 0);
   85:     ~lm_file_dependency(void);
   86: 
   87:     // a path can be retrieved as either a relative path to the library or as a
   88:     // full path by providing the library path as an argument
   89:     const std::string& path(void) const;
   90:     std::string path_full(const std::string& library_path) const;
   91:     void set_path(const std::string& library_path, const std::string& path);
   92: 
   93:     unsigned line(void) const;
   94:     void set_line(unsigned line = 0);
   95: 
   96:     unsigned column(void) const;
   97:     void set_column(unsigned column = 0);
   98: 
   99:     bool write(std::ostream& context) const;
  100:     bool read(std::istream& context);
  101: 
  102:     bool print(std::ostream&) const;
  103: 
  104:   private:
  105:     std::string m_path; // file dependencies are stored as paths relative to the containing library
  106:     unsigned m_line;    // line - starts at 1, 0 means no line/column information
  107:     unsigned m_column;  // column - starts at 0
  108:   };
  109: 
  110:   std::ostream& operator <<(std::ostream&, const lm_file_dependency&);
  111: 
  112:   // dependencies on other units
  113: 
  114:   class lm_unit_dependency
  115:   {
  116:   public:
  117:     lm_unit_dependency(void);
  118:     lm_unit_dependency(const std::string& library, const lm_unit_name& name);
  119:     ~lm_unit_dependency(void);
  120: 
  121:     const std::string& library(void) const;
  122:     void set_library(const std::string& library);
  123: 
  124:     const lm_unit_name& unit_name(void) const;
  125:     void set_unit_name(const lm_unit_name& unit_name);
  126: 
  127:     const std::string& name(void) const;
  128:     void set_name(const std::string& name);
  129: 
  130:     const std::string& type(void) const;
  131:     void set_type(const std::string& type);
  132: 
  133:     bool write(std::ostream& context) const;
  134:     bool read(std::istream& context);
  135: 
  136:     bool print(std::ostream&) const;
  137: 
  138:   private:
  139:     std::string m_library;
  140:     lm_unit_name m_name;
  141:   };
  142: 
  143:   std::ostream& operator<<(std::ostream&, const lm_unit_dependency&);
  144: 
  145:   // the set of all dependencies
  146: 
  147:   class lm_dependencies
  148:   {
  149:   public:
  150:     lm_dependencies(void);
  151:     lm_dependencies(const lm_dependencies&);
  152:     lm_dependencies& operator=(const lm_dependencies&);
  153:     ~lm_dependencies(void);
  154: 
  155:     // source file dependency
  156:     void set_source_file(const lm_file_dependency&);
  157:     bool source_file_present(void) const;
  158:     const lm_file_dependency& source_file(void) const;
  159: 
  160:     // other file dependencies
  161:     unsigned file_add(const lm_file_dependency& dependency);
  162:     unsigned file_size(void) const;
  163:     const lm_file_dependency& file_dependency(unsigned) const;
  164:     void file_erase(unsigned);
  165: 
  166:     // unit dependencies
  167:     unsigned unit_add(const lm_unit_dependency& dependency);
  168:     unsigned unit_size(void) const;
  169:     const lm_unit_dependency& unit_dependency(unsigned) const;
  170:     void unit_erase(unsigned);
  171: 
  172:     void clear(void);
  173:     bool empty(void) const;
  174: 
  175:     bool write(std::ostream& context) const;
  176:     bool read(std::istream& context);
  177: 
  178:     bool print(std::ostream&) const;
  179: 
  180:   private:
  181:     lm_file_dependency* m_source;            // source file dependency (optional)
  182:     std::vector<lm_file_dependency> m_files; // other file dependencies
  183:     std::vector<lm_unit_dependency> m_units; // unit dependencies
  184:   };
  185: 
  186:   std::ostream& operator << (std::ostream&, const lm_dependencies&);
  187: 
  188:   ////////////////////////////////////////////////////////////////////////////////
  189:   // library unit superclass
  190:   // user's units must be derivatives of lm_unit and overload all the virtuals
  191: 
  192:   class lm_unit
  193:   {
  194:     friend class lm_library;
  195:   public:
  196:     ////////////////////////////////////////
  197:     // constructor/destructor
  198: 
  199:     lm_unit(const lm_unit_name& name, lm_library* library);
  200:     virtual ~lm_unit(void);
  201: 
  202:     ////////////////////////////////////////
  203:     // Header data
  204: 
  205:     // unit name
  206:     const lm_unit_name& unit_name(void) const;
  207:     const std::string& name(void) const;
  208:     const std::string& type(void) const;
  209: 
  210:     // dependencies
  211:     // all file dependencies are converted for internal use to a path relative to the library
  212:     // they can be retrieved either in this form or as a full path
  213: 
  214:     // source file dependency
  215:     void set_source_file(const lm_file_dependency&);
  216:     bool source_file_present(void) const;
  217:     const lm_file_dependency& source_file(void) const;
  218: 
  219:     // other file dependencies
  220:     unsigned file_add(const lm_file_dependency& dependency);
  221:     unsigned file_size(void) const;
  222:     const lm_file_dependency& file_dependency(unsigned) const;
  223:     void file_erase(unsigned);
  224: 
  225:     // unit dependencies
  226:     unsigned unit_add(const lm_unit_dependency& dependency);
  227:     unsigned unit_size(void) const;
  228:     const lm_unit_dependency& unit_dependency(unsigned) const;
  229:     void unit_erase(unsigned);
  230: 
  231:     const lm_dependencies& dependencies(void) const;
  232:     void set_dependencies(const lm_dependencies&);
  233:     void clear_dependencies(void);
  234:     bool empty_dependencies(void) const;
  235: 
  236:     // dependency checking
  237: 
  238:     bool out_of_date(void) const;
  239:     bool up_to_date(void) const;
  240:     lm_dependencies out_of_date_reason(void) const;
  241: 
  242:     // supplementary data
  243: 
  244:     const std::string& supplementary_data(void) const;
  245:     void set_supplementary_data(const std::string& data);
  246: 
  247:     ////////////////////////////////////////
  248:     // unit data management
  249: 
  250:     bool load(void);
  251:     bool save(void);
  252:     bool loaded(void) const;
  253:     void mark(void);
  254: 
  255:     // file modified time - only changes after a save
  256: 
  257:     time_t modified(void) const;
  258: 
  259:     ////////////////////////////////////////
  260:     // containing library manager details
  261: 
  262:     // get the owning library
  263:     const lm_library* library(void) const;
  264:     lm_library* library(void);
  265: 
  266:     // owning library name and path
  267:     const std::string& library_name(void) const;
  268:     const std::string& library_path(void) const;
  269: 
  270:     ////////////////////////////////////////
  271:     // error handling - these apply to the last read/write operation
  272: 
  273:     bool error(void) const;
  274: 
  275:     ////////////////////////////////////////
  276:     // functions that customise subclasses of this superclass
  277:     // You MUST provide at least:
  278:     //   - read - either read operation can be overloaded
  279:     //   - write - either write operation can be overloaded
  280:     //   - clone
  281: 
  282:     // read(filename) is the one actually called to read your data
  283:     // the default read(filename) simply calls read(istream) to actually read the file
  284:     // the default read(istream) does nothing but fail by returning false so you must overload one or other
  285: 
  286:     // you can just overload read(istream) if you want to use IOstream, or you
  287:     // can overload read(filename) to use any I/O system
  288: 
  289:     virtual bool read(const std::string& filename, void* type_data);
  290:     virtual bool read(std::istream& file, void* type_data);
  291: 
  292:     // as above, but for writing the data type
  293: 
  294:     // write(filename) is the one actually called to write your data
  295:     // the default write(filename) simply calls write(ostream) to actually write the file
  296:     // the default write(ostream) does nothing but fail by returning false so you must overload one or other
  297: 
  298:     // you can just overload write(ostream) if you want to use IOstream, or you
  299:     // can overload write(filename) to use any I/O system
  300: 
  301:     virtual bool write(const std::string& filename, void* type_data);
  302:     virtual bool write(std::ostream& file, void* type_data);
  303: 
  304:     // purge clears any memory associated with the unit - makes the unit unloaded
  305:     // the default does nothing
  306:     virtual bool purge(void);
  307: 
  308:     // the clone function creates a new-ed copy of the subclass
  309:     virtual lm_unit* clone(void) const;
  310: 
  311:     // the default print routines print header-only information
  312:     // you can overload these to provide a debug printout of the data structure
  313:     virtual bool print(std::ostream&) const;
  314:     virtual bool print_long(std::ostream&) const;
  315: 
  316:   protected:
  317:     // header file management
  318:     std::string filename(void) const;
  319:     std::string header_filename(void) const;
  320:     bool write_header(void);
  321:     bool read_header(void);
  322: 
  323:   private:
  324:     // header fields
  325:     lm_unit_name m_name;            // name
  326:     lm_dependencies m_dependencies; // file and unit dependencies
  327:     std::string m_supplement;       // supplementary data
  328:     bool m_header_modified;         // header modified
  329: 
  330:     // internal fields
  331:     bool m_loaded;                  // loaded flag
  332:     bool m_marked;                  // mark - determines whether the unit needs saving
  333: 
  334:     // library manager fields
  335:     lm_library* m_library;          // parent library
  336: 
  337:     // error handling fields
  338:     bool m_error;                    // error flag if load or save fails - from IOstream
  339:   };
  340: 
  341:   // Iostream print calls the short print method
  342:   std::ostream& operator << (std::ostream& str, const lm_unit& u);
  343: 
  344:   ////////////////////////////////////////////////////////////////////////////////
  345:   // other types used in the library manager
  346:   ////////////////////////////////////////////////////////////////////////////////
  347: 
  348:   // user types
  349: 
  350:   typedef smart_ptr_nocopy<lm_unit> lm_unit_ptr;
  351:   typedef lm_unit* (*lm_create_callback)(const lm_unit_name& unit_name, lm_library* parent_library, void* type_data);
  352: 
  353:   // internal types used in the library manager but made global because they are shared
  354: 
  355:   struct lm_callback_entry
  356:   {
  357:     lm_create_callback m_callback;
  358:     std::string m_description;
  359:     void* m_type_data;
  360: 
  361:     lm_callback_entry(lm_create_callback callback = 0, const std::string& description = std::string(), void* type_data = 0) :
  362:       m_callback(callback), m_description(description), m_type_data(type_data) {}
  363:   };
  364: 
  365:   ////////////////////////////////////////////////////////////////////////////////
  366:   // Library
  367:   // Must be contained in a library_manager
  368:   // Manages objects of class lm_unit and its subclasses
  369:   ////////////////////////////////////////////////////////////////////////////////
  370: 
  371:   class lm_library
  372:   {
  373:   public:
  374:     friend class library_manager;
  375:     friend class lm_unit;
  376: 
  377:     //////////////////////////////////////////////////////////////////////////////
  378:     // constructors/destructor - lm_library should only ever be constructed by library_manager
  379: 
  380:     lm_library(library_manager* manager);
  381:     lm_library(const lm_library&);
  382:     lm_library& operator = (const lm_library&);
  383:     ~lm_library(void);
  384: 
  385:   public:
  386: 
  387:     const library_manager* manager(void) const;
  388:     library_manager* manager(void);
  389: 
  390:     //////////////////////////////////////////////////////////////////////////////
  391:     // initialisers
  392: 
  393:     bool create(const std::string& name, const std::string& path, bool writable);
  394:     bool open(const std::string& path);
  395: 
  396:     //////////////////////////////////////////////////////////////////////////////
  397:     // management of types
  398: 
  399:     bool load_type(const std::string& type);
  400:     bool load_types(void);
  401:     bool remove_type(const std::string& type);
  402: 
  403:     //////////////////////////////////////////////////////////////////////////////
  404:     // whole library operations
  405: 
  406:     bool load(void);
  407:     bool save(void);
  408:     bool purge(void);
  409:     bool close(void);
  410:     bool erase(void);
  411: 
  412:     const std::string& name(void) const;
  413:     const std::string& path(void) const;
  414: 
  415:     //////////////////////////////////////////////////////////////////////////////
  416:     // managing read/write status
  417: 
  418:     bool set_read_write(bool writable);
  419:     bool set_writable(void);
  420:     bool set_read_only(void);
  421:     bool writable(void) const;
  422:     bool read_only(void) const;
  423:     bool os_writable(void) const;
  424:     bool os_read_only(void) const;
  425:     bool lm_writable(void) const;
  426:     bool lm_read_only(void) const;
  427: 
  428:     //////////////////////////////////////////////////////////////////////////////
  429:     // unit management
  430: 
  431:     bool exists(const lm_unit_name& name) const;
  432:     lm_unit_ptr create(const lm_unit_name&);
  433:     bool loaded(const lm_unit_name& name) const;
  434:     bool load(const lm_unit_name& unit);
  435:     bool purge(const lm_unit_name& unit);
  436:     bool save(const lm_unit_name& unit);
  437:     bool erase(const lm_unit_name& name);
  438:     bool mark(const lm_unit_name& name);
  439:     time_t modified(const lm_unit_name& name) const;
  440: 
  441:     bool erase_by_source(const std::string& source_file);
  442: 
  443:     const lm_unit_ptr find(const lm_unit_name& name) const;
  444:     lm_unit_ptr find(const lm_unit_name& name);
  445: 
  446:     std::vector<lm_unit_name> names(void) const;
  447:     std::vector<std::string> names(const std::string& type) const;
  448:     std::vector<lm_unit_ptr> handles(void) const;
  449:     std::vector<lm_unit_ptr> handles(const std::string& type) const;
  450: 
  451:     //////////////////////////////////////////////////////////////////////////////
  452:     // dependency checking
  453: 
  454:     bool out_of_date(const lm_unit_name& name) const;
  455:     bool up_to_date(const lm_unit_name& name) const;
  456:     lm_dependencies out_of_date_reason(const lm_unit_name& name) const;
  457: 
  458:     std::pair<bool,unsigned> tidy(void);
  459: 
  460:     //////////////////////////////////////////////////////////////////////////////
  461:     // do-everything print function
  462: 
  463:     bool pretty_print(std::ostream& str,
  464:                       bool print_units = false,                       // print the unit names not just the library names
  465:                       const std::string& type = std::string()) const; // print just this type ("" means all)
  466: 
  467:     ////////////////////////////////////////////////////////////////////////////////
  468:     // diagnostic print routines
  469: 
  470:     bool print(std::ostream& str) const;
  471:     bool print_long(std::ostream& str) const;
  472: 
  473:   private:
  474: 
  475:     std::map<lm_unit_name,lm_unit_ptr>::iterator local_find(const lm_unit_name& name);
  476:     std::map<lm_unit_name,lm_unit_ptr>::const_iterator local_find(const lm_unit_name& name) const;
  477: 
  478:     std::string m_name;                         // name
  479:     std::string m_path;                         // path
  480:     bool m_writable;                            // writable
  481:     std::map<lm_unit_name,lm_unit_ptr> m_units; // units
  482:     library_manager* m_manager;                 // parent library manager
  483:   };
  484: 
  485:   std::ostream& operator << (std::ostream& str, const lm_library& lib);
  486: 
  487:   ////////////////////////////////////////////////////////////////////////////////
  488:   // Library Manager
  489:   ////////////////////////////////////////////////////////////////////////////////
  490: 
  491:   class library_manager
  492:   {
  493:   public:
  494:     friend class lm_library;
  495:     friend class lm_unit;
  496: 
  497:     ////////////////////////////////////////////////////////////////////////////////
  498:     // static functions allow you to test whether a directory is a library before opening it
  499:     // you can also find the library's name without opening it
  500: 
  501:     static bool is_library(const std::string& path, const std::string& owner);
  502:     static std::string library_name(const std::string& path, const std::string& owner);
  503: 
  504:     // non-static forms test for libraries with the same owner as the library manager
  505: 
  506:     bool is_library(const std::string& path);
  507:     std::string library_name(const std::string& path);
  508: 
  509:     //////////////////////////////////////////////////////////////////////////////
  510:     // tructors
  511: 
  512:     explicit library_manager(const std::string& owner, bool library_case = false, bool unit_case = false);
  513:     ~library_manager(void);
  514: 
  515:     //////////////////////////////////////////////////////////////////////////////
  516:     // case sensitivity
  517: 
  518:     bool library_case(void) const;
  519:     void set_library_case(bool library_case);
  520: 
  521:     bool unit_case(void) const;
  522:     void set_unit_case(bool library_case);
  523: 
  524:     //////////////////////////////////////////////////////////////////////////////
  525:     // type handling
  526:     // only units of types added in this way will be recognised
  527: 
  528:     bool add_type(const std::string& type,
  529:                   const std::string& description,
  530:                   lm_create_callback fn = 0,
  531:                   void* type_data = 0);
  532:     bool remove_type(const std::string& type);
  533:     std::vector<std::string> types(void) const;
  534: 
  535:     std::string description(const std::string& type) const;
  536:     lm_create_callback callback(const std::string& type) const;
  537:     void* type_data(const std::string& type) const;
  538: 
  539:     //////////////////////////////////////////////////////////////////////////////
  540:     // Library mappings
  541:     // The library manager implements two different styles of library mappings
  542:     //   - mapping file
  543:     //   - ini file
  544:     // mapping file handling uses a simple text file to store the mappings in an internally-defined format
  545:     // ini file handling stores library mappings using the ini_manager component
  546:     // These modes are switched on by simply specifying a mapping file or an ini file to hold the mappings
  547: 
  548:     // mapping file methods
  549: 
  550:     // set but do not load - use this when you want to create a new mapping file
  551:     void set_mapping_file(const std::string& mapping_file);
  552:     // set and load - use this with an existing mapping file
  553:     bool load_mappings (const std::string& mapping_file);
  554:     // return the mapping file string
  555:     std::string mapping_file();
  556: 
  557:     // ini file methods - the ini manager must be pre-loaded with the list of ini files to manage
  558: 
  559:     // set and load - this will create the relevant sections in the local ini file if not present already
  560:     bool set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_section);
  561:     ini_manager* get_ini_manager(void) const;
  562: </