blob: 4d12cb753536a399c21119483fbee1f373011441 [file] [log] [blame]
Brian Silverman70325d62015-09-20 17:00:43 -04001// Copyright (c) 2006, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31//
32// This file implements the Template class. For information about
33// how to use this class, and to write the templates it takes as input,
34// see the doc/ directory.
35
36#ifndef CTEMPLATE_TEMPLATE_H_
37#define CTEMPLATE_TEMPLATE_H_
38
39#include <time.h> // for time_t
40#include <string>
41#include <ctemplate/template_cache.h>
42#include <ctemplate/template_enums.h>
43#include <ctemplate/template_string.h>
44
45// We include this just so folks don't have to include both template.h
46// and template_dictionary.h, or template_namelist.h etc, to use the
47// template system; we don't actually use anything in these files
48// ourselves.
49#if 1
50#include <ctemplate/template_dictionary.h>
51#include <ctemplate/template_namelist.h>
52#include <ctemplate/per_expand_data.h>
53#else
54namespace ctemplate {
55class TemplateDictionaryInterface;
56class PerExpandData;
57}
58#endif
59
60namespace google_ctemplate_streamhtmlparser {
61class HtmlParser;
62}
63
64// NOTE: if you are statically linking the template library into your binary
65// (rather than using the template .dll), set '/D CTEMPLATE_DLL_DECL='
66// as a compiler flag in your project file to turn off the dllimports.
67#ifndef CTEMPLATE_DLL_DECL
68# define CTEMPLATE_DLL_DECL __declspec(dllimport)
69#endif
70
71namespace ctemplate {
72
73// These free functions form the "simple" template API, and support
74// the most common operations (expanding a template from a file, and
75// from a string). They all just delegate to a default instance of
76// the TemplateCache object.
77//
78// For more sophisticated use of the template system, you may need
79// to create your own TemplateCache object, and work directly with
80// it. See template_cache.h for details.
81
82extern CTEMPLATE_DLL_DECL const TemplateCache* default_template_cache();
83extern CTEMPLATE_DLL_DECL TemplateCache* mutable_default_template_cache();
84
85
86// ---- EXPANDING A TEMPLATE -------
87// ExpandTemplate
88// ExpandWithData
89
90// Loads the template named filename from disk if necessary -- it
91// gets it from the cache instead, if the template had been loaded
92// before or if it had been put explicitly in the cache via a call
93// to StringToTemplateCache() -- and expands it using the given
94// dictionary.
95// The first version is the most general, followed by common-case code.
96inline bool ExpandTemplate(const TemplateString& filename, Strip strip,
97 const TemplateDictionaryInterface *dictionary,
98 ExpandEmitter* output) {
99 return mutable_default_template_cache()->ExpandWithData(
100 filename, strip, dictionary, NULL, output);
101}
102inline bool ExpandTemplate(const TemplateString& filename, Strip strip,
103 const TemplateDictionaryInterface* dictionary,
104 std::string* output_buffer) {
105 return mutable_default_template_cache()->ExpandWithData(
106 filename, strip, dictionary, NULL, output_buffer);
107}
108
109// If you want any per-expand data to be used at expand time, call
110// this routine instead of Expand. You pass in an extra
111// PerExpandData structure (see per_expand_data.h) which sets this
112// data: whether or not you want the template to be annotated, and
113// any data you want to pass in to template modifers. If
114// per_expand_data is NULL, this is exactly the same as Expand().
115// The first version is the most general, followed by common-case code.
116inline bool ExpandWithData(const TemplateString& filename, Strip strip,
117 const TemplateDictionaryInterface *dictionary,
118 PerExpandData* per_expand_data,
119 ExpandEmitter* output) {
120 return mutable_default_template_cache()->ExpandWithData(
121 filename, strip, dictionary, per_expand_data, output);
122}
123inline bool ExpandWithData(const TemplateString& filename, Strip strip,
124 const TemplateDictionaryInterface* dictionary,
125 PerExpandData* per_expand_data,
126 std::string* output_buffer) {
127 return mutable_default_template_cache()->ExpandWithData(
128 filename, strip, dictionary, per_expand_data, output_buffer);
129}
130
131// ---- INSERTING INTO THE CACHE -------
132// LoadTemplate
133// StringToTemplateCache
134
135// Reads a file from disk and inserts it into the template, if it's
136// not already there. Returns true on success or false if the
137// template could not be found, or could not be parsed. It's never
138// necessary to call this -- Expand() will load templates lazily if
139// needed -- but you may want to if you want to make sure templates
140// exist before trying to expand them, or because you want to
141// control disk access patterns, or for some other reason.
142inline bool LoadTemplate(const TemplateString& filename, Strip strip) {
143 return mutable_default_template_cache()->LoadTemplate(filename, strip);
144}
145
146// Inserts the given string into the default template cache, as if
147// it were a file read from disk. You can call Expand() with its
148// first arg (filename) the same as the key you use here. You can
149// also use this key as the 'filename' for sub-included templates,
150// in TemplateDictionary::SetFilename().
151inline bool StringToTemplateCache(const TemplateString& key,
152 const TemplateString& content,
153 Strip strip) {
154 return mutable_default_template_cache()->StringToTemplateCache(
155 key, content, strip);
156}
157inline bool StringToTemplateCache(const TemplateString& key,
158 const char* content, size_t content_len,
159 Strip strip) {
160 return mutable_default_template_cache()->StringToTemplateCache(
161 key, content, content_len, strip);
162}
163
164
165// ---------------------------------------------------------------------
166// The follow are deprecated.
167// TODO(csilvers): move to parsed_template.h
168
169// TemplateState of a template is:
170// - TS_EMPTY before parsing is complete,
171// - TS_ERROR if a syntax error was found during parsing, and
172// - TS_READY if parsing has completed successfully
173// (TS_UNUSED is not used)
174enum TemplateState { TS_UNUSED, TS_EMPTY, TS_ERROR, TS_READY };
175
176// Used for Auto-Escape. It represents the different contexts a template may
177// be initialized in via the AUTOESCAPE pragma in the template file
178// (or string). It is only public for testing. The contexts are:
179// - TC_HTML: The template contains HTML code. Need not be a complete HTML
180// page just content the browser interprets in the context of
181// HTML parsing. This should be the most common context to use.
182// This mode activates our HTML parser.
183// - TC_JS: The template contains raw javascript. If your template
184// starts with <script> tag, it is of type TC_HTML not TC_JS.
185// TC_JS is typically associated with a content-type of
186// text/javascript. This mode activates our HTML parser.
187// - TC_CSS: The template contains CSS (cascaded style-sheet). If your
188// template starts with a <style> tag, it is of type TC_HTML
189// not TC_CSS. A TC_CSS template is typically associated with a
190// text/css content-type header. Currently treated same as
191// TC_HTML but don't rely on that. We may later develop
192// CSS-specific sanitizers and parsers.
193// - TC_JSON: The template contains raw JSON. Applies javascript_escape
194// to variables. Note: javascript_escape is safer than
195// json_escape which we may want to remove.
196// - TC_XML: The template contains raw XML. Applies xml_escape to variables.
197// CAUTION: This mode is not suitable for cases where the
198// application data encapsulated in XML requires special
199// escaping, such as the case of XHTML.
200// TC_XML is typically associated with text/xml content-type.
201// - TC_MANUAL: Equivalent to not specifying auto-escaping at all.
202//
203// TODO(csilvers): Make this a private part of the Template class.
204enum TemplateContext { TC_UNUSED, TC_HTML, TC_JS, TC_CSS, TC_JSON,
205 TC_XML, TC_MANUAL };
206
207
208// This class is deprecated. Old code uses this class heavily (via
209// GetTemplate() to obtain a Template*, and then methods on that
210// Template*) but new code should use the free functions above.
211class CTEMPLATE_DLL_DECL Template {
212 public:
213 // ---- METHODS FOR TOOLS ----
214 // These are not intended for normal use, but are public so a
215 // tool can use them.
216
217 // Used by make_tpl_varnames_h.cc.
218 void WriteHeaderEntries(std::string *outstring) const;
219
220 // ---- DEPRECATED METHODS ----
221 // These methods used to be the primary way of using the Template
222 // object, but have been deprecated in favor of the (static)
223 // methods above. If you are using these deprecated methods,
224 // consider moving to the above methods instead, or to moving to
225 // using your own TemplateCache (which supports richer operations
226 // on parsed templates).
227
228 // Loads a template from disk or cache or string, and returns the Template*.
229 // INSTEAD, use the static Expand that takes a filename.
230 static Template *GetTemplate(const TemplateString& filename, Strip strip);
231 virtual ~Template(); // when the time comes to delete these Template*'s.
232
233 // Parses a string immediately and returns the resulting Template*.
234 // You can call the (deprecated) non-static Expand() method on this
235 // template in order to expand it with a dictionary. You are
236 // responsible for deleting the Template* when you are done with it.
237 // INSTEAD, use StringToTemplateCache (with a key) plus the static Expand().
238 // TOOO(csilvers): return a const Template* instead.
239 static Template* StringToTemplate(const TemplateString& content,
240 Strip strip);
241 static Template* StringToTemplate(const char* content, size_t content_len,
242 Strip strip) {
243 return StringToTemplate(TemplateString(content, content_len), strip);
244 }
245
246 // Non-static Expand*() works on a Template* returned from GetTemplate().
247 // INSTEAD, use static expand with a filename (or key-name for strings).
248 bool ExpandWithData(ExpandEmitter* output,
249 const TemplateDictionaryInterface* dictionary,
250 PerExpandData* per_expand_data) const {
251 return ExpandWithDataAndCache(output, dictionary, per_expand_data,
252 default_template_cache());
253 }
254 bool ExpandWithData(std::string* output_buffer,
255 const TemplateDictionaryInterface* dictionary,
256 PerExpandData* per_expand_data) const {
257 if (output_buffer == NULL) return false;
258 StringEmitter e(output_buffer);
259 return ExpandWithData(&e, dictionary, per_expand_data);
260 }
261 bool Expand(ExpandEmitter* output,
262 const TemplateDictionaryInterface* dictionary) const {
263 return ExpandWithData(output, dictionary, NULL);
264 }
265 bool Expand(std::string* output_buffer,
266 const TemplateDictionaryInterface* dictionary) const {
267 return ExpandWithData(output_buffer, dictionary, NULL);
268 }
269
270 // Dump to stdout or a string. filename is just used to annotate output.
271 void Dump(const char *filename) const;
272 void DumpToString(const char *filename, std::string *out) const;
273
274 // Retrieves the state, template-file, or strip mode of this Template.
275 TemplateState state() const;
276 const char *template_file() const;
277 const char *original_filename() const;
278 Strip strip() const;
279
280 // Work at the level of groups of templates, so just call through to
281 // the default TemplateCache; see template_cache.h for what these do.
282 // INSTEAD, create your own TemplateCache and call these methods on that.
283 static bool SetTemplateRootDirectory(const std::string& dir) {
284 return mutable_default_template_cache()->SetTemplateRootDirectory(dir);
285 }
286 static bool AddAlternateTemplateRootDirectory(const std::string& dir) {
287 return mutable_default_template_cache()->AddAlternateTemplateRootDirectory(
288 dir);
289 }
290 static std::string template_root_directory() {
291 return default_template_cache()->template_root_directory();
292 }
293 static std::string FindTemplateFilename(
294 const std::string& unresolved) {
295 return default_template_cache()->FindTemplateFilename(unresolved);
296 }
297 static void RemoveStringFromTemplateCache(const std::string& key) {
298 mutable_default_template_cache()->Delete(key);
299 }
300 static void ClearCache() {
301 mutable_default_template_cache()->ClearCache();
302 }
303 static void ReloadAllIfChanged() {
304 mutable_default_template_cache()->ReloadAllIfChanged(
305 TemplateCache::LAZY_RELOAD);
306 }
307
308 // ---- EXTRA-DEPRECATED METHODS ----
309 // These methods were deprecated even before the move to
310 // TemplateCache. We'd really like you to move from these to one
311 // of the "approved" methods, or even one of the deprecated
312 // methods. Comments here don't even describe what these
313 // functions do, just how to transition off of using them.
314
315 // INSTEAD, use the StringToTemplateCache function that takes the strip mode.
316 static bool StringToTemplateCache(const TemplateString& key,
317 const TemplateString& content);
318 static bool StringToTemplateCache(const TemplateString& key,
319 const char* content, size_t content_len) {
320 return StringToTemplateCache(key, TemplateString(content, content_len));
321 }
322 // This is to prevent against typos: you want the global (free-function)
323 // StringToTemplateCache here, not the one in Template.
324 static bool StringToTemplateCache(const TemplateString& key,
325 const char* content, Strip);
326
327 // INSTEAD, use ReloadAllIfChanged.
328 bool ReloadIfChanged();
329
330 protected:
331 friend class SectionTemplateNode; // for access to set_state(), ParseState
332 friend class TemplateTemplateNode; // for recursive call to Expand()
333
334 // Template constructor
335 // Reads the template file and parses it into a parse tree of TemplateNodes
336 // by calling the method ReloadIfChanged
337 // The top node is a section node with the arbitrary name "__{{MAIN}}__"
338 // 'Strip' indicates how to handle whitespace when expanding the
339 // template. DO_NOT_STRIP keeps the template exactly as-is.
340 // STRIP_BLANK_LINES elides all blank lines in the template.
341 // STRIP_WHITESPACE elides all blank lines, and also all whitespace
342 // at either the beginning or end of a line. It also removes
343 // any linefeed (possibly following whitespace) that follows a closing
344 // '}}' of any kind of template marker EXCEPT a template variable.
345 // This means a linefeed may be removed anywhere by simply placing
346 // a comment marker as the last element on the line.
347 // These two options allow the template to include whitespace for
348 // readability without adding to the expanded output.
349 Template(const TemplateString& filename, Strip strip, TemplateCache* owner);
350
351 // MaybeInitHtmlParser
352 // In TemplateContexts where the HTML parser is needed, we
353 // initialize it in the appropriate mode. Also we do a sanity
354 // check (cannot fail) on the template filename. This function is
355 // called at most once for a Template. In_tag is only meaningful
356 // for TC_HTML: It is true for templates that start inside an HTML
357 // tag and hence are expected to contain HTML attribute name/value
358 // pairs only. It is false for standard HTML templates.
359 void MaybeInitHtmlParser(bool in_tag);
360
361 // BuildTree
362 // Parses the contents of the file (retrieved via ReloadIfChanged)
363 // and stores the resulting parse structure in tree_. Returns true
364 // iff the tree-builder encountered no errors. Note: takes
365 // ownership of input_buffer, and will delete it. It should have
366 // been created via new[].
367 bool BuildTree(const char *input_buffer, const char* input_buffer_end);
368
369 // Internal version of ReloadIfChanged, used when the function already
370 // has a write-lock on g_template_mutex.
371 bool ReloadIfChangedLocked();
372
373 // set_state
374 // Sets the state of the template. Used during BuildTree().
375 void set_state(TemplateState new_state);
376
377 // StripBuffer
378 // Modifies buffer in-place based on the strip_ mode, to remove
379 // extra whitespace. May delete[] the input buffer and replace
380 // it with a new buffer. Used by ReloadIfChanged().
381 void StripBuffer(char **buffer, size_t* len);
382
383 // The file we originally got from the Template() constructor
384 const std::string original_filename_;
385 // The pathname as fully resolved on the filesystem
386 std::string resolved_filename_;
387 time_t filename_mtime_; // lastmod time for filename last time we loaded it
388
389 // What to do with whitespace at template-expand time
390 Strip strip_;
391
392 // Keeps track of where we are in reloading, or if there was an error loading
393 TemplateState state_;
394
395 // The cache we got this template from. This is not well-defined: a
396 // Template can be in more than one cache.
397 // TODO(csilvers): remove this once we deprecate the one user, which
398 // is ReloadIfChanged.
399 TemplateCache* template_cache_;
400
401 // The current template-contents, as read from the file
402 const char* template_text_;
403 int template_text_len_;
404
405 // The current parsed template structure. Has pointers into template_text_.
406 class SectionTemplateNode *tree_; // defined in template.cc
407
408 // Template markers have the form {{VARIABLE}}, etc. These constants
409 // define the {{ and }} that delimit template markers.
410 struct CTEMPLATE_DLL_DECL MarkerDelimiters {
411 const char* start_marker;
412 size_t start_marker_len;
413 const char* end_marker;
414 size_t end_marker_len;
415
416 MarkerDelimiters() {
417 start_marker = "{{"; // The default start-marker
418 start_marker_len = strlen(start_marker);
419 end_marker = "}}";
420 end_marker_len = strlen(end_marker);
421 }
422 };
423
424 // The current parsing state. Used in BuildTree() and subroutines
425 struct CTEMPLATE_DLL_DECL ParseState {
426 const char* bufstart;
427 const char* bufend;
428 enum { PS_UNUSED, GETTING_TEXT, GETTING_NAME } phase;
429 MarkerDelimiters current_delimiters;
430 ParseState()
431 : bufstart(NULL), bufend(NULL), phase(PS_UNUSED), current_delimiters()
432 {}
433 };
434 ParseState parse_state_;
435
436 // All templates are initialized to TC_MANUAL (no Auto-Escape). Then,
437 // during template parsing (BuildTree()), if an AUTOESCAPE pragma is
438 // encountered, the context changes appropriately.
439 TemplateContext initial_context_;
440 // Non-null if the template was initialized in an Auto-Escape mode that
441 // requires a parser (currently TC_HTML, TC_CSS and TC_JS).
442 google_ctemplate_streamhtmlparser::HtmlParser *htmlparser_;
443
444 // A sorted list of trusted variable names, declared here because a unittest
445 // needs to verify that it is appropriately sorted (an unsorted array would
446 // lead to the binary search of this array failing).
447 static const char * const kSafeWhitelistedVariables[];
448 static const size_t kNumSafeWhitelistedVariables;
449
450 private:
451 friend class TemplateCache;
452 friend class TemplateCachePeer; // to access num_deletes_
453
454 // Internal implementation of Expand
455 bool ExpandWithDataAndCache(ExpandEmitter* output,
456 const TemplateDictionaryInterface *dictionary,
457 PerExpandData* per_expand_data,
458 const TemplateCache* cache) const;
459
460 // This is called for recursive expands, when we already hold template_lock.
461 bool ExpandLocked(ExpandEmitter* output,
462 const TemplateDictionaryInterface *dictionary,
463 PerExpandData* per_expand_data,
464 const TemplateCache* cache) const;
465
466 // Returns the lastmod time in mtime_
467 // For string-based templates, not backed by a file, this returns 0
468 time_t mtime() const;
469
470 // These are helper routines to StripFile. I would make them static
471 // inside template.cc, but they use the MarerDelimiters struct.
472 static bool ParseDelimiters(const char* text, size_t textlen,
473 MarkerDelimiters* delim);
474 static bool IsBlankOrOnlyHasOneRemovableMarker(const char** line, size_t* len,
475 const MarkerDelimiters& delim);
476 static size_t InsertLine(const char *line, size_t len, Strip strip,
477 const MarkerDelimiters& delim, char* buffer);
478
479 // This is only used by template_cache_test, via TemplateCachePeer.
480 static int num_deletes() { return num_deletes_; }
481
482 static int num_deletes_; // how many times the destructor has been called
483
484 // Can't invoke copy constructor or assignment operator
485 Template(const Template&);
486 void operator=(const Template &);
487};
488
489}
490
491
492#endif // CTEMPLATE_TEMPLATE_H_