pax_global_header 0000666 0000000 0000000 00000000064 13631223166 0014515 g ustar 00root root 0000000 0000000 52 comment=25c570cdb50e11c19aac5f2398e845b570eca76b
ctemplate-ctemplate-2.4/ 0000775 0000000 0000000 00000000000 13631223166 0015314 5 ustar 00root root 0000000 0000000 ctemplate-ctemplate-2.4/AUTHORS 0000664 0000000 0000000 00000000043 13631223166 0016361 0 ustar 00root root 0000000 0000000 google-ctemplate@googlegroups.com
ctemplate-ctemplate-2.4/COPYING 0000664 0000000 0000000 00000002707 13631223166 0016355 0 ustar 00root root 0000000 0000000 Copyright (c) 2005, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ctemplate-ctemplate-2.4/ChangeLog 0000664 0000000 0000000 00000032544 13631223166 0017076 0 ustar 00root root 0000000 0000000 Sun Mar 08 18:00:14 2020 Olaf van der Spek
* ctemplate: version 2.4 release
* Switch to Python 3
Wed Mar 19 20:02:51 2014 Olaf van der Spek
* ctemplate: version 2.3 release
* Fixed some more C++11 issues.
* Removed deprecated Template::SetEscapedValueAndShowSection()
* and Template::ReloadIfChanged().
Wed Apr 18 23:36:08 2012 Olaf van der Spek
* ctemplate: version 2.2 release
* Fixed several issues reported by G++ 4.7
Thu Mar 22 00:29:09 2012 Olaf van der Spek
* ctemplate: version 2.1 release
* Added operator[] to TemplateDictionary
* Added begin(), end(), data() and size() to TemplateString
* Refactored code
Tue Jan 24 16:00:51 2012 Google Inc.
* ctemplate: version 2.0 release
* Changed the 'official' ctemplate email in setup.py/etc
* Rewrote docs to refer to Ctemplate, not Google Template
* Renamed google-ctemplate.sln to ctemplate.sln
* Changed copyright text to reflect Google's relinquished ownership
Thu Dec 22 14:03:27 2011 Google Inc.
* ctemplate: version 1.1 release
* Make reloads always prefer files earlier on the search patch (ssas)
* PORTING: Add a default BSWAP32, needed for AIX (csilvers)
* Die at configure-time when g++ isn't installed
Fri Aug 26 13:10:46 2011 Google Inc.
* ctemplate: version 1.0 release
* No changes since 1.0rc2
Fri Jul 29 12:19:50 2011 Google Inc.
* ctemplate: version 1.0rc2 release
* BUGFIX: removed #includes of non-installed headers from installed ones
* BUGFIX: Make compile-test test against an install
Fri Jul 22 15:31:05 2011 Google Inc.
* ctemplate: version 1.0rc1 release
* BUGFIX: Dumpers were ignoring a tpl-string 'length' (csilvers)
* BUGFIX: Add a needed $(top_srcdir) to Makefile.am
* Replace 0x00-0x1F with space in xml_escape (alexvod)
* Fix xml encoding to handle form-feed properly (ghurley)
* DOCUMENTATION: Wer missing some docs in the tarball (csilvers)
* BUILD: Update acx_pthread.m4 for nostdlib (Kacper)
* BUGFIX: Make CreateSectionIterator check tpl-globals (williasr)
* PORTING: Fix solaris build by getting rid of PATH_MAX (csilvers)
Mon Jan 24 15:38:31 2011 Google Inc.
* ctemplate: version 0.99 release
* Accept . as part of tag/attr names when autoescaping (falmeida)
* Optimize javascript template escaping (blount)
* Allow inside :H=snippet modifiers (jdtang)
* make_tpl_varnames can write multiple tpls to one file (jad)
* Add a few escaping modifier equivalences (jad)
* BUGFIX: Fix ReloadAllIfChanged() with path (panicker)
* PORTING: Relace tr with more portable sed, in tests (csilvers)
* Updated from autoconf 2.64 to autoconf 2.65
Fri Sep 24 11:38:27 2010 Google Inc.
* ctemplate: version 0.98 release
* Add new image URL modifier: :I=html, :I=css, etc (jshneier, dougy)
* Allow lowercase words in pragma contexts (csilvers)
* Enable full-word matching for tpl filenames (aneeshnaman)
* Performance improvements for small_map (wonchun)
* Avoid some compiler warnings (mac)
* Fix a c++ conformance bug involving const (chandlerc)
* BUGFIX: never reload string templates (panicker)
* BUGFIX: Fix refcounting to avoid accessing freed memory (panicker)
* PORTING: Avoid SIBGUS on sparc by aligning memory more (csilvers)
* PORTING: Use isascii_is*() to avoid langtype issues (csilvers)
* PORTING: Fix 'class not properly dll-epxorted' warnings (csilvers)
* PORTING: Rename README.windows to README_windows.txt (csilvers)
* Made NEWS file non-empty.
* Added ctemplate.pc + ctemplate_nothreads.pc for pkg-config (csilvers)
Mon Apr 19 15:55:23 2010 Google Inc.
* ctemplate: version 0.97 release
* Major API revamp: +TemplateCache, -Template (panicker, csilvers)
* Major documentation revamp: howto -> guide + reference (csilvers)
* Protect auto-generated #include files with header guard (dnovillo)
* Allow ftp:// in ValidateUrl modifier (martone)
* Speed up template modifiers (turnidge)
* BUGFIX: Fix a dnagling pointer in template-modifiers (csilvers)
* PORTING: cygwin/mingw now compile (due to autoconf macros) (csilvers)
* PORTING: improve generate_fs_test on windows (csilvers)
Mon Oct 19 11:42:57 2009 Google Inc.
* ctemplate: version 0.96 release
* Support multiple template root directories (williasr)
* Remove TemplateContext from TemplateToString (jad)
* Remove programmatic auto-escape code (jad)
* Speedup: use linker to detect immutable TemplateStrings (csilvers)
* Implement ShowTemplateGlobalSection (williasr)
* Change SetIntValue to accept longs (omoikane)
* Allow TemplateDictionary c'tor to take a TemplateString (csilvers)
* Make Mutex safer to run during global destructors (csilvers)
* BUILD: don't set TMPDIR when building; ar reads it (csilvers)
* BUILD: fix compiling of C (as opposed to C++) test file (csilvers)
* BUILD: remove bash-specific 'test x == y' from configure.ac (csilvers)
* BUGFIX: use AllocAligned when allocating non-char objects (csilvers)
* PORTING: remove obsolete MSVC Detect64BitPortabilityProblems (csilvers)
* Updated from autoconf 2.61 to 2.62
Fri Jun 12 08:13:35 2009 Google Inc.
* ctemplate: version 0.95 release
* Change default namespace from google to ctemplate
* Rename include directory from google to ctemplate
* Remove deprecated code: template_from_string.{h,cc}
* Remove deprecated code: modifiers in TemplateDictionary class
* Remove last arg from StringToTemplate; use autoescape pragma instead
* Remove template_modifiers namespace
* Provide a script to help convert namespaces and #includes
* TemplateDictionary constructor takes TemplateString, not string
Thu May 7 11:27:28 2009 Google Inc.
* ctemplate: version 0.94 release
* Use arena for all memory allocations: 3-4% speedup (csilvers)
* Add the ability to hook the annotation system (ryoji)
* Expose Expand(ExpandEmitter*,...) to allow custom emitters (csilvers)
* Add RemoveStringFromTemplateCache (csilvers)
* Add new :url_escape_with_arg=css modifier for urls in CSS (jad)
* Support tr1's unordered_map in preference to hash_map (csilvers)
* Use Murmurhash for all string hashing, rather than hash<> (csilvers)
* Better parsing of meta tags and dangling < for auto-escape (falmeida)
* Add AddXssSafeModifier (jad)
* Allow disabling auto-escape for 'trusted' vars (jad)
* BUGFIX: resolve possible memory-leaks in CopyDictionary (csilvers)
* BUGFIX: fix bug when reloading with AUTOESCAPE pragma (jad)
* Updated autoconf version to 2.61 and libtool version to 1.5.26
Mon Feb 2 13:51:33 2009 Google Inc.
* ctemplate: version 0.93 release
* New AUTOESCAPE pragma: alternative to GetTemplateWithAutoescaping (jad)
* Improve autoescape for CSS template and more (jad)
* Replace RegisterStringAsTemplate with TemplateToString (csilvers)
* Speed up template code by hashing and cacheing template strings (jcrim)
* Add StaticTemplateString to make hashing/cacheing even faster
* Autogenerate parser files from .config files (falmeida)
* TESTING: new compile_test to test end-to-end compilation (csilvers)
* Fix Mutex class to allow expanding template before main() (csilvers)
Wed Nov 12 11:24:33 2008 Google Inc.
* ctemplate: version 0.92 release
* BUG FIX: affecting an included string-template with autoescaping (jad)
* BUG FIX: long-name cmdline flag in diff_tpl_auto_escape (jad)
* Do include-template indenting after applying modifiers (jad)
* Add human-readable error messages to the html parser (falmeida)
* Create an abstract base class for TemplateDictionary (williasr)
* PORTING: Be more careful about Windows #defines and types (csilvers)
* PORTING: Make unittest scripts more sh-compatible (falmeida)
* Show missing includes in annotated output (ribrdb)
* Improvements to javascript escaping (escape \f) (jad)
* Improvements to json escaping (escape <>&) (jad)
* Avoid raciness by preferring cached to new template-strings (csilvers)
Tue Aug 19 16:20:27 2008 Google Inc.
* ctemplate: version 0.91 release
* NEW FEATURE: "separator" sections (csilvers)
* NEW FEATURE: changing the markup separator via {{=XXX YYY=}} (csilvers)
* NEW FEATURE: Add an Expand modifier to template dictionary (turnidge)
* TemplateAsString class -> Template::RegisterStringAsTemplate (edwardcu)
* TemplateModifier class -> PerExpandData class (csilvers)
* Store more data in the arena, shrinking TemplateDictionary (csilvers)
* Use TemplateString more widely internally; small speedup (adamk)
* Lazily initialize hash-maps, saving time and space (csilvers)
* Make template annotations more efficient (turnidge)
* PORTABILITY: Fixed a testing script to run on solaris x86 (csilvers)
* Fix namespaces to start with :: (csilvers)
* Improve html parser in various ways (falmeida)
Sun Apr 27 15:06:15 2008 Google Inc.
* ctemplate: version 0.90 release
* MAJOR NEW FEATURE: New "auto-escape" mode (jad, falmeida, mughda)
* New tool, diff_tpl_auto_escape, to convert templates to auto-escaping
* Fixed make install to install test datafiles (csilvers)
* Add a new modifier: javascript_escape_with_arg=number (jad)
* Javascript modifier now escapes all js newlines (msamuel)
Thu Jan 24 16:09:43 2008 Google Inc.
* ctemplate: version 0.9 release
* Bugfix: now we honor "preserve newlines in javacript" (ktl)
* Fix indentation of included templates (csilvers)
* Deprecate the SetEscaped* methods in favor of modifiers (csilvers)
* Revamp the way template modifiers are registered (csilvers)
* Change the psuedo-name of main section from __MAIN__ to __{{MAIN}}__
* Fix types to quiet windows compiler (csilvers)
* Allow infile and outfile for template-converter (ambrose)
* Some doc fixes
Thu Aug 16 21:42:55 2007 Google Inc.
* ctemplate: version 0.8 release
* Add the ability to dynamically add modifiers (ribrdb)
* Support per-Expand() data for template modifiers (ribrdb)
* New commandline flag -f for make_tpl_varnames_h (herbertc)
* Windows: give debug dll and release dll different names (csilvers)
* A few fixups of Windows includes, based on user reports (csilvers)
Tue Jul 3 12:46:59 2007 Google Inc.
* ctemplate: version 0.7 release
* Bugfix: another lock hygiene fix, for recursive includes (csilvers)
* Minor type-hygiene improvements: size_t for int, etc. (csilvers)
* Porting improvements: tests pass on OS X, FreeBSD, Solaris (csilvers)
* Windows port! -- VS solution provided for all unittests (csilvers)
Thu Jun 21 14:02:32 2007 Google Inc.
* ctemplate: version 0.6.1 release
* Bugfix: data corruption bug with >2 template modifiers (jmacgill)
* Bugfix: syntax error in template-namelist: configure-bug (csilvers)
* Bugfix: improve lock hygiene to avoid potential deadlock (csilvers)
Sat Jun 9 22:34:52 2007 Google Inc.
* ctemplate: version 0.6 release
* Use computed includes for hash_map/set: easier config (csilvers)
* Added all used .m4 templates to the distribution (csilvers)
* Beefed-up and revamped modifier code (csilvers)
* New modifiers for url-escaping, attribute-cleansing, etc (ribrdb)
* Annotations now include modifier information (csilvers)
* Support embedded NULs in template names and values (csilvers)
Mon May 14 17:27:10 2007 Google Inc.
* ctemplate: version 0.5 release
* Add new MakeCopy() method to copy template dictionaries (csilvers)
* Add JSON-escaping (mikepurvis)
* Internal change that should ease thread-handling a bit (csilvers)
* Fix url_query_escape to avoid stack overflow (csilvers)
Mon Jan 15 14:10:42 2007 Google Inc.
* ctemplate: version 0.4 release
* Improve html-escaping by adding single-quote (bdangelo)
* Improve javascript-escaping by adding more characters too (smknappy)
* Add url-escaping, for url query parameters (dcoker)
* Add support for "pre" escaping, which preserves whitespace (dboswell)
* Typo fixes in documentation (csilvers)
* Expand() returns false if a template file failed to load (jmittleman)
Mon Aug 21 17:44:32 2006 Google Inc.
* ctemplate: version 0.3 release
* New contrib/ directory entry: vi syntax highlighting (patlac)
* New contrib/ directory entry: emacs syntax highlighting (tonyg)
* Allow escape-modifiers to affect includes, not just vars (csilvers)
separating logic from presentation.
* Add JSON escape-functor (majewski)
Wed Jun 14 14:56:04 2006 Google Inc.
* ctemplate: version 0.2 release
* API CHANGE: new typedefs (and types) for namelist functions (csilvers)
* carry annotation status through to child templates/sections (ehamon)
* Support registering templates after global construct time (njain)
* Add pthread-rwlock support for darwin (csilvers)
* SetTemplateGlobalValue(): new variable type with new scoping (ehamon)
* Export a nothreads version of the ctemplate library (csilvers)
* Got rid of scandir call, which should improve portability (csilvers)
Mon Mar 13 22:20:46 2006 Google Inc.
* ctemplate: initial release:
The ctemplate package contains a library implementing a simple
but powerful template language for C++. It emphasizes
ctemplate-ctemplate-2.4/Makefile.am 0000775 0000000 0000000 00000062026 13631223166 0017361 0 ustar 00root root 0000000 0000000 ## Process this file with automake to produce Makefile.in
# Make sure that when we re-make ./configure, we get the macros we need
ACLOCAL_AMFLAGS = -I m4
# This is so we can #include
AM_CPPFLAGS = -I$(top_srcdir)/src
# These are good warnings to turn on by default
if GCC
AM_CXXFLAGS = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare
endif
dist_doc_DATA = AUTHORS ChangeLog NEWS README
# mingw does weird directory munging on /tmp, which causes some of our
# tests to fail, so use a different tmpdir there.
if MINGW
TMPDIR = ./
dist_doc_DATA += README_windows.txt
else
TMPDIR = /tmp
endif
ctemplateincludedir = $(includedir)/ctemplate
## The .h files you want to install (that is, .h files that people
## who install this package can include in their own applications.)
## We have to include both the .h and .h.in forms. The latter we
## put in noinst_HEADERS.
## NOTE: If you add a file here, also add it to the end of configure.ac
nodist_ctemplateinclude_HEADERS = \
src/ctemplate/template.h \
src/ctemplate/template_cache.h \
src/ctemplate/template_string.h \
src/ctemplate/template_enums.h \
src/ctemplate/template_pathops.h \
src/ctemplate/template_modifiers.h \
src/ctemplate/template_dictionary.h \
src/ctemplate/template_dictionary_interface.h \
src/ctemplate/template_annotator.h \
src/ctemplate/template_emitter.h \
src/ctemplate/template_namelist.h \
src/ctemplate/per_expand_data.h \
src/ctemplate/str_ref.h
noinst_HEADERS = \
src/ctemplate/template.h.in \
src/ctemplate/template_cache.h.in \
src/ctemplate/template_string.h.in \
src/ctemplate/template_enums.h.in \
src/ctemplate/template_pathops.h.in \
src/ctemplate/template_modifiers.h.in \
src/ctemplate/template_dictionary.h.in \
src/ctemplate/template_dictionary_interface.h.in \
src/ctemplate/template_annotator.h.in \
src/ctemplate/template_emitter.h.in \
src/ctemplate/template_namelist.h.in \
src/ctemplate/per_expand_data.h.in \
src/ctemplate/str_ref.h.in
## This is for HTML and other documentation you want to install.
## Add your documentation files (in doc/) in addition to these
## top-level boilerplate files. Also add a TODO file if you have one.
dist_html_DATA = doc/designstyle.css doc/index.html \
doc/howto.html doc/guide.html doc/reference.html \
doc/tips.html doc/example.html doc/auto_escape.html \
doc/xss_resources.html
## The libraries (.so's) you want to install
lib_LTLIBRARIES =
## Libraries that we want to use only internally (for our unittest binaries)
noinst_LTLIBRARIES =
## The binaries you want to install
bin_PROGRAMS =
bin_SCRIPTS =
## The location of the windows project file for each binary we make
WINDOWS_PROJECTS = ctemplate.sln
## unittests you want to run when people type 'make check'.
## TESTS is for binary unittests, check_SCRIPTS for script-based unittests.
## TESTS_ENVIRONMENT sets environment variables for when you run unittest,
## but it only seems to take effect for *binary* unittests (argh!)
TESTS =
check_SCRIPTS =
TESTS_ENVIRONMENT = TEMPLATE_ROOTDIR=$(top_srcdir)
# Every time you add a unittest to check_SCRIPTS, add it here too
noinst_SCRIPTS =
# Add to this for tests that use data
TESTDATA =
## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
# These files are auto-generated via generate_fsm.py. Since we don't want
# to require python to build ctemplate, we include these in the dist
src/htmlparser/htmlparser_fsm.h: src/htmlparser/generate_fsm.py src/htmlparser/fsm_config.py src/htmlparser/htmlparser_fsm.config
$(top_srcdir)/src/htmlparser/generate_fsm.py $(top_srcdir)/src/htmlparser/htmlparser_fsm.config > $@
src/htmlparser/jsparser_fsm.h: src/htmlparser/generate_fsm.py src/htmlparser/fsm_config.py src/htmlparser/jsparser_fsm.config
$(top_srcdir)/src/htmlparser/generate_fsm.py $(top_srcdir)/src/htmlparser/jsparser_fsm.config > $@
src/tests/statemachine_test_fsm.h: src/htmlparser/generate_fsm.py src/htmlparser/fsm_config.py src/tests/statemachine_test_fsm.config
$(top_srcdir)/src/htmlparser/generate_fsm.py $(top_srcdir)/src/tests/statemachine_test_fsm.config > $@
# This is a required hack for auto-generated .h files: cf the automake info pages
# NOTE: since we put these .h files in BUILT_SOURCES, we don't need to put
# them in as deps for the binaries that use them. In fact, it's important
# that we don't; instead we put them in EXTRA_DIST. This mean, in practice,
# they'll go at the end of the distribution tarfile, which means they'll
# have a later timestamp than the .config files that generate them, which
# means users won't try to rebuild them. Ah, the joys of automake.
BUILT_SOURCES = src/htmlparser/htmlparser_fsm.h \
src/htmlparser/jsparser_fsm.h \
src/tests/statemachine_test_fsm.h
# These are the symbols (classes, mostly) we want to export from our library.
# Note this regexp applies to the *mangled* name, which is why we have to
# be careful where we want to assert [^A-Za-z]. (Particularly bad on Darwin.)
# template_modifiers and BaseArena and UnsafeArena perhaps shouldn't be
# exported, but they're needed -- at least -- for some unittests.
CTEMPLATE_SYMBOLS = '(ctemplate|template_modifiers|BaseArena|UnsafeArena|[^A-Za-z]Template[^A-Za-z]|TemplateDictionary|TemplateNamelist|TemplateFromString|TemplateString|TemplateState|[^A-Za-z]Strip[^A-Za-z])'
lib_LTLIBRARIES += libctemplate.la
WINDOWS_PROJECTS += vsprojects/libctemplate/libctemplate.vcxproj
libctemplate_la_SOURCES = $(nodist_ctemplateinclude_HEADERS) \
src/base/arena-inl.h \
src/base/arena.cc \
src/base/arena.h \
src/base/fileutil.h \
src/base/macros.h \
src/base/manual_constructor.h \
src/base/mutex.h \
src/base/small_map.h \
src/base/thread_annotations.h \
src/base/util.h \
src/indented_writer.h \
src/per_expand_data.cc \
src/template.cc \
src/template_annotator.cc \
src/template_cache.cc \
src/template_dictionary.cc \
src/template_modifiers.cc \
src/template_modifiers_internal.h \
src/template_namelist.cc \
src/template_pathops.cc \
src/template_string.cc \
src/htmlparser/htmlparser.cc \
src/htmlparser/htmlparser.h \
src/htmlparser/htmlparser_cpp.h \
src/htmlparser/jsparser.cc \
src/htmlparser/jsparser.h \
src/htmlparser/statemachine.cc \
src/htmlparser/statemachine.h
libctemplate_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS)
# -version-info gets passed to libtool
libctemplate_la_LDFLAGS = $(PTHREAD_CFLAGS) \
-export-symbols-regex $(CTEMPLATE_SYMBOLS) \
-no-undefined \
-version-info @SO_VERSION@
libctemplate_la_LIBADD = $(PTHREAD_LIBS)
# For MinGW, we need to bring in the windows port files
if MINGW
libctemplate_la_SOURCES += src/windows/port.h src/windows/port.cc
endif MINGW
# automake will make different .o files for this library, which is good,
# because we use an extra compiler flag.
lib_LTLIBRARIES += libctemplate_nothreads.la
libctemplate_nothreads_la_SOURCES = $(libctemplate_la_SOURCES)
libctemplate_nothreads_la_DEPENDENCIES = $(libctemplate_la_DEPENDENCIES)
libctemplate_nothreads_la_CXXFLAGS = -DNDEBUG -DNO_THREADS $(AM_CXXFLAGS)
libctemplate_nothreads_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_SYMBOLS) \
-no-undefined \
-version-info @SO_VERSION@
# For our tests, we want versions of these libraries that include asserts.
noinst_LTLIBRARIES += libctemplate_debug.la
libctemplate_debug_la_SOURCES = $(libctemplate_la_SOURCES)
libctemplate_debug_la_DEPENDENCIES = $(libctemplate_la_DEPENDENCIES)
libctemplate_debug_la_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
libctemplate_debug_la_LDFLAGS = $(libctemplate_la_LDFLAGS)
libctemplate_debug_la_LIBADD = $(libctemplate_la_LIBADD)
noinst_LTLIBRARIES += libctemplate_nothreads_debug.la
libctemplate_nothreads_debug_la_SOURCES = $(libctemplate_nothreads_la_SOURCES)
libctemplate_nothreads_debug_la_DEPENDENCIES = $(libctemplate_nothreads_la_DEPENDENCIES)
libctemplate_nothreads_debug_la_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
libctemplate_nothreads_debug_la_LDFLAGS = $(libctemplate_nothreads_la_LDFLAGS)
# We could also make a library that has the TemplateDictionaryPeer
# class. This class is useful for testing (it provides introspection
# on the TemplateDictionary hierarchy that's easier to use than the
# default debugging method, TemplateDictionary::Dump()) but by the
# same token also violates abstraction in ways that might be fragile.
# We don't expose the library for now, until the demonstrated need
# outweighs the costs. If you'd like to use this library, please send
# mail to google-ctemplate@googlegroups.com!
##lib_LTLIBRARIES += libctemplate_testing.la
noinst_LTLIBRARIES += libctemplate_testing.la libctemplate_testing_nothreads.la
libctemplate_testing_la_SOURCES = $(nodist_ctemplateinclude_HEADERS) \
src/tests/template_test_util.h \
src/tests/template_test_util.cc
libctemplate_testing_la_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
CTEMPLATE_TESTING_SYMBOLS = 'TemporaryRegisterTemplate|TemplateDictionaryPeer'
libctemplate_testing_la_LDFLAGS = $(PTHREAD_CFLAGS) \
-export-symbols-regex $(CTEMPLATE_TESTING_SYMBOLS) \
-no-undefined \
-version-info @SO_VERSION@
libctemplate_testing_la_LIBADD = $(PTHREAD_LIBS)
libctemplate_testing_nothreads_la_SOURCES = $(libctemplate_testing_la_SOURCES)
libctemplate_testing_nothreads_la_CXXFLAGS = $(AM_CXXFLAGS) -DNO_THREADS
libctemplate_testing_nothreads_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_TESTING_SYMBOLS) \
-no-undefined \
-version-info @SO_VERSION@
# This library depends on libctemplate, but it can use either libctemplate
# or libctemplate_nothreads. Rather than have two versions of this
# library, I just leave out the deps entirely: you must be sure to specify
# one of the two whenever you link this library into your code.
#libctemplate_testing_la_LIBADD = libctemplate.la # or libctemplate_nothreads.la
# Helper apps
bin_PROGRAMS += make_tpl_varnames_h
WINDOWS_PROJECTS += vsprojects/make_tpl_varname_h/make_tpl_varname_h.vcxproj
make_tpl_varnames_h_SOURCES = $(nodist_ctemplateinclude_HEADERS) \
src/make_tpl_varnames_h.cc
make_tpl_varnames_h_LDADD = libctemplate_nothreads.la
bin_PROGRAMS += diff_tpl_auto_escape
WINDOWS_PROJECTS += vsprojects/diff_tpl_auto_escape/diff_tpl_auto_escape.vcxproj
diff_tpl_auto_escape_SOURCES = $(nodist_ctemplateinclude_HEADERS) \
src/diff_tpl_auto_escape.cc
diff_tpl_auto_escape_LDADD = libctemplate_nothreads.la
bin_SCRIPTS += src/template-converter
# For each of the tests, we test with and without threads
TESTS += compile_test compile_nothreads_test
WINDOWS_PROJECTS += vsprojects/compile_test/compile_test.vcxproj
compile_test_SOURCES = $(nodist_ctemplateinclude_HEADERS) \
src/tests/compile_test.cc
compile_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
compile_test_LDFLAGS = $(PTHREAD_CFLAGS)
compile_test_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
compile_nothreads_test_SOURCES = $(compile_test_SOURCES)
compile_nothreads_test_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
compile_nothreads_test_LDADD = libctemplate_nothreads_debug.la
# With compile_test, we are making sure that the code compiles without
# needing config.h/etc. The best test is to make sure we can compile
# with just the installed header files. The best way to do this is at
# installcheck time. When this rule is run (via 'make distcheck'),
# 'includedir' is the installed include-dir.
installcheck-local:
$(CXX) -I $(includedir) -c $(top_srcdir)/src/tests/compile_test.cc \
-o installcheck_compile_test.o
TESTS += template_test_util_test template_test_util_nothreads_test
WINDOWS_PROJECTS += vsprojects/template_test_util_test/template_test_util_test.vcxproj
template_test_util_test_SOURCES = src/tests/config_for_unittests.h \
src/template_dictionary.cc \
src/tests/template_test_util_test.cc
template_test_util_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_test_util_test_LDFLAGS = $(PTHREAD_CFLAGS)
template_test_util_test_LDADD = libctemplate_testing.la libctemplate_debug.la \
$(PTHREAD_LIBS)
template_test_util_nothreads_test_SOURCES = $(template_test_util_test_SOURCES)
template_test_util_nothreads_test_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_test_util_nothreads_test_LDADD = libctemplate_testing_nothreads.la \
libctemplate_nothreads_debug.la
TESTS += template_dictionary_unittest template_dictionary_nothreads_unittest
WINDOWS_PROJECTS += vsprojects/template_dictionary_unittest/template_dictionary_unittest.vcxproj
template_dictionary_unittest_SOURCES = src/tests/config_for_unittests.h \
src/base/arena.h \
src/tests/template_dictionary_unittest.cc
template_dictionary_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_dictionary_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
template_dictionary_unittest_LDADD = libctemplate_testing.la libctemplate_debug.la \
$(PTHREAD_LIBS)
template_dictionary_nothreads_unittest_SOURCES = $(template_dictionary_unittest_SOURCES)
template_dictionary_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_dictionary_nothreads_unittest_LDADD = libctemplate_testing_nothreads.la \
libctemplate_nothreads_debug.la
TESTS += template_modifiers_unittest template_modifiers_nothreads_unittest
WINDOWS_PROJECTS += vsprojects/template_modifiers_unittest/template_modifiers_unittest.vcxproj
template_modifiers_unittest_SOURCES = src/tests/config_for_unittests.h \
src/tests/template_modifiers_unittest.cc
template_modifiers_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_modifiers_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
template_modifiers_unittest_LDADD = libctemplate_testing.la libctemplate_debug.la \
$(PTHREAD_LIBS)
template_modifiers_nothreads_unittest_SOURCES = $(template_modifiers_unittest_SOURCES)
template_modifiers_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_modifiers_nothreads_unittest_LDADD = libctemplate_testing_nothreads.la \
libctemplate_nothreads_debug.la
TESTS += template_setglobals_unittest template_setglobals_nothreads_unittest
WINDOWS_PROJECTS += vsprojects/template_setglobals_unittest/template_setglobals_unittest.vcxproj
template_setglobals_unittest_SOURCES = src/tests/config_for_unittests.h \
src/tests/template_setglobals_unittest.cc
template_setglobals_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_setglobals_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
template_setglobals_unittest_LDADD = libctemplate_testing.la libctemplate_debug.la \
$(PTHREAD_LIBS)
template_setglobals_nothreads_unittest_SOURCES = $(template_setglobals_unittest_SOURCES)
template_setglobals_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_setglobals_nothreads_unittest_LDADD = libctemplate_testing_nothreads.la \
libctemplate_nothreads_debug.la
TESTS += template_cache_test template_cache_nothreads_test
WINDOWS_PROJECTS += vsprojects/template_cache_test/template_cache_test.vcxproj
template_cache_test_SOURCES = src/tests/config_for_unittests.h \
src/template_modifiers_internal.h \
src/tests/template_cache_test.cc
template_cache_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_cache_test_LDFLAGS = $(PTHREAD_CFLAGS)
template_cache_test_LDADD = libctemplate_testing.la libctemplate_debug.la \
$(PTHREAD_LIBS)
template_cache_nothreads_test_SOURCES = $(template_cache_test_SOURCES)
template_cache_nothreads_test_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_cache_nothreads_test_LDADD = libctemplate_testing_nothreads.la \
libctemplate_nothreads_debug.la
TESTS += template_unittest template_nothreads_unittest
WINDOWS_PROJECTS += vsprojects/template_unittest/template_unittest.vcxproj
WINDOWS_PROJECTS += vsprojects/template_unittest_static/template_unittest_static.vcxproj
template_unittest_SOURCES = src/tests/config_for_unittests.h \
src/template_modifiers_internal.h \
src/tests/template_unittest.cc
template_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
template_unittest_LDADD = libctemplate_testing.la libctemplate_debug.la \
$(PTHREAD_LIBS)
template_nothreads_unittest_SOURCES = $(template_unittest_SOURCES)
template_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_nothreads_unittest_LDADD = libctemplate_testing_nothreads.la \
libctemplate_nothreads_debug.la
TESTS += template_regtest template_nothreads_regtest
WINDOWS_PROJECTS += vsprojects/template_regtest/template_regtest.vcxproj
template_regtest_SOURCES = src/tests/template_regtest.cc
template_regtest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
template_regtest_LDFLAGS = $(PTHREAD_CFLAGS)
template_regtest_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
template_nothreads_regtest_SOURCES = $(template_regtest_SOURCES)
template_nothreads_regtest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
template_nothreads_regtest_LDADD = libctemplate_nothreads_debug.la
TESTDATA += \
src/tests/template_unittest_test_footer.in \
src/tests/template_unittest_test_html.in \
src/tests/template_unittest_test_invalid1.in \
src/tests/template_unittest_test_invalid2.in \
src/tests/template_unittest_test_markerdelim.in \
src/tests/template_unittest_test_modifiers.in \
src/tests/template_unittest_test_nul.in \
src/tests/template_unittest_test_selective_css.in \
src/tests/template_unittest_test_selective_html.in \
src/tests/template_unittest_test_selective_js.in \
src/tests/template_unittest_test_simple.in \
src/tests/template_unittest_test_valid1.in \
src/tests/template_unittest_test_footer_dict01.out \
src/tests/template_unittest_test_footer_dict02.out \
src/tests/template_unittest_test_html_dict01.out \
src/tests/template_unittest_test_html_dict02.out \
src/tests/template_unittest_test_markerdelim_dict01.out \
src/tests/template_unittest_test_markerdelim_dict02.out \
src/tests/template_unittest_test_modifiers_dict01.out \
src/tests/template_unittest_test_nul_dict01.out \
src/tests/template_unittest_test_selective_css_dict01.out \
src/tests/template_unittest_test_selective_css_dict02.out \
src/tests/template_unittest_test_selective_html_dict01.out \
src/tests/template_unittest_test_selective_html_dict02.out \
src/tests/template_unittest_test_selective_js_dict01.out \
src/tests/template_unittest_test_selective_js_dict02.out \
src/tests/template_unittest_test_simple_dict01.out \
src/tests/template_unittest_test_simple_dict02.out \
src/tests/template_unittest_test_simple_dict03.out \
src/tests/template_unittest_test_valid1_dict01.out
TESTS += htmlparser_test htmlparser_nothreads_test
WINDOWS_PROJECTS += vsprojects/htmlparser_test/htmlparser_test.vcxproj
htmlparser_test_SOURCES = src/tests/htmlparser_cpp_test.cc
htmlparser_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
htmlparser_test_LDFLAGS = $(PTHREAD_CFLAGS)
htmlparser_test_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
htmlparser_nothreads_test_SOURCES = $(htmlparser_test_SOURCES)
htmlparser_nothreads_test_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
htmlparser_nothreads_test_LDADD = libctemplate_nothreads_debug.la
TESTDATA += \
src/tests/htmlparser_testdata/cdata.html \
src/tests/htmlparser_testdata/comments.html \
src/tests/htmlparser_testdata/context.html \
src/tests/htmlparser_testdata/google.html \
src/tests/htmlparser_testdata/javascript_attribute.html \
src/tests/htmlparser_testdata/javascript_block.html \
src/tests/htmlparser_testdata/javascript_regexp.html \
src/tests/htmlparser_testdata/position.html \
src/tests/htmlparser_testdata/reset.html \
src/tests/htmlparser_testdata/simple.html \
src/tests/htmlparser_testdata/tags.html
# We want to compile statemachine.cc as a c file as well as a c++ file
statemachine.c: $(top_srcdir)/src/htmlparser/statemachine.cc
cp $< $@
BUILT_SOURCES += statemachine.c
CLEANFILES = statemachine.c
TESTS += statemachine_test
WINDOWS_PROJECTS += vsprojects/statemachine_test/statemachine_test.vcxproj
statemachine_test_SOURCES = src/tests/statemachine_test.c \
statemachine.c
statemachine_test_CFLAGS = -I$(top_srcdir)/src/htmlparser
TESTS += generate_fsm_c_test
WINDOWS_PROJECTS += vsprojects/generate_fsm_c_test/generate_fsm_c_test.vcxproj
generate_fsm_c_test_SOURCES = src/tests/generate_fsm_c_test.c
generate_fsm_c_test_DEPENDENCIES = src/tests/htmlparser_testdata/sample_fsm.c
# This is something only maintainers need (since they're the only ones
# who generate .h or .c files from .config files).
check_SCRIPTS += generate_fsm_test_sh
noinst_SCRIPTS += src/tests/generate_fsm_test.sh
generate_fsm_test_sh: src/tests/generate_fsm_test.sh \
src/tests/htmlparser_testdata/sample_fsm.config \
src/tests/htmlparser_testdata/sample_fsm.c \
src/htmlparser/generate_fsm.py
sh $(top_srcdir)/src/tests/generate_fsm_test.sh $(top_srcdir)
TESTDATA += \
src/tests/htmlparser_testdata/sample_fsm.config \
src/tests/htmlparser_testdata/sample_fsm.c
check_SCRIPTS += make_tpl_varnames_h_unittest_sh
noinst_SCRIPTS += src/tests/make_tpl_varnames_h_unittest.sh
make_tpl_varnames_h_unittest_sh: src/tests/make_tpl_varnames_h_unittest.sh \
make_tpl_varnames_h
sh $(top_srcdir)/src/tests/make_tpl_varnames_h_unittest.sh \
$(top_builddir)/make_tpl_varnames_h $(TMPDIR)/$@_dir
check_SCRIPTS += diff_tpl_auto_escape_unittest_sh
noinst_SCRIPTS += src/tests/diff_tpl_auto_escape_unittest.sh
diff_tpl_auto_escape_unittest_sh: src/tests/diff_tpl_auto_escape_unittest.sh \
diff_tpl_auto_escape
sh $(top_srcdir)/src/tests/diff_tpl_auto_escape_unittest.sh \
$(top_builddir)/diff_tpl_auto_escape $(TMPDIR)/$@_dir
## ^^^^ END OF RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
## This should always include $(TESTS), but may also include other
## binaries that you compile but don't want automatically installed.
check_PROGRAMS = $(TESTS)
rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
@cd packages && ./rpm.sh ${PACKAGE} ${VERSION}
deb: dist-gzip packages/deb.sh packages/deb/*
@cd packages && ./deb.sh ${PACKAGE} ${VERSION}
# http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = lib${PACKAGE}.pc lib${PACKAGE}_nothreads.pc
CLEANFILES += $(pkgconfig_DATA)
# I get the description and URL lines from the rpm spec. I use sed to
# try to rewrite exec_prefix, libdir, and includedir in terms of
# prefix, if possible.
lib${PACKAGE}.pc: Makefile packages/rpm/rpm.spec
echo 'prefix=$(prefix)' > "$@".tmp
echo 'exec_prefix='`echo '$(exec_prefix)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp
echo 'libdir='`echo '$(libdir)' | sed 's@^$(exec_prefix)@$${exec_prefix}@'` >> "$@".tmp
echo 'includedir='`echo '$(includedir)' | sed 's@^$(prefix)@$${prefix}@'` >> "$@".tmp
echo '' >> "$@".tmp
echo 'Name: $(PACKAGE)' >> "$@".tmp
echo 'Version: $(VERSION)' >> "$@".tmp
-grep '^Summary:' $(top_srcdir)/packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
-grep '^URL: ' $(top_srcdir)/packages/rpm/rpm.spec >> "$@".tmp
echo 'Requires:' >> "$@".tmp
echo 'Libs: -L$${libdir} -l$(PACKAGE)' >> "$@".tmp
echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp
echo 'Cflags: -I$${includedir}' >> "$@".tmp
mv -f "$@".tmp "$@"
# The nothreads version is mostly the same
lib${PACKAGE}_nothreads.pc: lib${PACKAGE}.pc
grep -v Libs.private lib${PACKAGE}.pc | sed s/-l$(PACKAGE)/-l$(PACKAGE)_nothreads/ > "$@"
# Windows wants write permission to .vcxproj files and maybe even sln files.
dist-hook:
test -e "$(distdir)/vsprojects" \
&& chmod -R u+w $(distdir)/*.sln $(distdir)/vsprojects/
## If you're using libtool, add 'libtool' here. Also add this rule:
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck
# In addition to the normal stuff, we include all the windows-specific
# code, and also the code used to generate the html-parser fsm files.
# NOTE: BUILT_SOURCES should come after the .config files, so they
# come later (and thus end up with a later timestamp) when we tar/untar.
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
$(SCRIPTS) $(TESTDATA) libtool autogen.sh \
src/htmlparser/generate_fsm.py src/htmlparser/fsm_config.py \
src/tests/statemachine_test_fsm.config \
src/htmlparser/htmlparser_fsm.config \
src/htmlparser/jsparser_fsm.config \
$(BUILT_SOURCES) \
src/windows/config.h src/windows/preprocess.sh \
src/windows/ctemplate $(WINDOWS_PROJECTS) \
src/solaris/libstdc++.la contrib
ctemplate-ctemplate-2.4/NEWS 0000664 0000000 0000000 00000027733 13631223166 0016027 0 ustar 00root root 0000000 0000000 == 08 March 2020 ==
Ctemplate 2.4
Switch to Python 3
== 19 March 2014 ==
Ctemplate 2.3 has been released. Fixed some more C++11 issues.
Removed deprecated Template::SetEscapedValueAndShowSection() and Template::ReloadIfChanged().
== 18 April 2012 ==
Ctemplate 2.2 has been released. Several issues reported by G++ 4.7 have been fixed.
== 22 March 2012 ==
2.1 has been released. operator[] has been added to TemplateDictionary.
== 24 January 2012 ==
I've just released ctemplate 2.0. It has no functional changes from
ctemplate 1.2.
The `google-ctemplate` project has been renamed to `ctemplate`. I
(csilvers) am stepping down as maintainer, to be replaced by Olaf van
der Spek. Welcome to the team, Olaf! I've been impressed by your
contributions to the project discussions and code to date, and look
forward to having you on the team.
I bumped the major version number up to 2 to reflect the new community
ownership of the project. All the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-2.0/ChangeLog changes]
are related to the renaming.
=== 18 January 2011 ===
The `google-ctemplate` Google Code page has been renamed to
`ctemplate`, in preparation for the project being renamed to
`ctemplate`. In the coming weeks, I'll be stepping down as
maintainer for the ctemplate project, and as part of that Google is
relinquishing ownership of the project; it will now be entirely
community run. The name change reflects that shift.
=== 22 December 2011 ===
I've just released ctemplate 1.1. The only functionality change is
obscure: when a reload is done (via, say, `ReloadAllIfChanged`), and a
new file has been created since the last reload that both a) has the
same filename as a template file that had been loaded in the past, and
b) is earlier on the template search-path than the previously loaded
file, *and* c) the previously loaded file hasn't changed since the
last reload, then at reload-time we now load the new file into the
template, replacing the old file. Before we would only load the new
file if the old file had changed on disk, and would otherwise leave
the template alone. Even more minor changes are in the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-1.1/ChangeLog ChangeLog].
=== 26 August 2011 ===
I've just released ctemplate 1.0! (I've decided 4 weeks is well
within the definition of "the next week or so"...)
A bit anti-climactic: there are no changes from ctemplate 1.0rc2.
=== 29 July 2011 ===
I've just released ctemplate 1.0rc2. This fixes a serious bug where I
had added #includes in installed header files, that tried to include
non-installed header files. This means it was impossible to use
installed ctemplate; it only worked if you were using it from the
tarball directory.
I also fixed the unittest that was supposed to catch this, but didn't
(it was also building in the tarball directory).
If no further problems are found in the next week or so, I will
release ctemplate 1.0.
=== 22 July 2011 ===
I've just released ctemplate 1.0rc1. If no problems are found in the
next week or two, I will release ctemplate 1.0.
ctemplate 1.0rc1 has relatively few changes from ctemplate 0.99.
xml-escaping has been improved a bit. A couple of bugs have been
fixed, including one where we were ignoring template-global sections
(a relatively new feature) in some places. A full list of changes is
available in the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-1.0rc1/ChangeLog ChangeLog].
I've also changed the internal tools used to integrate
Google-supplied patches to ctemplate into the opensource release.
These new tools should result in more frequent updates with better
change descriptions. They will also result in future ChangeLog
entries being much more verbose (for better or for worse).
=== 24 January 2011 ===
I've just released ctemplate 0.99. I expect this to be the last
release before ctemplate 1.0. Code has settled down; the big change
here is some efficiency improvements to javascript template escaping.
There is also a bugfix for an obscure case where ReloadAllIfChanged()
is used with multiple ctemplate search paths, where files are deleted
in one part of the search path between reloads. Unless you need
either of the above, there's no particular reason to upgrade.
A full list of changes is available in the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-0.99/ChangeLog ChangeLog].
=== 23 September 2010 ===
I've just released ctemplate 0.98. The changes are settling down as
we approach ctemplate 1.0 -- a few new default modifiers, a few
performance tweaks, a few portability improvements, but nothing
disruptive.
In my testing for this release, I noticed that the template regression
test (but not other template tests) would segfault on gcc 4.1.1 when
compiled with -O2. This seems pretty clearly to be a compiler bug; if
you need to use gcc 4.1.1 to compile ctemplate, you may wish to build
via `./configure CXXFLAGS="-O1 -g"` just to be safe.
=== 20 April 2010 ===
I've just released ctemplate 0.97. This change consists primarily of
a significant change to the API: the addition of the `TemplateCache`
class, combined with deprecation of the `Template` class.
`TemplateCache` is a class that holds a collection of templates; this
concept always existed in ctemplate, but was not previously exposed.
Many static methods of the `Template` class, such as
`ReloadAllIfChanged()`, have become methods on `TemplateCache` instead
(the `Template` methods have been retained for backwards
compatibility.) Other methods, such as `Expand()`, have become free
functions. In fact, the entire `Template` class has been deprecated.
The deprecation of `Template` calls for changes in all clients of the
template code -- you can see in the example at the top of this page
how the code has changed from `Template* tpl =
ctemplate::Template::GetTemplate("example.tpl",
ctemplate::DO_NOT_STRIP); tpl->Expand(&output, &dict);` to
`ctemplate::ExpandTemplate("example.tpl", ctemplate::DO_NOT_STRIP,
&dict, &output);`. These changes will make the code simpler and more
thread-safe.
Old code should continue to work -- the `Template` class remains --
but new code should use the new API, and old code should transition as
convenient. One old API method is intrinsically thread-unsafe, and
should be prioritized to change: `tpl->ReloadIfChanged` should change
to `ctemplate::Template::ReloadAllIfChanged()`. Note this is a
semantic change: all templates are now reloaded, rather than just one.
However, since templates are reloaded lazily, and only if they've
changed on disk, I'm hopeful it will always be a reasonable change to
make.
To go along with these changes, the documentation has been almost
entirely revamped and made more accessible. Obscure ctemplate
features have been excised from the user's guide and moved into a
separate reference document. The new API is fully documented,
including new flexibility around reloading templates, made available
by the introduction of `TemplateCache`.
There are some more minor changes as well, such as the addition of
#include guards in the auto-generated .tpl.h files, to make it safe to
multiply-include them. I've also been continuing the portability
work: ctemplate should now work under Cygwin and MinGW. A full list
of changes is available in the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-0.97/ChangeLog ChangeLog].
I know I've said this before, but I don't expect major API changes
before the 1.0 release. The most significant changes I expect to see
are the potential removal of some of the 'forwarding' methods in the
(deprecated) `Template` class.
=== 12 June 2009 ===
I've just released ctemplate 0.95. This is entirely an API cleanup
release. Actually, relatively little of the API proper has changed:
`StringToTemplate` no longer takes an autoescape-context arg (instead
you specify this as part of the template-string, using the
`AUTOESCAPE` pragma). A few obsolete constructs have gone away, such
as the `TemplateFromString` class and
`TemplateDictionary::html_escape` and friends (just use the top-level
`html_escape`). See the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-0.95/ChangeLog
ChangeLog] for a full list of these changes.
The biggest change is a renaming: the default namespace is now
`ctemplate` rather than `google`, and the include directory is
`ctemplate` rather than `google`. Other namespaces, such as
`template_modifiers`, have gone away.
All these changes will require you to modify your old code to get it
working with ctemplate 0.95. I've written a
[http://google-ctemplate.googlecode.com/svn/trunk/contrib/convert_to_95.pl
script] to help you do that. Please open an
[http://code.google.com/p/google-ctemplate/issues/list issue] if you
see a problem with the script. I've tested it, but not as widely as
I'd like. Also note the script will not be perfect for more complex
constructs, which you will have to clean up by hand.
I hope (expect) the API is now stable, and we won't see any more such
changes before ctemplate 1.0. I tried to isolate them all in this
release; except for the API changes, this release should behave
identically to ctemplate 0.94.
=== 7 May 2009 ===
I've just released ctemplate 0.94. A few new features have been
added, such as the ability to expand a template into your own custom
`ExpandEmitter` instance, and the ability to hook the annotation
system (typically used for debugging). You can now remove strings
from the template cache in addition to adding them. Also, there
continues to be a trickle of new modifiers, in this case a modifier
for URL's in a CSS context.
However, the most invasive changes were made for speed reasons. The
biggest is that (almost) all `TemplateDictionary` allocations are now
done on the arena -- this includes allocations by the STL classes
inside the dictionary. This allows us to free all the memory at once,
rather than item by item, and has yielded a 3-4% speed improvement in
our tests. I've combined this with a `small_map` class that stores
items in a vector instead of a hash-map until we get to 3 or 4 items;
this gives another speed increase in the (common) case a template has
only a few sections or includes.
I also changed the hashing code to use
[http://murmurhash.googlepages.com/ MurmurHash] everywhere, rather
than the string hash function built into the STL library. This should
be faster.
All these changes should not be outwardly visible, but they do use
more advanced features of C++ than ctemplate has to date. This may
result in some problems compiling, or conceivably when running. If
you see any, please file an
[http://code.google.com/p/google-ctemplate/issues/list issue report].
You can see a full list of changes on the
[http://google-ctemplate.googlecode.com/svn/tags/ctemplate-0.94/ChangeLog
ChangeLog].
=== 20 August 2008 ===
ctemplate 0.91 introduces the beginning of some API changes, as I look
to clean up the API in preparation for ctemplate 1.0. After 1.0, the
API will remain backwards compatible, but until that time, the API may
change. Please take a look at the
[http://google-ctemplate.googlecode.com/svn/trunk/ChangeLog ChangeLog]
to see if any of these changes affect you.
One change is the introduction of a new `PerExpandData` class, which
holds some state that was formerly in the `TemplateDictionary` class.
I'm still not sure if this class is a good idea, if it should be
separate from `TemplateDictionary` or a member, or what functionality
should move there (for instance, should `SetTemplateGlobal` move
there, since template-global variables are really, in some sense,
per-expand variables?) If you have any feedback, ideally based on
your own experience using the current API, feel free to post it at
`google-ctemplate@googlegroups.com`.
ctemplate also has several new features, including the addition of
"separator" sections, and the ability to change the markup character
(from `{{`). See the
[http://google-ctemplate.googlecode.com/svn/trunk/ChangeLog ChangeLog]
for a complete list, and the
[http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html howto
documentation] for more details on these new features.
ctemplate-ctemplate-2.4/README 0000664 0000000 0000000 00000002740 13631223166 0016177 0 ustar 00root root 0000000 0000000 See the documentation in the doc/ directory for information about how
to use the ctemplate library.
COMPILING
---------
To compile test applications with these classes, run ./configure
followed by make. To install these header files on your system, run
'make install'. (On Windows, the instructions are different; see
README.windows.) See INSTALL for more details.
This code should work on any modern C++ system. It has been tested on
Linux (Ubuntu, Fedora, RedHat), Solaris 10 x86, FreeBSD 6.0, OS X 10.3
and 10.4, and Windows under both VC++7 and VC++8.
There are a few Windows-specific details; see README.windows for more
information.
CTEMPLATE AND THREADS
---------------------
The ctemplate library has thread support, so it works properly in a
threaded environment. For this to work, if you link libraries with
-lctemplate you may find you also need to add -pthread (or, on some
systems, -pthreads, and on others, -lpthread) to get the library to
compile. If you leave out the -pthread, you'll see errors like this:
symbol lookup error: /usr/local/lib/libctemplate.so.0: undefined symbol: pthread_rwlock_init
If your code isn't multi-threaded, you can instead use the
ctemplate_nothread library:
-lctemplate_nothreads
To summarize, there are two ways to link in ctemlpate in non-threaded
applications. For instance:
1) gcc -o my_app my_app.o -lctemplate -pthread
2) gcc -o my_app my_app.o -lctemplate_nothreads
If your application uses threads, you should use form (1).
ctemplate-ctemplate-2.4/README.md 0000664 0000000 0000000 00000004611 13631223166 0016575 0 ustar 00root root 0000000 0000000 Welcome to the C++ CTemplate system!
====================================
This library provides an easy to use and lightning fast text templating system
to use with C++ programs.
It was originally called Google Templates, due to its origin as the template
system used for Google search result pages. Now it has a more general name
matching its community-owned nature.
Documentation
-------------
Refer to the [Project
Documentation]()
to learn how to use the CTemplate system.
There is also a
[HOWTO]()
and
[Examples]().
Compiling
---------
To compile test applications with these classes, run `./autogen.sh && ./configure` followed by
`make` on unixoid platforms like Linux or MacOSX.
To install these header files on your system, run `make install`.
See INSTALL for more details.
This code should work on any modern C++ system. It has been tested on Linux
(Ubuntu, Fedora, RedHat), Solaris 10 x86, FreeBSD 6.0, OS X 10.3 and 10.4, and
Windows under both VC++7 and VC++8.
There are a few Windows-specific details; see README.windows for more
information.
CTemplate and Threads
---------------------
The ctemplate library has thread support, so it works properly in a threaded
environment.
For this to work, if you link libraries with `-lctemplate` you may also need to
add `-pthread` (or, on some systems, `-pthreads`, and on others, `-lpthread`) to
get the library to compile. If you leave out the `-pthread`, you'll see errors
like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
symbol lookup error: /usr/local/lib/libctemplate.so.0: undefined symbol: pthread_rwlock_init
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If your code isn't multi-threaded, you can instead use the ctemplate\_nothread
library: `-lctemplate_nothreads`
To summarize, there are two ways to link in ctemlpate in non-threaded
applications. For instance:
1. Thread safe build:`gcc -o my_app my_app.o -lctemplate -pthread`
2. Unthreaded code:`gcc -o my_app my_app.o -lctemplate_nothreads`
If your application uses threads, you should use form (1).
ctemplate-ctemplate-2.4/README_windows.txt 0000664 0000000 0000000 00000004047 13631223166 0020571 0 ustar 00root root 0000000 0000000 This project has been ported to Windows. A working solution file
exists in this directory:
ctemplate.sln
You can load this solution file into either VC++ 7.1 (Visual Studio
2003) or VC++ 8.0 (Visual Studio 2005) -- in the latter case, it will
automatically convert the files to the latest format for you.
When you build the solution, it will create libctemplate.dll, the main
library for this project, plus a number of unittests, which you can
run by hand (or, more easily, under the Visual Studio debugger) to
make sure everything is working properly on your system. The binaries
will end up in a directory called "debug" or "release" in the
top-level directory (next to the .sln file).
I don't know very much about how to install DLLs on Windows, so you'll
have to figure out that part for yourself. If you choose to just
re-use the existing .sln, make sure you set the IncludeDir's
appropriately! Look at the properties for libctemplate.dll.
If you wish to link to ctemplate statically instead of using the .dll,
you can; see the example project template_unittest_static. For this
to work, you'll need to add "/D CTEMPLATE_DLL_DECL=" to the compile
line of every ctemplate .cc file.
Note that these systems are set to build in Debug mode by default.
You may want to change them to Release mode.
Currently, Template::StringToTemplate returns a Template object that
you, the caller, must free. We've heard reports that Windows can have
trouble allocating memory in a .dll that is meant to be freed in the
application. Thus, we suggest you not use StringToTemplate from
Windows. Instead, you can use Template::StringToTemplateCache()
followed by Template::GetTemplate().
I have little experience with Windows programming, so there may be
better ways to set this up than I've done! If you run across any
problems, please post to the google-ctemplate Google Group, or report
them on the ctemplate Google Code site:
http://groups.google.com/group/google-ctemplate
http://code.google.com/p/ctemplate/issues/list
-- craig
ctemplate-ctemplate-2.4/autogen.sh 0000775 0000000 0000000 00000001136 13631223166 0017316 0 ustar 00root root 0000000 0000000 #!/bin/sh
# Before using, you should figure out all the .m4 macros that your
# configure.m4 script needs and make sure they exist in the m4/
# directory.
#
# These are the files that this script might edit:
# aclocal.m4 configure Makefile.in src/config.h.in \
# depcomp config.guess config.sub install-sh missing mkinstalldirs \
#
# Here's a command you can run to see what files aclocal will import:
# aclocal -I ../autoconf --output=- | sed -n 's/^m4_include..\([^]]*\).*/\1/p'
set -ex
rm -rf autom4te.cache
autoreconf --force --install --warnings all,no-obsolete
rm -rf autom4te.cache
exit 0
ctemplate-ctemplate-2.4/configure.ac 0000664 0000000 0000000 00000011235 13631223166 0017604 0 ustar 00root root 0000000 0000000 ## Process this file with autoconf to produce configure.
## In general, the safest way to proceed is to run ./autogen.sh
# make sure we're interpreted by some minimal autoconf
AC_PREREQ([2.69])
AC_INIT([ctemplate],[2.3],[google-ctemplate@googlegroups.com])
AM_SILENT_RULES([yes])
# Update this value for every release! (A:B:C will map to foo.so.(A-C).C.B)
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
SO_VERSION=3:0:0
# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([subdir-objects dist-zip])
AC_CONFIG_HEADERS([src/config.h])
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AM_PROG_AR
AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
# MinGW uses autoconf, but also needs the windows shim routines
# (since it doesn't have its own support for, say, pthreads).
# This requires us to #include a special header file, and also to
# link in some windows versions of .o's instead of the unix versions.
AH_BOTTOM([
#if defined( __MINGW32__) || defined(__MINGW64__)
#include "windows/port.h"
#endif
])
AM_CONDITIONAL(MINGW, expr $host : '.*-mingw' >/dev/null 2>&1)
LT_INIT([disable-fast-install])
AC_SUBST(LIBTOOL_DEPS)
AC_SUBST(SO_VERSION)
AX_C___ATTRIBUTE__
# Defines PRIuS
AC_COMPILER_CHARACTERISTICS
# Here are some examples of how to check for the existence of a fn or file
AC_CHECK_FUNCS([getopt_long getopt])
AC_CHECK_HEADERS([getopt.h])
AC_CHECK_HEADERS([utime.h]) # used by unittests to mock file-times
AC_HEADER_DIRENT # for template_unittest.cc, template_regtest.cc
# We need to do byte-swapping efficiently to hash efficiently in
# template_string.cc. Different architectures do this differently.
AC_CHECK_HEADERS(byteswap.h) # Linux (GNU in general)
AC_CHECK_HEADERS(libkern/OSByteOrder.h) # OS X
AC_CHECK_HEADERS(sys/byteorder.h) # Solaris 10
AC_CHECK_HEADERS(endian.h) # Linux
AC_CHECK_HEADERS(machine/endian.h) # OS X
AC_CHECK_HEADERS(sys/endian.h) # FreeBSD
AC_CHECK_HEADERS(sys/isa_defs.h) # Solaris 10
# A lot of the code in this directory depends on pthreads
AX_PTHREAD
# We'd like to use read/write locks in several places in the code.
# See if our pthreads support extends to that. Note: for linux, it
# does as long as you define _XOPEN_SOURCE appropriately.
AC_RWLOCK
# For mingw/cygwin, figure out if the mutex code needs to use
# 'volatile' in some places. They differ from MSVC, and the API is
# unclear, so it's best just to check.
AC_INTERLOCKED_EXCHANGE_NONVOLATILE
# Figures out where hash_map and hash_set live, and what namespace they use
AC_CXX_STL_HASH
AC_SUBST(ac_cv_cxx_hash_namespace)
AC_SUBST(ac_cv_cxx_hash_map)
AC_SUBST(ac_cv_cxx_hash_set)
if test "$ac_cv___attribute__" = "yes"; then
AC_SUBST(ac_google_attribute, 1)
else
AC_SUBST(ac_google_attribute, 0)
fi
# On some systems (eg gnu/linux), the linker defines _start and
# data_start to indicate the extent of the .text section. We can use
# this to know strings are immutable. In the code, we make the
# variables weak, just in case, but for this check, we only want to
# say "yes" if the linker supports the vars, *and* the compiler supports
# attribute-weak.
AC_LINK_IFELSE([
AC_LANG_PROGRAM([], [[
extern char _start[];
extern char data_start[];
extern char dummy[] __attribute__((weak));
return (_start && data_start && dummy);
]])
], [
ac_have_attribute_weak=1
], [
ac_have_attribute_weak=0
])
AC_SUBST(ac_have_attribute_weak)
# In unix (that is, using this script), this dll-export stuff will always
# be the empty string. In windows, we'll replace it with windows-specific
# text.
ac_windows_dllexport_defines=
ac_windows_dllexport=
AC_SUBST(ac_windows_dllexport_defines)
AC_SUBST(ac_windows_dllexport)
# Write generated configuration file, and also .h files
AC_CONFIG_FILES([Makefile \
src/ctemplate/template_string.h \
src/ctemplate/template_enums.h \
src/ctemplate/template.h \
src/ctemplate/template_cache.h \
src/ctemplate/template_modifiers.h \
src/ctemplate/template_emitter.h \
src/ctemplate/template_annotator.h \
src/ctemplate/template_dictionary.h \
src/ctemplate/template_pathops.h \
src/ctemplate/template_namelist.h \
src/ctemplate/find_ptr.h \
src/ctemplate/per_expand_data.h \
src/ctemplate/str_ref.h \
src/ctemplate/template_dictionary_interface.h \
])
AC_OUTPUT
ctemplate-ctemplate-2.4/contrib/ 0000775 0000000 0000000 00000000000 13631223166 0016754 5 ustar 00root root 0000000 0000000 ctemplate-ctemplate-2.4/contrib/README.contrib 0000664 0000000 0000000 00000001300 13631223166 0021265 0 ustar 00root root 0000000 0000000 All files under this contrib directory are UNSUPPORTED; use at your
own risk. They were provided by users of ctemplate and were not
tested by the authors of ctemplate. These files are not owned by
Google. Please contact the authors of the contributions for help
about these, not the ctemplate authors. Thanks!, and enjoy.
highlighting.vim by Patrick Lacasse
How to set up syntax highlighting (colorization) for ctemplate .tpl
files, using vim. A shar file; see top-of-file for how to extract.
tpl-mode.el by Tony Gentilcore
Elisp file for syntax highlighting (colorization) for ctemplate
.tpl files, using emacs. See top-of-file for how to use.
ctemplate-ctemplate-2.4/contrib/convert_to_95.pl 0000775 0000000 0000000 00000013223 13631223166 0022014 0 ustar 00root root 0000000 0000000 #!/usr/bin/perl -pli.bak
# Copyright (c) 2006, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ---
# Author: Craig Silverstein
# This is a perl script for editing your source files that were
# written with ctemplate <0.95, to use the new #include paths,
# namespace names, and function locations in ctemplate 0.95.
#
# This script will modify your files in place. It is safe to
# call it multiple times. To call it, do something like:
# find -print0 | xargs -0 ./convert_to_95.pl
#
# Issues:
# TemplateFromString logic is tricky. Best to check up by hand.
# Can't always tell when 1st arg to TemplateFromString is empty string.
# If it might be for your app, change the logic to use StringToTemplate.
# Fails if TemplateFromString or StringToTemplate span multiple lines.
# Change all the #include lines
s@google/template.h@ctemplate/template.h@g;
s@google/per_expand_data.h@ctemplate/per_expand_data.h@g;
s@google/template.h@ctemplate/template.h@g;
s@google/template_annotator.h@ctemplate/template_annotator.h@g;
s@google/template_dictionary.h@ctemplate/template_dictionary.h@g;
s@google/template_dictionary_interface.h@ctemplate/template_dictionary_interface.h@g;
s@google/template_emitter.h@ctemplate/template_emitter.h@g;
s@google/template_enums.h@ctemplate/template_enums.h@g;
s@google/template_from_string.h@ctemplate/template_from_string.h@g;
s@google/template_modifiers.h@ctemplate/template_modifiers.h@g;
s@google/template_namelist.h@ctemplate/template_namelist.h@g;
s@google/template_pathops.h@ctemplate/template_pathops.h@g;
s@google/template_string.h@ctemplate/template_string.h@g;
# Change all the namespace uses
s@namespace\s+google@namespace ctemplate@g; # brought into google namespace
s@\bgoogle::@ctemplate::@g;
s@namespace\s+template_modifiers\s*{@@ && ($in_tm = 1);
$in_tm && s@}@@ && ($in_tm = 0);
s@\btemplate_modifiers::@@g;
# Change TemplateFromString::GetTemplate to
# Template::StringToTemplateCache(cache_key, template_text);
# return Template::GetTemplate(cache_key, strip);
# unless cache_key is the empty string, in which case it should be
# return Template::StringToTemplate(template_text, strip, TC_MANUAL);
# We have to be tricky, to do this in one command.
# Better would be to just do Template::StringToTemplate(), but then we
# have to free the memory when we're done, which is too hard to do here.
s@TemplateFromString::GetTemplate\s*\(""\s*,([^,]+),([^,]+)\)@Template::StringToTemplate($1, $2, ctemplate::TC_MANUAL)@;
s@TemplateFromString::GetTemplate\s*\(([^,]+),([^,]+),([^,]+)\)@Template::GetTemplate((ctemplate::Template::StringToTemplateCache($1, $2), $1), $3)@;
if (m@TemplateFromString::GetTemplate\s*\([^)]*$@) {
warn("$ARGV:$.: TemplateFromString spans mutiple lines. You will need " .
"to clean it up by hand. See comments in $0.");
}
# Get rid of the 4th arg to Template::TemplateToString. If it's
# TC_MANUAL, that's fine. If it's not, we need to tell the user to
# fix this up manually by adding an {{%PRAGMA AUTOESCAPE}} to the
# beginning of their string.
if (s@(\bStringToTemplate\s*\([^)]*),\s*TC_([A-Z_]*)@$1@g) {
if ($2 ne "MANUAL") { # TC_MANUAL is the new default
warn("WARNING: $ARGV:$.: You will need to manually fix up the " .
"StringToTemplate change to add an AUTOESCAPE {{\%pragma}} to " .
"the beginning of the input string, to set the context to TC_$2\n");
}
}
if (m@\bStringToTemplate\s*\([^)]*$@) {
warn("$ARGV:$.: StringToTemplate spans mutiple lines. You will need " .
"to clean it up by hand: get rid of the TC_foo arg. If it's not " .
"TC_MANUAL, you will need to add an AUTOESCAPE pragma. " .
"See comments in $0.");
}
# Change all the TemplateDictionary escapes. Now they are globals in
# the ctemplate namespace.
s@TemplateDictionary::html_escape@html_escape@g;
s@TemplateDictionary::pre_escape@pre_escape@g;
s@TemplateDictionary::xml_escape@xml_escape@g;
s@TemplateDictionary::javascript_escape@javascript_escape@g;
s@TemplateDictionary::url_query_escape@url_query_escape@g;
s@TemplateDictionary::json_escape@json_escape@g;
# This cleans up anything messy we left behind.
s@\bctemplate::ctemplate::@ctemplate::@g; # get rid of redundant specifier
close ARGV if eof; # to reset $. for each file
ctemplate-ctemplate-2.4/contrib/highlighting.vim 0000664 0000000 0000000 00000015505 13631223166 0022144 0 ustar 00root root 0000000 0000000 #!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2006-08-08 13:38 PDT by .
# Commandline: shar -T .vim
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 1477 -rw-r--r-- .vim/syntax/tpl.vim
# 56 -rw-r--r-- .vim/ftdetect/tpl.vim
#
echo >/dev/null <<_NOTES_EOF
From: Patrick Lacasse
Subject: vim color for google-ctemplate howto
To: google-ctemplate@googlegroups.com
Date: Fri, 4 Aug 2006 11:38:39 -0400
Hi group,
I'm now using google-ctemplate. My text editor is vim. Here is a little gift
for other people like me.
Howto have google-ctemplate colored by vim :
In your home directory, run 'sh $0'.
Now restart vim.
This will autodetects file with tpl extension and colors them. You can change
the color by changing the HiLink lines ( try changing String by
Identifier ) .
I'm not sure exactly about what are the legal marker names. Feel free to
change the regexes.
I only tryed this with vim 6.4 , I just cut and past the things about version
checking.
For more information about syntax higlithning in vim, try
:help syntax
Amusez-vous bien,
Patrick Lacasse
patlac@borabora.crchul.ulaval.ca
_NOTES_EOF
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
set `$dir/gettext --version 2>&1`
if test "$3" = GNU
then
gettext_dir=$dir
fi
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
$echo 'WARNING: not restoring timestamps. Consider getting and'
$echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh09814; then
$echo 'x -' 'creating lock directory'
else
$echo 'failed to create lock directory'
exit 1
fi
# ============= .vim/syntax/tpl.vim ==============
if test ! -d '.vim'; then
$echo 'x -' 'creating directory' '.vim'
mkdir '.vim'
fi
if test ! -d '.vim/syntax'; then
$echo 'x -' 'creating directory' '.vim/syntax'
mkdir '.vim/syntax'
fi
if test -f '.vim/syntax/tpl.vim' && test "$first_param" != -c; then
$echo 'x -' SKIPPING '.vim/syntax/tpl.vim' '(file already exists)'
else
$echo 'x -' extracting '.vim/syntax/tpl.vim' '(text)'
sed 's/^X//' << 'SHAR_EOF' > '.vim/syntax/tpl.vim' &&
" Vim syntax file
" Language: google-ctemplate
" Maintainer: Patrick Lacasse
" Last Change: 2006 Août 03
"
" For information about google-ctemplate see
" http://goog-ctemplate.sourceforge.net/
"
" This vim syntax file works on vim 5.6, 5.7, 5.8 and 6.x.
" It implements Bram Moolenaar's April 25, 2001 recommendations to make
" the syntax file maximally portable across different versions of vim.
X
" For version 5.x: Clear all syntax items
" For version 6.x: Quit when a syntax file was already loaded
if version < 600
X syntax clear
elseif exists("b:current_syntax")
X finish
endif
X
syntax match tplMarkerError "{{}\?\([^}]\+}\?\)*}}"
syntax match tplSectionMarker "{{[#/][A-Za-z_]\+}}"
syntax match tplInclude "{{>[A-Za-z_]\+}}"
syntax match tplComment "{{![A-Za-z_]\+}}"
syntax match tplVariableMarker "{{[_A-Za-z]\+}}"
X
" Define the default highlighting.
" For version 5.7 and earlier: only when not done already
" For version 5.8 and later: only when an item doesn't have highlighting yet
if version >= 508 || !exists("did_tpl_syn_inits")
X if version < 508
X let did_tpl_syn_inits = 1
X command -nargs=+ HiLink hi link
X else
X command -nargs=+ HiLink hi def link
X endif
X
X HiLink tplSectionMarker Repeat
X HiLink tplInclude Include
X HiLink tplComment Comment
X HiLink tplVariableMarker String
X HiLink tplMarkerError Error
X
X delcommand HiLink
endif
X
let b:current_syntax = "tpl"
SHAR_EOF
(set 20 06 08 08 13 34 11 '.vim/syntax/tpl.vim'; eval "$shar_touch") &&
chmod 0644 '.vim/syntax/tpl.vim' ||
$echo 'restore of' '.vim/syntax/tpl.vim' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo '.vim/syntax/tpl.vim:' 'MD5 check failed'
536faef79eff0597e642c5db04c1f79d .vim/syntax/tpl.vim
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < '.vim/syntax/tpl.vim'`"
test 1477 -eq "$shar_count" ||
$echo '.vim/syntax/tpl.vim:' 'original size' '1477,' 'current size' "$shar_count!"
fi
fi
# ============= .vim/ftdetect/tpl.vim ==============
if test ! -d '.vim/ftdetect'; then
$echo 'x -' 'creating directory' '.vim/ftdetect'
mkdir '.vim/ftdetect'
fi
if test -f '.vim/ftdetect/tpl.vim' && test "$first_param" != -c; then
$echo 'x -' SKIPPING '.vim/ftdetect/tpl.vim' '(file already exists)'
else
$echo 'x -' extracting '.vim/ftdetect/tpl.vim' '(text)'
sed 's/^X//' << 'SHAR_EOF' > '.vim/ftdetect/tpl.vim' &&
au BufRead,BufNewFile *.tpl set filetype=tpl
SHAR_EOF
(set 20 06 08 08 13 34 20 '.vim/ftdetect/tpl.vim'; eval "$shar_touch") &&
chmod 0644 '.vim/ftdetect/tpl.vim' ||
$echo 'restore of' '.vim/ftdetect/tpl.vim' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo '.vim/ftdetect/tpl.vim:' 'MD5 check failed'
774fd4a092b77400ef6e74a7256ff8ef .vim/ftdetect/tpl.vim
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < '.vim/ftdetect/tpl.vim'`"
test 56 -eq "$shar_count" ||
$echo '.vim/ftdetect/tpl.vim:' 'original size' '56,' 'current size' "$shar_count!"
fi
fi
rm -fr _sh09814
exit 0
ctemplate-ctemplate-2.4/contrib/tpl-mode.el 0000664 0000000 0000000 00000020056 13631223166 0021022 0 ustar 00root root 0000000 0000000 ;;; tpl-mode.el -- a major mode for editing Google CTemplate files.
;;; By Tony Gentilcore, July 2006
;;;
;;; TO USE:
;;; 1) Copy this file somewhere you in emacs load-path. To see what
;;; your load-path is, run inside emacs: C-h v load-path
;;; 2) Add the following two lines to your .emacs file:
;;; (setq auto-mode-alist (cons '("\\.tpl$" . tpl-mode) auto-mode-alist))
;;; (autoload 'tpl-mode "tpl-mode" "Major mode for editing CTemplate files." t)
;;; 3) Optionally (but recommended), add this third line as well:
;;; (add-hook 'tpl-mode-hook '(lambda () (font-lock-mode 1)))
;;; ---
;;;
;;; While the CTemplate language can be used for any types of text,
;;; this mode is intended for using CTemplate to write HTML.
;;;
;;; The indentation still has minor bugs due to the fact that
;;; templates do not require valid HTML.
;;;
;;; It would be nice to be able to highlight attributes of HTML tags,
;;; however this is difficult due to the presence of CTemplate symbols
;;; embedded within attributes.
(eval-when-compile
(require 'font-lock))
(defgroup tpl-mode nil
"Major mode for editing CTemplate files"
:group 'languages)
(defvar tpl-mode-version "1.0"
"Version of `tpl-mode.el'.")
(defvar tpl-mode-abbrev-table nil
"Abbrev table for use in tpl-mode buffers.")
(define-abbrev-table 'tpl-mode-abbrev-table ())
(defcustom tpl-mode-hook nil
"*Hook that runs upon entering tpl-mode."
:type 'hook
)
(defvar tpl-mode-map nil
"Keymap for tpl-mode major mode")
(if tpl-mode-map
nil
(setq tpl-mode-map (make-sparse-keymap))
)
(define-key tpl-mode-map "\t" 'tpl-indent-command)
(define-key tpl-mode-map "\C-m" 'newline-and-indent)
(defvar tpl-mode-syntax-table nil
"Syntax table in use in tpl-mode buffers.")
;; Syntax table.
(if tpl-mode-syntax-table
nil
(setq tpl-mode-syntax-table (make-syntax-table text-mode-syntax-table))
(modify-syntax-entry ?< "(> " tpl-mode-syntax-table)
(modify-syntax-entry ?> ")< " tpl-mode-syntax-table)
(modify-syntax-entry ?\" ". " tpl-mode-syntax-table)
(modify-syntax-entry ?\\ ". " tpl-mode-syntax-table)
(modify-syntax-entry ?' "w " tpl-mode-syntax-table)
)
(defvar tpl-basic-offset 2
"The basic indentation offset.")
;; Constant regular expressions to identify template elements.
(defconst tpl-mode-tpl-token "[a-zA-Z][a-zA-Z0-9_:=\-]*?")
(defconst tpl-mode-section (concat "\\({{[#/]"
tpl-mode-tpl-token
"}}\\)"))
(defconst tpl-mode-open-section (concat "\\({{#"
tpl-mode-tpl-token
"}}\\)"))
(defconst tpl-mode-close-section (concat "{{/\\("
tpl-mode-tpl-token
"\\)}}"))
(defconst tpl-mode-comment "\\({{![^}]+?}}\\)")
(defconst tpl-mode-include (concat "\\({{>"
tpl-mode-tpl-token
"}}\\)"))
(defconst tpl-mode-variable (concat "\\({{"
tpl-mode-tpl-token
"}}\\)"))
(defconst tpl-mode-builtins
(concat
"\\({{\\<"
(regexp-opt
'("BI_NEWLINE" "BI_SPACE")
t)
"\\>}}\\)"))
(defconst tpl-mode-close-section-at-start (concat "^[ \t]*?"
tpl-mode-close-section))
;; Constant regular expressions to identify html tags.
;; Taken from HTML 4.01 / XHTML 1.0 Reference found at:
;; http://www.w3schools.com/tags/default.asp.
(defconst tpl-mode-html-constant "\\(?[a-z0-9]\\{2,5\\};\\)")
(defconst tpl-mode-pair-tag
(concat
"\\<"
(regexp-opt
'("a" "abbr" "acronym" "address" "applet" "area" "b" "bdo"
"big" "blockquote" "body" "button" "caption" "center" "cite"
"code" "col" "colgroup" "dd" "del" "dfn" "dif" "div" "dl"
"dt" "em" "fieldset" "font" "form" "frame" "frameset" "h1"
"h2" "h3" "h4" "h5" "h6" "head" "html" "i" "iframe" "ins"
"kbd" "label" "legend" "li" "link" "map" "menu" "noframes"
"noscript" "object" "ol" "optgroup" "option" "p" "pre" "q"
"s" "samp" "script" "select" "small" "span" "strike"
"strong" "style" "sub" "sup" "table" "tbody" "td" "textarea"
"tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var")
t)
"\\>"))
(defconst tpl-mode-standalone-tag
(concat
"\\<"
(regexp-opt
'("base" "br" "hr" "img" "input" "meta" "param")
t)
"\\>"))
(defconst tpl-mode-open-tag (concat "<\\("
tpl-mode-pair-tag
"\\)"))
(defconst tpl-mode-close-tag (concat "\\("
tpl-mode-pair-tag
"\\)>"))
(defconst tpl-mode-close-tag-at-start (concat "^[ \t]*?"
tpl-mode-close-tag))
(defconst tpl-mode-blank-line "^[ \t]*?$")
(defconst tpl-mode-dangling-open (concat "\\("
tpl-mode-open-section
"\\)\\|\\("
tpl-mode-open-tag
"\\)[^/]*$"))
(defun tpl-indent-command ()
"Command for indenting text. Just calls tpl-indent."
(interactive)
(tpl-indent))
;; Function to control indenting.
(defun tpl-indent ()
"Indent current line"
;; Set the point to beginning of line.
(beginning-of-line)
;; If we are at the beginning of the file, indent to 0.
(if (bobp)
(indent-line-to 0)
(let ((tag-stack 1) (close-tag "") (cur-indent 0) (old-pnt (point-marker))
(close-at-start) (open-token) (dangling-open))
(progn
;; Determine if this is a template line or an html line.
(if (looking-at "^[ \t]*?{{")
(setq close-at-start tpl-mode-close-section-at-start
open-token "{{#")
(setq close-at-start tpl-mode-close-tag-at-start
open-token "<")
)
;; If there is a closing tag at the start of the line, search back
;; for its opener and indent to that level.
(if (looking-at close-at-start)
(progn
(save-excursion
(setq close-tag (match-string 1))
;; Keep searching for a match for the close tag until
;; the tag-stack is 0.
(while (and (not (bobp))
(> tag-stack 0)
(re-search-backward (concat open-token
"\\(/?\\)"
close-tag) nil t))
(if (string-equal (match-string 1) "/")
;; We found another close tag, so increment tag-stack.
(setq tag-stack (+ tag-stack 1))
;; We found an open tag, so decrement tag-stack.
(setq tag-stack (- tag-stack 1))
)
(setq cur-indent (current-indentation))
)
)
(if (> tag-stack 0)
(save-excursion
(forward-line -1)
(setq cur-indent (current-indentation))
)
)
)
;; This was not a closing tag, so we check if the previous line
;; was an opening tag.
(save-excursion
;; Keep moving back until we find a line that is not blank
(while (progn
(forward-line -1)
(and (not (bobp)) (looking-at tpl-mode-blank-line))
)
)
(setq cur-indent (current-indentation))
(if (re-search-forward tpl-mode-dangling-open old-pnt t)
(setq cur-indent (+ cur-indent tpl-basic-offset))
)
)
)
;; Finally, we execute the actual indentation.
(if (> cur-indent 0)
(indent-line-to cur-indent)
(indent-line-to 0)
)
)
)
)
)
;; controls highlighting
(defconst tpl-mode-font-lock-keywords
(list
(list tpl-mode-section
'(1 font-lock-keyword-face))
(list tpl-mode-comment
'(1 font-lock-comment-face))
(list tpl-mode-include
'(1 font-lock-builtin-face))
(list tpl-mode-builtins
'(1 font-lock-variable-name-face))
(list tpl-mode-variable
'(1 font-lock-reference-face))
(list (concat "?\\(" tpl-mode-pair-tag "\\)")
'(1 font-lock-function-name-face))
(list (concat "<\\(" tpl-mode-standalone-tag "\\)")
'(1 font-lock-function-name-face))
(list tpl-mode-html-constant
'(1 font-lock-variable-name-face))
))
(put 'tpl-mode 'font-lock-defaults '(tpl-font-lock-keywords nil t))
(defun tpl-mode ()
"Major mode for editing CTemplate file."
(interactive)
(kill-all-local-variables)
(use-local-map tpl-mode-map)
(setq major-mode 'tpl-mode)
(setq mode-name "tpl-mode")
(setq local-abbrev-table tpl-mode-abbrev-table)
(setq indent-tabs-mode nil)
(set-syntax-table tpl-mode-syntax-table)
; show trailing whitespace, but only when the user can fix it
(setq show-trailing-whitespace (not buffer-read-only))
(make-local-variable 'indent-line-function)
(setq indent-line-function 'tpl-indent)
(setq font-lock-defaults '(tpl-mode-font-lock-keywords))
(run-hooks 'tpl-mode-hook)
)
(provide 'tpl-mode)
ctemplate-ctemplate-2.4/ctemplate.sln 0000775 0000000 0000000 00000017507 13631223166 0020025 0 ustar 00root root 0000000 0000000 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libctemplate", "vsprojects\libctemplate\libctemplate.vcxproj", "{FB27FBDB-E6C0-4D00-A7F8-1EEEF1B48ABC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compile_test", "vsprojects\compile_test\compile_test.vcxproj", "{4B263748-5F0F-468C-8C5C-ED2682BB6BE3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_dictionary_unittest", "vsprojects\template_dictionary_unittest\template_dictionary_unittest.vcxproj", "{9160CC7F-3BC6-49F1-A158-70DF579376CA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_modifiers_unittest", "vsprojects\template_modifiers_unittest\template_modifiers_unittest.vcxproj", "{D9E45FD2-07AC-4EE8-9DA4-26E0427D619E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_regtest", "vsprojects\template_regtest\template_regtest.vcxproj", "{0072B37E-DCDA-4128-BC12-7C0A7EF59016}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_setglobals_unittest", "vsprojects\template_setglobals_unittest\template_setglobals_unittest.vcxproj", "{686099C0-A778-4D27-80B5-A7E051658D2F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_cache_test", "vsprojects\template_cache_test\template_cache_test.vcxproj", "{5105C0FF-C28A-480B-8298-A66AB4F1F0C0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_unittest", "vsprojects\template_unittest\template_unittest.vcxproj", "{5105C0FF-C28A-480B-8298-A66AB4F1F0CD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_unittest_static", "vsprojects\template_unittest_static\template_unittest_static.vcxproj", "{ED69C82B-F593-418A-8D17-C64CBB11E603}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_tpl_varname_h", "vsprojects\make_tpl_varname_h\make_tpl_varname_h.vcxproj", "{CFD560F2-1B16-4CEE-985D-B19FDE74513F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "diff_tpl_auto_escape", "vsprojects\diff_tpl_auto_escape\diff_tpl_auto_escape.vcxproj", "{72CD1C2A-56F6-4DDA-957B-BCF181BB558E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "template_test_util_test", "vsprojects\template_test_util_test\template_test_util_test.vcxproj", "{87132061-D584-4388-A80B-D8560F8D0895}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "statemachine_test", "vsprojects\statemachine_test\statemachine_test.vcxproj", "{A105C0FF-C28A-480B-8298-A66AB4F1F0CD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "htmlparser_test", "vsprojects\htmlparser_test\htmlparser_test.vcxproj", "{B105C0FF-C28A-480B-8298-A66AB4F1F0CD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_fsm_c_test", "vsprojects\generate_fsm_c_test\generate_fsm_c_test.vcxproj", "{8FB1935F-FC23-465D-8C18-C1466A99D08D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FB27FBDB-E6C0-4D00-A7F8-1EEEF1B48ABC}.Debug|x86.ActiveCfg = Debug|Win32
{FB27FBDB-E6C0-4D00-A7F8-1EEEF1B48ABC}.Debug|x86.Build.0 = Debug|Win32
{FB27FBDB-E6C0-4D00-A7F8-1EEEF1B48ABC}.Release|x86.ActiveCfg = Release|Win32
{FB27FBDB-E6C0-4D00-A7F8-1EEEF1B48ABC}.Release|x86.Build.0 = Release|Win32
{4B263748-5F0F-468C-8C5C-ED2682BB6BE3}.Debug|x86.ActiveCfg = Debug|Win32
{4B263748-5F0F-468C-8C5C-ED2682BB6BE3}.Debug|x86.Build.0 = Debug|Win32
{4B263748-5F0F-468C-8C5C-ED2682BB6BE3}.Release|x86.ActiveCfg = Release|Win32
{4B263748-5F0F-468C-8C5C-ED2682BB6BE3}.Release|x86.Build.0 = Release|Win32
{9160CC7F-3BC6-49F1-A158-70DF579376CA}.Debug|x86.ActiveCfg = Debug|Win32
{9160CC7F-3BC6-49F1-A158-70DF579376CA}.Debug|x86.Build.0 = Debug|Win32
{9160CC7F-3BC6-49F1-A158-70DF579376CA}.Release|x86.ActiveCfg = Release|Win32
{9160CC7F-3BC6-49F1-A158-70DF579376CA}.Release|x86.Build.0 = Release|Win32
{D9E45FD2-07AC-4EE8-9DA4-26E0427D619E}.Debug|x86.ActiveCfg = Debug|Win32
{D9E45FD2-07AC-4EE8-9DA4-26E0427D619E}.Debug|x86.Build.0 = Debug|Win32
{D9E45FD2-07AC-4EE8-9DA4-26E0427D619E}.Release|x86.ActiveCfg = Release|Win32
{D9E45FD2-07AC-4EE8-9DA4-26E0427D619E}.Release|x86.Build.0 = Release|Win32
{0072B37E-DCDA-4128-BC12-7C0A7EF59016}.Debug|x86.ActiveCfg = Debug|Win32
{0072B37E-DCDA-4128-BC12-7C0A7EF59016}.Debug|x86.Build.0 = Debug|Win32
{0072B37E-DCDA-4128-BC12-7C0A7EF59016}.Release|x86.ActiveCfg = Release|Win32
{0072B37E-DCDA-4128-BC12-7C0A7EF59016}.Release|x86.Build.0 = Release|Win32
{686099C0-A778-4D27-80B5-A7E051658D2F}.Debug|x86.ActiveCfg = Debug|Win32
{686099C0-A778-4D27-80B5-A7E051658D2F}.Debug|x86.Build.0 = Debug|Win32
{686099C0-A778-4D27-80B5-A7E051658D2F}.Release|x86.ActiveCfg = Release|Win32
{686099C0-A778-4D27-80B5-A7E051658D2F}.Release|x86.Build.0 = Release|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0C0}.Debug|x86.ActiveCfg = Debug|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0C0}.Debug|x86.Build.0 = Debug|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0C0}.Release|x86.ActiveCfg = Release|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0C0}.Release|x86.Build.0 = Release|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Debug|x86.ActiveCfg = Debug|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Debug|x86.Build.0 = Debug|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Release|x86.ActiveCfg = Release|Win32
{5105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Release|x86.Build.0 = Release|Win32
{ED69C82B-F593-418A-8D17-C64CBB11E603}.Debug|x86.ActiveCfg = Debug|Win32
{ED69C82B-F593-418A-8D17-C64CBB11E603}.Debug|x86.Build.0 = Debug|Win32
{ED69C82B-F593-418A-8D17-C64CBB11E603}.Release|x86.ActiveCfg = Release|Win32
{ED69C82B-F593-418A-8D17-C64CBB11E603}.Release|x86.Build.0 = Release|Win32
{CFD560F2-1B16-4CEE-985D-B19FDE74513F}.Debug|x86.ActiveCfg = Debug|Win32
{CFD560F2-1B16-4CEE-985D-B19FDE74513F}.Debug|x86.Build.0 = Debug|Win32
{CFD560F2-1B16-4CEE-985D-B19FDE74513F}.Release|x86.ActiveCfg = Release|Win32
{CFD560F2-1B16-4CEE-985D-B19FDE74513F}.Release|x86.Build.0 = Release|Win32
{72CD1C2A-56F6-4DDA-957B-BCF181BB558E}.Debug|x86.ActiveCfg = Debug|Win32
{72CD1C2A-56F6-4DDA-957B-BCF181BB558E}.Debug|x86.Build.0 = Debug|Win32
{72CD1C2A-56F6-4DDA-957B-BCF181BB558E}.Release|x86.ActiveCfg = Release|Win32
{72CD1C2A-56F6-4DDA-957B-BCF181BB558E}.Release|x86.Build.0 = Release|Win32
{87132061-D584-4388-A80B-D8560F8D0895}.Debug|x86.ActiveCfg = Debug|Win32
{87132061-D584-4388-A80B-D8560F8D0895}.Debug|x86.Build.0 = Debug|Win32
{87132061-D584-4388-A80B-D8560F8D0895}.Release|x86.ActiveCfg = Release|Win32
{87132061-D584-4388-A80B-D8560F8D0895}.Release|x86.Build.0 = Release|Win32
{A105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Debug|x86.ActiveCfg = Debug|Win32
{A105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Debug|x86.Build.0 = Debug|Win32
{A105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Release|x86.ActiveCfg = Release|Win32
{A105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Release|x86.Build.0 = Release|Win32
{B105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Debug|x86.ActiveCfg = Debug|Win32
{B105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Debug|x86.Build.0 = Debug|Win32
{B105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Release|x86.ActiveCfg = Release|Win32
{B105C0FF-C28A-480B-8298-A66AB4F1F0CD}.Release|x86.Build.0 = Release|Win32
{8FB1935F-FC23-465D-8C18-C1466A99D08D}.Debug|x86.ActiveCfg = Debug|Win32
{8FB1935F-FC23-465D-8C18-C1466A99D08D}.Debug|x86.Build.0 = Debug|Win32
{8FB1935F-FC23-465D-8C18-C1466A99D08D}.Release|x86.ActiveCfg = Release|Win32
{8FB1935F-FC23-465D-8C18-C1466A99D08D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
ctemplate-ctemplate-2.4/doc/ 0000775 0000000 0000000 00000000000 13631223166 0016061 5 ustar 00root root 0000000 0000000 ctemplate-ctemplate-2.4/doc/auto_escape.html 0000664 0000000 0000000 00000037006 13631223166 0021245 0 ustar 00root root 0000000 0000000
Guide to using Auto Escape
Guide to using Auto Escape
Introduction
Auto Escape is an optional mode of execution in the Template System
developed to provide a better defense against cross-site scripting (XSS)
in web applications. In this mode, the Template System assumes
responsibility for applying the proper escaping modifiers for each
variable in your template (and templates it may include). As such, the
template developer no longer needs to manually apply escaping modifiers
to each variable, a process which is repetitive and error-prone
particularly in larger and more complex applications.
In order for the Template System to properly determine the escaping
modifiers to apply to variables, it activates a built-in HTML-aware
parser during template initialization. The parser scans the template
to determines the context in which each variable is being emitted.
The scanning is performed at initialization-time only hence does not
contribute to processing costs at template expansion time.
Refer to Security Considerations
for additional security information on escaping directives and their
use according to the context in which content is being expanded.
Current Status
Auto Escape currently supports well HTML and
Javascript templates. It also provides very basic support
for CSS, JSON and XML templates
where it applies the corresponding escaping modifier but without
utilizing a parser. We may in the future provide parsers specific
to these contexts and modifiers for them that are finer-grained.
Overview
This section provides more background on Auto Escape.
Refer to How to Auto Escape
for information on how to leverage this mode in your application.
Using template modifiers
In the simplest case, where you only want to use template-modifiers
to achieve html-safety (that is, you only use
html_escape, url_query_escape, and so
forth), you can stop specifying template-modifiers in your template at
all. The Auto Escape mode will generate the modifiers on its own and
perform the correct escaping.
If you need other types of modifiers, including your own custom
modifiers, you can still specify them in your template and they will
continue to work just the same. The Auto Escape mode will simply apply
the appropriate escaping modifiers after your own.
Other reasons for manually specifying variable modifiers include:
To indicate a variable is safe. You may add the
:none modifier as the last modifier for a given
variable, in which case the Auto Escape mode will leave it
untouched and not apply escaping directives to it. Use only
when you are sure the variable is trusted to be safe from XSS.
To select a different escaping modifier from a list of
equivalent modifiers. Certain modifiers are equivalent from
an escaping point of view in that they would all ensure given
content is safe when escaped in a specific context. The
Auto Escape mode choses the most common escaping modifier for
that use but allows you to indicate a different choice as shown
below:
TemplateContext
Primary Modifier
Accepted alternatives
TC_HTML
:html_escape
:pre_escape
:html_escape_with_arg=snippet
:html_escape_with_arg=attribute
:html_escape_with_arg=url
:url_query_escape
:url_escape_with_arg=html
:img_src_url_escape_with_arg=html
TC_HTML and TC_CSS
:cleanse_css
:url_escape_with_arg=css
:img_src_url_escape_with_arg=css
TC_XML
:xml_escape
:html_escape
:html_escape_with_arg=attribute
TC_JS
:javascript_escape
:url_escape_with_arg=javascript
:img_src_url_escape_with_arg=javascript
TC_JSON
:javascript_escape
:json_escape
To add additional escaping modifiers. The Template System will
never remove escaping directives you explicitly specify.
The table belows indicates which modifier Auto-Escape selects to
escape a given variable, based on the context of the variable being
inserted and, possibly, on more specific information such as whether
the variable is inside quotation marks. The table only applies for
the well-supported TemplateContext values (currently
TC_HTML and TC_JS).
In a few cases, we do not have
a modifier that is both safe against XSS and respecting of
the semantics of the variable therefore we fail the template
initialization. An error is logged indicating the cause of
the failure.
Context
HTML Quoted?
Examples
Action Performed
Regular HTML Body and HTML comments
Any
<p>Hello {{USER}}</p>
Escape USER using
:html_escape
In URL attribute: Starts at pos 0
Yes
<a href="{{URL}}">;
Escape URL using
:url_escape_with_arg=html
In URL attribute: Other
Yes
<a href="/foo?q={{QUERY}}">
Escape QUERY using
:html_escape
In URL attribute: Starting at pos 0
No
<form action={{URL}}>
Fail template initialization
In URL attribute: Other
No
<a href=/foo?q={{QUERY}}>My Link</a>
Escape QUERY using
:url_query_escape
In STYLE attribute
Yes
<div style="color:{{COLOR}};">
Escape COLOR using
:cleanse_css
In STYLE attribute
No
<div style=color:{{COLOR}};>
Fail template initialization
In Javascript attribute: String literal
Yes
<a href="url" onclick="doFoo('{{ARG}}');">
Escape ARG using
:javascript_escape
In Javascript attribute: Non-string literal
Yes
<a href="url" onclick="doFoo({{ARG}});">
Escape ARG using
:javascript_escape_with_arg=number
In Javascript attribute: Any
No
<a href="url" onclick=doFoo('{{ARG}}');>
Fail template initialization.
In all other attributes
Yes
<b class="{{CLASS}}">
Escape CLASS using
:html_escape
In all other attributes
No
<table border={{BORDER}}>
Escape BORDER using
:html_escape_with_arg=attribute
In Javascript code: In a string literal
Any
<script>var a = '{{VALUE}}';</script>
Escape VALUE using
:javascript_escape
In Javascript code: Non-string literal
Any
<script>var a = {{VALUE}};</script>
Escape VALUE using
:javascript_escape_with_arg=number
In a <style> tag
Any
<style>font-size={{FONTSIZE}};</style>
Escape FONTSIZE using
:cleanse_css
Comments:
For values of URL-accepting attributes, we apply a different
modifier if the variable is at the beginning of the attribute
value or not because in the former case we consider the
variable to represent a complete URL and hence also check
that its scheme is safe (HTTP or
HTTPS).
We recommend that you enclose attribute values in quotes
in particular:
Under some conditions outlined in the table above, when
variables are present in attribute values that are not
enclosed in quotes, we may fail template initialization
because we do not have escaping modifiers that are safe to
use.
Also the determination of which escaping modifier
to apply for unquoted attribute values specifically
is likely to change in the future.
The Auto Escape mode is designed to be simple to use and to produce
correct correct escaping with minimal input. It does however come with
restrictions governing the use of this template system.
Templates may only be included in regular HTML
text. Including a template within HTML comments or inside an
HTML tag is currently not supported. In the example below,
HEADER and FOOTER are properly
included but TAG and COMMENT are
not.
If the template system detects that you are including a
template in another HTML context, it will log a warning.
Included templates may not cross HTML boundaries. They
cannot start with one TemplateContext and end in
another. For example, the template below crosses boundaries --
it starts in HTML and ends in Javascript -- and is therefore
not a valid included template for auto-escaping.
<html>
<head>
</head>
<body>
Hello USER.
<script>
var a = 'not a nice template';
To rectify this violation, continue the template by
completing the javascript code and terminating it with a
</script> tag.
Error reporting. We currently report errors by logging
a warning or an error during initial template
initialization and parsing if we suspect something is
incorrect. Please check for them, as they indicate an error
that may cause auto-escaping to work improperly.
Beware of double escaping. When you use the Auto Escape mode,
you surrender all variable escaping to the template system.
If you also perform your own escaping in your source code, you may
face situations where content was escaped multiple times.
In particular, do not use any of the legacy methods below or
others that perform variable escaping.
SetEscapedValue
SetEscapedFormatttedValue
SetEscapedValueAndShowSection
Supported HTML contexts. HTML (TC_HTML) and
Javascript (TC_JS) templates are well supported.
Other template contexts have only basic support.
For these contexts, variables are escaped as follows:
TemplateContext
Escaping Applied
TC_JSON
:javascript_escape
TC_XML
:xml_escape
TC_CSS
:cleanse_css
New restrictions on the use of BI_SPACE and
BI_NEWLINE. These system variables may not be
re-assigned to a semantically different value via
dict->SetValue or related methods, and they may
not have modifiers attached to them in templates. For
instance: it's ok to redefine BI_NEWLINE from
\n to \r\n, since html treats them
identically. But changing it to hello, world! is
not allowed.
A new filename convention
The Auto Escape feature codifies simple conventions
of template filenames:
CSS templates optionally include, in their filename, the
keywords style or stylesheet or
css.
Javascript templates optionally include, in their filename, the
keywords js or javascript.
If we find one of these keywords in the filename but
it does not match the template type given, we log a warning.
One reason this example is so simple is that it doesn't even
require a separate template file, but instead uses
StringToTemplateCache(). It also doesn't use sections or
template-includes.
Note: If this template was intended to run in a web application, you can
leverage the functionality provided by the auto-escape mode. Simply add
the AUTOESCAPE pragma directive at the top of the template text and your
variables will be automatically escaped for the context you specify.
For example, if your template is returned in an HTML context,
change the template_text declaration as follows:
This maybe-show-text functionality is one way the template
machinery is more powerful than just using printf.
Another nice property of templates is you can reuse the same variable
multiple times in your template string. You can also define the
variable values in any order.
Search Results Page
Here is an example template that could be used to format a Google
search results page:
{{>HEADER}}
<body bgcolor=white>
{{>PAGE_HEADING}}{{!The following div must be on the same line}}<div>
{{!The ONE_RESULT section displays a single search item}}
{{#ONE_RESULT}}
{{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
{{#SUBITEM_SECTION}}<blockquote>{{/SUBITEM_SECTION}}
{{! LEAD_LINE is received HTML-escaped from the backend.}}
<p><a href="{{JUMP_TO_URL:html_escape}}" target=nw>{{LEAD_LINE}}</a><font size=-1>
{{! SNIPPET1, SNIPPET2 are HTML-escaped in the snippet generator.}}
{{#SNIPPET1_SECTION}}
<br>{{SNIPPET1}}
{{/SNIPPET1_SECTION}}
{{#SNIPPET2_SECTION}}
<br>{{SNIPPET2}}
{{/SNIPPET2_SECTION}}
{{#DESCRIPTION_SECTION}}
{{! DESC is received HTML-escaped from the backend.}}
<br><span class=f>Description:</span> {{DESC}}
{{/DESCRIPTION_SECTION}}
{{#CATEGORY_SECTION}}
<br><span class=f>Category:</span> <a href="{{CAT_URL:html_escape}}" class=f>
{{CATEGORY:html_escape}}</a>
{{/CATEGORY_SECTION}}
{{#LASTLINE_SECTION}}
<br><font color="{{ALT_TEXT_COLOR:h}}">{{URL:h}}
{{#KS_SECTION}}} - {{KSIZE:h}}{{/KS_SECTION}}}
{{#CACHE_SECTION}}} - <a href="{{CACHE_URL:h}}" class=f>Cached</A>
{{/CACHE_SECTION}}}
{{#SIM_SECTION}}} - <a href="{{SIM_PAGES_URL:h}}" class=f>Similar pages</A>
{{/SIM_SECTION}}}
{{#STOCK_SECTION}}
- <a href="{{STOCK_URL:h}}" class=f>Stock quotes: {{STOCK_SYMBOL:h}}</a>
{{/STOCK_SECTION}}
</font>
{{/LASTLINE_SECTION}}
{{#MORE_SECTION}}
<br>[ <a href="{{MORE_URL:h}}" class=f>More results from {{MORE_LABEL:h}}</a> ]
{{/MORE_SECTION}}
</font><br>
{{! Note: there are two SUBITEM_SECTIONs. They both show or hide together}}
{{#SUBITEM_SECTION}}</blockquote>{{/SUBITEM_SECTION}}
{{/ONE_RESULT}}
</div> {{! this /div closes the div at the top of this file}}
{{>PAGE_FOOTING}}
Here is a sample procedure that could populate a dictionary for
expanding that template. The "one procedure" entry point is
fill_search_results_dictionary. The
SetTemplateValues function is a separate entry point for
initializing each top-level template with some standard values.
#include "template.h"
RegisterTemplateFilename(SEARCH_RESULTS_FN, "search_results.tpl");
#include "search_results.tpl.varnames.h" // defines ksr_HEADER, etc.
using ctemplate::TemplateDictionary;
using ctemplate::ExpandTemplate;
using ctemplate::STRIP_WHITESPACE;
// IsEmpty
// A simple utility function
static bool IsEmpty(const string &str) {
return str.empty();
}
// SetTemplateValues
// Use the TemplateDictionary object to set template-wide values that
// may be used in the top-level template and all its sub-sections
// and included templates. The template-wide values are all
// colors from the Palette object
void SetTemplateValues(TemplateDictionary *dictionary, const Palette* colors) {
// better would be to use ksr_LINK_COLOR, etc, assuming those are
// defined in search_results.tpl.varnames.h. But using literal
// text, as here, is legal as well.
dictionary->SetValue("LINK_COLOR", colors->link_color);
dictionary->SetValue("BAR_TEXT_COLOR", colors->bar_text_color);
dictionary->SetValue("TEXT_COLOR", colors->text_color);
dictionary->SetValue("FAINT_COLOR", colors->faint_color);
dictionary->SetValue("IMPORTANT_COLOR", colors->important_color);
dictionary->SetValue("BAR_COLOR", colors->bar_color);
dictionary->SetValue("ALT_TEXT_COLOR", colors->alt_text_color);
dictionary->SetValue("ALINK_COLOR", colors->alink_color);
dictionary->SetValue("VLINK_COLOR", colors->vlink_color);
}
// fill_search_results_dictionary
// Iterates through all the QueryResults contained in the Query object.
// For each one, it sets corresponding template dictionary values
// (or hides sections containing their variables, if appropriate) in
// a sub-dictionary and then adds that dictionary to the parent
void fill_search_results_dictionary(TemplateDictionary *dictionary,
const Query *query) {
dictionary->SetFilename(SEARCH_RESULTS_FN);
// These two functions are defined elsewhere
fill_header_dictionary(dictionary->AddIncludeDictionary(ksr_HEADER));
fill_page_heading_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_HEADING),
query);
ResultsList *results = query->GetResults();
int resCount = 0;
for (ResultsList::const_iterator iter = results->begin();
iter != results->end();
++iter) {
QueryResult *qr = (*iter);
// Create a new sub-dictionary named "Result Dict <n>" for this entry
++resCount;
TemplateDictionary *result_dictionary =
dictionary->AddSectionDictionary(ksr_ONE_RESULT);
result_dictionary->SetValue(ksr_JUMP_TO_URL, qr->GetUrl());
if (qr->IsSubItem()) {
result_dictionary->ShowSection(ksr_SUBITEM_SECTION);
}
result_dictionary->SetValue(ksr_LEAD_LINE, qr->GetLeadLine());
result_dictionary->SetValueAndShowSection(ksr_SNIPPET1, qr->GetSnippet1(),
ksr_SNIPPET1_SECTION);
result_dictionary->SetValueAndShowSection(ksr_SNIPPET2, qr->GetSnippet2(),
ksr_SNIPPET2_SECTION);
result_dictionary->SetValueAndShowSection(ksr_DESC, qr->GetDescription(),
ksr_DESCRIPTION_SECTION);
result_dictionary->SetValueAndShowSection(ksr_CAT_URL, qr->GetCategoryUrl(),
ksr_CATEGORY_SECTION);
result_dictionary->SetValueAndShowSection("CATEGORY", qr->GetCategoryName(),
"CATEGORY_SECTION");
if (IsEmpty(qr->GetDisplayUrl()) &&
IsEmpty(qr->GetPageSize()) &&
IsEmpty(qr->GetCachedUrl()) &&
IsEmpty(qr->GetSimilarPagesUrl()) &&
(IsEmpty(qr->GetStockUrl()) ||
IsEmpty(qr->GetStockSymbol())) ) {
// there is nothing on the last line, so hide it altogether
} else {
result_dictionary->ShowSection("LASTLINE_SECTION");
result_dictionary->SetValue(ksr_URL, qr->GetDisplayUrl());
result_dictionary->SetValueAndShowSection(ksr_KSIZE, qr->GetPageSize(),
ksr_KS_SECTION);
result_dictionary->SetValueAndShowSection(ksr_CACHE_URL, qr->GetCachedUrl(),
ksr_CACHE_SECTION);
result_dictionary->SetValueAndShowSection(ksr_SIM_PAGES_URL,
qr->GetSimilarPagesUrl(),
ksr_SIM_SECTION);
result_dictionary->SetValueAndShowSection(ksr_STOCK_URL, qr->GetStockUrl(),
ksr_STOCK_SECTION);
result_dictionary->SetValueAndShowSection(ksr_STOCK_SYMBOL,
qr->GetStockSymbol(),
ksr_STOCK_SECTION);
}
result_dictionary->SetValueAndShowSection(ksr_MORE_URL, qr->GetMoreUrl(),
ksr_MORE_SECTION);
result_dictionary->SetValueAndShowSection(ksr_MORE_LABEL, qr->GetMoreLabel(),
ksr_MORE_SECTION);
}
fill_page_footing_dictionary(dictionary->AddIncludeDictionary(ksr_PAGE_FOOTING),
query);
}
void output_page(const Query* query) {
TemplateDictionary dict("search-results dict");
string output;
fill_search_results_dictionary(&dict, query);
ctemplate::ExpandTemplate(SEARCH_RESULTS_FN, STRIP_WHITESPACE, &dict, &output);
// output now holds the expanded template
}
Craig Silverstein
ctemplate-ctemplate-2.4/doc/guide.html 0000664 0000000 0000000 00000127144 13631223166 0020055 0 ustar 00root root 0000000 0000000
How To Use the Ctemplate (formerly Google Template) System
How To Use the Ctemplate (formerly Google Template) System
(as of
)
Motivation
A template system can be used to separate output formatting
specifications, which govern the appearance and location of output
text and data elements, from the executable logic which prepares the
data and makes decisions about what appears in the output.
Template systems lie along a continuum of power versus separation.
"Powerful" constructs like variable assignment or conditional
statements make it easy to modify the look of an application within
the template system exclusively, without having to modify any of the
underlying "application logic". They do so, however, at the cost of
separation, turning the templates themselves into part of the
application logic.
This template system leans strongly towards preserving the
separation of logic and presentation. It is intentionally constrained
in the features it supports and, as a result, applications tend to
require quite a bit of code to instantiate a template. This may not
be to everybody's tastes. However, while this design limits the power
of the template language, it does not limit the power or
flexibility of the template system. This system supports
arbitrarily complex text formatting. Many Google applications,
including the "main" Google web search, use this system
for formatting output.
Finally, this system is designed with an eye towards efficiency.
Template instantiation is very quick, with an eye towards minimizing
both memory use and memory fragmentation.
Overview
There are two main parts to the Ctemplate System:
Templates
Data dictionaries
The templates are text files that contain the format specification
for the formatted output, i.e, the template language. The data
dictionaries contain the mappings from the template elements (markers)
embedded in the templates to the data that they will format. Here's
a simple template:
Here's a dictionary that one could use to instantiate the template:
{"TITLE": "Template example",
"BODY": "This is a simple template example.\nIt's boring",
"DATE": "11/20/2005"}
If we instantiated the template with this dictionary (a process we
call "expanding"), here's the output we would get:
<html><head><title>Template example</title></head>
<body>This is a simple template example.
It's boring</body></html>
{{TITLE}} and {{BODY}} are template
elements, also called markers. In the dictionary,
TITLE, BODY, and DATE are
dictionary names, and the values associated with each one, such
as 11/20/2005, are dictionary values.
A few points are clear even from this simple example:
Dictionary keys and values are strings; the Ctemplate
system is not typed.
Dictionary values come already formatted. It was up to the
application code to decide how to format the value for
DATE, and to insert the date into the dictionary
already formatted.
Not all dictionary values must be used by a template.
DATE is entirely ignored.
Not all template elements may exist in the dictionary. In this
example, {{META_TAGS}} is not found in the
dictionary. This is perfectly legal; missing dictionary names
evaluate to the empty string.
Templates
The template language has four major types of markers (the full
list of marker types is described in the reference guide):
Variable markers, which are replaced by text based on
dictionary values. All markers in the above example are
variable markers. Variable markers look like this:
{{FOO}}
Start section and end section markers, which delimit
sections which may appear zero, one, or N times in
the output. The number of times a section appears is
determined by the data dictionaries, as explained below.
Each time a section is expanded, it uses a different
dictionary, so that the output values may be different from one
iteration of a section expansion to another. Note that the
specification of how sections expand is entirely dependent on
the dictionary, as set up by the application; there is no way
to specify a repeat count in the template language itself.
Section markers look like this:
{{#FOO}}...{{/FOO}}
Template-include markers, which designate other templates to be
expanded and inserted at the location where the marker appears.
These are treated much like sections -- one may think of them
as sections whose content is specified in a
different file instead of inline -- and just like sections, can
be expanded zero, one or N times in the output, each with a
different dictionary and even a different include-file.
Template-include markers look like this:
{{>FOO}}
Comment markers, which may annotate the template
structure but drop completely out of the expanded
output. Comment markers look like this:
{{! comment lives here -- cool, no?}}
These marker types each have their own namespace. For readability,
however, it is best to not overuse a single name.
Anything found in a template of the form {{...}} is
interpreted as a template marker. All other text is considered
formatting text and is output verbatim at template expansion time.
Formatting text may consist of HTML tags, XML tags, linefeeds and
other spacing characters, constant text, etc.
Data Dictionaries
A data dictionary is a map from keys to values. The keys are
always strings, each string representing either a variable, a section,
or a template-include file. (Comments are not stored in the data
dictionary!) These values correspond to the name of the associated
template marker: a section {{#FOO}} in the template text
is matched to the key "FOO" in the dictionary, if it
exists. Note the case must match as well.
The value associated with a key differs according to key type. The
value associated with a variable is simple: it's the value for
that variable. Both keys and values can be any 8-bit
character-string, and may include internal NULs (\0).
The value associated with a section is more complicated, and
somewhat recursive: it's a list of data dictionaries. Come
template-expansion time, the section is expanded once for each
dictionary in the list, so if there are two dictionaries in the list,
then the section text will occur in the output twice. The first time,
all variables/etc. in the section will be evaluated taking into
account the first dictionary. The second time, all
variables/etc. will be evaluated taking into account the second
dictionary. (See below for a definition of
"taking into account.")
A template-include is a special type of section, so the
associated value is the same: a list of dictionaries.
Template-includes also have one other, mandatory associated piece of
information: the filename of the template to include.
The application program is responsible for building this data
dictionary, including all nesting. It then applies this dictionary to
a single template to produce formatted output.
Expanding a Template
A program using Ctemplate typically reads in templates at
load time. During the course of program execution, the program will
repeatedly perform the following two steps: first, instantiate a data
dictionary, and second, apply the dictionary to the template to
produce output.
The template system applies a dictionary to a template by finding
all template markers in the template, and replacing them with the
appropriate dictionary values. It matches template markers to
dictionary keys in the obvious way. For instance, a template marker
{{FOO}} matches the dictionary key FOO. The
marker {{#BAR}} matches the dictionary key
BAR, as does the marker {{/BAR}}. The
marker {{>BAZ}} matches the dictionary key
BAZ. (And of course, the marker {{!
comment}} doesn't match any dictionary key at all.)
If no dictionary key is found for a given template marker, then the
template marker is ignored: if a variable, it expands to the empty
string; if a section or include-template, the section or
include-template is expanded zero times.
All names are case sensitive. Names -- that is, variable keys and,
as a result, template markers -- must be made of (7-bit ascii)
alphanumeric characters and the underscore. The comment marker,
which does not map to dictionary keys, may contain any characters
whatsoever except }, the close-curly brace. It's a
syntax error for any template marker to violate this rule.
Outside of the template markers, templates may contain any text
whatsoever, including (single) curly braces and NUL characters.
The Auto Escape mode helps protect against cross-site scripting
(XSS) attacks in web-applications by automatically escaping variables
in your template. The Guide to using Auto
Escape has an overview of Auto Escape as well as discussion of its
limitations.
Auto Escape is enabled on a template-by-template basis. Simply add
the AUTOESCAPE pragma to the desired template. That template will then
be automatically escaped, independently of the templates it may
include or it may be included from. The AUTOESCAPE pragma must be
placed at the top of the template. It takes a 'context' argument
saying what context the template is used in: html, javascript, css,
xml, etc. (There's also a state=IN_TAG argument that is
used when the template is just a snippet of html intended for use in a
tag.) See the reference
guide for a full description of autoescape arguments.
The table below shows four small sample templates along with their
corresponding AUTOESCAPE pragma. The two most common contexts are
HTML and JAVASCRIPT. We also show a sample
template for the CSS context as well as a sample template
for the IN_TAG state of HTML
(although it is expected to be rarely used).
Auto-escaping works by automatically applying modifiers to
every variable in the template. You can manually apply modifiers as
well, and even define your own. See the reference guide for a full
discussion of modifiers and how to use them.
The dictionary structure is a tree: there's a 'main' dictionary,
and then a list of sub-dictionaries for each section or
include-template. Even with all this complexity, the lookup rules are
mostly straightforward: when looking up a marker -- be it a variable,
section, or include-template marker -- the system looks in the
currently applicable dictionary. If it's found there, great. If not,
and the parent dictionary is not an include-template, it continues the
look in the parent dictionary, and possibly the grandparent, etc.
That is, lookup has static scoping: you look in your dictionary
and any parent dictionary that is associated with the same
template-file. As soon as continuing the lookup would require you to
jump to a new template-file (which is what include-template would do),
we stop the lookup.
For instance, for a template that says
{{#RESULTS}}{{RESULTNUM}}. {{>ONE_RESULT}}{{/RESULTS}},
"ONE_RESULT" is looked for in the "RESULTS" dictionary,
and if not found there, is looked for in the main, top-level
dictionary. Likewise, the variable "RESULTNUM" is looked
for first in the "RESULTS" dictionary, then in the main dictionary if
necessary. However, "ONE_RESULT" will not do equivalent cascading
lookups. In fact, it will have no parent dictionaries at all, because
it's a different template file and thus in a different scope.
Because of these scoping rules, it's perfectly reasonable to set
all variables that are needed in a given template file, in the
top-level dictionary for that template. In fact, the ShowSection() function is provided to
support just this idiom. To avoid confusion in such a usage mode,
it's strongly encouraged that you give unique names to all sections
and include-templates in a single template file. (It's no problem,
given the template scoping rules, for a single section or
include-template name to be repeated across different template
files.)
There's a single special case: the global variable
dictionary. Every dictionary inherits its initial set of values
from the global dictionary. Clients can set
variables in the global dictionary just like they can in normal
template dictionaries they create.
The system initializes the global dictionary with a few useful
values for your convenience. All system variables are prefixed with
BI, to emphasize they are "built in" variables.
BI_SPACE, which has the value
<space>. It is used to force a space
at the beginning or end of a line in the template,
where it would normally be suppressed. (See below.)
BI_NEWLINE, which has the value
<newline> It is used to force a
newline at the end of a line, where it would normally
be suppressed. (See below.)
As is usual for inheritance, if a user explicitly assigns a value
to these variable-names in its own dictionary, this overrides the
inherited value. So, dict->SetValue("BI_SPACE",
" ") causes BI_SPACE to have the value
, rather than <space>, when
expanding dict.
Note that only variables can be inherited from the global
dictionary, not section dictionaries or include-file dictionaries.
A couple of small implementation notes: global inheritance is "last
chance", so if a section's parent dictionary redefined
BI_SPACE, say, the section dictionary inherits the
parent-dict value, not the global-dict value. Second, variable
inheritance happens at expand time, not at dictionary-create time. So
if you create a section dictionary, and then afterwards set a variable
in its parent dictionary (or in the global dictionary), the section
will inherit that variable value, if it doesn't define the
value itself.
Writing Application Code To Use Templates
Most application code concerns filling a template dictionary, but
there is also code for expanding templates given a dictionary. A
final category of code lets you inspect and control the template
system.
Creating A Template Dictionary
The class TemplateDictionary is used for all template
dictionary operations. new ctemplate::TemplateDictionary(name) is
used to create a new top-level dictionary.
dict->AddSectionDictionary(name) and
dict->AddIncludeDictionary(name) are used to create
sub-dictionaries for sections or include-files. After
creating a dictionary, the application should call one or more
functions for each marker in the template. As an example, consider
the following template:
<html><body> {{! This page has no head section.}}
{{#CHANGE_USER}}
<A HREF="/login">Click here</A> if you are not {{USERNAME}}<br>
{{/CHANGE_USER}}
Last five searches:<ol>
{{#PREV_SEARCHES}
<li> {{PREV_SEARCH}}
{{/PREV_SEARCHES}}
</ol>
{{>RESULT_TEMPLATE}}
{{FOOTER}}
</body></html>
To instantiate the template, the user should call a function to set
up FOOTER, and a function to say what to do for the
sections CHANGE_USER and PREV_SEARCHES, and
for the include-template RESULT_TEMPLATE. Quite likely,
the application will also want to create a sub-dictionary for
CHANGE_USER, and in that sub-dictionary call a function
to set up USERNAME. There will also be sub-dictionaries
for PREV_SEARCHES, each of which will need to set
PREV_SEARCH. Only when this is all set up will the
application be able to apply the dictionary to the template to get
output.
The appropriate function to call for a given template marker
depends on its type.
For variables, the only interesting action is to set the variable's
value. For most variables, the right method to call is
dict->SetValue(name, value). (The name and value
can be specified as strings in a variety of ways: C++ strings, char
*'s, or char *'s plus length.)
There are two other ways to set a variable's value as well, each
with a different scoping rule. You can call
ctemplate::TemplateDictionary::SetGlobalValue(name, value)
-- no TemplateDictionary instance needed here -- to set a
variable that can be used by all templates in an application. This
is quite rare.
You can also call dict->SetTemplateGlobalValue(name,
value). This sets a variable that is seen by all child
dictionaries of this dictionary: sub-sections you create via
AddSectionDictionary, and included templates you create
via AddIncludeDictionary (both described below). This
differs from SetValue(), because SetValue()
values are never inherited across template-includes. Almost always,
SetValue is what you want;
SetTemplateGlobalValue is intended for variables that are
"global" to a particular template tree not all template trees, such as
a color scheme to use, a language code, etc.
To make it easier to use SetValue(), there are a few
helper routines to help setting values of a few special forms.
SetIntValue(name, int): takes an int as the value.
SetFormattedValue(name, fmt, ...): the
fmt and ... work just like in
printf: SetFormattedValue("HOMEPAGE",
"http://%s/", hostname).
Example:
ctemplate::TemplateDictionary* dict = new ctemplate::TemplateDictionary("var example");
dict->SetValue("FOOTER", "Aren't these great results?");
Sections are used in two ways in templates. One is to expand some
text multiple times. This is how PREV_SEARCHES is used
in the example above. In this case we'll have one small
sub-dictionary for each of the five previous searches the user did.
To do this, call AddSectionDictionary(section_name)
to create the sub-dictionary. It returns a
TemplateDictionary* that you can use to fill the
sub-dictionary.
The other use of sections is to conditionally show or hide a block
of text at template-expand time. This is how CHANGE_USER
is used in the example template: if the user is logged in, we show the
section with the user's username, otherwise we choose not to show the
section.
This second case is a special case of the first, and the "standard"
way to show a section is to expand it exactly one time, by calling
AddSectionDictionary() once, and then setting
USERNAME in the sub-dictionary.
However, the hide/show idiom is so common there are a few
convenience methods to make it simpler. The first takes advantage of
the fact sections inherit variables from their parent: you set
USERNAME in the parent dictionary, rather than a section
sub-dictionary, and then call ShowSection(), which adds a
single, empty dictionary for that section. This causes the section to
be shown once, and to inherit all its variable values from its
parent.
A second convenience method is written for the particular case we
have with USERNAME: if the user's username is non-empty,
we wish to
show the section with USERNAME set to the username,
otherwise we wish to hide the section and show neither
USERNAME nor the text around it. The method
SetValueAndShowSection(name, value, section_name) does
exactly that: if value is non-empty, add a single dictionary to
section_name and call section_dict->AddValue(name,
value).
Example:
ctemplate::TemplateDictionary* dict = new ctemplate::TemplateDictionary("section example");
const char* username = GetUsername(); // returns "" for no user
if (username[0] != '\0') {
ctemplate::TemplateDictionary* sub_dict = dict->AddSectionDictionary("CHANGE_USER");
sub_dict->SetValue("USERNAME", username);
} else {
// don't need to do anything; we want a hidden section, which is the default
}
// Instead of the above 'if' statement, we could have done this:
if (username[0] != '\0') {
dict->ShowSection("CHANGE_USER"); // adds a single, empty dictionary
dict->SetValue("USERNAME", username); // take advantage of inheritance
} else {
// don't need to do anything; we want a hidden section, which is the default
}
// Or we could have done this:
dict->SetValueAndShowSection("USERNAME", username, "CHANGE_USER");
// Moving on...
GetPrevSearches(prev_searches, &num_prev_searches);
if (num_prev_searches > 0) {
for (int i = 0; i < num_prev_searches; ++i) {
TemplateDictionary* sub_dict = dict->AddSectionDictionary("PREV_SEARCHES");
sub_dict->SetValue("PREV_SEARCH", prev_searches[i]);
}
}
Template-includes
Template-include markers are much like section markers, so
AddIncludeDictionary(name) acts, not surprisingly,
exactly like AddSectionDictionary(name). However, since
variable inheritance doesn't work across include boundaries, there is
no template-include equivalent to ShowSection() or
SetValueAndShowSection().
One difference between template-includes and sections is that for a
sub-dictionary that you create via
AddIncludeDictionary(), you must call
subdict->SetFilename() to indicate the name of the
template to include. If you do not set this, the sub-dictionary will
be ignored. The filename may be absolute, or relative, in which case
it's relative to some entry in the template search path.
Example:
using ctemplate::TemplateDictionary;
TemplateDictionary* dict = new TemplateDictionary("include example");
GetResults(results, &num_results);
for (int i = 0; i < num_results; ++i) {
TemplateDictionary* sub_dict = dict->AddIncludeDictionary("RESULT_TEMPLATE");
sub_dict->SetFilename("results.tpl");
FillResultsTemplate(sub_dict, results[i]);
}
In practice, it's much more likely that
FillResultsTemplate() will be the one to call
SetFilename(). Note that it's not an error to call
SetFilename() on a dictionary even if the dictionary is
not being used for a template-include; in that case, the function is a
no-op, but is perhaps still useful as self-documenting code.
Another property of template-includes is that they set the indentation level
for the included template, that is, every line in the included template is
indented by the same amount as the template-includes line itself. For
instance, if you have a template PRINT_STUFF like this:
print "Hello!"
print "You are the 10th caller!"
print "Congratulations!"
and you include it in the template:
if ShouldPrintStuff():
{{>PRINT_STUFF}}
else:
pass
then when it is expanded, all three print lines will be indented,
not just the first one:
if ShouldPrintStuff():
print "Hello!"
print "You are the 10th caller!"
print "Congratulations!"
else:
pass
Note that this behavior is immaterial when using STRIP_WHITESPACE, since in that case
all leading whitespace is stripped.
Once you have a template dictionary, it's simplicity itself to
expand the template with those dictionary values, putting the output
in a string:
ctemplate::TemplateDictionary dict("debug-name");
FillDictionary(&dict, ...);
string output;
bool error_free = ctemplate::ExpandTemplate(<filename>, ctemplate::STRIP_WHITESPACE, &dict, &output);
// output now holds the expanded template.
// ExpandTemplate returns false if the system cannot load-and-parse
// <filename> or any of the template files referenced by the
// TemplateDictionary.
The first argument to ExpandTemplate is the filename
holding the template to expand (though there are ways to use non-file-based templates as well). The second argument
is the "strip" mode, which specifies how to treat whitespace in the
template. It can take the following values:
ctemplate::DO_NOT_STRIP: do nothing. This expands
the template file verbatim.
ctemplate::STRIP_BLANK_LINES: remove all blank
lines. This ignores any blank lines found in the template file
when parsing it. When the template is html, this reduces the
size of the output text without requiring a sacrifice of
readability for the input file.
ctemplate::STRIP_WHITESPACE: remove not only blank
lines when parsing, but also whitespace at the beginning and
end of each line. It also removes any linefeed (possibly
following whitespace) that follows a closing }} of
any kind of template marker except a template variable.
(This means a linefeed may be removed anywhere by simply
placing a comment marker as the last element on the line.)
When the template is html, this reduces the size of the output
html without changing the way it renders (except in a few
special cases.) When using this flag, the built-in template
variables BI_NEWLINE and BI_SPACE can
be useful to force a space or newline in a particular
situation.
The expanded template is written to the string output.
If output was not empty before calling
Expand(), the expanded template is appended to the end of
output.
There is also a "power user" version of
ExpandTemplate(), called ExpandWithData(),
that allows you to pass in per-expand data. Another "power user"
version allows you to expand the template into a custom output
container, rather than a string. See the reference guide for more
information about these advanced methods.
The first argument to ExpandTemplate is named
"filename", suggesting that the template has to be read from an
on-disk file. But in reality, the "filename" argument is just a key
into an internal cache. (By default, the template system looks on
disk to satisfy a cache miss, hence the "filename" to describe this
variable.) If you have a template specified in a string rather than a
file, you can manually insert it into the cache via
ctemplate::StringToTemplateCache().
StringToTemplateCache() parses the string you pass in
as if it were a template file, and inserts it into the global cache
with the key and strip-mode that you provide. You can then use this
key and strip-mode as the first two arguments to
ExpandTemplate. You can also use the key as the argument
to ctemplate::TemplateDictionary::SetFilename().
Prefer file-based to string-based templates where possible.
Updating a file-based template requires merely a data push, rather
than pushing the new executable, and it also makes it easier for
non-programmers to modify the template. One reason to use
string-based templates is if you are in an environment where having
data files could be dangerous—for instance, you work on a disk
that is usually full, or need the template to work even in the face of
disk I/O errors.
This package comes with a script, template-converter, that
takes a template file as input and emits a C++ code snippet (an .h
file) that defines a string with those template contents. This makes
it easy to start by using a normal, file-based template, and then
switch to StringToTemplateCache() later if you so
desire.
Copying a Template Dictionary
You can use the MakeCopy() method on a template
dictionary to make a "deep" copy of the template. This can be useful
for situations like the following: you want to fill a template several
times, each time with 90% of the values the same, but the last 10%
different. Computing the values is slow. Here's how you can use
MakeCopy() to do it:
fill dict with 90%
newdict1 = dict->MakeCopy();
fill newdict1 with last 10%
newdict2 = dict->MakeCopy();
fill newdict2 with last 10%
etc.
The Template Cache
When templates are loaded from disk, they are stored in an internal
template cache, which is used by ExpandTemplate() and
(most obviously) StringToTemplateCache(). You can define
your own template cache with the TemplateCache class.
This is an advanced technique used when you want to support having
several versions of a template file in memory at the same time (for
instance, a webserver might want to keep an old version of a template
file around until all old requests using that template are done being
serviced). It also supports advanced operations like removing a
template from the cache, and reloading templates from disk if they
have changed.
See the reference
manual for more details about the template cache.
Template and Threads
All expansion functions and static TemplateDictionary
methods are threadsafe: you can safely call
ctemplate::TemplateDictionary::SetGlobalValue()
without needing to worry about locking.
Non-static TemplateDictionary methods are not
thread-safe. It is not safe for two threads to assign values to the
same template-dictionary without doing their own locking. Note that
this is expected to be quite rare: usually only one thread will care
about a given template-dictionary.
Templates have the advantage that they separate the presentation of
your data from the application logic that generates the data.
Naturally, you want to do the same for testing: you would like to test
the application's logic in a way that is robust to changes in
the presentation.
The easiest way to test this logic is with unit tests that exercise
the functions in your code that fill template dictionaries. The class
ctemplate::TemplateDictionaryPeer in
template_test_util.h is designed to help you do exactly
that.
Here's a sample test using TemplateDictionaryPeer:
void MyTestMethod() {
// Create and populate the dictionary as your app normally would.
// In this case, we create a dict with data like this:
// { color:blue,
// shape_section: [
// { size:big, num_sides:7 },
// { size:big, num_sides:7 },
// { size:big, num_sides:7 }
// ]
// }
MyObject obj;
ctemplate::TemplateDictionary dict;
obj.FillDictionary(&dict);
// Create a TemplateDictionaryPeer to gain access to the dict contents.
ctemplate::TemplateDictionaryPeer peer(&dict);
// Expect color:blue at the top level of this dictionary.
EXPECT_STREQ("blue", peer.GetSectionValue("color"));
// Fetch sub-dictionaries from the dict.
vector<const ctemplate::TemplateDictionary*> shape_dicts;
peer.GetSectionDictionaries("shape_section", &shape_dicts);
EXPECT_EQ(3, shape_dicts.size());
for (int i = 0; i < 3; ++i) {
// Create another peer for each sub-dict, and assert that each sub-dict
// contains the expected data.
ctemplate::TemplateDictionaryPeer shape_peer(dicts[i]);
EXPECT_STREQ("big", shape_peer.GetSectionValue("size"));
EXPECT_STREQ("7", shape_peer.GetSectionValue("num_sides"));
}
}
Note that by using TemplateDictionaryPeer, you can
unit test the code for filling a TemplateDictionary
independent of the consuming Template.
The above tests your dictionary filling functions, but doesn't
touch the template expansion. Naturally, you may also want to test
the template itself. In this case, you will want to avoid using your
program's dictionary filling functions, and will instead provide a
custom dictionary in your test. There are a variety of properties you
might want to test about the template, but here are a few sample
tests:
void TestTemplateHTMLEscapesColor() {
// Populate a dictionary that lets us exercise the condition we're testing.
// In this case, that the 'color' tag will be HTML escaped.
ctemplate::TemplateDictionary dict("t1");
dict.SetValue("color", "<blue>");
// Expand the template with this dictionary.
string result;
ctemplate::ExpandTemplate(FLAGS_test_srcdir + "templates/my_template.html",
ctemplate::STRIP_WHITESPACE, &dict, &result);
// Assert that the expansion has the appropriate text in it.
EXPECT_THAT(result, HasSubstr("<blue>"));
}
void TestColorAppearsBeforeShape() {
// This time, the condition under test is that the "color" element of
// the dictionary appears before the "shape" element.
// Create an appropriate dictionary.
ctemplate::TemplateDictionary dict("t2"); // Note: use sufficiently unique
dict.SetValue("color", "white_asdf"); // strings that they won't occur
dict.SetValue("shape", "square_asdf"); // "bare" in the template.
string result;
ctemplate::ExpandTemplate(FLAGS_test_srcdir + "templates/my_template.html",
ctemplate::STRIP_WHITESPACE, &dict, &result);
// Assert that color comes before shape.
EXPECT_THAT(result, ContainsRegex("white_asdf.*square_asdf"));
}
Like all web applications, programs that use the Ctemplate
System to create HTML documents can be vulnerable to
Cross-Site-Scripting (XSS) attacks unless data inserted into a
template is appropriately sanitized and/or escaped. Which specific
form of escaping or sanitization is required depends on the context in
which the template variable appears within a HTML document (such as,
regular "inner text", within a <script> tag, or
within an onClick handler).
If you are concerned with XSS, your are strongly encouraged to
leverage the Auto Escape mode developed
specifically to better defend your application against XSS. The Auto
Escape mode follows the guidelines outlined below. Do note however
that regardless of whether you use Auto Escape or not, escaping alone
while generally required, is often not enough! You also may need to
sanitize or validate the input, as for instance with URL attributes.
For further information, refer to additional resources on Cross-Site-Scripting
issues.
The remainder of this section provides a brief summary of techniques
to prevent XSS vulnerabilities due to template variables in various
HTML contexts.
Regular text (outside of tags and other special situations).
Use the auto-escape pragma to html-escape the variable.
HTML tag attributes.
In addition to the auto-escape pragma, ensure that the
attribute is enclosed in double quotes in the template.
URL attributes (eg., href/src).
In addition to the auto-escape pragma, ensure that the
attribute is enclosed in double quotes in the template.
Beware of inserting variables containing data from untrusted
sources into the context of a style tag or
attribute.
Certain CSS style-sheet constructs can result in the
invocation of javascript. To prevent XSS, the variable must be
carefully validated and sanitized.
Populating javascript variables.
In addition to the auto-escape pragma, ensure that the
literal is enclosed in quotes in the template:
<script>
var msg_text = '{{MESSAGE}}';
</script>
Literals of non-string types cannot be quoted and escaped.
Instead, ensure that the variable's value is set such that it is
guaranteed that the resulting string corresponds to a javascript
literal of the expected type. For example, use
dict->SetValueInt("NUM_ITEMS", num_items);
to populate an integer javascript variable in the template
fragment
<script>
var num_items = {{NUM_ITEMS}};
</script>
Populating javascript variables within event handlers such as
onClick.
Tag attributes whose values are evaluated as a javascript
expression (such as on{Click,Load,etc} handlers)
generally require HTML-Escape in addition to Javascript-Escape,
since the attribute's value is HTML-unescaped by the browser
before it is passed to the javascript interpreter.
However, the javascript-escaping provided by auto-escape
makes a subsequent HTML-Escape unnecessary. As such you can
apply the same rules for variables within event handlers
as you would for javascript variables in string literals:
<button ...
onclick='GotoUrl("{{TARGET_URL}}");'>
Consider potential non-template sources of XSS.
There are a number of scenarios in which XSS can arise that
are unrelated to the insertion of values into HTML templates,
including,
injection into HTTP headers such as Location,
incorrect browser-side guess of the content-encoding of a HTML
document without explicitly specified charset,
incorrect browser-side guess of a non-HTML document's
content-type that overrides the document's specified
Content-Type,
browser-side handling of documents served for download-to-disk
(Content-Disposition: attachment).
Please consult additional documentation on
Cross-Site-Scripting for more detailed discussion of such
issues.
Both dictionary keys and template filenames are strings. Instead
of using raw strings, we encourage you to use a bit of machinery to
help protect against various types of errors.
For dictionary keys, you can use the make_tpl_varnames_h tool
to create static string variables to use instead of a string constant.
This will protect against typos, as the make_tpl_varnames_h
documentation describes. It also yields slightly more efficient
code.
For template filenames that a program uses -- including
sub-templates -- we suggest the following idiom:
There are methods to change the global state of the template
system, to examine templates, and to examine template dictionaries.
See the reference guide for more
information.
Craig Silverstein
ctemplate-ctemplate-2.4/doc/howto.html 0000664 0000000 0000000 00000001441 13631223166 0020107 0 ustar 00root root 0000000 0000000
How To Use the Ctemplate (formerly Google Template) System
This document has split into two parts: a user's guide and a
reference guide. Use the links below to see these, and other
documents about the template system.
Craig Silverstein
ctemplate-ctemplate-2.4/doc/index.html 0000664 0000000 0000000 00000006415 13631223166 0020064 0 ustar 00root root 0000000 0000000
Ctemplate (formerly Google Template) System
Ctemplate System
Status: Current
(as of 25 April 2008)
Welcome to the C++ CTemplate system! (This project was originally
called Google Templates, due to its origin as the template system used
for Google search result pages, but now has a more general name
matching its community-owned nature.)
As a quick start, here's a small but complete program that uses this
template library. For more details see, the links below.
Template file example.tpl
Hello {{NAME}},
You have just won ${{VALUE}}!
{{#IN_CA}}Well, ${{TAXED_VALUE}}, after taxes.{{/IN_CA}}
C++ program example.cc
#include <stdlib.h>
#include <string>
#include <iostream>
#include <ctemplate/template.h>
int main(int argc, char** argv) {
ctemplate::TemplateDictionary dict("example");
dict.SetValue("NAME", "John Smith");
int winnings = rand() % 100000;
dict.SetIntValue("VALUE", winnings);
dict.SetFormattedValue("TAXED_VALUE", "%.2f", winnings * 0.83);
// For now, assume everyone lives in CA.
// (Try running the program with a 0 here instead!)
if (1) {
dict.ShowSection("IN_CA");
}
std::string output;
ctemplate::ExpandTemplate("example.tpl", ctemplate::DO_NOT_STRIP, &dict, &output);
std::cout << output;
return 0;
}
Compiling and linking (using gcc)
gcc -o example example.cc -lctemplate_nothreads
I can use the "nothreads" library because example.cc
doesn't use threads. If example.cc were threaded, I
would do something like this instead:
gcc -o example example.cc -lctemplate -pthread
See the README for more details about the two different ctemplate
libraries.
In-depth Documentation
Howto: Introduction to the
Ctemplate system, and a tutorial for using it.
Auto Escape: Guide to using
the optional Auto Escape mode to protect your web application
better against XSS.
Tips: Advice, tips, and recommendations
for best practices with templates, to make them easier to write
and maintain, and to avoid common template mistakes.
Examples: Some example templates and
application code that uses them. These are taken from actual
Google applications.
Craig Silverstein
Last modified: Mon Feb 22 10:59:03 PST 2010
ctemplate-ctemplate-2.4/doc/reference.html 0000664 0000000 0000000 00000213372 13631223166 0020715 0 ustar 00root root 0000000 0000000
Ctemplate System Reference Guide
Ctemplate System Reference Guide
(as of
)
Overview
The main class used by the template system is
TemplateDictionary, which is used to expand a template
file. It is used by the main functions for expanding a template,
found in template.h.
TemplateCache is used to hold a collection of
Template objects. TemplateNamelist provides
various introspection routines on collections of Template
objects.
TemplateModifier and PerExpandData are
used to modify the values of a TemplateDictionary at
expand time. TemplateAnnotator does too, but is intended
for debugging purposes. TemplateDictionaryPeer is used
for testing template code.
ExpandEmitter provides the ability to emit an expanded
template to an arbitrary output store.
TemplateString is a string-like class that is built to
be very efficient when used with the template system. For instance,
tools are available to hash constant TemplateString
objects at compile-time, speeding up their use at run-time.
The rest of this document describes these classes and functions in
more detail, as well as build tools and other mechanisms for handling
templates.
(Note: the code snippets below all assume the default configuration
option is set, which puts template code in namespace
ctemplate.)
Templates are strings that contain special formatting code called
template markers. In the Ctemplate System, template
strings are usually read from a file.
Anything found in a template of the form {{...}} is
interpreted as a template marker. All other text is considered
formatting text and is output verbatim at template expansion time.
Outside of the template markers, templates may contain any text
whatsoever, including (single) curly braces and NUL characters.
The template language has six types of markers:
Variable markers, which are replaced by text based on
dictionary values. Variable markers look like this:
{{FOO}}
Start section and end section markers, which
delimit sections which may appear zero, one, or N times in
the output. Section markers look like this:
{{#FOO}}...{{/FOO}}
Template-include markers, which designate other
templates to be expanded and inserted at the location where the
marker appears. These are treated much like sections -- one
may think of them as sections whose content is specified in a
different file instead of inline -- and just like sections, can
be expanded zero, one or N times in the output, each with a
different dictionary. Template-include markers look like this:
{{>FOO}}
Comment markers, which may annotate the template
structure but drop completely out of the expanded
output. Comment markers look like this:
{{! comment lives here -- cool, no?}}
Set-delimiter markers, which change the marker
delimiters from {{ and }} to custom
strings. (The only requirement is that these strings not
contain whitespace or the equals sign.) This is useful for
languages like TeX, where double-braces may occur in the text
and are awkward to use for markup. Set-delimiter markers look
like this: {{=< >=}} <! Now markers are
delimited by braces > <=| |=> |! And now markers are
delimited by bars! |
Pragma markers, which invoke additional built-in template
features when processing the template. Pragma markers look like
this: {{%PRAGMA [name="value"...]}}. Currently,
AUTOESCAPE is the only pragma defined.
These marker types each have their own namespace. For readability,
however, it is best to not overuse a single name.
Modifiers
A variable and include-template can have one or more modifiers attached to them, like so:
{{MYVAR:mod1:mod2:mod3=value:mod4=value with spaces:mod5}}
A modifier is a filter that's
applied at template-expand time, that munges the value of the variable
before it's output. See the TemplateModifier class for
more details.
When expanding a variable (or template-include) with a modifier,
the modifiers are applied in order, left to right. For a
template-include, first the entire sub-template is expanded, as a
single string, and then the modifiers are applied to that string.
In general, using explicit modifiers does not turn off auto-escaping on a variable. The explicit
modifier :none does suppress auto-escaping.
If you have a section named FOO, you can define inside
of it a section named FOO_separator, and the template
system will automatically expand that section every time
FOO is expanded, except for the last. Thus, the
contents of FOO_separator can be used to separate
repeated values of a section.
Here's an example:
Here are the meeting attendees:
{{#ATTENDEES}}
{{NAME}}
{{#ATTENDEES_separator}}, {{/ATTENDEES_separator}}
{{/ATTENDEES}}
.
Here is a more convoluted example, to show the date:
You'd set up a template dictionary to repeat DATE
three times, with DATE_COMPONENT set to the month, day,
and year (or day, month, and year, depending on your locale...), and
DATE_SEP set to / or - or
whatever date-separator is called for.
SEP_separator is always evaluated with the current
dictionary. Thus, in the date example, if you wanted a different
separator each time, you could do so by setting DATE_SEP
to a different value for each repetition of DATE.
While SEP_separator is automatically expanded by the
template system, it is otherwise a perfectly normal section. You can
even instantiate it yourself by calling
AddSectionDictionary("SEP_separator"). In that case, the
section will be expanded both via the automatic expansion as a
separator, and as a normal section via the section dictionary you
added. This is more confusing than helpful, and you should probably
never do it.
There can be at most one "separator" sub-section per section. If
there are more, only the last is automatically expanded.
In the template system -- in functions like
ExpandTemplate() -- a template is specified by a pair:
filename + strip-mode. The filename specifies the name of the
template file on disk (but see below for string templates). The strip
mode specifies how this file should be parsed as it's read from disk,
in particular, how whitespace should be handled. It can take the
following values:
ctemplate::DO_NOT_STRIP: do nothing. This expands
the template file verbatim.
ctemplate::STRIP_BLANK_LINES: remove all blank
lines. This ignores any blank lines found in the template file
when parsing it. When the template is html, this reduces the
size of the output text without requiring a sacrifice of
readability for the input file.
ctemplate::STRIP_WHITESPACE: remove not only blank
lines when parsing, but also whitespace at the beginning and
end of each line. It also removes any linefeed (possibly
following whitespace) that follows a closing }} of
any kind of template marker except a template variable.
(This means a linefeed may be removed anywhere by simply
placing a comment marker as the last element on the line.)
When the template is html, this reduces the size of the output
html without changing the way it renders (except in a few
special cases.) When using this flag, the built-in template
variables BI_NEWLINE and BI_SPACE can
be useful to force a space or newline in a particular
situation.
The filename is where the template file lives on disk. It can be
either an absolute filename, or relative to a directory in the
template search path.
In addition to reading a template from disk, it is possible to read
a template from a string, using StringToTemplateCache().
The first argument of StringToTemplateCache() is a "key"
to use to refer to this string-based template. This key takes the
place of the filename, for any routine that asks for a
filename + strip.
This is the main workhorse function of the template system. It
takes the filename of a template, a template dictionary, and a string to
emit to, and emits an "expanded" version of the template using the
given template dictionary to fill in the template markers.
If the template specified by the given filename is already found in
an internal cache, the cached version of the template is used,
otherwise the template is loaded from disk, parsed, and stored in the
cache before expansion is performed. As always, the "filename" can
also be a key to a string-based template,
inserted directly into the cache via
StringToTemplateCache().
There is an overloaded version of Expand() that takes
an ExpandEmitter rather
than a string, as the source to expand the template into.
This function returns true if the template was successfully
expanded into the output parameter. It returns false if expansion
failed or was only partially successful. It might fail because the
template file cannot be found on disk, or because the template has
syntax errors and cannot be parsed, or because the template
sub-includes another template, and that sub-template has errors. To
minimize the risk of errors at expand-time, you can call
LoadTemplate() (below) first to load and parse the
template into the cache. This will catch all errors except for errors
involving sub-templates.
In the case of partial failures -- typically, failures resulting in
an error in a sub-inclued template -- there may be partial data
emitted to the output before the error was detected. If
ExpandTemplate() returns false, you should be careful to
check for and remove this partial data, if desired.
Per-expand data is applied to all templates that are seen while
expanding: not only the template you called Expand() on,
but also sub-templates that are brought in via template-includes
({{>INCLUDE}}). See the description of the PerExpandData class for more
details about how expansion can be modified by per-expand data.
The return value has the same meaning as for
ExpandTemplate() In fact, if you pass in
NULL as the per_expand_data argument, this
function is exactly equivalent to ExpandTemplate().
This function takes a filename and a strip-mode, and loads the file
into the default template cache. Future calls to
ExpandTemplate() or ExpandWithData() will
get the parsed template from the cache, without needing to go to
disk.
This function returns true if the template was successfully read
from disk, parsed, and inserted into the cache. It will also return
true if the template is already in the cache (even if the file has
changed on disk since the template was inserted into the cache). It
will return false if the file cannot be found on disk, or cannot be
successfully parsed. (Note that LoadTemplate() cannot
detect errors in sub-included templates, since the identity of
sub-included templates is specified in a
TemplateDictionary, not in the template itself.)
In addition to reading a template file from disk, it is also
possible to read a template file from a string, using
StringToTemplateCache(). It takes the content
as a string. It also takes in a key and a strip
mode. The given key and strip mode can be used as the filename/strip
pair in calls to ExpandTemplate() and similar
functions. The key can also be used as the "filename" in calls to
ctemplate::TemplateDictionary::SetFilename(), allowing
this template to be included inside other templates.
StringToTemplateCache() returns true if the string is
successfully inserted into the cache. It returns false otherwise,
probably because there is already a string or filename in the cache
with the same key.
default_template_cache() and mutable_default_template_cache()
All the above routines -- ExpandTemplate(),
LoadTemplate(), and the like -- read and write parsed
templates to the default template cache. This is just a static
instance of the TemplateCache class. It can
be accessed via these two functions:
default_template_cache() and, if you need a non-const
version of the cache, mutable_default_template_cache().
These can be useful if you need the advanced features of template
caches, such as ReloadAllIfChanged() or
ClearCache().
The class TemplateDictionary is used for all template
dictionary operations. In general, an application will need to call a
TemplateDictionary method for every marker in the
associated template (the major exception: markers that evaluate to the
empty string can be ignored).
The appropriate function to call for a given template marker
depends on its type.
Data Dictionaries
A data dictionary is a map from keys to values. The keys are
always strings, corresponding to the name of the associated template
marker, so a section {{#FOO}} in the template text is
matched to the key FOO in the dictionary, if it exists.
Note the case must match as well.
The value associated with a key differs according to key type. The
value associated with a variable is simple: it's the value for
that variable. Both keys and values can be any 8-bit
character-string, and may include internal NULs (\0).
The value associated with a section is a list of data
dictionaries. At template-expansion time, the section is expanded
once for each dictionary in the list. The first time, all
variables/etc. in the section will be evaluated taking into account
the first dictionary. The second time, all variables/etc. will be
evaluated taking into account the second dictionary. (See below for a definition of "taking into
account.")
The value associated with a template-include is also a list
of data dictionaries. Each data dictionary in this list must also
have one other, mandatory associated piece of associated information:
the filename of the template to include. At expand-time, that
filename is passed as-is to ctemplate::ExpandTemplate()
(or, more exactly, the equivalent of ExpandTemplate() in
the same TemplateCache that the parent template comes
from).
The dictionary structure is a tree: there's a 'main' dictionary,
and then a list of sub-dictionaries for each section or
include-template. When looking up a marker -- be it a variable,
section, or include-template marker -- the system looks in the
currently applicable dictionary. If it's found there, that value is
used. If not, and the parent dictionary is not an include-template,
it continues the look in the parent dictionary, and possibly the
grandparent, etc. That is, lookup has static scoping: you look
in your dictionary and any parent dictionary that is associated with
the same template-file. As soon as continuing the lookup would
require you to jump to a new template-file (which is what
include-template would do), we stop the lookup.
If lookup fails in all dictionaries, the template system does a
final lookup in the global variable dictionary.
The system initializes the global dictionary with a few useful
values for your convenience (the user can add more). All system
variables are prefixed with BI, to emphasize they are
"built in" variables.
BI_SPACE, which has the value
<space>. It is used to force a space
at the beginning or end of a line in the template,
where it would normally be suppressed. (See below.)
BI_NEWLINE, which has the value
<newline> It is used to force a
newline at the end of a line, where it would normally
be suppressed. (See below.)
Variable inheritance happens at expand time, not at
dictionary-create time. So if you create a section dictionary, and
then afterwards set a variable in its parent dictionary (or in the
global dictionary), the section will inherit that variable
value, if it doesn't define the value itself.
SetValue() and variants
SetValue() is used to set the value for a variable
marker in a dictionary. It takes a string as input -- nominally a TemplateString, though a C++
string or C char* will be auto-converted -- for the variable name and
its value. The name is the same string as is used for the variable's
template-marker inside the template this dictionary will be expanded
with: if the template reads Hello {{NAME}} then the
first argument to SetValue() must be NAME.
Case matters.
SetIntValue() takes an integer as the value, rather
than a string. On all platforms, the integer may be up to 64
bits.
SetFormattedValue() is a convenience routine.
SetFormattedValue(key, arg1, arg2, ...) is logically
equivalent to
without having to worry about the size of buffer, or
about stack overflow.
SetValueWithoutCopy() is provided to give an extra bit
of efficiency when needed. SetValue() will copy the key
and value into an internal data structure used by the
TemplateDictionary; this avoids dangling pointers if the
arguments to SetValue() are temporaries, or otherwise
have shorter lifetime than the TemplateDictionary. But
if you know that both the key and value strings have lifetime longer
than the TemplateDictionary -- perhaps because they are
global (static duration) char*'s -- you can call
SetValueWIthoutCopy() to avoid the copy. This yields a
small time savings at the cost of significant code fragility, so
should only be used when absolutely necessary.
SetGlobalValue() and SetTemplateGlobalValue()
SetGlobalValue() is like SetValue() but
works on the global dictionary. Since the global dictionary is shared
across all template dictionaries, this is a static method on
TemplateDictionary. It is thread-safe. It is also
relatively slow.
SetTemplateGlobalValue() is like
SetValue(), but the values are preserved across
template-includes.
This example shows all three forms:
A.tpl:
{{NAME}} has won {{>PRIZE}}. It is worth {{AMOUNT}}.
B.tpl:
{{AMOUNT}} dollars! And it's all yours, {{NAME}}
C.tpl:
To: {{NAME}}. Amount: {{AMOUNT}}.
code:
ctemplate::TemplateDictionary dict("set_value_demo");
ctemplate::TemplateDictionary* subdict = dict.AddIncludeDictionary("PRIZE");
subdict->SetFilename("B.tpl");
dict->SetValue("NAME", "Jane McJane");
dict->SetTemplateGlobalValue("AMOUNT", "One Million");
ctemplate::TemplateDictionary::SetGlobalValue("NAME", "John Doe");
ctemplate::TemplateDictionary dict_c("set_value_demo, part 2");
ctemplate::ExpandTemplate("A.tpl", ..., &dict);
ctemplate::ExpandTemplate("C.tpl", ..., &dict_c);
The first expand yields this:
Jane McJane has won One Million dollars! And it's all yours, John Doe. It is worth One Million.
The second expand yields this:
To: John Doe. Amount: .
NAME was set via SetValue(), so its
value was not propagated across the include-dict boundary; instead,
the subdict (B.tpl) got its value for NAME from the
global dictionary. AMOUNT, on the other hand, was set
via SetTemplateGlobalValue(), so its value was propagated
across the boundary, and the subdict saw it. However, the totally
unrelated template, C.tpl, did not see either value, and only sees the
values in the global dictionary. (Of course, had we filled
dict_c with some values, C.tpl would have had access to
those.)
AddSectionDictionary(), ShowSection(),
and SetValueAndShowSection()
AddSectionDictionary(section_name) returns a
sub-dictionary associated with the given section_name (for instance,
dict.AddSectionDictionary("MYSECT") for a template like
{{#MYSECT}}...{{/MYSECT}}). If called multiple times, it
will return a new dictionary each time. During Expand(),
the section will be expanded once for each time
AddSectionDictionary() was called; that is, the text
inside the section delimiters will be repeated once for each
AddSectionDictionary() call, and within a single
repetition, the dictionary returned by
AddSectionDictionary() will be used to populate the text
inside the section delimiters. (With the current dictionary as that
dictionary's parent, for inheritance purposes.)
This suggests that if AddSectionDictionary() is never
called on a section, the text inside the section will be omitted
entirely by Expand().
ShowSection() is a convenience method used to show the
text inside the section exactly once. It is equivalent to calling
AddSectionDictionary() once, and ignoring the returned
sub-dictionary. All variables in the section will depend on
dictionary inheritence to get their values.
SetValueAndShowSection() is another convenience
method,, used to show a section if and only if a related variable is
set to a non-empty value. SetValueAndShowSection(name, value,
section_name) is equivalent to this: if value is empty do
nothing, otherwise add a single dictionary to
section_name and call section_dict->AddValue(name,
value).
Example:
ctemplate::TemplateDictionary* dict = new ctemplate::TemplateDictionary("section example");
const char* username = GetUsername(); // returns "" for no user
if (username[0] != '\0') {
ctemplate::TemplateDictionary* sub_dict = dict->AddSectionDictionary("CHANGE_USER");
sub_dict->SetValue("USERNAME", username);
} else {
// don't need to do anything; we want a hidden section, which is the default
}
// Instead of the above 'if' statement, we could have done this:
if (username[0] != '\0') {
dict->ShowSection("CHANGE_USER"); // adds a single, empty dictionary
dict->SetValue("USERNAME", username); // take advantage of inheritance
} else {
// don't need to do anything; we want a hidden section, which is the default
}
// Or we could have done this:
dict->SetValueAndShowSection("USERNAME", username, "CHANGE_USER");
// Moving on...
GetPrevSearches(prev_searches, &num_prev_searches);
if (num_prev_searches > 0) {
for (int i = 0; i < num_prev_searches; ++i) {
TemplateDictionary* sub_dict = dict->AddSectionDictionary("PREV_SEARCHES");
sub_dict->SetValue("PREV_SEARCH", prev_searches[i]);
}
}
AddIncludeDictionary() and SetFilename()
AddIncludeDictionary(section_name) returns a
sub-dictionary associated with the given include_name (for instance,
dict.AddIncludeDictionary("MYTPL") for a template like
{{>MYTPL}}). If called multiple times, it
will return a new dictionary each time. It is the responsibility of
the caller to then call SetFilename() on the
sub-dictionary returned.
During Expand(),
each dictionary returned by AddIncludeDictionary will be
examined in turn. For each dictionary for which
SetFilename() is called, that filename will be read as a
template (via LoadTemplate(), with the same
"strip" value as the current template), and expanded using the
dictionary. (Note that the dictionary will not inherit
SetValue() values from the parent dictionary, though it
will inherit SetTemplateGlobalValue() values.) This
expanded template will then be emitted to the output.
Note that if AddIncludeDictionary() is never called,
the template-include will be a no-op during Expand().
Likewise, if it is called but SetFilename() is never
called on the resulting sub-dictionary, the template-include will be a
no-op. On the other hand, if it is called multiple times, multiple
templates -- possibly all from the same file, possibly not -- will be
inserted at the point of the template-include.
If a user has called StringToTemplateCache(key, ...),
then the user can call SetFilename(key) to include the
contents of the string as the sub-template.
Dump() and DumpToString()
These routines dump the contents of a dictionary and its
sub-dictionaries. Dump() dumps to stdout,
DumpToString() to a string. They are intended for
debugging.
This class holds a collection of templates. It can be used to give
you a coherent view of the template system: you load all the templates
you are going to use into the cache, and then reload them from disk in
one atomic operation. You can have multiple
TemplateCache objects in your executable, perhaps one for
each service you provide, or perhaps one per thread (so as to avoid
thread contention when loading templates).
One intended use of the template cache is to make it safe to reload
template files while serving user requests from a webserver. The idea
is that every user request, as it's created, is associated with the
current template cache. When you wish to reload, you
Clone() the current cache, and then reload inside the
cloned copy. New requests will get the cloned cache, while old
requests will continue to render using the old cache.
TemplateCache is written to make this use-case efficient:
templates are shared between caches when appropriate, with
reference-counting to keep memory management easy.
The default template cache
The template system creates a default template cache, which is
available via the functions default_template_cache() and
mutable_default_template_cache().
For simple uses of the template system, using the default cache,
via ExpandTemplate() and the like, may be perfectly
adequate. If you want more sophisticated features, such as the
ability to have different versions of the same template file active at
one time, or to change the template root-directory, you will have to
use an explicit TemplateCache.
LoadTemplate() and StringToTemplateCache()
These two routines are how you explicitly insert data into the
cache. LoadTemplate() reads a template from disk, while
StringToTemplateCache() takes the data from a
user-specified string. These work exactly the same as the global LoadTemplate() and StringToTemplateCache(),
except they insert into the given TemplateCache, rather
than the global cache.
LoadTemplate() is not strictly necessary: if the cache
cannot find a template it needs at Expand*() time, it will
automatically try to fetch it from disk. It is intended mostly for
use with Freeze(), which disables
this auto-fetch behavior.
Both of these routines take a strip mode
specifying how the template system should treat whitespace while
parsing.
If the template-cache is frozen,
LoadTemplate() will only return true if the template is
already stored in the cache, and will return false in every other
case. For a frozen cache, StringToTemplateCache() will
always return false.
ExpandWithData() and ExpandFrozen()
These routines takes a string that represents either a template
filename (for disk-based templates), or a key used in
StringToTemplateCache() (for string-based templates), a strip mode saying how to parse the template's
whitespace, and per-expand data (which
can be NULL). Overloads are provided to output the expanded template
to either a string or to an arbitrary ExpandEmitter.
Expand uses the filename + strip pair to fetch the template from
the cache, if it's there. If not, ExpandWithData() will
fetch the template from disk and insert it into the cache.
ExpandFrozen(), on the other hand, will just fail to
expand, and return false. This is the only difference in behavior
between the two routines. To reinforce this behavior,
ExpandFrozen() will return false immediately if Freeze() has not been called on the
cache.
While expanding, the template system may come across template
sub-includes ({{>SUB_TEMPLATE}}). It will attempt to
fetch these templates from the cache as well; failing that, it will
try to load the template from disk (for ExpandWithData())
or else fail the expand and return false (for
ExpandFrozen()).
Because ExpandFrozen() never updates the cache, it is
a const method, unlike ExpandWithData().
Note that TemplateCache does not provide the
convenience ExpandTemplate() routine, as the analogue of
the global ExpandTemplate(). If you are
not interested in the per-expand data, just call
ExpandWithData() with the per-expand data set to NULL.
ReloadAllIfChanged()
For every file-based template in the cache (this method ignores
string-based templates), ReloadAllIfChanged() checks the
filesystem to see if the file has changed since it was loaded into the
cache. If so, the cache loads a new version of the file into the
cache. Note that at this point both the old and new versions of the
file exist in the cache! Only the new version is accessible via new
calls to Expand(), but any expansions currently in flight
during the ReloadAllIfChanged() call will continue to use
the old version.
NOTE: ReloadAllIfChanged() never modifies existing
items in the cache in any way. It only loads new entries into the
cache.
ReloadAllIfChanged() comes in two flavors, controlled
by the passed-in enum. In "immediate" mode, it synchronously iterates
through the cache and reloads all files that need it. In "lazy" mode,
it waits to reload a given template file until the next time it's
actually used (in a call to Expand*()). "Immediate" mode
is safer in the case where templates depend on each other and the
files change a lot, since all files are reloaded at about the same
time. "Lazy" mode avoids the latency spike of "immediate" mode, and
is preferable in the (common) case that files on disk change only
rarely.
By default, filenames passed in to Expand*() are taken
to be relative to the current working directory. These functions
change that behavior. SetTemplateRootDirectory() resets
the search path to be the single path passed in to this function.
Every time AddAlternateTemplateRootDirectory() is called,
it adds another directory to the end of the search path. The template
system will follow the search path, in order, when looking for a
filename.
Note that the template search path is only meaningful when the
filename passed to Expand*() (or specified for a
sub-include) is a relative filename. If the filename is an absolute
filename, starting with /, the search path is
ignored.
template_root_directory() returns the first entry in
the search path. There is currently no way to access other entries in
the search path.
FindTemplateFilename()
FindTemplateFilename() does the work of finding a
template file in the filesystem, using the current template search
path. It takes a relative pathname as input, and returns an absolute
pathname as output, indicating where the template file lives on the
filesystem. If the template file is not found, this method returns
the empty string.
Freeze() marks the template cache as immutable. After
this method is called, the cache can no longer be modified by loading
new templates or reloading existing templates. During expansion only
cached included templates will be used; they won't be loaded
on-demand.
Before calling Freeze(), you should make sure your
cache has all the templates it might need, using
LoadTemplate() and StringToTemplateCache().
Otherwise, ExpandWithData() and
ExpandFrozen() may fail.
Once the cache is frozen, calls to
SetTemplateRootDirectory(),
AddAlternateTemplateRootDirectory(),
Delete(), and ReloadAllIfChanged() will
fail.
After the cache is frozen, the TemplateCache object is
effectively const.
Delete()
This method deletes an entry from the cache. If the entry is in
the cache multiple times (each with a different "strip" mode), this
method deletes all of them.
ClearCache()
This method deletes all entries from the cache. It can be called
even on a frozen cache.
Note: this method is not typically necessary unless you are testing
for memory leaks. It is intended to be called just before exiting the
program, and after all template expansions are completed. Using it in
that way may prevent unnecessary reporting by the leak checker.
Clone()
Clone() makes a shallow copy of the given
TemplateCache object, and returns the copy. The new copy
and the old share the same template objects; since it's a shallow
copy, they actually share pointers to the exact same object. (Since
the template cache never changes a template object once it's loaded
into the cache, sharing the pointer isn't a risk.)
The intended use of Clone(), as described above, is to
allow fine control over "epochal" changes in templates. One
TemplateCache can hold all versions of the template files
before the big update; after the update is done, you can clone the old
cache and then call ReloadAllIfChanged() on the clone.
This is a low-cost operation, since the two copies share most
resources. Smart pointers take care of most memory management
issues.
The caller is responsible for calling delete on the
returned TemplateCache object.
This class provides information about registered templates. Or more
precisely, all templates corresponding to registered filenames.
All methods in this class are static.
RegisterTemplate() and
RegisterTemplateFilename()
TemplateNamelist::RegisterTemplate() takes a filename
and adds it to the static namelist used by
TemplateNamelist. All other methods of
TemplateNamelist work only on registered filenames.
It's fairly rare to call this method directly. Instead, the more
common use is to use the macro RegisterTemplateFilename
somewhere in the global scope, like so:
The reason to prefer the macro is it defines a global variable that
you can use instead of the hard-coded template name. This helps catch
typos. The RegisterTemplateFilename() example is
functionally equivalent to:
A modifier is a filter that's applied at template-expand time, that
munges the value of the variable before it's output. For instance,
<html><body>{{NAME:html_escape}}</body></html>
asks the template system to apply the built-in
html_escape modifier when expanding
{{NAME}}. If you set NAME in your
dictionary to be Jim & Bob, what will actually be
emitted in the template is Jim & Bob.
You can chain modifiers together. This template first html-escapes
NAME, and then javascript-escapes that result:
Here are the modifiers that are built in to the template system.
They are all defined in template_modifiers.cc:
long name
short name
description
:cleanse_css
:c
Removes characters not safe for a CSS value. Safe characters
are alphanumeric, space, underscore, period, coma, exclamation
mark, pound, percent, and dash.
:html_escape
:h
html-escapes the variable before output
(eg & -> &)
:html_escape_with_arg
:H
special purpose html escaping. See
:H Arguments
below for details.
:img_src_url_escape_with_arg
:I
special purpose image url escaping. See
:I and :U Arguments
below for details.
:javascript_escape
:j
javascript-escapes the variable before output (eg
" -> \x27 and
& -> \x26)
:javascript_escape_with_arg
:J
special purpose javascript escaping. See
:J Arguments
below for details.
:json_escape
:o
json-escapes a variable before output as a string in json;
HTML characters are escaped using Unicode escape sequences
(e.g & -> \u0026) to comply with
RFC 4627.
:none
leaves the variable as is (used to disable auto-escaping)
:pre_escape
:p
pre-escapes the variable before output (same as html_escape but
whitespace is preserved; useful for <pre>...</pre>)
performs URL escaping on the variable before output.
space is turned into +, and everything other than [0-9a-zA-Z.,_:*/~!()-], is
transformed into %-style escapes. Use this when you are building
URLs with variables as parameters:
xml-escapes the variable before output
(the five characters <>&"' become
<>&"')
suitable for content returned in raw XML. It is not intended
for escaping content within CDATA blocks.
The *_with_arg modifiers require an argument to
specify the type of escaping to use. The following sections list
the supported arguments for each of these modifiers.
:H Arguments
Here are the values that are supported by
the html_escape_with_arg modifier:
value
description
=snippet
like html_escape, but allows HTML entities and
some tags to pass through unchanged. The allowed tags
are <br>, <wbr>, <b>,
and </b>.
=pre
same as pre_escape
=url
same as :U=html below. For backwards compatibility.
=attribute
replaces characters not safe for an use in an unquoted
attribute with underscore. Safe characters are alphanumeric,
underscore, dash, period, and colon.
:I and :U Arguments
Here are the values that are supported by
the img_src_url_escape_with_arg and
url_escape_with_arg modifiers:
value
description
=html
Ensures that a variable contains a safe URL. Safe means that
it is either a http or https URL, or else it has no protocol
specified.
If the URL is safe, the modifier HTML-escapes the URL.
Otherwise, the modifier replaces the unsafe URL with one of the
following values:
/images/cleardot.gif (the :I
modifier)
# (the :U modifier)
Do not use :U for image URLs. Use :I
instead. # is not a safe replacement for an image URL.
<img src=#> can cause each browser to request the
entire page again.
=javascript
Same as =html, but using javascript escaping
instead of html escaping.
=css
Same as =html but using CSS escaping instead
of html escaping so that the variable can be safely inserted
within a CSS @import statement or a CSS property.
The characters in [\r\n()'"<>*\] are transformed
into %-style escapes.
=query
(Supported for :U only) Same as
url_query_escape.
:J Arguments
Here are the values that are supported by
the javascript_escape_with_arg modifier:
value
description
=number
Ensures that the variable is a valid number or boolean
javascript literal. This includes booleans
true and false, decimal
numbers (e.g. 4.10 or -5.01e+10)
as well as hex numbers (e.g. 0x5FF). This modifier
is intended to ensure the variable not enclosed in
quotes cannot contain javascript code that may execute. It does
not guarantee that the variable is syntactically well-formed.
If the variable is safe, it is returned
as-is, otherwise it is replaced with null.
In the future we may add more logic to support objects and
arrays.
Custom Modifiers
In addition to the built-in modifiers, you can write your own
modifier. Custom modifiers must have a name starting with "x-", and
the name can contain alphanumeric characters plus dashes and
underscores. Custom modifiers can also accept values with any
character except for : and }. For example
this template could be a valid use of a custom modifier:
{{VAR:x-my_modifier:value1,value2,value3 has spaces,etc}}
See <template_modifiers.h> for details on how to
write a modifier and how to register it. In short, you write a
modifier by subclassing ctemplate::TemplateModifier and
overriding the Modify method, and you register it by
calling ctemplate::AddModifier() Here is an example of
the code for a custom modifier:
class StarEscape : public ctemplate::TemplateModifier {
void Modify(const char* in, size_t inlen,
const ctemplate::PerExpandData* per_expand_data,
ctemplate::ExpandEmitter* outbuf, const string& arg) const {
outbuf->Emit(string("*") + string(in, inlen) + string("*"));
}
};
Subclassing TemplateModifier
The minimum work to create a custom modifier is to subclass
TemplateModifier and override the Modify()
method. Modify() takes as input the value of the text to
be modified, as well as the per expand
data associated with this Expand() call. The method
may use this input, plus any other data it may have, to generate
output, which it should write into the given
ExpandEmitter.
The subclass can also override MightModify(). This is
useful for modifiers that are typically a no-op (in which case the
modifier is just doing busy-work, copying its input to the output
ExpandEmitter). If MightModify() returns
false, the template system will avoid calling Modify() at
all on that variable, avoiding the busy-work copy.
AddModifier()
AddModifier() is used to register a custom modifier,
so the modifier can be used in templates. The name of the modifier
must start with x-.
AddXssSafeModifier()
AddXssSafeModifier() is used to register a custom
modifier that can work well with the auto-escape system. It is used when the
modifier produces output that is "safe" from cross-site scripting
attacks in all contexts in which it might be used. For instance, a
modifier that only emits numbers is xss-safe if it's only used in html
or javascript contexts.
If the auto-escape pragma is used
in a document, then all variables will be auto-escaped, even if
explicit modifiers are used on the variable. The rules are a little
complicated:
If the explicit modifier is a built-in modifier, and that
modifier is "compatible" with the modifier that auto-escape
would perform ("compatible" means it safely escapes in at least
as many contexts as the auto-escape modifier), then only the
explicit modifier is applied, and no further auto-escaping is
done.
If the explicit modifier is a custom modifier registered using
AddXssSafeModifier(), no further auto-escaping is
done.
If the explicit modifier is the :none modifier, no
further auto-escaping is done. This is the mechanism for
manually turning off auto-escaping.
In all other situations, auto-escaping will be performed after
the explicit modifiers have all run.
ExpandWithData() and
TemplateModifier::Modify() both take a
PerExpandData object. Per-expand data is applied to all
templates that are seen while expanding: not only the template you
called ExpandWithData() on, but also sub-templates that
are brought in via template-includes ({{>INCLUDE}}).
There are several types of per-expand data you can set, by calling
the appropriate method on a PerExpandData object.
SetAnnotateOutput()
This is a debugging function. When expanding this template, it adds
marker-strings to the output to indicate what template-substitutions
the system made. This takes a string argument which can be used to
shorten the filenames printed in the annotations: if the filename
contains the string you give, everything before that string is elided
from the filename before printing. (It's safe to just always pass in
the empty string.)
SetAnnotator()
This overrides the default text-based annotation used by
SetAnnotateOutput(). If this is set and
SetAnnotateOutput() is called, the per-expand data will
use this TemplateAnnotator instance
to do the annotation, rather than the default instance.
InsertForModifiers() and LookupForModifiers()
InsertForModifiers() stores an arbitrary key/value
pair in the PerExpandData structure. This is used with
template modifiers: the
PerExpandData object passed to
ExpandWithData() is made available to every template
modifier that is called during expand time (including any custom
modifiers). The intended use of this functionality is to allow a
modifier to work one way when expanding a template with dictionary A,
and another way when expanding a template with dictionary B. For
instance, a modifier might encrypt part of a webpage using a user's
secret-key, which is of course different for every expansion of the
webpage.
LookupForModifiers() can be used by a
template-modifier to read the key/value pair inserted by
InsertForModifiers().
LookupForModifiersAsString() is the same, but returns the
value as a char* rather than a void*, for convenience.
SetTemplateExpansionModifier()
This is an advanced feature for those who need a custom hook into
template expansion. It will not be used by most programmers. It
takes a template-modifier as its argument, but this template modifier
is treated specially: instead of applying when an appropriate magic
string appears in the text of a template, it applies every time a
template is expanded during a call to ExpandWithData().
Note this means that it's called not only after the top-level
template, that ExpandWithData() is called on, is
expanded, but also on every sub-template that is expanded due to a
template-include.
This unusual functionality has a few unusual properties. Since the
template expansion modifier is not called in normal fashion, the
normal arg argument to the template modifier does not
make sense. Instead, the arg is set to the path of the
template which is being expanded. Also, template expansion modifiers
can be expensive, since they are applied pretty indiscriminately, so
it can be worth implementing the MightModifiy() predicate
for the passed-in TemplateModifier to avoid unnecessary
work.
The TemplateAnnotator class is used to pass in to PerExpandData::SetAnnotator(),
to control how expand-time annotation is done. This is meant to be
used as a debugging routine.
This class is an abstract base class; SetAnnotator()
takes a subclass that implements the various methods of the base
class. These methods control the action taken when various template
markers are seen during template expansion.
template_annotator.h defines the abstract base class,
and also a concrete subclass that is used by default for annotation if
SetAnnotator() is not called.
By design, it is not possible to view the contents of a
TemplateDictionary; we want to make sure the interface
between the logic layer of the application and the presentation layer
of the template goes in only one direction. While generally this
keeps programs as clean as possible, it presents problems in testing
code, which may want to verify that a given
TemplateDictionary has been filled properly. The
TemplateDictionaryPeer addresses this need. It lives in
template_test_util.h.
Some of the methods of TemplateDictionaryPeer are
useful for internal tests only. Below are some of the methods that
are most useful for user-level tests.
STS_INIT_FOR_TEST
This macro allows use of STS_INIT for testing, even
when the input pointer is not guaranteed to be allocated for the
entire length of the test (it must, of course, be allocated for the
entire lifetime of the template being tested). Since normally
STS_INIT requires inputs to have static duration, this
allows for more flexibility in tests, at the cost of worse memory
management and decreased code safety (in that it's possible to
accidentally violate the lifetime requirements).
GetSectionValue()
This returns the value for the named variable. It uses normal
template scoping rules to resolve the name.
IsHiddenSection() and IsHiddenTemplate()
Checks if a section or sub-template is "hidden" (that is, won't be
displayed at all).
GetSectionDictionaries() and GetIncludeDictionaries()
Returns all the sub-dictionaries for a given section or
template-include, in a vector.>
Other Testing Functions
template_test_util.h has other useful routines for
testing, such as ExpandIs(), which tests whether a
template + dictionary pair expands into an expected string. See the
header file for details.
There are two overloads of ExpandTemplate(): the first
emits the expanded template to a C++ string, and the second emits to
an ExpandEmitter: an abstract base class that serves as a
data source. It supports just one overloaded method,
Emit(), that can take a char, a char*, or a C++ string as
input.
Using this class requires subclassing ExpandEmitter
and providing the various definitions for Emit(). For
instance, a subclass might provide definitions of Emit()
that send the input bytes out to a network socket.
In addition to defining the abstract base class,
template_emitter.h provides a sample concrete subclass
implementation, for emitting to a string.
TemplateString is a string-like implementation.
Ctemplate uses TemplateString almost exclusively,
internally. Many of the public API methods, such as
TemplateDictionary::SetValue(), also take
TemplateString as input. TemplateString
has implicit constructors for both C++ strings and char*'s, so every
method that takes a TemplateString will also work if
given a C++ string or a char*. If you have a char* and know its
length, you can save a bit of work by explicitly constructing a
TemplateString with a char* + length, for instance:
Some compile-time tools work with TemplateString to
offload computation from runtime to compile-time. This is possible
because the Ctemplate code often stores a hash of a string
rather than a string directly. For static, immutable strings,
TemplateString can store a pre-computed hash value. This
functionality is used by make_tpl_varnames_h. Thus,
using this tool to create constants to use for SetValue()
keys provides not only protection against typos, but a speed
improvement as well.
For immutable strings in your code, you can create efficient
compile-time template-string objects of your own -- in this case of
type StaticTemplateString -- by using the
STS_INIT macro, like so:
The string variable's name, kSectName is repeated
twice. The variable's value is specified inside the macro. Note that
this macro should be used at the top level of a file, not inside
functions (even when the variables are made static), and you should
define the StaticTemplateString exactly as above:
static const StaticTemplateString. Otherwise, the
undefined constructor/destructor order of C++ may result in surprising
behavior, wherein the StaticTemplateString is not
initialized when it ought to be.
The Template Class
In older version of ctemplate, the Template class,
which holds parsed templates, was a major part of the template
workflow: the common template use-case would be:
In current use, this model is deprecated in favor of the single
ExpandTemplate() call; support for Template
methods may be removed entirely in future versions of ctemplate.
However, you may still find older code using this old formulation.
The Guide to using Auto Escape has
an overview of Auto Escape as well as discussion of its limitations.
To use it, put the following text at the top of the template:
{{%AUTOESCAPE context="CONTEXT" [state="STATE"]}}
Description of the arguments:
The context attribute is one of HTML,
JAVASCRIPT, CSS,
JSON or XML. It must correspond
to the context in which the browser will interpret this
template. Warning: Setting the wrong context will
result in wrong escaping applied to all variables in
the given template. In particular, if the template starts with
a <script> tag, its context is
HTML and not JAVASCRIPT. Auto-Escape
will recognize the <script> tag and hence
properly Javascript-escape the variables within it. Similarly,
if the template starts with a <style> tag,
its context is HTML and not CSS.
The state attribute is commonly omitted. It accepts the
value IN_TAG in the HTML context
to indicate that the template only contains (one or more)
HTML attribute name and value pairs that are part of an
HTML tag formed in a parent template.
This will auto-escape every variable in the template. To turn off
auto-escaping for a particular variable, you can apply the
none modifier, like so: {{MYVAR:none}}.
Here is an example of an autoescaped document:
{{%AUTOESCAPE context="HTML"}}
<body>
<p>Hello {{USER}}</p>
<p><a href="{{URL}}">Your Account</a></p>
<p>Your identifier: {{ID:none}}{{! This is dangerous! }}</p>
</body>
Development Tools
This package includes several tools to make it easier to use write
and use templates.
make_tpl_varnames_h is a "lint" style syntax checker
and header file generator. It takes the names of template files as
command line arguments and loads each file into a Template object by
retrieving the file via the Template factory method. The loading of
the file does pure syntax checking and reports such errors as
mis-matched section start/end markers, mis-matched open/close
double-curly braces, such as "{{VAR}", or invalid
characters in template variables/names/comments.
If the template passes the syntax check, by default the utility
then creates a header file for use in the executable code that fills
the dictionary for the template. If the developer includes this
header file, then constants in the header file may be referenced in
the dictionary building function, rather than hard-coding strings as
variable and section names. By using these constants, the compiler
can notify the developer of spelling errors and mismatched names.
Here's an example of how this is used, and how it helps prevent
errors:
The initial letter 'k', indicating a defined constant.
One or more prefix letters which are derived from the
template file name. These prefix letters consist of the first
letter of the file name, followed by the first letter following
each underscore in the name, with the exception of the letter
'p' when it is followed by the letters "ost", as is a recommended convention for
template versioning. For example, the prefix letters for the
file one_search_result_post20020815.tpl are
osr.
An underscore.
The variable or section name itself, same casing.
As an example, the section name "RESULT_NUMBER" in the file
one_search_result_post20020815.tpl would be given the constant name
kosr_RESULT_NUMBER and would appear in the header file as
const char * const kosr_RESULT_NUMBER = "RESULT_NUMBER";
-- as in the example above. (The variable is actually a
StaticTemplateString, not a char*, but the basic idea
holds.)
An alternate output directory may be specified by the command line
flag --header_dir.
The name of the generated header file is the same as the name of
the template file with an extension added to the name. By default,
that extension is .varnames.h. In the above example, the
header file containing the constant declarations would be named
one_search_result_post20020815.tpl.varnames.h. An
alternate extension may be provided via the command line flag
--outputfile_suffix.
Important command line flags:
--noheader -- Indicates that a header file
should not be generated; only syntax checking should be done.
--header_dir -- sets the directory where the header
is written. Default: "./"
--template_dir -- sets the template root
directory. Default: ./ which is the correct
specification when it is run from the directory where the templates
are located. This is only used if the input template filenames
are specified as relative paths rather than absolute
paths.
--outputfile_suffix -- the extension added to the
name of the template file to create the name of the generated
header file. Default: .varnames.h.
For a full list of command line flags, run
make_tpl_varnames_h --help.
StringToTemplateCache() lets you load a template
from a string instead of a file. Applications may prefer this option
to reduce the dependencies of the executable, or use it in
environments where data files are not practical. In such cases,
template-converter can be used as a template "compiler",
letting the developer write a template file as a data file in the
normal way, and then "compiling" it to a C++ string to be included in
the executable.
Usage is template-converter <template filename>.
C++ code is output is to stdout; it can be stored in a .h file or
included directly into a C++ file. Perl must be installed to use this
script.
Craig Silverstein
ctemplate-ctemplate-2.4/doc/tips.html 0000664 0000000 0000000 00000047476 13631223166 0017750 0 ustar 00root root 0000000 0000000
Tips and Guidelines for Using the Ctemplate System
Tips and Guidelines for Using the Ctemplate System
(as of 10 March 2010)
The basic rules of the template system are
enough to use it, but over time, we at Google have developed some
tips, guidelines, and best practices that make it easier to use
templates effectively, and to avoid common template errors.
Early in Google's use of templates, we noticed a problem: if a
binary that uses a template and its corresponding template were both
modified, particularly if the change were such that the old binary
could not work with the new template or the new binary could not work
with the old template, then somehow they both had to be deployed at
the same instant to not present errors to our users. This was hard to
do. The solution was to adopt a template naming and versioning
convention. The procedure to use it follows:
Each template name ends with _postYYYYMMDD.tpl,
where YYYMMDD is the date of this version's initial
creation.
Before making (non-backward-compatible) modifications to a
template, copy the template to a new name, incorporating a
later date than the original one being copied.
Edit the new file, and push it to the production server.
Finally, update the code to refer to the new template-name
(ideally, using the RegisterTemplateFilename
idiom), and push the new executable to the production
server.
When this convention is followed, the new template file does not
overwrite the old one when it is deployed, because it is a new file
with a new name. The old template file is still there to be used as
long as the old binary is still in production and the new template
file just sits there being ignored. Then when the new binary finally
gets deployed, it immediately starts using the new template file,
because it is coded (in RegisterTemplateFilename) to do
so. After that, it is the old template file that continues to sit
there ignored.
The make_tpl_varnames_h
utility knows about the "_postYYYYMMDD" naming convention, so it
is important that you use that convention exactly if you use the
make_tpl_varnames_h.
Processing Phases
Typically a program using the Ctemplate System will
perform the following phases, usually in this order:
Retrieve and prepare the data used to fill a dictionary.
Build the data dictionary, including all its
sub-dictionaries, that will supply the values to the
designated template object, its sections, and its
included templates.
Retrieve the top-level template object required to
format the data. (This may or may
not involve reading and parsing a template file,
depending on whether the requested file has already
been read and parsed by the running program or
whether that file has been marked "reload if changed"
and was in fact changed.)
Expand the template object into an output buffer
using the completed data dictionary.
Output the buffer.
Clean up: Destroy the top-level data dictionary
whenever it is no longer needed.
Optionally, clear the cache at the end of program
execution.
Most of the code of the program will be in Phases 1 and
2. Clearly, Phase 1 is outside the scope of the template system. But
in designing the code for Phase 2 (building the data dictionary), it
is wise to have the structure of the program reflect the structure of
the templates being used. Specifically, there should be a single
procedure call to build the dictionary for a single template. That
procedure call should take parameters that include all the data
required to populate the data dictionary for that template and all the
templates it includes. Following this "one template/one procedure
call" guideline further, for each included template, another procedure
should be called to populate the (or each) data dictionary for
that included template. This maintains the "one template/one procedure
call" principle in a nested fashion that reflects the nesting of the
templates.
This is not to imply that the "one procedure call" for a template
should not be modularized into sub-procedures for readability and
maintainability, or that it should not call other auxilliary
procedures for such things as formatting the data and converting it to
the appropriate strings, etc. But it does mean that there should be
one entry point for building the dictionary tree for one template and
that entry point should show the data dependencies of that template
through its parameter list. This code for populating the data
dictionary should NOT be intermingled with data gathering code
that should have been done in Phase 1.
(Inside Google, the convention has been used to name the dictionary
building procedure using the pattern fill_..._dictionary
where the dots are related to the name of the template the data is
being prepared for. For instance, the data for the template named
one_search_result.tpl might be placed in a dictionary via a function
named fill_one_search_result_dictionary.)
Choose template names to create unique constant prefixes.
Template names should contain at least two words
to avoid constant prefix clashes (e.g. kxy_
instead of kx_ ) The name of a new template
should be checked against the existing names before
proceeding. If your new template name produces a prefix that
conflicts with an already existing template, you should change
the name of your new template, even though it may be the only
perfect name you can come up with. You'll have to use a less
than perfect name in that case. (See "Template Syntax Checker
and Header File Generator" below for more explanation about
constant prefixes.)
Use SetFormattedValue
discriminately.
This method should never be used to sneak HTML into the
executable as in
In that case, the <b> and
</b> should be moved into the template.
Never have a section encompass an entire template.
If the first line of a template is a start section marker
and the last line is its matching end section marker, then
those markers are unnecessary in almost all cases. They are
usually put there to allow the entire template to be hidden or
iterated, but since it encompasses the entire file, the
section may be hidden by not expanding the file (or by hiding
the template-include section that includes the file) and it
may be iterated by iterating the template-include marker of
the including template. (The only exception might be if the
entire page is to be iterated, but this seems a bit of a
stretch.)
An included template is just a section whose contents are
located in a separate file. You may iterate over it just
like you do sections.
For example, if your template has the following
template-include marker:
to iterate that section. (Note: Make sure you call
child_dict->SetFilename()! If your included
template is not showing in the output, this is the first thing
you should check.)
The recommended idiom to fill an include-template dictionary is
like this:
But what do you do if you decide, in
fill_include_template_dictionary, that you don't
want to display anything for this include-template after all? It
seems like it's too late: you've already created the
sub-dictionary. The solution is simple: just be sure that
fill_include_template_dictionary() doesn't call
SetFilename() in that case.
Never have a section which only contains another section.
For example, don't do this:
{{#OUTER_SECTION}}
{{#INNER_SECTION}}
section contents here
{{/INNER_SECTION}}
{{/OUTER_SECTION}}
or this equivalent template code (see the previous item):
This is usually done because the developer thinks the outer
section must be used to hide the section when the inner
section, intended for iteration, has no iterations. In both
cases, you should only have one section (either
INNER_SECTION or INCLUDED_SECTION in
the examples) and iterate that section either 0 times or more
than 0 times. It's the wonder of the dual use of sections,
i.e. that they may be conditional or iterative or, in this case,
both.
A related suggestion: Do not have a section whose entire
contents is one variable marker with nothing else, unless you
need to iterate over that section with multiple values of that
variable. You don't need the surrounding section just to hide
the marker. A variable marker that is not set, does not
produce output. By convention, we set such variables to the
empty string. But in neither case do you need to hide it by
hiding a surrounding section that contains nothing else.
Use this hide/show idiom for if-else blocks.
Since sections are hidden by default, you can use represent
if-else logic in your code via ShowSection. For
example:
if ( my_test ) {
dict->ShowSection(kxyz_TRUE_BLOCK);
[ more code to fill the values for that section]
} else {
dict->ShowSection(kxyz_FALSE_BLOCK);
[ more code to fill the values for that section]
}
Write... vs. Fill...Dictionary methods
- Observe the proper division of labor, don't mix them.
The output (or write) function should create the top level
template dictionary, call one or more fill-dictionary routines
with it, then get the template and expand it. It should not call
dictionary modifying methods, like ShowSection
and SetValue. By keeping these separated into
their own fill-dictionary routine, the code is more modular and
lends itself to template re-use. If you maintain the proper
division of labor, the template you are filling and outputting
may be filled and included in a larger template by someone
else.
Use AddSectionDictionary only when you want to
iterate over a section or, secondarily, if you need to avoid name
conflicts.
Sometimes developers get the idea that every section requires
its own child dictionary created by an
AddSectionDictionary call. Because of variable
inheritence, this isn't usually so. The intended purpose of
AddSectionDictionary is to enable iteration over a
section. Secondarily, if the section contains generic names that
may conflict with the same name in other parts of the template,
it may be safer to call AddSectionDictionary to
create a separate namespace. In any case, do not assume you must
call AddSectionDictionary just because you are
working within a section. The main dictionary can be used for all
levels of conditional sections as long as you avoid name
conflicts by keeping the marker names unique.
Do not place RegisterTemplateFilename
statements in header (.h) files.
RegisterTemplateFilename is a macro that
instantiates a TemplateNamelist object. If you place
it in a header file, a different object will get created each time
it is included in another .cc file.
The RegisterTemplateFilename statement and its
associated #include of the varnames.h
file should occur only in the .cc file that
implements the fill-dictionary routine for that template. You
should never have more than one
RegisterTemplateFilename for a single template and
you should try hard not to copy the #include file to
other files as well. The template versioning makes this more
important because a developer may not know that the template name
with included version number needs to be updated in more than one
file when versioning occurs. [Also see above for more information
about what routine uses the filename declared by the
RegisterTemplateFilename statement.]
Never reference more than one template in a
fill...dictionary method.
Each template should have its own fill-dictionary
routine. That routine should only reference marker names defined
in that template. If this convention is followed, then all the
prefixes in a fill-dictionary routine will be the same. [Note
that an implication of this convention is that if the template
includes another template, via a template-include marker, then
containing template's fill-dictionary routine should call the
included template's fill-dictionary routine (being careful to
observe the convention described above). But
then, this is merely a restatement of "One
template / One procedure call".]
Have fill...dictionary call SetFilename even if the
dictionary is never used for a template-include.
SetFilename() is required when a dictionary is created via
AddIncludeDictionary(). However, it's safe to set
all the time. By setting it always, you make the code work
properly if this dictionary ever changes to be template-included
after all. Even if not, by saying what template file the
dictionary is intended to go with, you are self-documenting your
code.
Do not call c_str() on strings to pass them to
TemplateDictionary methods.
Note that all the TemplateDictionary methods are defined to
take TemplateString objects. These are created
automatically from both strings and char*'s (and can be created
manually if you have a char* and a length). So if you have a
string, it's safe and efficient to just pass it in directly; you
do not need to extract the const char * from your string object
to pass it to these methods. For some reason, this is a common
error of novice template coders.
The one exception to this rule is when using the method
SetFormattedValue. When calling that
method, you must call c_str() on strings that are to
be inserted
into the format string, just as you would when providing data for
any other printf format string.
Do not use SetGlobalValue when you could use
SetValue or SetTemplateGlobalValue.
SetGlobalValue should be used quite rarely, for
constants that really are consistent across all your templates.
It's slower to look up a value in the global dictionary than it
is in the template-specific dictionary.
Do not use StringToTemplateCache unless you have
a specific need for its non-file-based attributes.
ctemplate::StringToTemplateCache was created for
use in highly constrained cases where file I/O may be impaired or
undesirable, for instance to produce a server error message
where there may be disk problems or to produce formatted
output where there are processes that do not have a facility
for updating data files dynamically. It is not recommended for
ordinary use since it cannot be updated dynamically via a
data-push; changes always require a binary push.
Use auto-escaping to prevent
Cross-Site-Scripting security vulnerabilities.
Use {{%AUTOESCAPE}} consistently. Use the
:none modifier to override autoesacping only in
those (usually rare) cases where there is a specific reason the
template variable should not be escaped, for example:
The template variable contains HTML markup that should be
interpreted by the browser. In this case you must be very careful to
ensure that the variable can in no case contain "harmful" HTML. Also,
keep in mind the above
recommendation on the use of SetFormattedValue and
consider moving the HTML markup into the template.
The variable is known to be already escaped at the point it
is inserted into the template (for example, the value might be
kept in escaped form in a storage backend). Here, escaping again
via a variable-modifier would result in "double escaping". You
must ensure that the variable comes escaped in the appropriate
context (that is, if you're inserting the variable into an html
document, it's html-escaped and not java-escaped).
Do not leave an extra space when using {{BI_SPACE}}
The built-in template variable BI_SPACE is itself
replaced by a single space. It is used where you need to make
sure a space is preserved at the end of a line. It is a common
mistake to leave an extra space before this marker, which results
in not one, but two, spaces created in the document.
Cross-Site Scripting (commonly abbreviated as XSS) is a security
issue that arises when an attacker can cause client-side script (such as
JavaScript) of his or her choosing to execute within another user's
browser in the context of a given web-site or web-application. This may
allow the attacker to steal that user's session cookies for the
web-application in question, or otherwise manipulate that user's session
context.
XSS vulnerabilities most often arise if a web-application renders
data that originated from an untrusted source (such as a query
parameter) in a HTML document without carefully validating or escaping
that data.
The following online resources provide further information on XSS
vulnerabilities and how to avoid them:
The Open Web Application Security Project (OWASP) has an
introductory
article on XSS.