diff --git a/src/ezc.cpp b/src/ezc.cpp index 5c8bacb..23d5073 100644 --- a/src/ezc.cpp +++ b/src/ezc.cpp @@ -1,156 +1,174 @@ +/* + * 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, 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 "ezc.h" +namespace Ezc +{ + + +std::string CreateMsg(const char * type, const char * arg) +{ +std::ostringstream buffer; + + buffer << ""; + +return buffer.str(); +} + + /* * - * Ezc + * Pattern * * */ - - -void Ezc::Init() +void Pattern::ParseFile(std::string file_name) { -} - -Ezc::Ezc() -{ - Init(); -} - - -void Ezc::CreateTree(const char * file) -{ - std::string file_name = "\""; - file_name += file; + file_name.insert(file_name.begin(), '\"'); item_root.directives.clear(); item_root.directives.push_back( file_name ); - item_root.CreateTreeReadInclude(); + + CreateTreeReadInclude(item_root); } - -std::string Ezc::MakeText() +void Pattern::ParseFile(const char * file_name) { - output.clear(); - - item_root.MakeText(output, user_info_table); - -return output; + ParseFile( std::string(file_name) ); } -void Ezc::Insert(const std::string & key, UserFunction ufunction) +void Pattern::Directory(const char * d) { - UserInfo ui; - ui.user_function = ufunction; - ui.iter = 0; + directory = d; +} - user_info_table.insert( std::make_pair(key, ui) ); +void Pattern::Directory(const std::string & d) +{ + directory = d; } - -/* - * - * Ezc::Item - * - * - */ - - -Ezc::Item * Ezc::Item::AddItem(const Ezc::Item & porg) +bool Pattern::CheckFileName(const char * name) { - Item * pitem = new Item(porg); + // very simple testing -- this path 'some..name' is incorrect as well + // (in the future it can be changed) - item_table.push_back(pitem); - -return pitem; -} - - -void Ezc::Item::ClearTable() -{ - std::vector::iterator i = item_table.begin(); - - for( ; i != item_table.end() ; ++i ) - delete *i; - - item_table.clear(); -} - -Ezc::Item::Item() -{ -} - -Ezc::Item::~Item() -{ - ClearTable(); -} - -void Ezc::Item::ReadFile(const char * name, std::string & result) -{ - std::ifstream file(name); - - if( !file ) + for( ; *name ; ++name ) { - std::ostringstream buffer; - buffer << ""; - result = buffer.str(); - - return; + if( *name=='.' && *(name+1)=='.' ) + return false; } - std::getline(file, result, '\0'); -} - - -Ezc::Item::ItemType Ezc::Item::LastItemType() -{ - if( item_table.empty() ) - return item_none; - -return item_table.back()->type; -} - - -bool Ezc::Item::ReadChar(const char * & itext, char & result) -{ - if( *itext==0 || *itext=='[' || *itext==']' ) - return false; - - - if( *itext == '\\' ) - { - if( *(itext+1)=='\\' || *(itext+1)=='[' || *(itext+1)==']' ) - { - result = *(++itext); - ++itext; - return true; - } - } - - result = *itext; - ++itext; - return true; } -void Ezc::Item::SkipWhiteCharacters(const char * & itext) +std::string Pattern::ReadFile(const char * name) +{ + // for security reason we can't open a file which has two dots + // somewhere in its name '..' + if( !CheckFileName(name) ) + return CreateMsg("incorrect file name:", name); + + std::string file_name; + + if( name[0]!='\\' && name[0]!='/' ) + { + // name is a relative path + file_name += directory; + + if( !file_name.empty() ) + file_name += '/'; + } + + file_name += name; + + std::ifstream file(file_name.c_str()); + + if( !file ) + return CreateMsg("can't open:", name); + // or we can give the whole path here (file_name) + else + { + std::string result; + std::getline(file, result, '\0'); + + return result; + } +} + + +int Pattern::ReadCharInText() +{ + if( *itext==0 || *itext=='[' ) + return -1; + + if( *itext == '\\' ) + { + if( *(itext+1)=='\\' || *(itext+1)=='[' || *(itext+1)==']' ) + ++itext; + } + +return *(itext++); +} + + +void Pattern::SkipWhiteCharacters() { while( *itext==' ' || *itext=='\t' ) ++itext; } -void Ezc::Item::ReadDirective(const char * & itext, std::string & directive) +std::string Pattern::ReadDirective() { - directive.clear(); +std::string directive; - SkipWhiteCharacters(itext); + SkipWhiteCharacters(); while( (*itext>='a' && *itext<='z') || (*itext>='A' && *itext<='Z') || @@ -161,69 +179,62 @@ void Ezc::Item::ReadDirective(const char * & itext, std::string & directive) ++itext; } + +return directive; } -void Ezc::Item::ReadString(const char * & itext, std::string & directive) -{ - directive.clear(); - SkipWhiteCharacters(itext); + +std::string Pattern::ReadString() +{ +std::string directive; + + SkipWhiteCharacters(); if( *itext != '\"' ) - return; + return directive; // string is signed by its first character equal (") - directive += *itext; - ++itext; + directive += '\"'; - while( (*itext>='a' && *itext<='z') || - (*itext>='A' && *itext<='Z') || - (*itext>='0' && *itext<='9') || - *itext=='_' || *itext=='-' || *itext=='.' || *itext==' ' - || *itext==':' || *itext=='\\' )// tymczasowo - { + for( ++itext ; *itext && *itext!='\"' && *itext!='\n' ; ++itext ) directive += *itext; - ++itext; - } - if( *itext != '\"' ) - { // the second quotation mark (") is missing directive.clear(); - } else - { ++itext; - } // the second quotation mark (") we don't add into the 'directive' + +return directive; } -void Ezc::Item::ReadDirectiveOrString(const char * & itext, std::string & directive) +std::string Pattern::ReadDirectiveOrString() { - SkipWhiteCharacters(itext); + SkipWhiteCharacters(); if( *itext == '\"' ) { // we've got string - return ReadString(itext, directive); + return ReadString(); } else { - return ReadDirective(itext, directive); + return ReadDirective(); } } -void Ezc::Item::CreateTreeReadItemDirectiveCheckEnding(const char * & itext) +void Pattern::CreateTreeReadItemDirectiveCheckEnding(Item & item) { - SkipWhiteCharacters(itext); + SkipWhiteCharacters(); if( *itext != ']' ) { - type = item_err; + item.type = Item::item_err; while( *itext!=0 && *itext!=']' ) ++itext; @@ -234,141 +245,164 @@ void Ezc::Item::CreateTreeReadItemDirectiveCheckEnding(const char * & itext) } -void Ezc::Item::CreateTreeReadItemDirective(const char * & itext) +void Pattern::ReadDirectiveIfany(Item & item) { -std::string directive; + item.type = Item::item_ifany; + while( true ) + { + std::string directive = ReadDirective(); + + if( directive.empty() ) + break; + + item.directives.push_back(directive); + } + + if( item.directives.empty() ) + item.type = Item::item_err; +} + + +void Pattern::ReadDirectiveIfone(Item & item) +{ + ReadDirectiveIfany(item); + + if( item.type == Item::item_ifany ) + item.type = Item::item_ifone; +} + + +void Pattern::ReadDirectiveIs(Item & item) +{ + item.type = Item::item_is; + std::string directive = ReadDirective(); + + if( !directive.empty() ) + { + item.directives.push_back(directive); + + directive = ReadDirectiveOrString(); + + if( !directive.empty() ) + item.directives.push_back(directive); + } + + if( item.directives.size() != 2 ) + item.type = Item::item_err; +} + + +void Pattern::ReadDirectiveIfindex(Item & item) +{ + item.type = Item::item_ifindex; + std::string directive = ReadDirective(); + + if( !directive.empty() ) + { + item.directives.push_back(directive); + + directive = ReadDirective(); + + if( !directive.empty() ) + item.directives.push_back(directive); + } + + if( item.directives.size() != 2 ) + item.type = Item::item_err; +} + + +void Pattern::ReadDirectiveFor(Item & item) +{ + item.type = Item::item_for; + std::string directive = ReadDirective(); + + if( !directive.empty() ) + item.directives.push_back(directive); + else + item.type = Item::item_err; + +} + + +void Pattern::ReadDirectiveInclude(Item & item) +{ + item.type = Item::item_include; + std::string directive = ReadString(); + + if( !directive.empty() ) + item.directives.push_back(directive); + else + item.type = Item::item_err; + +} + + +void Pattern::CreateTreeReadItemDirective(Item & item) +{ ++itext; - directives.clear(); - ReadDirective(itext,directive); + std::string directive = ReadDirective(); if( directive == "if-any" ) - { - type = item_ifany; - - while( true ) - { - ReadDirective(itext,directive); - - if( directive.empty() ) - break; - - directives.push_back(directive); - } - - if( directives.empty() ) - type = item_err; - } + ReadDirectiveIfany(item); + else + if( directive == "if-one" ) + ReadDirectiveIfone(item); else if( directive == "is" ) - { - type = item_is; - - ReadDirective(itext,directive); - - if( !directive.empty() ) - { - directives.push_back(directive); - - ReadDirectiveOrString(itext,directive); - - if( !directive.empty() ) - directives.push_back(directive); - } - - if( directives.size() != 2 ) - type = item_err; - } + ReadDirectiveIs(item); else if( directive == "if-index" ) - { - type = item_ifindex; - - ReadDirective(itext,directive); - - if( !directive.empty() ) - { - directives.push_back(directive); - - ReadDirective(itext,directive); - - if( !directive.empty() ) - directives.push_back(directive); - } - - if( directives.size() != 2 ) - type = item_err; - } + ReadDirectiveIfindex(item); else if( directive == "end" ) - { - type = item_end; - } + item.type = Item::item_end; else if( directive == "else" ) - { - type = item_else; - } + item.type = Item::item_else; else if( directive == "for" ) - { - type = item_for; - - ReadDirective(itext,directive); - - if( !directive.empty() ) - directives.push_back(directive); - else - type = item_err; - } + ReadDirectiveFor(item); else if( directive == "include" ) - { - type = item_include; - - ReadString(itext,directive); - - if( !directive.empty() ) - directives.push_back(directive); - else - type = item_err; - } + ReadDirectiveInclude(item); else { - directives.push_back(directive); - type = item_normal; + // user defined + item.directives.push_back(directive); + item.type = Item::item_normal; } - CreateTreeReadItemDirectiveCheckEnding(itext); + CreateTreeReadItemDirectiveCheckEnding(item); } -void Ezc::Item::CreateTreeReadItemText(const char * & itext) +void Pattern::CreateTreeReadItemText(Item & item) { -char c; +int c; - text.clear(); + while( (c = ReadCharInText()) != -1 ) + item.text += c; - while( ReadChar(itext, c) ) - text += c; - - type = item_text; + item.type = Item::item_text; } -bool Ezc::Item::CreateTreeReadItem(const char * & itext) +bool Pattern::CreateTreeReadItem(Item & item) { + item.Clear(); if( *itext == '[' ) { - CreateTreeReadItemDirective(itext); + CreateTreeReadItemDirective(item); return true; } else if( *itext ) { - CreateTreeReadItemText(itext); + CreateTreeReadItemText(item); return true; } @@ -378,397 +412,507 @@ return false; -bool Ezc::Item::CreateTreeReadDeleteLastEndItem() + +void Pattern::CreateTreeReadInclude(Item & item) { - if( item_table.empty() ) - return false; - - if( item_table.back()->LastItemType() == item_end ) - { - item_table.back()->item_table.erase( - item_table.back()->item_table.begin() + - item_table.back()->item_table.size() - 1 ); - - return true; - } - -return false; -} - -void Ezc::Item::CreateTreeReadInclude() -{ - if( directives.empty() || directives[0].empty() || directives[0][0]!='\"' ) + if( item.directives.empty() || item.directives[0].empty() || item.directives[0][0]!='\"' ) return; - ClearTable(); - type = item_container; - - std::string file_text; - - ReadFile(directives[0].c_str()+1, file_text); - - const char * pinput = file_text.c_str(); - CreateTree(pinput); - + std::string file_text = ReadFile( item.directives[0].c_str()+1 ); + + const char * itext_copy = itext; + itext = file_text.c_str(); + CreateTree(item); + itext = itext_copy; } -void Ezc::Item::CreateTreeReadIf(const char * & itext) +void Pattern::CreateTreeReadIf(Item & item) { -Item item; + Item * pitem = item.AddItem(); + CreateTree(*pitem); - item.type = item_container; - AddItem(item); - item_table.back()->CreateTree(itext); - - if( item_table.back()->LastItemType() == item_else ) + if( pitem->LastItemType() == Item::item_else ) { - // basically we don't have to erase it - CreateTreeReadDeleteLastEndItem(); + pitem->DeleteLastItem(); - item.ClearTable(); - AddItem(item); - item_table.back()->CreateTree(itext); + pitem = item.AddItem(); + CreateTree(*pitem); } - if( !CreateTreeReadDeleteLastEndItem() ) - { - // [end] is missing - // it's probably the end of the input string - } + pitem->DeleteLastItem(); // it deletes [end] from the tree } -void Ezc::Item::CreateTreeReadFor(const char * & itext) +void Pattern::CreateTreeReadFor(Item & item) { -Item item; + Item * pitem = item.AddItem(); + CreateTree(*pitem); - item.type = item_container; - AddItem(item); - item_table.back()->CreateTree(itext); - - if( !CreateTreeReadDeleteLastEndItem() ) - { - // [end] is missing - // it's probably the end of the input string - } + pitem->DeleteLastItem(); // it deletes [end] from the tree } -void Ezc::Item::CreateTree(const char * & itext) +void Pattern::CreateTree(Item & item) { - if( type != item_container) - return; + item.Clear(); + item.type = Item::item_container; - Item item; + Item item_temp; - while( item.CreateTreeReadItem(itext) ) + while( CreateTreeReadItem(item_temp) ) { - AddItem(item); + Item * pitem = item.AddItem(item_temp); - if( item.type==item_end || item.type==item_else ) + if( item_temp.type==Item::item_end || item_temp.type==Item::item_else ) return; - if( item.type == Item::item_ifany || - item.type == Item::item_ifindex || - item.type == Item::item_is ) - item_table.back()->CreateTreeReadIf(itext); + if( pitem->type == Item::item_ifany || + pitem->type == Item::item_ifone || + pitem->type == Item::item_ifindex || + pitem->type == Item::item_is ) + CreateTreeReadIf(*pitem); - if( item.type == Item::item_for ) - item_table.back()->CreateTreeReadFor(itext); + if( pitem->type == Item::item_for ) + CreateTreeReadFor(*pitem); - if( item.type == item_include ) - item_table.back()->CreateTreeReadInclude(); + if( pitem->type == Item::item_include ) + CreateTreeReadInclude(*pitem); } } -// -void Ezc::Item::MakeTextContainer(std::string & otext, UserInfoTable & user_info_table) +/* + * + * Pattern::Item + * + * + */ + + +Pattern::Item * Pattern::Item::AddItem(const Pattern::Item * porg) +{ +Item * pitem; + + if( porg ) + pitem = new Item(*porg); + else + pitem = new Item(); + + item_table.push_back(pitem); + +return pitem; +} + + +Pattern::Item * Pattern::Item::AddItem(const Pattern::Item & porg) +{ + return AddItem(&porg); +} + +void Pattern::Item::ClearItems() { std::vector::iterator i = item_table.begin(); for( ; i != item_table.end() ; ++i ) - (*i)->MakeText(otext, user_info_table); + delete *i; + + item_table.clear(); +} + +void Pattern::Item::Clear() +{ + ClearItems(); + type = item_none; + text.clear(); + directives.clear(); } -void Ezc::Item::MakeTextMsgCantFind(std::string & otext, std::string & key) +Pattern::Item::ItemType Pattern::Item::LastItemType() { - std::ostringstream msg; + if( item_table.empty() ) + return item_none; - msg << ""; - otext += msg.str(); +return item_table.back()->type; } - -void Ezc::Item::MakeTextNormal(std::string & otext, UserInfoTable & user_info_table) +void Pattern::Item::DeleteLastItem() { - if( directives.empty() ) + if( item_table.empty() ) return; - UserInfoTable::iterator i = user_info_table.find( directives[0] ); + delete item_table.back(); - if( i != user_info_table.end() ) - { - Info info; - info.result = false; - info.iter = 0; - (i->second.user_function)(info); - - otext += info.text; - } - else - { - MakeTextMsgCantFind(otext, directives[0]); - } -} - -void Ezc::Item::MakeTextIfany(std::string & otext, UserInfoTable & user_info_table) -{ - std::vector::iterator d = directives.begin(); - int how_many_true = 0; - - for( ; d != directives.end() ; ++d ) - { - UserInfoTable::iterator i = user_info_table.find( *d ); - - if( i != user_info_table.end() ) - { - Info info; - info.result = false; - info.iter = 0; - (i->second.user_function)(info); - - if( !info.text.empty() || info.result ) - ++how_many_true; - } - else - { - MakeTextMsgCantFind(otext, *d); - } - } - - if( how_many_true == directives.size() ) - { - // one element should be in the table (but we're testing) - if( item_table.size() > 0 ) - item_table[0]->MakeText(otext, user_info_table); - } - else - { - // second element can be (or not -- it's from [else]) - if( item_table.size() > 1 ) - item_table[1]->MakeText(otext, user_info_table); - } + item_table.erase( item_table.end() - 1 ); } -void Ezc::Item::MakeTextIs(std::string & otext, UserInfoTable & user_info_table) +Pattern::Item::Item() { - if( directives.size() != 2 ) - return; + type = item_none; +} - bool result = false; - UserInfoTable::iterator i = user_info_table.find( directives[0] ); - if( i != user_info_table.end() ) - { - Info info1, info2; - info1.result = info2.result = false; - info1.iter = info2.iter = 0; - (i->second.user_function)(info1); +Pattern::Item::Item(const Pattern::Item & i) : type(i.type), text(i.text), directives(i.directives) +{ + CopyItemTable(i); +} - if( !directives[1].empty() && directives[1][0]=='\"' ) - { - if( std::strcmp(info1.text.c_str(), directives[1].c_str()+1) == 0 ) - result = true; - } - else - { - i = user_info_table.find( directives[1] ); - if( i != user_info_table.end() ) - { - (i->second.user_function)(info2); +Pattern::Item & Pattern::Item::operator=(const Pattern::Item & i) +{ + type = i.type; + text = i.text; + directives = i.directives; - if( info1.result==info2.result && info1.text==info2.text ) - result = true; - } - else - { - MakeTextMsgCantFind(otext, directives[1]); - } - } - } - else - { - MakeTextMsgCantFind(otext, directives[0]); - } + CopyItemTable(i); + +return *this; +} + + +void Pattern::Item::CopyItemTable(const Pattern::Item & item) +{ + std::vector::const_iterator i = item.item_table.begin(); + + for( ; i != item.item_table.end() ; ++i) + AddItem( *i ); +} + + +Pattern::Item::~Item() +{ + ClearItems(); +} + + +/* + * + * Info + * + * + */ + +Info::Info() +{ + result = false; + iter = 0; +} + + +/* + * + * Generator + * + * + */ - if( result ) - { - // one element should be in the table (but we're testing) - if( item_table.size() > 0 ) - item_table[0]->MakeText(otext, user_info_table); - } - else - { - // second element can be (or not -- it's from [else]) - if( item_table.size() > 1 ) - item_table[1]->MakeText(otext, user_info_table); - } +std::string & Generator::Generate(Pattern & data) +{ + otext.clear(); + MakeText( data.item_root ); + +return otext; +} + +std::string & Generator::String() +{ + return otext; +} + +void Generator::Insert(const std::string & key, UserFunction ufunction) +{ + UserInfo ui; + ui.user_function = ufunction; + ui.iter = 0; + + user_info_table.insert( std::make_pair(key, ui) ); } -void Ezc::Item::MakeTextIfindex(std::string & otext, UserInfoTable & user_info_table) -{ - if( directives.size() != 2 ) - return; - UserInfoTable::iterator i = user_info_table.find( directives[0] ); +void Generator::MakeTextContainer(Pattern::Item & item) +{ + std::vector::iterator i = item.item_table.begin(); + + for( ; i != item.item_table.end() ; ++i ) + MakeText(**i); +} + + +bool Generator::Find(const std::string & key, UserInfo ** user_info) +{ + UserInfoTable::iterator i = user_info_table.find( key ); if( i == user_info_table.end() ) { - MakeTextMsgCantFind(otext, directives[0]); + otext += CreateMsg("can't find", key.c_str() ); + return false; } - - bool result = false; - if( directives[1] == "odd" ) + *user_info = &(i->second); + +return true; +} + + +void Generator::MakeTextNormal(Pattern::Item & item) +{ + if( item.directives.size() != 1 ) + return; + + UserInfo * user_info; + + if( Find(item.directives[0], &user_info) ) { - if( ( i->second.iter & 1) == 1 ) - result = true; - } - else - if( directives[1] == "even" ) - { - if( ( i->second.iter & 1) == 0 ) - result = true; - } - else - if( directives[1] == "first" ) - { - if( i->second.iter == 0 ) - result = true; - } - else - { - const char * number_text = directives[1].c_str(); - char * last_char; - - int number = (int)strtol(number_text, &last_char, 10); - - if( *last_char == '\0' ) - { - if( i->second.iter == number ) - result = true; - } - else - { - otext += ""; - } - + Info info; + (user_info->user_function)(info); + + otext += info.text; } +} +void Generator::MakeTextIf_go(Pattern::Item & item, bool result) +{ if( result ) { - // one element should be in the table (but we're testing) - if( item_table.size() > 0 ) - item_table[0]->MakeText(otext, user_info_table); + if( item.item_table.size() > 0 ) + MakeText( *item.item_table[0] ); } else { // second element can be (or not -- it's from [else]) - if( item_table.size() > 1 ) - item_table[1]->MakeText(otext, user_info_table); + if( item.item_table.size() > 1 ) + MakeText( *item.item_table[1] ); } } -void Ezc::Item::MakeTextFor(std::string & otext, UserInfoTable & user_info_table) +void Generator::MakeTextIfany(Pattern::Item & item) { - if( directives.empty() ) + std::vector::iterator d = item.directives.begin(); + unsigned how_many_true = 0; + + for( ; d != item.directives.end() ; ++d ) + { + UserInfo * user_info; + + if( !Find(*d, &user_info) ) + return; + + + Info info; + (user_info->user_function)(info); + + if( !info.text.empty() || info.result ) + ++how_many_true; + + } + + MakeTextIf_go(item, how_many_true == item.directives.size() ); +} + + +void Generator::MakeTextIfone(Pattern::Item & item) +{ + std::vector::iterator d = item.directives.begin(); + int how_many_true = 0; + + for( ; d != item.directives.end() ; ++d ) + { + UserInfo * user_info; + + if( !Find(*d, &user_info) ) + return; + + Info info; + (user_info->user_function)(info); + + if( !info.text.empty() || info.result ) + ++how_many_true; + } + + MakeTextIf_go(item, how_many_true > 0 ); +} + + +void Generator::MakeTextIs(Pattern::Item & item) +{ + if( item.directives.size() != 2 ) + return; + + UserInfo * user_info; + + if( !Find(item.directives[0], &user_info) ) + return; + + bool result = false; + Info info1, info2; + (user_info->user_function)(info1); + + if( !item.directives[1].empty() && item.directives[1][0]=='\"' ) + { + if( std::strcmp(info1.text.c_str(), item.directives[1].c_str()+1) == 0 ) + result = true; + } + else + { + if( Find(item.directives[1], &user_info) ) + { + (user_info->user_function)(info2); + + if( info1.result==info2.result && info1.text==info2.text ) + result = true; + } + } + + MakeTextIf_go(item, result); +} + + +bool Generator::MakeTextIfindexnumber(Pattern::Item & item, UserInfo * user_info, bool & result) +{ + if( item.directives.size() != 2 ) + return false; + + const char * number_text = item.directives[1].c_str(); + char * last_char; + + int number = (int)strtol(number_text, &last_char, 10); + + if( *last_char == '\0' ) + { + if( user_info->iter == number ) + result = true; + } + else + { + otext += CreateMsg("if-index: syntax error"); + + return false; + } + +return true; +} + + +void Generator::MakeTextIfindex(Pattern::Item & item) +{ + if( item.directives.size() != 2 ) + return; + + UserInfo * user_info; + bool result = false; + + if( !Find(item.directives[0], &user_info) ) + return; + + + if( item.directives[1] == "odd" ) + { + if( ( user_info->iter & 1) == 1 ) + result = true; + } + else + if( item.directives[1] == "even" ) + { + if( ( user_info->iter & 1) == 0 ) + result = true; + } + else + if( item.directives[1] == "first" ) + { + if( user_info->iter == 0 ) + result = true; + } + else + { + if( !MakeTextIfindexnumber(item, user_info, result) ) + return; + } + + MakeTextIf_go(item, result); +} + + +void Generator::MakeTextFor(Pattern::Item & item) +{ + if( item.directives.size() != 1 ) + return; + + UserInfo * user_info; + + if( !Find(item.directives[0], &user_info) ) return; - UserInfoTable::iterator i = user_info_table.find( directives[0] ); + Info info; + user_info->iter = 0; - if( i != user_info_table.end() ) + while( true ) { - Info info; - info.result = false; - info.iter = 0; + (user_info->user_function)(info); + + if( info.text.empty() && !info.result ) + break; - i->second.iter = info.iter; + if( item.item_table.size() > 0 ) + MakeText( *item.item_table[0] ); - while( true ) - { - (i->second.user_function)(info); - - if( info.text.empty() && !info.result ) - break; - - if( item_table.size() > 0 ) - item_table[0]->MakeText(otext, user_info_table); - - ++info.iter; - i->second.iter = info.iter; - } - } - else - { - MakeTextMsgCantFind(otext, directives[0]); + ++info.iter; + user_info->iter = info.iter; } } -void Ezc::Item::MakeText(std::string & otext, UserInfoTable & user_info_table) +void Generator::MakeText(Pattern::Item & item) { - if( type == item_text ) + switch( item.type ) { - otext += text; + case Pattern::Item::item_text: + otext += 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_ifone: + MakeTextIfone(item); + break; + case Pattern::Item::item_ifindex: + MakeTextIfindex(item); + break; + case Pattern::Item::item_is: + MakeTextIs(item); + break; + case Pattern::Item::item_for: + MakeTextFor(item); + break; + case Pattern::Item::item_err: + otext += CreateMsg("a wrong directive"); + break; + default: + break; } - else - if( type == item_container ) - { - MakeTextContainer(otext, user_info_table); - } - else - if( type == item_normal ) - { - MakeTextNormal(otext, user_info_table); - } - else - if( type == item_ifany ) - { - MakeTextIfany(otext, user_info_table); - } - else - if( type == item_ifindex ) - { - MakeTextIfindex(otext, user_info_table); - } - else - if( type == item_is ) - { - MakeTextIs(otext, user_info_table); - } - else - if( type == item_for ) - { - MakeTextFor(otext, user_info_table); - } - else - if( type == item_err ) - { - otext += ""; - } - - } + +void Generator::Clear() +{ + user_info_table.clear(); + otext.clear(); +} + + +} // namespace Ezc + diff --git a/src/ezc.h b/src/ezc.h index 75b71d2..993cfea 100644 --- a/src/ezc.h +++ b/src/ezc.h @@ -1,3 +1,40 @@ +/* + * 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, 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 headerfileezc #define headerfileezc @@ -10,16 +47,100 @@ #include -class Ezc +namespace Ezc +{ + +std::string CreateMsg(const char * type, const char * arg = 0); + + +class Pattern { public: - struct Info + void ParseFile(std::string file_name); + void ParseFile(const char * file_name); + void Directory(const char * d); + void Directory(const std::string & d); + + struct Item { + enum ItemType + { + item_none, item_container, item_text, item_ifany, item_for, item_else, + item_end, item_err, item_normal, item_ifindex, item_include, item_is, item_ifone + }; + + ItemType type; std::string text; - bool result; - int iter; + std::vector item_table; + std::vector directives; + + Item(); + Item(const Item & i); + Item & operator=(const Item & i); + 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 item_root; + +private: + const char * itext; + std::string directory; + + + bool CheckFileName(const char * name); + std::string ReadFile(const char * name); + + int ReadCharInText(); + void SkipWhiteCharacters(); + + std::string ReadDirective(); + std::string ReadString(); + std::string ReadDirectiveOrString(); + + void CreateTreeReadItemDirectiveCheckEnding(Item & item); + + void ReadDirectiveIfany(Item & item); + void ReadDirectiveIfone(Item & item); + void ReadDirectiveIs(Item & item); + void ReadDirectiveIfindex(Item & item); + void ReadDirectiveFor(Item & item); + void ReadDirectiveInclude(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); + +}; // Pattern + + +struct Info +{ + std::string text; + bool result; + int iter; + + Info(); +}; + + + +class Generator +{ +private: typedef void (*UserFunction)(Info &); struct UserInfo @@ -30,64 +151,34 @@ public: typedef std::map UserInfoTable; - UserInfoTable user_info_table; +public: - Ezc(); - void Init(); - void CreateTree(const char * file); - std::string MakeText(); void Insert(const std::string & key, UserFunction ufunction); + std::string & Generate(Pattern & data); + std::string & String(); + void Clear(); private: - struct Item - { - enum ItemType - { - item_none, item_container, item_text, item_ifany, item_for, item_else, - item_end, item_err, item_normal, item_ifindex, item_include, item_is - }; + + UserInfoTable user_info_table; + std::string otext; - ItemType type; - std::string text; - std::vector item_table; - - std::vector directives; - Item(); - ~Item(); - Item * AddItem(const Item & porg); - void ReadFile(const char * name, std::string & result); - void SkipWhiteCharacters(const char * & itext); - void ReadDirective(const char * & itext, std::string & directive); - void ReadString(const char * & itext, std::string & directive); - void ReadDirectiveOrString(const char * & itext, std::string & directive); - void ClearTable(); - ItemType LastItemType(); - bool ReadChar(const char * & itext, char & result); - void CreateTreeReadItemDirectiveCheckEnding(const char * & itext); - void CreateTreeReadItemDirective(const char * & itext); - void CreateTreeReadItemText(const char * & itext); - bool CreateTreeReadItem(const char * & itext); - void CreateTreeReadIf(const char * & itext); - void CreateTreeReadFor(const char * & itext); - bool CreateTreeReadDeleteLastEndItem(); - void CreateTreeReadInclude(); - void CreateTree(const char * & itext); + bool Find(const std::string & key, UserInfo ** user_info); + void MakeTextIf_go(Pattern::Item & item, bool result); + bool MakeTextIfindexnumber(Pattern::Item & item, UserInfo * user_info, bool & result); + void MakeTextIfany(Pattern::Item & item); + void MakeTextIfone(Pattern::Item & item); + void MakeTextIfindex(Pattern::Item & item); + void MakeTextFor(Pattern::Item & item); + void MakeTextContainer(Pattern::Item & item); + void MakeTextNormal(Pattern::Item & item); + void MakeTextIs(Pattern::Item & item); + void MakeText(Pattern::Item & item); - void MakeTextIfany(std::string & otext, UserInfoTable & user_info_table); - void MakeTextIfindex(std::string & otext, UserInfoTable & user_info_table); - void MakeTextFor(std::string & otext, UserInfoTable & user_info_table); - void MakeTextContainer(std::string & otext, UserInfoTable & user_info_table); - void MakeTextMsgCantFind(std::string & otext, std::string & key); - void MakeTextNormal(std::string & otext, UserInfoTable & user_info_table); - void MakeTextIs(std::string & otext, UserInfoTable & user_info_table); - void MakeText(std::string & otext,UserInfoTable & user_info_table); - }; +}; // Generator - Item item_root; - std::string input; - std::string output; -}; +} // namespace Ezc #endif