/* * This file is a part of PikoTools * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name Tomasz Sowa nor the names of contributors to this * project may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "confparser.h" #include "utf8/utf8.h" namespace PT { SpaceParser::SpaceParser() { root_space = 0; SetDefault(); } void SpaceParser::SetSpace(Space * pspace) { root_space = pspace; } void SpaceParser::SetSpace(Space & pspace) { root_space = &pspace; } void SpaceParser::SetDefault() { // 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; use_escape_char = true; input_as_utf8 = false; } void SpaceParser::SplitSingle(bool split) { split_single = split; } void SpaceParser::SkipEmpty(bool skip) { skip_empty = skip; } void SpaceParser::UseEscapeChar(bool escape) { use_escape_char = escape; } void SpaceParser::UTF8(bool utf) { input_as_utf8 = utf; } SpaceParser::Status SpaceParser::Parse(const char * file_name) { reading_from_file = true; file.clear(); file.open( file_name ); if( file ) { Parse(); file.close(); } else { status = cant_open_file; } return status; } SpaceParser::Status SpaceParser::Parse(const std::string & file_name) { return Parse(file_name.c_str()); } SpaceParser::Status SpaceParser::Parse(const wchar_t * file_name) { PT::WideToUTF8(file_name, afile_name); return Parse(afile_name.c_str()); } SpaceParser::Status SpaceParser::Parse(const std::wstring & file_name) { return Parse(file_name.c_str()); } SpaceParser::Status SpaceParser::ParseString(const char * str) { reading_from_file = false; reading_from_wchar_string = false; pchar_ascii = str; pchar_unicode = 0; Parse(); return status; } SpaceParser::Status SpaceParser::ParseString(const std::string & str) { return ParseString(str.c_str()); } SpaceParser::Status SpaceParser::ParseString(const wchar_t * str) { reading_from_file = false; reading_from_wchar_string = true; pchar_unicode = str; pchar_ascii = 0; Parse(); return status; } SpaceParser::Status SpaceParser::ParseString(const std::wstring & str) { return ParseString(str.c_str()); } void SpaceParser::Parse() { if( !root_space ) { status = no_space; return; } line = 1; status = ok; space = root_space; ReadChar(); SkipWhiteLines(); ParseLoop(); if( status == ok && space != root_space ) { // last closing a space characters ')' are missing status = syntax_error; } } void SpaceParser::ParseLoop() { while( status == ok && lastc != -1 ) { if( lastc == list_end ) { SpaceEnds(); } else { ReadVariable(); if( lastc == list_start ) { SpaceStarts(); } else if( lastc == separator && !variable.empty() ) { ReadAddValue(); } else { status = syntax_error; } } if( status == ok ) SkipWhiteLines(); } } void SpaceParser::SpaceEnds() { if( space == root_space ) { // there cannot be a loose list end character in the global space status = syntax_error; } else { space = space->parent; ReadChar(); } } void SpaceParser::SpaceStarts() { Space * new_space = new Space(); space->spaces.push_back(new_space); new_space->parent = space; new_space->name = variable; space = new_space; ReadChar(); } void SpaceParser::ReadAddValue() { ReadChar(); // skipping separator '=' if( ReadValue() ) { AddOption(); } else { status = syntax_error; } } bool SpaceParser::IsVariableChar(int c) { if( (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='.' || c==',' || c=='_' ) return true; return false; } bool SpaceParser::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 SpaceParser::SkipWhite() { while( IsWhite(lastc) || lastc == commentary ) { if( lastc == commentary ) SkipLine(); else ReadChar(); } } void SpaceParser::SkipWhiteLines() { while( IsWhite(lastc) || lastc == commentary || lastc=='\n' ) { if( lastc == commentary ) SkipLine(); else ReadChar(); } } void SpaceParser::SkipLine() { while( lastc != -1 && lastc != '\n' ) ReadChar(); } void SpaceParser::Trim(std::wstring & s) { std::wstring::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::wstring::npos); // looking for white characters at the beginning for(i=0 ; itable_single[variable] = value[0]; DeleteFromTable(variable); } else { space->table[variable] = value; DeleteFromTableSingle(variable); } } void SpaceParser::DeleteFromTable(const std::wstring & var) { Space::Table::iterator i = space->table.find(var); if( i != space->table.end() ) space->table.erase(i); } void SpaceParser::DeleteFromTableSingle(const std::wstring & var) { Space::TableSingle::iterator i = space->table_single.find(var); if( i != space->table_single.end() ) space->table_single.erase(i); } void SpaceParser::ReadVariable() { variable.clear(); SkipWhite(); while( IsVariableChar(lastc) ) { variable += lastc; ReadChar(); } SkipWhite(); } bool SpaceParser::ReadValue() { value.clear(); SkipWhite(); if( lastc == list_start ) return ReadValueList(); else return ReadValueNoList(); } bool SpaceParser::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 SpaceParser::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 SpaceParser::ReadValueQuoted() { ReadChar(); // skipping the first quote // !! IMPROVE ME // add some other escaped characters especialy \0 (the serializator is working that way now) while( lastc != '"' && lastc != -1 ) { if( use_escape_char && lastc == '\\' ) ReadChar(); value_item += lastc; ReadChar(); } if( lastc != '"' ) return false; ReadChar(); // skipping the last quote SkipWhite(); return true; } bool SpaceParser::ReadValueSimple(bool use_list_delimiter) { int list_delimiter1 = -1; int list_delimiter2 = -1; if( use_list_delimiter ) list_delimiter1 = list_delimiter; if( use_list_delimiter || space != root_space ) 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 SpaceParser::ReadUTF8Char() { int c; bool correct; lastc = -1; do { PT::UTF8ToInt(file, c, correct); if( !file ) return lastc; } while( !correct ); lastc = c; if( lastc == '\n' ) ++line; return lastc; } int SpaceParser::ReadASCIIChar() { lastc = file.get(); if( lastc == '\n' ) ++line; return lastc; } int SpaceParser::ReadCharFromWcharString() { if( *pchar_unicode == 0 ) lastc = -1; else lastc = *(pchar_unicode++); if( lastc == '\n' ) ++line; return lastc; } int SpaceParser::ReadCharFromUTF8String() { int c; bool correct; lastc = -1; do { size_t len = PT::UTF8ToInt(pchar_ascii, c, correct); pchar_ascii += len; if( *pchar_ascii == 0 ) return lastc; } while( !correct ); lastc = c; if( lastc == '\n' ) ++line; return lastc; } int SpaceParser::ReadCharFromAsciiString() { if( *pchar_ascii == 0 ) lastc = -1; else lastc = *(pchar_ascii++); if( lastc == '\n' ) ++line; return lastc; } int SpaceParser::ReadChar() { if( reading_from_file ) { if( input_as_utf8 ) return ReadUTF8Char(); else return ReadASCIIChar(); } else { if( reading_from_wchar_string ) { return ReadCharFromWcharString(); } else { if( input_as_utf8 ) return ReadCharFromUTF8String(); else return ReadCharFromAsciiString(); } } } } // namespace