2 * Copyright 2001-2006 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * Simple template replacement engine.
24 #include "util/TemplateEngine.h"
28 using namespace xmltooling;
31 void TemplateEngine::setTagPrefix(const char* tagPrefix)
33 keytag = string("<") + tagPrefix + " ";
34 iftag = string("<") + tagPrefix + "if ";
35 ifnottag = string("<") + tagPrefix + "ifnot ";
36 ifendtag = string("</") + tagPrefix + "if>";
37 ifnotendtag = string("</") + tagPrefix + "ifnot>";
40 void TemplateEngine::html_encode(ostream& os, const char* start) const
42 while (start && *start) {
44 case '<': os << "<"; break;
45 case '>': os << ">"; break;
46 case '"': os << """; break;
47 case '#': os << "#"; break;
48 case '%': os << "%"; break;
49 case '&': os << "&"; break;
50 case '\'': os << "'"; break;
51 case '(': os << "("; break;
52 case ')': os << ")"; break;
53 case ':': os << ":"; break;
54 case '[': os << "["; break;
55 case '\\': os << "\"; break;
56 case ']': os << "]"; break;
57 case '`': os << "`"; break;
58 case '{': os << "{"; break;
59 case '}': os << "}"; break;
60 default: os << *start;
66 void TemplateEngine::trimspace(string& s) const
68 string::size_type end = s.size() - 1, start = 0;
70 // Trim stuff on right.
71 while (end > 0 && !isgraph(s[end])) end--;
73 // Trim stuff on left.
74 while (start < end && !isgraph(s[start])) start++;
77 s = s.substr(start, end - start + 1);
80 void TemplateEngine::process(
85 const map<string,string>& parameters,
86 const XMLToolingException* e
90 time_t now = time(NULL);
95 const char* nowbuf = ctime(&now);
98 const char* line = buf.c_str();
101 while ((thispos = strchr(lastpos, '<')) != NULL) {
102 // Output the string up to this token.
104 os << buf.substr(lastpos-line, thispos-lastpos);
106 // Make sure this token matches our tokens.
107 #ifdef HAVE_STRCASECMP
108 if (visible && !strncasecmp(thispos, keytag.c_str(), keytag.length()))
110 if (visible && !_strnicmp(thispos, keytag.c_str(), keytag.length()))
113 // Save this position off.
114 lastpos = thispos + keytag.length();
116 // search for the end-tag
117 if ((thispos = strstr(lastpos, "/>")) != NULL) {
118 string key = buf.substr(lastpos-line, thispos-lastpos);
121 map<string,string>::const_iterator i=parameters.find(key);
122 if (i != parameters.end()) {
123 html_encode(os,i->second.c_str());
126 const char* ep = e->getProperty(key.c_str());
130 lastpos = thispos + 2; // strlen("/>")
133 #ifdef HAVE_STRCASECMP
134 else if (!strncasecmp(thispos, iftag.c_str(), iftag.length()))
136 else if (!_strnicmp(thispos, iftag.c_str(), iftag.length()))
139 // Save this position off.
140 lastpos = thispos + iftag.length();
142 // search for the end of this tag
143 if ((thispos = strchr(lastpos, '>')) != NULL) {
144 string key = buf.substr(lastpos-line, thispos-lastpos);
146 map<string,string>::const_iterator i=parameters.find(key);
149 if (i != parameters.end())
151 else if (e && e->getProperty(key.c_str()))
154 lastpos = thispos + 1; // strlen(">")
155 process(cond, buf, lastpos, os, parameters, e);
158 #ifdef HAVE_STRCASECMP
159 else if (!strncasecmp(thispos, ifendtag.c_str(), ifendtag.length()))
161 else if (!_strnicmp(thispos, ifendtag.c_str(), ifendtag.length()))
164 // Save this position off and pop the stack.
165 lastpos = thispos + ifendtag.length();
168 #ifdef HAVE_STRCASECMP
169 else if (!strncasecmp(thispos, ifnottag.c_str(), ifnottag.length()))
171 else if (!_strnicmp(thispos, ifnottag.c_str(), ifnottag.length()))
174 // Save this position off.
175 lastpos = thispos + ifnottag.length();
177 // search for the end of this tag
178 if ((thispos = strchr(lastpos, '>')) != NULL) {
179 string key = buf.substr(lastpos-line, thispos-lastpos);
181 map<string,string>::const_iterator i=parameters.find(key);
184 if (i != parameters.end())
186 else if (e && e->getProperty(key.c_str()))
189 lastpos = thispos + 1; // strlen(">")
190 process(cond, buf, lastpos, os, parameters, e);
193 #ifdef HAVE_STRCASECMP
194 else if (!strncasecmp(thispos, ifnotendtag.c_str(), ifnotendtag.length()))
196 else if (!_strnicmp(thispos, ifnotendtag.c_str(), ifnotendtag.length()))
199 // Save this position off and pop the stack.
200 lastpos = thispos + ifnotendtag.length();
207 lastpos = thispos + 1;
211 os << buf.substr(lastpos-line);
214 void TemplateEngine::run(istream& is, ostream& os, const map<string,string>& parameters, const XMLToolingException* e) const
217 while (getline(is, line))
220 const char* pos=buf.c_str();
221 process(true, buf, pos, os, parameters, e);