#include "ezc.h" /* * * Ezc * * */ bool Ezc::ReadFile(const char * name) { std::ifstream file(name); if( !file ) { std::ostringstream buffer; buffer << ""; input = buffer.str(); return false; } std::getline(file, input, '\0'); return true; } void Ezc::Init() { } Ezc::Ezc() { Init(); } void Ezc::CreateTree() { item_root.ClearTable(); item_root.type = Item::item_container; const char * pinput = input.c_str(); item_root.CreateTree(pinput); } std::string Ezc::MakeText() { output.clear(); item_root.MakeText(output, user_info_table); return output; } void Ezc::Insert(const std::string & key, UserFunction ufunction) { UserInfo ui; ui.user_function = ufunction; user_info_table.insert( std::make_pair(key, ui) ); } /* * * Ezc::Item * * */ Ezc::Item * Ezc::Item::AddItem(const Ezc::Item & porg) { Item * pitem = new Item(porg); 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(); } 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) { while( *itext==' ' || *itext=='\t' ) ++itext; } void Ezc::Item::ReadDirective(const char * & itext, std::string & directive) { directive.clear(); SkipWhiteCharacters(itext); while( (*itext>='a' && *itext<='z') || (*itext>='A' && *itext<='Z') || (*itext>='0' && *itext<='9') || *itext=='_' || *itext=='-' ) { directive += *itext; ++itext; } } void Ezc::Item::CreateTreeReadItemDirectiveCheckEnding(const char * & itext) { SkipWhiteCharacters(itext); if( *itext != ']' ) { type = item_err; while( *itext!=0 && *itext!=']' ) ++itext; } if( *itext == ']' ) ++itext; } void Ezc::Item::CreateTreeReadItemDirective(const char * & itext) { std::string directive; ++itext; directives.clear(); ReadDirective(itext,directive); if( directive == "if-any" ) { type = item_ifany; while( true ) { ReadDirective(itext,directive); if( directive.empty() ) break; directives.push_back(directive); } } else if( directive == "end" ) { type = item_end; } else if( directive == "else" ) { type = item_else; } else if( directive == "for" ) { type = item_for; ReadDirective(itext,directive); if( !directive.empty() ) directives.push_back(directive); } else { directives.push_back(directive); type = item_normal; } CreateTreeReadItemDirectiveCheckEnding(itext); } void Ezc::Item::CreateTreeReadItemText(const char * & itext) { char c; text.clear(); while( ReadChar(itext, c) ) text += c; type = item_text; } bool Ezc::Item::CreateTreeReadItem(const char * & itext) { if( *itext == '[' ) { CreateTreeReadItemDirective(itext); return true; } else if( *itext ) { CreateTreeReadItemText(itext); return true; } // the end of the string return false; } void Ezc::Item::CreateTreeReadAll(const char * & itext) { Item item; while( item.CreateTreeReadItem(itext) ) { AddItem(item); if( item.type==item_end || item.type==item_else ) return; if( item.type == Item::item_ifany ) item_table.back()->CreateTreeReadIfany(itext); if( item.type == Item::item_for ) item_table.back()->CreateTreeReadFor(itext); } } bool Ezc::Item::CreateTreeReadDeleteLastEndItem() { 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::CreateTreeReadIfany(const char * & itext) { Item item; item.type = item_container; AddItem(item); item_table.back()->CreateTree(itext); if( item_table.back()->LastItemType() == item_else ) { // basically we don't have to erase it CreateTreeReadDeleteLastEndItem(); item.ClearTable(); AddItem(item); item_table.back()->CreateTree(itext); } if( !CreateTreeReadDeleteLastEndItem() ) { // [end] is missing // it's probably the end of the input string } } void Ezc::Item::CreateTreeReadFor(const char * & itext) { Item item; 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 } } void Ezc::Item::CreateTree(const char * & itext) { if( type == item_container) CreateTreeReadAll(itext); } // void Ezc::Item::MakeTextContainer(std::string & otext, UserInfoTable & user_info_table) { std::vector::iterator i = item_table.begin(); for( ; i != item_table.end() ; ++i ) (*i)->MakeText(otext, user_info_table); } void Ezc::Item::MakeTextMsgCantFind(std::string & otext, std::string & key) { std::ostringstream msg; msg << ""; otext += msg.str(); } void Ezc::Item::MakeTextNormal(std::string & otext, UserInfoTable & user_info_table) { if( directives.empty() ) return; UserInfoTable::iterator i = user_info_table.find( directives[0] ); 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); } } void Ezc::Item::MakeTextFor(std::string & otext, UserInfoTable & user_info_table) { if( directives.empty() ) return; UserInfoTable::iterator i = user_info_table.find( directives[0] ); if( i != user_info_table.end() ) { Info info; info.result = false; info.iter = 0; i->second.iter = info.iter; while( true ) { (i->second.user_function)(info); ++info.iter; i->second.iter = info.iter; if( info.text.empty() && !info.result ) break; if( item_table.size() > 0 ) item_table[0]->MakeText(otext, user_info_table); } } else { MakeTextMsgCantFind(otext, directives[0]); } } void Ezc::Item::MakeText(std::string & otext, UserInfoTable & user_info_table) { if( type == item_text ) { otext += text; } 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_for ) { MakeTextFor(otext, user_info_table); } else if( type == item_err ) { otext += ""; } }