2007-02-08 18:54:37 +01:00
|
|
|
/*
|
|
|
|
* This file is a part of TTCalc - a mathematical calculator
|
|
|
|
* and is distributed under the (new) BSD licence.
|
|
|
|
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2008-10-13 06:17:57 +02:00
|
|
|
* Copyright (c) 2006-2008, Tomasz Sowa
|
2007-02-08 18:54:37 +01:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2007-01-22 12:12:01 +01:00
|
|
|
#include "compileconfig.h"
|
|
|
|
|
|
|
|
#include "iniparser.h"
|
|
|
|
|
|
|
|
|
|
|
|
IniParser::IniParser()
|
|
|
|
{
|
|
|
|
strip_white_characters_from_value = true;
|
|
|
|
convert_value_to_small_letters = true;
|
2008-01-24 00:51:53 +01:00
|
|
|
section_case_sensitive = false;
|
|
|
|
pattern_case_sensitive = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::ConvertValueToSmallLetters(bool conv)
|
|
|
|
{
|
|
|
|
convert_value_to_small_letters = conv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::SectionCaseSensitive(bool sens)
|
|
|
|
{
|
|
|
|
section_case_sensitive = sens;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::PatternCaseSensitive(bool sens)
|
|
|
|
{
|
|
|
|
pattern_case_sensitive = sens;
|
2007-01-22 12:12:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::Associate(const char * pattern, std::string * result)
|
|
|
|
{
|
|
|
|
table.insert( std::make_pair(std::string(pattern), result) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::Associate(const std::string & pattern, std::string * result)
|
|
|
|
{
|
|
|
|
table.insert( std::make_pair(pattern, result) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniParser::Associate(const char * pattern, std::map<std::string, std::string> * result)
|
|
|
|
{
|
|
|
|
table_whole_section.insert( std::make_pair(std::string(pattern), result) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniParser::Associate(const std::string & pattern, std::map<std::string, std::string> * result)
|
|
|
|
{
|
|
|
|
table_whole_section.insert( std::make_pair(pattern, result) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void IniParser::Clear()
|
|
|
|
{
|
|
|
|
table.clear();
|
|
|
|
table_whole_section.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IniParser::Error IniParser::ReadFromFile(const char * path)
|
|
|
|
{
|
|
|
|
file.open(path);
|
|
|
|
|
|
|
|
if(!file)
|
|
|
|
return err_cant_open_file;
|
|
|
|
|
|
|
|
Error err = Read();
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int IniParser::GetBadLine()
|
|
|
|
{
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IniParser::Error IniParser::Read()
|
|
|
|
{
|
|
|
|
std::string section, pattern, value;
|
|
|
|
Error err;
|
|
|
|
|
|
|
|
line = 1;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
err = ReadSection(section);
|
|
|
|
if( err != err_ok )
|
|
|
|
break;
|
|
|
|
|
|
|
|
err = ReadExpression(pattern, value);
|
|
|
|
|
|
|
|
while( err == err_ok )
|
|
|
|
{
|
|
|
|
if( strip_white_characters_from_value )
|
|
|
|
StripWhiteCharacters(value);
|
|
|
|
|
|
|
|
CheckAndSet( section, pattern, value );
|
|
|
|
|
|
|
|
err = ReadExpression(pattern, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
while( err == err_is_section );
|
|
|
|
|
|
|
|
|
|
|
|
if( err == err_file_end )
|
|
|
|
err = err_ok;
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IniParser::Error IniParser::ReadSection(std::string & section)
|
|
|
|
{
|
|
|
|
section.erase();
|
|
|
|
|
|
|
|
int c = SkipCommentaryAndEmptyLines();
|
|
|
|
if( c == EOF )
|
|
|
|
return err_file_end;
|
|
|
|
|
|
|
|
if( c != '[' )
|
|
|
|
{
|
|
|
|
// this line is not for a section (empty section?)
|
|
|
|
ReturnCharacter(c);
|
|
|
|
return err_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( IsSectionCharacter( (c = ReadCharacter()) ) )
|
2008-01-24 00:51:53 +01:00
|
|
|
if( section_case_sensitive )
|
|
|
|
section += c;
|
|
|
|
else
|
|
|
|
section += LowerCase(c);
|
2007-01-22 12:12:01 +01:00
|
|
|
|
|
|
|
if( c != ']' )
|
|
|
|
{
|
|
|
|
ReturnCharacter(c);
|
|
|
|
return err_incorrect_character;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int IniParser::SkipCommentaryAndEmptyLines()
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
SkipWhiteCharacters();
|
|
|
|
c = ReadCharacter();
|
|
|
|
|
|
|
|
if( c == '#' )
|
|
|
|
SkipLine();
|
|
|
|
else
|
|
|
|
if( c == 10 )
|
|
|
|
c='#';
|
|
|
|
}
|
|
|
|
while( c == '#' );
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
IniParser::Error IniParser::CheckEndOfLine()
|
|
|
|
{
|
|
|
|
SkipWhiteCharacters();
|
|
|
|
int c = ReadCharacter();
|
|
|
|
|
|
|
|
if( c == EOF )
|
|
|
|
return err_file_end;
|
|
|
|
|
|
|
|
if( c != 10 )
|
|
|
|
{
|
|
|
|
ReturnCharacter(c);
|
|
|
|
return err_incorrect_character;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err_ok;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IniParser::Error IniParser::ReadExpression(std::string & pattern, std::string & value)
|
|
|
|
{
|
|
|
|
pattern.erase();
|
|
|
|
value.erase();
|
|
|
|
|
|
|
|
int c = SkipCommentaryAndEmptyLines();
|
|
|
|
if( c == EOF )
|
|
|
|
return err_file_end;
|
|
|
|
|
|
|
|
if( c == '[' )
|
|
|
|
{
|
|
|
|
ReturnCharacter(c);
|
|
|
|
return err_is_section;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( IsPatternCharacter(c) )
|
|
|
|
{
|
2008-01-24 00:51:53 +01:00
|
|
|
if( pattern_case_sensitive )
|
|
|
|
pattern += c;
|
|
|
|
else
|
|
|
|
pattern += LowerCase(c);
|
|
|
|
|
2007-01-22 12:12:01 +01:00
|
|
|
c = ReadCharacter();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( IsWhiteCharacter(c) )
|
|
|
|
{
|
|
|
|
SkipWhiteCharacters();
|
|
|
|
c = ReadCharacter();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( c != '=' )
|
|
|
|
{
|
|
|
|
ReturnCharacter(c);
|
|
|
|
return err_incorrect_character;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkipWhiteCharacters();
|
|
|
|
|
|
|
|
while( IsValueCharacter( (c = ReadCharacter()) ) )
|
|
|
|
if( convert_value_to_small_letters )
|
|
|
|
value += LowerCase(c);
|
|
|
|
else
|
|
|
|
value += c;
|
|
|
|
|
|
|
|
ReturnCharacter(c);
|
|
|
|
|
|
|
|
//return CheckEndOfLine();
|
|
|
|
return err_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::CheckAndSet(const std::string & section, const std::string & pattern, const std::string & value)
|
|
|
|
{
|
|
|
|
TableWholeSection::iterator iw = table_whole_section.find( section );
|
|
|
|
|
|
|
|
if( iw != table_whole_section.end() )
|
|
|
|
{
|
|
|
|
(*iw->second).insert( std::make_pair( pattern, value ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Table::iterator i = table.find( section + '|' + pattern );
|
|
|
|
|
|
|
|
if( i == table.end() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
*i->second = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IniParser::IsWhiteCharacter(int c)
|
|
|
|
{
|
|
|
|
// 13 is in 'dos and windows' systems at the end of a text file (13 and 10 exactly)
|
|
|
|
if( c==' ' || c=='\t' || c==13 )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::SkipWhiteCharacters()
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
while( IsWhiteCharacter( (c=ReadCharacter()) ) );
|
|
|
|
|
|
|
|
ReturnCharacter(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int IniParser::ReadCharacter()
|
|
|
|
{
|
|
|
|
int c = file.get();
|
|
|
|
|
|
|
|
if( !file )
|
|
|
|
c = EOF;
|
|
|
|
else
|
|
|
|
if( c == 10 )
|
|
|
|
++line;
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::ReturnCharacter(int c)
|
|
|
|
{
|
|
|
|
file.unget();
|
|
|
|
|
|
|
|
if( c == 10 )
|
|
|
|
--line;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool IniParser::IsSectionCharacter(int c)
|
|
|
|
{
|
|
|
|
if( (c>='a' && c<='z') ||
|
|
|
|
(c>='A' && c<='Z') ||
|
|
|
|
(c>='0' && c<='9') ||
|
|
|
|
c=='_' || c=='.' )
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool IniParser::IsPatternCharacter(int c)
|
|
|
|
{
|
|
|
|
return IsSectionCharacter(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool IniParser::IsValueCharacter(int c)
|
|
|
|
{
|
|
|
|
if( c!=10 && c!=EOF )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::SkipLine()
|
|
|
|
{
|
|
|
|
while( ReadCharacter() != 10 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int IniParser::LowerCase(int c)
|
|
|
|
{
|
|
|
|
if( c>='A' && c<='Z')
|
|
|
|
return c - 'A' + 'a';
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
this function sets '*start' and '*end' to point to the middle part of the string
|
|
|
|
without any whitespaces at the end and at the beginning
|
|
|
|
|
|
|
|
'*start' will be the first correct character
|
|
|
|
'*end' will be after the last correct character
|
|
|
|
*/
|
|
|
|
void IniParser::CheckWhiteCharacters(const char * string, const char ** start, const char ** end)
|
|
|
|
{
|
|
|
|
const char * p;
|
|
|
|
|
|
|
|
// we're setting 'p' at the end of the string (at '\0' character)
|
|
|
|
for( p = string ; *p ; ++p );
|
|
|
|
|
|
|
|
if( p == string )
|
|
|
|
{
|
|
|
|
// an empty string
|
|
|
|
*start = *end = string;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we're looking for a last character which is different than a white character
|
|
|
|
for( --p ; p != string && (*p==' ' || *p=='\t') ; --p );
|
|
|
|
|
|
|
|
// 'end' will be after the last character
|
|
|
|
*end = p+1;
|
|
|
|
|
|
|
|
// we're looking for a first character which is different than a white character
|
|
|
|
for( p = string ; *p==' ' || *p=='\t' ; ++p );
|
|
|
|
|
|
|
|
*start = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void IniParser::StripWhiteCharacters(std::string & string)
|
|
|
|
{
|
|
|
|
const char *s, * start, * end;
|
|
|
|
|
|
|
|
s = string.c_str();
|
|
|
|
CheckWhiteCharacters(s, &start, &end);
|
|
|
|
|
|
|
|
|
|
|
|
std::string::size_type istart, iend;
|
|
|
|
|
|
|
|
istart = start - s;
|
|
|
|
iend = end - s;
|
|
|
|
|
|
|
|
string.erase(iend, string.length() - iend);
|
|
|
|
string.erase(0, istart);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|