/* * This file is a part of Winix * and is not publicly distributed * * Copyright (c) 2008-2010, Tomasz Sowa * All rights reserved. * */ #include #include "confparser.h" #include "misc.h" ConfParser::ConfParser() { // you can change this separators to what you want // you shoud not use only white characters here (as expected by IsWhite() method) // and new line characters ('\n') separator = '='; commentary = '#'; list_start = '('; list_end = ')'; list_delimiter = ','; split_single = false; skip_empty = false; default_str = ""; default_int = 0; default_size = 0; default_bool = false; } void ConfParser::SplitSingle(bool split) { split_single = split; } void ConfParser::SkipEmpty(bool skip) { skip_empty = skip; } ConfParser::Status ConfParser::Parse(const char * file_name) { line = 1; table.clear(); table_single.clear(); file.clear(); file.open( file_name ); if( file ) { status = ParseFile(); file.close(); } else { status = cant_open_file; } return status; } ConfParser::Status ConfParser::Parse(const std::string & file_name) { return Parse(file_name.c_str()); } ConfParser::Status ConfParser::ParseFile() { ReadChar(); SkipWhiteLines(); while( lastc != -1 ) { if( !ReadVariable() ) return syntax_error; if( lastc != separator ) return syntax_error; if( !ReadValue() ) return syntax_error; AddOption(); SkipWhite(); if( lastc != -1 && lastc != '\n' ) return syntax_error; // some characters have left at the end of an option SkipWhiteLines(); } return ok; } bool ConfParser::IsVariableChar(int c) { if( (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='.' || c==',' || c=='_' ) return true; return false; } void ConfParser::AddOption() { if( value.empty() && skip_empty ) { DeleteFromTable(variable); DeleteFromTableSingle(variable); return; } if( split_single && value.size() == 1 ) { table_single[variable] = value[0]; DeleteFromTable(variable); } else { table[variable] = value; DeleteFromTableSingle(variable); } } void ConfParser::DeleteFromTable(const std::string & var) { Table::iterator i = table.find(var); if( i != table.end() ) table.erase(i); } void ConfParser::DeleteFromTableSingle(const std::string & var) { TableSingle::iterator i = table_single.find(var); if( i != table_single.end() ) table_single.erase(i); } bool ConfParser::ReadVariable() { variable.clear(); SkipWhite(); while( IsVariableChar(lastc) ) { variable += lastc; ReadChar(); } SkipWhite(); return !variable.empty(); } bool ConfParser::ReadValue() { value.clear(); ReadChar(); // skipping separator '=' SkipWhite(); if( lastc == list_start ) return ReadValueList(); else return ReadValueNoList(); } bool ConfParser::ReadValueList() { ReadChar(); // skipping first list character '(' SkipWhiteLines(); // lists can be split into several lines while( lastc != -1 && lastc != list_end ) { if( !ReadValueNoList(true) ) return false; if( lastc == list_delimiter ) ReadChar(); SkipWhiteLines(); } if( lastc != list_end ) return false; ReadChar(); // skipping last list character ')' SkipWhite(); return true; } bool ConfParser::ReadValueNoList(bool use_list_delimiter) { bool res; value_item.clear(); if( lastc == '"' ) { res = ReadValueQuoted(); // quoted value if( res ) value.push_back(value_item); } else { res = ReadValueSimple(use_list_delimiter); if( res && !value_item.empty() ) value.push_back(value_item); } return res; } bool ConfParser::ReadValueQuoted() { ReadChar(); // skipping the first quote while( lastc != '"' && lastc != -1 ) { if( lastc == '\\' ) ReadChar(); value_item += lastc; ReadChar(); } if( lastc != '"' ) return false; ReadChar(); // skipping the last quote SkipWhite(); return true; } bool ConfParser::ReadValueSimple(bool use_list_delimiter) { int list_delimiter1 = -1; int list_delimiter2 = -1; if( use_list_delimiter ) { list_delimiter1 = list_delimiter; list_delimiter2 = list_end; } while( lastc!=-1 && lastc!='\n' && lastc!=commentary && lastc!=list_delimiter1 && lastc!=list_delimiter2 ) { value_item += lastc; ReadChar(); } Trim(value_item); SkipWhite(); return true; } int ConfParser::ReadChar() { lastc = file.get(); if( lastc == '\n' ) ++line; return lastc; } bool ConfParser::IsWhite(int c) { // dont use '\n' here // 13 (\r) is at the end of a line in a dos file \r\n // 160 is an unbreakable space if( c==' ' || c=='\t' || c==13 || c==160 ) return true; return false; } void ConfParser::SkipWhite() { while( IsWhite(lastc) || lastc == commentary ) { if( lastc == commentary ) SkipLine(); else ReadChar(); } } void ConfParser::SkipWhiteLines() { while( IsWhite(lastc) || lastc == commentary || lastc=='\n' ) { if( lastc == commentary ) SkipLine(); else ReadChar(); } } void ConfParser::SkipLine() { while( lastc != -1 && lastc != '\n' ) ReadChar(); } void ConfParser::Trim(std::string & s) { std::string::size_type i; if( s.empty() ) return; // looking for white characters at the end for(i=s.size()-1 ; i>0 && IsWhite(s[i]) ; --i); if( i==0 && IsWhite(s[i]) ) { // the whole string has white characters s.clear(); return; } // deleting white characters at the end if( i != s.size() - 1 ) s.erase(i+1, std::string::npos); // looking for white characters at the beginning for(i=0 ; isecond.empty() ) return def; return t->second[0]; } return i->second; } int ConfParser::Int(const char * name) { return Int(std::string(name), default_int); } int ConfParser::Int(const char * name, int def) { return Int(std::string(name), def); } int ConfParser::ToInt(const std::string & value) { long res = (value[0] == '0')? strtol(value.c_str() + 1, 0, 8) : strtol(value.c_str(), 0, 10); return res; } int ConfParser::Int(const std::string & name, int def) { TableSingle::iterator i = table_single.find(name); if( i == table_single.end() ) { Table::iterator t = table.find(name); if( t == table.end() || t->second.empty() ) return def; return ToInt(t->second[0]); } return ToInt(i->second); } size_t ConfParser::Size(const char * name) { return Size(std::string(name), default_size); } size_t ConfParser::Size(const char * name, size_t def) { return Size(std::string(name), def); } size_t ConfParser::ToSize(const std::string & value) { long res = (value[0] == '0')? strtoul(value.c_str() + 1, 0, 8) : strtoul(value.c_str(), 0, 10); return (size_t)res; } size_t ConfParser::Size(const std::string & name, size_t def) { TableSingle::iterator i = table_single.find(name); if( i == table_single.end() ) { Table::iterator t = table.find(name); if( t == table.end() || t->second.empty() ) return def; return ToSize(t->second[0]); } return ToSize(i->second); } bool ConfParser::Bool(const char * name) { return Bool(std::string(name), default_bool); } bool ConfParser::Bool(const char * name, bool def) { return Bool(std::string(name), def); } bool ConfParser::ToBool(const std::string & value) { return ( EqualNoCase(value.c_str(), "true") || EqualNoCase(value.c_str(), "yes") || EqualNoCase(value.c_str(), "1") ); } bool ConfParser::Bool(const std::string & name, bool def) { TableSingle::iterator i = table_single.find(name); if( i == table_single.end() ) { Table::iterator t = table.find(name); if( t == table.end() || t->second.empty() ) return def; return ToBool(t->second[0]); } return ToBool(i->second); } void ConfParser::SetDefaultText(const std::string & def) { default_str = def; } void ConfParser::SetDefaultInt(int def) { default_int = def; } void ConfParser::SetDefaultSize(size_t def) { default_size = def; } void ConfParser::SetDefaultBool(bool def) { default_bool = def; } // in lists we don't use default values void ConfParser::ListText(const char * name, std::vector & list) { ListText(std::string(name), list); } void ConfParser::ListText(const std::string & name, std::vector & list) { list.clear(); ConfParser::TableSingle::iterator i = table_single.find(name); if( i != table_single.end() ) { list.push_back(i->second); return; } ConfParser::Table::iterator z = table.find(name); if( z != table.end() ) { list = z->second; return; } }