#ifndef __GM_CONFIG_SECTIONS_H__ #define __GM_CONFIG_SECTIONS_H__ #include #include #include #include namespace Arc { /// This class is used to process ini-like configuration files. /// Those files consist of sections which have folloving format: /// /// [section/subsection:identifier] /// key=value /// key=value /// /// The section names are enclosed in [] and consist of /// multiple parts separated by /. The section may have /// optional identifier separated from rest of then name by :. /// The section name parts may not contain : character. /// Hence if : is present in name all characters to the right /// are treated as identifier. /// class ConfigIni { private: ConfigFile* fin; bool open; std::list section_names; std::string section_indicator; std::string current_section; std::string current_identifier; int current_section_n; std::list::iterator current_section_p; int line_number; bool current_section_changed; ConfigIni(ConfigIni const&); ConfigIni& operator=(ConfigIni const&); public: /// Creates object associated with file located at filename. /// File is kept open and is closed in destructor. ConfigIni(const char* filename); /// Creates object associated with already open file f. /// Associated file will not be closed in destructor and /// corresponding ConfigFile object must be valid during /// whole lifetime of this object. ConfigIni(ConfigFile& f); /// Ordinary destructor ~ConfigIni(void); /// Returns true if proper configuration file is associated. operator bool(void) const { return ((fin!=NULL) && (*fin)); }; /// Specifies section name which will be processed. /// Unspecified sections will be skipped by ReadNext() methods. bool AddSection(const char* name); /// By default ReadNext does not inform about presence of the /// section. Only commands from sections are returned. /// If section indicator is set ReadNext returns immediately /// when new section is started with indicator reported as read line. /// Note: indicator can't be empty string. void SetSectionIndicator(const char* ind = NULL) { section_indicator = ind?ind:""; }; /// Read next line of configuration from sesction(s) specified by AddSection(). /// Returns true in case of success and fills content of line into line. bool ReadNext(std::string& line); /// Read next line of configuration from sesction(s) specified by AddSection(). /// Returns true in case of success and fills split content of line into /// command and value. bool ReadNext(std::string& name,std::string& value); /// Return full name of the section to which last read line belongs. /// This name also includes subsection name. const char* Section(void) const { return current_section.c_str(); }; /// Returns true if last ReadNext() switched to next section. bool SectionNew(void) const { return current_section_changed; }; /// Return number of the section to which last read line belongs. /// Numbers are assigned in order they are passed to AddSection() /// method starting from 0. int SectionNum(void) const { return current_section_n; }; /// Returns name of the section to which last read line matched. /// It is similar to Section() method but name is as specified /// in AddSection() and hence does not contain subsection(s). const char* SectionMatch(void) const { if(current_section_n<0) return ""; return current_section_p->c_str(); }; /// Returns name of subsection to which last read line belongs. const char* SubSection(void) const { if(current_section_n<0) return ""; if(current_section.length() > current_section_p->length()) return (current_section.c_str()+current_section_p->length()+1); return ""; }; /// Return name of subsubsection to which last read line belongs /// relative to subsection given by name. If current subsection /// does not match specified name then NULL is returned. const char* SubSectionMatch(const char* name); /// Return identifier of the section to which last read line belongs. const char* SectionIdentifier(void) const { return current_identifier.c_str(); } /// Helper method which reads keyword from string at 'line' separated by 'separator' /// and stores it in 'str'. /// If separator is set to \0 then whole line is consumed. /// If quotes are not \0 keyword may be enclosed in specified character. /// Returns position of first character in 'line', which is not in read keyword. static int NextArg(const char* line,std::string &str,char separator = ' ',char quotes = '\0'); /// Reads keyword from string at 'rest' and reduces 'rest' by removing keyword from it. /// The way it processes keyword is similar to static NextArg method. static std::string NextArg(std::string &rest,char separator = ' ',char quotes = '\0'); }; } // namespace ARex #endif // __GM_CONFIG_SECTIONS_H__