/* * 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-2013, 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_ezc_generator #define headerfile_ezc_generator #include "pattern.h" #include "functions.h" #include #include #include namespace Ezc { /* StreamType we use only method write(const wchar_t * str, size_t len) from the stream */ template class Generator { public: Generator(); Generator(const Generator & n); Generator & operator=(const Generator & n); ~Generator(); void SetMax(size_t max_items_, size_t max_for_items_); // recognizing some special characters in text patterns (item_text in Patterns) // \r will be a carriage return (13) // \n will be a new line (10) // \t will be a tabulator (9) // \s will be a space // \\ will be one '\' // if the second character is different from those shown above the first slash will be printed // so "\x" gives "\x" // default: false void RecognizeSpecialChars(bool spec); // trimming white characters (at the beginning and at the end of an item_text) // (special char \s if enabled is not treated as a white character here) // default: false void TrimWhite(bool trim); // skipping new line characters (from the whole string in an item_text) // but you can use a new line character written as "\n" (if special chars are turn on) // default: false void SkipNewLine(bool skip); // default: 20 void SetMaxFilters(size_t new_len); // default stack size: 300 void SetStackSize(size_t new_stack_size); // do not print anything to stream stream_index // useful when using Generate() method with StreamType tables // this is a small optimization if we know that a stream with stream_index will not be used later // set stream_index to -1 to turn off (default) void SkipStream(int stream_index); // the main methods for generating void Generate(StreamType & o, Pattern & p, Functions & f); void Generate(std::vector & o, Pattern & p, Functions & f); void Generate(std::vector & o, Pattern & p, Functions & f); // this method is used only if the pattern has cached functions void Generate(StreamType & o, Pattern & p); void Generate(std::vector & o, Pattern & p); void Generate(std::vector & o, Pattern & p); private: // current output stream // if we are printing only to one stream e.g. [put stream "3"] // then output_stream is pointing directly to that stream // but if we are printing to more than one stream e.g. [put stream "0" "2" "5"] // then output_stream is pointing to output_tmp_stream and at the end // output_tmp_stream is copied to the correct streams // output_stream can be null e.g. [put stream] without arguments // in such a case we do not print anything StreamType * output_stream; Pattern * pattern; Functions * functions; // output_tmp_stream is used when outputting to more than one stream // (first we output to output_tmp_stream and then the content is copied // to the correct streams) StreamType output_tmp_stream; // pointers to the output streams std::vector output_stream_tab; // indices to output_stream_tab // they are set by [put stream ...] keyword // at the beginning there is only one index created automatically - "0" std::vector output_stream_index; // if has_skip_stream_index is true then when reading stream indices from [put stream ...] // a stream with skip_stream_index index will be ignored bool has_skip_stream_index; size_t skip_stream_index; // temporary error messages std::wstring temp_msg; bool break_generating; size_t current_item; size_t max_items; size_t max_for_items; bool special_chars; bool trim_white; bool skip_new_line; size_t stack_index; size_t stack_size; size_t filter_index; size_t filter_size; // we have to use a pointers table because standard streams such // as std::wostringstream are not copyable std::vector filter_tab; const StreamType empty_stream; // temporary streams used in [if..] [is...] or [for...] // or if output_stream is null and an ezc function should be called StreamType stream_temp1, stream_temp2; // whether last function has put its content in case_sensitive (set FunInfo::case_sensitive) bool last_case_sensitive; // last result from a user function (FunInfo::res) bool last_res; // true if this Generator is working now bool is_generator_working; // true if the Generator is working with [for ...], [if ...] etc. bool is_generating_for; bool is_generating_if; bool is_generating_is; bool is_generating_normal; bool is_generating_filter; // an empty string for FunInfo objects // when there is no any parameters const std::wstring empty; // a stack for [for] statements std::vector stack_tab; void ResizeFilterTab(); void ResizeStack(); void ClearFilterTab(); void ClearForStack(bool resize_stack = true); void ClearStream(StreamType & str); void RemoveStackFunData(Stack & sitem); template CharType ToLower(CharType c); template bool StrCmpNc(CharType * str1, CharType * str2); bool AreStreamsEqual(StreamType & str1, StreamType & str2, bool case_sensitive); bool Find(const Item::Function & item_fun, typename Functions::Function ** function); void Call(typename Functions::Function * function, FunInfo & info); void Call(typename Functions::Function * function, std::vector & params, StreamType & out_stream, bool clear_out_stream, const StreamType & in_stream); bool Call(Item::Function & item_fun, StreamType & out_stream, bool clear_out_stream); bool Call(Item::Function & function); wchar_t CreateSpecialChar(wchar_t c); const wchar_t * PrintSpecialChar(const wchar_t * start, const wchar_t * end); void PrintSpecialText(const wchar_t * start, const wchar_t * end); void PrintNormalText(const wchar_t * start, const wchar_t * end); void TrimWhite(const wchar_t *& start, const wchar_t *& end); void SkipWhite(const wchar_t *& str); size_t StrToSize(const wchar_t * str, const wchar_t ** str_end = 0); bool LookForLastForStatement(size_t & last_for_index); void WriteTmpStreamToStreams(); void CreateMsg(const wchar_t * type, const wchar_t * arg = 0); void CreateMsg(const std::wstring & type, const std::wstring & arg); void CreateMsg(const std::wstring & type); void CreateUnknownMsg(const std::wstring & fun); bool LimitAchieved(); void MakeTextIf_go(Item & item, bool result); bool MakeTextIfindexnumber(Item & item, size_t for_index, bool & result); void MakeTextIf(Item & item); void MakeTextIfno(Item & item); void MakeTextIfany(Item & item); void MakeTextIfone(Item & item); void MakeTextIfanyno(Item & item); void MakeTextIfoneno(Item & item); void MakeTextIfindex(Item & item); void MakeTextForLoop(Item & item, typename Functions::Function * function); void MakeTextFor(Item & item); void MakeItemText(Item & item); void MakeTextContainer(Item & item); void MakeTextNormal(Item & item); void MakeTextIs(Item & item, bool equal); void MakeTextIs(Item & item); void MakeTextIsno(Item & item); void MakeTextDefine(Item & item); void MakeTextFilter(Item & item); void MakeTextEzc(Item & item); void MakeText(Item & item); void MakeEzcStream(Item::Function & fun); void Generate(Pattern * p, Functions * f); }; // class Generator template Generator::Generator() : empty_stream() { output_stream = 0; pattern = 0; functions = 0; max_items = 50000; max_for_items = 5000; filter_size = 20; special_chars = false; trim_white = false; skip_new_line = false; is_generator_working = false; stack_size = 300; has_skip_stream_index = false; } template Generator::Generator(const Generator & n) { operator=(n); } template Generator & Generator::operator=(const Generator & n) { // !! CHECK ME may output_streams should not be copied? output_stream_tab = n.output_stream_tab; output_stream_index = n.output_stream_index; output_tmp_stream = n.output_tmp_stream; output_stream = n.output_stream; pattern = n.pattern; functions = n.functions; max_items = n.max_items; max_for_items = n.max_for_items; special_chars = n.special_chars; trim_white = n.trim_white; skip_new_line = n.skip_new_line; has_skip_stream_index = n.has_skip_stream_index; // filter and stack will be auto resized after next call to Generate() method filter_size = n.filter_size; stack_size = n.stack_size; // don't copy filter tab // don't copy stack // !! CHECK ME // may copying should be denied when generator is working? // don't copy 'is_generator_working' flag is_generator_working = false; return *this; } template Generator::~Generator() { ClearFilterTab(); ClearForStack(); } template void Generator::ResizeFilterTab() { if( filter_tab.size() != filter_size ) { if( filter_tab.size() < filter_size ) { for(size_t i=filter_tab.size() ; i void Generator::ResizeStack() { if( stack_tab.size() != stack_size ) { if( stack_tab.size() > stack_size ) { for(size_t i=stack_size ; i void Generator::ClearFilterTab() { for(size_t i=0 ; i void Generator::ClearForStack(bool resize_stack) { for(size_t i=0 ; i void Generator::ClearStream(StreamType & str) { #ifdef EZC_HAS_SPECIAL_STREAM str.Clear(); #else str.str(L""); #endif } template void Generator::RemoveStackFunData(Stack & s) { if( s.fun_data && s.remove ) { delete s.fun_data; s.fun_data = 0; } } template void Generator::SkipStream(int stream_index) { if( stream_index < 0 ) { has_skip_stream_index = false; } else { has_skip_stream_index = true; skip_stream_index = stream_index; } } template template CharType Generator::ToLower(CharType c) { if( c>='A' && c<='Z' ) return c - 'A' + 'a'; return c; } template template bool Generator::StrCmpNc(CharType * str1, CharType * str2) { for( ; ToLower(*str1) == ToLower(*str2) ; ++str1, ++str2) if( *str1 == 0 ) return true; return false; } template bool Generator::AreStreamsEqual(StreamType & str1, StreamType & str2, bool case_sensitive) { if( case_sensitive ) { #ifdef EZC_HAS_SPECIAL_STREAM return str1.Str() == str2.Str(); #else return str1.str() == str2.str(); #endif } else { #ifdef EZC_HAS_SPECIAL_STREAM return StrCmpNc(str1.CStr(), str2.CStr()); #else return StrCmpNc(str1.str().c_str(), str2.str().c_str()); #endif } } template void Generator::SetMax(size_t max_items_, size_t max_for_items_) { max_items = max_items_; max_for_items = max_for_items_; } template void Generator::RecognizeSpecialChars(bool spec) { special_chars = spec; } template void Generator::TrimWhite(bool trim) { trim_white = trim; } template void Generator::SkipNewLine(bool skip) { skip_new_line = skip; } template void Generator::SetMaxFilters(size_t new_len) { // the table will be resized when Generate() method is called filter_size = new_len; } template void Generator::SetStackSize(size_t new_stack_size) { // the stack will be resized when Generate() method is called stack_size = new_stack_size; } template void Generator::Generate(Pattern * p, Functions * f) { if( is_generator_working ) { CreateMsg(L"generator busy"); return; } output_stream = 0; output_stream_index.clear(); ClearStream(output_tmp_stream); if( !output_stream_tab.empty() ) { if( !has_skip_stream_index || skip_stream_index != 0 ) { output_stream_index.push_back(0); output_stream = output_stream_tab[0]; } } pattern = p; functions = f; break_generating = false; current_item = 0; // in the case that there something has left on the stack // from previous call to Generate() // (an exception could have been thrown) ClearForStack(false); ResizeFilterTab(); ResizeStack(); filter_index = 0; stack_index = 0; if( pattern ) { try { is_generator_working = true; MakeText( pattern->item_root ); if( output_stream_index.size() > 1 ) WriteTmpStreamToStreams(); is_generator_working = false; } catch(...) { is_generator_working = false; throw; } } } template void Generator::Generate(StreamType & o, Pattern & p, Functions & f) { output_stream_tab.resize(1); output_stream_tab[0] = &o; Generate(&p, &f); } template void Generator::Generate(std::vector & o, Pattern & p, Functions & f) { output_stream_tab.resize(o.size()); for(size_t i=0 ; i void Generator::Generate(std::vector & o, Pattern & p, Functions & f) { output_stream_tab.resize(o.size()); for(size_t i=0 ; i void Generator::Generate(StreamType & o, Pattern & p) { output_stream_tab.resize(1); output_stream_tab[0] = &o; Generate(&p, 0); } template void Generator::Generate(std::vector & o, Pattern & p) { output_stream_tab.resize(o.size()); for(size_t i=0 ; i void Generator::Generate(std::vector & o, Pattern & p) { output_stream_tab.resize(o.size()); for(size_t i=0 ; i bool Generator::Find(const Item::Function & item_fun, typename Functions::Function ** function) { if( !functions ) { if( item_fun.fun_cache ) { *function = reinterpret_cast::Function*>(item_fun.fun_cache); return true; } else { CreateUnknownMsg(item_fun.name); return false; } } if( !functions->Find(item_fun.name, function) ) { CreateUnknownMsg(item_fun.name); return false; } return true; } template void Generator::Call(typename Functions::Function * function, FunInfo & info) { info.Clear(); info.is_for = is_generating_for; info.is_if = is_generating_if; info.is_is = is_generating_is; info.is_normal = is_generating_normal; info.is_filter = is_generating_filter; info.stack = &stack_tab[stack_index-1]; info.iter = stack_tab[stack_index-1].iter; if( function->type == Functions::function ) { (function->user_function)(info); } else { info.out << function->variable; info.res = !function->variable.empty(); } last_res = info.res; last_case_sensitive = info.case_sensitive; } template void Generator::Call(typename Functions::Function * function, std::vector & params, StreamType & out_stream, bool clear_out_stream, const StreamType & in_stream) { if( clear_out_stream ) ClearStream(out_stream); if( params.empty() ) { FunInfo info(out_stream, params, empty, in_stream); Call(function, info); } else { FunInfo info(out_stream, params, params[0], in_stream); Call(function, info); } } // return: true if a function or variable was found and called template bool Generator::Call(Item::Function & item_fun, StreamType & out_stream, bool clear_out_stream) { typename Functions::Function * fun; if( !Find(item_fun, &fun) ) return false; Call(fun, item_fun.params, out_stream, clear_out_stream, empty_stream); return true; } // return: true if a function or variable was found and called template bool Generator::Call(Item::Function & item_fun) { return Call(item_fun, stream_temp1, true); } template wchar_t Generator::CreateSpecialChar(wchar_t c) { wchar_t res = 0; if( c == 'r' ) res = '\r'; else if( c == 'n' ) res = '\n'; else if( c == 't' ) res = '\t'; else if( c == 's' ) res = ' '; else if( c == '\\' ) res = '\\'; return res; } // a special character is precedeed by a slash '\' // if the special character is unknown the first slash is printing // so "\t" gives one character of code 9 // and "\x" gives "\x" template const wchar_t * Generator::PrintSpecialChar(const wchar_t * start, const wchar_t * end) { wchar_t special = 0; if( *start == '\\' && (start+1) != end ) special = CreateSpecialChar(*(start+1)); if( special ) { output_stream->write(&special, 1); start += 2; } else { if( !skip_new_line || *start != 10 ) output_stream->write(start, 1); start += 1; } return start; } template void Generator::PrintSpecialText(const wchar_t * start, const wchar_t * end) { if( output_stream ) { while( start != end ) { const wchar_t * end2 = start; // looking for a first new line character or a special char // (for new line only if skip_new_line is true) while( end2 != end && *end2 != '\\' && (!skip_new_line || *end2 != 10) ) end2 += 1; // printing the first part of the text if( start != end2 ) output_stream->write(start, end2 - start); start = end2; // skipping one or more new line characters or special chars // (new lines only if skip_new_line is true) while( start != end && (*start == '\\' || (skip_new_line && *start == 10)) ) start = PrintSpecialChar(start, end); } } } template void Generator::PrintNormalText(const wchar_t * start, const wchar_t * end) { if( output_stream ) { if( skip_new_line ) { while( start != end ) { const wchar_t * end2 = start; // looking for a first new line character while( end2 != end && *end2 != 10 ) end2 += 1; // printing the first part of the text (until the new line) if( start != end2 ) output_stream->write(start, end2 - start); start = end2; // skipping one or more new line characters while( start != end && *start == 10 ) start += 1; } } else { if( start != end ) output_stream->write(start, end - start); } } } template void Generator::TrimWhite(const wchar_t *& start, const wchar_t *& end) { while( start != end && pattern->IsWhite(*start) ) ++start; while( start != end && pattern->IsWhite(*(end-1)) ) --end; } template void Generator::SkipWhite(const wchar_t *& str) { while( pattern->IsWhite(*str) ) str += 1; } template size_t Generator::StrToSize(const wchar_t * str, const wchar_t ** str_end) { size_t res = 0; SkipWhite(str); // !! IMPROVE ME // overflow is not checked while( *str>='0' && *str<='9' ) { res *= 10; res += *str - '0'; str += 1; } SkipWhite(str); if( str_end ) *str_end = str; return res; } template void Generator::WriteTmpStreamToStreams() { #ifdef EZC_HAS_SPECIAL_STREAM const std::wstring & str = output_tmp_stream.Str(); #else const std::wstring & str = output_tmp_stream.str(); #endif if( !str.empty() ) { for(size_t s = 0 ; s < output_stream_index.size() ; ++s) { size_t i = output_stream_index[s]; if( i < output_stream_tab.size() ) output_stream_tab[i]->write(str.c_str(), str.size()); } ClearStream(output_tmp_stream); } } template void Generator::CreateMsg(const wchar_t * type, const wchar_t * arg) { if( output_stream ) { pattern->CreateMsg(temp_msg, type, arg); output_stream->write(temp_msg.c_str(), temp_msg.size()); } } template void Generator::CreateMsg(const std::wstring & type, const std::wstring & arg) { CreateMsg(type.c_str(), arg.c_str()); } template void Generator::CreateMsg(const std::wstring & type) { CreateMsg(type.c_str()); } template void Generator::CreateUnknownMsg(const std::wstring & fun) { CreateMsg(L"unknown function", fun.c_str()); } template void Generator::MakeItemText(Item & item) { const wchar_t * start = item.text.c_str(); const wchar_t * end = item.text.c_str() + item.text.size(); if( trim_white ) TrimWhite(start, end); if( special_chars ) PrintSpecialText(start, end); else PrintNormalText(start, end); } template void Generator::MakeTextContainer(Item & item) { std::vector::iterator i = item.item_tab.begin(); for( ; i != item.item_tab.end() && !break_generating ; ++i ) MakeText(**i); } template void Generator::MakeTextNormal(Item & item) { if( item.functions.size() != 1 ) return; is_generating_normal = true; if( output_stream ) { Call(item.functions[0], *output_stream, false); } else { Call(item.functions[0], stream_temp1, false); ClearStream(stream_temp1); } } template void Generator::MakeTextIf_go(Item & item, bool result) { if( result ) { if( item.item_tab.size() > 0 ) MakeText( *item.item_tab[0] ); } else { // second element can be (or not -- it's from [else]) if( item.item_tab.size() > 1 ) MakeText( *item.item_tab[1] ); } } template void Generator::MakeTextIf(Item & item) { if( item.functions.size() != 1 ) return; is_generating_if = true; if( !Call(item.functions[0]) ) return; MakeTextIf_go(item, last_res); } template void Generator::MakeTextIfno(Item & item) { if( item.functions.size() != 1 ) return; is_generating_if = true; if( !Call(item.functions[0]) ) return; MakeTextIf_go(item, !last_res); } template void Generator::MakeTextIfany(Item & item) { std::vector::iterator d = item.functions.begin(); unsigned how_many_true = 0; is_generating_if = true; for( ; d != item.functions.end() ; ++d ) { if( !Call(*d) ) return; if( last_res ) ++how_many_true; } MakeTextIf_go(item, how_many_true == item.functions.size()); } template void Generator::MakeTextIfone(Item & item) { std::vector::iterator d = item.functions.begin(); unsigned how_many_true = 0; is_generating_if = true; for( ; d != item.functions.end() ; ++d ) { if( Call(*d) ) { if( last_res ) { ++how_many_true; break; // there is no sense to go through all functions } } } MakeTextIf_go(item, how_many_true > 0); } template void Generator::MakeTextIfanyno(Item & item) { std::vector::iterator d = item.functions.begin(); unsigned how_many_true = 0; is_generating_if = true; for( ; d != item.functions.end() ; ++d ) { if( !Call(*d) ) return; if( last_res ) ++how_many_true; } MakeTextIf_go(item, how_many_true == 0); } template void Generator::MakeTextIfoneno(Item & item) { std::vector::iterator d = item.functions.begin(); unsigned how_many_false = 0; is_generating_if = true; for( ; d != item.functions.end() ; ++d ) { if( Call(*d) ) { if( !last_res ) { ++how_many_false; break; } } } MakeTextIf_go(item, how_many_false > 0); } template void Generator::MakeTextIs(Item & item, bool equal) { if( item.functions.size() != 2 ) return; is_generating_is = true; // if one of these two functions has set case_sensitive to false // then we compare in case insensitive mode bool case_sensitive = true; if( !Call(item.functions[0], stream_temp1, true) ) return; if( !last_case_sensitive ) case_sensitive = false; if( !Call(item.functions[1], stream_temp2, true) ) return; if( !last_case_sensitive ) case_sensitive = false; bool res = AreStreamsEqual(stream_temp1, stream_temp2, case_sensitive); if( !equal ) res = !res; MakeTextIf_go(item, res); } template void Generator::MakeTextIs(Item & item) { MakeTextIs(item, true); } template void Generator::MakeTextIsno(Item & item) { MakeTextIs(item, false); } template bool Generator::LookForLastForStatement(size_t & last_for_index) { last_for_index = stack_index; while( last_for_index-- > 0 ) { if( stack_tab[last_for_index].is_for ) return true; } return false; } template bool Generator::MakeTextIfindexnumber(Item & item, size_t for_index, bool & result) { if( item.functions.size() != 1 ) return false; const wchar_t * number_text = item.functions[0].name.c_str(); const wchar_t * last_char; size_t number = StrToSize(number_text, &last_char); if( *last_char != '\0' ) { CreateMsg(L"if-index: syntax error"); return false; } result = (stack_tab[for_index].iter == number); return true; } template void Generator::MakeTextIfindex(Item & item) { size_t for_index; if( item.functions.size() != 1 || !LookForLastForStatement(for_index) ) return; bool result = false; if( item.functions[0].name == L"odd" ) { result = (stack_tab[for_index].iter & 1) == 1; } else if( item.functions[0].name == L"even" ) { result = (stack_tab[for_index].iter & 1) == 0; } else if( item.functions[0].name == L"first" ) { result = stack_tab[for_index].iter == 0; } else { if( !MakeTextIfindexnumber(item, for_index, result) ) return; } MakeTextIf_go(item, result); } template void Generator::MakeTextForLoop(Item & item, typename Functions::Function * function) { stack_tab[stack_index-1].is_for = true; for( ; !break_generating ; stack_tab[stack_index-1].iter += 1 ) { if( stack_tab[stack_index-1].iter >= max_for_items ) { CreateMsg(item.functions[0].name.c_str(), L"function exceeded a limit for a [for] statement"); break; } // is_generating_for will be changed by next call to MakeText() // so we should set it in each iterations is_generating_for = true; Call(function, item.functions[0].params, stream_temp1, true, empty_stream); if( !last_res ) break; if( !item.item_tab.empty() ) MakeText( *item.item_tab[0] ); // should be only one item - item_container } } template void Generator::MakeTextFor(Item & item) { if( item.functions.size() != 1 ) return; typename Functions::Function * function; if( !Find(item.functions[0], &function) ) return; MakeTextForLoop(item, function); } template void Generator::MakeTextDefine(Item & item) { if( !functions ) { CreateMsg(L"[def] statement is not available when used without functions set"); return; } if( item.functions.size() == 1 ) { // inserting a new variable if( item.functions[0].params.size() == 1 ) functions->Insert(item.functions[0].name, item.functions[0].params[0]); } else if( item.functions.size() == 2 ) { typename Functions::Function * function; if( Find(item.functions[1], &function) ) { if( function->type == Functions::function ) { // inserting a new function functions->Insert(item.functions[0].name, function->user_function); } else { // inserting a new variable (the value is copied) functions->Insert(item.functions[0].name, function->variable); } } } } template void Generator::MakeTextFilter(Item & item) { if( item.functions.size() != 1 ) return; typename Functions::Function * function; if( !Find(item.functions[0], &function) ) return; if( filter_index >= filter_tab.size() ) { CreateMsg(L"Generator exceeded allowed number of filters"); return; } StreamType * old_stream = output_stream; output_stream = filter_tab[filter_index]; ClearStream(*output_stream); filter_index += 1; if( !item.item_tab.empty() ) MakeText( *item.item_tab[0] ); // should be only one item - item_container is_generating_filter = true; if( old_stream ) { Call(function, item.functions[0].params, *old_stream, false, *output_stream); } else { Call(function, item.functions[0].params, stream_temp1, true, *output_stream); ClearStream(stream_temp1); } ClearStream(*output_stream); output_stream = old_stream; filter_index -= 1; } template void Generator::MakeEzcStream(Item::Function & fun) { if( output_stream_index.size() > 1 ) WriteTmpStreamToStreams(); output_stream_index.clear(); for(size_t i=0 ; i 1 ) { ClearStream(output_tmp_stream); output_stream = &output_tmp_stream; } else if( output_stream_index.size() == 1 ) { size_t index = output_stream_index[0]; output_stream = output_stream_tab[index]; } else { output_stream = 0; } } template void Generator::MakeTextEzc(Item & item) { for(size_t i=0 ; i bool Generator::LimitAchieved() { if( break_generating ) return true; if( ++current_item > max_items ) { break_generating = true; CreateMsg(L"Generator exceeded allowed number of elements"); return true; } if( ++stack_index > stack_tab.size() ) { break_generating = true; CreateMsg(L"Generator exceeded the stack size"); return true; } return false; } template void Generator::MakeText(Item & item) { if( LimitAchieved() ) return; is_generating_for = false; is_generating_if = false; is_generating_is = false; is_generating_normal = false; is_generating_filter = false; stack_tab[stack_index-1].Clear(); if ( item.type == Item::item_text ) MakeItemText(item); else if( item.type == Item::item_container )MakeTextContainer(item); else if( item.type == Item::item_normal ) MakeTextNormal(item); else if( item.type == Item::item_if ) MakeTextIf(item); else if( item.type == Item::item_ifno ) MakeTextIfno(item); else if( item.type == Item::item_ifany ) MakeTextIfany(item); else if( item.type == Item::item_ifone ) MakeTextIfone(item); else if( item.type == Item::item_ifanyno ) MakeTextIfanyno(item); else if( item.type == Item::item_ifoneno ) MakeTextIfoneno(item); else if( item.type == Item::item_ifindex ) MakeTextIfindex(item); else if( item.type == Item::item_is ) MakeTextIs(item); else if( item.type == Item::item_isno ) MakeTextIsno(item); else if( item.type == Item::item_def ) MakeTextDefine(item); else if( item.type == Item::item_for ) MakeTextFor(item); else if( item.type == Item::item_filter ) MakeTextFilter(item); else if( item.type == Item::item_ezc ) MakeTextEzc(item); else if( item.type == Item::item_err ) CreateMsg(L"a wrong directive"); RemoveStackFunData(stack_tab[stack_index-1]); stack_index -=1; } } // namespace Ezc #endif