importing confparser to pikotools

git-svn-id: svn://ttmath.org/publicrep/pikotools/trunk@371 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2012-01-12 00:24:08 +00:00
parent 67e694219d
commit f2ba48a10e
7 changed files with 1860 additions and 0 deletions

29
confparser/Makefile Executable file
View File

@ -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

4
confparser/Makefile.dep Executable file
View File

@ -0,0 +1,4 @@
# DO NOT DELETE
confparser.o: confparser.h ../utf8/utf8.h
space.o: confparser.h ../utf8/utf8.h

1
confparser/Makefile.o.dep Executable file
View File

@ -0,0 +1 @@
o = confparser.o space.o

684
confparser/confparser.cpp Executable file
View File

@ -0,0 +1,684 @@
/*
* This file is a part of PicoTools
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* 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 <cstdlib>
#include <wchar.h>
#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 ; i<s.size() && IsWhite(s[i]) ; ++i);
// deleting white characters at the beginning
if( i != 0 )
s.erase(0, i);
}
void ConfParser::AddOption()
{
if( value.empty() && skip_empty )
{
DeleteFromTable(variable);
DeleteFromTableSingle(variable);
return;
}
if( split_single && value.size() == 1 )
{
space->table_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

326
confparser/confparser.h Executable file
View File

@ -0,0 +1,326 @@
/*
* This file is a part of PicoTools
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* 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 <fstream>
#include <string>
#include <vector>
#include <list>
#include <map>
#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

374
confparser/space.cpp Executable file
View File

@ -0,0 +1,374 @@
/*
* This file is a part of PicoTools
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* 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 <cstdlib>
#include <wchar.h>
#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 ; i<s.spaces.size() ; ++i)
{
Space * pspace = new Space(*s.spaces[i]);
pspace->parent = this;
spaces.push_back(pspace);
}
return *this;
}
void Space::Clear()
{
name.clear();
table_single.clear();
table.clear();
for(size_t i=0 ; i<spaces.size() ; ++i)
delete spaces[i];
spaces.clear();
}
std::wstring * Space::GetValue(const wchar_t * name)
{
tmp_name = name;
return GetValue(tmp_name);
}
std::wstring * Space::GetValue(const std::wstring & name)
{
TableSingle::iterator i = table_single.find(name);
if( i != table_single.end() )
{
return &i->second;
}
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<int>(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<size_t>(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<std::wstring> & list)
{
tmp_name = name;
return ListText(tmp_name, list);
}
bool Space::ListText(const std::wstring & name, std::vector<std::wstring> & 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

442
confparser/space.h Executable file
View File

@ -0,0 +1,442 @@
/*
* This file is a part of PicoTools
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* 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 <fstream>
#include <string>
#include <vector>
#include <list>
#include <map>
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<std::wstring> Value;
typedef std::map<std::wstring, Value> 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<std::wstring, std::wstring> TableSingle;
std::wstring name; // space name
TableSingle table_single; // std::map<std::wstring, std::wstring>
Table table; // std::map<std::wstring, std::vector<std::wstring> >
// childs
typedef std::vector<Space*> Spaces;
std::vector<Space*> 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<std::wstring> & list);
bool ListText(const std::wstring & name, std::vector<std::wstring> & list);
/*
serialize the content
*/
template<class Stream>
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<class Stream>
void PrintLevel(Stream & out, bool use_indents, int level) const;
template<class Stream>
void SerializeTableSingle(Stream & out, bool use_indents, int level) const;
template<class Stream>
void SerializeTableMulti(Stream & out, bool use_indents, int level) const;
template<class Stream>
void PrintValue(Stream & out, const std::wstring & str) const;
};
template<class Stream>
void Space::PrintLevel(Stream & out, bool use_indents, int level) const
{
if( use_indents )
{
for(int i=0 ; i<level ; ++i)
out << ' ';
}
}
template<class Stream>
void Space::PrintValue(Stream & out, const std::wstring & str) const
{
out << '\"';
for(size_t i=0 ; i<str.size() ; ++i)
{
if( str[i] == '\\' )
out << L"\\\\";
else
if( str[i] == '"' )
out << L"\\\"";
else
if( str[i] == 0 )
out << L"\\0";
else
out << str[i];
}
out << '\"';
}
template<class Stream>
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<class Stream>
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<class Stream>
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 ; i<spaces.size() ; ++i)
spaces[i]->Serialize(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