From 9215130b9d3a46fe2f69bc3de59634268c1137c8 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 7 Nov 2013 10:16:10 +0000 Subject: [PATCH] added: possibility to generate output to more than one stream Generate() methods can take std::vector with pointers to streams added: 'ezc' keyword -- currently only for selecting streams e.g. [ezc stream "0" "3"] - after now the output is generated to streams 0 and 3 git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@445 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/generator.h | 359 +++++++++++++++++++++++++++++++++++++++--------- src/item.h | 5 +- src/pattern.cpp | 10 +- src/pattern.h | 3 +- 4 files changed, 311 insertions(+), 66 deletions(-) diff --git a/src/generator.h b/src/generator.h index e7d5c09..d9dae5b 100755 --- a/src/generator.h +++ b/src/generator.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2007-2012, Tomasz Sowa + * Copyright (c) 2007-2013, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -95,19 +95,54 @@ public: // 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 tmp_stream and at the end + // 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; - + + // tmp_stream is used when outputting to more than one stream + // (first we output to tmp_stream and then the content is copied + // to the correct streams) + StreamType 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; @@ -130,6 +165,7 @@ private: 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) @@ -188,10 +224,11 @@ private: 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); + size_t StrToSize(const wchar_t * str, const wchar_t ** str_end = 0); bool LookForLastForStatement(size_t & last_for_index); - void CreateMsg(StreamType & out, const wchar_t * type, const wchar_t * arg = 0); + + 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); @@ -217,9 +254,14 @@ private: void MakeTextIsno(Item & item); void MakeTextDefine(Item & item); void MakeTextFilter(Item & item); + void MakeTextEzc(Item & item); void MakeText(Item & item); - void Generate(StreamType * o, Pattern * p, Functions * f); + void MakeEzcStream(Item::Function & fun); + + void Generate(Pattern * p, Functions * f); + + }; // class Generator @@ -243,6 +285,7 @@ Generator::Generator() : empty_stream() skip_new_line = false; is_generator_working = false; stack_size = 300; + has_skip_stream_index = false; } @@ -257,15 +300,20 @@ Generator::Generator(const Generator & n) template Generator & Generator::operator=(const Generator & n) { - output_stream = n.output_stream; + // !! 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; @@ -372,6 +420,21 @@ void Generator::RemoveStackFunData(Stack & s) } +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 @@ -463,21 +526,31 @@ void Generator::SetStackSize(size_t new_stack_size) } + template -void Generator::Generate(StreamType * o, Pattern * p, Functions * f) +void Generator::Generate(Pattern * p, Functions * f) { if( is_generator_working ) { - if( o ) - CreateMsg(*o, L"generator busy"); - + CreateMsg(L"generator busy"); return; } - output_stream = o; - pattern = p; - functions = f; + output_stream = 0; + output_stream_index.clear(); + ClearStream(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; @@ -491,12 +564,16 @@ void Generator::Generate(StreamType * o, Pattern * p, Functionsitem_root ); + + if( output_stream_index.size() > 1 ) + WriteTmpStreamToStreams(); + is_generator_working = false; } catch(...) @@ -508,23 +585,77 @@ void Generator::Generate(StreamType * o, Pattern * p, Functions void Generator::Generate(StreamType & o, Pattern & p, Functions & f) { - Generate(&o, &p, &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) { - Generate(&o, &p, 0); + 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::Call(Item::Function & item_fun) - template wchar_t Generator::CreateSpecialChar(wchar_t c) { @@ -695,25 +825,28 @@ return start; template void Generator::PrintSpecialText(const wchar_t * start, const wchar_t * end) { - while( start != end ) + if( output_stream ) { - const wchar_t * end2 = start; + 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; + // 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); + // 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); + 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); + } } } @@ -721,31 +854,34 @@ void Generator::PrintSpecialText(const wchar_t * start, const wchar_ template void Generator::PrintNormalText(const wchar_t * start, const wchar_t * end) { - if( skip_new_line ) + if( output_stream ) { - while( start != end ) + if( skip_new_line ) { - const wchar_t * end2 = start; + while( start != end ) + { + const wchar_t * end2 = start; - // looking for a first new line character - while( end2 != end && *end2 != 10 ) - end2 += 1; + // 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); + // 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; + 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); } - } - else - { - if( start != end ) - output_stream->write(start, end-start); } } @@ -788,18 +924,35 @@ size_t res = 0; } SkipWhite(str); - *str_end = str; + + if( str_end ) + *str_end = str; return res; } - template -void Generator::CreateMsg(StreamType & out, const wchar_t * type, const wchar_t * arg) +void Generator::WriteTmpStreamToStreams() { - pattern->CreateMsg(temp_msg, type, arg); - out.write(temp_msg.c_str(), temp_msg.size()); + #ifdef EZC_HAS_SPECIAL_STREAM + const std::wstring & str = tmp_stream.Str(); + #else + const std::wstring & str = 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(tmp_stream); + } } @@ -808,7 +961,11 @@ void Generator::CreateMsg(StreamType & out, const wchar_t * type, co template void Generator::CreateMsg(const wchar_t * type, const wchar_t * arg) { - CreateMsg(*output_stream, type, arg); + if( output_stream ) + { + pattern->CreateMsg(temp_msg, type, arg); + output_stream->write(temp_msg.c_str(), temp_msg.size()); + } } @@ -871,7 +1028,16 @@ void Generator::MakeTextNormal(Item & item) return; is_generating_normal = true; - Call(item.functions[0], *output_stream, false); + + if( output_stream ) + { + Call(item.functions[0], *output_stream, false); + } + else + { + Call(item.functions[0], stream_temp1, false); + ClearStream(stream_temp1); + } } @@ -1240,6 +1406,7 @@ void Generator::MakeTextFilter(Item & item) return; } + StreamType * old_stream = output_stream; output_stream = filter_tab[filter_index]; ClearStream(*output_stream); @@ -1250,13 +1417,80 @@ void Generator::MakeTextFilter(Item & item) MakeText( *item.item_tab[0] ); // should be only one item - item_container is_generating_filter = true; - Call(function, item.functions[0].params, *old_stream, false, *output_stream); + 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(tmp_stream); + output_stream = &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() { @@ -1310,6 +1544,7 @@ void Generator::MakeText(Item & 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"); diff --git a/src/item.h b/src/item.h index 18c5777..d652335 100755 --- a/src/item.h +++ b/src/item.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2007-2011, Tomasz Sowa + * Copyright (c) 2007-2013, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,7 +55,8 @@ struct Item { item_none, item_container, item_text, item_normal, item_is, item_isno, item_if, item_ifno, item_ifany, item_ifone, item_ifanyno, item_ifoneno, item_ifindex, - item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter + item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter, + item_ezc }; struct Function diff --git a/src/pattern.cpp b/src/pattern.cpp index 5b5aa37..0ca6daa 100755 --- a/src/pattern.cpp +++ b/src/pattern.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2007-2012, Tomasz Sowa + * Copyright (c) 2007-2013, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -837,6 +837,13 @@ void Pattern::ReadDirectiveFilter(Item & item) } +void Pattern::ReadDirectiveEzc(Item & item) +{ + item.type = Item::item_ezc; + ReadFunctions(item); +} + + // user defined directive void Pattern::ReadDirectiveNormal(const std::wstring & name, Item & item) @@ -872,6 +879,7 @@ std::wstring name; else if( name == L"include" ) ReadDirectiveInclude(item); else if( name == L"def" ) ReadDirectiveDef(item); else if( name == L"filter" ) ReadDirectiveFilter(item); + else if( name == L"ezc" ) ReadDirectiveEzc(item); else if( name == L"#" ) ReadDirectiveComment(item); else ReadDirectiveNormal(name, item); diff --git a/src/pattern.h b/src/pattern.h index 001dbc9..3574496 100755 --- a/src/pattern.h +++ b/src/pattern.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2007-2012, Tomasz Sowa + * Copyright (c) 2007-2013, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -200,6 +200,7 @@ private: void ReadDirectiveInclude(Item & item); void ReadDirectiveDef(Item & item); void ReadDirectiveFilter(Item & item); + void ReadDirectiveEzc(Item & item); void ReadDirectiveNormal(const std::wstring & name, Item & item); void CreateTreeReadItemDirectiveCheckEnding(Item & item);