blob: c1f3869e6b79e674f15a95c532558af170c56ee2 [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// Author: csilvers@google.com (Craig Silverstein)
32//
33// Based on the 'old' TemplateDictionary by Frank Jernigan.
34//
35// A template dictionary maps names (as found in template files)
36// to their values. There are three types of names:
37// variables: value is a string.
38// sections: value is a list of sub-dicts to use when expanding the section;
39// the section is expanded once per sub-dict.
40// template-include: value is a list of pairs: name of the template file
41// to include, and the sub-dict to use when expanding it.
42// TemplateDictionary has routines for setting these values.
43//
44// For (many) more details, see the doc/ directory.
45
46#ifndef TEMPLATE_TEMPLATE_DICTIONARY_H_
47#define TEMPLATE_TEMPLATE_DICTIONARY_H_
48
49#include <stdarg.h> // for StringAppendV()
50#include <stddef.h> // for size_t and ptrdiff_t
51#include <stdlib.h> // for NULL
52#include <sys/types.h>
53#include <functional> // for less<>
54#include <map>
55#include <string>
56#include <vector>
57
58#include <ctemplate/str_ref.h>
59#include <ctemplate/template_dictionary_interface.h>
60#include <ctemplate/template_modifiers.h>
61#include <ctemplate/template_string.h>
62
63// NOTE: if you are statically linking the template library into your binary
64// (rather than using the template .dll), set '/D CTEMPLATE_DLL_DECL='
65// as a compiler flag in your project file to turn off the dllimports.
66#ifndef CTEMPLATE_DLL_DECL
67# define CTEMPLATE_DLL_DECL __declspec(dllimport)
68#endif
69
70namespace ctemplate {
71template <class T, class C> class ArenaAllocator;
72class UnsafeArena;
73template<typename A, int B, typename C, typename D> class small_map;
74template<typename NormalMap> class small_map_default_init; // in small_map.h
75}
76
77namespace ctemplate {
78
79
80class CTEMPLATE_DLL_DECL TemplateDictionary : public TemplateDictionaryInterface {
81 public:
82 // name is used only for debugging.
83 // arena is used to store all names and values. It can be NULL (the
84 // default), in which case we create own own arena.
85 explicit TemplateDictionary(const TemplateString& name,
86 UnsafeArena* arena=NULL);
87 ~TemplateDictionary();
88
89 // If you want to be explicit, you can use NO_ARENA as a synonym to NULL.
90 static UnsafeArena* const NO_ARENA;
91
92 std::string name() const {
93 return std::string(name_.data(), name_.size());
94 }
95
96 // Returns a recursive copy of this dictionary. This dictionary
97 // *must* be a "top-level" dictionary (that is, not created via
98 // AddSectionDictionary() or AddIncludeDictionary()). Caller owns
99 // the resulting dict, and must delete it. If arena is NULL, we
100 // create our own. Returns NULL if the copy fails (probably because
101 // the "top-level" rule was violated).
102 TemplateDictionary* MakeCopy(const TemplateString& name_of_copy,
103 UnsafeArena* arena=NULL);
104
105 // --- Routines for VARIABLES
106 // These are the five main routines used to set the value of a variable.
107 // As always, wherever you see TemplateString, you can also pass in
108 // either a char* or a C++ string, or a TemplateString(s, slen).
109
110 void SetValue(const TemplateString variable, const TemplateString value);
111 void SetIntValue(const TemplateString variable, long value);
112 void SetFormattedValue(const TemplateString variable, const char* format, ...)
113#if 0
114 __attribute__((__format__ (__printf__, 3, 4)))
115#endif
116 ; // starts at 3 because of implicit 1st arg 'this'
117
118 class SetProxy {
119 public:
120 SetProxy(TemplateDictionary& dict, const TemplateString& variable) :
121 dict_(dict),
122 variable_(variable) {
123 }
124
125 void operator=(str_ref value) {
126 dict_.SetValue(variable_, TemplateString(value.data(), value.size()));
127 }
128
129 void operator=(long value) {
130 dict_.SetIntValue(variable_, value);
131 }
132
133 private:
134 TemplateDictionary& dict_;
135 const TemplateString& variable_;
136 };
137
138 SetProxy operator[](const TemplateString& variable) {
139 return SetProxy(*this, variable);
140 }
141
142 // We also let you set values in the 'global' dictionary which is
143 // referenced when all other dictionaries fail. Note this is a
144 // static method: no TemplateDictionary instance needed. Since
145 // this routine is rarely used, we don't provide variants.
146 static void SetGlobalValue(const TemplateString variable,
147 const TemplateString value);
148
149 // This is used for a value that you want to be 'global', but only
150 // in the scope of a given template, including all its sections and
151 // all its sub-included dictionaries. The main difference between
152 // SetTemplateGlobalValue() and SetValue(), is that
153 // SetTemplateGlobalValue() values persist across template-includes.
154 // This is intended for session-global data; since that should be
155 // fairly rare, we don't provide variants.
156 void SetTemplateGlobalValue(const TemplateString variable,
157 const TemplateString value);
158
159 // Similar SetTemplateGlobalValue above, this method shows a section in this
160 // template, all its sections, and all its template-includes. This is intended
161 // for session-global data, for example allowing you to show variant portions
162 // of your template for certain browsers/languages without having to call
163 // ShowSection on each template you use.
164 void ShowTemplateGlobalSection(const TemplateString variable);
165
166 // These routines are like SetValue and SetTemplateGlobalValue, but
167 // they do not make a copy of the input data. THE CALLER IS
168 // RESPONSIBLE FOR ENSURING THE PASSED-IN STRINGS LIVE FOR AT LEAST
169 // AS LONG AS THIS DICTIONARY! In general, they yield a quite minor
170 // performance increase for significant increased code fragility,
171 // so do not use them unless you really need the speed improvements.
172 void SetValueWithoutCopy(const TemplateString variable,
173 const TemplateString value);
174 void SetTemplateGlobalValueWithoutCopy(const TemplateString variable,
175 const TemplateString value);
176
177
178 // --- Routines for SECTIONS
179 // We show a section once per dictionary that is added with its name.
180 // Recall that lookups are hierarchical: if a section tried to look
181 // up a variable in its sub-dictionary and fails, it will look next
182 // in its parent dictionary (us). So it's perfectly appropriate to
183 // keep the sub-dictionary empty: that will show the section once,
184 // and take all var definitions from us. ShowSection() is a
185 // convenience routine that does exactly that.
186
187 // Creates an empty dictionary whose parent is us, and returns it.
188 // As always, wherever you see TemplateString, you can also pass in
189 // either a char* or a C++ string, or a TemplateString(s, slen).
190 TemplateDictionary* AddSectionDictionary(const TemplateString section_name);
191 void ShowSection(const TemplateString section_name);
192
193 // A convenience method. Often a single variable is surrounded by
194 // some HTML that should not be printed if the variable has no
195 // value. The way to do this is to put that html in a section.
196 // This method makes it so the section is shown exactly once, with a
197 // dictionary that maps the variable to the proper value. If the
198 // value is "", on the other hand, this method does nothing, so the
199 // section remains hidden.
200 void SetValueAndShowSection(const TemplateString variable,
201 const TemplateString value,
202 const TemplateString section_name);
203
204
205 // --- Routines for TEMPLATE-INCLUDES
206 // Included templates are treated like sections, but they require
207 // the name of the include-file to go along with each dictionary.
208
209 TemplateDictionary* AddIncludeDictionary(const TemplateString variable);
210
211 // This is required for include-templates; it specifies what template
212 // to include. But feel free to call this on any dictionary, to
213 // document what template-file the dictionary is intended to go with.
214 void SetFilename(const TemplateString filename);
215
216 // --- DEBUGGING TOOLS
217
218 // Logs the contents of a dictionary and its sub-dictionaries.
219 // Dump goes to stdout/stderr, while DumpToString goes to the given string.
220 // 'indent' is how much to indent each line of the output.
221 void Dump(int indent=0) const;
222 virtual void DumpToString(std::string* out, int indent=0) const;
223
224
225 // --- DEPRECATED ESCAPING FUNCTIONALITY
226
227 // Escaping in the binary has been deprecated in favor of using modifiers
228 // to do the escaping in the template:
229 // "...{{MYVAR:html_escape}}..."
230 void SetEscapedValue(const TemplateString variable, const TemplateString value,
231 const TemplateModifier& escfn);
232 void SetEscapedFormattedValue(const TemplateString variable,
233 const TemplateModifier& escfn,
234 const char* format, ...)
235#if 0
236 __attribute__((__format__ (__printf__, 4, 5)))
237#endif
238 ; // starts at 4 because of implicit 1st arg 'this'
239 void SetEscapedValueAndShowSection(const TemplateString variable,
240 const TemplateString value,
241 const TemplateModifier& escfn,
242 const TemplateString section_name);
243
244
245 private:
246 friend class SectionTemplateNode; // for access to GetSectionValue(), etc.
247 friend class TemplateTemplateNode; // for access to GetSectionValue(), etc.
248 friend class VariableTemplateNode; // for access to GetSectionValue(), etc.
249 // For unittesting code using a TemplateDictionary.
250 friend class TemplateDictionaryPeer;
251
252 class DictionaryPrinter; // nested class
253 friend class DictionaryPrinter;
254
255 // We need this functor to tell small_map how to create a map<> when
256 // it decides to do so: we want it to create that map on the arena.
257 class map_arena_init;
258
259 typedef std::vector<TemplateDictionary*,
260 ArenaAllocator<TemplateDictionary*, UnsafeArena> >
261 DictVector;
262 // The '4' here is the size where small_map switches from vector<> to map<>.
263 typedef small_map<std::map<TemplateId, TemplateString, std::less<TemplateId>,
264 ArenaAllocator<std::pair<const TemplateId, TemplateString>,
265 UnsafeArena> >,
266 4, std::equal_to<TemplateId>, map_arena_init>
267 VariableDict;
268 typedef small_map<std::map<TemplateId, DictVector*, std::less<TemplateId>,
269 ArenaAllocator<std::pair<const TemplateId, DictVector*>,
270 UnsafeArena> >,
271 4, std::equal_to<TemplateId>, map_arena_init>
272 SectionDict;
273 typedef small_map<std::map<TemplateId, DictVector*, std::less<TemplateId>,
274 ArenaAllocator<std::pair<const TemplateId, DictVector*>,
275 UnsafeArena> >,
276 4, std::equal_to<TemplateId>, map_arena_init>
277 IncludeDict;
278 // This is used only for global_dict_, which is just like a VariableDict
279 // but does not bother with an arena (since this memory lives forever).
280 typedef small_map<std::map<TemplateId, TemplateString, std::less<TemplateId> >,
281 4, std::equal_to<TemplateId>,
282 small_map_default_init<
283 std::map<TemplateId, TemplateString,
284 std::less<TemplateId> > > >
285 GlobalDict;
286
287
288 // These are helper functions to allocate the parts of the dictionary
289 // on the arena.
290 template<typename T> inline void LazilyCreateDict(T** dict);
291 inline void LazyCreateTemplateGlobalDict();
292 inline DictVector* CreateDictVector();
293 inline TemplateDictionary* CreateTemplateSubdict(
294 const TemplateString& name,
295 UnsafeArena* arena,
296 TemplateDictionary* parent_dict,
297 TemplateDictionary* template_global_dict_owner);
298
299 // This is a helper function to insert <key,value> into m.
300 // Normally, we'd just use m[key] = value, but map rules
301 // require default constructor to be public for that to compile, and
302 // for some types we'd rather not allow that. HashInsert also inserts
303 // the key into an id(key)->key map, to allow for id-lookups later.
304 template<typename MapType, typename ValueType>
305 static void HashInsert(MapType* m, TemplateString key, ValueType value);
306
307 // Constructor created for all children dictionaries. This includes
308 // both a pointer to the parent dictionary and also the the
309 // template-global dictionary from which all children (both
310 // IncludeDictionary and SectionDictionary) inherit. Values are
311 // filled into global_template_dict via SetTemplateGlobalValue.
312 explicit TemplateDictionary(const TemplateString& name,
313 class UnsafeArena* arena,
314 TemplateDictionary* parent_dict,
315 TemplateDictionary* template_global_dict_owner);
316
317 // Helps set up the static stuff. Must be called exactly once before
318 // accessing global_dict_. GoogleOnceInit() is used to manage that
319 // initialization in a thread-safe way.
320 static void SetupGlobalDict();
321
322 // Utility functions for copying a string into the arena.
323 // Memdup also copies in a trailing NUL, which is why we have the
324 // trailing-NUL check in the TemplateString version of Memdup.
325 TemplateString Memdup(const char* s, size_t slen);
326 TemplateString Memdup(const TemplateString& s) {
327 if (s.is_immutable() && s.data()[s.size()] == '\0') {
328 return s;
329 }
330 return Memdup(s.data(), s.size());
331 }
332
333 // Used for recursive MakeCopy calls.
334 TemplateDictionary* InternalMakeCopy(
335 const TemplateString& name_of_copy,
336 UnsafeArena* arena,
337 TemplateDictionary* parent_dict,
338 TemplateDictionary* template_global_dict_owner);
339
340 // A helper for creating section and include dicts.
341 static std::string CreateSubdictName(
342 const TemplateString& dict_name, const TemplateString& sub_name,
343 size_t index, const char* suffix);
344
345 // Must be called whenever we add a value to one of the dictionaries above,
346 // to ensure that we can reconstruct the id -> string mapping.
347 static void AddToIdToNameMap(TemplateId id, const TemplateString& str);
348
349 // Used to do the formatting for the SetFormatted*() functions
350 static int StringAppendV(char* space, char** out,
351 const char* format, va_list ap);
352
353 // How Template::Expand() and its children access the template-dictionary.
354 // These fill the API required by TemplateDictionaryInterface.
355 virtual TemplateString GetValue(const TemplateString& variable) const;
356 virtual bool IsHiddenSection(const TemplateString& name) const;
357 virtual bool IsUnhiddenSection(const TemplateString& name) const {
358 return !IsHiddenSection(name);
359 }
360 virtual bool IsHiddenTemplate(const TemplateString& name) const;
361 virtual const char* GetIncludeTemplateName(
362 const TemplateString& variable, int dictnum) const;
363
364 // Determine whether there's anything set in this dictionary
365 bool Empty() const;
366
367 // This is needed by DictionaryPrinter because it's not a friend
368 // of TemplateString, but we are
369 static std::string PrintableTemplateString(
370 const TemplateString& ts) {
371 return std::string(ts.data(), ts.size());
372 }
373 static bool InvalidTemplateString(const TemplateString& ts) {
374 return ts.data() == NULL;
375 }
376 // Compilers differ about whether nested classes inherit our friendship.
377 // The only thing DictionaryPrinter needs is IdToString, so just re-export.
378 static TemplateString IdToString(TemplateId id) { // for DictionaryPrinter
379 return TemplateString::IdToString(id);
380 }
381
382 // CreateTemplateIterator
383 // This is SectionIterator exactly, just with a different name to
384 // self-document the fact the value applies to a template include.
385 // Caller frees return value.
386 virtual TemplateDictionaryInterface::Iterator* CreateTemplateIterator(
387 const TemplateString& section_name) const;
388
389 // CreateSectionIterator
390 // Factory method implementation that constructs a iterator representing the
391 // set of dictionaries associated with a section name, if any. This
392 // implementation checks the local dictionary itself, not the template-wide
393 // dictionary or the global dictionary.
394 // Caller frees return value.
395 virtual TemplateDictionaryInterface::Iterator* CreateSectionIterator(
396 const TemplateString& section_name) const;
397
398 // TemplateDictionary-specific implementation of dictionary iterators.
399 template <typename T> // T is *TemplateDictionary::const_iterator
400 class Iterator : public TemplateDictionaryInterface::Iterator {
401 protected:
402 friend class TemplateDictionary;
403 Iterator(T begin, T end) : begin_(begin), end_(end) { }
404 public:
405 virtual ~Iterator() { }
406 virtual bool HasNext() const;
407 virtual const TemplateDictionaryInterface& Next();
408 private:
409 T begin_;
410 const T end_;
411 };
412
413 // A small helper factory function for Iterator
414 template <typename T>
415 static Iterator<typename T::const_iterator>* MakeIterator(const T& dv) {
416 return new Iterator<typename T::const_iterator>(dv.begin(), dv.end());
417 }
418
419
420 // The "name" of the dictionary for debugging output (Dump, etc.)
421 // The arena, also set at construction time.
422 class UnsafeArena* const arena_;
423 bool should_delete_arena_; // only true if we 'new arena' in constructor
424 TemplateString name_; // points into the arena, or to static memory
425
426 // The three dictionaries that I own -- for vars, sections, and template-incs
427 VariableDict* variable_dict_;
428 SectionDict* section_dict_;
429 IncludeDict* include_dict_;
430
431
432 // The template_global_dict is consulted if a lookup in the variable, section,
433 // or include dicts named above fails. It forms a convenient place to store
434 // session-specific data that's applicable to all templates in the dictionary
435 // tree.
436 // For the parent-template, template_global_dict_ is not NULL, and
437 // template_global_dict_owner_ is this. For all of its children,
438 // template_global_dict_ is NULL, and template_global_dict_owner_ points to
439 // the root parent-template (the one with the non-NULL template_global_dict_).
440 TemplateDictionary* template_global_dict_;
441 TemplateDictionary* template_global_dict_owner_;
442
443 // My parent dictionary, used when variable lookups at this level fail.
444 // Note this is only for *variables* and *sections*, not templates.
445 TemplateDictionary* parent_dict_;
446 // The static, global dictionary, at the top of the parent-dictionary chain
447 static GlobalDict* global_dict_;
448 static TemplateString* empty_string_; // what is returned on lookup misses
449
450 // The filename associated with this dictionary. If set, this declares
451 // what template the dictionary is supposed to be expanded with. Required
452 // for template-includes, optional (but useful) for 'normal' dicts.
453 const char* filename_;
454
455 private:
456 // Can't invoke copy constructor or assignment operator
457 TemplateDictionary(const TemplateDictionary&);
458 void operator=(const TemplateDictionary&);
459};
460
461}
462
463
464#endif // TEMPLATE_TEMPLATE_DICTIONARY_H_