changed: directory name: confparser -> space
git-svn-id: svn://ttmath.org/publicrep/pikotools/trunk@401 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
481
space/space.h
Executable file
481
space/space.h
Executable file
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* This file is a part of PikoTools
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
#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 * name);
|
||||
int Int(const wchar_t * name, int def);
|
||||
int Int(const std::wstring & name, int def);
|
||||
long Long(const wchar_t * name);
|
||||
long Long(const wchar_t * name, long def);
|
||||
long Long(const std::wstring & name, long def);
|
||||
size_t Size(const wchar_t * name);
|
||||
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);
|
||||
|
||||
std::wstring & FindAdd(const wchar_t * name);
|
||||
std::wstring & FindAdd(const std::wstring & name);
|
||||
|
||||
std::wstring & Add(const wchar_t * name, bool value);
|
||||
std::wstring & Add(const std::wstring & name, bool value);
|
||||
|
||||
std::wstring & Add(const wchar_t * name, int value);
|
||||
std::wstring & Add(const std::wstring & name, int value);
|
||||
|
||||
std::wstring & Add(const wchar_t * name, long value);
|
||||
std::wstring & Add(const std::wstring & name, long value);
|
||||
|
||||
std::wstring & Add(const wchar_t * name, const wchar_t * value);
|
||||
std::wstring & Add(const wchar_t * name, const std::wstring & value);
|
||||
std::wstring & Add(const std::wstring & name, const std::wstring & value);
|
||||
|
||||
void Remove(const wchar_t * name);
|
||||
void Remove(const std::wstring & name);
|
||||
|
||||
|
||||
|
||||
Space & AddSpace(const wchar_t * name);
|
||||
Space & AddSpace(const std::wstring & name);
|
||||
|
||||
// looking for the first space with the specified name
|
||||
// if there is not such a space those methods return a null pointer
|
||||
Space * FindSpace(const wchar_t * name);
|
||||
Space * FindSpace(const std::wstring & name);
|
||||
|
||||
// looking for the first space with the specified name
|
||||
// if there is not such a space then this methods adds such a space
|
||||
Space & FindAddSpace(const wchar_t * name);
|
||||
Space & FindAddSpace(const std::wstring & name);
|
||||
|
||||
void RemoveSpace(const wchar_t * name);
|
||||
void RemoveSpace(const std::wstring & name);
|
||||
void RemoveSpace(size_t child_index);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
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);
|
||||
long ToLong(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
|
Reference in New Issue
Block a user