Browse Source

added: support for UTF-8 (files utf8.h utf8.cpp)

they can be even used without the rest library
         as only a library for converting between wide characters and UTF-8
changed: everywhere we use std::wstring instead of std::string
changed: Generator and Functions are templates now
         they take a stream type
renamed: Info to FunInfo and it is a template too
         taking a stream type

now you can use other kind of streams with the library
previous was only std::ostringstream



git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@326 e52654a7-88a9-db11-a3e9-0013d4bc506e
master
Tomasz Sowa 11 years ago
parent
commit
8f94937ed1
  1. 8
      src/Makefile.dep
  2. 2
      src/Makefile.o.dep
  3. 1669
      src/ezc.cpp
  4. 330
      src/ezc.h
  5. 252
      src/functions.h
  6. 93
      src/funinfo.h
  7. 996
      src/generator.h
  8. 163
      src/item.cpp
  9. 91
      src/item.h
  10. 1033
      src/pattern.cpp
  11. 219
      src/pattern.h
  12. 102
      src/stringconv.cpp
  13. 60
      src/stringconv.h
  14. 670
      src/utf8.cpp
  15. 114
      src/utf8.h

8
src/Makefile.dep

@ -1,3 +1,9 @@
# DO NOT DELETE
edanticezc.o: ezc.h /home/tomek/roboczy/winix/core/log.h
edanticitem.o: item.h
edanticpattern.o: pattern.h item.h stringconv.h utf8.h
edanticpattern.o: /home/tomek/roboczy/winix/core/log.h
edanticpattern.o: /home/tomek/roboczy/winix/core/textstream.h
edanticpattern.o: /home/tomek/roboczy/winix/core/misc.h
edanticstringconv.o: stringconv.h
edanticutf8.o: utf8.h

2
src/Makefile.o.dep

@ -1 +1 @@
o = ezc.o
o = item.o pattern.o stringconv.o utf8.o

1669
src/ezc.cpp

File diff suppressed because it is too large

330
src/ezc.h

@ -36,334 +36,12 @@
*/
#ifndef headerfileezc
#define headerfileezc
#ifndef headerfile_ezc_ezc
#define headerfile_ezc_ezc
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <map>
#include <cstdlib>
#include <cstring>
namespace Ezc
{
class Pattern
{
public:
Pattern();
void ParseFile(const std::string & file_name);
void ParseFile(const char * file_name);
void ParseString(const std::string & str);
void ParseString(const char * str);
// first we're trying to read a file from directory dir
// if there is no such a file there then we try read from dir2
// (the second dir2 can be empty - it will not be used)
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);
bool IsWhite(int c);
struct Item
{
enum Type
{
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 Function
{
std::string name; // function name
std::vector<std::string> params; // function parameters
};
Type type;
std::string text; // used in: item_text, item_include (as a file name)
std::vector<Item*> item_tab; // !! zamienic na 'items'?
std::vector<Function> functions;
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();
Type LastItemType();
void DeleteLastItem();
void Clear();
};
Item item_root;
private:
const char * itext;
// allowing include tag
// default: true
bool allow_include;
// if true all text-items which have only white characters (with new lines as well)
// will be deleted - useful in *.txt templates
// this not actually delete the whole item but only the string
// the item will be present with an empty string
// default: false
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, include_level_max;
std::string commentary_start, commentary_stop;
std::string ReadFile(const std::string & name);
std::string ReadFile(const char * name);
bool HasFileAtBeginning(const char * path, const char * file);
bool IsFileCorrect(const char * name);
bool ReadFileFromDir(const std::string & dir, const char * name, std::string & result);
int ReadCharInText();
void SkipWhite();
void CheckWhiteAndDelete(std::string & s);
bool IsNameChar(int c);
bool IsDigit(int c);
bool IsPositiveNumber(const std::string & str);
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 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);
void ReadDirectiveFor(Item & item);
void ReadDirectiveComment(Item & item);
void ReadDirectiveInclude(Item & item);
void ReadDirectiveDef(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);
}; // class Pattern
struct Info
{
// output stream
std::ostringstream & out;
// table of parameters
std::vector<std::string> & 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
// normally is 0
// in a [for] statement it indicates the number of the current iteration (the first is 0)
int iter;
// return value from a user function (default false if not set directly by the user function)
// for a variable it is set to true if the variable is not empty
bool res;
// arguments: output_stream, table_of_parameters, the_first_parameter
Info(std::ostringstream & o, std::vector<std::string> & pars, const std::string & p);
void Clear();
};
// functions or variables
class Functions
{
public:
typedef void (*UserFunction)(Info &);
enum Type { function, variable };
struct Function
{
Type type;
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 is currently executed
Function();
};
void Insert(const std::string & key, UserFunction ufunction); // inserting a function
void Insert(const std::string & key, const char * var); // inserting a variable
void Insert(const std::string & key, const std::string & var); // inserting a variable
bool Find(const std::string & key, Function ** fun);
void Clear();
private:
typedef std::map<std::string, Function> FunctionsTable;
FunctionsTable functions_tab;
};
class Generator
{
public:
Generator();
Generator(std::ostringstream & o, Pattern & p, 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_);
// recognizing some special characters in text patterns (item_text in Patterns)
// \r will be a carriage return (13)
// \n will be a new line (10)
// \t will be a tabulator (9)
// \s will be a space
// \\ will be one '\'
// default: false
void RecognizeSpecialChars(bool spec);
// trimming white characters (at the beginning and at the end of an item_text)
// (special char \s if enabled is not treated as a white character here)
// default: false
void TrimWhite(bool trim);
// skipping new line characters (from the whole string in an item_text)
// but you can use a new line character written as "\n" (if special chars are turn on)
// default: false
void SkipNewLine(bool skip);
void Generate();
private:
std::ostringstream * output_stream;
Pattern * pattern;
Functions * functions;
bool break_generating;
int current_item;
int max_items;
int max_for_items;
bool special_chars;
bool trim_white;
bool skip_new_line;
// an empty string for info objects
const std::string empty;
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);
char CreateSpecialChar(char c);
void PrintSpecialText(const char * start, const char * end);
void PrintNormalText(const char * start, const char * end);
void TrimWhite(const char *& start, const char *& end);
void MakeTextIf_go(Pattern::Item & item, bool result);
bool MakeTextIfindexnumber(Pattern::Item & item, Functions::Function * function, bool & result);
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 MakeItemText(Pattern::Item & item);
void MakeTextContainer(Pattern::Item & item);
void MakeTextNormal(Pattern::Item & item);
void MakeTextIs(Pattern::Item & item);
void MakeTextIsno(Pattern::Item & item);
void MakeTextDefine(Pattern::Item & item);
void MakeText(Pattern::Item & item);
}; // class Generator
} // namespace Ezc
#include "utf8.h"
#include "generator.h"
#endif

252
src/functions.h

@ -0,0 +1,252 @@
/*
* This file is a part of EZC -- Easy templating in C++
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2007-2010, 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 headerfile_ezc_functions
#define headerfile_ezc_functions
#include <map>
#include "funinfo.h"
namespace Ezc
{
// functions or variables
template<class StreamType>
class Functions
{
public:
typedef void (*UserFunction)(FunInfo<StreamType> &);
enum Type { function, variable };
struct Function
{
Type type;
UserFunction user_function; // used when type is 'function'
std::wstring 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 is currently executed
Function();
};
void Insert(const char * key, UserFunction ufunction); // inserting a function
void Insert(const char * key, const char * var); // inserting a variable
void Insert(const char * key, const std::string & var); // inserting a variable
void Insert(const std::string & key, UserFunction ufunction); // inserting a function
void Insert(const std::string & key, const char * var); // inserting a variable
void Insert(const std::string & key, const std::string & var); // inserting a variable
void Insert(const std::wstring & key, UserFunction ufunction);
void Insert(const std::wstring & key, const wchar_t * var);
void Insert(const std::wstring & key, const std::wstring & var);
bool Find(const std::string & key, Function ** fun);
bool Find(const std::wstring & key, Function ** fun);
void Clear();
private:
typedef std::map<std::wstring, Function> FunctionsTable;
FunctionsTable functions_tab;
std::wstring temp_key;
};
template<class StreamType>
Functions<StreamType>::Function::Function()
{
type = Functions::variable;
user_function = 0;
iter = 0;
is_for = false;
is_running = false;
}
template<class StreamType>
void Functions<StreamType>::Insert(const char * key, UserFunction ufunction)
{
Function f;
f.type = function;
f.user_function = ufunction;
AssignString(key, temp_key);
functions_tab[temp_key] = f;
}
template<class StreamType>
void Functions<StreamType>::Insert(const char * key, const char * var)
{
Function f;
f.type = variable;
AssignString(var, f.variable);
AssignString(key, temp_key);
functions_tab[temp_key] = f;
}
template<class StreamType>
void Functions<StreamType>::Insert(const char * key, const std::string & var)
{
Function f;
f.type = variable;
AssignString(var, f.variable);
AssignString(key, temp_key);
functions_tab[temp_key] = f;
}
template<class StreamType>
void Functions<StreamType>::Insert(const std::string & key, UserFunction ufunction)
{
Insert(key.c_str(), ufunction);
}
template<class StreamType>
void Functions<StreamType>::Insert(const std::string & key, const char * var)
{
Insert(key.c_str(), var);
}
template<class StreamType>
void Functions<StreamType>::Insert(const std::string & key, const std::string & var)
{
Insert(key.c_str(), var);
}
template<class StreamType>
void Functions<StreamType>::Insert(const std::wstring & key, UserFunction ufunction)
{
Function f;
f.type = function;
f.user_function = ufunction;
functions_tab[key] = f;
}
template<class StreamType>
void Functions<StreamType>::Insert(const std::wstring & key, const wchar_t * var)
{
Function f;
f.type = variable;
f.variable = var;
functions_tab[key] = f;
}
template<class StreamType>
void Functions<StreamType>::Insert(const std::wstring & key, const std::wstring & var)
{
Function f;
f.type = variable;
f.variable = var;
functions_tab[key] = f;
}
template<class StreamType>
bool Functions<StreamType>::Find(const std::string & key, Function ** fun)
{
AssignString(key, temp_key);
return Find(temp_key, fun);
}
template<class StreamType>
bool Functions<StreamType>::Find(const std::wstring & key, Function ** fun)
{
typename FunctionsTable::iterator i = functions_tab.find( key );
if( i == functions_tab.end() )
return false;
*fun = &(i->second);
return true;
}
template<class StreamType>
void Functions<StreamType>::Clear()
{
functions_tab.clear();
}
} // namespace Ezc
#endif

93
src/funinfo.h

@ -0,0 +1,93 @@
/*
* This file is a part of EZC -- Easy templating in C++
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2007-2010, 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 headerfile_ezc_info
#define headerfile_ezc_info
#include <vector>
namespace Ezc
{
template<class StreamType>
struct FunInfo
{
// output stream
StreamType & out;
// table of parameters
std::vector<std::wstring> & 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 string
const std::wstring & par;
// this is set by Generator
// normally is 0
// in a [for] statement it indicates the number of the current iteration (the first is 0)
int iter;
// return value from a user function (default false if not set directly by the user function)
// for a variable it is set to true if the variable is not empty
bool res;
// arguments: output_stream, table_of_parameters, the_first_parameter
FunInfo(StreamType & o, std::vector<std::wstring> & pars, const std::wstring & p) : out(o), params(pars), par(p)
{
Clear();
}
void Clear()
{
res = false; // false by default
iter = 0;
}
};
} // namespace Ezc
#endif

996
src/generator.h

@ -0,0 +1,996 @@
/*
* This file is a part of EZC -- Easy templating in C++
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2007-2010, 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 headerfile_ezc_generator
#define headerfile_ezc_generator
#include "pattern.h"
#include "functions.h"
#include <sstream>
#include <fstream>
namespace Ezc
{
template<class StreamType>
class Generator
{
public:
Generator();
Generator(StreamType & o, Pattern & p, Functions<StreamType> & f);
void Set(StreamType & o, Pattern & p, Functions<StreamType> & f);
void Set(StreamType & o);
void Set(Pattern & p);
void Set(Functions<StreamType> & f);
void SetMax(int max_items_, int max_for_items_);
// recognizing some special characters in text patterns (item_text in Patterns)
// \r will be a carriage return (13)
// \n will be a new line (10)
// \t will be a tabulator (9)
// \s will be a space
// \\ will be one '\'
// default: false
void RecognizeSpecialChars(bool spec);
// trimming white characters (at the beginning and at the end of an item_text)
// (special char \s if enabled is not treated as a white character here)
// default: false
void TrimWhite(bool trim);
// skipping new line characters (from the whole string in an item_text)
// but you can use a new line character written as "\n" (if special chars are turn on)
// default: false
void SkipNewLine(bool skip);
void Generate();
private:
StreamType * output_stream;
Pattern * pattern;
Functions<StreamType> * functions;
// temporary error messages
std::wstring temp_msg;
bool break_generating;
int current_item;
int max_items;
int max_for_items;
bool special_chars;
bool trim_white;
bool skip_new_line;
// an empty string for info objects
// when there is no any parameters
const std::wstring empty;
void PutChar(wchar_t z, StreamType & out);
void PutStringGeneric(const wchar_t * start, size_t len, StreamType & out);
// !! tu bedzie chyba problem z kompilacja
// kiedy typ strumienia to bedzie std::ostream
// chwilowo zostawiam jak jest
/*
void PutString(const wchar_t * start, const wchar_t * end, std::ostream & out)
{
PutStringGeneric(start, end-start, out);
}
void PutString(const wchar_t * start, const wchar_t * end, std::iostream & out)
{
PutStringGeneric(start, end-start, out);
}
void PutString(const wchar_t * start, const wchar_t * end, std::ofstream & out)
{
PutStringGeneric(start, end-start, out);
}
void PutString(const wchar_t * start, const wchar_t * end, std::fstream & out)
{
PutStringGeneric(start, end-start, out);
}
void PutString(const wchar_t * start, const wchar_t * end, std::ostringstream & out)
{
PutStringGeneric(start, end-start, out);
}
void PutString(const wchar_t * start, const wchar_t * end, std::stringstream & out)
{
PutStringGeneric(start, end-start, out);
}
*/
void PutString(const std::wstring & str, StreamType & out)
{
PutString(str.c_str(), str.c_str() + str.size(), out);
}
void PutString(const wchar_t * start, const wchar_t * end, StreamType & out)
{
out.write(start, end-start);
}
bool Find(const std::wstring & key, typename Functions<StreamType>::Function ** function);
void Call(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
bool Call(const std::wstring & name, FunInfo<StreamType> & info, typename Functions<StreamType>::Function ** pfun = 0);
bool Call(typename Item::Function & function, bool * info_res = 0, typename Functions<StreamType>::Function ** pfun = 0);
void CallUserFunction(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
void CallVariable(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
wchar_t CreateSpecialChar(wchar_t c);
void PrintSpecialText(const wchar_t * start, const wchar_t * end);
void PrintNormalText(const wchar_t * start, const wchar_t * end);
void TrimWhite(const wchar_t *& start, const wchar_t *& end);
void SkipWhite(const wchar_t *& str);
int StrToInt(const wchar_t * str, const wchar_t ** str_end);
void CreateMsg(StreamType & o, const wchar_t * type, const wchar_t * arg = 0);
void CreateMsg(StreamType & o, const std::wstring & type, const std::wstring & arg);
void CreateMsg(StreamType & o, const std::wstring & type);
void MakeTextIf_go(Item & item, bool result);
bool MakeTextIfindexnumber(Item & item, typename Functions<StreamType>::Function * function, bool & result);
void MakeTextIf(Item & item);
void MakeTextIfno(Item & item);
void MakeTextIfany(Item & item);
void MakeTextIfone(Item & item);
void MakeTextIfanyno(Item & item);
void MakeTextIfoneno(Item & item);
void MakeTextIfindex(Item & item);
void MakeTextForLoop(Item & item, typename Functions<StreamType>::Function * function);
void MakeTextFor(Item & item);
void MakeItemText(Item & item);
void MakeTextContainer(Item & item);
void MakeTextNormal(Item & item);
void MakeTextIs(Item & item);
void MakeTextIsno(Item & item);
void MakeTextDefine(Item & item);
void MakeText(Item & item);
}; // class Generator
template<class StreamType>
void Generator<StreamType>::PutChar(wchar_t z, StreamType & out)
{
typedef typename StreamType::char_type CharType;
out << static_cast<CharType>(z);
}
/*
template<class StreamType>
void Generator<StreamType>::PutString(const wchar_t * start, const wchar_t * end, StreamType & out)
{
out.write(start, end-start);
}
template<class StreamType>
void Generator<StreamType>::PutString(const std::wstring & str, StreamType & out)
{
PutString(str.c_str(), str.c_str() + str.size(), out);
}
*/
template<class StreamType>
void Generator<StreamType>::PutStringGeneric(const wchar_t * start, size_t len, StreamType & out)
{
typedef typename StreamType::char_type CharType;
for(size_t i=0 ; i<len ; ++i)
out << static_cast<CharType>(start[i]);
}
template<class StreamType>
Generator<StreamType>::Generator()
{
output_stream = 0;
pattern = 0;
functions = 0;
max_items = 50000;
max_for_items = 5000;
special_chars = false;
trim_white = false;
skip_new_line = false;
}
template<class StreamType>
Generator<StreamType>::Generator(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
output_stream = &o;
pattern = &p;
functions = &f;
max_items = 50000;
max_for_items = 5000;
special_chars = false;
trim_white = false;
skip_new_line = false;
}
template<class StreamType>
void Generator<StreamType>::Set(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
output_stream = &o;
pattern = &p;
functions = &f;
}
template<class StreamType>
void Generator<StreamType>::Set(StreamType & o)
{
output_stream = &o;
}
template<class StreamType>
void Generator<StreamType>::Set(Pattern & p)
{
pattern = &p;
}
template<class StreamType>
void Generator<StreamType>::Set(Functions<StreamType> & f)
{
functions = &f;
}
template<class StreamType>
void Generator<StreamType>::SetMax(int max_items_, int max_for_items_)
{
max_items = max_items_;
max_for_items = max_for_items_;
}
template<class StreamType>
void Generator<StreamType>::RecognizeSpecialChars(bool spec)
{
special_chars = spec;
}
template<class StreamType>
void Generator<StreamType>::TrimWhite(bool trim)
{
trim_white = trim;
}
template<class StreamType>
void Generator<StreamType>::SkipNewLine(bool skip)
{
skip_new_line = skip;
}
template<class StreamType>
void Generator<StreamType>::Generate()
{
if( !output_stream || !pattern || !functions )
return;
break_generating = false;
current_item = 0;
MakeText( pattern->item_root );
}
template<class StreamType>
bool Generator<StreamType>::Find(const std::wstring & key, typename Functions<StreamType>::Function ** function)
{
if( !functions->Find(key, function) )
{
CreateMsg(*output_stream, L"can't find", key.c_str() );
return false;
}
return true;
}
template<class StreamType>
void Generator<StreamType>::CallUserFunction(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
{
if( function->is_running )
{
// recurrences are not allowed
CreateMsg(*output_stream, L"the function is being executed");
return;
}
function->is_running = true;
(function->user_function)(info);
function->is_running = false;
}
template<class StreamType>
void Generator<StreamType>::CallVariable(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
{
info.res = !function->variable.empty();
}
template<class StreamType>
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
{
info.Clear();
info.iter = function->iter;
if( function->type == Functions<StreamType>::function )
CallUserFunction(function, info);
else
CallVariable(function, info);
}
// return: true if a function or variable was found and called
template<class StreamType>
bool Generator<StreamType>::Call(const std::wstring & name, FunInfo<StreamType> & info, typename Functions<StreamType>::Function ** pfun)
{
typename Functions<StreamType>::Function * function;
if( Find(name, &function) )
{
Call(function, info);
if( pfun )
*pfun = function;
return true;
}
return false;
}
// return: true if a function or variable was found and called
template<class StreamType>
bool Generator<StreamType>::Call(typename Item::Function & function, bool * info_res, typename Functions<StreamType>::Function ** pfun)
{
bool called;
if( function.params.empty() )
{
FunInfo<StreamType> info(*output_stream, function.params, empty);
called = Call(function.name, info, pfun);
if( info_res )
*info_res = info.res;
}
else
{
FunInfo<StreamType> info(*output_stream, function.params, function.params[0]);
called = Call(function.name, info, pfun);
if( info_res )
*info_res = info.res;
}
return called;
}
template<class StreamType>
wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c)
{
wchar_t res = 0;
if( c == 'r' )
res = '\r';
else
if( c == 'n' )
res = '\n';
else
if( c == 't' )
res = '\t';
else
if( c == 's' )
res = ' ';
else
if( c == '\\' )
res = '\\';
return res;
}
template<class StreamType>
void Generator<StreamType>::PrintSpecialText(const wchar_t * start, const wchar_t * end)
{
wchar_t special;
while( start != end )
{
special = 0;
if( *start == '\\' && (start+1) != end )
special = CreateSpecialChar(*(start+1));
if( special )
{
*output_stream << special;
start += 2;
}
else
{
if( !(skip_new_line && *start == 10) )
*output_stream << *start;
start += 1;
}
}
}
template<class StreamType>
void Generator<StreamType>::PrintNormalText(const wchar_t * start, const wchar_t * end)
{
if( skip_new_line )
{
for( ; start != end ; ++start)
{
if( *start != 10 )
PutChar(*start, *output_stream);
}
}
else
{
if( start != end )
PutString(start, end, *output_stream);
}
}
template<class StreamType>
void Generator<StreamType>::TrimWhite(const wchar_t *& start, const wchar_t *& end)
{
while( start != end && pattern->IsWhite(*start) )
++start;
while( start != end && pattern->IsWhite(*(end-1)) )
--end;
}
template<class StreamType>
void Generator<StreamType>::SkipWhite(const wchar_t *& str)
{
while( pattern->IsWhite(*str) )
str += 1;
}
template<class StreamType>
int Generator<StreamType>::StrToInt(const wchar_t * str, const wchar_t ** str_end)
{
int res = 0;
SkipWhite(str);
// overflow is not checked
while( *str>='0' && *str<='9' )
{
res *= 10;
res += *str - '0';
str += 1;
}
SkipWhite(str);
*str_end = str;
return res;
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & o, const wchar_t * type, const wchar_t * arg)
{
pattern->CreateMsg(temp_msg, type, arg);
PutString(temp_msg, o);
temp_msg.clear();
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & o, const std::wstring & type, const std::wstring & arg)
{
CreateMsg(o, type.c_str(), arg.c_str());
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & o, const std::wstring & type)
{
CreateMsg(o, type.c_str());
}
template<class StreamType>
void Generator<StreamType>::MakeItemText(Item & item)
{
const wchar_t * start = item.text.c_str();
const wchar_t * end = item.text.c_str() + item.text.size();
if( trim_white )
TrimWhite(start, end);
if( special_chars )
PrintSpecialText(start, end);
else
PrintNormalText(start, end);
}
template<class StreamType>
void Generator<StreamType>::MakeTextContainer(Item & item)
{
std::vector<Item*>::iterator i = item.item_tab.begin();
for( ; i != item.item_tab.end() && !break_generating ; ++i )
MakeText(**i);
}
template<class StreamType>
void Generator<StreamType>::MakeTextNormal(Item & item)
{
if( item.functions.size() != 1 )
return;
typename Functions<StreamType>::Function * pfun;
bool called = Call(item.functions[0], 0, &pfun);
if( called && pfun->type == Functions<StreamType>::variable )
PutString(pfun->variable, *output_stream);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIf_go(Item & item, bool result)
{
if( result )
{
if( item.item_tab.size() > 0 )
MakeText( *item.item_tab[0] );
}
else
{
// second element can be (or not -- it's from [else])
if( item.item_tab.size() > 1 )
MakeText( *item.item_tab[1] );
}
}
template<class StreamType>
void Generator<StreamType>::MakeTextIf(Item & item)
{
bool info_res;
if( item.functions.size() != 1 )
return;
if( !Call(item.functions[0], &info_res) )
return;
MakeTextIf_go(item, info_res);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIfno(Item & item)
{
bool info_res;
if( item.functions.size() != 1 )
return;
if( !Call(item.functions[0], &info_res) )
return;
MakeTextIf_go(item, !info_res);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIfany(Item & item)
{
std::vector<typename Item::Function>::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());
}
template<class StreamType>
void Generator<StreamType>::MakeTextIfone(Item & item)
{
std::vector<typename Item::Function>::iterator d = item.functions.begin();
unsigned how_many_true = 0;
bool info_res;
for( ; d != item.functions.end() ; ++d )
{
if( Call(*d, &info_res) && info_res )
{
// there is no sense to go through all functions
++how_many_true;
break;
}
}
MakeTextIf_go(item, how_many_true > 0);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIfanyno(Item & item)
{
std::vector<typename Item::Function>::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 == 0);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIfoneno(Item & item)
{
std::vector<typename Item::Function>::iterator d = item.functions.begin();
unsigned how_many_false = 0;
bool info_res;
for( ; d != item.functions.end() ; ++d )
{
if( Call(*d, &info_res) && !info_res )
++how_many_false;
}
MakeTextIf_go(item, how_many_false > 0);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIs(Item & item)
{
bool info_res1, info_res2;
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);
}
template<class StreamType>
void Generator<StreamType>::MakeTextIsno(Item & item)
{
bool info_res1, info_res2;
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);
}
template<class StreamType>
bool Generator<StreamType>::MakeTextIfindexnumber(Item & item, typename Functions<StreamType>::Function * function, bool & result)
{
if( item.functions.size() != 2 )
return false;
const wchar_t * number_text = item.functions[1].name.c_str();
const wchar_t * last_char;
int number = StrToInt(number_text, &last_char);
if( *last_char != '\0' )
{
CreateMsg(*output_stream, L"if-index: syntax error");
return false;
}
result = (function->iter == number);
return true;
}
template<class StreamType>
void Generator<StreamType>::MakeTextIfindex(Item & item)
{
if( item.functions.size() != 2 )
return;
// we actually don't call a function (or variable) here
// but only reading the iterator
typename Functions<StreamType>::Function * function;
if( !Find(item.functions[0].name, &function) )
return;
bool result = false;
if( item.functions[1].name == L"odd" )
{
result = (function->iter & 1) == 1;
}
else
if( item.functions[1].name == L"even" )
{
result = (function->iter & 1) == 0;
}
else
if( item.functions[1].name == L"first" )
{
result = function->iter == 0;
}
else
{
if( !MakeTextIfindexnumber(item, function, result) )
return;
}
MakeTextIf_go(item, result);
}
template<class StreamType>
void Generator<StreamType>::MakeTextForLoop(Item & item, typename Functions<StreamType>::Function * function)
{
bool info_res;
for( ; !break_generating ; function->iter += 1 )
{
if( function->iter >= max_for_items )
{
CreateMsg(*output_stream, item.functions[0].name.c_str(),
L"function exceeded a limit for a [for] statement");
break;
}
Call(item.functions[0], &info_res);
if( !info_res )
break;
if( !item.item_tab.empty() )
MakeText( *item.item_tab[0] ); // should be only one item - item_container
}
}
template<class StreamType>
void Generator<StreamType>::MakeTextFor(Item & item)
{
if( item.functions.size() != 1 )
return;
typename Functions<StreamType>::Function * function;
if( !Find(item.functions[0].name, &function) )
return;
if( function->is_for )
{
CreateMsg(*output_stream, item.functions[0].name.c_str(),
L"this function is already used in a [for] statement");
return;