花了一天时间,模仿 php btemplate做了一个 c++版本,还不是很完善,请大家试用
不过在制作的过程中,发现效率有些问题,可能会导致用户感不足,在下一个版本中会做一些调整吧
/* Copyright (C) 2005 Hunter(whywhathow at hotmail.com)
The LRU Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
*/
/*!
* \file mytemplate.h
* \brief 模板引擎
* \author HunterLiu
* \date 2005-7-10
*/
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include "boost/shared_ptr.hpp"
#include <string>
#include <map>
//#include <execinfo.h>
#include <cassert>
#include <cstdlib>
#include <cstdio>
class CTemplateException : public std::exception
{
public:
const char *what() {return m_sErrMsg;};
CTemplateException(const char *psErrMsg, const char *sFunc = 0, int iLineNumber = -1)
{
assert(psErrMsg);
m_sErrMsg[0] = 0;
if (sFunc && iLineNumber > -1)
{
//a.out: test_assert.cpp:5: void test(): Assertion `0 > 1' failed.
snprintf(m_sErrMsg, sizeof(m_sErrMsg), "line %3d: %s: %s", iLineNumber, sFunc, psErrMsg);
}
else
{
snprintf(m_sErrMsg, sizeof(m_sErrMsg), "%s", psErrMsg);
}
};
virtual ~CTemplateException() throw () {};
protected:
char m_sErrMsg[512];
};
class CDuplicateException: public CTemplateException
{
public:
CDuplicateException(const char *psErrMsg, const char *sFunc, int iLineNumber):CTemplateException(psErrMsg, sFunc, iLineNumber)
{};
};
class CFileException: public CTemplateException
{
public:
CFileException(const char *psErrMsg, const char *sFunc, int iLineNumber):CTemplateException(psErrMsg, sFunc, iLineNumber)
{};
};
class CTemplateArray
{
public:
CTemplateArray();
void addElement(const std::string &strName, const std::string &strValue);
u_int32_t getElementCount();
const std::map<std::string, std::string> &getElementArray();
private:
std::map<std::string, std::string> m_cElementArray;
};
class CTemplate
{
public:
CTemplate();
//! gobal variable
void setVar(const std::string &strName, const std::string &strValue);
//! loop variable
void setLoopVar(const std::string &strLoopName, const std::string &strValue);
//! 由CTemplate托管该内存块
void setLoopVar(const std::string &strLoopName, boost::shared_ptr<CTemplateArray> &cArray);
void loadTemplateFile(const std::string &strFileName, bool bOutputDirect, bool bStore);
void loadTemplateStr(const std::string &strTemplate, bool bOutputDirect, bool bStore);
std::string getOutput();
private:
bool isDuplicate(const std::string &strName);
void loadIncludeFile(std::string &sTemplateContent, std::string::size_type iIncBegin,
std::string::size_type iIncEnd);
void replaceVariable(std::string &sContent, const std::string &sToken, const std::string &sValue,
std::string::size_type iBeginPos, std::string::size_type iEndPos);
std::map<std::string, std::string> m_cGobalVariable;
std::map<std::string, std::string> m_cLoopVariable;
std::map<std::string, boost::shared_ptr<CTemplateArray> > m_cLoopArray;
std::string m_sTemplateContent;
char m_sFilePath[255];
char m_sFileName[255];
};
#endif
/* Copyright (C) 2005 Hunter(whywhathow at hotmail.com)
The LRU Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
*/
#include "mytemplate.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
using namespace std;
using namespace boost;
CTemplateArray::CTemplateArray():m_cElementArray()
{
}
void CTemplateArray::addElement(const std::string &strName, const std::string &strValue)
{
//map<std::string, std::string>::iterator end =
if (m_cElementArray.find(strName) != m_cElementArray.end())
throw CDuplicateException("duplicate element ", __func__, __LINE__);
m_cElementArray[strName] = strValue;
}
u_int32_t CTemplateArray::getElementCount()
{
return m_cElementArray.size();
}
const std::map<std::string, std::string> &CTemplateArray::getElementArray()
{
return m_cElementArray;
}
CTemplate::CTemplate():m_cGobalVariable(), m_cLoopVariable(), m_cLoopArray(),m_sTemplateContent()
{
}
bool CTemplate::isDuplicate(const std::string &strName)
{
if (m_cGobalVariable.find(strName) != m_cGobalVariable.end())
return true;
if (m_cLoopVariable.find(strName) != m_cLoopVariable.end())
return true;
if (m_cLoopArray.find(strName) != m_cLoopArray.end())
return true;
return false;
}
void CTemplate::setVar(const std::string &strName, const std::string &strValue)
{
if (isDuplicate(strName))
throw CDuplicateException("duplicate element ", __func__, __LINE__);
m_cGobalVariable[strName] = strValue;
}
//! loop variable
void CTemplate::setLoopVar(const std::string &strLoopName, const std::string &strValue)
{
if (isDuplicate(strLoopName))
throw CDuplicateException("duplicate element ", __func__, __LINE__);
m_cLoopVariable[strLoopName] = strValue;
}
//! 由CTemplate托管该内存块
void CTemplate::setLoopVar(const std::string &strLoopName, shared_ptr<CTemplateArray> &cArray)
{
if (isDuplicate(strLoopName))
throw CDuplicateException("duplicate element ", __func__, __LINE__);
m_cLoopArray[strLoopName] = cArray;
}
class CFileManager
{
ifstream &m_ifs;
public:
CFileManager(ifstream &ifs):m_ifs(ifs)
{};
~CFileManager()
{ m_ifs.close(); };
};
int GetFileSize(const std::string &strFileName)
{
struct stat stFileStat;
if (stat(strFileName.c_str(),&stFileStat)==0)
return stFileStat.st_size;
return -1;
}
void OpenFile(const std::string &strFileName, string &sFileContent)
{
int iFileSize = GetFileSize(strFileName);
//cout << strFileName << endl;
if (iFileSize < 0)
throw CFileException("file not found", __func__, __LINE__);
if (iFileSize > 102400 - 512)
throw CFileException("template too large", __func__, __LINE__);
ifstream cFile(strFileName.c_str(), ios::in);
if (cFile.fail())
throw CFileException("file not found2", __func__, __LINE__);
CFileManager cFileManager(cFile);
char sTempBuffer[iFileSize+10];
cFile.read(sTempBuffer, iFileSize);
if (cFile.fail())
throw CFileException("read fail", __func__, __LINE__);
sFileContent.assign(sTempBuffer, iFileSize);
}
void CTemplate::loadTemplateFile(const std::string &strFileName, bool bOutputDirect, bool bStore)
{
if (strFileName.length() > 250)
throw CTemplateException("file path too long ", __func__, __LINE__);
if (strFileName[0] != '/')
throw CTemplateException("file path must lead by '/'", __func__, __LINE__);
#ifndef __CYGWIN__
snprintf(m_sFilePath, sizeof(m_sFilePath), "%s", strFileName.c_str());
snprintf(m_sFileName, sizeof(m_sFileName), "%s", strFileName.c_str());
dirname(m_sFilePath);
basename(m_sFileName);
#else
char sTmpFile[255];
snprintf(sTmpFile, sizeof(sTmpFile), "%s", strFileName.c_str());
// have memory leak? I don't know if there is memory malloc in the new dirname()
snprintf(m_sFilePath, sizeof(m_sFilePath), "%s", dirname(sTmpFile));
snprintf(m_sFileName, sizeof(m_sFileName), "%s", basename(sTmpFile));
#endif
OpenFile(strFileName, m_sTemplateContent);
if (strFileName.find(".shtml") != string::npos)
{
string::size_type iFirstIncBegin, iFirstIncEnd;
iFirstIncBegin = m_sTemplateContent.find("<!--#include");
if(iFirstIncBegin == string::npos) return;
iFirstIncEnd = m_sTemplateContent.find("-->",iFirstIncBegin);
if(iFirstIncEnd == string::npos) return;
loadIncludeFile(m_sTemplateContent, iFirstIncBegin, iFirstIncEnd+3);
}
}
void CTemplate::replaceVariable(string &sContent, const string &sToken, const string &sValue,
string::size_type iBeginPos, string::size_type iEndPos)
{
string::size_type iCurrPos;
while((iCurrPos = sContent.find(sToken, iBeginPos))!= string::npos)
{
if (iEndPos != string::npos && iCurrPos >= iEndPos)
return;
sContent.replace(iCurrPos, sToken.length(), sValue);
iBeginPos = iCurrPos + sValue.length();
}
}
string CTemplate::getOutput()
{
if (m_cGobalVariable.size() == 0 && m_cLoopVariable.size() == 0 && m_cLoopArray.size() == 0)
return m_sTemplateContent;
std::map<std::string, std::string>::iterator iter;
for (iter = m_cGobalVariable.begin(); iter != m_cGobalVariable.end(); ++iter)
{
string sToken("<% ");
sToken += iter->first;
sToken += " %>";
replaceVariable(m_sTemplateContent, sToken, iter->second, 0, string::npos);
}
std::map<std::string, boost::shared_ptr<CTemplateArray> >::iterator iter2;
for (iter2 = m_cLoopArray.begin(); iter2 != m_cLoopArray.end(); ++iter2)
{
string sTokenBegin("<% BLOCK ");
sTokenBegin += iter2->first;
sTokenBegin += " BEGIN %>";
string sTokenEnd("<% BLOCK ");
sTokenEnd += iter2->first;
sTokenEnd += " END %>";
string::size_type iBeginPos = 0, iCurrPos, iEndPos;
while((iCurrPos = m_sTemplateContent.find(sTokenBegin, iBeginPos))!= string::npos)
{
iEndPos = m_sTemplateContent.find(sTokenEnd, iCurrPos);
if (iEndPos == string::npos)
break;
iEndPos += sTokenEnd.length();
string sTmpContent = m_sTemplateContent.substr(iCurrPos, iEndPos);
std::map<std::string, std::string>::const_iterator iter3 = iter2->second->getElementArray().begin();
for (; iter3 != iter2->second->getElementArray().end(); ++iter3)
{
string sToken("<% ");
sToken += iter3->first;
sToken += " %>";
replaceVariable(sTmpContent, sToken, iter3->second, 0, string::npos);
}
m_sTemplateContent.replace(iCurrPos, iEndPos - iCurrPos, sTmpContent);
iBeginPos = iEndPos;
}
}
return m_sTemplateContent;
}
void CTemplate::loadIncludeFile(string &m_sTemplateContent, string::size_type iIncBegin,
string::size_type iIncEnd)
{
std::string::size_type iBegin, iEnd;
do
{
iBegin = m_sTemplateContent.find("\"", iIncBegin);
if (iBegin == std::string::npos || iBegin > iIncEnd)
throw CTemplateException("include syntax error", __func__, __LINE__);
iEnd = m_sTemplateContent.find("\"",iBegin + 1);
if(iEnd == std::string::npos || iEnd > iIncEnd)
throw CTemplateException("include syntax error2", __func__, __LINE__);
std::string sFilePath = m_sTemplateContent.substr(iBegin + 1, iEnd - iBegin - 1);
if (sFilePath.find("..") != std::string::npos)
throw CTemplateException("include path must not use '..' ", __func__, __LINE__);
std::string sTempPath = string(m_sFilePath) + "/" + sFilePath;
string strTmpFileContent;
OpenFile(sTempPath, strTmpFileContent);
//cout << m_sTemplateContent.length() << endl;
//cout << strTmpFileContent.length() << endl;
m_sTemplateContent.replace(iIncBegin, iIncEnd - iIncBegin, strTmpFileContent);
//cout << m_sTemplateContent.length() << endl;
iIncBegin = m_sTemplateContent.find("<!--#include", iIncEnd);
if (iIncBegin == string::npos) return;
iIncEnd = m_sTemplateContent.find("-->", iIncBegin);
if (iIncEnd == string::npos) return;
iIncEnd += 3;
}
while(true);
}
void CTemplate::loadTemplateStr(const std::string &strTemplate, bool bOutputDirect, bool bStore)
{
}
#ifdef TEST
int main()
{
try
{
shared_ptr<CTemplateArray> array(new CTemplateArray);
array->addElement("hehe", "123456");
array->addElement("hehe1", "1234567");
array->addElement("hehe2", "1234568");
shared_ptr<CTemplateArray> array(new CTemplateArray);
array->addElement("hehe", "123456");
array->addElement("hehe1", "1234567");
array->addElement("hehe2", "1234568");
CTemplate mytemplate;
mytemplate.setLoopVar("xixi", array);
mytemplate.setVar("kk", "123456");
mytemplate.loadTemplateFile("/usr/local/html_template/xxx.shtml", false, false);
cout << mytemplate.getOutput() << endl;
}
catch(CDuplicateException &err)
{
cout << err.what() << endl;
}
catch(CTemplateException &err)
{
cout << err.what() << endl;
}
cerr << "done" << endl;
return 0;
}
#endif