/* * This file is a part of Winix * and is not publicly distributed * * Copyright (c) 2008-2010, Tomasz Sowa * All rights reserved. * */ #include "confparser.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; } 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 ; i