library_manager.hpp

    1: #ifndef LIBRARY_MANAGER_HPP
    2: #define LIBRARY_MANAGER_HPP
    3: /*------------------------------------------------------------------------------
    4: 
    5:   Author:    Andy Rushton
    6:   Copyright: (c) Andy Rushton, 2004
    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 "os_fixes.hpp"
   23: #include "smart_ptr.hpp"
   24: #include "textio.hpp"
   25: #include "persistent.hpp"
   26: #include "ini_manager.hpp"
   27: #include <string>
   28: #include <vector>
   29: #include <list>
   30: #include <map>
   31: #include <time.h>
   32: 
   33: ////////////////////////////////////////////////////////////////////////////////
   34: // Internals
   35: ////////////////////////////////////////////////////////////////////////////////
   36: 
   37: class lm_library;
   38: class library_manager;
   39: 
   40: ////////////////////////////////////////////////////////////////////////////////
   41: // unit names
   42: ////////////////////////////////////////////////////////////////////////////////
   43: 
   44: class lm_unit_name
   45: {
   46: public:
   47:   lm_unit_name(const std::string& name = std::string(), const std::string& type = std::string());
   48:   ~lm_unit_name(void);
   49: 
   50:   const std::string& name(void) const;
   51:   void set_name(const std::string& name);
   52:   void lowercase(void);
   53: 
   54:   const std::string& type(void) const;
   55:   void set_type(const std::string& type);
   56: 
   57:   friend void dump(dump_context& context, const lm_unit_name& name) throw(persistent_dump_failed);
   58:   friend void restore(restore_context& context, lm_unit_name& name) throw(persistent_restore_failed);
   59: 
   60:   friend std::string to_string(const lm_unit_name& name);
   61:   friend otext& print(otext&, const lm_unit_name&);
   62:   friend otext& operator << (otext&, const lm_unit_name&);
   63: 
   64:   friend bool operator == (const lm_unit_name& l, const lm_unit_name& r);
   65:   friend bool operator < (const lm_unit_name& l, const lm_unit_name& r);
   66: 
   67: private:
   68:   std::string m_name;
   69:   std::string m_type;
   70: };
   71: 
   72: // redefine friends for gcc v4.1
   73: void dump(dump_context& context, const lm_unit_name& name) throw(persistent_dump_failed);
   74: void restore(restore_context& context, lm_unit_name& name) throw(persistent_restore_failed);
   75: std::string to_string(const lm_unit_name& name);
   76: otext& print(otext&, const lm_unit_name&);
   77: otext& operator << (otext&, const lm_unit_name&);
   78: bool operator == (const lm_unit_name& l, const lm_unit_name& r);
   79: bool operator < (const lm_unit_name& l, const lm_unit_name& r);
   80: 
   81: ////////////////////////////////////////////////////////////////////////////////
   82: // dependencies
   83: ////////////////////////////////////////////////////////////////////////////////
   84: 
   85: // dependencies on external files
   86: 
   87: class lm_file_dependency
   88: {
   89: public:
   90:   lm_file_dependency(void);
   91:   lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line = 0, unsigned column = 0);
   92:   ~lm_file_dependency(void);
   93: 
   94:   // a path can be retrieved as either a relative path to the library or as a full path by providing the library path as an argument
   95:   const std::string& path(void) const;
   96:   std::string path_full(const std::string& library_path) const;
   97:   void set_path(const std::string& library_path, const std::string& path);
   98: 
   99:   unsigned line(void) const;
  100:   void set_line(unsigned line = 0);
  101: 
  102:   unsigned column(void) const;
  103:   void set_column(unsigned column = 0);
  104: 
  105:   friend void dump(dump_context& context, const lm_file_dependency&) throw(persistent_dump_failed);
  106:   friend void restore(restore_context& context, lm_file_dependency&) throw(persistent_restore_failed);
  107:   friend otext& print(otext&, const lm_file_dependency&);
  108:   friend otext& print(otext&, const lm_file_dependency&, unsigned indent);
  109:   friend otext& operator <<(otext&, const lm_file_dependency&);
  110: 
  111: private:
  112:   std::string m_path; // file dependencies are stored as paths relative to the containing library
  113:   unsigned m_line;    // line - starts at 1, 0 means no line/column information
  114:   unsigned m_column;  // column - starts at 0
  115: };
  116: 
  117: // redefine friends for gcc v4.1
  118: void dump(dump_context& context, const lm_file_dependency&) throw(persistent_dump_failed);
  119: void restore(restore_context& context, lm_file_dependency&) throw(persistent_restore_failed);
  120: otext& print(otext&, const lm_file_dependency&);
  121: otext& print(otext&, const lm_file_dependency&, unsigned indent);
  122: otext& operator <<(otext&, const lm_file_dependency&);
  123: 
  124: // dependencies on other units
  125: 
  126: class lm_unit_dependency
  127: {
  128: public:
  129:   lm_unit_dependency(void);
  130:   lm_unit_dependency(const std::string& library, const lm_unit_name& name);
  131:   ~lm_unit_dependency(void);
  132: 
  133:   const std::string& library(void) const;
  134:   void set_library(const std::string& library);
  135: 
  136:   const lm_unit_name& unit_name(void) const;
  137:   void set_unit_name(const lm_unit_name& unit_name);
  138: 
  139:   const std::string& name(void) const;
  140:   void set_name(const std::string& name);
  141: 
  142:   const std::string& type(void) const;
  143:   void set_type(const std::string& type);
  144: 
  145:   friend void dump(dump_context& context, const lm_unit_dependency&) throw(persistent_dump_failed);
  146:   friend void restore(restore_context& context, lm_unit_dependency&) throw(persistent_restore_failed);
  147:   friend otext& print(otext&, const lm_unit_dependency&);
  148:   friend otext& print(otext&, const lm_unit_dependency&, unsigned indent);
  149:   friend otext& operator<<(otext&, const lm_unit_dependency&);
  150: 
  151: private:
  152:   std::string m_library;
  153:   lm_unit_name m_name;
  154: };
  155: 
  156: // redefine friends for gcc v4.1
  157: void dump(dump_context& context, const lm_unit_dependency&) throw(persistent_dump_failed);
  158: void restore(restore_context& context, lm_unit_dependency&) throw(persistent_restore_failed);
  159: otext& print(otext&, const lm_unit_dependency&);
  160: otext& print(otext&, const lm_unit_dependency&, unsigned indent);
  161: otext& operator<<(otext&, const lm_unit_dependency&);
  162: 
  163: // the set of all dependencies
  164: 
  165: class lm_dependencies
  166: {
  167: public:
  168:   lm_dependencies(void);
  169:   ~lm_dependencies(void);
  170: 
  171:   // source file dependency
  172:   void set_source_file(const lm_file_dependency&);
  173:   bool source_file_present(void) const;
  174:   const lm_file_dependency& source_file(void) const;
  175: 
  176:   // other file dependencies
  177:   unsigned file_add(const lm_file_dependency& dependency);
  178:   unsigned file_size(void) const;
  179:   const lm_file_dependency& file_dependency(unsigned) const;
  180:   void file_erase(unsigned);
  181: 
  182:   // unit dependencies
  183:   unsigned unit_add(const lm_unit_dependency& dependency);
  184:   unsigned unit_size(void) const;
  185:   const lm_unit_dependency& unit_dependency(unsigned) const;
  186:   void unit_erase(unsigned);
  187: 
  188:   void clear(void);
  189:   bool empty(void) const;
  190: 
  191:   // persistence
  192:   friend void dump(dump_context& context, const lm_dependencies&) throw(persistent_dump_failed);
  193:   friend void restore(restore_context& context, lm_dependencies&) throw(persistent_restore_failed);
  194: 
  195:   // diagnostic print routines
  196:   friend otext& print(otext&, const lm_dependencies&, unsigned indent = 0);
  197:   friend otext& operator << (otext&, const lm_dependencies&);
  198: 
  199: private:
  200:   smart_ptr<lm_file_dependency> m_source;  // source file dependency (optional)
  201:   std::vector<lm_file_dependency> m_files; // other file dependencies
  202:   std::vector<lm_unit_dependency> m_units; // unit dependencies
  203: };
  204: 
  205: // redefine friends for gcc v4.1
  206: void dump(dump_context& context, const lm_dependencies&) throw(persistent_dump_failed);
  207: void restore(restore_context& context, lm_dependencies&) throw(persistent_restore_failed);
  208: otext& print(otext&, const lm_dependencies&, unsigned indent);
  209: otext& operator << (otext&, const lm_dependencies&);
  210: 
  211: ////////////////////////////////////////////////////////////////////////////////
  212: // library unit superclass
  213: // All units must be contained in an lm_library object
  214: 
  215: class lm_unit
  216: {
  217:   friend class lm_library;
  218: public:
  219:   ////////////////////////////////////////
  220:   // constructor/destructor
  221: 
  222:   lm_unit(const lm_unit_name& name, lm_library* library);
  223:   virtual ~lm_unit(void);
  224: 
  225:   ////////////////////////////////////////
  226:   // Header data
  227: 
  228:   // unit name
  229:   const lm_unit_name& unit_name(void) const;
  230:   const std::string& name(void) const;
  231:   const std::string& type(void) const;
  232: 
  233:   // dependencies
  234:   // all file dependencies are converted for internal use to a path relative to the library
  235:   // they can be retrieved either in this form or as a full path
  236: 
  237:   // source file dependency
  238:   void set_source_file(const lm_file_dependency&);
  239:   bool source_file_present(void) const;
  240:   const lm_file_dependency& source_file(void) const;
  241: 
  242:   // other file dependencies
  243:   unsigned file_add(const lm_file_dependency& dependency);
  244:   unsigned file_size(void) const;
  245:   const lm_file_dependency& file_dependency(unsigned) const;
  246:   void file_erase(unsigned);
  247: 
  248:   // unit dependencies
  249:   unsigned unit_add(const lm_unit_dependency& dependency);
  250:   unsigned unit_size(void) const;
  251:   const lm_unit_dependency& unit_dependency(unsigned) const;
  252:   void unit_erase(unsigned);
  253: 
  254:   const lm_dependencies& dependencies(void) const;
  255:   void set_dependencies(const lm_dependencies&);
  256:   void clear_dependencies(void);
  257:   bool empty_dependencies(void) const;
  258: 
  259:   // dependency checking
  260: 
  261:   bool out_of_date(void) const;
  262:   bool up_to_date(void) const;
  263:   lm_dependencies out_of_date_reason(void) const;
  264: 
  265:   // supplementary data
  266: 
  267:   const std::string& supplementary_data(void) const;
  268:   void set_supplementary_data(const std::string& data);
  269: 
  270:   ////////////////////////////////////////
  271:   // unit data management
  272: 
  273:   bool load(void);
  274:   bool save(void);
  275:   bool loaded(void) const;
  276:   void mark(void);
  277: 
  278:   // file modified time - only changes after a save
  279: 
  280:   time_t modified(void) const;
  281: 
  282:   ////////////////////////////////////////
  283:   // containing library manager details
  284: 
  285:   // get the owning library
  286:   const lm_library* library(void) const;
  287:   lm_library* library(void);
  288: 
  289:   // owning library name and path
  290:   const std::string& library_name(void) const;
  291:   const std::string& library_path(void) const;
  292: 
  293:   ////////////////////////////////////////
  294:   // error handling - these apply to the last read/write operation
  295: 
  296:   bool error(void) const;
  297:   int error_number(void) const;
  298:   std::string error_string(void) const;
  299: 
  300:   ////////////////////////////////////////
  301:   // print diagnostics
  302:   // these call the print methods which may be overloaded for each subclass
  303: 
  304:   friend otext& print(otext& str, const lm_unit& u);
  305:   friend otext& print_long(otext& str, const lm_unit& u, unsigned indent);
  306:   friend otext& operator << (otext& str, const lm_unit& u);
  307: 
  308:   ////////////////////////////////////////
  309:   // functions that customise subclasses of this superclass
  310:   // You MUST provide at least:
  311:   //   - read - either read operation can be overloaded
  312:   //   - write - either write operation can be overloaded
  313:   //   - clone
  314: 
  315:   // the default read(filename) calls read(itext) to actually read the file
  316:   // you can just overload read(itext) if you want to use TextIO, or you can overload read(filename) to use any I/O system
  317:   // the default read(itext) does nothing but fail by returning false so you must overload one or other
  318:   virtual bool read(const std::string& filename, void* type_data);
  319:   virtual bool read(itext& file, void* type_data);
  320: 
  321:   // as above, write(filename) calls write(otext) to actually write the file
  322:   // you can just overload write(otext) if you want to use TextIO, or you can overload write(filename) to use any I/O system
  323:   // the default write(otext) does nothing but fail by returning false so you must overload one or other
  324:   virtual bool write(const std::string& filename, void* type_data);
  325:   virtual bool write(otext& file, void* type_data);
  326: 
  327:   // purge clears any memory associated with the unit - makes the unit unloaded
  328:   // the default does nothing
  329:   virtual bool purge(void);
  330: 
  331:   // the clone function creates a copy of the subclass - see the docs on smart_ptr for an explanation
  332:   virtual lm_unit* clone(void) const;
  333: 
  334:   // the default print routines print header-only information
  335:   // you can overload these to provide a debug dump of the data structure
  336:   virtual otext& print(otext&) const;
  337:   virtual otext& print_long(otext&, unsigned indent = 0) const;
  338: 
  339: protected:
  340:   // header file management
  341:   std::string filename(void) const;
  342:   std::string header_filename(void) const;
  343:   bool dump_header(void);
  344:   bool restore_header(void);
  345: 
  346: private:
  347:   // header fields
  348:   lm_unit_name m_name;            // name
  349:   lm_dependencies m_dependencies; // file and unit dependencies
  350:   std::string m_supplement;       // supplementary data
  351:   bool m_header_modified;         // header modified
  352: 
  353:   // internal fields
  354:   bool m_loaded;                  // loaded flag
  355:   bool m_marked;                  // mark - determines whether the unit needs saving
  356: 
  357:   // library manager fields
  358:   lm_library* m_library;          // parent library
  359: 
  360:   // error handling fields
  361:   int m_error;                    // error code if load or save fails
  362:   std::string m_error_string;     // string part of above error status
  363: };
  364: 
  365: // redefine friends for gcc v4.1
  366: otext& print(otext& str, const lm_unit& u);
  367: otext& print_long(otext& str, const lm_unit& u, unsigned indent);
  368: otext& operator << (otext& str, const lm_unit& u);
  369: 
  370: ////////////////////////////////////////////////////////////////////////////////
  371: // other types used in the library manager
  372: ////////////////////////////////////////////////////////////////////////////////
  373: 
  374: // user types
  375: 
  376: typedef smart_ptr_nocopy<lm_unit> lm_unit_ptr;
  377: typedef lm_unit* (*lm_create_callback)(const lm_unit_name& unit_name, lm_library* parent_library, void* type_data);
  378: 
  379: // internal types used in the library manager but made global because they are shared
  380: 
  381: struct lm_callback_entry
  382: {
  383:   lm_create_callback m_callback;
  384:   std::string m_description;
  385:   void* m_type_data;
  386: 
  387:   lm_callback_entry(lm_create_callback callback = 0, const std::string& description = std::string(), void* type_data = 0) :
  388:     m_callback(callback), m_description(description), m_type_data(type_data) {}
  389: };
  390: 
  391: typedef std::map<std::string,lm_callback_entry> lm_callback_map;
  392: 
  393: typedef std::pair<bool,unsigned> lm_tidy_result;
  394: 
  395: ////////////////////////////////////////////////////////////////////////////////
  396: // Library
  397: // Must be contained in a library_manager
  398: // Manages objects of class lm_unit and its subclasses
  399: ////////////////////////////////////////////////////////////////////////////////
  400: 
  401: class lm_library
  402: {
  403: public:
  404: 
  405:   friend class library_manager;
  406:   friend class lm_unit;
  407:   typedef std::map<lm_unit_name,lm_unit_ptr> unit_map;
  408: 
  409:   //////////////////////////////////////////////////////////////////////////////
  410:   // library management
  411: 
  412:   lm_library(library_manager* manager);
  413:   ~lm_library(void);
  414:   lm_library(const lm_library&);
  415:   lm_library& operator = (const lm_library&);
  416: 
  417:   const library_manager* manager(void) const;
  418:   library_manager* manager(void);
  419: 
  420:   //////////////////////////////////////////////////////////////////////////////
  421:   // initialisers
  422: 
  423:   bool create(const std::string& name, const std::string& path, bool writable);
  424:   bool open(const std::string& path);
  425: 
  426:   //////////////////////////////////////////////////////////////////////////////
  427:   // management of types
  428: 
  429:   bool load_type(const std::string& type);
  430:   bool load_types(void);
  431:   bool remove_type(const std::string& type);
  432: 
  433:   //////////////////////////////////////////////////////////////////////////////
  434:   // whole library operations
  435: 
  436:   bool load(void);
  437:   bool save(void);
  438:   bool purge(void);
  439:   bool close(void);
  440:   bool erase(void);
  441: 
  442:   const std::string& name(void) const;
  443:   const std::string& path(void) const;
  444: 
  445:   //////////////////////////////////////////////////////////////////////////////
  446:   // managing read/write status
  447: 
  448:   bool set_read_write(bool writable);
  449:   bool set_writable(void);
  450:   bool set_read_only(void);
  451:   bool writable(void) const;
  452:   bool read_only(void) const;
  453:   bool os_writable(void) const;
  454:   bool os_read_only(void) const;
  455:   bool lm_writable(void) const;
  456:   bool lm_read_only(void) const;
  457: 
  458:   //////////////////////////////////////////////////////////////////////////////
  459:   // unit management
  460: 
  461: private:
  462:   unit_map::iterator local_find(const lm_unit_name& name);
  463:   unit_map::const_iterator local_find(const lm_unit_name& name) const;
  464: 
  465: public:
  466:   bool exists(const lm_unit_name& name) const;
  467:   lm_unit_ptr create(const lm_unit_name&);
  468:   bool loaded(const lm_unit_name& name) const;
  469:   bool load(const lm_unit_name& unit);
  470:   bool purge(const lm_unit_name& unit);
  471:   bool save(const lm_unit_name& unit);
  472:   bool erase(const lm_unit_name& name);
  473:   bool mark(const lm_unit_name& name);
  474:   time_t modified(const lm_unit_name& name) const;
  475: 
  476:   bool erase_by_source(const std::string& source_file);
  477: 
  478:   const lm_unit_ptr find(const lm_unit_name& name) const;
  479:   lm_unit_ptr find(const lm_unit_name& name);
  480: 
  481:   std::vector<lm_unit_name> names(void) const;
  482:   std::vector<std::string> names(const std::string& type) const;
  483:   std::vector<lm_unit_ptr> handles(void) const;
  484:   std::vector<lm_unit_ptr> handles(const std::string& type) const;
  485: 
  486:   //////////////////////////////////////////////////////////////////////////////
  487:   // dependency checking
  488: 
  489:   bool out_of_date(const lm_unit_name& name) const;
  490:   bool up_to_date(const lm_unit_name& name) const;
  491:   lm_dependencies out_of_date_reason(const lm_unit_name& name) const;
  492: 
  493:   lm_tidy_result tidy(void);
  494: 
  495:   //////////////////////////////////////////////////////////////////////////////
  496:   // I/O
  497:   // do-everything print routine!
  498: 
  499:   bool pretty_print(otext& str, unsigned indent, bool print_units, const std::string& type) const;
  500: 
  501:   ////////////////////////////////////////////////////////////////////////////////
  502:   // diagnostic print routines
  503: 
  504:   otext& print(otext& str, unsigned indent = 0)