From f2ba48a10eb3882e58ac24b0ed83b06087441727 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 12 Jan 2012 00:24:08 +0000 Subject: [PATCH] importing confparser to pikotools git-svn-id: svn://ttmath.org/publicrep/pikotools/trunk@371 e52654a7-88a9-db11-a3e9-0013d4bc506e --- confparser/Makefile | 29 ++ confparser/Makefile.dep | 4 + confparser/Makefile.o.dep | 1 + confparser/confparser.cpp | 684 ++++++++++++++++++++++++++++++++++++++ confparser/confparser.h | 326 ++++++++++++++++++ confparser/space.cpp | 374 +++++++++++++++++++++ confparser/space.h | 442 ++++++++++++++++++++++++ 7 files changed, 1860 insertions(+) create mode 100755 confparser/Makefile create mode 100755 confparser/Makefile.dep create mode 100755 confparser/Makefile.o.dep create mode 100755 confparser/confparser.cpp create mode 100755 confparser/confparser.h create mode 100755 confparser/space.cpp create mode 100755 confparser/space.h diff --git a/confparser/Makefile b/confparser/Makefile new file mode 100755 index 0000000..37c2e80 --- /dev/null +++ b/confparser/Makefile @@ -0,0 +1,29 @@ +include Makefile.o.dep + +libname=confparser.a + +all: $(libname) + +$(libname): $(o) + ar rcs $(libname) $(o) + + +.SUFFIXES: .cpp .o + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $< + + + +depend: + makedepend -Y. -I.. -f- *.cpp > Makefile.dep + echo -n "o = " > Makefile.o.dep + ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep + + +clean: + rm -f *.o + rm -f $(libname) + + +include Makefile.dep diff --git a/confparser/Makefile.dep b/confparser/Makefile.dep new file mode 100755 index 0000000..b27e3c9 --- /dev/null +++ b/confparser/Makefile.dep @@ -0,0 +1,4 @@ +# DO NOT DELETE + +confparser.o: confparser.h ../utf8/utf8.h +space.o: confparser.h ../utf8/utf8.h diff --git a/confparser/Makefile.o.dep b/confparser/Makefile.o.dep new file mode 100755 index 0000000..3bb09a2 --- /dev/null +++ b/confparser/Makefile.o.dep @@ -0,0 +1 @@ +o = confparser.o space.o diff --git a/confparser/confparser.cpp b/confparser/confparser.cpp new file mode 100755 index 0000000..32b8012 --- /dev/null +++ b/confparser/confparser.cpp @@ -0,0 +1,684 @@ +/* + * This file is a part of PicoTools + * 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 +{ + + + +ConfParser::ConfParser() +{ + root_space = 0; + SetDefault(); +} + + +void ConfParser::SetSpace(Space * pspace) +{ + root_space = pspace; +} + + +void ConfParser::SetSpace(Space & pspace) +{ + root_space = &pspace; +} + + +void ConfParser::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 ConfParser::SplitSingle(bool split) +{ + split_single = split; +} + + +void ConfParser::SkipEmpty(bool skip) +{ + skip_empty = skip; +} + + +void ConfParser::UseEscapeChar(bool escape) +{ + use_escape_char = escape; +} + + +void ConfParser::UTF8(bool utf) +{ + input_as_utf8 = utf; +} + + + + +ConfParser::Status ConfParser::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; +} + + + +ConfParser::Status ConfParser::Parse(const std::string & file_name) +{ + return Parse(file_name.c_str()); +} + + + + +ConfParser::Status ConfParser::Parse(const wchar_t * file_name) +{ + PT::WideToUTF8(file_name, afile_name); + return Parse(afile_name.c_str()); +} + + + +ConfParser::Status ConfParser::Parse(const std::wstring & file_name) +{ + return Parse(file_name.c_str()); +} + + + +ConfParser::Status ConfParser::ParseString(const char * str) +{ + reading_from_file = false; + reading_from_wchar_string = false; + pchar_ascii = str; + pchar_unicode = 0; + + Parse(); + +return status; +} + + +ConfParser::Status ConfParser::ParseString(const std::string & str) +{ + return ParseString(str.c_str()); +} + + +ConfParser::Status ConfParser::ParseString(const wchar_t * str) +{ + reading_from_file = false; + reading_from_wchar_string = true; + pchar_unicode = str; + pchar_ascii = 0; + + Parse(); + +return status; +} + + +ConfParser::Status ConfParser::ParseString(const std::wstring & str) +{ + return ParseString(str.c_str()); +} + + +void ConfParser::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 ConfParser::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 ConfParser::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 ConfParser::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 ConfParser::ReadAddValue() +{ + ReadChar(); // skipping separator '=' + + if( ReadValue() ) + { + AddOption(); + } + else + { + status = syntax_error; + } +} + + +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; +} + + +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::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 ConfParser::DeleteFromTable(const std::wstring & var) +{ + Space::Table::iterator i = space->table.find(var); + + if( i != space->table.end() ) + space->table.erase(i); +} + + + +void ConfParser::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 ConfParser::ReadVariable() +{ + variable.clear(); + SkipWhite(); + + while( IsVariableChar(lastc) ) + { + variable += lastc; + ReadChar(); + } + + SkipWhite(); +} + + + +bool ConfParser::ReadValue() +{ + value.clear(); + 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 + +// !! dodac obsluge innych escapowanych znakow w szczegolnosci \0 (serializator Space juz tak zapisuje) + + 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 ConfParser::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 ConfParser::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 ConfParser::ReadASCIIChar() +{ + lastc = file.get(); + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + + + +int ConfParser::ReadCharFromWcharString() +{ + if( *pchar_unicode == 0 ) + lastc = -1; + else + lastc = *(pchar_unicode++); + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + +int ConfParser::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 ConfParser::ReadCharFromAsciiString() +{ + if( *pchar_ascii == 0 ) + lastc = -1; + else + lastc = *(pchar_ascii++); + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + +int ConfParser::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 + + + + diff --git a/confparser/confparser.h b/confparser/confparser.h new file mode 100755 index 0000000..7d129e1 --- /dev/null +++ b/confparser/confparser.h @@ -0,0 +1,326 @@ +/* + * This file is a part of PicoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2010-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. + */ + +#ifndef headerfile_picotools_confparser_confparser +#define headerfile_picotools_confparser_confparser + +#include +#include +#include +#include +#include +#include "space.h" + + + +namespace PT +{ + + + +class ConfParser +{ +public: + + + /* + ctor -- setting default values (SetDefault() method) + */ + ConfParser(); + + + /* + setting the root space + */ + void SetSpace(Space * pspace); + void SetSpace(Space & pspace); + + + /* + setting options of the parser to the default values + utf8, split single etc. + */ + void SetDefault(); + + + /* + status of parsing + */ + enum Status { ok, cant_open_file, syntax_error, no_space }; + + + /* + the last status of parsing, set by Parse() methods + */ + Status status; + + + /* + a number of a line in which there is a syntax_error + */ + int line; + + + /* + main methods used to parse + file_name is the path to a file + */ + Status Parse(const char * file_name); + Status Parse(const std::string & file_name); + Status Parse(const wchar_t * file_name); + Status Parse(const std::wstring & file_name); + + + /* + main methods used to parse + str - input string (either 8bit ascii or UTF-8 -- see UTF8() method) + */ + Status ParseString(const char * str); + Status ParseString(const std::string & str); + + + /* + main methods used to parse + here input string is always in unicode (wide characters) + */ + Status ParseString(const wchar_t * str); + Status ParseString(const std::wstring & str); + + + /* + if your list consists of only one item, e.g: + option1 = value 1 + option2 = "value 2" + option3 = ( "value 3" ) + then if you call SplitSingle(true) then such values will be stored in + 'table_single' instead of 'table' map + default: false + */ + void SplitSingle(bool split); + + + /* + if true then empty values and lists, e.g: + option = + option2 = () + will be omitted (not inserted to 'table' or 'table_single') + default: false + */ + void SkipEmpty(bool skip); + + + /* + '\' character is used to escape other characters in a quoted string + so "some \t t\"ext" will produce "some t t"ext" + (this is only use in quoted string) + default: true + */ + void UseEscapeChar(bool escape); + + + /* + if true then the input file or string (char* or std::string) is treated as UTF-8 + */ + void UTF8(bool utf); + + +private: + + + /* + current space set by SetSpace(); + */ + Space * root_space; + + + /* + a space in which we are now + */ + Space * space; + + + /* + true if Parse() method was called + false if ParseString() was called + */ + bool reading_from_file; + + + /* + pointers to the current character + if ParseString() is in used + */ + const char * pchar_ascii; + const wchar_t * pchar_unicode; + + + /* + true if ParseString(wchar_t *) or ParseString(std::wstring&) was called + */ + bool reading_from_wchar_string; + + + /* + last read variable (option) + */ + std::wstring variable; + + + /* + last read list item + */ + std::wstring value_item; + + + /* + last read list + */ + Space::Value value; + + + /* + separator between a variable and a value, default: '=' + */ + int separator; + + + /* + commentary char, default: '#' + */ + int commentary; + + + /* + list starting character, default: '(' + */ + int list_start; + + + /* + list ending character, default: ')' + */ + int list_end; + + + /* + list delimiter, default: ',' + */ + int list_delimiter; + + + /* + last read char + or -1 if the end + */ + int lastc; + + + /* + current file + */ + std::ifstream file; + + + /* + if true then lists with one item will be put into 'table_single' table + default: false + */ + bool split_single; + + + /* + if true then empty lists, e.g: + option = + option2 = () + will be omitted (not inserted to 'table' or 'table_single') + default: false + */ + bool skip_empty; + + + /* + input file is in UTF-8 + default: false + */ + bool input_as_utf8; + + + /* + if true you can use an escape character '\' in quoted values + */ + bool use_escape_char; + + + std::string afile_name; + + void Parse(); + void ParseLoop(); + void SpaceEnds(); + void SpaceStarts(); + void ReadAddValue(); + void AddOption(); + + void DeleteFromTable(const std::wstring & var); + void DeleteFromTableSingle(const std::wstring & var); + + void ReadVariable(); + bool ReadValue(); + bool ReadValueList(); + bool ReadValueNoList(bool use_list_delimiter = false); + bool ReadValueQuoted(); + bool ReadValueSimple(bool use_list_delimiter = false); + + int ReadUTF8Char(); + int ReadASCIIChar(); + int ReadCharFromWcharString(); + int ReadCharFromUTF8String(); + int ReadCharFromAsciiString(); + int ReadChar(); + bool IsWhite(int c); + bool IsVariableChar(int c); + void SkipWhite(); + void SkipWhiteLines(); + void SkipLine(); + void Trim(std::wstring & s); + +}; + + +} // namespace + + +#endif diff --git a/confparser/space.cpp b/confparser/space.cpp new file mode 100755 index 0000000..6209203 --- /dev/null +++ b/confparser/space.cpp @@ -0,0 +1,374 @@ +/* + * This file is a part of PicoTools + * 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 +{ + + + +Space::Space() +{ + parent = 0; +} + + +Space::~Space() +{ + Clear(); +} + + +Space::Space(const Space & s) +{ + operator=(s); +} + + +Space & Space::operator=(const Space & s) +{ + Clear(); + + name = s.name; + table_single = s.table_single; + table = s.table; + parent = s.parent; + + for(size_t i=0 ; iparent = this; + spaces.push_back(pspace); + } + +return *this; +} + + + + + + +void Space::Clear() +{ + name.clear(); + table_single.clear(); + table.clear(); + + for(size_t i=0 ; isecond; + } + else + { + Table::iterator t = table.find(name); + + if( t == table.end() || t->second.empty() ) + { + return 0; + } + else + { + return &t->second[0]; + } + } +} + + + + + +std::wstring & Space::Text(const wchar_t * name) +{ + tmp_name = name; + return Text(tmp_name, L""); +} + + + +std::wstring & Space::Text(const wchar_t * name, const wchar_t * def) +{ + tmp_name = name; + return Text(tmp_name, def); +} + + +std::wstring & Space::Text(const std::wstring & name, const wchar_t * def) +{ + std::wstring * value = GetValue(name); + + if( value ) + { + return *value; + } + else + { + tmp_value_text = def; + return tmp_value_text; + } +} + + + +std::string & Space::AText(const wchar_t * name) +{ + tmp_name = name; + return AText(tmp_name, ""); +} + + + +std::string & Space::AText(const wchar_t * name, const char * def) +{ + tmp_name = name; + return AText(tmp_name, def); +} + + +std::string & Space::AText(const std::wstring & name, const char * def) +{ + std::wstring * value = GetValue(name); + + if( value ) + { + PT::WideToUTF8(*value, tmp_value_text_ascii); + return tmp_value_text_ascii; + } + else + { + tmp_value_text_ascii = def; + return tmp_value_text_ascii; + } +} + + + + +int Space::Int(const wchar_t * name) +{ + tmp_name = name; + return Int(tmp_name, 0); +} + + +int Space::Int(const wchar_t * name, int def) +{ + tmp_name = name; + return Int(tmp_name, def); +} + + +int Space::ToInt(const std::wstring & value) +{ + long res = (value[0] == '0')? wcstol(value.c_str() + 1, 0, 8) : wcstol(value.c_str(), 0, 10); + +return static_cast(res); +} + + +int Space::Int(const std::wstring & name, int def) +{ + std::wstring * value = GetValue(name); + + if( value ) + return ToInt(*value); + +return def; +} + + + +size_t Space::Size(const wchar_t * name) +{ + tmp_name = name; + return Size(tmp_name, 0); +} + + +size_t Space::Size(const wchar_t * name, size_t def) +{ + tmp_name = name; + return Size(tmp_name, def); +} + + + +size_t Space::ToSize(const std::wstring & value) +{ + unsigned long res = (value[0] == '0')? wcstoul(value.c_str() + 1, 0, 8) : wcstoul(value.c_str(), 0, 10); + +return static_cast(res); +} + + +size_t Space::Size(const std::wstring & name, size_t def) +{ + std::wstring * value = GetValue(name); + + if( value ) + return ToSize(*value); + +return def; +} + + + + +bool Space::Bool(const wchar_t * name) +{ + tmp_name = name; + return Bool(tmp_name, false); +} + + +bool Space::Bool(const wchar_t * name, bool def) +{ + tmp_name = name; + return Bool(tmp_name, def); +} + + + +bool Space::ToBool(const std::wstring & value) +{ + return ( EqualNoCase(value.c_str(), L"true") || + EqualNoCase(value.c_str(), L"yes") || + EqualNoCase(value.c_str(), L"1") + ); +} + + +bool Space::Bool(const std::wstring & name, bool def) +{ + std::wstring * value = GetValue(name); + + if( value ) + return ToBool(*value); + +return def; +} + + + + +// in lists we don't use default values +bool Space::ListText(const wchar_t * name, std::vector & list) +{ + tmp_name = name; + return ListText(tmp_name, list); +} + + +bool Space::ListText(const std::wstring & name, std::vector & list) +{ + list.clear(); + TableSingle::iterator i = table_single.find(name); + + if( i != table_single.end() ) + { + list.push_back(i->second); + return true; + } + else + { + Table::iterator t = table.find(name); + + if( t != table.end() ) + { + list = t->second; + return true; + } + } + +return false; +} + + +wchar_t Space::ToSmall(wchar_t c) +{ + if( c>='A' && c<='Z' ) + c = c - 'A' + 'a'; + +return c; +} + + +bool Space::EqualNoCase(const wchar_t * str1, const wchar_t * str2) +{ + while( *str1 && *str2 && ToSmall(*str1) == ToSmall(*str2) ) + { + ++str1; + ++str2; + } + + if( *str1 == 0 && *str2 == 0 ) + return true; + +return false; +} + + +} // namespace + + + diff --git a/confparser/space.h b/confparser/space.h new file mode 100755 index 0000000..590f03d --- /dev/null +++ b/confparser/space.h @@ -0,0 +1,442 @@ +/* + * This file is a part of PicoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2010-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. + */ + +#ifndef headerfile_picotools_confparser_space +#define headerfile_picotools_confparser_space + +#include +#include +#include +#include +#include + + +namespace PT +{ + + + +/* +A parser for parsing config files. + +A config file can look like this: + variable1 = value 1 + variable2 = " value 2 " + variable3 = (value 1, value 2) + variable4 = (" value 1 " , "value2", value 3) + +sample of use: + ConfParser parser; + parser.Parse("/path/to/config"); + + if( parser.status == ConfParser::ok ) + { + // the whole config we have in parser.table (parser.table_single) + } + +config syntax: + option = list + + list can consists of any number of items, if you're using more than one item you should + use brackets () + + for one item the brackets can be ommited: + option = value + white characters at the beginning of the value (and at the end) will be trimmed, + or you can use quotes: + option = "value" + option2 = "value with spaces at the end " + + the form without quotes: + option = value + should be written in one line, so this is not allowed: + option = + value + you can use a new line characters only between brackets and quotes: + option = "this is + a multiline string" + option = ( value1, + value2 ) + + but there is one requirement: the first character " or ( should be in the same line, + so this is not allowed + option = + "this is wrong" + but this is ok: + option = " + that is ok" + + empty lists: + option = () + this creates an empty list: parser.table['option'].empty() == true + + option = + this creates an empty list too (the same as previously) + + option = "" + but this doesn't create an empty list, it creates a list with one (empty) item + + commentaries: + # this is a commentary (until the end of the line) + option = value # this is a commentary too + + commentaries are treated as white characters, other example: + option = ( # this is my list + "value 1" # this is a value one + value 2 # and this is a value two + ) # end of my list + + overwriting: + option1 = some value + option1 = other value + # always the last option is used so option1 is "other value" + + list delimiter: + option1 = (value1, value2, value3) + option2 = ("value1", "value2", "value3") + above we're using a comma ',' as a list delimiter but when using quotes (second line) + the commas can be omitted: + option2 = ("value1" "value2" "value3") + + white characters: + the name of an option cannot consist of white characters + some option = value # this is wrong + some_option = value # this is ok + + which characters are allowed in an option name is defined by IsVariableChar() method + + you can use white characters in values + option = value with spaces or tabs + white characters at the beginning and at the end will be trimmed, + so if you want them use quotes: + option = " other value with spaces " + + special characters in quoted strings: + option = "this is a string with \" a quote inside" + the option will be: this is a string with " a quote inside + \\ - means one \ + basically: \char produces char + so: + "\a" gives "a" + "\\" gives "\" + "\Z" gives "Z" and so on + you can call UseEscapeChar(false) to turn this off + + +*/ + + + +class Space +{ +public: + + Space(); + ~Space(); + + Space(const Space & s); + Space & operator=(const Space & s); + + void Clear(); + + + // first we are searching in 'table_single' and if there is not + // such a 'name' there then we are looking in 'table' (for the first item in the vector) + // these methods return true if 'name' was found + // in other case they return false and 'out' will be equal 'def' + // they can return a null pointer if there is not such a 'name' + std::wstring * GetValue(const wchar_t * name); + std::wstring * GetValue(const std::wstring & name); + + + /* + those methods are used to extract information from space.table or space.table_single + as a parameter they take the name of an option + and a default value (if there is no such a parameter), + they return appropriate value (either text, int or boolean) + (in lists they return the first item if exists) + + when calling Text(...) and AText(...) you should copy the object to whom a reference is returned + it will be cleared in a next call to one of these methods (as well to Int() Size() and Bool()) + + AText(...) always returns a reference to UTF-8 string + */ + std::wstring & Text(const wchar_t * name); + std::wstring & Text(const wchar_t * name, const wchar_t * def); + std::wstring & Text(const std::wstring & name, const wchar_t * def); + std::string & AText(const wchar_t * name); + std::string & AText(const wchar_t * name, const char * def); + std::string & AText(const std::wstring & name, const char * def); + int Int(const wchar_t *); + int Int(const wchar_t * name, int def); + int Int(const std::wstring & name, int def); + size_t Size(const wchar_t *); + size_t Size(const wchar_t * name, size_t def); + size_t Size(const std::wstring & name, size_t def); + bool Bool(const wchar_t *); + bool Bool(const wchar_t * name, bool def); + bool Bool(const std::wstring & name, bool def); + + + + /* + * + * + raw access to the parsed values + * + * + */ + + /* + this is the table which represents your config file + in the Table map: the first (key) is your 'option' and the second is 'list' + */ + typedef std::vector Value; + typedef std::map Table; + + + + /* + if your config file consists mainly of single forms such as: + option = value + option2 = value2 + then you can call SplitSingle(true) for not inserting single values to + previous 'table' but instead to 'table_single' + table_single as the second parameter takes only std::wstring (instead of the whole std::vector) + so you can save a little memory from not using std::vector + */ + typedef std::map TableSingle; + + + std::wstring name; // space name + TableSingle table_single; // std::map + Table table; // std::map > + + // childs + typedef std::vector Spaces; + std::vector spaces; + + // a parent space + // null means a root space + Space * parent; + + /* + those methods are used to extract lists + note: if there is one option in table_single they will return it + return true if such an option exists (but value can be an empty list) + */ + bool ListText(const wchar_t * name, std::vector & list); + bool ListText(const std::wstring & name, std::vector & list); + + + /* + serialize the content + */ + template + void Serialize(Stream & out, bool use_indents = false, bool use_comments = false, int level = 0) const; + +private: + std::wstring tmp_name; + std::wstring tmp_value_text; + std::string tmp_value_text_ascii; + + int ToInt(const std::wstring & value); + size_t ToSize(const std::wstring & value); + bool ToBool(const std::wstring & value); + wchar_t ToSmall(wchar_t c); + bool EqualNoCase(const wchar_t * str1, const wchar_t * str2); + + + template + void PrintLevel(Stream & out, bool use_indents, int level) const; + + template + void SerializeTableSingle(Stream & out, bool use_indents, int level) const; + + template + void SerializeTableMulti(Stream & out, bool use_indents, int level) const; + + template + void PrintValue(Stream & out, const std::wstring & str) const; + +}; + + + + + +template +void Space::PrintLevel(Stream & out, bool use_indents, int level) const +{ + if( use_indents ) + { + for(int i=0 ; i +void Space::PrintValue(Stream & out, const std::wstring & str) const +{ + out << '\"'; + + for(size_t i=0 ; i +void Space::SerializeTableSingle(Stream & out, bool use_indents, int level) const +{ + if( !table_single.empty() ) + { + TableSingle::const_iterator i; + + for(i = table_single.begin() ; i != table_single.end() ; ++i) + { + PrintLevel(out, use_indents, level); + out << i->first << L" = "; + PrintValue(out, i->second); + out << '\n'; + } + } +} + + + +template +void Space::SerializeTableMulti(Stream & out, bool use_indents, int level) const +{ +Table::const_iterator i2; +size_t v; + + + if( !table.empty() ) + { + for(i2 = table.begin() ; i2 != table.end() ; ++i2) + { + PrintLevel(out, use_indents, level); + out << i2->first << L" = "; + + if( i2->second.size() != 1 ) + out << '('; + + for(v = 0 ; v < i2->second.size() ; ++v) + { + if( v > 0 ) + PrintLevel(out, use_indents, level + i2->first.size() + 3); + + PrintValue(out, i2->second[v]); + + if( v + 1 < i2->second.size() ) + out << '\n'; + } + + if( i2->second.size() != 1 ) + out << ')'; + + out << '\n'; + } + } +} + + +template +void Space::Serialize(Stream & out, bool use_indents, bool use_comments, int level) const +{ + if( level > 0 ) + { + out << '\n'; + PrintLevel(out, use_indents, level); + + if( !name.empty() ) + out << name << ' '; + + out << L"(\n"; + + if( use_comments ) + { + PrintLevel(out, use_indents, level); + out << L"# space level " << level << '\n'; + } + } + + SerializeTableSingle(out, use_indents, level); + SerializeTableMulti(out, use_indents, level); + + for(size_t i=0 ; iSerialize(out, use_indents, use_comments, level+1); + + if( level > 0 ) + { + PrintLevel(out, use_indents, level); + out << ')'; + + if( use_comments ) + { + if( name.empty() ) + out << L" # end of unnamed space"; + else + out << L" # end of space: " << name; + + out << L" (level " << level << L")"; + } + + out << '\n'; + } +} + + +} // namespace + + + +#endif