#ifndef STLPLUS_INI_MANAGER #define STLPLUS_INI_MANAGER //////////////////////////////////////////////////////////////////////////////// // Author: Andy Rushton // Copyright: (c) Southampton University 1999-2004 // (c) Andy Rushton 2004-2009 // License: BSD License, see ../docs/license.html // A subsystem for managing INI (i.e. .ini) files // An INI file has the following format // file ::= header { section }* // header ::= { comment | blank }* // section ::= section_header { declaration | comment | blank }* // section_header ::= '[' title ']' '\n' // declaration ::= variable '=' value '\n' // comment ::= ';' text '\n' // blank ::= '\n' // title ::= [~']']* // variable ::= [~'=']* // value ::= .* // text ::= .* // Whitespace is trimmed from the leading and trailing ends of title, variable and value // Note: a header is represented internally as a Clint section (i.e. a section with no name) //////////////////////////////////////////////////////////////////////////////// #include "subsystems_fixes.hpp" #include #include #include namespace stlplus { //////////////////////////////////////////////////////////////////////////////// // Internals class ini_manager_body; //////////////////////////////////////////////////////////////////////////////// // Ini-file manager class class ini_manager { public: ini_manager(void); explicit ini_manager(const std::vector& filenames); ini_manager(const ini_manager&); ini_manager& operator= (const ini_manager&); ~ini_manager(void); ////////////////////////////////////////////////////////////////////////////// // file management // add files starting with the most local file (e.g. the current project) which has depth 0 // and working back to the most global (e.g. the installation settings) which has a depth of size()-1 // This does nothing if the file has already been loaded - it is not permitted to manage the same file twice. // Returns true if the file loaded okay or was already loaded (it is counted as successful if the file did // not exist, only read errors cause a failure) bool add_file(const std::string& filename); // as above, returns false if *none* of the files were added // filenames[0] is the local file, and so on bool add_files(const std::vector& filenames); // saves modified ini files - returns true if all modified files were written successfully bool save(void); // get the number of files being managed unsigned size(void) const; // get the ini filename associated with a depth std::string filename(unsigned depth = 0) const; // test whether a file in the ini manager is writable bool writable(unsigned depth = 0) const; // test whether a file is empty // An ini file is considered empty if it has no named sections and the header is empty or missing bool empty(unsigned depth = 0) const; // erase the ini file from the ini manager and from the disk bool erase(unsigned depth = 0); // remove the file from the ini manager but do not erase it from the disk bool remove(unsigned depth = 0); ////////////////////////////////////////////////////////////////////////////// // section management // returns the union of all section names in all of the ini files std::vector section_names(void) const; // returns the section names in one of the ini files std::vector section_names(unsigned depth) const; // tests whether a section is found in any of the ini files bool section_exists(const std::string& title) const; // tests whether the section is found in the specific ini file bool section_exists(const std::string& title, unsigned depth) const; // adds a section to the specified ini file - does nothing if it is already present bool add_section(const std::string& section, unsigned depth = 0); // test whether a section is empty bool empty_section(const std::string& section, unsigned depth = 0); // removes a section from the specified ini file if it exists there but cannot remove it from any other file bool erase_section(const std::string& section, unsigned depth = 0); // removes all the contents of a section from the specified ini file but keeps the empty section bool clear_section(const std::string& section, unsigned depth = 0); ////////////////////////////////////////////////////////////////////////////// // variable management // test whether a variable exists in any of the ini files bool variable_exists(const std::string& section, const std::string variable) const; // test whether a variable exists in specified ini file bool variable_exists(const std::string& section, const std::string variable, unsigned depth) const; // get the union of all variables declared in all ini files std::vector variable_names(const std::string& section) const; // get the set of all varaibale names from one file std::vector variable_names(const std::string& section, unsigned depth) const; // get the depth of the first ini file to define a variable // returns 0 if defined in the local ini file, etc. Returns (unsigned)-1 if the variable doesn't exist unsigned variable_depth(const std::string& section, const std::string variable) const; // get the filename that first defines the variable std::string variable_filename(const std::string& section, const std::string variable) const; // ditto for its linenumber within that file unsigned variable_linenumber(const std::string& section, const std::string variable) const; // get the value of a variable as a single unprocessed string // if the variable does not exist the string will be empty, but beware that // you also get an empty string if a variable exists but has no value // you can differentiate between the two cases by using variable_exists_all above std::string variable_value(const std::string& section, const std::string variable) const; // get the value from the specified file std::string variable_value(const std::string& section, const std::string variable, unsigned depth) const; // get the value of a variable as a processed string // processing splits the value at commas and furthermore supports quoted strings (so that values can contain commas for example) // quoted strings are dequoted before they are added to the result // the result is a vector of dequoted strings, one per value in the comma-separated list std::vector variable_values(const std::string& section, const std::string variable) const; // get the processed variable from the specified file std::vector variable_values(const std::string& section, const std::string variable, unsigned depth) const; // add a variable to the specified file bool add_variable(const std::string& section, const std::string& variable, const std::string& value, unsigned depth = 0); // add a variable as a processed string // processing means that the values in the string vector are converted into a comma-separated list // values containing reserved characters are automatically quoted - so you should not even try to quote them yourself bool add_variable(const std::string& section, const std::string& variable, const std::vector& values, unsigned depth = 0); // erase a variable from the specified file // this does not remove the variable from other ini files, so the variable may still exist // to mask a global variable, set the variable to an empty string instead bool erase_variable(const std::string& section, const std::string& variable, unsigned depth = 0); ////////////////////////////////////////////////////////////////////////////// // sundry line-entry management // add a comment to the specified ini file bool add_comment(const std::string& section, const std::string& comment, unsigned depth = 0); // add a blank line to the specified ini file bool add_blank(const std::string& section, unsigned depth = 0); bool print(std::ostream&) const; private: friend class ini_manager_body; ini_manager_body* m_body; }; //////////////////////////////////////////////////////////////////////////////// // diagnostic print routine std::ostream& operator << (std::ostream&, const ini_manager&); //////////////////////////////////////////////////////////////////////////////// } // end namespace stlplus #endif