#ifndef STLPLUS_LIBRARY_MANAGER #define STLPLUS_LIBRARY_MANAGER //////////////////////////////////////////////////////////////////////////////// // Author: Andy Rushton // Copyright: (c) Southampton University 1999-2004 // (c) Andy Rushton 2004-2009 // License: BSD License, see ../docs/license.html // Generalised library manager. // Manages library units in a set of library directories. A unit is both a file // on-disk and a data-structure in memory. To use the library manager, you need // to: // - design a type based on lm_unit with serialising functions read/write // - decide on a file extension for the type // - decide on a description of the type // - write a create callback for this type // - register the file extension, description and callback with the library manager //////////////////////////////////////////////////////////////////////////////// #include "subsystems_fixes.hpp" #include "ini_manager.hpp" #include "smart_ptr.hpp" #include #include #include #include #include #include namespace stlplus { //////////////////////////////////////////////////////////////////////////////// // Internals //////////////////////////////////////////////////////////////////////////////// class lm_library; class library_manager; //////////////////////////////////////////////////////////////////////////////// // unit names //////////////////////////////////////////////////////////////////////////////// class lm_unit_name { public: lm_unit_name(const std::string& name = std::string(), const std::string& type = std::string()); ~lm_unit_name(void); const std::string& name(void) const; void set_name(const std::string& name); void lowercase(void); const std::string& type(void) const; void set_type(const std::string& type); bool write(std::ostream& context) const; bool read(std::istream& context); std::string to_string(void) const; bool print(std::ostream&) const; private: std::string m_name; std::string m_type; }; std::ostream& operator << (std::ostream&, const lm_unit_name&); bool operator == (const lm_unit_name& l, const lm_unit_name& r); bool operator < (const lm_unit_name& l, const lm_unit_name& r); //////////////////////////////////////////////////////////////////////////////// // dependencies //////////////////////////////////////////////////////////////////////////////// // dependencies on external files class lm_file_dependency { public: lm_file_dependency(void); lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line = 0, unsigned column = 0); ~lm_file_dependency(void); // 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 const std::string& path(void) const; std::string path_full(const std::string& library_path) const; void set_path(const std::string& library_path, const std::string& path); unsigned line(void) const; void set_line(unsigned line = 0); unsigned column(void) const; void set_column(unsigned column = 0); bool write(std::ostream& context) const; bool read(std::istream& context); bool print(std::ostream&) const; private: std::string m_path; // file dependencies are stored as paths relative to the containing library unsigned m_line; // line - starts at 1, 0 means no line/column information unsigned m_column; // column - starts at 0 }; std::ostream& operator <<(std::ostream&, const lm_file_dependency&); // dependencies on other units class lm_unit_dependency { public: lm_unit_dependency(void); lm_unit_dependency(const std::string& library, const lm_unit_name& name); ~lm_unit_dependency(void); const std::string& library(void) const; void set_library(const std::string& library); const lm_unit_name& unit_name(void) const; void set_unit_name(const lm_unit_name& unit_name); const std::string& name(void) const; void set_name(const std::string& name); const std::string& type(void) const; void set_type(const std::string& type); bool write(std::ostream& context) const; bool read(std::istream& context); bool print(std::ostream&) const; private: std::string m_library; lm_unit_name m_name; }; std::ostream& operator<<(std::ostream&, const lm_unit_dependency&); // the set of all dependencies class lm_dependencies { public: lm_dependencies(void); lm_dependencies(const lm_dependencies&); lm_dependencies& operator=(const lm_dependencies&); ~lm_dependencies(void); // source file dependency void set_source_file(const lm_file_dependency&); bool source_file_present(void) const; const lm_file_dependency& source_file(void) const; // other file dependencies unsigned file_add(const lm_file_dependency& dependency); unsigned file_size(void) const; const lm_file_dependency& file_dependency(unsigned) const; void file_erase(unsigned); // unit dependencies unsigned unit_add(const lm_unit_dependency& dependency); unsigned unit_size(void) const; const lm_unit_dependency& unit_dependency(unsigned) const; void unit_erase(unsigned); void clear(void); bool empty(void) const; bool write(std::ostream& context) const; bool read(std::istream& context); bool print(std::ostream&) const; private: lm_file_dependency* m_source; // source file dependency (optional) std::vector m_files; // other file dependencies std::vector m_units; // unit dependencies }; std::ostream& operator << (std::ostream&, const lm_dependencies&); //////////////////////////////////////////////////////////////////////////////// // library unit superclass // user's units must be derivatives of lm_unit and overload all the virtuals class lm_unit { friend class lm_library; public: //////////////////////////////////////// // constructor/destructor lm_unit(const lm_unit_name& name, lm_library* library); virtual ~lm_unit(void); //////////////////////////////////////// // Header data // unit name const lm_unit_name& unit_name(void) const; const std::string& name(void) const; const std::string& type(void) const; // dependencies // all file dependencies are converted for internal use to a path relative to the library // they can be retrieved either in this form or as a full path // source file dependency void set_source_file(const lm_file_dependency&); bool source_file_present(void) const; const lm_file_dependency& source_file(void) const; // other file dependencies unsigned file_add(const lm_file_dependency& dependency); unsigned file_size(void) const; const lm_file_dependency& file_dependency(unsigned) const; void file_erase(unsigned); // unit dependencies unsigned unit_add(const lm_unit_dependency& dependency); unsigned unit_size(void) const; const lm_unit_dependency& unit_dependency(unsigned) const; void unit_erase(unsigned); const lm_dependencies& dependencies(void) const; void set_dependencies(const lm_dependencies&); void clear_dependencies(void); bool empty_dependencies(void) const; // dependency checking bool out_of_date(void) const; bool up_to_date(void) const; lm_dependencies out_of_date_reason(void) const; // supplementary data const std::string& supplementary_data(void) const; void set_supplementary_data(const std::string& data); //////////////////////////////////////// // unit data management bool load(void); bool save(void); bool loaded(void) const; void mark(void); // file modified time - only changes after a save time_t modified(void) const; //////////////////////////////////////// // containing library manager details // get the owning library const lm_library* library(void) const; lm_library* library(void); // owning library name and path const std::string& library_name(void) const; const std::string& library_path(void) const; //////////////////////////////////////// // error handling - these apply to the last read/write operation bool error(void) const; //////////////////////////////////////// // functions that customise subclasses of this superclass // You MUST provide at least: // - read - either read operation can be overloaded // - write - either write operation can be overloaded // - clone // read(filename) is the one actually called to read your data // the default read(filename) simply calls read(istream) to actually read the file // the default read(istream) does nothing but fail by returning false so you must overload one or other // you can just overload read(istream) if you want to use IOstream, or you // can overload read(filename) to use any I/O system virtual bool read(const std::string& filename, void* type_data); virtual bool read(std::istream& file, void* type_data); // as above, but for writing the data type // write(filename) is the one actually called to write your data // the default write(filename) simply calls write(ostream) to actually write the file // the default write(ostream) does nothing but fail by returning false so you must overload one or other // you can just overload write(ostream) if you want to use IOstream, or you // can overload write(filename) to use any I/O system virtual bool write(const std::string& filename, void* type_data); virtual bool write(std::ostream& file, void* type_data); // purge clears any memory associated with the unit - makes the unit unloaded // the default does nothing virtual bool purge(void); // the clone function creates a new-ed copy of the subclass virtual lm_unit* clone(void) const; // the default print routines print header-only information // you can overload these to provide a debug printout of the data structure virtual bool print(std::ostream&) const; virtual bool print_long(std::ostream&) const; protected: // header file management std::string filename(void) const; std::string header_filename(void) const; bool write_header(void); bool read_header(void); private: // header fields lm_unit_name m_name; // name lm_dependencies m_dependencies; // file and unit dependencies std::string m_supplement; // supplementary data bool m_header_modified; // header modified // internal fields bool m_loaded; // loaded flag bool m_marked; // mark - determines whether the unit needs saving // library manager fields lm_library* m_library; // parent library // error handling fields bool m_error; // error flag if load or save fails - from IOstream }; // Iostream print calls the short print method std::ostream& operator << (std::ostream& str, const lm_unit& u); //////////////////////////////////////////////////////////////////////////////// // other types used in the library manager //////////////////////////////////////////////////////////////////////////////// // user types typedef smart_ptr_nocopy lm_unit_ptr; typedef lm_unit* (*lm_create_callback)(const lm_unit_name& unit_name, lm_library* parent_library, void* type_data); // internal types used in the library manager but made global because they are shared struct lm_callback_entry { lm_create_callback m_callback; std::string m_description; void* m_type_data; lm_callback_entry(lm_create_callback callback = 0, const std::string& description = std::string(), void* type_data = 0) : m_callback(callback), m_description(description), m_type_data(type_data) {} }; //////////////////////////////////////////////////////////////////////////////// // Library // Must be contained in a library_manager // Manages objects of class lm_unit and its subclasses //////////////////////////////////////////////////////////////////////////////// class lm_library { public: friend class library_manager; friend class lm_unit; ////////////////////////////////////////////////////////////////////////////// // constructors/destructor - lm_library should only ever be constructed by library_manager lm_library(library_manager* manager); lm_library(const lm_library&); lm_library& operator = (const lm_library&); ~lm_library(void); public: const library_manager* manager(void) const; library_manager* manager(void); ////////////////////////////////////////////////////////////////////////////// // initialisers bool create(const std::string& name, const std::string& path, bool writable); bool open(const std::string& path); ////////////////////////////////////////////////////////////////////////////// // management of types bool load_type(const std::string& type); bool load_types(void); bool remove_type(const std::string& type); ////////////////////////////////////////////////////////////////////////////// // whole library operations bool load(void); bool save(void); bool purge(void); bool close(void); bool erase(void); const std::string& name(void) const; const std::string& path(void) const; ////////////////////////////////////////////////////////////////////////////// // managing read/write status bool set_read_write(bool writable); bool set_writable(void); bool set_read_only(void); bool writable(void) const; bool read_only(void) const; bool os_writable(void) const; bool os_read_only(void) const; bool lm_writable(void) const; bool lm_read_only(void) const; ////////////////////////////////////////////////////////////////////////////// // unit management bool exists(const lm_unit_name& name) const; lm_unit_ptr create(const lm_unit_name&); bool loaded(const lm_unit_name& name) const; bool load(const lm_unit_name& unit); bool purge(const lm_unit_name& unit); bool save(const lm_unit_name& unit); bool erase(const lm_unit_name& name); bool mark(const lm_unit_name& name); time_t modified(const lm_unit_name& name) const; bool erase_by_source(const std::string& source_file); const lm_unit_ptr find(const lm_unit_name& name) const; lm_unit_ptr find(const lm_unit_name& name); std::vector names(void) const; std::vector names(const std::string& type) const; std::vector handles(void) const; std::vector handles(const std::string& type) const; ////////////////////////////////////////////////////////////////////////////// // dependency checking bool out_of_date(const lm_unit_name& name) const; bool up_to_date(const lm_unit_name& name) const; lm_dependencies out_of_date_reason(const lm_unit_name& name) const; std::pair tidy(void); ////////////////////////////////////////////////////////////////////////////// // do-everything print function bool pretty_print(std::ostream& str, bool print_units = false, // print the unit names not just the library names const std::string& type = std::string()) const; // print just this type ("" means all) //////////////////////////////////////////////////////////////////////////////// // diagnostic print routines bool print(std::ostream& str) const; bool print_long(std::ostream& str) const; private: std::map::iterator local_find(const lm_unit_name& name); std::map::const_iterator local_find(const lm_unit_name& name) const; std::string m_name; // name std::string m_path; // path bool m_writable; // writable std::map m_units; // units library_manager* m_manager; // parent library manager }; std::ostream& operator << (std::ostream& str, const lm_library& lib); //////////////////////////////////////////////////////////////////////////////// // Library Manager //////////////////////////////////////////////////////////////////////////////// class library_manager { public: friend class lm_library; friend class lm_unit; //////////////////////////////////////////////////////////////////////////////// // static functions allow you to test whether a directory is a library before opening it // you can also find the library's name without opening it static bool is_library(const std::string& path, const std::string& owner); static std::string library_name(const std::string& path, const std::string& owner); // non-static forms test for libraries with the same owner as the library manager bool is_library(const std::string& path); std::string library_name(const std::string& path); ////////////////////////////////////////////////////////////////////////////// // tructors explicit library_manager(const std::string& owner, bool library_case = false, bool unit_case = false); ~library_manager(void); ////////////////////////////////////////////////////////////////////////////// // case sensitivity bool library_case(void) const; void set_library_case(bool library_case); bool unit_case(void) const; void set_unit_case(bool library_case); ////////////////////////////////////////////////////////////////////////////// // type handling // only units of types added in this way will be recognised bool add_type(const std::string& type, const std::string& description, lm_create_callback fn = 0, void* type_data = 0); bool remove_type(const std::string& type); std::vector types(void) const; std::string description(const std::string& type) const; lm_create_callback callback(const std::string& type) const; void* type_data(const std::string& type) const; ////////////////////////////////////////////////////////////////////////////// // Library mappings // The library manager implements two different styles of library mappings // - mapping file // - ini file // mapping file handling uses a simple text file to store the mappings in an internally-defined format // ini file handling stores library mappings using the ini_manager component // These modes are switched on by simply specifying a mapping file or an ini file to hold the mappings // mapping file methods // set but do not load - use this when you want to create a new mapping file void set_mapping_file(const std::string& mapping_file); // set and load - use this with an existing mapping file bool load_mappings (const std::string& mapping_file); // return the mapping file string std::string mapping_file(); // ini file methods - the ini manager must be pre-loaded with the list of ini files to manage // set and load - this will create the relevant sections in the local ini file if not present already bool set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_section); ini_manager* get_ini_manager(void) const; // save to the library mapping handler, whichever kind it is bool save_mappings (void); ////////////////////////////////////////////////////////////////////////////// // library management // operations on a single library // test whether a named library exists bool exists(const std::string& name) const; // create a new libarry in the specified directory lm_library* create(const std::string& name, const std::string& path, bool writable = true); // open an existing library lm_library* open(const std::string& path); // load all units in the library bool load(const std::string& name); // save all marked units in the library bool save(const std::string& name); // purge all loaded units in the library bool purge(const std::string& name); // close the library - remove it from the manager but leave on disk bool close(const std::string& name); // erase the library - delete the directory and remove the library from the manager bool erase(const std::string& name); // operations on all libraries - as above but applied to all the libraries in the manager bool load(void); bool save(void); bool purge(void); bool close(void); bool erase(void); // get name and path of a library - name can differ in case if the library manager is case-insensitive std::string name(const std::string& library) const; std::string path(const std::string& library) const; // control and test read/write status bool set_writable(const std::string& library); bool set_read_only(const std::string& library); bool writable(const std::string& library) const; bool read_only(const std::string& library) const; bool os_writable(const std::string& library) const; bool os_read_only(const std::string& library) const; bool lm_writable(const std::string& library) const; bool lm_read_only(const std::string& library) const; // find a library in the manager - returns null if not found lm_library* find(const std::string& name); const lm_library* find(const std::string& name) const; // get the set of all library names std::vector names(void) const; // get the set of all libraries std::vector handles(void) const; std::vector handles(void); ////////////////////////////////////////////////////////////////////////////// // current library management bool setwork(const std::string& library); bool unsetwork(void); const lm_library* work(void) const; lm_library* work(void); std::string work_name(void) const; ////////////////////////////////////////////////////////////////////////////// // unit management within a library // Note: you can also manipulate the library class through a handle returned by find() or handles() bool exists(const std::string& library, const lm_unit_name& name) const; lm_unit_ptr create(const std::string& library, const lm_unit_name& name); bool loaded(const std::string& library, const lm_unit_name& name) const; bool load(const std::string& library, const lm_unit_name& name); bool purge(const std::string& library, const lm_unit_name& name); bool save(const std::string& library, const lm_unit_name& name); bool erase(const std::string& library, const lm_unit_name& name); bool mark(const std::string& library, const lm_unit_name& name); time_t modified(const std::string& library, const lm_unit_name& name) const; bool erase_by_source(const std::string& source_file); const lm_unit_ptr find(const std::string& library, const lm_unit_name& name) const; lm_unit_ptr find(const std::string& library, const lm_unit_name& name); std::vector names(const std::string& library) const; std::vector names(const std::string& library, const std::string& type) const; std::vector handles(const std::string& library) const; std::vector handles(const std::string& library, const std::string& type) const; ////////////////////////////////////////////////////////////////////////////// // dependency checking bool out_of_date(const std::string& library, const lm_unit_name& name) const; bool up_to_date(const std::string& library, const lm_unit_name& name) const; lm_dependencies out_of_date_reason(const std::string& library, const lm_unit_name& name) const; // delete out of date units from a library or all libraries // return the number of units tidied and a flag to say whether all units were successfully tidied std::pair tidy(const std::string& library); std::pair tidy(void); ////////////////////////////////////////////////////////////////////////////// // do-everything print routine! bool pretty_print(std::ostream& str, bool print_units = false, // print the unit names not just the library names const std::string& library = std::string(), // print just the specified library ("" means all) const std::string& type = std::string()) const; // print just this type ("" means all) //////////////////////////////////////////////////////////////////////////////// // diagnostic print routines bool print(std::ostream& str) const; bool print_long(std::ostream& str) const; ////////////////////////////////////////////////////////////////////////////// // internals private: // NOT a copyable object library_manager(const library_manager&); library_manager& operator = (const library_manager&); protected: std::list::iterator local_find(const std::string& name); std::list::const_iterator local_find(const std::string& name) const; std::string m_owner; // owner application name std::string m_mapping_file; // mapping file method of library management ini_manager* m_ini_files; // ini manager method of library management std::string m_ini_section; // ini manager method of library management std::string m_ini_work; // ini manager method of library management std::list m_libraries; // libraries std::string m_work; // work library std::map m_callbacks; // callbacks bool m_library_case; // case sensitivity for library names bool m_unit_case; // case sensitivity for unit names }; std::ostream& operator << (std::ostream& str, const library_manager& libraries); //////////////////////////////////////////////////////////////////////////////// } // end namespace stlplus #endif