#include "ezc.h" /* * * Ezc * * */ void Ezc::Init() { } Ezc::Ezc() { Init(); } void Ezc::CreateTree(const char * file) { std::string file_name = "\""; file_name += file; item_root.directives.clear(); item_root.directives.push_back( file_name ); item_root.CreateTreeReadInclude(); } 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; ui.iter = 0; 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(); } void Ezc::Item::ReadFile(const char * name, std::string & result) { std::ifstream file(name); if( !file ) { std::ostringstream buffer; buffer << ""; result = buffer.str(); return; } 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) { 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=='-' || *itext=='.' ) { directive += *itext; ++itext; } } void Ezc::Item::ReadString(const char * & itext, std::string & directive) { directive.clear(); SkipWhiteCharacters(itext); if( *itext != '\"' ) return; // string is signed by its first character equal (") directive += *itext; ++itext; while( (*itext>='a' && *itext<='z') || (*itext>='A' && *itext<='Z') || (*itext>='0' && *itext<='9') || *itext=='_' || *itext=='-' || *itext=='.' || *itext==' ' || *itext==':' || *itext=='\\' )// tymczasowo { 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' } void Ezc::Item::ReadDirectiveOrString(const char * & itext, std::string & directive) { SkipWhiteCharacters(itext); if( *itext == '\"' ) { // we've got string return ReadString(itext, directive); } else { return ReadDirective(itext, directive); } } 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); } if( directives.empty() ) type = item_err; } 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; } 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; } 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 type = item_err; } else if( directive == "include" ) { type = item_include; ReadString(itext,directive); if( !directive.empty() ) directives.push_back(directive); else type = item_err; } 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; } 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::CreateTreeReadInclude() { if( directives.empty() || directives[0].empty() || 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); } void Ezc::Item::CreateTreeReadIf(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) return; 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.type == Item::item_ifindex || item.type == Item::item_is ) item_table.back()->CreateTreeReadIf(itext); if( item.type == Item::item_for ) item_table.back()->CreateTreeReadFor(itext); if( item.type == item_include ) item_table.back()->CreateTreeReadInclude(); } } // 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::MakeTextIs(std::string & otext, UserInfoTable & user_info_table) { if( directives.size() != 2 ) return; 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); 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); if( info1.result==info2.result && info1.text==info2.text ) result = true; } else { MakeTextMsgCantFind(otext, directives[1]); } } } else { MakeTextMsgCantFind(otext, directives[0]); } 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); } } 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] ); if( i == user_info_table.end() ) { MakeTextMsgCantFind(otext, directives[0]); } bool result = false; if( directives[1] == "odd" ) { 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 += ""; } } 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); } } 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); 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]); } } 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_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 += ""; } }