2010-11-22 02:23:32 +01:00
|
|
|
/*
|
|
|
|
* This file is a part of EZC -- Easy templating in C++
|
|
|
|
* and is distributed under the (new) BSD licence.
|
|
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2011-01-15 00:59:30 +01:00
|
|
|
* Copyright (c) 2007-2011, Tomasz Sowa
|
2010-11-22 02:23:32 +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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "pattern.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Ezc
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pattern::Pattern()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
|
|
|
|
commentary_start = L"<!-- ";
|
|
|
|
commentary_stop = L" -->";
|
|
|
|
|
|
|
|
allow_include = true;
|
|
|
|
input_as_utf8 = false;
|
|
|
|
delete_white_text_items = false;
|
|
|
|
|
|
|
|
include_level_max = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::Clear()
|
|
|
|
{
|
|
|
|
item_root.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-25 23:39:58 +01:00
|
|
|
void Pattern::ClearCache()
|
|
|
|
{
|
|
|
|
ClearCache(item_root);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ClearCache(Item & item)
|
|
|
|
{
|
|
|
|
for(size_t f = 0; f < item.functions.size() ; ++f)
|
|
|
|
item.functions[f].fun_cache = 0;
|
|
|
|
|
|
|
|
for(size_t i = 0; i < item.item_tab.size() ; ++i)
|
|
|
|
ClearCache(*item.item_tab[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-22 02:23:32 +01:00
|
|
|
|
|
|
|
void Pattern::Directory(const char * dir, const char * dir2)
|
|
|
|
{
|
|
|
|
directory.clear();
|
|
|
|
directory2.clear();
|
|
|
|
|
|
|
|
if( dir )
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(dir, directory);
|
2010-11-22 02:23:32 +01:00
|
|
|
|
|
|
|
if( dir2 )
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(dir2, directory2);
|
2010-11-22 02:23:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::Directory(const std::string & dir)
|
|
|
|
{
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(dir, directory);
|
2010-11-22 02:23:32 +01:00
|
|
|
directory2.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::Directory(const std::string & dir, const std::string & dir2)
|
|
|
|
{
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(dir, directory);
|
|
|
|
UTF8ToWide(dir2, directory2);
|
2010-11-22 02:23:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::Directory(const wchar_t * dir, const wchar_t * dir2)
|
|
|
|
{
|
|
|
|
directory.clear();
|
|
|
|
directory2.clear();
|
|
|
|
|
|
|
|
if( dir )
|
|
|
|
directory = dir;
|
|
|
|
|
|
|
|
if( dir2 )
|
|
|
|
directory2 = dir2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::Directory(const std::wstring & dir)
|
|
|
|
{
|
|
|
|
directory = dir;
|
|
|
|
directory2.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::Directory(const std::wstring & dir, const std::wstring & dir2)
|
|
|
|
{
|
|
|
|
directory = dir;
|
|
|
|
directory2 = dir2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseFile(const std::string & file_name)
|
|
|
|
{
|
|
|
|
ParseFile( file_name.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseFile(const char * file_name)
|
|
|
|
{
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(file_name, item_root.file_name);
|
2010-11-22 02:23:32 +01:00
|
|
|
include_level = 0;
|
|
|
|
CreateTreeReadIncludeSkipAllowFlag(item_root);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseFile(const std::wstring & file_name)
|
|
|
|
{
|
|
|
|
ParseFile( file_name.c_str() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseFile(const wchar_t * file_name)
|
|
|
|
{
|
|
|
|
item_root.file_name = file_name;
|
|
|
|
include_level = 0;
|
|
|
|
CreateTreeReadIncludeSkipAllowFlag(item_root);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseString(const char * str)
|
|
|
|
{
|
2010-11-25 23:39:58 +01:00
|
|
|
if( input_as_utf8 )
|
|
|
|
UTF8ToWide(str, string_content);
|
|
|
|
else
|
|
|
|
AssignString(str, string_content);
|
|
|
|
|
2010-11-22 02:23:32 +01:00
|
|
|
ParseString(string_content.c_str());
|
|
|
|
string_content.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseString(const std::string & str)
|
|
|
|
{
|
|
|
|
ParseString(str.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseString(const wchar_t * str)
|
|
|
|
{
|
|
|
|
itext = str;
|
|
|
|
include_level = 0;
|
|
|
|
CreateTree(item_root);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ParseString(const std::wstring & str)
|
|
|
|
{
|
|
|
|
ParseString(str.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::AllowInclude(bool allow)
|
|
|
|
{
|
|
|
|
allow_include = allow;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::DeleteWhiteTextItems(bool del)
|
|
|
|
{
|
|
|
|
delete_white_text_items = del;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::SetIncludeMax(int include_max)
|
|
|
|
{
|
|
|
|
include_level_max = include_max;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::UTF8(bool utf8)
|
|
|
|
{
|
|
|
|
input_as_utf8 = utf8;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::SetCommentary(const char * com_start, const char * com_stop)
|
|
|
|
{
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(com_start, commentary_start);
|
|
|
|
UTF8ToWide(com_stop, commentary_stop);
|
2010-11-22 02:23:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::SetCommentary(const std::string & com_start, const std::string & com_stop)
|
|
|
|
{
|
2010-11-25 23:39:58 +01:00
|
|
|
UTF8ToWide(com_start, commentary_start);
|
|
|
|
UTF8ToWide(com_stop, commentary_stop);
|
2010-11-22 02:23:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::SetCommentary(const wchar_t * com_start, const wchar_t * com_stop)
|
|
|
|
{
|
|
|
|
commentary_start = com_start;
|
|
|
|
commentary_stop = com_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::SetCommentary(const std::wstring & com_start, const std::wstring & com_stop)
|
|
|
|
{
|
|
|
|
commentary_start = com_start;
|
|
|
|
commentary_stop = com_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg)
|
|
|
|
{
|
|
|
|
out = commentary_start;
|
2010-11-23 22:59:52 +01:00
|
|
|
out += L"Ezc: ";
|
2010-11-22 02:23:32 +01:00
|
|
|
out += type;
|
|
|
|
|
|
|
|
if( arg )
|
|
|
|
{
|
|
|
|
out += ' ';
|
|
|
|
out += arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
out += commentary_stop;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::HasFileAtBeginning(const wchar_t * path, const wchar_t * file)
|
|
|
|
{
|
|
|
|
for(; *path && *file; ++path, ++file)
|
|
|
|
{
|
|
|
|
if( *path != *file )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( *file != 0 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// "\" is from a dos path syntax
|
|
|
|
if( *path==0 || *path=='\\' || *path=='/' )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
".." is not allowed in the file path
|
|
|
|
you cannot go up from your template directory
|
|
|
|
*/
|
|
|
|
bool Pattern::IsFileCorrect(const wchar_t * name)
|
|
|
|
{
|
|
|
|
while( *name )
|
|
|
|
{
|
|
|
|
if( HasFileAtBeginning(name, L"..") )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// looking for the next slash of backslash
|
|
|
|
while( *name && *name!='\\' && *name!='/' )
|
|
|
|
name += 1;
|
|
|
|
|
|
|
|
// skipping the slash (or backslash)
|
|
|
|
if( *name )
|
|
|
|
name += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
'name' must be a relative path - without a slash or backslash
|
|
|
|
*/
|
|
|
|
void Pattern::ReadFile(const std::wstring & name, std::wstring & result)
|
|
|
|
{
|
|
|
|
ReadFile(name.c_str(), result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
'name' must be a relative path - without a slash or backslash
|
|
|
|
*/
|
|
|
|
void Pattern::ReadFile(const wchar_t * name, std::wstring & result)
|
|
|
|
{
|
|
|
|
if( !IsFileCorrect(name) )
|
|
|
|
{
|
2010-12-06 01:22:38 +01:00
|
|
|
CreateMsg(result, L"incorrect file name: ", name);
|
2010-11-22 02:23:32 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result.clear();
|
|
|
|
|
|
|
|
if( !ReadFileFromDir(directory, name, result) )
|
|
|
|
if( !ReadFileFromDir(directory2, name, result) )
|
|
|
|
CreateMsg(result, L"can't open: ", name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::ReadFileFromDir(const std::wstring & dir, const wchar_t * name, std::wstring & result)
|
|
|
|
{
|
|
|
|
if( dir.empty() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
file_name = dir;
|
|
|
|
file_name += '/';
|
|
|
|
file_name += name;
|
|
|
|
WideToUTF8(file_name, afile_name);
|
|
|
|
|
|
|
|
std::ifstream file(afile_name.c_str());
|
|
|
|
|
|
|
|
if( !file )
|
|
|
|
{
|
|
|
|
file_name.clear();
|
|
|
|
afile_name.clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef EZC_USE_WINIX_LOGGER
|
2010-11-25 23:39:58 +01:00
|
|
|
if( include_level <= 1 )
|
|
|
|
log << log3 << "Ezc: reading pattern: " << afile_name << logend;
|
|
|
|
else
|
|
|
|
log << log3 << " including pattern: " << afile_name << logend;
|
2010-11-22 02:23:32 +01:00
|
|
|
#endif
|
|
|
|
|
2010-11-25 23:39:58 +01:00
|
|
|
ReadFile(file, result);
|
|
|
|
|
2010-11-22 02:23:32 +01:00
|
|
|
file_name.clear();
|
|
|
|
afile_name.clear();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadFile(std::ifstream & file, std::wstring & result)
|
|
|
|
{
|
|
|
|
if( input_as_utf8 )
|
|
|
|
{
|
|
|
|
UTF8ToWide(file, result);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ReadFileContent(file, result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadFileContent(std::ifstream & file, std::wstring & result)
|
|
|
|
{
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
int c = file.get();
|
|
|
|
|
|
|
|
if( !file )
|
|
|
|
break;
|
|
|
|
|
|
|
|
result += static_cast<wchar_t>(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int Pattern::ReadCharInText()
|
|
|
|
{
|
|
|
|
if( *itext==0 || *itext=='[' )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if( *itext == '\\' )
|
|
|
|
{
|
|
|
|
if( *(itext+1)=='\\' || *(itext+1)=='[' || *(itext+1)==']' )
|
|
|
|
++itext;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *(itext++);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::IsWhite(wchar_t c)
|
|
|
|
{
|
|
|
|
// 13 (\r) is from a dos file at the end of a line (\r\n)
|
|
|
|
// 160 is a non-breaking space
|
|
|
|
|
|
|
|
if( c==' ' || c=='\t' || c==13 || c==160 || c==10 )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::SkipWhite()
|
|
|
|
{
|
|
|
|
while( IsWhite(*itext) )
|
|
|
|
++itext;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CheckWhiteAndDelete(std::wstring & s)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if( s.empty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(i=0 ; i<s.size() && IsWhite(s[i]) ; ++i);
|
|
|
|
|
|
|
|
if( i == s.size() )
|
|
|
|
s.clear(); // the whole string consists of white characters
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::IsNameChar(wchar_t c)
|
|
|
|
{
|
|
|
|
return ((c>='a' && c<='z') ||
|
|
|
|
(c>='A' && c<='Z') ||
|
|
|
|
(c>='0' && c<='9') ||
|
|
|
|
c=='_' || c=='-' || c=='.' || c=='#');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::IsDigit(wchar_t c)
|
|
|
|
{
|
|
|
|
return (c>='0' && c<='9');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::IsPositiveNumber(const std::wstring & str)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for(i=0 ; i<str.size() ; ++i)
|
|
|
|
if( !IsDigit(str[i]) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// reading an expression name or a function name
|
|
|
|
bool Pattern::ReadName(std::wstring & name)
|
|
|
|
{
|
|
|
|
name.clear();
|
|
|
|
SkipWhite();
|
|
|
|
|
|
|
|
while( IsNameChar(*itext) )
|
|
|
|
{
|
|
|
|
name += *itext;
|
|
|
|
++itext;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !name.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// string can have a quote character (escaped with a backslash) e.g. "sample text \"with quotes\""
|
|
|
|
// use \\ to insert one backslash
|
|
|
|
bool Pattern::ReadString(std::wstring & str)
|
|
|
|
{
|
|
|
|
str.clear();
|
|
|
|
SkipWhite();
|
|
|
|
|
|
|
|
// string is signed by its first quote character (")
|
|
|
|
if( *itext != '\"' )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
++itext;
|
|
|
|
|
|
|
|
while( *itext && *itext!='\"' )
|
|
|
|
{
|
|
|
|
if( itext[0]=='\\' && itext[1]=='\"' )
|
|
|
|
{
|
|
|
|
str += '\"';
|
|
|
|
itext += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( itext[0]=='\\' && itext[1]=='\\' )
|
|
|
|
{
|
|
|
|
str += '\\';
|
|
|
|
itext += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str += *itext;
|
|
|
|
itext += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( *itext == '\"' )
|
|
|
|
++itext;
|
|
|
|
|
|
|
|
// if there was not a quote at the end we do not report an error
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::ReadParams(Item::Function & function)
|
|
|
|
{
|
|
|
|
function.params.clear();
|
|
|
|
|
|
|
|
while( ReadString(temp_param) )
|
|
|
|
function.params.push_back(temp_param);
|
|
|
|
|
|
|
|
temp_param.clear();
|
|
|
|
|
|
|
|
return !function.params.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::ReadFunction(Item::Function & function)
|
|
|
|
{
|
|
|
|
SkipWhite();
|
|
|
|
|
|
|
|
function.name.clear();
|
|
|
|
function.params.clear();
|
|
|
|
|
|
|
|
if( !ReadName(function.name) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ReadParams(function);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::ReadFunctions(Item & item)
|
|
|
|
{
|
|
|
|
item.functions.clear();
|
|
|
|
|
|
|
|
while( ReadFunction(temp_function) )
|
|
|
|
item.functions.push_back(temp_function);
|
|
|
|
|
|
|
|
temp_function.name.clear();
|
|
|
|
temp_function.params.clear();
|
|
|
|
|
|
|
|
return !item.functions.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadItemDirectiveCheckEnding(Item & item)
|
|
|
|
{
|
|
|
|
SkipWhite();
|
|
|
|
|
|
|
|
if( *itext != ']' )
|
|
|
|
{
|
|
|
|
item.type = Item::item_err;
|
|
|
|
|
|
|
|
while( *itext!=0 && *itext!=']' )
|
|
|
|
++itext;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( *itext == ']' )
|
|
|
|
++itext;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIf(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_if;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() != 1 )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIfno(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_ifno;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() != 1 )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIfany(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_ifany;
|
|
|
|
|
|
|
|
if( !ReadFunctions(item) )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIfone(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_ifone;
|
|
|
|
|
|
|
|
if( !ReadFunctions(item) )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIfanyno(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_ifanyno;
|
|
|
|
|
|
|
|
if( !ReadFunctions(item) )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIfoneno(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_ifoneno;
|
|
|
|
|
|
|
|
if( !ReadFunctions(item) )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIs(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_is;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() != 2 )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIsno(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_isno;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() != 2 )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveIfindex(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_err;
|
|
|
|
item.functions.clear();
|
|
|
|
temp_function.params.clear();
|
|
|
|
|
|
|
|
// reading: odd, even, first or a number (without quotes)
|
|
|
|
if( !ReadName(temp_function.name) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( temp_function.name != L"odd" && temp_function.name != L"even" &&
|
|
|
|
temp_function.name != L"first" && !IsPositiveNumber(temp_function.name) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
item.functions.push_back(temp_function);
|
|
|
|
item.type = Item::item_ifindex;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveFor(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_for;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() != 1 )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveComment(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_comment;
|
|
|
|
|
|
|
|
// skipping the comment
|
|
|
|
while( *itext && *itext!=']' )
|
|
|
|
++itext;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveInclude(Item & item)
|
|
|
|
{
|
|
|
|
if( ReadString(item.file_name) )
|
|
|
|
item.type = Item::item_include;
|
|
|
|
else
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::ReadDirectiveDef(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_err;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() == 1 )
|
|
|
|
{
|
|
|
|
if( item.functions[0].params.size() == 1 )
|
|
|
|
{
|
|
|
|
// this is: [def variable "value"]
|
|
|
|
item.type = Item::item_def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( item.functions.size() == 2 )
|
|
|
|
{
|
|
|
|
if( item.functions[0].params.empty() && item.functions[1].params.empty())
|
|
|
|
{
|
|
|
|
// this is:
|
|
|
|
// [def variable2 variable1], or
|
|
|
|
// [def function2 function1]
|
|
|
|
item.type = Item::item_def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-26 13:42:49 +01:00
|
|
|
void Pattern::ReadDirectiveFilter(Item & item)
|
|
|
|
{
|
|
|
|
item.type = Item::item_filter;
|
|
|
|
ReadFunctions(item);
|
|
|
|
|
|
|
|
if( item.functions.size() != 1 )
|
|
|
|
item.type = Item::item_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-11-22 02:23:32 +01:00
|
|
|
// user defined directive
|
|
|
|
void Pattern::ReadDirectiveNormal(const std::wstring & name, Item & item)
|
|
|
|
{
|
|
|
|
temp_function.name = name;
|
|
|
|
ReadParams(temp_function);
|
|
|
|
item.functions.clear();
|
|
|
|
item.functions.push_back(temp_function);
|
|
|
|
item.type = Item::item_normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadItemDirective(Item & item)
|
|
|
|
{
|
|
|
|
std::wstring name;
|
|
|
|
|
|
|
|
++itext;
|
|
|
|
ReadName(name);
|
|
|
|
|
|
|
|
if ( name == L"if" ) ReadDirectiveIf(item);
|
|
|
|
else if( name == L"if-no" ) ReadDirectiveIfno(item);
|
|
|
|
else if( name == L"if-any" ) ReadDirectiveIfany(item);
|
|
|
|
else if( name == L"if-one" ) ReadDirectiveIfone(item);
|
|
|
|
else if( name == L"if-any-no" ) ReadDirectiveIfanyno(item);
|
|
|
|
else if( name == L"if-one-no" ) ReadDirectiveIfoneno(item);
|
|
|
|
else if( name == L"if-index" ) ReadDirectiveIfindex(item);
|
|
|
|
else if( name == L"is" ) ReadDirectiveIs(item);
|
|
|
|
else if( name == L"is-no" ) ReadDirectiveIsno(item);
|
|
|
|
else if( name == L"end" ) item.type = Item::item_end;
|
|
|
|
else if( name == L"else" ) item.type = Item::item_else;
|
|
|
|
else if( name == L"for" ) ReadDirectiveFor(item);
|
|
|
|
else if( name == L"include" ) ReadDirectiveInclude(item);
|
|
|
|
else if( name == L"def" ) ReadDirectiveDef(item);
|
2011-01-26 13:42:49 +01:00
|
|
|
else if( name == L"filter" ) ReadDirectiveFilter(item);
|
2010-11-22 02:23:32 +01:00
|
|
|
else if( name == L"#" ) ReadDirectiveComment(item);
|
|
|
|
else
|
|
|
|
ReadDirectiveNormal(name, item);
|
|
|
|
|
|
|
|
CreateTreeReadItemDirectiveCheckEnding(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadItemText(Item & item)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
while( (c = ReadCharInText()) != -1 )
|
|
|
|
item.text += static_cast<wchar_t>(c);
|
|
|
|
|
|
|
|
if( delete_white_text_items )
|
|
|
|
CheckWhiteAndDelete(item.text);
|
|
|
|
|
|
|
|
item.type = Item::item_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Pattern::CreateTreeReadItem(Item & item)
|
|
|
|
{
|
|
|
|
item.Clear();
|
|
|
|
|
|
|
|
if( *itext == '[' )
|
|
|
|
{
|
|
|
|
CreateTreeReadItemDirective(item);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if( *itext )
|
|
|
|
{
|
|
|
|
CreateTreeReadItemText(item);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the end of the string
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadInclude(Item & item)
|
|
|
|
{
|
|
|
|
if( !allow_include )
|
|
|
|
return;
|
|
|
|
|
|
|
|
CreateTreeReadIncludeSkipAllowFlag(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadIncludeSkipAllowFlag(Item & item)
|
|
|
|
{
|
|
|
|
if( item.file_name.empty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( include_level > include_level_max )
|
|
|
|
{
|
|
|
|
#ifdef EZC_USE_WINIX_LOGGER
|
2010-11-23 22:59:52 +01:00
|
|
|
log << log1 << "Ezc: \"include\" directive has reached the maximum level" << logend;
|
2010-11-22 02:23:32 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
++include_level;
|
|
|
|
std::wstring file_text; // this temporary object must not be global (includes can be nested)
|
|
|
|
ReadFile(item.file_name, file_text);
|
|
|
|
|
|
|
|
const wchar_t * itext_old = itext;
|
|
|
|
itext = file_text.c_str();
|
|
|
|
CreateTree(item);
|
|
|
|
itext = itext_old;
|
|
|
|
--include_level;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadIf(Item & item)
|
|
|
|
{
|
|
|
|
Item * pitem = item.AddItem();
|
|
|
|
CreateTree(*pitem);
|
|
|
|
|
|
|
|
if( pitem->LastItemType() == Item::item_else )
|
|
|
|
{
|
|
|
|
pitem->DeleteLastItem();
|
|
|
|
|
|
|
|
pitem = item.AddItem();
|
|
|
|
CreateTree(*pitem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pitem->LastItemType() == Item::item_end )
|
|
|
|
pitem->DeleteLastItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTreeReadFor(Item & item)
|
|
|
|
{
|
|
|
|
Item * pitem = item.AddItem();
|
|
|
|
CreateTree(*pitem);
|
|
|
|
|
|
|
|
if( pitem->LastItemType() == Item::item_end )
|
|
|
|
pitem->DeleteLastItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Pattern::CreateTree(Item & item)
|
|
|
|
{
|
|
|
|
item.Clear();
|
|
|
|
item.type = Item::item_container;
|
|
|
|
|
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
Item * pitem = item.AddItem();
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if( !CreateTreeReadItem(*pitem) )
|
|
|
|
{
|
|
|
|
item.DeleteLastItem();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while( pitem->type == Item::item_comment );
|
|
|
|
|
|
|
|
if( pitem->type == Item::item_end || pitem->type == Item::item_else )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( pitem->type == Item::item_if ||
|
|
|
|
pitem->type == Item::item_ifno ||
|
|
|
|
pitem->type == Item::item_ifany ||
|
|
|
|
pitem->type == Item::item_ifone ||
|
|
|
|
pitem->type == Item::item_ifanyno ||
|
|
|
|
pitem->type == Item::item_ifoneno ||
|
|
|
|
pitem->type == Item::item_ifindex ||
|
|
|
|
pitem->type == Item::item_is ||
|
|
|
|
pitem->type == Item::item_isno )
|
|
|
|
CreateTreeReadIf(*pitem);
|
|
|
|
|
2011-01-26 13:42:49 +01:00
|
|
|
if( pitem->type == Item::item_for ||
|
|
|
|
pitem->type == Item::item_filter )
|
2010-11-22 02:23:32 +01:00
|
|
|
CreateTreeReadFor(*pitem);
|
|
|
|
|
|
|
|
if( pitem->type == Item::item_include )
|
|
|
|
CreateTreeReadInclude(*pitem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Ezc
|
|
|
|
|
|
|
|
|
|
|
|
|