504 lines
7.7 KiB
C++
504 lines
7.7 KiB
C++
#include "ezc.h"
|
|
|
|
|
|
/*
|
|
*
|
|
* Ezc
|
|
*
|
|
*
|
|
*/
|
|
|
|
bool Ezc::ReadFile(const char * name)
|
|
{
|
|
std::ifstream file(name);
|
|
|
|
if( !file )
|
|
{
|
|
std::ostringstream buffer;
|
|
buffer << "<!-- ezc: can't open: " << name << " -->";
|
|
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<Item*>::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<Item*>::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 << "<!-- ezc: can't find: " << key << " -->";
|
|
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<std::string>::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 += "<!-- ezc: wrong directive -->";
|
|
}
|
|
|
|
|
|
}
|
|
|