From 573d241dc1948cf07fc059fec90809ba7e706a59 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 19 Jul 2010 23:07:00 +0000 Subject: [PATCH] changed: functions can have more than one parameter and the parameters can be used in [if...] statements too sample: [normal_function "par1" "par2" "par3"] [if-one function "par1" "par2" "par3"]...[end] each function can have its own parameters: [if-one function1 "par1" "par2" "par3" function2 "par" "par2"]...[end] changed: [is] is now [if] (not exactly but very similar) [is-no] is now [if-no] (the same) [if] and [if-no] are taking one function (with or without arguments) sample: [if function]...[end] [if function "par1"]...[end] [if function "par1" "par2" "par3" "par4"]...[end] [is] is taking two functions now and evaluates them to boolean value (variables are also evaluated to boolean - if not empty that means true) [is function1 function2]...[end] [is variable1 variable2] either variable1 and variable2 are empty or both are not empty (they don't have to be equal)[end] added: [if-any-no fun1 fun2 fun3] the three functions have to return false [end] [if-one-no fun1 fun2 fun3] one the the three functions have to return false [end] removed: extracting the unix directory from the file name (in patterns) you have to call Pattern::Directory() method first to set directories git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@298 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/ezc.cpp | 1051 +++++++++++++++++++++++++-------------------------- src/ezc.h | 155 ++++---- 2 files changed, 601 insertions(+), 605 deletions(-) diff --git a/src/ezc.cpp b/src/ezc.cpp index fdeb802..767d1d0 100644 --- a/src/ezc.cpp +++ b/src/ezc.cpp @@ -1,7 +1,7 @@ /* * This file is a part of EZC -- Easy templating in C++ * and is distributed under the (new) BSD licence. - * Author: Tomasz Sowa + * Author: Tomasz Sowa */ /* @@ -41,80 +41,11 @@ #include "core/log.h" #endif + namespace Ezc { -void CreateMsg(std::ostringstream & o, const char * type, const char * arg) -{ - o << ""; -} - - -std::string CreateMsg(const char * type, const char * arg) -{ -std::ostringstream buffer; - - CreateMsg(buffer, type, arg); - -return buffer.str(); -} - - - - -/* - this method splits the input file name into a directory and a file name - e.g - if 'name' is "/this/is/dummy/file.ezc" - the result will be: - dir = "/this/is/dummy" - file = "file.ezc" -*/ -void SplitUnixDirectory(const char * name, std::string & dir, std::string & file) -{ - dir.clear(); - file.clear(); - - int i; - for( i=0 ; name[i] != 0 ; ++i ); - - if( i == 0 ) - return; - - for( --i ; i>=0 && name[i]!='\\' && name[i]!='/' ; --i ); - - if( i < 0 ) - { - file.assign(name); - } - else - { - if( i == 0 ) - // we're leaving one '/' in the directory - // (we have only the root directory) - dir.assign(name, 1); - else - dir.assign(name, i); - - file.assign(name + i + 1 ); - } - -return; -} - -void SplitUnixDirectory(const std::string & name, std::string & dir, std::string & file) -{ - SplitUnixDirectory(name.c_str(), dir, file); -} - - - /* * * Pattern @@ -126,6 +57,35 @@ void SplitUnixDirectory(const std::string & name, std::string & dir, std::string Pattern::Pattern() { Clear(); + + commentary_start = ""; + + allow_include = true; + delete_white_text_items = false; + + include_level_max = 100; +} + + +void Pattern::CreateMsg(std::ostringstream & o, const char * type, const char * arg) +{ + o << commentary_start << "ezc: " << type; + + if( arg ) + o << ' ' << arg << ' '; + + o << commentary_stop; +} + + +std::string Pattern::CreateMsg(const char * type, const char * arg) +{ +std::ostringstream buffer; + + CreateMsg(buffer, type, arg); + +return buffer.str(); } @@ -137,23 +97,10 @@ void Pattern::ParseFile(const std::string & file_name) - void Pattern::ParseFile(const char * file_name) { -Item::Directive file; - - file.is_text = true; - - if( directory.empty() ) - SplitUnixDirectory(file_name, directory, file.name); - else - file.name = file_name; - - item_root.directives.clear(); - item_root.directives.push_back( file ); - - include_level = 0; - + item_root.text = file_name; + include_level = 0; CreateTreeReadIncludeSkipAllowFlag(item_root); } @@ -161,9 +108,7 @@ Item::Directive file; void Pattern::ParseString(const std::string & str) { - itext = str.c_str(); - include_level = 0; - CreateTree(item_root); + ParseString( str.c_str() ); } @@ -177,11 +122,13 @@ void Pattern::ParseString(const char * str) void Pattern::Directory(const char * dir, const char * dir2) { - directory = dir; + directory.clear(); + directory2.clear(); - if( !dir2 ) - directory2.clear(); - else + if( dir ) + directory = dir; + + if( dir2 ) directory2 = dir2; } @@ -200,33 +147,68 @@ void Pattern::Directory(const std::string & dir, const std::string & dir2) } +void Pattern::AllowInclude(bool allow) +{ + allow_include = allow; +} + + +void Pattern::DeleteWhiteTextItems(bool del) +{ + delete_white_text_items = del; +} + + +void Pattern::SetCommentary(const char * com_start, const char * com_stop) +{ + commentary_start = com_start; + commentary_stop = com_stop; +} + + +void Pattern::SetCommentary(const std::string & com_start, const std::string & com_stop) +{ + commentary_start = com_start; + commentary_stop = com_stop; +} + + +void Pattern::SetIncludeMax(int include_max) +{ + include_level_max = include_max; +} + + void Pattern::Clear() { item_root.Clear(); - - allow_include = true; - delete_all_white = false; } bool Pattern::CheckFileName(const char * name) { - // very simple testing -- this path 'some..name' is incorrect as well - // (in the future it can be changed) +size_t i; - for( ; *name ; ++name ) - { - if( *name=='.' && *(name+1)=='.' ) + // we do not allow a slash or backslash in the name + for(i=0 ; name[i]!=0 ; ++i) + if( name[i] == '/' || name[i] == '\\' ) return false; - } + // "." is not allowed + if( i==1 && name[0]=='.' ) + return false; + + // ".." is not allowed too + if( i==2 && name[0]=='.' && name[1]=='.' ) + return false; + return true; } /* - 'name' must be a relative path + 'name' must be a relative path - without a slash or backslash */ std::string Pattern::ReadFile(const std::string & name) { @@ -235,12 +217,10 @@ std::string Pattern::ReadFile(const std::string & name) /* - 'name' must be a relative path + 'name' must be a relative path - without a slash or backslash */ std::string Pattern::ReadFile(const char * name) { - // for security reasons we can't open a file which has two dots - // somewhere in its name '..' if( !CheckFileName(name) ) return CreateMsg("incorrect file name:", name); @@ -254,9 +234,7 @@ return result; } -/* - 'name' must be a relative path -*/ + bool Pattern::ReadFileFromDir(const std::string & dir, const char * name, std::string & result) { if( dir.empty() ) @@ -298,17 +276,17 @@ return *(itext++); bool Pattern::IsWhite(int c ) { - // 13 is from a dos file at the end of a line (\r\n) + // 13 (\r) is from a dos file at the end of a line (\r\n) // 160 is an unbreakable space - if( c==' ' || c=='\t' || c==13 || c==160 ) + if( c==' ' || c=='\t' || c==13 || c==160 || c==10 ) return true; return false; } -void Pattern::SkipWhiteCharacters() +void Pattern::SkipWhite() { while( IsWhite(*itext) ) ++itext; @@ -317,39 +295,59 @@ void Pattern::SkipWhiteCharacters() void Pattern::CheckWhiteAndDelete(std::string & s) { -std::string::size_type i; +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=='#'); +} - directive.is_text = false; - SkipWhiteCharacters(); - while( (*itext>='a' && *itext<='z') || - (*itext>='A' && *itext<='Z') || - (*itext>='0' && *itext<='9') || - *itext=='_' || *itext=='-' || *itext=='.' || *itext=='#' ) +bool Pattern::IsDigit(int c) +{ + return (c>='0' && c<='9'); +} + + +bool Pattern::IsPositiveNumber(const std::string & str) +{ +size_t i; + + for(i=0 ; i= 100 ) + if( include_level > include_level_max ) { #ifdef EZC_USE_WINIX_LOGGER - log << log1 << "EZC: infinite loop in \"include\" directive" << logend; + log << log1 << "EZC: \"include\" directive has reached the maximum level" << logend; #endif return; } ++include_level; - std::string file_text = ReadFile( item.directives[0].name ); + std::string file_text = ReadFile( item.text ); const char * itext_old = itext; itext = file_text.c_str(); @@ -730,7 +741,8 @@ void Pattern::CreateTreeReadIf(Item & item) CreateTree(*pitem); } - pitem->DeleteLastItem(); // it deletes [end] from the tree + if( pitem->LastItemType() == Item::item_end ) + pitem->DeleteLastItem(); } @@ -739,7 +751,8 @@ void Pattern::CreateTreeReadFor(Item & item) Item * pitem = item.AddItem(); CreateTree(*pitem); - pitem->DeleteLastItem(); // it deletes [end] from the tree + if( pitem->LastItemType() == Item::item_end ) + pitem->DeleteLastItem(); } @@ -760,9 +773,12 @@ void Pattern::CreateTree(Item & item) if( item_temp.type==Item::item_end || item_temp.type==Item::item_else ) return; - if( pitem->type == Item::item_ifany || + 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 ) @@ -777,6 +793,8 @@ void Pattern::CreateTree(Item & item) } + + /* * * Pattern::Item @@ -823,11 +841,11 @@ void Pattern::Item::Clear() ClearItems(); type = item_none; text.clear(); - directives.clear(); + functions.clear(); } -Pattern::Item::ItemType Pattern::Item::LastItemType() +Pattern::Item::Type Pattern::Item::LastItemType() { if( item_table.empty() ) return item_none; @@ -842,8 +860,7 @@ void Pattern::Item::DeleteLastItem() return; delete item_table.back(); - - item_table.erase( item_table.end() - 1 ); + item_table.pop_back(); } @@ -853,7 +870,7 @@ Pattern::Item::Item() } -Pattern::Item::Item(const Pattern::Item & i) : type(i.type), text(i.text), directives(i.directives) +Pattern::Item::Item(const Pattern::Item & i) : type(i.type), text(i.text), functions(i.functions) { CopyItemTable(i); } @@ -863,7 +880,7 @@ Pattern::Item & Pattern::Item::operator=(const Pattern::Item & i) { type = i.type; text = i.text; - directives = i.directives; + functions = i.functions; CopyItemTable(i); @@ -903,7 +920,7 @@ void Info::Clear() } -Info::Info(std::ostringstream & o, const std::string & p) : out(o), par(p) +Info::Info(std::ostringstream & o, std::vector & pars, const std::string & p) : out(o), params(pars), par(p) { Clear(); } @@ -1012,19 +1029,27 @@ Generator::Generator(std::ostringstream & o, Pattern & p, Functions & f) } -void Generator::SetOutStream(std::ostringstream & o) +void Generator::Set(std::ostringstream & o, Pattern & p, Functions & f) +{ + output_stream = &o; + pattern = &p; + functions = &f; +} + + +void Generator::Set(std::ostringstream & o) { output_stream = &o; } -void Generator::SetPattern(Pattern & p) +void Generator::Set(Pattern & p) { pattern = &p; } -void Generator::SetFunctions(Functions & f) +void Generator::Set(Functions & f) { functions = &f; } @@ -1043,7 +1068,9 @@ void Generator::Generate() if( !output_stream || !pattern || !functions ) return; - current_item = 0; + break_generating = false; + current_item = 0; + MakeText( pattern->item_root ); } @@ -1055,7 +1082,7 @@ bool Generator::Find(const std::string & key, Functions::Function ** function) { if( !functions->Find(key, function) ) { - CreateMsg(*output_stream, "can't find", key.c_str() ); + pattern->CreateMsg(*output_stream, "can't find", key.c_str() ); return false; } @@ -1069,7 +1096,7 @@ void Generator::CallUserFunction(Functions::Function * function, Info & info) if( function->is_running ) { // recurrences are not allowed - CreateMsg(*output_stream, "the function is being executed" ); + pattern->CreateMsg(*output_stream, "the function is being executed" ); return; } @@ -1118,6 +1145,30 @@ return false; } +// return: true if a function or variable was found and called +bool Generator::Call(Pattern::Item::Function & function, bool * info_res, Functions::Function ** pfun) +{ +bool called; + + if( function.params.empty() ) + { + Info info(*output_stream, function.params, empty); + called = Call(function.name, info, pfun); + + if( info_res ) + *info_res = info.res; + } + else + { + Info info(*output_stream, function.params, function.params[0]); + called = Call(function.name, info, pfun); + + if( info_res ) + *info_res = info.res; + } + +return called; +} @@ -1127,7 +1178,7 @@ void Generator::MakeTextContainer(Pattern::Item & item) { std::vector::iterator i = item.item_table.begin(); - for( ; i != item.item_table.end() && current_item != -1 ; ++i ) + for( ; i != item.item_table.end() && !break_generating ; ++i ) MakeText(**i); } @@ -1135,22 +1186,11 @@ void Generator::MakeTextContainer(Pattern::Item & item) void Generator::MakeTextNormal(Pattern::Item & item) { - if( item.directives.empty() ) + if( item.functions.size() != 1 ) return; Functions::Function * pfun; - bool called; - - if( item.directives.size() == 2 ) - { - Info info(*output_stream, item.directives[1].name); - called = Call(item.directives[0].name, info, &pfun); - } - else - { - Info info(*output_stream, empty); - called = Call(item.directives[0].name, info, &pfun); - } + bool called = Call(item.functions[0], 0, &pfun); if( called && pfun->type == Functions::variable ) *output_stream << pfun->variable; @@ -1174,58 +1214,63 @@ void Generator::MakeTextIf_go(Pattern::Item & item, bool result) } -void Generator::MakeTextIfany(Pattern::Item & item) + +void Generator::MakeTextIf(Pattern::Item & item) { - std::vector::iterator d = item.directives.begin(); - unsigned how_many_true = 0; +bool info_res; - for( ; d != item.directives.end() ; ++d ) - { - Info info(*output_stream, empty); + if( item.functions.size() != 1 ) + return; - if( !Call(d->name, info) ) - return; - - if( info.res ) - ++how_many_true; - } + if( !Call(item.functions[0], &info_res) ) + return; - MakeTextIf_go(item, how_many_true == item.directives.size() ); + MakeTextIf_go(item, info_res); } void Generator::MakeTextIfno(Pattern::Item & item) { - std::vector::iterator d = item.directives.begin(); - unsigned how_many_true = 0; +bool info_res; - for( ; d != item.directives.end() ; ++d ) - { - Info info(*output_stream, empty); + if( item.functions.size() != 1 ) + return; - if( Call(d->name, info) && info.res ) - { - // there is no sense to go through all functions - ++how_many_true; - break; - } - } + if( !Call(item.functions[0], &info_res) ) + return; - MakeTextIf_go(item, how_many_true == 0 ); + MakeTextIf_go(item, !info_res); } +void Generator::MakeTextIfany(Pattern::Item & item) +{ + std::vector::iterator d = item.functions.begin(); + unsigned how_many_true = 0; + bool info_res; + + for( ; d != item.functions.end() ; ++d ) + { + if( !Call(*d, &info_res) ) + return; + + if( info_res ) + ++how_many_true; + } + + MakeTextIf_go(item, how_many_true == item.functions.size()); +} + void Generator::MakeTextIfone(Pattern::Item & item) { - std::vector::iterator d = item.directives.begin(); - int how_many_true = 0; + std::vector::iterator d = item.functions.begin(); + unsigned how_many_true = 0; + bool info_res; - for( ; d != item.directives.end() ; ++d ) + for( ; d != item.functions.end() ; ++d ) { - Info info(*output_stream, empty); - - if( Call(d->name, info) && info.res ) + if( Call(*d, &info_res) && info_res ) { // there is no sense to go through all functions ++how_many_true; @@ -1233,179 +1278,133 @@ void Generator::MakeTextIfone(Pattern::Item & item) } } - MakeTextIf_go(item, how_many_true > 0 ); + MakeTextIf_go(item, how_many_true > 0); } -bool Generator::MakeTextIsFunText(const std::string & fun_name, const std::string & text, bool & res) +void Generator::MakeTextIfanyno(Pattern::Item & item) { -Functions::Function * function; + std::vector::iterator d = item.functions.begin(); + unsigned how_many_true = 0; + bool info_res; - if( !Find(fun_name, &function) ) - return false; - - - if( function->type == Functions::function ) + for( ; d != item.functions.end() ; ++d ) { - Info info(*output_stream, text); + if( !Call(*d, &info_res) ) + return; - Call(function, info); - res = info.res; - } - else - { - // this is a variable - res = (function->variable == text); + if( info_res ) + ++how_many_true; } - -return true; + MakeTextIf_go(item, how_many_true == 0); } -bool Generator::MakeTextIsFunFun(const std::string & fun_name1, const std::string & fun_name2, bool & res) +void Generator::MakeTextIfoneno(Pattern::Item & item) { -Functions::Function * function1, * function2; + std::vector::iterator d = item.functions.begin(); + unsigned how_many_false = 0; + bool info_res; - if( !Find(fun_name1, &function1) ) - return false; - - if( !Find(fun_name2, &function2) ) - return false; - - - if( function1->type == Functions::function && function2->type == Functions::function ) + for( ; d != item.functions.end() ; ++d ) { - Info info1(*output_stream, empty); - Info info2(*output_stream, empty); - - Call(function1, info1); - Call(function2, info2); - res = (info1.res == info2.res); + if( Call(*d, &info_res) && !info_res ) + ++how_many_false; } - else - if( function1->type == Functions::function ) - { - Info info(*output_stream, fun_name2); - Call(function1, info); // only the former is a function - res = info.res; - } - else - if( function2->type == Functions::function ) - { - Info info(*output_stream, fun_name1); - - Call(function2, info); // only the latter is a function - res = info.res; - } - else - res = (function1->variable == function2->variable); // both are variables - - -return false; + MakeTextIf_go(item, how_many_false > 0); } -// if 'isno' is true that means we're generating tag [is-no ...] -// default: false -void Generator::MakeTextIs(Pattern::Item & item, bool isno) + +void Generator::MakeTextIs(Pattern::Item & item) { - if( item.directives.size() != 2 ) +bool info_res1, info_res2; +bool res = false; + + if( item.functions.size() != 2 ) return; - bool result = false; + if( !Call(item.functions[0], &info_res1) ) + return; - if( item.directives[0].is_text && item.directives[1].is_text ) - { - // both directives are text - result = (item.directives[0].name == item.directives[1].name); - } - else - if( item.directives[0].is_text ) - { - // first directive is text, second not - if( !MakeTextIsFunText(item.directives[1].name, item.directives[0].name, result) ) - return; - } - else - if( item.directives[1].is_text ) - { - // second directive is text, first not - if( !MakeTextIsFunText(item.directives[0].name, item.directives[1].name, result) ) - return; - } - else - { - // both directive are not text - MakeTextIsFunFun(item.directives[0].name, item.directives[1].name, result); - } + if( !Call(item.functions[1], &info_res2) ) + return; - if( isno ) - result = !result; - - MakeTextIf_go(item, result); + MakeTextIf_go(item, info_res1 == info_res2); } +void Generator::MakeTextIsno(Pattern::Item & item) +{ +bool info_res1, info_res2; +bool res = false; + + if( item.functions.size() != 2 ) + return; + + if( !Call(item.functions[0], &info_res1) ) + return; + + if( !Call(item.functions[1], &info_res2) ) + return; + + MakeTextIf_go(item, info_res1 != info_res2); +} + bool Generator::MakeTextIfindexnumber(Pattern::Item & item, Functions::Function * function, bool & result) { - if( item.directives.size() != 2 ) + if( item.functions.size() != 2 ) return false; - const char * number_text = item.directives[1].name.c_str(); + const char * number_text = item.functions[1].name.c_str(); char * last_char; - int number = (int)strtol(number_text, &last_char, 10); + int number = (int)strtol(number_text, &last_char, 10); // !! dodac obsluge bialych znakow na koncu (na poczatku chyba jest od strtol) - if( *last_char == '\0' ) + if( *last_char != '\0' ) { - result = (function->iter == number); - } - else - { - CreateMsg(*output_stream, "if-index: syntax error"); - - return false; + pattern->CreateMsg(*output_stream, "if-index: syntax error"); + return false; } + result = (function->iter == number); + return true; } void Generator::MakeTextIfindex(Pattern::Item & item) { - if( item.directives.size() != 2 ) + if( item.functions.size() != 2 ) return; // we actually don't call a function (or variable) here - // but only reading an iteration index + // but only reading the iterator Functions::Function * function; - if( !Find(item.directives[0].name, &function) ) + if( !Find(item.functions[0].name, &function) ) return; bool result = false; - if( item.directives[1].name == "odd" ) + if( item.functions[1].name == "odd" ) { - if( (function->iter & 1) == 1 ) - result = true; + result = (function->iter & 1) == 1; } else - if( item.directives[1].name == "even" ) + if( item.functions[1].name == "even" ) { - if( (function->iter & 1) == 0 ) - result = true; + result = (function->iter & 1) == 0; } else - if( item.directives[1].name == "first" ) + if( item.functions[1].name == "first" ) { - if( function->iter == 0 ) - result = true; + result = function->iter == 0; } else { @@ -1420,51 +1419,42 @@ void Generator::MakeTextIfindex(Pattern::Item & item) void Generator::MakeTextForLoop(Pattern::Item & item, Functions::Function * function) { - for( ; current_item != -1 ; ++function->iter ) +bool info_res; + + for( ; !break_generating ; function->iter += 1 ) { if( function->iter >= max_for_items ) { - CreateMsg(*output_stream, item.directives[0].name.c_str(), "function exceeded a limit for a [for] statement"); + pattern->CreateMsg(*output_stream, item.functions[0].name.c_str(), + "function exceeded a limit for a [for] statement"); break; } - if( item.directives.size() == 2 ) - { - Info info(*output_stream, item.directives[1].name); - Call(function, info); - - if( !info.res ) - break; - } - else - { - Info info(*output_stream, empty); - Call(function, info); - - if( !info.res ) - break; - } + Call(item.functions[0], &info_res); + if( !info_res ) + break; if( !item.item_table.empty() ) - MakeText( *item.item_table[0] ); + MakeText( *item.item_table[0] ); // should be only one item - item_container } } void Generator::MakeTextFor(Pattern::Item & item) { - if( item.directives.empty() ) + if( item.functions.size() != 1 ) return; Functions::Function * function; - if( !Find(item.directives[0].name, &function) ) + if( !Find(item.functions[0].name, &function) ) return; if( function->is_for ) { - CreateMsg(*output_stream, item.directives[0].name.c_str(), "this function is already used in a [for] statement"); + pattern->CreateMsg(*output_stream, item.functions[0].name.c_str(), + "this function is already used in a [for] statement"); return; } @@ -1481,23 +1471,29 @@ void Generator::MakeTextFor(Pattern::Item & item) void Generator::MakeTextDefine(Pattern::Item & item) { - if( item.directives.size() != 2 ) - return; - - if( item.directives[1].is_text ) + if( item.functions.size() == 1 ) { - functions->Insert(item.directives[0].name, item.directives[1].name); + // 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 ) { Functions::Function * function; - if( Find(item.directives[1].name, &function) ) + if( Find(item.functions[1].name, &function) ) { if( function->type == Functions::function ) - functions->Insert(item.directives[0].name, function->user_function); - else - functions->Insert(item.directives[0].name, function->variable); + { + // 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); + } } } } @@ -1507,57 +1503,32 @@ void Generator::MakeTextDefine(Pattern::Item & item) void Generator::MakeText(Pattern::Item & item) { - if( current_item == -1 ) + if( break_generating ) return; if( ++current_item > max_items ) { - current_item = -1; - CreateMsg(*output_stream, "Generator exceeded allowed number of elements"); + break_generating = true; + pattern->CreateMsg(*output_stream, "Generator exceeded allowed number of elements"); return; } - switch( item.type ) - { - case Pattern::Item::item_text: - *output_stream << item.text; - break; - case Pattern::Item::item_container: - MakeTextContainer(item); - break; - case Pattern::Item::item_normal: - MakeTextNormal(item); - break; - case Pattern::Item::item_ifany: - MakeTextIfany(item); - break; - case Pattern::Item::item_ifno: - MakeTextIfno(item); - break; - case Pattern::Item::item_ifone: - MakeTextIfone(item); - break; - case Pattern::Item::item_ifindex: - MakeTextIfindex(item); - break; - case Pattern::Item::item_is: - MakeTextIs(item); - break; - case Pattern::Item::item_isno: - MakeTextIs(item, true); - break; - case Pattern::Item::item_for: - MakeTextFor(item); - break; - case Pattern::Item::item_def: - MakeTextDefine(item); - break; - case Pattern::Item::item_err: - CreateMsg(*output_stream, "a wrong directive"); - break; - default: - break; - } + if ( item.type == Pattern::Item::item_text ) *output_stream << item.text; + else if( item.type == Pattern::Item::item_container ) MakeTextContainer(item); + else if( item.type == Pattern::Item::item_normal ) MakeTextNormal(item); + else if( item.type == Pattern::Item::item_if ) MakeTextIf(item); + else if( item.type == Pattern::Item::item_ifno ) MakeTextIfno(item); + else if( item.type == Pattern::Item::item_ifany ) MakeTextIfany(item); + else if( item.type == Pattern::Item::item_ifone ) MakeTextIfone(item); + else if( item.type == Pattern::Item::item_ifanyno ) MakeTextIfanyno(item); + else if( item.type == Pattern::Item::item_ifoneno ) MakeTextIfoneno(item); + else if( item.type == Pattern::Item::item_ifindex ) MakeTextIfindex(item); + else if( item.type == Pattern::Item::item_is ) MakeTextIs(item); + else if( item.type == Pattern::Item::item_isno ) MakeTextIsno(item); + else if( item.type == Pattern::Item::item_for ) MakeTextFor(item); + else if( item.type == Pattern::Item::item_def ) MakeTextDefine(item); + else if( item.type == Pattern::Item::item_err ) + pattern->CreateMsg(*output_stream, "a wrong directive"); } diff --git a/src/ezc.h b/src/ezc.h index 517042d..faf4a88 100644 --- a/src/ezc.h +++ b/src/ezc.h @@ -1,7 +1,7 @@ /* * This file is a part of EZC -- Easy templating in C++ * and is distributed under the (new) BSD licence. - * Author: Tomasz Sowa + * Author: Tomasz Sowa */ /* @@ -51,18 +51,11 @@ namespace Ezc { -void CreateMsg(std::ostringstream & o, const char * type, const char * arg = 0); -std::string CreateMsg(const char * type, const char * arg = 0); -void SplitUnixDirectory(const char * name, std::string & dir, std::string & file); -void SplitUnixDirectory(const std::string & name, std::string & dir, std::string & file); - - - - class Pattern { public: + Pattern(); void ParseFile(const std::string & file_name); @@ -76,30 +69,41 @@ public: void Directory(const char * dir, const char * dir2 = 0); void Directory(const std::string & dir); void Directory(const std::string & dir, const std::string & dir2); + + void AllowInclude(bool allow); + void DeleteWhiteTextItems(bool del); + + void SetCommentary(const char * com_start, const char * com_stop); + void SetCommentary(const std::string & com_start, const std::string & com_stop); + + void SetIncludeMax(int include_max); void Clear(); + + void CreateMsg(std::ostringstream & o, const char * type, const char * arg = 0); + std::string CreateMsg(const char * type, const char * arg = 0); + + struct Item { - // change the name to 'Type' - enum ItemType + enum Type { - item_none, item_container, item_text, item_ifany, item_ifno, item_for, - item_else, item_end, item_err, item_normal, item_ifindex, - item_include, item_is, item_isno, item_ifone, item_comment, item_def + 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 }; - struct Directive + struct Function { - bool is_text; // if true that means a directive in quotes "static text" - std::string name; + std::string name; // function name + std::vector params; // function parameters }; - - ItemType type; - std::string text; - std::vector item_table; - std::vector directives; + Type type; + std::string text; // used in: item_text, item_include (as a file name) + std::vector item_table; // !! zamienic na 'items'? + std::vector functions; Item(); Item(const Item & i); @@ -107,16 +111,21 @@ public: void CopyItemTable(const Item & i); ~Item(); - Item * AddItem(const Item * porg = 0); - Item * AddItem(const Item & porg); - void ClearItems(); - ItemType LastItemType(); - void DeleteLastItem(); - void Clear(); + Item * AddItem(const Item * porg = 0); + Item * AddItem(const Item & porg); + void ClearItems(); + Type LastItemType(); + void DeleteLastItem(); + void Clear(); }; Item item_root; + +private: + + const char * itext; + // allowing include tag // default: true bool allow_include; @@ -126,37 +135,48 @@ public: // this not actually delete the whole item but only the string // the item will be present with an empty string // default: false - bool delete_all_white; - -private: - const char * itext; + bool delete_white_text_items; // first we're trying to read a file from 'directory' // if there is no such a file there then we try read from 'directory2' // we read from these directories only if they are not empty std::string directory, directory2; - int include_level; + int include_level, include_level_max; + + + + std::string commentary_start, commentary_stop; + + + - bool CheckFileName(const char * name); std::string ReadFile(const std::string & name); std::string ReadFile(const char * name); + bool CheckFileName(const char * name); bool ReadFileFromDir(const std::string & dir, const char * name, std::string & result); int ReadCharInText(); bool IsWhite(int c); - void SkipWhiteCharacters(); + void SkipWhite(); void CheckWhiteAndDelete(std::string & s); - Item::Directive ReadDirective(); - Item::Directive ReadString(); - Item::Directive ReadDirectiveOrString(); + bool IsNameChar(int c); + bool IsDigit(int c); + bool IsPositiveNumber(const std::string & str); - void CreateTreeReadItemDirectiveCheckEnding(Item & item); + bool ReadName(std::string & name); + bool ReadString(std::string & str); + bool ReadFunction(Item::Function & function); + bool ReadParams(Item::Function & function); + bool ReadFunctions(Item & item); - void ReadDirectiveIfany(Item & item); + void ReadDirectiveIf(Item & item); void ReadDirectiveIfno(Item & item); + void ReadDirectiveIfany(Item & item); void ReadDirectiveIfone(Item & item); + void ReadDirectiveIfanyno(Item & item); + void ReadDirectiveIfoneno(Item & item); void ReadDirectiveIs(Item & item); void ReadDirectiveIsno(Item & item); void ReadDirectiveIfindex(Item & item); @@ -164,21 +184,19 @@ private: void ReadDirectiveComment(Item & item); void ReadDirectiveInclude(Item & item); void ReadDirectiveDef(Item & item); - void ReadDirectiveNormal(Item::Directive & directive, Item & item); + void ReadDirectiveNormal(const std::string & name, Item & item); + void CreateTreeReadItemDirectiveCheckEnding(Item & item); void CreateTreeReadItemDirective(Item & item); - void CreateTreeReadItemText(Item & item); bool CreateTreeReadItem(Item & item); - void CreateTreeReadIf(Item & item); void CreateTreeReadFor(Item & item); void CreateTree(Item & item); - void CreateTreeReadInclude(Item & item); void CreateTreeReadIncludeSkipAllowFlag(Item & item); -}; // Pattern +}; // class Pattern @@ -189,9 +207,12 @@ struct Info // output stream std::ostringstream & out; - // an optional string parameter in a normal statement [user_function "parameter"] - // or in "is" statement [is user_function "parameter"] - // or in "for" statement [for user_function "parameter"] + // table of parameters + std::vector & params; + + // the first parameter + // you can always use it even if there is not any parameters + // in such a way the reference points to an empty valid string const std::string & par; // this is set by Generator @@ -203,8 +224,8 @@ struct Info // for a variable it is set to true if the variable is not empty bool res; - // arguments: output_stream, string_parameter - Info(std::ostringstream & o, const std::string & p); + // arguments: output_stream, table_of_parameters, the_first_parameter + Info(std::ostringstream & o, std::vector & pars, const std::string & p); void Clear(); }; @@ -223,12 +244,12 @@ public: { Type type; - UserFunction user_function; - std::string variable; + UserFunction user_function; // used when type is 'function' + std::string variable; // used when type is 'variable' - int iter; - bool is_for; // true if is used by a [for] statement - bool is_running; // true if this function (if is) is currently running + int iter; + bool is_for; // true if is used by a [for] statement + bool is_running; // true if this function is currently executed Function(); }; @@ -259,9 +280,10 @@ public: Generator(); Generator(std::ostringstream & o, Pattern & p, Functions & f); - void SetOutStream(std::ostringstream & o); - void SetPattern(Pattern & p); - void SetFunctions(Functions & f); + void Set(std::ostringstream & o, Pattern & p, Functions & f); + void Set(std::ostringstream & o); + void Set(Pattern & p); + void Set(Functions & f); void SetMax(int max_items_, int max_for_items_); void Generate(); @@ -269,9 +291,10 @@ public: private: std::ostringstream * output_stream; - Pattern * pattern; + Pattern * pattern; Functions * functions; + bool break_generating; int current_item; int max_items; int max_for_items; @@ -281,30 +304,32 @@ private: bool Find(const std::string & key, Functions::Function ** function); - void Call(Functions::Function * function, Info & info); bool Call(const std::string & name, Info & info, Functions::Function ** pfun = 0); + bool Call(Pattern::Item::Function & function, bool * info_res = 0, Functions::Function ** pfun = 0); void CallUserFunction(Functions::Function * function, Info & info); void CallVariable(Functions::Function * function, Info & info); void MakeTextIf_go(Pattern::Item & item, bool result); bool MakeTextIfindexnumber(Pattern::Item & item, Functions::Function * function, bool & result); - void MakeTextIfany(Pattern::Item & item); + void MakeTextIf(Pattern::Item & item); void MakeTextIfno(Pattern::Item & item); + void MakeTextIfany(Pattern::Item & item); void MakeTextIfone(Pattern::Item & item); + void MakeTextIfanyno(Pattern::Item & item); + void MakeTextIfoneno(Pattern::Item & item); void MakeTextIfindex(Pattern::Item & item); void MakeTextForLoop(Pattern::Item & item, Functions::Function * function); void MakeTextFor(Pattern::Item & item); void MakeTextContainer(Pattern::Item & item); void MakeTextNormal(Pattern::Item & item); - bool MakeTextIsFunText(const std::string & fun_name, const std::string & text, bool & res); - bool MakeTextIsFunFun(const std::string & fun_name1, const std::string & fun_name2, bool & res); - void MakeTextIs(Pattern::Item & item, bool isno = false); + void MakeTextIs(Pattern::Item & item); + void MakeTextIsno(Pattern::Item & item); void MakeTextDefine(Pattern::Item & item); void MakeText(Pattern::Item & item); -}; // Generator +}; // class Generator } // namespace Ezc