From 8f94937ed159553c91a17736e8295fa686104f7d Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 22 Nov 2010 01:23:32 +0000 Subject: [PATCH] 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 --- src/Makefile.dep | 8 +- src/Makefile.o.dep | 2 +- src/ezc.cpp | 1669 -------------------------------------------- src/ezc.h | 330 +-------- src/functions.h | 252 +++++++ src/funinfo.h | 93 +++ src/generator.h | 996 ++++++++++++++++++++++++++ src/item.cpp | 163 +++++ src/item.h | 91 +++ src/pattern.cpp | 1033 +++++++++++++++++++++++++++ src/pattern.h | 219 ++++++ src/stringconv.cpp | 102 +++ src/stringconv.h | 60 ++ src/utf8.cpp | 670 ++++++++++++++++++ src/utf8.h | 114 +++ 15 files changed, 3805 insertions(+), 1997 deletions(-) delete mode 100644 src/ezc.cpp create mode 100755 src/functions.h create mode 100755 src/funinfo.h create mode 100755 src/generator.h create mode 100755 src/item.cpp create mode 100755 src/item.h create mode 100755 src/pattern.cpp create mode 100755 src/pattern.h create mode 100755 src/stringconv.cpp create mode 100755 src/stringconv.h create mode 100755 src/utf8.cpp create mode 100755 src/utf8.h diff --git a/src/Makefile.dep b/src/Makefile.dep index 1782db6..9908373 100755 --- a/src/Makefile.dep +++ b/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 diff --git a/src/Makefile.o.dep b/src/Makefile.o.dep index 9806e60..babaa59 100755 --- a/src/Makefile.o.dep +++ b/src/Makefile.o.dep @@ -1 +1 @@ -o = ezc.o +o = item.o pattern.o stringconv.o utf8.o diff --git a/src/ezc.cpp b/src/ezc.cpp deleted file mode 100644 index 60cc355..0000000 --- a/src/ezc.cpp +++ /dev/null @@ -1,1669 +0,0 @@ -/* - * 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-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. - */ - -#include "ezc.h" - -#ifdef EZC_USE_WINIX_LOGGER -#include "core/log.h" -#endif - - -namespace Ezc -{ - - -/* - * - * Pattern - * - * - */ - - -Pattern::Pattern() -{ - Clear(); - - commentary_start = ""; - - allow_include = true; - delete_white_text_items = false; - - include_level_max = 100; -} - - -void Pattern::CreateMsg(std::ostringstream & o, const char * type, const char * arg) -{ - o << commentary_start << "ezc: " << type; - - if( arg ) - o << ' ' << arg << ' '; - - o << commentary_stop; -} - - -std::string Pattern::CreateMsg(const char * type, const char * arg) -{ -std::ostringstream buffer; - - CreateMsg(buffer, type, arg); - -return buffer.str(); -} - - - -void Pattern::ParseFile(const std::string & file_name) -{ - ParseFile( file_name.c_str() ); -} - - - -void Pattern::ParseFile(const char * file_name) -{ - item_root.text = file_name; - include_level = 0; - CreateTreeReadIncludeSkipAllowFlag(item_root); -} - - - -void Pattern::ParseString(const std::string & str) -{ - ParseString( str.c_str() ); -} - - -void Pattern::ParseString(const char * str) -{ - itext = str; - include_level = 0; - CreateTree(item_root); -} - - -void Pattern::Directory(const char * dir, const char * dir2) -{ - directory.clear(); - directory2.clear(); - - if( dir ) - directory = dir; - - if( dir2 ) - directory2 = dir2; -} - - -void Pattern::Directory(const std::string & dir) -{ - directory = dir; - directory2.clear(); -} - - -void Pattern::Directory(const std::string & dir, const std::string & dir2) -{ - directory = dir; - directory2 = dir2; -} - - -void Pattern::AllowInclude(bool allow) -{ - allow_include = allow; -} - - -void Pattern::DeleteWhiteTextItems(bool del) -{ - delete_white_text_items = del; -} - - -void Pattern::SetCommentary(const char * com_start, const char * com_stop) -{ - commentary_start = com_start; - commentary_stop = com_stop; -} - - -void Pattern::SetCommentary(const std::string & com_start, const std::string & com_stop) -{ - commentary_start = com_start; - commentary_stop = com_stop; -} - - -void Pattern::SetIncludeMax(int include_max) -{ - include_level_max = include_max; -} - - -void Pattern::Clear() -{ - item_root.Clear(); -} - - - -bool Pattern::HasFileAtBeginning(const char * path, const char * file) -{ - for(; *path && *file; ++path, ++file) - { - if( *path != *file ) - return false; - } - - if( *file != 0 ) - return false; - - // "\" is from a dos path syntax - if( *path==0 || *path=='\\' || *path=='/' ) - return true; - -return false; -} - - -/* - ".." is not allowed in the file path - you cannot go up from your template directory -*/ -bool Pattern::IsFileCorrect(const char * name) -{ - while( *name ) - { - if( HasFileAtBeginning(name, "..") ) - return false; - - // looking for the next slash of backslash - while( *name && *name!='\\' && *name!='/' ) - name += 1; - - // skipping the slash (or backslash) - if( *name ) - name += 1; - } - -return true; -} - - - - -/* - 'name' must be a relative path - without a slash or backslash -*/ -std::string Pattern::ReadFile(const std::string & name) -{ - return ReadFile(name.c_str()); -} - - -/* - 'name' must be a relative path - without a slash or backslash -*/ -std::string Pattern::ReadFile(const char * name) -{ - if( !IsFileCorrect(name) ) - return CreateMsg("incorrect file name:", name); - - std::string result; - - if( !ReadFileFromDir(directory, name, result) ) - if( !ReadFileFromDir(directory2, name, result) ) - return CreateMsg("can't open: ", name); - -return result; -} - - - -bool Pattern::ReadFileFromDir(const std::string & dir, const char * name, std::string & result) -{ - if( dir.empty() ) - return false; - - std::string file_name(dir); - file_name += '/'; - file_name += name; - - std::ifstream file(file_name.c_str()); - - if( !file ) - return false; - - std::getline(file, result, '\0'); - - #ifdef EZC_USE_WINIX_LOGGER - log << log3 << "EZC: read pattern: " << file_name << logend; - #endif - -return true; -} - - -int Pattern::ReadCharInText() -{ - if( *itext==0 || *itext=='[' ) - return -1; - - if( *itext == '\\' ) - { - if( *(itext+1)=='\\' || *(itext+1)=='[' || *(itext+1)==']' ) - ++itext; - } - -return *(itext++); -} - - -bool Pattern::IsWhite(int c) -{ - // 13 (\r) is from a dos file at the end of a line (\r\n) - // 160 is an unbreakable space - - if( c==' ' || c=='\t' || c==13 || c==160 || c==10 ) - return true; - -return false; -} - - -void Pattern::SkipWhite() -{ - while( IsWhite(*itext) ) - ++itext; -} - - -void Pattern::CheckWhiteAndDelete(std::string & s) -{ -size_t i; - - if( s.empty() ) - return; - - for(i=0 ; i='a' && c<='z') || - (c>='A' && c<='Z') || - (c>='0' && c<='9') || - c=='_' || c=='-' || c=='.' || c=='#'); -} - - -bool Pattern::IsDigit(int c) -{ - return (c>='0' && c<='9'); -} - - -bool Pattern::IsPositiveNumber(const std::string & str) -{ -size_t i; - - for(i=0 ; i include_level_max ) - { - #ifdef EZC_USE_WINIX_LOGGER - log << log1 << "EZC: \"include\" directive has reached the maximum level" << logend; - #endif - - return; - } - - ++include_level; - std::string file_text = ReadFile( item.text ); - - const char * itext_old = itext; - itext = file_text.c_str(); - CreateTree(item); - itext = itext_old; - --include_level; -} - - -void Pattern::CreateTreeReadIf(Item & item) -{ - Item * pitem = item.AddItem(); - CreateTree(*pitem); - - if( pitem->LastItemType() == Item::item_else ) - { - pitem->DeleteLastItem(); - - pitem = item.AddItem(); - CreateTree(*pitem); - } - - if( pitem->LastItemType() == Item::item_end ) - pitem->DeleteLastItem(); -} - - -void Pattern::CreateTreeReadFor(Item & item) -{ - Item * pitem = item.AddItem(); - CreateTree(*pitem); - - if( pitem->LastItemType() == Item::item_end ) - pitem->DeleteLastItem(); -} - - -void Pattern::CreateTree(Item & item) -{ - item.Clear(); - item.type = Item::item_container; - - Item item_temp; - - while( CreateTreeReadItem(item_temp) ) - { - if( item_temp.type == Item::item_comment ) - continue; - - Item * pitem = item.AddItem(item_temp); - - if( item_temp.type==Item::item_end || item_temp.type==Item::item_else ) - return; - - if( pitem->type == Item::item_if || - pitem->type == Item::item_ifno || - pitem->type == Item::item_ifany || - pitem->type == Item::item_ifone || - pitem->type == Item::item_ifanyno || - pitem->type == Item::item_ifoneno || - pitem->type == Item::item_ifindex || - pitem->type == Item::item_is || - pitem->type == Item::item_isno ) - CreateTreeReadIf(*pitem); - - if( pitem->type == Item::item_for ) - CreateTreeReadFor(*pitem); - - if( pitem->type == Item::item_include ) - CreateTreeReadInclude(*pitem); - } -} - - - - -/* - * - * Pattern::Item - * - * - */ - - -Pattern::Item * Pattern::Item::AddItem(const Pattern::Item * porg) -{ -Item * pitem; - - if( porg ) - pitem = new Item(*porg); - else - pitem = new Item(); - - item_tab.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_tab.begin(); - - for( ; i != item_tab.end() ; ++i ) - delete *i; - - item_tab.clear(); -} - - - -void Pattern::Item::Clear() -{ - ClearItems(); - type = item_none; - text.clear(); - functions.clear(); -} - - -Pattern::Item::Type Pattern::Item::LastItemType() -{ - if( item_tab.empty() ) - return item_none; - -return item_tab.back()->type; -} - - -void Pattern::Item::DeleteLastItem() -{ - if( item_tab.empty() ) - return; - - delete item_tab.back(); - item_tab.pop_back(); -} - - -Pattern::Item::Item() -{ - type = item_none; -} - - -Pattern::Item::Item(const Pattern::Item & i) : type(i.type), text(i.text), functions(i.functions) -{ - CopyItemTable(i); -} - - -Pattern::Item & Pattern::Item::operator=(const Pattern::Item & i) -{ - type = i.type; - text = i.text; - functions = i.functions; - - CopyItemTable(i); - -return *this; -} - - -void Pattern::Item::CopyItemTable(const Pattern::Item & item) -{ - std::vector::const_iterator i = item.item_tab.begin(); - - for( ; i != item.item_tab.end() ; ++i) - AddItem( *i ); -} - - -Pattern::Item::~Item() -{ - ClearItems(); -} - - - - - -/* - * - * Info - * - * - */ - -void Info::Clear() -{ - res = false; // false by default - iter = 0; -} - - -Info::Info(std::ostringstream & o, std::vector & pars, const std::string & p) : out(o), params(pars), par(p) -{ - Clear(); -} - - - - - -/* - * - * Functions - * - * - */ - -Functions::Function::Function() -{ - type = Functions::variable; - user_function = 0; - iter = 0; - is_for = false; - is_running = false; -} - - -void Functions::Insert(const std::string & key, UserFunction ufunction) -{ - Function f; - f.type = function; - f.user_function = ufunction; - - functions_tab[key] = f; -} - - -void Functions::Insert(const std::string & key, const char * var) -{ - Function f; - f.type = variable; - f.variable = var; - - functions_tab[key] = f; -} - - -void Functions::Insert(const std::string & key, const std::string & var) -{ - Function f; - f.type = variable; - f.variable = var; - - functions_tab[key] = f; -} - - -bool Functions::Find(const std::string & key, Function ** fun) -{ - FunctionsTable::iterator i = functions_tab.find( key ); - - if( i == functions_tab.end() ) - return false; - - *fun = &(i->second); - -return true; -} - - -void Functions::Clear() -{ - functions_tab.clear(); -} - - - - - - -/* - * - * Generator - * - * - */ - - -Generator::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; -} - - -Generator::Generator(std::ostringstream & o, Pattern & p, Functions & 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; -} - - -void Generator::Set(std::ostringstream & o, Pattern & p, Functions & f) -{ - output_stream = &o; - pattern = &p; - functions = &f; -} - - -void Generator::Set(std::ostringstream & o) -{ - output_stream = &o; -} - - -void Generator::Set(Pattern & p) -{ - pattern = &p; -} - - -void Generator::Set(Functions & f) -{ - functions = &f; -} - - -void Generator::SetMax(int max_items_, int max_for_items_) -{ - max_items = max_items_; - max_for_items = max_for_items_; -} - - -void Generator::RecognizeSpecialChars(bool spec) -{ - special_chars = spec; -} - - -void Generator::TrimWhite(bool trim) -{ - trim_white = trim; -} - -void Generator::SkipNewLine(bool skip) -{ - skip_new_line = skip; -} - - -void Generator::Generate() -{ - if( !output_stream || !pattern || !functions ) - return; - - break_generating = false; - current_item = 0; - - MakeText( pattern->item_root ); -} - - - - - -bool Generator::Find(const std::string & key, Functions::Function ** function) -{ - if( !functions->Find(key, function) ) - { - pattern->CreateMsg(*output_stream, "can't find", key.c_str() ); - return false; - } - -return true; -} - - - -void Generator::CallUserFunction(Functions::Function * function, Info & info) -{ - if( function->is_running ) - { - // recurrences are not allowed - pattern->CreateMsg(*output_stream, "the function is being executed" ); - return; - } - - function->is_running = true; - (function->user_function)(info); - function->is_running = false; -} - - - -void Generator::CallVariable(Functions::Function * function, Info & info) -{ - info.res = !function->variable.empty(); -} - - - -void Generator::Call(Functions::Function * function, Info & info) -{ - info.Clear(); - info.iter = function->iter; - - if( function->type == Functions::function ) - CallUserFunction(function, info); - else - CallVariable(function, info); -} - - -// return: true if a function or variable was found and called -bool Generator::Call(const std::string & name, Info & info, Functions::Function ** pfun) -{ -Functions::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 -bool Generator::Call(Pattern::Item::Function & function, bool * info_res, Functions::Function ** pfun) -{ -bool called; - - if( function.params.empty() ) - { - Info info(*output_stream, function.params, empty); - called = Call(function.name, info, pfun); - - if( info_res ) - *info_res = info.res; - } - else - { - Info info(*output_stream, function.params, function.params[0]); - called = Call(function.name, info, pfun); - - if( info_res ) - *info_res = info.res; - } - -return called; -} - - -char Generator::CreateSpecialChar(char c) -{ -char 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; -} - - -void Generator::PrintSpecialText(const char * start, const char * end) -{ -char 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; - } - } -} - - -void Generator::PrintNormalText(const char * start, const char * end) -{ - if( skip_new_line ) - { - for( ; start != end ; ++start) - { - if( *start != 10 ) - *output_stream << *start; - } - } - else - { - if( start != end ) - output_stream->write(start, end-start); - } -} - - -void Generator::TrimWhite(const char *& start, const char *& end) -{ - while( start != end && pattern->IsWhite(*start) ) - ++start; - - while( start != end && pattern->IsWhite(*(end-1)) ) - --end; -} - - -void Generator::MakeItemText(Pattern::Item & item) -{ -const char * start = item.text.c_str(); -const char * end = item.text.c_str() + item.text.size(); - - if( trim_white ) - TrimWhite(start, end); - - if( special_chars ) - PrintSpecialText(start, end); - else - PrintNormalText(start, end); -} - - -void Generator::MakeTextContainer(Pattern::Item & item) -{ - std::vector::iterator i = item.item_tab.begin(); - - for( ; i != item.item_tab.end() && !break_generating ; ++i ) - MakeText(**i); -} - - - -void Generator::MakeTextNormal(Pattern::Item & item) -{ - if( item.functions.size() != 1 ) - return; - - Functions::Function * pfun; - bool called = Call(item.functions[0], 0, &pfun); - - if( called && pfun->type == Functions::variable ) - *output_stream << pfun->variable; -} - - - -void Generator::MakeTextIf_go(Pattern::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] ); - } -} - - - -void Generator::MakeTextIf(Pattern::Item & item) -{ -bool info_res; - - if( item.functions.size() != 1 ) - return; - - if( !Call(item.functions[0], &info_res) ) - return; - - MakeTextIf_go(item, info_res); -} - - -void Generator::MakeTextIfno(Pattern::Item & item) -{ -bool info_res; - - if( item.functions.size() != 1 ) - return; - - if( !Call(item.functions[0], &info_res) ) - return; - - MakeTextIf_go(item, !info_res); -} - - -void Generator::MakeTextIfany(Pattern::Item & item) -{ - std::vector::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()); -} - - -void Generator::MakeTextIfone(Pattern::Item & item) -{ - std::vector::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); -} - - -void Generator::MakeTextIfanyno(Pattern::Item & item) -{ - std::vector::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); -} - - -void Generator::MakeTextIfoneno(Pattern::Item & item) -{ - std::vector::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); -} - - - -void Generator::MakeTextIs(Pattern::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); -} - - -void Generator::MakeTextIsno(Pattern::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); -} - - -bool Generator::MakeTextIfindexnumber(Pattern::Item & item, Functions::Function * function, bool & result) -{ - if( item.functions.size() != 2 ) - return false; - - const char * number_text = item.functions[1].name.c_str(); - char * last_char; - - int number = (int)strtol(number_text, &last_char, 10); // !! dodac obsluge bialych znakow na koncu (na poczatku chyba jest od strtol) - - if( *last_char != '\0' ) - { - pattern->CreateMsg(*output_stream, "if-index: syntax error"); - return false; - } - - result = (function->iter == number); - -return true; -} - - -void Generator::MakeTextIfindex(Pattern::Item & item) -{ - if( item.functions.size() != 2 ) - return; - - // we actually don't call a function (or variable) here - // but only reading the iterator - - Functions::Function * function; - - if( !Find(item.functions[0].name, &function) ) - return; - - bool result = false; - - - if( item.functions[1].name == "odd" ) - { - result = (function->iter & 1) == 1; - } - else - if( item.functions[1].name == "even" ) - { - result = (function->iter & 1) == 0; - } - else - if( item.functions[1].name == "first" ) - { - result = function->iter == 0; - } - else - { - if( !MakeTextIfindexnumber(item, function, result) ) - return; - } - - MakeTextIf_go(item, result); -} - - - -void Generator::MakeTextForLoop(Pattern::Item & item, Functions::Function * function) -{ -bool info_res; - - for( ; !break_generating ; function->iter += 1 ) - { - if( function->iter >= max_for_items ) - { - pattern->CreateMsg(*output_stream, item.functions[0].name.c_str(), - "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 - } -} - - -void Generator::MakeTextFor(Pattern::Item & item) -{ - if( item.functions.size() != 1 ) - return; - - Functions::Function * function; - - if( !Find(item.functions[0].name, &function) ) - return; - - if( function->is_for ) - { - pattern->CreateMsg(*output_stream, item.functions[0].name.c_str(), - "this function is already used in a [for] statement"); - return; - } - - function->is_for = true; - function->iter = 0; - - MakeTextForLoop(item, function); - - function->is_for = false; - function->iter = 0; -} - - - -void Generator::MakeTextDefine(Pattern::Item & item) -{ - if( item.functions.size() == 1 ) - { - // inserting a new variable - if( item.functions[0].params.size() == 1 ) - functions->Insert(item.functions[0].name, item.functions[0].params[0]); - } - else - if( item.functions.size() == 2 ) - { - Functions::Function * function; - - if( Find(item.functions[1].name, &function) ) - { - if( function->type == Functions::function ) - { - // inserting a new function - functions->Insert(item.functions[0].name, function->user_function); - } - else - { - // inserting a new variable (the value is copied) - functions->Insert(item.functions[0].name, function->variable); - } - } - } -} - - - - -void Generator::MakeText(Pattern::Item & item) -{ - if( break_generating ) - return; - - if( ++current_item > max_items ) - { - break_generating = true; - pattern->CreateMsg(*output_stream, "Generator exceeded allowed number of elements"); - return; - } - - if ( item.type == Pattern::Item::item_text ) MakeItemText(item); - else if( item.type == Pattern::Item::item_container ) MakeTextContainer(item); - else if( item.type == Pattern::Item::item_normal ) MakeTextNormal(item); - else if( item.type == Pattern::Item::item_if ) MakeTextIf(item); - else if( item.type == Pattern::Item::item_ifno ) MakeTextIfno(item); - else if( item.type == Pattern::Item::item_ifany ) MakeTextIfany(item); - else if( item.type == Pattern::Item::item_ifone ) MakeTextIfone(item); - else if( item.type == Pattern::Item::item_ifanyno ) MakeTextIfanyno(item); - else if( item.type == Pattern::Item::item_ifoneno ) MakeTextIfoneno(item); - else if( item.type == Pattern::Item::item_ifindex ) MakeTextIfindex(item); - else if( item.type == Pattern::Item::item_is ) MakeTextIs(item); - else if( item.type == Pattern::Item::item_isno ) MakeTextIsno(item); - else if( item.type == Pattern::Item::item_for ) MakeTextFor(item); - else if( item.type == Pattern::Item::item_def ) MakeTextDefine(item); - else if( item.type == Pattern::Item::item_err ) - pattern->CreateMsg(*output_stream, "a wrong directive"); -} - - -} // namespace Ezc - diff --git a/src/ezc.h b/src/ezc.h index 578998e..dfb6772 100644 --- a/src/ezc.h +++ b/src/ezc.h @@ -36,334 +36,12 @@ */ -#ifndef headerfileezc -#define headerfileezc +#ifndef headerfile_ezc_ezc +#define headerfile_ezc_ezc -#include -#include -#include -#include -#include -#include -#include - -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 params; // function parameters - }; - - Type type; - std::string text; // used in: item_text, item_include (as a file name) - std::vector item_tab; // !! zamienic na 'items'? - std::vector 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 & 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 & 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 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 diff --git a/src/functions.h b/src/functions.h new file mode 100755 index 0000000..a5aca84 --- /dev/null +++ b/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 + */ + +/* + * 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 +#include "funinfo.h" + + + +namespace Ezc +{ + + + +// functions or variables +template +class Functions +{ +public: + + typedef void (*UserFunction)(FunInfo &); + 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 FunctionsTable; + FunctionsTable functions_tab; + std::wstring temp_key; +}; + + + + + + + +template +Functions::Function::Function() +{ + type = Functions::variable; + user_function = 0; + iter = 0; + is_for = false; + is_running = false; +} + + + + +template +void Functions::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 +void Functions::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 +void Functions::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 +void Functions::Insert(const std::string & key, UserFunction ufunction) +{ + Insert(key.c_str(), ufunction); +} + + +template +void Functions::Insert(const std::string & key, const char * var) +{ + Insert(key.c_str(), var); +} + + +template +void Functions::Insert(const std::string & key, const std::string & var) +{ + Insert(key.c_str(), var); +} + + + + + + +template +void Functions::Insert(const std::wstring & key, UserFunction ufunction) +{ + Function f; + f.type = function; + f.user_function = ufunction; + + functions_tab[key] = f; +} + + + +template +void Functions::Insert(const std::wstring & key, const wchar_t * var) +{ + Function f; + f.type = variable; + f.variable = var; + + functions_tab[key] = f; +} + + +template +void Functions::Insert(const std::wstring & key, const std::wstring & var) +{ + Function f; + f.type = variable; + f.variable = var; + + functions_tab[key] = f; +} + + + + + + +template +bool Functions::Find(const std::string & key, Function ** fun) +{ + AssignString(key, temp_key); + return Find(temp_key, fun); +} + + +template +bool Functions::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 +void Functions::Clear() +{ + functions_tab.clear(); +} + + + +} // namespace Ezc + + +#endif diff --git a/src/funinfo.h b/src/funinfo.h new file mode 100755 index 0000000..b917355 --- /dev/null +++ b/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 + */ + +/* + * 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 + + + +namespace Ezc +{ + + +template +struct FunInfo +{ + // output stream + StreamType & out; + + // table of parameters + std::vector & 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 & pars, const std::wstring & p) : out(o), params(pars), par(p) + { + Clear(); + } + + void Clear() + { + res = false; // false by default + iter = 0; + } +}; + + + + +} // namespace Ezc + + +#endif diff --git a/src/generator.h b/src/generator.h new file mode 100755 index 0000000..1d417f9 --- /dev/null +++ b/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 + */ + +/* + * 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 +#include + +namespace Ezc +{ + + +template +class Generator +{ +public: + + Generator(); + Generator(StreamType & o, Pattern & p, Functions & f); + + void Set(StreamType & o, Pattern & p, Functions & f); + void Set(StreamType & 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: + + StreamType * output_stream; + Pattern * pattern; + Functions * 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::Function ** function); + + void Call(typename Functions::Function * function, FunInfo & info); + bool Call(const std::wstring & name, FunInfo & info, typename Functions::Function ** pfun = 0); + bool Call(typename Item::Function & function, bool * info_res = 0, typename Functions::Function ** pfun = 0); + + void CallUserFunction(typename Functions::Function * function, FunInfo & info); + void CallVariable(typename Functions::Function * function, FunInfo & 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::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::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 +void Generator::PutChar(wchar_t z, StreamType & out) +{ +typedef typename StreamType::char_type CharType; + + out << static_cast(z); +} + +/* +template +void Generator::PutString(const wchar_t * start, const wchar_t * end, StreamType & out) +{ + out.write(start, end-start); +} + + +template +void Generator::PutString(const std::wstring & str, StreamType & out) +{ + PutString(str.c_str(), str.c_str() + str.size(), out); +} +*/ + + +template +void Generator::PutStringGeneric(const wchar_t * start, size_t len, StreamType & out) +{ +typedef typename StreamType::char_type CharType; + + for(size_t i=0 ; i(start[i]); +} + + + + +template +Generator::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 +Generator::Generator(StreamType & o, Pattern & p, Functions & 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 +void Generator::Set(StreamType & o, Pattern & p, Functions & f) +{ + output_stream = &o; + pattern = &p; + functions = &f; +} + + +template +void Generator::Set(StreamType & o) +{ + output_stream = &o; +} + + +template +void Generator::Set(Pattern & p) +{ + pattern = &p; +} + + +template +void Generator::Set(Functions & f) +{ + functions = &f; +} + + +template +void Generator::SetMax(int max_items_, int max_for_items_) +{ + max_items = max_items_; + max_for_items = max_for_items_; +} + + +template +void Generator::RecognizeSpecialChars(bool spec) +{ + special_chars = spec; +} + + +template +void Generator::TrimWhite(bool trim) +{ + trim_white = trim; +} + + +template +void Generator::SkipNewLine(bool skip) +{ + skip_new_line = skip; +} + + +template +void Generator::Generate() +{ + if( !output_stream || !pattern || !functions ) + return; + + break_generating = false; + current_item = 0; + + MakeText( pattern->item_root ); +} + + + + + +template +bool Generator::Find(const std::wstring & key, typename Functions::Function ** function) +{ + if( !functions->Find(key, function) ) + { + CreateMsg(*output_stream, L"can't find", key.c_str() ); + return false; + } + +return true; +} + + + +template +void Generator::CallUserFunction(typename Functions::Function * function, FunInfo & 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 +void Generator::CallVariable(typename Functions::Function * function, FunInfo & info) +{ + info.res = !function->variable.empty(); +} + + + +template +void Generator::Call(typename Functions::Function * function, FunInfo & info) +{ + info.Clear(); + info.iter = function->iter; + + if( function->type == Functions::function ) + CallUserFunction(function, info); + else + CallVariable(function, info); +} + + +// return: true if a function or variable was found and called +template +bool Generator::Call(const std::wstring & name, FunInfo & info, typename Functions::Function ** pfun) +{ +typename Functions::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 +bool Generator::Call(typename Item::Function & function, bool * info_res, typename Functions::Function ** pfun) +{ +bool called; + + if( function.params.empty() ) + { + FunInfo info(*output_stream, function.params, empty); + called = Call(function.name, info, pfun); + + if( info_res ) + *info_res = info.res; + } + else + { + FunInfo info(*output_stream, function.params, function.params[0]); + called = Call(function.name, info, pfun); + + if( info_res ) + *info_res = info.res; + } + +return called; +} + + +template +wchar_t Generator::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 +void Generator::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 +void Generator::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 +void Generator::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 +void Generator::SkipWhite(const wchar_t *& str) +{ + while( pattern->IsWhite(*str) ) + str += 1; +} + + + +template +int Generator::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 +void Generator::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 +void Generator::CreateMsg(StreamType & o, const std::wstring & type, const std::wstring & arg) +{ + CreateMsg(o, type.c_str(), arg.c_str()); +} + + + +template +void Generator::CreateMsg(StreamType & o, const std::wstring & type) +{ + CreateMsg(o, type.c_str()); +} + + + + + +template +void Generator::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 +void Generator::MakeTextContainer(Item & item) +{ + std::vector::iterator i = item.item_tab.begin(); + + for( ; i != item.item_tab.end() && !break_generating ; ++i ) + MakeText(**i); +} + + + +template +void Generator::MakeTextNormal(Item & item) +{ + if( item.functions.size() != 1 ) + return; + + typename Functions::Function * pfun; + bool called = Call(item.functions[0], 0, &pfun); + + if( called && pfun->type == Functions::variable ) + PutString(pfun->variable, *output_stream); +} + + + +template +void Generator::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 +void Generator::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 +void Generator::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 +void Generator::MakeTextIfany(Item & item) +{ + std::vector::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 +void Generator::MakeTextIfone(Item & item) +{ + std::vector::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 +void Generator::MakeTextIfanyno(Item & item) +{ + std::vector::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 +void Generator::MakeTextIfoneno(Item & item) +{ + std::vector::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 +void Generator::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 +void Generator::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 +bool Generator::MakeTextIfindexnumber(Item & item, typename Functions::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 +void Generator::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::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 +void Generator::MakeTextForLoop(Item & item, typename Functions::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 +void Generator::MakeTextFor(Item & item) +{ + if( item.functions.size() != 1 ) + return; + + typename Functions::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; + } + + function->is_for = true; + function->iter = 0; + + MakeTextForLoop(item, function); + + function->is_for = false; + function->iter = 0; +} + + + +template +void Generator::MakeTextDefine(Item & item) +{ + if( item.functions.size() == 1 ) + { + // inserting a new variable + if( item.functions[0].params.size() == 1 ) + functions->Insert(item.functions[0].name, item.functions[0].params[0]); + } + else + if( item.functions.size() == 2 ) + { + typename Functions::Function * function; + + if( Find(item.functions[1].name, &function) ) + { + if( function->type == Functions::function ) + { + // inserting a new function + functions->Insert(item.functions[0].name, function->user_function); + } + else + { + // inserting a new variable (the value is copied) + functions->Insert(item.functions[0].name, function->variable); + } + } + } +} + + + + +template +void Generator::MakeText(Item & item) +{ + if( break_generating ) + return; + + if( ++current_item > max_items ) + { + break_generating = true; + CreateMsg(*output_stream, L"Generator exceeded allowed number of elements"); + return; + } + + if ( item.type == Item::item_text ) MakeItemText(item); + else if( item.type == Item::item_container )MakeTextContainer(item); + else if( item.type == Item::item_normal ) MakeTextNormal(item); + else if( item.type == Item::item_if ) MakeTextIf(item); + else if( item.type == Item::item_ifno ) MakeTextIfno(item); + else if( item.type == Item::item_ifany ) MakeTextIfany(item); + else if( item.type == Item::item_ifone ) MakeTextIfone(item); + else if( item.type == Item::item_ifanyno ) MakeTextIfanyno(item); + else if( item.type == Item::item_ifoneno ) MakeTextIfoneno(item); + else if( item.type == Item::item_ifindex ) MakeTextIfindex(item); + else if( item.type == Item::item_is ) MakeTextIs(item); + else if( item.type == Item::item_isno ) MakeTextIsno(item); + else if( item.type == Item::item_for ) MakeTextFor(item); + else if( item.type == Item::item_def ) MakeTextDefine(item); + else if( item.type == Item::item_err ) + CreateMsg(*output_stream, L"a wrong directive"); +} + + + + +} // namespace Ezc + + +#endif diff --git a/src/item.cpp b/src/item.cpp new file mode 100755 index 0000000..63bdd02 --- /dev/null +++ b/src/item.cpp @@ -0,0 +1,163 @@ +/* + * 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-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. + */ + + +#include "item.h" + + + +namespace Ezc +{ + + + + + +Item * Item::AddItem(const Item * porg) +{ +Item * pitem; + + if( porg ) + pitem = new Item(*porg); + else + pitem = new Item(); + + item_tab.push_back(pitem); + +return pitem; +} + + + +Item * Item::AddItem(const Item & porg) +{ + return AddItem(&porg); +} + + + +void Item::ClearItems() +{ + std::vector::iterator i = item_tab.begin(); + + for( ; i != item_tab.end() ; ++i ) + delete *i; + + item_tab.clear(); +} + + + + +void Item::Clear() +{ + ClearItems(); + type = item_none; + text.clear(); + file_name.clear(); + functions.clear(); +} + + + +Item::Type Item::LastItemType() +{ + if( item_tab.empty() ) + return item_none; + +return item_tab.back()->type; +} + + + +void Item::DeleteLastItem() +{ + if( item_tab.empty() ) + return; + + delete item_tab.back(); + item_tab.pop_back(); +} + + + +Item::Item() +{ + type = item_none; +} + + + +Item::Item(const Item & i) : type(i.type), text(i.text), functions(i.functions) +{ + CopyItemTable(i); +} + + + +Item & Item::operator=(const Item & i) +{ + type = i.type; + text = i.text; + functions = i.functions; + + CopyItemTable(i); + +return *this; +} + + + +void Item::CopyItemTable(const Item & item) +{ + std::vector::const_iterator i = item.item_tab.begin(); + + for( ; i != item.item_tab.end() ; ++i) + AddItem(*i); +} + + + +Item::~Item() +{ + ClearItems(); +} + + + +} // namespace Ezc + diff --git a/src/item.h b/src/item.h new file mode 100755 index 0000000..1c531d5 --- /dev/null +++ b/src/item.h @@ -0,0 +1,91 @@ +/* + * 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-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_item +#define headerfile_ezc_item + +#include +#include + + +namespace Ezc +{ + + + +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::wstring name; // function name + std::vector params; // function parameters + }; + + Type type; + std::wstring text; // used in: item_text + std::wstring file_name; // used in: item_include (as a file name) + std::vector item_tab; // childs + std::vector 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(); +}; + + + +} // namespace Ezc + + +#endif diff --git a/src/pattern.cpp b/src/pattern.cpp new file mode 100755 index 0000000..9a8fda7 --- /dev/null +++ b/src/pattern.cpp @@ -0,0 +1,1033 @@ +/* + * 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-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. + */ + + +#include "pattern.h" + +#ifdef EZC_USE_WINIX_LOGGER +#include "core/log.h" +#endif + + +namespace Ezc +{ + + + +Pattern::Pattern() +{ + Clear(); + + commentary_start = L""; + + allow_include = true; + input_as_utf8 = false; + delete_white_text_items = false; + + include_level_max = 100; +} + + + +void Pattern::Clear() +{ + item_root.Clear(); +} + + + +void Pattern::Directory(const char * dir, const char * dir2) +{ + directory.clear(); + directory2.clear(); + + if( dir ) + AssignString(dir, directory); + + if( dir2 ) + AssignString(dir2, directory2); +} + + + +void Pattern::Directory(const std::string & dir) +{ + AssignString(dir, directory); + directory2.clear(); +} + + + +void Pattern::Directory(const std::string & dir, const std::string & dir2) +{ + AssignString(dir, directory); + AssignString(dir2, directory2); +} + + + +void Pattern::Directory(const wchar_t * dir, const wchar_t * dir2) +{ + directory.clear(); + directory2.clear(); + + if( dir ) + directory = dir; + + if( dir2 ) + directory2 = dir2; +} + + + +void Pattern::Directory(const std::wstring & dir) +{ + directory = dir; + directory2.clear(); +} + + + +void Pattern::Directory(const std::wstring & dir, const std::wstring & dir2) +{ + directory = dir; + directory2 = dir2; +} + + + +void Pattern::ParseFile(const std::string & file_name) +{ + ParseFile( file_name.c_str() ); +} + + + + +void Pattern::ParseFile(const char * file_name) +{ + AssignString(file_name, item_root.file_name); + include_level = 0; + CreateTreeReadIncludeSkipAllowFlag(item_root); +} + + + + +void Pattern::ParseFile(const std::wstring & file_name) +{ + ParseFile( file_name.c_str() ); +} + + + + +void Pattern::ParseFile(const wchar_t * file_name) +{ + item_root.file_name = file_name; + include_level = 0; + CreateTreeReadIncludeSkipAllowFlag(item_root); +} + + + + +void Pattern::ParseString(const char * str) +{ + AssignString(str, string_content); + ParseString(string_content.c_str()); + string_content.clear(); +} + + + +void Pattern::ParseString(const std::string & str) +{ + ParseString(str.c_str()); +} + + + + + + + + +void Pattern::ParseString(const wchar_t * str) +{ + itext = str; + include_level = 0; + CreateTree(item_root); +} + + + +void Pattern::ParseString(const std::wstring & str) +{ + ParseString(str.c_str()); +} + + + + + + + + + +void Pattern::AllowInclude(bool allow) +{ + allow_include = allow; +} + + + +void Pattern::DeleteWhiteTextItems(bool del) +{ + delete_white_text_items = del; +} + + + +void Pattern::SetIncludeMax(int include_max) +{ + include_level_max = include_max; +} + + + +void Pattern::UTF8(bool utf8) +{ + input_as_utf8 = utf8; +} + + + + + + +void Pattern::SetCommentary(const char * com_start, const char * com_stop) +{ + AssignString(com_start, commentary_start); + AssignString(com_stop, commentary_stop); +} + + + +void Pattern::SetCommentary(const std::string & com_start, const std::string & com_stop) +{ + AssignString(com_start, commentary_start); + AssignString(com_stop, commentary_stop); +} + + + +void Pattern::SetCommentary(const wchar_t * com_start, const wchar_t * com_stop) +{ + commentary_start = com_start; + commentary_stop = com_stop; +} + + + +void Pattern::SetCommentary(const std::wstring & com_start, const std::wstring & com_stop) +{ + commentary_start = com_start; + commentary_stop = com_stop; +} + + + + + + +void Pattern::CreateMsg(std::wstring & out, const char * type, const char * arg) +{ + out = commentary_start; + out += L"EZC: "; + AssignString(type, out, false); + + if( arg ) + { + out += ' '; + AssignString(arg, out, false); + } + + out += commentary_stop; +} + + +void Pattern::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg) +{ + out = commentary_start; + out += L"EZC: "; + out += type; + + if( arg ) + { + out += ' '; + out += arg; + } + + out += commentary_stop; +} + + + + + + + +bool Pattern::HasFileAtBeginning(const wchar_t * path, const wchar_t * file) +{ + for(; *path && *file; ++path, ++file) + { + if( *path != *file ) + return false; + } + + if( *file != 0 ) + return false; + + // "\" is from a dos path syntax + if( *path==0 || *path=='\\' || *path=='/' ) + return true; + +return false; +} + + +/* + ".." is not allowed in the file path + you cannot go up from your template directory +*/ +bool Pattern::IsFileCorrect(const wchar_t * name) +{ + while( *name ) + { + if( HasFileAtBeginning(name, L"..") ) + return false; + + // looking for the next slash of backslash + while( *name && *name!='\\' && *name!='/' ) + name += 1; + + // skipping the slash (or backslash) + if( *name ) + name += 1; + } + +return true; +} + + + + +/* + 'name' must be a relative path - without a slash or backslash +*/ +void Pattern::ReadFile(const std::wstring & name, std::wstring & result) +{ + ReadFile(name.c_str(), result); +} + + +/* + 'name' must be a relative path - without a slash or backslash +*/ +void Pattern::ReadFile(const wchar_t * name, std::wstring & result) +{ + if( !IsFileCorrect(name) ) + { + CreateMsg(result, L"incorrect file name:", name); + } + else + { + result.clear(); + + if( !ReadFileFromDir(directory, name, result) ) + if( !ReadFileFromDir(directory2, name, result) ) + CreateMsg(result, L"can't open: ", name); + } +} + + + + +bool Pattern::ReadFileFromDir(const std::wstring & dir, const wchar_t * name, std::wstring & result) +{ + if( dir.empty() ) + return false; + + file_name = dir; + file_name += '/'; + file_name += name; + + WideToUTF8(file_name, afile_name); + + std::ifstream file(afile_name.c_str()); + + if( !file ) + { + file_name.clear(); + afile_name.clear(); + return false; + } + + ReadFile(file, result); + + #ifdef EZC_USE_WINIX_LOGGER + log << log3 << "EZC: read pattern: " << afile_name << logend; + #endif + + file_name.clear(); + afile_name.clear(); + +return true; +} + + + + +void Pattern::ReadFile(std::ifstream & file, std::wstring & result) +{ + if( input_as_utf8 ) + { + UTF8ToWide(file, result); + } + else + { + ReadFileContent(file, result); + } +} + + + + +void Pattern::ReadFileContent(std::ifstream & file, std::wstring & result) +{ + while( true ) + { + int c = file.get(); + + if( !file ) + break; + + result += static_cast(c); + } +} + + + + +int Pattern::ReadCharInText() +{ + if( *itext==0 || *itext=='[' ) + return -1; + + if( *itext == '\\' ) + { + if( *(itext+1)=='\\' || *(itext+1)=='[' || *(itext+1)==']' ) + ++itext; + } + +return *(itext++); +} + + +bool Pattern::IsWhite(wchar_t c) +{ + // 13 (\r) is from a dos file at the end of a line (\r\n) + // 160 is a non-breaking space + + if( c==' ' || c=='\t' || c==13 || c==160 || c==10 ) + return true; + +return false; +} + + + +void Pattern::SkipWhite() +{ + while( IsWhite(*itext) ) + ++itext; +} + + + +void Pattern::CheckWhiteAndDelete(std::wstring & s) +{ +size_t i; + + if( s.empty() ) + return; + + for(i=0 ; i='a' && c<='z') || + (c>='A' && c<='Z') || + (c>='0' && c<='9') || + c=='_' || c=='-' || c=='.' || c=='#'); +} + + + +bool Pattern::IsDigit(wchar_t c) +{ + return (c>='0' && c<='9'); +} + + + +bool Pattern::IsPositiveNumber(const std::wstring & str) +{ +size_t i; + + for(i=0 ; i(c); + + if( delete_white_text_items ) + CheckWhiteAndDelete(item.text); + + item.type = Item::item_text; +} + + + +bool Pattern::CreateTreeReadItem(Item & item) +{ + item.Clear(); + + if( *itext == '[' ) + { + CreateTreeReadItemDirective(item); + return true; + } + else + if( *itext ) + { + CreateTreeReadItemText(item); + return true; + } + +// the end of the string +return false; +} + + + + + +void Pattern::CreateTreeReadInclude(Item & item) +{ + if( !allow_include ) + return; + + CreateTreeReadIncludeSkipAllowFlag(item); +} + + + + +void Pattern::CreateTreeReadIncludeSkipAllowFlag(Item & item) +{ + if( item.file_name.empty() ) + return; + + if( include_level > include_level_max ) + { + #ifdef EZC_USE_WINIX_LOGGER + log << log1 << "EZC: \"include\" directive has reached the maximum level" << logend; + #endif + + return; + } + + ++include_level; + std::wstring file_text; // this temporary object must not be global (includes can be nested) + ReadFile(item.file_name, file_text); + + const wchar_t * itext_old = itext; + itext = file_text.c_str(); + CreateTree(item); + itext = itext_old; + --include_level; +} + + + +void Pattern::CreateTreeReadIf(Item & item) +{ + Item * pitem = item.AddItem(); + CreateTree(*pitem); + + if( pitem->LastItemType() == Item::item_else ) + { + pitem->DeleteLastItem(); + + pitem = item.AddItem(); + CreateTree(*pitem); + } + + if( pitem->LastItemType() == Item::item_end ) + pitem->DeleteLastItem(); +} + + + +void Pattern::CreateTreeReadFor(Item & item) +{ + Item * pitem = item.AddItem(); + CreateTree(*pitem); + + if( pitem->LastItemType() == Item::item_end ) + pitem->DeleteLastItem(); +} + + + +void Pattern::CreateTree(Item & item) +{ + item.Clear(); + item.type = Item::item_container; + + while( true ) + { + Item * pitem = item.AddItem(); + + do + { + if( !CreateTreeReadItem(*pitem) ) + { + item.DeleteLastItem(); + return; + } + } + while( pitem->type == Item::item_comment ); + + if( pitem->type == Item::item_end || pitem->type == Item::item_else ) + return; + + if( pitem->type == Item::item_if || + pitem->type == Item::item_ifno || + pitem->type == Item::item_ifany || + pitem->type == Item::item_ifone || + pitem->type == Item::item_ifanyno || + pitem->type == Item::item_ifoneno || + pitem->type == Item::item_ifindex || + pitem->type == Item::item_is || + pitem->type == Item::item_isno ) + CreateTreeReadIf(*pitem); + + if( pitem->type == Item::item_for ) + CreateTreeReadFor(*pitem); + + if( pitem->type == Item::item_include ) + CreateTreeReadInclude(*pitem); + } +} + + + + + + +} // namespace Ezc + + + diff --git a/src/pattern.h b/src/pattern.h new file mode 100755 index 0000000..82e7c24 --- /dev/null +++ b/src/pattern.h @@ -0,0 +1,219 @@ +/* + * 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-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_pattern +#define headerfile_ezc_pattern + +#include +#include "item.h" +#include "stringconv.h" +#include "utf8.h" + + + +namespace Ezc +{ + + +class Pattern +{ +public: + + Pattern(); + + /*! + clearing only the tree + */ + void Clear(); + + + // 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 Directory(const wchar_t * dir, const wchar_t * dir2 = 0); + void Directory(const std::wstring & dir); + void Directory(const std::wstring & dir, const std::wstring & dir2); + + void ParseFile(const char * file_name); + void ParseFile(const std::string & file_name); + + void ParseFile(const wchar_t * file_name); + void ParseFile(const std::wstring & file_name); + + + void ParseString(const char * str); + void ParseString(const std::string & str); + void ParseString(const wchar_t * str); + void ParseString(const std::wstring & str); + + void AllowInclude(bool allow); + void DeleteWhiteTextItems(bool del); + void SetIncludeMax(int include_max); + + // files and strings (only char* and std::string) are treated + // as UTF-8 + void UTF8(bool utf8); + + void SetCommentary(const char * com_start, const char * com_stop); + void SetCommentary(const std::string & com_start, const std::string & com_stop); + void SetCommentary(const wchar_t * com_start, const wchar_t * com_stop); + void SetCommentary(const std::wstring & com_start, const std::wstring & com_stop); + + void CreateMsg(std::wstring & out, const char * type, const char * arg = 0); + void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0); + static bool IsWhite(wchar_t c); + + + + Item item_root; + + +private: + + // the main pointer to the parsed text + const wchar_t * 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::wstring directory, directory2; + + + bool input_as_utf8; + + int include_level, include_level_max; + + + + std::wstring commentary_start, commentary_stop; + + + // temporary content for ParseString(const char*) method + std::wstring string_content; + + // temporary object for a file name + std::wstring file_name; + + // temporary object for a file name + std::string afile_name; + + // temporary object for a EZC function's parameter + std::wstring temp_param; + + // temporary object for a EZC function + Item::Function temp_function; + + + + void ReadFile(const std::wstring & name, std::wstring & result); + void ReadFile(const wchar_t * name, std::wstring & result); + bool HasFileAtBeginning(const wchar_t * path, const wchar_t * file); + bool IsFileCorrect(const wchar_t * name); + bool ReadFileFromDir(const std::wstring & dir, const wchar_t * name, std::wstring & result); + void ReadFile(std::ifstream & file, std::wstring & result); + void ReadFileContent(std::ifstream & file, std::wstring & result); + + int ReadCharInText(); + void SkipWhite(); + void CheckWhiteAndDelete(std::wstring & s); + + bool IsNameChar(wchar_t c); + bool IsDigit(wchar_t c); + bool IsPositiveNumber(const std::wstring & str); + + bool ReadName(std::wstring & name); + bool ReadString(std::wstring & str); + bool ReadParams(Item::Function & function); + bool ReadFunction(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::wstring & 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 + + + + + + + + + +} // namespace Ezc + + +#endif diff --git a/src/stringconv.cpp b/src/stringconv.cpp new file mode 100755 index 0000000..04e6445 --- /dev/null +++ b/src/stringconv.cpp @@ -0,0 +1,102 @@ +/* + * 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-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. + */ + +#include "stringconv.h" + + + + +namespace Ezc +{ + +void AssignString(const char * src, std::wstring & dst, bool clear) +{ +size_t len; + + if( clear ) + dst.clear(); + + for(len=0 ; src[len] ; ++len){} + dst.reserve(len); + + for( ; *src ; ++src ) + dst += static_cast(*src); +} + + +void AssignString(const std::string & src, std::wstring & dst, bool clear) +{ + if( clear ) + dst.clear(); + + dst.reserve(src.size()); + + for(size_t i=0 ; i(src[i]); +} + + +void AssignString(const wchar_t * src, std::string & dst, bool clear) +{ +size_t len; + + if( clear ) + dst.clear(); + + for(len=0 ; src[len] ; ++len){} + dst.reserve(len); + + for( ; *src ; ++src ) + dst += static_cast(*src); +} + + +void AssignString(const std::wstring & src, std::string & dst, bool clear) +{ + if( clear ) + dst.clear(); + + dst.reserve(src.size()); + + for(size_t i=0 ; i(src[i]); +} + + + +} // namespace Ezc + diff --git a/src/stringconv.h b/src/stringconv.h new file mode 100755 index 0000000..99476e8 --- /dev/null +++ b/src/stringconv.h @@ -0,0 +1,60 @@ +/* + * 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-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_stringconv +#define headerfile_ezc_stringconv + +#include + + + +namespace Ezc +{ + + +void AssignString(const char * src, std::wstring & dst, bool clear = true); +void AssignString(const std::string & src, std::wstring & dst, bool clear = true); +void AssignString(const wchar_t * src, std::string & dst, bool clear = true); +void AssignString(const std::wstring & src, std::string & dst, bool clear = true); + + + +} // namespace Ezc + + +#endif diff --git a/src/utf8.cpp b/src/utf8.cpp new file mode 100755 index 0000000..0bc8bbb --- /dev/null +++ b/src/utf8.cpp @@ -0,0 +1,670 @@ +/* + * This file is a part of EZC -- Easy templating in C++ + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 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. + */ + +#include "utf8.h" + + +namespace Ezc +{ + + + +/*! + an auxiliary function for converting from UTF-8 string +*/ +static bool UTF8ToInt_FirstOctet(unsigned char uz, size_t & len, int & res) +{ + for(len=0 ; (uz & 0x80) != 0 ; ++len) + uz <<= 1; + + if( len == 1 ) + return false; + + res = uz; + + if( len > 0 ) + res >>= len; + + if( res == 0 ) + return false; + + if( len == 0 ) + len = 1; + +return true; +} + + + +/*! + an auxiliary function for converting from UTF-8 string +*/ +static bool UTF8ToInt_AddNextOctet(unsigned char uz, int & res) +{ + if( (uz & 0xc0) != 0x80 ) + return false; + + res <<= 6; + res |= (uz & 0x3F); + +return true; +} + + + + +/*! + returns true if 'c' is a correct unicode character +*/ +bool UTF8_CheckRange(int c) +{ + return c>=0 && c<=0x10FFFF && !(c>=0xD800 && c<=0xDFFF); +} + + + + +/*! + this function converts one UTF-8 character into one wide-character + + input: + utf8 - an input UTF-8 string + utf8_len - size of the input string, + the string should be at least 4 bytes length for correctly + recognized the utf-8 sequence + + output: + res - an output character + correct - true if it is a correct character + + the function returns how many characters have been used from the input string + (returns zero only if utf8_len is zero) + even if there are errors the functions returns a different from zero value +*/ +size_t UTF8ToInt(const char * utf8, size_t utf8_len, int & res, bool & correct) +{ +size_t i, len; + + res = 0; + correct = false; + + if( utf8_len == 0 ) + return 0; + + if( !UTF8ToInt_FirstOctet(utf8[0], len, res) ) + return 1; + + if( utf8_len < len ) + return utf8_len; + + for(i=1 ; i 0 ) + { + if( (unsigned char)*utf8 <= 0x7f ) + { + // small optimization + len = 1; + correct = true; + z = static_cast(*utf8); + } + else + { + len = UTF8ToInt(utf8, utf8_len, z, correct); // the len will be different from zero + } + + if( !correct || (sizeof(wchar_t)==2 && z>0xffff) ) + { + if( mode == 1 ) + res += 0xFFFD; // U+FFFD "replacement character" + + was_error = true; + } + else + { + res += static_cast(z); + } + + utf8 += len; + utf8_len -= len; + } + +return !was_error; +} + + + +/*! + this function converts an utf8 string into wide string (std::wstring) + + input: + utf8 - an input utf8 null terminated string + mode - what to do with errors when converting + 0: skip an invalid character + 1: put U+FFFD "replacement character" istead of the invalid character (default) + + output: + res - an output wide string + + the function returns false if there were some errors when converting +*/ +bool UTF8ToWide(const char * utf8, std::wstring & res, bool clear, int mode) +{ +size_t utf8_len = 0; + + while( utf8[utf8_len] != 0 ) + utf8_len += 1; + +return UTF8ToWide(utf8, utf8_len, res, clear, mode); +} + + + +/*! + this function converts an utf8 string into wide string (std::wstring) + + input: + utf8 - an input utf8 string + mode - what to do with errors when converting + 0: skip an invalid character + 1: put U+FFFD "replacement character" istead of the invalid character (default) + + output: + res - an output wide string + + the function returns false if there were some errors when converting +*/ +bool UTF8ToWide(const std::string & utf8, std::wstring & res, bool clear, int mode) +{ + return UTF8ToWide(utf8.c_str(), utf8.size(), res, clear, mode); +} + + + +/*! + this function converts an utf8 stream into wide string (std::wstring) + + input: + utf8 - an input utf8 stream + mode - what to do with errors when converting + 0: skip an invalid character + 1: put U+FFFD "replacement character" istead of the invalid character (default) + + output: + res - an output wide string + + the function returns false if there were some errors when converting +*/ +bool UTF8ToWide(std::istream & utf8, std::wstring & res, bool clear, int mode) +{ +int z; +bool correct, was_error = false; + + if( clear ) + res.clear(); + + while( UTF8ToInt(utf8, z, correct) > 0 ) + { + if( !correct || (sizeof(wchar_t)==2 && z>0xffff) ) + { + if( mode == 1 ) + res += 0xFFFD; // U+FFFD "replacement character" + + was_error = true; + } + else + { + res += z; + } + } + +return !was_error; +} + + + + +/*! + this function converts one wide character into UTF-8 sequence + + input: + z - wide character + + output: + utf8 - a buffer for the output sequence + utf8_len - the size of the buffer + + the function returns how many characters have been written to the utf8, + zero means the utf8 buffer is too small or 'z' is an incorrect unicode character +*/ +size_t IntToUTF8(int z, char * utf8, size_t utf8_max_len) +{ +char buf[10]; +int i = 0; +int mask = 0x3f; // 6 first bits set + + if( utf8_max_len==0 || !UTF8_CheckRange(z) ) + return 0; + + if( z <= 0x7f ) + { + utf8[0] = static_cast(z); + return 1; + } + + do + { + buf[i] = 0x80 | (z & 0x3f); + i += 1; + z >>= 6; + mask >>= 1; + } + while( (z & (~mask)) != 0 ); + + unsigned int first = -1; + first <<= (7 - i); + first |= (z & mask); + + if( size_t(i+1) > utf8_max_len ) + return 0; + + utf8[0] = static_cast(first); + + int a = 1; + for(--i; i>=0 ; --i, ++a) + utf8[a] = buf[i]; + +return a; +} + + + +/*! + this function converts one wide character into UTF-8 string + + input: + z - wide character + + output: + utf8 - a UTF-8 string for the output sequence (the string is not cleared) + + the function returns how many characters have been written to the utf8 string, + zero means that 'z' is an incorrect unicode character +*/ +size_t IntToUTF8(int z, std::string & utf8, bool clear) +{ +char buf[10]; + + if( clear ) + utf8.clear(); + + size_t len = IntToUTF8(z, buf, sizeof(buf)/sizeof(char)); + size_t i; + + for(i=0 ; i + */ + +/* + * Copyright (c) 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_utf8 +#define headerfile_ezc_utf8 + +#include +#include + + +namespace Ezc +{ + +/*! + UTF-8, a transformation format of ISO 10646 + http://tools.ietf.org/html/rfc3629 +*/ + + + +/*! + returns true if 'c' is a correct unicode character +*/ +bool UTF8_CheckRange(int c); + + + +/*! + converting one character from UTF-8 to an int +*/ +size_t UTF8ToInt(const char * utf8, size_t utf8_len, int & res, bool & correct); +size_t UTF8ToInt(const std::string & utf8, int & res, bool & correct); +size_t UTF8ToInt(std::istream & utf8, int & res, bool & correct); + + +/*! + converting UTF-8 string to a wide string + + warning: current limitation + on MS Windows wide characters consist of two bytes only + and we tread them as UCS-2 (not UTF-16 with surrogate pairs as it should be trated) + so unicode characters above 0xffff value are ignored (depending on 'mode' parameter) +*/ +bool UTF8ToWide(const char * utf8, size_t utf8_len, std::wstring & res, bool clear = true, int mode = 1); +bool UTF8ToWide(const char * utf8, std::wstring & res, bool clear = true, int mode = 1); +bool UTF8ToWide(const std::string & utf8, std::wstring & res, bool clear = true, int mode = 1); +bool UTF8ToWide(std::istream & utf8, std::wstring & res, bool clear = true, int mode = 1); + + +/*! + converting one int character to UTF-8 +*/ +size_t IntToUTF8(int z, char * utf8, size_t utf8_max_len); +size_t IntToUTF8(int z, std::string & utf8, bool clear = true ); +size_t IntToUTF8(int z, std::ostream & utf8); + + +/*! + converting a wide string to UTF-8 string + + warning: current limitation + on MS Windows wide characters consist of two bytes only + and we tread them as UCS-2 (not UTF-16 with surrogate pairs as it should be trated) + so unicode characters above 0xffff value are ignored (depending on 'mode' parameter) +*/ +bool WideToUTF8(const wchar_t * wide_string, size_t string_len, std::string & utf8, bool clear = true, int mode = 1); +bool WideToUTF8(const wchar_t * wide_string, std::string & utf8, bool clear = true, int mode = 1); +bool WideToUTF8(const std::wstring & wide_string, std::string & utf8, bool clear = true, int mode = 1); +bool WideToUTF8(const wchar_t * wide_string, size_t string_len, std::ostream & utf8, int mode = 1); +bool WideToUTF8(const wchar_t * wide_string, std::ostream & utf8, int mode = 1); +bool WideToUTF8(const std::wstring & wide_string, std::ostream & utf8, int mode = 1); + + + + +} // namespace Ezc + + +#endif +