blob: 14e45a3b17c6d6ab504dfd47e2bbd1e76a0e98c1 [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#include <config.h>
36#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
37#include <assert.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <stdarg.h>
41#include <algorithm> // for sort()
42#include HASH_MAP_H
43#include <map>
44#include <string>
45#include <utility> // for pair<>
46#include <vector>
47
48#include "base/arena-inl.h"
49#include "base/thread_annotations.h"
50#include "indented_writer.h"
51#include <ctemplate/find_ptr.h>
52#include <ctemplate/template_dictionary.h>
53#include <ctemplate/template_modifiers.h>
54#include "base/small_map.h"
55#include "base/util.h" // for DCHECK
56
57using std::vector;
58using std::string;
59using std::map;
60using std::pair;
61using std::make_pair;
62
63namespace ctemplate {
64
65// Guards the initialization of the global dictionary.
66static GoogleOnceType g_once = GOOGLE_ONCE_INIT;
67// Guard access to the global dictionary.
68static Mutex g_static_mutex(base::LINKER_INITIALIZED);
69
70/*static*/ UnsafeArena* const TemplateDictionary::NO_ARENA = NULL;
71/*static*/ TemplateDictionary::GlobalDict* TemplateDictionary::global_dict_
72GUARDED_BY(g_static_mutex) PT_GUARDED_BY(g_static_mutex) = NULL;
73/*static*/ TemplateString* TemplateDictionary::empty_string_ = NULL;
74
75
76static const char* const kAnnotateOutput = "__ctemplate_annotate_output__";
77
78// ----------------------------------------------------------------------
79// TemplateDictionary::map_arena_init
80// This class is what small_map<> uses to create a new
81// arena-allocated map<> when it decides it needs to do that.
82// ----------------------------------------------------------------------
83
84class TemplateDictionary::map_arena_init {
85 public:
86 map_arena_init(UnsafeArena* arena) : arena_(arena) { }
87 template<typename T> void operator ()(ManualConstructor<T>* map) const {
88 map->Init(typename T::key_compare(), arena_);
89 }
90 private:
91 UnsafeArena* arena_;
92};
93
94// ----------------------------------------------------------------------
95// TemplateDictionary::LazilyCreateDict()
96// TemplateDictionary::LazilyCreateTemplateGlobalDict()
97// TemplateDictionary::CreateDictVector()
98// TemplateDictionary::CreateTemplateSubdict()
99// These routines allocate the objects that TemplateDictionary
100// allocates (sub-dictionaries, variable maps, etc). Each
101// allocates memory on the arena, and instructs the STL objects
102// to use the arena for their own internal allocations as well.
103// ----------------------------------------------------------------------
104
105template<typename T>
106inline void TemplateDictionary::LazilyCreateDict(T** dict) {
107 if (*dict != NULL)
108 return;
109 // Placement new: construct the map in the memory used by *dict.
110 void* buffer = arena_->AllocAligned(sizeof(**dict),
111 BaseArena::kDefaultAlignment);
112 new (buffer) T(arena_);
113 *dict = reinterpret_cast<T*>(buffer);
114}
115
116inline void TemplateDictionary::LazyCreateTemplateGlobalDict() {
117 if (!template_global_dict_owner_->template_global_dict_) {
118 template_global_dict_owner_->template_global_dict_ =
119 CreateTemplateSubdict("Template Globals", arena_,
120 template_global_dict_owner_,
121 template_global_dict_owner_);
122 }
123}
124
125inline TemplateDictionary::DictVector* TemplateDictionary::CreateDictVector() {
126 void* buffer = arena_->AllocAligned(sizeof(DictVector),
127 BaseArena::kDefaultAlignment);
128 // Placement new: construct the vector in the memory used by buffer.
129 new (buffer) DictVector(arena_);
130 return reinterpret_cast<DictVector*>(buffer);
131}
132
133inline TemplateDictionary* TemplateDictionary::CreateTemplateSubdict(
134 const TemplateString& name,
135 UnsafeArena* arena,
136 TemplateDictionary* parent_dict,
137 TemplateDictionary* template_global_dict_owner) {
138 void* buffer = arena->AllocAligned(sizeof(TemplateDictionary),
139 BaseArena::kDefaultAlignment);
140 // Placement new: construct the sub-tpl in the memory used by tplbuf.
141 new (buffer) TemplateDictionary(name, arena, parent_dict,
142 template_global_dict_owner);
143 return reinterpret_cast<TemplateDictionary*>(buffer);
144}
145
146
147// ----------------------------------------------------------------------
148// TemplateDictionary::HashInsert()
149// A convenience function that's equivalent to m[key] = value, but
150// converting the key to an id first, and without necessarily needing
151// key to have a default constructor like operator[] does. It also
152// inserts (key, id(key)) into a map to allow for id->key mapping.
153// ----------------------------------------------------------------------
154
155// By default, prefer the m[key] = value construct. We do something
156// more complex for TemplateString, though, since m[key] requires a
157// zero-arg constructor, which TemplateString doesn't have. We could
158// do the more complex thing everywhere, but that seems to trigger a
159// bug in in gcc 4.1.2 (at least) when compiled with -O2. Shrug.
160namespace {
161template<typename MapType, typename ValueType>
162inline void DoHashInsert(MapType* m, TemplateId id, ValueType value) {
163 (*m)[id] = value;
164}
165
166template<typename MapType>
167inline void DoHashInsert(MapType* m, TemplateId id, TemplateString value) {
168 pair<typename MapType::iterator, bool> r
169 = m->insert(typename MapType::value_type(id, value));
170 // Unfortunately, insert() doesn't actually replace if key is
171 // already in the map. Thus, in that case (insert().second == false),
172 // we need to overwrite the old value. Since TemplateString
173 // doesn't define operator=, the easiest legal way to overwrite is
174 // to use the copy-constructor with placement-new. Note that since
175 // TemplateString has no destructor, we don't need to call the
176 // destructor to 'clear out' the old value.
177 if (r.second == false) {
178 new (&r.first->second) TemplateString(value);
179 }
180}
181}
182
183template<typename MapType, typename ValueType>
184void TemplateDictionary::HashInsert(MapType* m,
185 TemplateString key, ValueType value) {
186 const TemplateId id = key.GetGlobalId();
187 DoHashInsert(m, id, value);
188 AddToIdToNameMap(id, key); // allows us to do the hash-key -> name mapping
189}
190
191// ----------------------------------------------------------------------
192// TemplateDictionary::SetupGlobalDict()
193// Must be called exactly once before accessing global_dict_.
194// GoogleOnceInit() is used to manage that initialization in a thread-safe
195// way.
196// ----------------------------------------------------------------------
197/*static*/ void TemplateDictionary::SetupGlobalDict()
198 NO_THREAD_SAFETY_ANALYSIS {
199 global_dict_ = new TemplateDictionary::GlobalDict;
200 // Initialize the built-ins
201 HashInsert(global_dict_, TemplateString("BI_SPACE"), TemplateString(" "));
202 HashInsert(global_dict_, TemplateString("BI_NEWLINE"), TemplateString("\n"));
203 // This is used for name-lookup misses.
204 empty_string_ = new TemplateString("");
205}
206
207// ----------------------------------------------------------------------
208// TemplateDictionary::TemplateDictionary()
209// TemplateDictionary::~TemplateDictionary()
210// The only tricky thing is that we make sure the static vars are
211// set up properly. This must be done at each construct time,
212// because it's the responsibility of the first dictionary created
213// in the program to set up the globals, and that could be us.
214// The UnsafeArena() argument is how big to make each arena
215// block. Too big and space is wasted. Too small and we spend
216// a lot of time allocating new arena blocks. 32k seems right.
217// ----------------------------------------------------------------------
218
219TemplateDictionary::TemplateDictionary(const TemplateString& name,
220 UnsafeArena* arena)
221 : arena_(arena ? arena : new UnsafeArena(32768)),
222 should_delete_arena_(arena ? false : true), // true if we called new
223 name_(Memdup(name)), // arena must have been set up first
224 variable_dict_(NULL),
225 section_dict_(NULL),
226 include_dict_(NULL),
227 template_global_dict_(NULL),
228 template_global_dict_owner_(this),
229 parent_dict_(NULL),
230 filename_(NULL) {
231 GoogleOnceInit(&g_once, &SetupGlobalDict);
232}
233
234TemplateDictionary::TemplateDictionary(
235 const TemplateString& name,
236 UnsafeArena* arena,
237 TemplateDictionary* parent_dict,
238 TemplateDictionary* template_global_dict_owner)
239 : arena_(arena), should_delete_arena_(false), // parents own it
240 name_(Memdup(name)), // arena must have been set up first
241 variable_dict_(NULL),
242 section_dict_(NULL),
243 include_dict_(NULL),
244 template_global_dict_(NULL),
245 template_global_dict_owner_(template_global_dict_owner),
246 parent_dict_(parent_dict),
247 filename_(NULL) {
248 assert(template_global_dict_owner_ != NULL);
249 GoogleOnceInit(&g_once, &SetupGlobalDict);
250}
251
252TemplateDictionary::~TemplateDictionary() {
253 // Everything we allocate, we allocate on the arena, so we
254 // don't need to free anything here.
255 if (should_delete_arena_) {
256 delete arena_;
257 }
258}
259
260// ----------------------------------------------------------------------
261// TemplateDictionary::MakeCopy()
262// Makes a recursive copy: so we copy any include dictionaries and
263// section dictionaries we see as well. InternalMakeCopy() is
264// needed just so we can ensure that if we're doing a copy of a
265// subtree, it's due to a recursive call. Returns NULL if there
266// is an error copying.
267// ----------------------------------------------------------------------
268
269TemplateDictionary* TemplateDictionary::InternalMakeCopy(
270 const TemplateString& name_of_copy,
271 UnsafeArena* arena,
272 TemplateDictionary* parent_dict,
273 TemplateDictionary* template_global_dict_owner) {
274
275 TemplateDictionary* newdict;
276 if (template_global_dict_owner_ == this) {
277 // We're a root-level template. We want the copy to be just like
278 // us, and have its own template_global_dict_, that it owns.
279 // We use the normal global new, since newdict will be returned
280 // to the user.
281 newdict = new TemplateDictionary(name_of_copy, arena);
282 } else { // recursive calls use private contructor
283 // We're not a root-level template, so we want the copy to refer to the
284 // same template_global_dict_ owner that we do.
285 // Note: we always use our own arena, even when we have a parent
286 // (though we have the same arena as our parent when we have one).
287 assert(arena);
288 assert(parent_dict ? arena == parent_dict->arena_ : true);
289 newdict = CreateTemplateSubdict(name_of_copy, arena,
290 parent_dict, template_global_dict_owner);
291 }
292
293 // Copy the variable dictionary
294 if (variable_dict_) {
295 newdict->LazilyCreateDict(&newdict->variable_dict_);
296 for (VariableDict::const_iterator it = variable_dict_->begin();
297 it != variable_dict_->end(); ++it) {
298 newdict->variable_dict_->insert(make_pair(it->first,
299 newdict->Memdup(it->second)));
300 }
301 }
302 // ...and the template-global-dict, if we have one (only root-level tpls do)
303 if (template_global_dict_) {
304 newdict->template_global_dict_ = template_global_dict_->InternalMakeCopy(
305 template_global_dict_->name(), newdict->arena_, newdict,
306 newdict->template_global_dict_owner_);
307 }
308 // Copy the section dictionary
309 if (section_dict_) {
310 newdict->LazilyCreateDict(&newdict->section_dict_);
311 for (SectionDict::iterator it = section_dict_->begin();
312 it != section_dict_->end(); ++it) {
313 DictVector* dicts = newdict->CreateDictVector();
314 newdict->section_dict_->insert(make_pair(it->first, dicts));
315 for (DictVector::iterator it2 = it->second->begin();
316 it2 != it->second->end(); ++it2) {
317 TemplateDictionary* subdict = *it2;
318 // In this case, we pass in newdict as the parent of our new dict.
319 dicts->push_back(subdict->InternalMakeCopy(
320 subdict->name(), newdict->arena_,
321 newdict, newdict->template_global_dict_owner_));
322 }
323 }
324 }
325 // Copy the includes-dictionary
326 if (include_dict_) {
327 newdict->LazilyCreateDict(&newdict->include_dict_);
328 for (IncludeDict::iterator it = include_dict_->begin();
329 it != include_dict_->end(); ++it) {
330 DictVector* dicts = newdict->CreateDictVector();
331 newdict->include_dict_->insert(make_pair(it->first, dicts));
332 for (DictVector::iterator it2 = it->second->begin();
333 it2 != it->second->end(); ++it2) {
334 TemplateDictionary* subdict = *it2;
335 // In this case, we pass in NULL as the parent of our new dict:
336 // parents are not inherited across include-dictionaries.
337 dicts->push_back(subdict->InternalMakeCopy(
338 subdict->name(), newdict->arena_,
339 NULL, newdict->template_global_dict_owner_));
340 }
341 }
342 }
343
344 // Finally, copy everything else not set properly by the constructor
345 newdict->filename_ = newdict->Memdup(filename_).ptr_;
346
347 return newdict;
348}
349
350TemplateDictionary* TemplateDictionary::MakeCopy(
351 const TemplateString& name_of_copy, UnsafeArena* arena) {
352 if (template_global_dict_owner_ != this) {
353 // We're not at the root, which is illegal.
354 return NULL;
355 }
356 return InternalMakeCopy(name_of_copy, arena,
357 NULL, template_global_dict_owner_);
358}
359
360
361// ----------------------------------------------------------------------
362// TemplateDictionary::StringAppendV()
363// Does an snprintf to a string. Idea is to grow string as needed.
364// Writes to space if possible -- caller must ensure space has
365// size at least 1024 -- and if not allocates a buffer of its
366// own which the caller must free. Sets out to the buffer written
367// to (space or something else). Returns the number of bytes
368// written into out.
369// ----------------------------------------------------------------------
370
371int TemplateDictionary::StringAppendV(char* space, char** out,
372 const char* format, va_list ap) {
373 const int kBufsize = 1024;
374 // It's possible for methods that use a va_list to invalidate
375 // the data in it upon use. The fix is to make a copy
376 // of the structure before using it and use that copy instead.
377 va_list backup_ap;
378 va_copy(backup_ap, ap);
379 int result = vsnprintf(space, kBufsize, format, backup_ap);
380 va_end(backup_ap);
381
382 if ((result >= 0) && (result < kBufsize)) {
383 *out = space;
384 return result; // It fit
385 }
386
387 // Repeatedly increase buffer size until it fits
388 int length = kBufsize;
389 while (true) {
390 if (result < 0) {
391 // Older snprintf() behavior. :-( Just try doubling the buffer size
392 length *= 2;
393 } else {
394 // We need exactly "result+1" characters
395 length = result+1;
396 }
397 char* buf = new char[length];
398
399 // Restore the va_list before we use it again
400 va_copy(backup_ap, ap);
401 result = vsnprintf(buf, length, format, backup_ap);
402 va_end(backup_ap);
403
404 if ((result >= 0) && (result < length)) {
405 *out = buf;
406 return result;
407 }
408 delete[] buf;
409 }
410}
411
412// ----------------------------------------------------------------------
413// TemplateDictionary::SetValue()
414// TemplateDictionary::SetIntValue()
415// TemplateDictionary::SetFormattedValue()
416// TemplateDictionary::SetEscapedValue()
417// TemplateDictionary::SetEscapedFormattedValue()
418// The functions to set the value of a variable. For each,
419// I first define the char*+length version. Then, after those
420// five definitions, I define a zillion alternate versions:
421// strings, char*s, etc. The only non-obvious thing about
422// each function is I make sure to copy both key and value to
423// the arena, so we have our own, persistent copy of them.
424// ----------------------------------------------------------------------
425
426void TemplateDictionary::SetValue(const TemplateString variable,
427 const TemplateString value) {
428 LazilyCreateDict(&variable_dict_);
429 HashInsert(variable_dict_, variable, Memdup(value));
430}
431
432void TemplateDictionary::SetValueWithoutCopy(const TemplateString variable,
433 const TemplateString value) {
434 LazilyCreateDict(&variable_dict_);
435 // Don't memdup value - the caller will manage memory.
436 HashInsert(variable_dict_, variable, value);
437}
438
439void TemplateDictionary::SetIntValue(const TemplateString variable,
440 long value) {
441 char buffer[64]; // big enough for any int
442 int valuelen = snprintf(buffer, sizeof(buffer), "%ld", value);
443 LazilyCreateDict(&variable_dict_);
444 HashInsert(variable_dict_, variable, Memdup(buffer, valuelen));
445}
446
447void TemplateDictionary::SetFormattedValue(const TemplateString variable,
448 const char* format, ...) {
449 char* buffer;
450
451 char* scratch = arena_->Alloc(1024); // StringAppendV requires >=1024 bytes
452 va_list ap;
453 va_start(ap, format);
454 const int buflen = StringAppendV(scratch, &buffer, format, ap);
455 va_end(ap);
456
457 LazilyCreateDict(&variable_dict_);
458
459 // If it fit into scratch, great, otherwise we need to copy into arena
460 if (buffer == scratch) {
461 scratch = arena_->Shrink(scratch, buflen+1); // from 1024 to |value+\0|
462 HashInsert(variable_dict_, variable, TemplateString(scratch, buflen));
463 } else {
464 arena_->Shrink(scratch, 0); // reclaim arena space we didn't use
465 HashInsert(variable_dict_, variable, Memdup(buffer, buflen));
466 delete[] buffer;
467 }
468}
469
470void TemplateDictionary::SetEscapedValue(TemplateString variable,
471 TemplateString value,
472 const TemplateModifier& escfn) {
473 SetValue(variable, string(escfn(value.data(), value.size())));
474}
475
476void TemplateDictionary::SetEscapedFormattedValue(TemplateString variable,
477 const TemplateModifier& escfn,
478 const char* format, ...) {
479 char* buffer;
480
481 char* scratch = arena_->Alloc(1024); // StringAppendV requires >=1024 bytes
482 va_list ap;
483 va_start(ap, format);
484 const int buflen = StringAppendV(scratch, &buffer, format, ap);
485 va_end(ap);
486
487 string escaped_string(escfn(buffer, buflen));
488 // Reclaim the arena space: the value we care about is now in escaped_string
489 arena_->Shrink(scratch, 0); // reclaim arena space we didn't use
490 if (buffer != scratch)
491 delete[] buffer;
492
493 SetValue(variable, escaped_string);
494}
495
496// ----------------------------------------------------------------------
497// TemplateDictionary::SetTemplateGlobalValue()
498// Sets a value in the template-global dict. Unlike normal
499// variable lookups, these persist across sub-includes.
500// ----------------------------------------------------------------------
501
502void TemplateDictionary::SetTemplateGlobalValue(const TemplateString variable,
503 const TemplateString value) {
504 assert(template_global_dict_owner_ != NULL);
505 LazyCreateTemplateGlobalDict();
506 template_global_dict_owner_->template_global_dict_->SetValue(variable, value);
507}
508
509void TemplateDictionary::SetTemplateGlobalValueWithoutCopy(
510 const TemplateString variable,
511 const TemplateString value) {
512 assert(template_global_dict_owner_ != NULL);
513 LazyCreateTemplateGlobalDict();
514 // Don't memdup value - the caller will manage memory.
515 template_global_dict_owner_->template_global_dict_->
516 SetValueWithoutCopy(variable, value);
517}
518
519// ----------------------------------------------------------------------
520// TemplateDictionary::SetGlobalValue()
521// Sets a value in the global dict. Note this is a static method.
522// ----------------------------------------------------------------------
523
524/*static*/ void TemplateDictionary::SetGlobalValue(
525 const TemplateString variable,
526 const TemplateString value) LOCKS_EXCLUDED(g_static_mutex) {
527 // We can't use memdup here, since we're a static method. We do a strdup,
528 // which is fine, since global_dict_ lives the entire program anyway.
529 // It's unnecessary to copy the variable, since HashInsert takes care of
530 // that for us.
531 char* value_copy = new char[value.length_ + 1];
532 memcpy(value_copy, value.ptr_, value.length_);
533 value_copy[value.length_] = '\0';
534
535 GoogleOnceInit(&g_once, &SetupGlobalDict);
536
537 MutexLock ml(&g_static_mutex);
538 HashInsert(global_dict_,
539 variable,
540 TemplateString(value_copy, value.length_));
541}
542
543// ----------------------------------------------------------------------
544// TemplateDictionary::AddSectionDictionary()
545// TemplateDictionary::ShowSection()
546// TemplateDictionary::ShowTemplateGlobalSection()
547// The new dictionary starts out empty, with us as the parent.
548// It shares our arena. The name is constructed out of our
549// name plus the section name. ShowSection() is the equivalent
550// to AddSectionDictionary("empty_dict").
551// ----------------------------------------------------------------------
552
553/*static*/ string TemplateDictionary::CreateSubdictName(
554 const TemplateString& dict_name, const TemplateString& sub_name,
555 size_t index, const char* suffix) {
556 char index_str[64];
557 snprintf(index_str, sizeof(index_str), "%" PRIuS, index);
558 return (PrintableTemplateString(dict_name) + "/" +
559 PrintableTemplateString(sub_name) + "#" + index_str + suffix);
560}
561
562TemplateDictionary* TemplateDictionary::AddSectionDictionary(
563 const TemplateString section_name) {
564 LazilyCreateDict(&section_dict_);
565 DictVector* dicts = find_ptr2(*section_dict_, section_name.GetGlobalId());
566 if (!dicts) {
567 dicts = CreateDictVector();
568 // Since most lists will remain under 8 or 16 entries but will frequently
569 // be more than four, this prevents copying from 1->2->4->8.
570 dicts->reserve(8);
571 HashInsert(section_dict_, section_name, dicts);
572 }
573 assert(dicts != NULL);
574 const string newname(CreateSubdictName(name_, section_name,
575 dicts->size() + 1, ""));
576 TemplateDictionary* retval = CreateTemplateSubdict(
577 newname, arena_, this, template_global_dict_owner_);
578 dicts->push_back(retval);
579 return retval;
580}
581
582
583void TemplateDictionary::ShowSection(const TemplateString section_name) {
584 LazilyCreateDict(&section_dict_);
585 if (!section_dict_->count(section_name.GetGlobalId())) {
586 TemplateDictionary* empty_dict = CreateTemplateSubdict(
587 "empty dictionary", arena_, this, template_global_dict_owner_);
588 DictVector* sub_dict = CreateDictVector();
589 sub_dict->push_back(empty_dict);
590 HashInsert(section_dict_, section_name, sub_dict);
591 }
592}
593
594void TemplateDictionary::ShowTemplateGlobalSection(
595 const TemplateString section_name) {
596 assert(template_global_dict_owner_ != NULL);
597 LazyCreateTemplateGlobalDict();
598 template_global_dict_owner_->template_global_dict_->
599 ShowSection(section_name);
600}
601
602// ----------------------------------------------------------------------
603// TemplateDictionary::SetValueAndShowSection()
604// TemplateDictionary::SetEscapedValueAndShowSection()
605// If value is "", do nothing. Otherwise, call AddSectionDictionary()
606// on the section and add exactly one entry to the sub-dictionary:
607// the given variable/value pair.
608// ----------------------------------------------------------------------
609
610void TemplateDictionary::SetValueAndShowSection(const TemplateString variable,
611 const TemplateString value,
612 const TemplateString section_name) {
613 if (value.length_ == 0) // no value: the do-nothing case
614 return;
615 TemplateDictionary* sub_dict = AddSectionDictionary(section_name);
616 sub_dict->SetValue(variable, value);
617}
618
619// ----------------------------------------------------------------------
620// TemplateDictionary::AddIncludeDictionary()
621// This is much like AddSectionDictionary(). One major difference
622// is that the new dictionary does not have a parent dictionary:
623// there's no automatic variable inclusion across template-file
624// boundaries. Note there is no ShowTemplate() -- you must always
625// specify the dictionary to use explicitly.
626// ----------------------------------------------------------------------
627
628TemplateDictionary* TemplateDictionary::AddIncludeDictionary(
629 const TemplateString include_name) {
630 LazilyCreateDict(&include_dict_);
631 DictVector* dicts = find_ptr2(*include_dict_, include_name.GetGlobalId());
632 if (!dicts) {
633 dicts = CreateDictVector();
634 HashInsert(include_dict_, include_name, dicts);
635 }
636 assert(dicts != NULL);
637 const string newname(CreateSubdictName(name_, include_name,
638 dicts->size() + 1, ""));
639 TemplateDictionary* retval = CreateTemplateSubdict(
640 newname, arena_, NULL, template_global_dict_owner_);
641 dicts->push_back(retval);
642 return retval;
643}
644
645
646// ----------------------------------------------------------------------
647// TemplateDictionary::SetFilename()
648// Sets the filename this dictionary is meant to be associated with.
649// When set, it's possible to expand a template with just the
650// template-dict; the template is loaded via SetFilename() (though
651// we'd have to assume a value for strip). This is required for
652// dictionaries that are meant to be used with an include-template.
653// ----------------------------------------------------------------------
654
655void TemplateDictionary::SetFilename(const TemplateString filename) {
656 filename_ = Memdup(filename).ptr_;
657}
658
659// ----------------------------------------------------------------------
660// TemplateDictionary::AddToIdToNameMap()
661// We have a problem when we try to dump the contents of the
662// dictionary, because instead of storing the keys to global_dict_
663// etc as strings, we store them as integer id's. We need this
664// map, from id->string, to be able to dump. This should be called
665// every time we add a string to a TemplateDictionary hashtable.
666// ----------------------------------------------------------------------
667
668/*static*/ void TemplateDictionary::AddToIdToNameMap(TemplateId id,
669 const TemplateString& str) {
670 // If str.id_ is set, that means we were added to the id-to-name map
671 // at TemplateString constructor time, when the id_ was set. So we
672 // don't need to bother again here.
673 if (str.id_ != 0) {
674 return;
675 }
676 // Verify that if this id is already in the map, it's there with our
677 // contents. If not, that would mean a hash collision (since our
678 // id's are hash values).
679 DCHECK(TemplateString::IdToString(id) == kStsEmpty ||
680 memcmp(str.ptr_, TemplateString::IdToString(id).ptr_,
681 str.length_) == 0)
682 << string(str.ptr_, str.length_) << " vs "
683 << string(TemplateString::IdToString(id).ptr_,
684 TemplateString::IdToString(id).length_);
685 TemplateString str_with_id(str.ptr_, str.length_, str.is_immutable(), id);
686 str_with_id.AddToGlobalIdToNameMap();
687}
688
689// ----------------------------------------------------------------------
690// TemplateDictionary::DumpToString()
691// TemplateDictionary::Dump()
692// The values are shown in the following order:
693// - Scalar values
694// - Sub-dictionaries and their associated section names.
695// - Sub-dictionaries and their associated template names, with filename.
696// ----------------------------------------------------------------------
697
698// DictionaryPrinter knows how to dump a whole dictionary tree.
699class TemplateDictionary::DictionaryPrinter {
700 public:
701 DictionaryPrinter(string* out, int initial_indent)
702 : writer_(out, initial_indent) {
703 }
704
705 void DumpToString(const TemplateDictionary& dict) {
706 // Show globals if we're a top-level dictionary
707 if (dict.parent_dict_ == NULL) {
708 DumpGlobals();
709 }
710
711 // Show template-globals
712 if (dict.template_global_dict_ && !dict.template_global_dict_->Empty()) {
713 DumpTemplateGlobals(*dict.template_global_dict_);
714 }
715
716 DumpDictionary(dict);
717 }
718
719 private:
720 void FillSortedGlobalDictMap(map<string, string>* sorted_global_dict)
721 LOCKS_EXCLUDED(g_static_mutex) {
722 ReaderMutexLock ml(&g_static_mutex);
723 for (GlobalDict::const_iterator it = global_dict_->begin();
724 it != global_dict_->end(); ++it) {
725 const TemplateString key = TemplateDictionary::IdToString(it->first);
726 assert(!InvalidTemplateString(key)); // checks key.ptr_ != NULL
727 (*sorted_global_dict)[PrintableTemplateString(key)] =
728 PrintableTemplateString(it->second);
729 }
730 }
731 void DumpGlobals() {
732 writer_.Write("global dictionary {\n");
733 writer_.Indent();
734
735 // We could be faster than converting every TemplateString into a
736 // string and inserted into an ordered data structure, but why bother?
737 map<string, string> sorted_global_dict;
738 FillSortedGlobalDictMap(&sorted_global_dict);
739 for (map<string, string>::const_iterator it = sorted_global_dict.begin();
740 it != sorted_global_dict.end(); ++it) {
741 writer_.Write(it->first + ": >" + it->second + "<\n");
742 }
743
744 writer_.Dedent();
745 writer_.Write("};\n");
746 }
747
748 void DumpTemplateGlobals(const TemplateDictionary& template_global_dict) {
749 writer_.Write("template dictionary {\n");
750 writer_.Indent();
751 DumpDictionaryContent(template_global_dict);
752 writer_.Dedent();
753 writer_.Write("};\n");
754 }
755
756 void DumpDictionary(const TemplateDictionary& dict) {
757 string intended_for = dict.filename_ && dict.filename_[0] ?
758 string(" (intended for ") + dict.filename_ + ")" : "";
759 writer_.Write("dictionary '", PrintableTemplateString(dict.name_),
760 intended_for, "' {\n");
761 writer_.Indent();
762 DumpDictionaryContent(dict);
763 writer_.Dedent();
764 writer_.Write("}\n");
765 }
766
767 void DumpDictionaryContent(const TemplateDictionary& dict) {
768 if (dict.variable_dict_) { // Show variables
769 DumpVariables(*dict.variable_dict_);
770 }
771
772
773 if (dict.section_dict_) { // Show section sub-dictionaries
774 DumpSectionDict(*dict.section_dict_);
775 }
776
777
778 if (dict.include_dict_) { // Show template-include sub-dictionaries
779 DumpIncludeDict(*dict.include_dict_);
780 }
781 }
782
783 void DumpVariables(const VariableDict& dict) {
784 map<string, string> sorted_variable_dict;
785 for (VariableDict::const_iterator it = dict.begin();
786 it != dict.end(); ++it) {
787 const TemplateString key = TemplateDictionary::IdToString(it->first);
788 assert(!InvalidTemplateString(key)); // checks key.ptr_ != NULL
789 sorted_variable_dict[PrintableTemplateString(key)] =
790 PrintableTemplateString(it->second);
791 }
792 for (map<string,string>::const_iterator it = sorted_variable_dict.begin();
793 it != sorted_variable_dict.end(); ++it) {
794 writer_.Write(it->first + ": >" + it->second + "<\n");
795 }
796 }
797
798
799 template<typename MyMap, typename MySectionDict>
800 void SortSections(MyMap* sorted_section_dict,
801 const MySectionDict& section_dict) {
802 typename MySectionDict::const_iterator it = section_dict.begin();
803 for (; it != section_dict.end(); ++it) {
804 const TemplateString key = TemplateDictionary::IdToString(it->first);
805 assert(!InvalidTemplateString(key)); // checks key.ptr_ != NULL
806 (*sorted_section_dict)[PrintableTemplateString(key)] = it->second;
807 }
808 }
809
810 void DumpSectionDict(const SectionDict& section_dict) {
811 map<string, const DictVector*> sorted_section_dict;
812 SortSections(&sorted_section_dict, section_dict);
813 for (map<string, const DictVector*>::const_iterator it =
814 sorted_section_dict.begin();
815 it != sorted_section_dict.end(); ++it) {
816 for (DictVector::const_iterator it2 = it->second->begin();
817 it2 != it->second->end(); ++it2) {
818 TemplateDictionary* dict = *it2;
819 writer_.Write("section ", it->first, " (dict ",
820 GetDictNum(it2 - it->second->begin() + 1,
821 it->second->size()),
822 ") -->\n");
823 writer_.Indent();
824 DumpToString(*dict);
825 writer_.Dedent();
826 }
827 }
828 }
829
830 void DumpIncludeDict(const IncludeDict& include_dict) {
831 map<string, const DictVector*> sorted_include_dict;
832 SortSections(&sorted_include_dict, include_dict);
833 for (map<string, const DictVector*>::const_iterator it =
834 sorted_include_dict.begin();
835 it != sorted_include_dict.end(); ++it) {
836 for (vector<TemplateDictionary*>::size_type i = 0;
837 i < it->second->size(); ++i) {
838 TemplateDictionary* dict = (*it->second)[i];
839 string from_name = (dict->filename_ && *dict->filename_) ?
840 string(", from ") + dict->filename_ :
841 string(", **NO FILENAME SET; THIS DICT WILL BE IGNORED**");
842 writer_.Write("include-template ", it->first, " (dict ",
843 GetDictNum(static_cast<int>(i + 1), it->second->size()),
844 from_name, ") -->\n");
845 writer_.Indent();
846 DumpToString(*dict);
847 writer_.Dedent();
848 }
849 }
850 }
851
852 string GetDictNum(size_t index, size_t size) const {
853 char buf[64]; // big enough for two ints
854 snprintf(buf, sizeof(buf), "%" PRIuS " of %" PRIuS, index, size);
855 return buf;
856 }
857
858 IndentedWriter writer_;
859};
860
861void TemplateDictionary::DumpToString(string* out, int indent) const {
862 DictionaryPrinter printer(out, indent);
863 printer.DumpToString(*this);
864}
865
866void TemplateDictionary::Dump(int indent) const {
867 string out;
868 DumpToString(&out, indent);
869 fwrite(out.data(), 1, out.length(), stdout);
870 fflush(stdout);
871}
872
873// ----------------------------------------------------------------------
874// TemplateDictionary::Memdup()
875// Copy the input into the arena, so we have a permanent copy of
876// it. Returns a pointer to the arena-copy, as a TemplateString
877// (in case the input has internal NULs).
878// ----------------------------------------------------------------------
879
880TemplateString TemplateDictionary::Memdup(const char* s, size_t slen) {
881 return TemplateString(arena_->MemdupPlusNUL(s, slen), slen); // add a \0 too
882}
883
884
885// ----------------------------------------------------------------------
886// TemplateDictionary::GetSectionValue()
887// TemplateDictionary::IsHiddenSection()
888// TemplateDictionary::IsHiddenTemplate()
889// TemplateDictionary::GetIncludeTemplateName()
890// The 'introspection' routines that tell Expand() what's in the
891// template dictionary. GetSectionValue() does variable lookup:
892// first look in this dict, then in parent dicts, etc. IsHidden*()
893// returns true iff the name is not present in the appropriate
894// dictionary. None of these functions ever returns NULL.
895// ----------------------------------------------------------------------
896
897TemplateString TemplateDictionary::GetValue(
898 const TemplateString& variable) const LOCKS_EXCLUDED(g_static_mutex) {
899 for (const TemplateDictionary* d = this; d; d = d->parent_dict_) {
900 if (d->variable_dict_) {
901 if (const TemplateString* it = find_ptr(*d->variable_dict_, variable.GetGlobalId()))
902 return *it;
903 }
904 }
905
906 // No match in the dict tree. Check the template-global dict.
907 assert(template_global_dict_owner_ != NULL);
908 if (template_global_dict_owner_->template_global_dict_
909 && template_global_dict_owner_->template_global_dict_->variable_dict_) {
910 const VariableDict* template_global_vars =
911 template_global_dict_owner_->template_global_dict_->variable_dict_;
912
913 if (const TemplateString* it = find_ptr(*template_global_vars, variable.GetGlobalId()))
914 return *it;
915 }
916
917 // No match in dict tree or template-global dict. Last chance: global dict.
918 {
919 ReaderMutexLock ml(&g_static_mutex);
920 if (const TemplateString* it = find_ptr(*global_dict_, variable.GetGlobalId()))
921 return *it;
922 return *empty_string_;
923 }
924}
925
926bool TemplateDictionary::IsHiddenSection(const TemplateString& name) const {
927 for (const TemplateDictionary* d = this; d; d = d->parent_dict_) {
928 if (d->section_dict_ &&
929 d->section_dict_->count(name.GetGlobalId()))
930 return false;
931 }
932 assert(template_global_dict_owner_ != NULL);
933 if (template_global_dict_owner_->template_global_dict_ &&
934 template_global_dict_owner_->template_global_dict_->section_dict_) {
935 SectionDict* sections =
936 template_global_dict_owner_->template_global_dict_->section_dict_;
937 if (sections->count(name.GetGlobalId())) {
938 return false;
939 }
940 }
941 return true;
942}
943
944bool TemplateDictionary::IsHiddenTemplate(const TemplateString& name) const {
945 for (const TemplateDictionary* d = this; d; d = d->parent_dict_) {
946 if (d->include_dict_ &&
947 d->include_dict_->count(name.GetGlobalId()))
948 return false;
949 }
950 return true;
951}
952
953const char *TemplateDictionary::GetIncludeTemplateName(
954 const TemplateString& variable, int dictnum) const {
955 for (const TemplateDictionary* d = this; d; d = d->parent_dict_) {
956 if (d->include_dict_) {
957 if (DictVector* it = find_ptr2(*d->include_dict_, variable.GetGlobalId())) {
958 TemplateDictionary* dict = (*it)[dictnum];
959 return dict->filename_ ? dict->filename_ : ""; // map NULL to ""
960 }
961 }
962 }
963 assert("Call IsHiddenTemplate before GetIncludeTemplateName" && 0);
964 abort();
965}
966
967bool TemplateDictionary::Empty() const {
968 if ((variable_dict_ && !variable_dict_->empty()) ||
969 (section_dict_ && section_dict_->empty()) ||
970 (include_dict_ && include_dict_->empty())) {
971 return false;
972 }
973 return true;
974}
975
976// ----------------------------------------------------------------------
977// TemplateDictionary::CreateSectionIterator()
978// TemplateDictionary::CreateTemplateIterator()
979// TemplateDictionary::Iterator::HasNext()
980// TemplateDictionary::Iterator::Next()
981// Iterator framework.
982// ----------------------------------------------------------------------
983
984template <typename T> bool TemplateDictionary::Iterator<T>::HasNext() const {
985 return begin_ != end_;
986}
987
988template <typename T> const TemplateDictionaryInterface&
989TemplateDictionary::Iterator<T>::Next() {
990 return **(begin_++);
991}
992
993TemplateDictionaryInterface::Iterator*
994TemplateDictionary::CreateTemplateIterator(
995 const TemplateString& section_name) const {
996 for (const TemplateDictionary* d = this; d; d = d->parent_dict_) {
997 if (d->include_dict_) {
998 if (DictVector* it = find_ptr2(*d->include_dict_, section_name.GetGlobalId())) {
999 // Found it! Return it as an Iterator
1000 return MakeIterator(*it);
1001 }
1002 }
1003 }
1004 assert("Call IsHiddenTemplate before CreateTemplateIterator" && 0);
1005 abort();
1006}
1007
1008TemplateDictionaryInterface::Iterator*
1009TemplateDictionary::CreateSectionIterator(
1010 const TemplateString& section_name) const {
1011 for (const TemplateDictionary* d = this; d; d = d->parent_dict_) {
1012 if (d->section_dict_) {
1013 if (const DictVector* it = find_ptr2(*d->section_dict_, section_name.GetGlobalId())) {
1014 // Found it! Return it as an Iterator
1015 return MakeIterator(*it);
1016 }
1017 }
1018 }
1019 // Check the template global dictionary.
1020 assert(template_global_dict_owner_);
1021 const TemplateDictionary* template_global_dict =
1022 template_global_dict_owner_->template_global_dict_;
1023 if (template_global_dict && template_global_dict->section_dict_) {
1024 if (const DictVector* it = find_ptr2(*template_global_dict->section_dict_, section_name.GetGlobalId())) {
1025 return MakeIterator(*it);
1026 }
1027 }
1028 assert("Call IsHiddenSection before GetDictionaries" && 0);
1029 abort();
1030}
1031
1032}