/* * This file is a part of EZC -- Easy templating in C++ * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2007-2011, 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 "pattern.h" namespace Ezc { Pattern::Pattern() { Clear(); commentary_start = L""; allow_include = true; input_as_utf8 = false; delete_white_text_items = false; include_level_max = 100; } void Pattern::Clear() { item_root.Clear(); } 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]); } void Pattern::Directory(const char * dir, const char * dir2) { directory.clear(); directory2.clear(); if( dir ) UTF8ToWide(dir, directory); if( dir2 ) UTF8ToWide(dir2, directory2); } void Pattern::Directory(const std::string & dir) { UTF8ToWide(dir, directory); directory2.clear(); } void Pattern::Directory(const std::string & dir, const std::string & dir2) { UTF8ToWide(dir, directory); UTF8ToWide(dir2, directory2); } 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) { UTF8ToWide(file_name, item_root.file_name); 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) { if( input_as_utf8 ) UTF8ToWide(str, string_content); else AssignString(str, string_content); 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) { UTF8ToWide(com_start, commentary_start); UTF8ToWide(com_stop, commentary_stop); } void Pattern::SetCommentary(const std::string & com_start, const std::string & com_stop) { UTF8ToWide(com_start, commentary_start); UTF8ToWide(com_stop, commentary_stop); } 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; out += L"Ezc: "; 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) ) { CreateMsg(result, L"incorrect file name: ", name); } 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 if( include_level <= 1 ) log << log3 << "Ezc: reading pattern: " << afile_name << logend; else log << log3 << " including pattern: " << afile_name << logend; #endif ReadFile(file, result); 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(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='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(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 log << log1 << "Ezc: \"include\" directive has reached the maximum level" << logend; #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); if( pitem->type == Item::item_for || pitem->type == Item::item_filter ) CreateTreeReadFor(*pitem); if( pitem->type == Item::item_include ) CreateTreeReadInclude(*pitem); } } } // namespace Ezc