花了一天时间,模仿 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
|