subsystems/ini_manager.hpp

    1: #ifndef STLPLUS_INI_MANAGER
    2: #define STLPLUS_INI_MANAGER
    3: ////////////////////////////////////////////////////////////////////////////////
    4: 
    5: //   Author:    Andy Rushton
    6: //   Copyright: (c) Andy Rushton, 2007
    7: //   License:   BSD License, see ../docs/license.html
    8: 
    9: //   A subsystem for managing INI (i.e. .ini) files
   10: //   An INI file has the following format
   11: 
   12: //     file           ::= header { section }*
   13: //     header         ::= { comment | blank }*
   14: //     section        ::= section_header { declaration | comment | blank }*
   15: //     section_header ::= '[' title ']' '\n'
   16: //     declaration    ::= variable '=' value '\n'
   17: //     comment        ::= ';' text '\n'
   18: //     blank          ::= '\n'
   19: //     title          ::= [~']']*
   20: //     variable       ::= [~'=']*
   21: //     value          ::= .*
   22: //     text           ::= .*
   23: 
   24: //   Whitespace is trimmed from the leading and trailing ends of title, variable and value
   25: //   Note: a header is represented internally as a Clint section (i.e. a section with no name)
   26: 
   27: ////////////////////////////////////////////////////////////////////////////////
   28: #include "subsystems_fixes.hpp"
   29: #include <vector>
   30: #include <string>
   31: #include <iostream>
   32: 
   33: namespace stlplus
   34: {
   35: 
   36:   ////////////////////////////////////////////////////////////////////////////////
   37:   // Internals
   38: 
   39:   class ini_manager_body;
   40: 
   41:   ////////////////////////////////////////////////////////////////////////////////
   42:   // Ini-file manager class
   43: 
   44:   class ini_manager
   45:   {
   46:   public:
   47: 
   48:     ini_manager(void);
   49: 
   50:     explicit ini_manager(const std::vector<std::string>& filenames);
   51: 
   52:     ini_manager(const ini_manager&);
   53:     ini_manager& operator= (const ini_manager&);
   54: 
   55:     ~ini_manager(void);
   56: 
   57:     //////////////////////////////////////////////////////////////////////////////
   58:     // file management
   59: 
   60:     // add files starting with the most local file (e.g. the current project) which has depth 0
   61:     // and working back to the most global (e.g. the installation settings) which has a depth of size()-1
   62:     // This does nothing if the file has already been loaded - it is not permitted to manage the same file twice.
   63:     // Returns true if the file loaded okay or was already loaded (it is counted as successful if the file did
   64:     // not exist, only read errors cause a failure)
   65:     bool add_file(const std::string& filename);
   66: 
   67:     // as above, returns false if *none* of the files were added
   68:     // filenames[0] is the local file, and so on
   69:     bool add_files(const std::vector<std::string>& filenames);
   70: 
   71:     // saves modified ini files - returns true if all modified files were written successfully
   72:     bool save(void);
   73: 
   74:     // get the number of files being managed
   75:     unsigned size(void) const;
   76: 
   77:     // get the ini filename associated with a depth
   78:     std::string filename(unsigned depth = 0) const;
   79: 
   80:     // test whether a file in the ini manager is writable
   81:     bool writable(unsigned depth = 0) const;
   82: 
   83:     // test whether a file is empty
   84:     // An ini file is considered empty if it has no named sections and the header is empty or missing
   85:     bool empty(unsigned depth = 0) const;
   86: 
   87:     // erase the ini file from the ini manager and from the disk
   88:     bool erase(unsigned depth = 0);
   89: 
   90:     // remove the file from the ini manager but do not erase it from the disk
   91:     bool remove(unsigned depth = 0);
   92: 
   93:     //////////////////////////////////////////////////////////////////////////////
   94:     // section management
   95: 
   96:     // returns the union of all section names in all of the ini files
   97:     std::vector<std::string> section_names(void) const;
   98: 
   99:     // returns the section names in one of the ini files
  100:     std::vector<std::string> section_names(unsigned depth) const;
  101: 
  102:     // tests whether a section is found in any of the ini files
  103:     bool section_exists(const std::string& title) const;
  104: 
  105:     // tests whether the section is found in the specific ini file
  106:     bool section_exists(const std::string& title, unsigned depth) const;
  107: 
  108:     // adds a section to the specified ini file - does nothing if it is already present
  109:     bool add_section(const std::string& section, unsigned depth = 0);
  110: 
  111:     // test whether a section is empty
  112:     bool empty_section(const std::string& section, unsigned depth = 0);
  113: 
  114:     // removes a section from the specified ini file if it exists there but cannot remove it from any other file
  115:     bool erase_section(const std::string& section, unsigned depth = 0);
  116: 
  117:     // removes all the contents of a section from the specified ini file but keeps the empty section
  118:     bool clear_section(const std::string& section, unsigned depth = 0);
  119: 
  120:     //////////////////////////////////////////////////////////////////////////////
  121:     // variable management
  122: 
  123:     // test whether a variable exists in any of the ini files
  124:     bool variable_exists(const std::string& section, const std::string variable) const;
  125: 
  126:     // test whether a variable exists in specified ini file
  127:     bool variable_exists(const std::string& section, const std::string variable, unsigned depth) const;
  128: 
  129:     // get the union of all variables declared in all ini files
  130:     std::vector<std::string> variable_names(const std::string& section) const;
  131: 
  132:     // get the set of all varaibale names from one file
  133:     std::vector<std::string> variable_names(const std::string& section, unsigned depth) const;
  134: 
  135:     // get the depth of the first ini file to define a variable
  136:     // returns 0 if defined in the local ini file, etc. Returns (unsigned)-1 if the variable doesn't exist
  137:     unsigned variable_depth(const std::string& section, const std::string variable) const;
  138: 
  139:     // get the filename that first defines the variable
  140:     std::string variable_filename(const std::string& section, const std::string variable) const;
  141:     // ditto for its linenumber within that file
  142:     unsigned variable_linenumber(const std::string& section, const std::string variable) const;
  143: 
  144:     // get the value of a variable as a single unprocessed string
  145:     // if the variable does not exist the string will be empty, but beware that
  146:     // you also get an empty string if a variable exists but has no value
  147:     // you can differentiate between the two cases by using variable_exists_all above
  148:     std::string variable_value(const std::string& section, const std::string variable) const;
  149: 
  150:     // get the value from the specified file
  151:     std::string variable_value(const std::string& section, const std::string variable, unsigned depth) const;
  152: 
  153:     // get the value of a variable as a processed string
  154:     // processing splits the value at commas and furthermore supports quoted strings (so that values can contain commas for example)
  155:     // quoted strings are dequoted before they are added to the result
  156:     // the result is a vector of dequoted strings, one per value in the comma-separated list
  157:     std::vector<std::string> variable_values(const std::string& section, const std::string variable) const;
  158: 
  159:     // get the processed variable from the specified file
  160:     std::vector<std::string> variable_values(const std::string& section, const std::string variable, unsigned depth) const;
  161: 
  162:     // add a variable to the specified file
  163:     bool add_variable(const std::string& section, const std::string& variable, const std::string& value, unsigned depth = 0);
  164: 
  165:     // add a variable as a processed string
  166:     // processing means that the values in the string vector are converted into a comma-separated list
  167:     // values containing reserved characters are automatically quoted - so you should not even try to quote them yourself
  168:     bool add_variable(const std::string& section, const std::string& variable, const std::vector<std::string>& values, unsigned depth = 0);
  169: 
  170:     // erase a variable from the specified file
  171:     // this does not remove the variable from other ini files, so the variable may still exist
  172:     // to mask a global variable, set the variable to an empty string instead
  173:     bool erase_variable(const std::string& section, const std::string& variable, unsigned depth = 0);
  174: 
  175:     //////////////////////////////////////////////////////////////////////////////
  176:     // sundry line-entry management
  177: 
  178:     // add a comment to the specified ini file
  179:     bool add_comment(const std::string& section, const std::string& comment, unsigned depth = 0);
  180: 
  181:     // add a blank line to the specified ini file
  182:     bool add_blank(const std::string& section, unsigned depth = 0);
  183: 
  184:     bool print(std::ostream&) const;
  185: 
  186:   private:
  187:     friend class ini_manager_body;
  188:     ini_manager_body* m_body;
  189:   };
  190: 
  191:   ////////////////////////////////////////////////////////////////////////////////
  192:   // diagnostic print routine
  193: 
  194:   std::ostream& operator << (std::ostream&, const ini_manager&);
  195: 
  196:   ////////////////////////////////////////////////////////////////////////////////
  197: 
  198: } // end namespace stlplus
  199: 
  200: #endif