mirror of
https://github.com/OlafvdSpek/ctemplate.git
synced 2025-10-05 19:16:54 +08:00
Thu Jan 24 16:09:43 2008 Google Inc. <opensource@google.com>
* 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
This commit is contained in:
parent
bb570c29d4
commit
896bd2ef9c
136
trunk/ChangeLog
136
trunk/ChangeLog
|
@ -1,9 +1,75 @@
|
|||
Mon Mar 13 22:20:46 2006 Google Inc. <opensource@google.com>
|
||||
Thu Jan 24 16:09:43 2008 Google Inc. <opensource@google.com>
|
||||
|
||||
* ctemplate: initial release:
|
||||
The ctemplate package contains a library implementing a simple
|
||||
but powerful template language for C++. It emphasizes
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
* 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. <opensource@google.com>
|
||||
|
||||
|
@ -16,62 +82,8 @@ Wed Jun 14 14:56:04 2006 Google Inc. <opensource@google.com>
|
|||
* Export a nothreads version of the ctemplate library (csilvers)
|
||||
* Got rid of scandir call, which should improve portability (csilvers)
|
||||
|
||||
Mon Aug 21 17:44:32 2006 Google Inc. <opensource@google.com>
|
||||
Mon Mar 13 22:20:46 2006 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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)
|
||||
* Add JSON escape-functor (majewski)
|
||||
|
||||
Mon Jan 15 14:10:42 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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 May 14 17:27:10 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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)
|
||||
|
||||
Sat Jun 9 22:34:52 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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)
|
||||
|
||||
Thu Jun 21 14:02:32 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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)
|
||||
|
||||
Tue Jul 3 12:46:59 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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 Aug 16 21:42:55 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* 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)
|
||||
* ctemplate: initial release:
|
||||
The ctemplate package contains a library implementing a simple
|
||||
but powerful template language for C++. It emphasizes
|
||||
|
|
|
@ -93,6 +93,17 @@ libctemplate_nothreads_la_SOURCES = $(libctemplate_la_SOURCES)
|
|||
libctemplate_nothreads_la_CXXFLAGS = -DNDEBUG -DNO_THREADS $(AM_CXXFLAGS)
|
||||
libctemplate_nothreads_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_SYMBOLS)
|
||||
|
||||
# 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_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_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
|
||||
|
@ -106,7 +117,7 @@ noinst_LTLIBRARIES += libctemplate_testing.la
|
|||
libctemplate_testing_la_SOURCES = $(googleinclude_HEADERS) \
|
||||
src/tests/template_test_util.h \
|
||||
src/tests/template_test_util.cc
|
||||
libctemplate_testing_la_CXXFLAGS = -DNDEBUG $(AM_CXXFLAGS)
|
||||
libctemplate_testing_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
CTEMPLATE_TESTING_SYMBOLS = 'TemporaryRegisterTemplate|TemplateDictionaryPeer'
|
||||
libctemplate_testing_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_TESTING_SYMBOLS)
|
||||
# This library depends on libctemplate, but it can use either libctemplate
|
||||
|
@ -134,12 +145,13 @@ template_dictionary_unittest_SOURCES = src/config_for_unittests.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.la libctemplate_testing.la \
|
||||
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_nothreads.la \
|
||||
libctemplate_testing.la
|
||||
template_dictionary_nothreads_unittest_LDADD = libctemplate_testing.la \
|
||||
libctemplate_nothreads_debug.la
|
||||
|
||||
|
||||
TESTS += template_modifiers_unittest template_modifiers_nothreads_unittest
|
||||
WINDOWS_PROJECTS += vsprojects/template_modifiers_unittest/template_modifiers_unittest.vcproj
|
||||
|
@ -147,12 +159,12 @@ template_modifiers_unittest_SOURCES = src/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.la libctemplate_testing.la \
|
||||
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_nothreads.la \
|
||||
libctemplate_testing.la
|
||||
template_modifiers_nothreads_unittest_LDADD = libctemplate_testing.la \
|
||||
libctemplate_nothreads_debug.la
|
||||
|
||||
TESTS += template_setglobals_unittest template_setglobals_nothreads_unittest
|
||||
WINDOWS_PROJECTS += vsprojects/template_setglobals_unittest/template_setglobals_unittest.vcproj
|
||||
|
@ -160,10 +172,10 @@ template_setglobals_unittest_SOURCES = src/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.la $(PTHREAD_LIBS)
|
||||
template_setglobals_unittest_LDADD = 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_nothreads.la
|
||||
template_setglobals_nothreads_unittest_LDADD = libctemplate_nothreads_debug.la
|
||||
|
||||
TESTS += template_from_string_unittest template_from_string_nothreads_unittest
|
||||
WINDOWS_PROJECTS += vsprojects/template_from_string_unittest/template_from_string_unittest.vcproj
|
||||
|
@ -171,10 +183,10 @@ template_from_string_unittest_SOURCES = src/config_for_unittests.h \
|
|||
src/tests/template_from_string_unittest.cc
|
||||
template_from_string_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_from_string_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_from_string_unittest_LDADD = libctemplate.la $(PTHREAD_LIBS)
|
||||
template_from_string_unittest_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
|
||||
template_from_string_nothreads_unittest_SOURCES = $(template_from_string_unittest_SOURCES)
|
||||
template_from_string_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
|
||||
template_from_string_nothreads_unittest_LDADD = libctemplate_nothreads.la
|
||||
template_from_string_nothreads_unittest_LDADD = libctemplate_nothreads_debug.la
|
||||
|
||||
TESTS += template_unittest template_nothreads_unittest
|
||||
WINDOWS_PROJECTS += vsprojects/template_unittest/template_unittest.vcproj
|
||||
|
@ -183,20 +195,20 @@ template_unittest_SOURCES = src/config_for_unittests.h \
|
|||
src/tests/template_unittest.cc
|
||||
template_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_unittest_LDADD = libctemplate.la $(PTHREAD_LIBS)
|
||||
template_unittest_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
|
||||
template_nothreads_unittest_SOURCES = src/tests/template_unittest.cc
|
||||
template_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
|
||||
template_nothreads_unittest_LDADD = libctemplate_nothreads.la
|
||||
template_nothreads_unittest_LDADD = libctemplate_nothreads_debug.la
|
||||
|
||||
TESTS += template_regtest template_nothreads_regtest
|
||||
WINDOWS_PROJECTS += vsprojects/template_regtest/template_regtest.vcproj
|
||||
template_regtest_SOURCES = src/tests/template_regtest.cc
|
||||
template_regtest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_regtest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_regtest_LDADD = libctemplate.la $(PTHREAD_LIBS)
|
||||
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.la
|
||||
template_nothreads_regtest_LDADD = libctemplate_nothreads_debug.la
|
||||
|
||||
make_tpl_varnames_h_unittest_sh: $(top_srcdir)/src/tests/make_tpl_varnames_h_unittest.sh \
|
||||
make_tpl_varnames_h
|
||||
|
|
|
@ -95,17 +95,40 @@ am_libctemplate_la_OBJECTS = libctemplate_la-arena.lo \
|
|||
libctemplate_la-template_pathops.lo \
|
||||
libctemplate_la-template_from_string.lo
|
||||
libctemplate_la_OBJECTS = $(am_libctemplate_la_OBJECTS)
|
||||
am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
||||
libctemplate_debug_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
|
||||
am__objects_1 = libctemplate_debug_la-arena.lo \
|
||||
libctemplate_debug_la-template.lo \
|
||||
libctemplate_debug_la-template_dictionary.lo \
|
||||
libctemplate_debug_la-template_modifiers.lo \
|
||||
libctemplate_debug_la-template_namelist.lo \
|
||||
libctemplate_debug_la-template_pathops.lo \
|
||||
libctemplate_debug_la-template_from_string.lo
|
||||
am_libctemplate_debug_la_OBJECTS = $(am__objects_1)
|
||||
libctemplate_debug_la_OBJECTS = $(am_libctemplate_debug_la_OBJECTS)
|
||||
libctemplate_nothreads_la_LIBADD =
|
||||
am__objects_1 = libctemplate_nothreads_la-arena.lo \
|
||||
am__objects_2 = libctemplate_nothreads_la-arena.lo \
|
||||
libctemplate_nothreads_la-template.lo \
|
||||
libctemplate_nothreads_la-template_dictionary.lo \
|
||||
libctemplate_nothreads_la-template_modifiers.lo \
|
||||
libctemplate_nothreads_la-template_namelist.lo \
|
||||
libctemplate_nothreads_la-template_pathops.lo \
|
||||
libctemplate_nothreads_la-template_from_string.lo
|
||||
am_libctemplate_nothreads_la_OBJECTS = $(am__objects_1)
|
||||
am_libctemplate_nothreads_la_OBJECTS = $(am__objects_2)
|
||||
libctemplate_nothreads_la_OBJECTS = \
|
||||
$(am_libctemplate_nothreads_la_OBJECTS)
|
||||
libctemplate_nothreads_debug_la_LIBADD =
|
||||
am__objects_3 = libctemplate_nothreads_debug_la-arena.lo \
|
||||
libctemplate_nothreads_debug_la-template.lo \
|
||||
libctemplate_nothreads_debug_la-template_dictionary.lo \
|
||||
libctemplate_nothreads_debug_la-template_modifiers.lo \
|
||||
libctemplate_nothreads_debug_la-template_namelist.lo \
|
||||
libctemplate_nothreads_debug_la-template_pathops.lo \
|
||||
libctemplate_nothreads_debug_la-template_from_string.lo
|
||||
am__objects_4 = $(am__objects_3)
|
||||
am_libctemplate_nothreads_debug_la_OBJECTS = $(am__objects_4)
|
||||
libctemplate_nothreads_debug_la_OBJECTS = \
|
||||
$(am_libctemplate_nothreads_debug_la_OBJECTS)
|
||||
libctemplate_testing_la_LIBADD =
|
||||
am_libctemplate_testing_la_OBJECTS = \
|
||||
libctemplate_testing_la-template_test_util.lo
|
||||
|
@ -127,68 +150,72 @@ PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
|
|||
am_make_tpl_varnames_h_OBJECTS = make_tpl_varnames_h.$(OBJEXT)
|
||||
make_tpl_varnames_h_OBJECTS = $(am_make_tpl_varnames_h_OBJECTS)
|
||||
make_tpl_varnames_h_DEPENDENCIES = libctemplate_nothreads.la
|
||||
am__objects_2 = template_dictionary_nothreads_unittest-template_dictionary_unittest.$(OBJEXT)
|
||||
am_template_dictionary_nothreads_unittest_OBJECTS = $(am__objects_2)
|
||||
am__objects_5 = template_dictionary_nothreads_unittest-template_dictionary_unittest.$(OBJEXT)
|
||||
am_template_dictionary_nothreads_unittest_OBJECTS = $(am__objects_5)
|
||||
template_dictionary_nothreads_unittest_OBJECTS = \
|
||||
$(am_template_dictionary_nothreads_unittest_OBJECTS)
|
||||
template_dictionary_nothreads_unittest_DEPENDENCIES = \
|
||||
libctemplate_nothreads.la libctemplate_testing.la
|
||||
libctemplate_testing.la libctemplate_nothreads_debug.la
|
||||
am_template_dictionary_unittest_OBJECTS = template_dictionary_unittest-template_dictionary_unittest.$(OBJEXT)
|
||||
template_dictionary_unittest_OBJECTS = \
|
||||
$(am_template_dictionary_unittest_OBJECTS)
|
||||
template_dictionary_unittest_DEPENDENCIES = libctemplate.la \
|
||||
libctemplate_testing.la $(am__DEPENDENCIES_1)
|
||||
am__objects_3 = template_from_string_nothreads_unittest-template_from_string_unittest.$(OBJEXT)
|
||||
am_template_from_string_nothreads_unittest_OBJECTS = $(am__objects_3)
|
||||
template_dictionary_unittest_DEPENDENCIES = libctemplate_testing.la \
|
||||
libctemplate_debug.la $(am__DEPENDENCIES_1)
|
||||
am__objects_6 = template_from_string_nothreads_unittest-template_from_string_unittest.$(OBJEXT)
|
||||
am_template_from_string_nothreads_unittest_OBJECTS = $(am__objects_6)
|
||||
template_from_string_nothreads_unittest_OBJECTS = \
|
||||
$(am_template_from_string_nothreads_unittest_OBJECTS)
|
||||
template_from_string_nothreads_unittest_DEPENDENCIES = \
|
||||
libctemplate_nothreads.la
|
||||
libctemplate_nothreads_debug.la
|
||||
am_template_from_string_unittest_OBJECTS = template_from_string_unittest-template_from_string_unittest.$(OBJEXT)
|
||||
template_from_string_unittest_OBJECTS = \
|
||||
$(am_template_from_string_unittest_OBJECTS)
|
||||
template_from_string_unittest_DEPENDENCIES = libctemplate.la \
|
||||
template_from_string_unittest_DEPENDENCIES = libctemplate_debug.la \
|
||||
$(am__DEPENDENCIES_1)
|
||||
am__objects_4 = template_modifiers_nothreads_unittest-template_modifiers_unittest.$(OBJEXT)
|
||||
am_template_modifiers_nothreads_unittest_OBJECTS = $(am__objects_4)
|
||||
am__objects_7 = template_modifiers_nothreads_unittest-template_modifiers_unittest.$(OBJEXT)
|
||||
am_template_modifiers_nothreads_unittest_OBJECTS = $(am__objects_7)
|
||||
template_modifiers_nothreads_unittest_OBJECTS = \
|
||||
$(am_template_modifiers_nothreads_unittest_OBJECTS)
|
||||
template_modifiers_nothreads_unittest_DEPENDENCIES = \
|
||||
libctemplate_nothreads.la libctemplate_testing.la
|
||||
libctemplate_testing.la libctemplate_nothreads_debug.la
|
||||
am_template_modifiers_unittest_OBJECTS = template_modifiers_unittest-template_modifiers_unittest.$(OBJEXT)
|
||||
template_modifiers_unittest_OBJECTS = \
|
||||
$(am_template_modifiers_unittest_OBJECTS)
|
||||
template_modifiers_unittest_DEPENDENCIES = libctemplate.la \
|
||||
libctemplate_testing.la $(am__DEPENDENCIES_1)
|
||||
am__objects_5 = template_nothreads_regtest-template_regtest.$(OBJEXT)
|
||||
am_template_nothreads_regtest_OBJECTS = $(am__objects_5)
|
||||
template_modifiers_unittest_DEPENDENCIES = libctemplate_testing.la \
|
||||
libctemplate_debug.la $(am__DEPENDENCIES_1)
|
||||
am__objects_8 = template_nothreads_regtest-template_regtest.$(OBJEXT)
|
||||
am_template_nothreads_regtest_OBJECTS = $(am__objects_8)
|
||||
template_nothreads_regtest_OBJECTS = \
|
||||
$(am_template_nothreads_regtest_OBJECTS)
|
||||
template_nothreads_regtest_DEPENDENCIES = libctemplate_nothreads.la
|
||||
template_nothreads_regtest_DEPENDENCIES = \
|
||||
libctemplate_nothreads_debug.la
|
||||
am_template_nothreads_unittest_OBJECTS = \
|
||||
template_nothreads_unittest-template_unittest.$(OBJEXT)
|
||||
template_nothreads_unittest_OBJECTS = \
|
||||
$(am_template_nothreads_unittest_OBJECTS)
|
||||
template_nothreads_unittest_DEPENDENCIES = libctemplate_nothreads.la
|
||||
template_nothreads_unittest_DEPENDENCIES = \
|
||||
libctemplate_nothreads_debug.la
|
||||
am_template_regtest_OBJECTS = \
|
||||
template_regtest-template_regtest.$(OBJEXT)
|
||||
template_regtest_OBJECTS = $(am_template_regtest_OBJECTS)
|
||||
template_regtest_DEPENDENCIES = libctemplate.la $(am__DEPENDENCIES_1)
|
||||
am__objects_6 = template_setglobals_nothreads_unittest-template_setglobals_unittest.$(OBJEXT)
|
||||
am_template_setglobals_nothreads_unittest_OBJECTS = $(am__objects_6)
|
||||
template_regtest_DEPENDENCIES = libctemplate_debug.la \
|
||||
$(am__DEPENDENCIES_1)
|
||||
am__objects_9 = template_setglobals_nothreads_unittest-template_setglobals_unittest.$(OBJEXT)
|
||||
am_template_setglobals_nothreads_unittest_OBJECTS = $(am__objects_9)
|
||||
template_setglobals_nothreads_unittest_OBJECTS = \
|
||||
$(am_template_setglobals_nothreads_unittest_OBJECTS)
|
||||
template_setglobals_nothreads_unittest_DEPENDENCIES = \
|
||||
libctemplate_nothreads.la
|
||||
libctemplate_nothreads_debug.la
|
||||
am_template_setglobals_unittest_OBJECTS = template_setglobals_unittest-template_setglobals_unittest.$(OBJEXT)
|
||||
template_setglobals_unittest_OBJECTS = \
|
||||
$(am_template_setglobals_unittest_OBJECTS)
|
||||
template_setglobals_unittest_DEPENDENCIES = libctemplate.la \
|
||||
template_setglobals_unittest_DEPENDENCIES = libctemplate_debug.la \
|
||||
$(am__DEPENDENCIES_1)
|
||||
am_template_unittest_OBJECTS = \
|
||||
template_unittest-template_unittest.$(OBJEXT)
|
||||
template_unittest_OBJECTS = $(am_template_unittest_OBJECTS)
|
||||
template_unittest_DEPENDENCIES = libctemplate.la $(am__DEPENDENCIES_1)
|
||||
template_unittest_DEPENDENCIES = libctemplate_debug.la \
|
||||
$(am__DEPENDENCIES_1)
|
||||
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
|
||||
SCRIPTS = $(bin_SCRIPTS) $(noinst_SCRIPTS)
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/src
|
||||
|
@ -210,8 +237,9 @@ LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
|
|||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(libctemplate_la_SOURCES) \
|
||||
SOURCES = $(libctemplate_la_SOURCES) $(libctemplate_debug_la_SOURCES) \
|
||||
$(libctemplate_nothreads_la_SOURCES) \
|
||||
$(libctemplate_nothreads_debug_la_SOURCES) \
|
||||
$(libctemplate_testing_la_SOURCES) \
|
||||
$(make_tpl_varnames_h_SOURCES) \
|
||||
$(template_dictionary_nothreads_unittest_SOURCES) \
|
||||
|
@ -227,7 +255,9 @@ SOURCES = $(libctemplate_la_SOURCES) \
|
|||
$(template_setglobals_unittest_SOURCES) \
|
||||
$(template_unittest_SOURCES)
|
||||
DIST_SOURCES = $(libctemplate_la_SOURCES) \
|
||||
$(libctemplate_debug_la_SOURCES) \
|
||||
$(libctemplate_nothreads_la_SOURCES) \
|
||||
$(libctemplate_nothreads_debug_la_SOURCES) \
|
||||
$(libctemplate_testing_la_SOURCES) \
|
||||
$(make_tpl_varnames_h_SOURCES) \
|
||||
$(template_dictionary_nothreads_unittest_SOURCES) \
|
||||
|
@ -412,6 +442,8 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README README.windows \
|
|||
# because we use an extra compiler flag.
|
||||
lib_LTLIBRARIES = libctemplate.la libctemplate_nothreads.la
|
||||
|
||||
# For our tests, we want versions of these libraries that include asserts.
|
||||
|
||||
# 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
|
||||
|
@ -420,7 +452,8 @@ lib_LTLIBRARIES = libctemplate.la libctemplate_nothreads.la
|
|||
# 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!
|
||||
noinst_LTLIBRARIES = libctemplate_testing.la
|
||||
noinst_LTLIBRARIES = libctemplate_debug.la \
|
||||
libctemplate_nothreads_debug.la libctemplate_testing.la
|
||||
bin_SCRIPTS = src/template-converter
|
||||
WINDOWS_PROJECTS = google-ctemplate.sln \
|
||||
vsprojects/libctemplate/libctemplate.vcproj \
|
||||
|
@ -467,11 +500,18 @@ libctemplate_la_LIBADD = $(PTHREAD_LIBS)
|
|||
libctemplate_nothreads_la_SOURCES = $(libctemplate_la_SOURCES)
|
||||
libctemplate_nothreads_la_CXXFLAGS = -DNDEBUG -DNO_THREADS $(AM_CXXFLAGS)
|
||||
libctemplate_nothreads_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_SYMBOLS)
|
||||
libctemplate_debug_la_SOURCES = $(libctemplate_la_SOURCES)
|
||||
libctemplate_debug_la_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
libctemplate_debug_la_LDFLAGS = $(libctemplate_la_LDFLAGS)
|
||||
libctemplate_debug_la_LIBADD = $(libctemplate_la_LIBADD)
|
||||
libctemplate_nothreads_debug_la_SOURCES = $(libctemplate_nothreads_la_SOURCES)
|
||||
libctemplate_nothreads_debug_la_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
|
||||
libctemplate_nothreads_debug_la_LDFLAGS = $(libctemplate_nothreads_la_LDFLAGS)
|
||||
libctemplate_testing_la_SOURCES = $(googleinclude_HEADERS) \
|
||||
src/tests/template_test_util.h \
|
||||
src/tests/template_test_util.cc
|
||||
|
||||
libctemplate_testing_la_CXXFLAGS = -DNDEBUG $(AM_CXXFLAGS)
|
||||
libctemplate_testing_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
CTEMPLATE_TESTING_SYMBOLS = 'TemporaryRegisterTemplate|TemplateDictionaryPeer'
|
||||
libctemplate_testing_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_TESTING_SYMBOLS)
|
||||
make_tpl_varnames_h_SOURCES = $(googleinclude_HEADERS) \
|
||||
|
@ -484,61 +524,61 @@ template_dictionary_unittest_SOURCES = src/config_for_unittests.h \
|
|||
|
||||
template_dictionary_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_dictionary_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_dictionary_unittest_LDADD = libctemplate.la libctemplate_testing.la \
|
||||
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_nothreads.la \
|
||||
libctemplate_testing.la
|
||||
template_dictionary_nothreads_unittest_LDADD = libctemplate_testing.la \
|
||||
libctemplate_nothreads_debug.la
|
||||
|
||||
template_modifiers_unittest_SOURCES = src/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.la libctemplate_testing.la \
|
||||
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_nothreads.la \
|
||||
libctemplate_testing.la
|
||||
template_modifiers_nothreads_unittest_LDADD = libctemplate_testing.la \
|
||||
libctemplate_nothreads_debug.la
|
||||
|
||||
template_setglobals_unittest_SOURCES = src/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.la $(PTHREAD_LIBS)
|
||||
template_setglobals_unittest_LDADD = 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_nothreads.la
|
||||
template_setglobals_nothreads_unittest_LDADD = libctemplate_nothreads_debug.la
|
||||
template_from_string_unittest_SOURCES = src/config_for_unittests.h \
|
||||
src/tests/template_from_string_unittest.cc
|
||||
|
||||
template_from_string_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_from_string_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_from_string_unittest_LDADD = libctemplate.la $(PTHREAD_LIBS)
|
||||
template_from_string_unittest_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
|
||||
template_from_string_nothreads_unittest_SOURCES = $(template_from_string_unittest_SOURCES)
|
||||
template_from_string_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
|
||||
template_from_string_nothreads_unittest_LDADD = libctemplate_nothreads.la
|
||||
template_from_string_nothreads_unittest_LDADD = libctemplate_nothreads_debug.la
|
||||
template_unittest_SOURCES = src/config_for_unittests.h \
|
||||
src/tests/template_unittest.cc
|
||||
|
||||
template_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_unittest_LDADD = libctemplate.la $(PTHREAD_LIBS)
|
||||
template_unittest_LDADD = libctemplate_debug.la $(PTHREAD_LIBS)
|
||||
template_nothreads_unittest_SOURCES = src/tests/template_unittest.cc
|
||||
template_nothreads_unittest_CXXFLAGS = -DNO_THREADS $(AM_CXXFLAGS)
|
||||
template_nothreads_unittest_LDADD = libctemplate_nothreads.la
|
||||
template_nothreads_unittest_LDADD = libctemplate_nothreads_debug.la
|
||||
template_regtest_SOURCES = src/tests/template_regtest.cc
|
||||
template_regtest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
|
||||
template_regtest_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
template_regtest_LDADD = libctemplate.la $(PTHREAD_LIBS)
|
||||
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.la
|
||||
template_nothreads_regtest_LDADD = libctemplate_nothreads_debug.la
|
||||
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
|
||||
$(SCRIPTS) libtool \
|
||||
src/windows $(WINDOWS_PROJECTS) src/solaris/libstdc++.la contrib
|
||||
|
@ -651,8 +691,12 @@ clean-noinstLTLIBRARIES:
|
|||
done
|
||||
libctemplate.la: $(libctemplate_la_OBJECTS) $(libctemplate_la_DEPENDENCIES)
|
||||
$(CXXLINK) -rpath $(libdir) $(libctemplate_la_LDFLAGS) $(libctemplate_la_OBJECTS) $(libctemplate_la_LIBADD) $(LIBS)
|
||||
libctemplate_debug.la: $(libctemplate_debug_la_OBJECTS) $(libctemplate_debug_la_DEPENDENCIES)
|
||||
$(CXXLINK) $(libctemplate_debug_la_LDFLAGS) $(libctemplate_debug_la_OBJECTS) $(libctemplate_debug_la_LIBADD) $(LIBS)
|
||||
libctemplate_nothreads.la: $(libctemplate_nothreads_la_OBJECTS) $(libctemplate_nothreads_la_DEPENDENCIES)
|
||||
$(CXXLINK) -rpath $(libdir) $(libctemplate_nothreads_la_LDFLAGS) $(libctemplate_nothreads_la_OBJECTS) $(libctemplate_nothreads_la_LIBADD) $(LIBS)
|
||||
libctemplate_nothreads_debug.la: $(libctemplate_nothreads_debug_la_OBJECTS) $(libctemplate_nothreads_debug_la_DEPENDENCIES)
|
||||
$(CXXLINK) $(libctemplate_nothreads_debug_la_LDFLAGS) $(libctemplate_nothreads_debug_la_OBJECTS) $(libctemplate_nothreads_debug_la_LIBADD) $(LIBS)
|
||||
libctemplate_testing.la: $(libctemplate_testing_la_OBJECTS) $(libctemplate_testing_la_DEPENDENCIES)
|
||||
$(CXXLINK) $(libctemplate_testing_la_LDFLAGS) $(libctemplate_testing_la_OBJECTS) $(libctemplate_testing_la_LIBADD) $(LIBS)
|
||||
install-binPROGRAMS: $(bin_PROGRAMS)
|
||||
|
@ -755,6 +799,13 @@ mostlyclean-compile:
|
|||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-arena.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-template.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-template_dictionary.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-template_from_string.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-template_modifiers.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-template_namelist.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_debug_la-template_pathops.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-arena.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_dictionary.Plo@am__quote@
|
||||
|
@ -762,6 +813,13 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_modifiers.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_namelist.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_pathops.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-arena.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-template.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-template_dictionary.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-template_from_string.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-template_modifiers.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-template_namelist.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_debug_la-template_pathops.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-arena.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-template.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-template_dictionary.Plo@am__quote@
|
||||
|
@ -854,6 +912,55 @@ libctemplate_la-template_from_string.lo: src/template_from_string.cc
|
|||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_la-template_from_string.lo `test -f 'src/template_from_string.cc' || echo '$(srcdir)/'`src/template_from_string.cc
|
||||
|
||||
libctemplate_debug_la-arena.lo: src/base/arena.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-arena.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-arena.Tpo" -c -o libctemplate_debug_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-arena.Tpo" "$(DEPDIR)/libctemplate_debug_la-arena.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-arena.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/arena.cc' object='libctemplate_debug_la-arena.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc
|
||||
|
||||
libctemplate_debug_la-template.lo: src/template.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-template.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-template.Tpo" -c -o libctemplate_debug_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-template.Tpo" "$(DEPDIR)/libctemplate_debug_la-template.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-template.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template.cc' object='libctemplate_debug_la-template.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc
|
||||
|
||||
libctemplate_debug_la-template_dictionary.lo: src/template_dictionary.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-template_dictionary.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-template_dictionary.Tpo" -c -o libctemplate_debug_la-template_dictionary.lo `test -f 'src/template_dictionary.cc' || echo '$(srcdir)/'`src/template_dictionary.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-template_dictionary.Tpo" "$(DEPDIR)/libctemplate_debug_la-template_dictionary.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-template_dictionary.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_dictionary.cc' object='libctemplate_debug_la-template_dictionary.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-template_dictionary.lo `test -f 'src/template_dictionary.cc' || echo '$(srcdir)/'`src/template_dictionary.cc
|
||||
|
||||
libctemplate_debug_la-template_modifiers.lo: src/template_modifiers.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-template_modifiers.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-template_modifiers.Tpo" -c -o libctemplate_debug_la-template_modifiers.lo `test -f 'src/template_modifiers.cc' || echo '$(srcdir)/'`src/template_modifiers.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-template_modifiers.Tpo" "$(DEPDIR)/libctemplate_debug_la-template_modifiers.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-template_modifiers.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_modifiers.cc' object='libctemplate_debug_la-template_modifiers.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-template_modifiers.lo `test -f 'src/template_modifiers.cc' || echo '$(srcdir)/'`src/template_modifiers.cc
|
||||
|
||||
libctemplate_debug_la-template_namelist.lo: src/template_namelist.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-template_namelist.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-template_namelist.Tpo" -c -o libctemplate_debug_la-template_namelist.lo `test -f 'src/template_namelist.cc' || echo '$(srcdir)/'`src/template_namelist.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-template_namelist.Tpo" "$(DEPDIR)/libctemplate_debug_la-template_namelist.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-template_namelist.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_namelist.cc' object='libctemplate_debug_la-template_namelist.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-template_namelist.lo `test -f 'src/template_namelist.cc' || echo '$(srcdir)/'`src/template_namelist.cc
|
||||
|
||||
libctemplate_debug_la-template_pathops.lo: src/template_pathops.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-template_pathops.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-template_pathops.Tpo" -c -o libctemplate_debug_la-template_pathops.lo `test -f 'src/template_pathops.cc' || echo '$(srcdir)/'`src/template_pathops.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-template_pathops.Tpo" "$(DEPDIR)/libctemplate_debug_la-template_pathops.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-template_pathops.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_pathops.cc' object='libctemplate_debug_la-template_pathops.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-template_pathops.lo `test -f 'src/template_pathops.cc' || echo '$(srcdir)/'`src/template_pathops.cc
|
||||
|
||||
libctemplate_debug_la-template_from_string.lo: src/template_from_string.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_debug_la-template_from_string.lo -MD -MP -MF "$(DEPDIR)/libctemplate_debug_la-template_from_string.Tpo" -c -o libctemplate_debug_la-template_from_string.lo `test -f 'src/template_from_string.cc' || echo '$(srcdir)/'`src/template_from_string.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_debug_la-template_from_string.Tpo" "$(DEPDIR)/libctemplate_debug_la-template_from_string.Plo"; else rm -f "$(DEPDIR)/libctemplate_debug_la-template_from_string.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_from_string.cc' object='libctemplate_debug_la-template_from_string.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_debug_la-template_from_string.lo `test -f 'src/template_from_string.cc' || echo '$(srcdir)/'`src/template_from_string.cc
|
||||
|
||||
libctemplate_nothreads_la-arena.lo: src/base/arena.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_la-arena.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_la-arena.Tpo" -c -o libctemplate_nothreads_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_la-arena.Tpo" "$(DEPDIR)/libctemplate_nothreads_la-arena.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_la-arena.Tpo"; exit 1; fi
|
||||
|
@ -903,6 +1010,55 @@ libctemplate_nothreads_la-template_from_string.lo: src/template_from_string.cc
|
|||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_la-template_from_string.lo `test -f 'src/template_from_string.cc' || echo '$(srcdir)/'`src/template_from_string.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-arena.lo: src/base/arena.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-arena.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-arena.Tpo" -c -o libctemplate_nothreads_debug_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-arena.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-arena.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-arena.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/arena.cc' object='libctemplate_nothreads_debug_la-arena.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-template.lo: src/template.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-template.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-template.Tpo" -c -o libctemplate_nothreads_debug_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-template.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template.cc' object='libctemplate_nothreads_debug_la-template.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-template_dictionary.lo: src/template_dictionary.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-template_dictionary.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-template_dictionary.Tpo" -c -o libctemplate_nothreads_debug_la-template_dictionary.lo `test -f 'src/template_dictionary.cc' || echo '$(srcdir)/'`src/template_dictionary.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_dictionary.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-template_dictionary.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_dictionary.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_dictionary.cc' object='libctemplate_nothreads_debug_la-template_dictionary.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-template_dictionary.lo `test -f 'src/template_dictionary.cc' || echo '$(srcdir)/'`src/template_dictionary.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-template_modifiers.lo: src/template_modifiers.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-template_modifiers.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-template_modifiers.Tpo" -c -o libctemplate_nothreads_debug_la-template_modifiers.lo `test -f 'src/template_modifiers.cc' || echo '$(srcdir)/'`src/template_modifiers.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_modifiers.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-template_modifiers.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_modifiers.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_modifiers.cc' object='libctemplate_nothreads_debug_la-template_modifiers.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-template_modifiers.lo `test -f 'src/template_modifiers.cc' || echo '$(srcdir)/'`src/template_modifiers.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-template_namelist.lo: src/template_namelist.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-template_namelist.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-template_namelist.Tpo" -c -o libctemplate_nothreads_debug_la-template_namelist.lo `test -f 'src/template_namelist.cc' || echo '$(srcdir)/'`src/template_namelist.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_namelist.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-template_namelist.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_namelist.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_namelist.cc' object='libctemplate_nothreads_debug_la-template_namelist.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-template_namelist.lo `test -f 'src/template_namelist.cc' || echo '$(srcdir)/'`src/template_namelist.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-template_pathops.lo: src/template_pathops.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-template_pathops.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-template_pathops.Tpo" -c -o libctemplate_nothreads_debug_la-template_pathops.lo `test -f 'src/template_pathops.cc' || echo '$(srcdir)/'`src/template_pathops.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_pathops.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-template_pathops.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_pathops.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_pathops.cc' object='libctemplate_nothreads_debug_la-template_pathops.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-template_pathops.lo `test -f 'src/template_pathops.cc' || echo '$(srcdir)/'`src/template_pathops.cc
|
||||
|
||||
libctemplate_nothreads_debug_la-template_from_string.lo: src/template_from_string.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_debug_la-template_from_string.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_debug_la-template_from_string.Tpo" -c -o libctemplate_nothreads_debug_la-template_from_string.lo `test -f 'src/template_from_string.cc' || echo '$(srcdir)/'`src/template_from_string.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_from_string.Tpo" "$(DEPDIR)/libctemplate_nothreads_debug_la-template_from_string.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_debug_la-template_from_string.Tpo"; exit 1; fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/template_from_string.cc' object='libctemplate_nothreads_debug_la-template_from_string.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_nothreads_debug_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_debug_la-template_from_string.lo `test -f 'src/template_from_string.cc' || echo '$(srcdir)/'`src/template_from_string.cc
|
||||
|
||||
libctemplate_testing_la-template_test_util.lo: src/tests/template_test_util.cc
|
||||
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_testing_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_testing_la-template_test_util.lo -MD -MP -MF "$(DEPDIR)/libctemplate_testing_la-template_test_util.Tpo" -c -o libctemplate_testing_la-template_test_util.lo `test -f 'src/tests/template_test_util.cc' || echo '$(srcdir)/'`src/tests/template_test_util.cc; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_testing_la-template_test_util.Tpo" "$(DEPDIR)/libctemplate_testing_la-template_test_util.Plo"; else rm -f "$(DEPDIR)/libctemplate_testing_la-template_test_util.Tpo"; exit 1; fi
|
||||
|
|
20
trunk/configure
vendored
20
trunk/configure
vendored
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.59 for ctemplate 0.8.
|
||||
# Generated by GNU Autoconf 2.59 for ctemplate 0.9.
|
||||
#
|
||||
# Report bugs to <opensource@google.com>.
|
||||
#
|
||||
|
@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
|||
# Identity of this package.
|
||||
PACKAGE_NAME='ctemplate'
|
||||
PACKAGE_TARNAME='ctemplate'
|
||||
PACKAGE_VERSION='0.8'
|
||||
PACKAGE_STRING='ctemplate 0.8'
|
||||
PACKAGE_VERSION='0.9'
|
||||
PACKAGE_STRING='ctemplate 0.9'
|
||||
PACKAGE_BUGREPORT='opensource@google.com'
|
||||
|
||||
ac_unique_file="README"
|
||||
|
@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
|
|||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures ctemplate 0.8 to adapt to many kinds of systems.
|
||||
\`configure' configures ctemplate 0.9 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
|
@ -1020,7 +1020,7 @@ fi
|
|||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of ctemplate 0.8:";;
|
||||
short | recursive ) echo "Configuration of ctemplate 0.9:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
|
@ -1163,7 +1163,7 @@ fi
|
|||
test -n "$ac_init_help" && exit 0
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
ctemplate configure 0.8
|
||||
ctemplate configure 0.9
|
||||
generated by GNU Autoconf 2.59
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
@ -1177,7 +1177,7 @@ cat >&5 <<_ACEOF
|
|||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by ctemplate $as_me 0.8, which was
|
||||
It was created by ctemplate $as_me 0.9, which was
|
||||
generated by GNU Autoconf 2.59. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
|
@ -1823,7 +1823,7 @@ fi
|
|||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='ctemplate'
|
||||
VERSION='0.8'
|
||||
VERSION='0.9'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
@ -21044,7 +21044,7 @@ _ASBOX
|
|||
} >&5
|
||||
cat >&5 <<_CSEOF
|
||||
|
||||
This file was extended by ctemplate $as_me 0.8, which was
|
||||
This file was extended by ctemplate $as_me 0.9, which was
|
||||
generated by GNU Autoconf 2.59. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
|
@ -21107,7 +21107,7 @@ _ACEOF
|
|||
|
||||
cat >>$CONFIG_STATUS <<_ACEOF
|
||||
ac_cs_version="\\
|
||||
ctemplate config.status 0.8
|
||||
ctemplate config.status 0.9
|
||||
configured by $0, generated by GNU Autoconf 2.59,
|
||||
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# make sure we're interpreted by some minimal autoconf
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
AC_INIT(ctemplate, 0.8, opensource@google.com)
|
||||
AC_INIT(ctemplate, 0.9, opensource@google.com)
|
||||
# The argument here is just something that should be in the current directory
|
||||
# (for sanity checking)
|
||||
AC_CONFIG_SRCDIR(README)
|
||||
|
|
|
@ -326,7 +326,7 @@ previous one:</p>
|
|||
<tr><td><code>:json_escape</code></td><td><code>:o</code></td>
|
||||
<td>json-escapes a variable before output as a string in json;
|
||||
similar to javascript escaping, but ignores characters such
|
||||
as <code>=</code> and <code>&</code>.</td>
|
||||
as <code>=</code> and <code>&</code>.</td>
|
||||
</tr>
|
||||
|
||||
<tr><td><code>:html_escape_with_arg</code></td><td><code>:H</code></td>
|
||||
|
@ -345,11 +345,11 @@ previous one:</p>
|
|||
|
||||
<p>The <code>html_escape_with_arg</code>
|
||||
and <code>url_escape_with_arg</code> modifiers are a bit different
|
||||
because they requires a value to specify the type of escaping to use.
|
||||
because they require a value to specify the type of escaping to use.
|
||||
For example, this template is equivalent to using
|
||||
the <code>pre_escape</code> modifier:</p>
|
||||
<pre>
|
||||
<html><body><pre>{{BODY:H=pre}}</pre></body></html>
|
||||
<html><body><pre>{{BODY:H=pre}}</pre></body></html>
|
||||
</pre>
|
||||
|
||||
<p>Here are the values that are supported by
|
||||
|
@ -418,10 +418,18 @@ template could be a valid use of a custom modifier:</p>
|
|||
{{VAR:x-my_modifier:value1,value2,value3 has spaces,etc}}
|
||||
</pre>
|
||||
|
||||
<p>See <code><template_modifiers.h></code>
|
||||
for details on how to write a modifier and how to register it (there's
|
||||
also an example of a custom
|
||||
modifier <A HREF="#variables">below</A>).</p>
|
||||
<p>See <code><template_modifiers.h></code> for details on how to
|
||||
write a modifier and how to register it. Here is an example of the
|
||||
code for a custom modifier:</p>
|
||||
<pre>
|
||||
class StarEscape : public template_modifiers::TemplateModifier {
|
||||
void Modify(const char* in, size_t inlen,
|
||||
const template_modifiers::ModifierData* per_expand_data,
|
||||
ExpandEmitter* outbuf, const string& arg) const {
|
||||
outbuf->Emit(string("*") + string(in, inlen) + string("*"));
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3> <A NAME="inheritence">Details on Dictionary Lookup</A> </h3>
|
||||
|
||||
|
@ -639,49 +647,18 @@ helper routines to help setting values of a few special forms.</p>
|
|||
|
||||
<ul>
|
||||
<li> <code>SetIntValue(name, int)</code>: takes an int as the value. </li>
|
||||
<li> <code>SetEscapedValue(name, value, escape_functor)</code>:
|
||||
escapes the value, using the escape-functor, which takes a
|
||||
string as input and gives a "munged" string as output.
|
||||
<code>TemplateDictionary</code> has a few escape-functors built
|
||||
in, including <code>html_escape</code>, which replaces
|
||||
<code><</code>, <code>></code>, <code>&</code>, and
|
||||
<code>"</code> with the appropriate html entity;
|
||||
<code>xml_escape</code>, which deals with the
|
||||
<code>&nbsp;</code> entity; and
|
||||
<code>javascript_escape</code>, which escapes quotes and other
|
||||
characters that are meaningful to javascript. These are
|
||||
helpful in avoiding security holes when the template is
|
||||
html/xml/javascript. You can also define your own functor; see
|
||||
the example below. </li>
|
||||
<li> <code>SetFormattedValue(name, fmt, ...)</code>: the
|
||||
<code>fmt</code> and <code>...</code> work just like in
|
||||
<code>printf</code>: <code>SetFormattedValue("HOMEPAGE",
|
||||
"http://%s/", hostname)</code>. </li>
|
||||
<li> <code>SetEscapedFormattedValue(name, escape_functor, fmt,
|
||||
...)</code>: formats the value just like <code>printf</code>,
|
||||
and then escapes the result using the given functor. </li>
|
||||
</ul>
|
||||
|
||||
<p>Example:</p>
|
||||
<pre>
|
||||
google::TemplateDictionary* dict = new google::TemplateDictionary("var example");
|
||||
dict->SetValue("FOOTER", "Aren't these great results?");
|
||||
class StarEscape : public template_modifiers::TemplateModifier {
|
||||
void Modify(const char* in, size_t inlen,
|
||||
const template_modifiers::ModifierData* per_expand_data,
|
||||
ExpandEmitter* outbuf, const string& arg) const {
|
||||
outbuf->Emit(string("*") + string(in, inlen) + string("*"));
|
||||
}
|
||||
};
|
||||
dict->SetEscapedValue("USERNAME", username, StarEscape());
|
||||
</pre>
|
||||
|
||||
<p>Note that the template itself can also specify escaping via <A
|
||||
HREF="#modifiers">variable modifiers</A>! It's very possible for you
|
||||
to escape the value when setting it in the dictionary, and then have
|
||||
the template escape it again when outputting, so be careful you escape
|
||||
only as much as you need to.</p>
|
||||
|
||||
<h4> <A NAME="sections">Sections</A> </h4>
|
||||
|
||||
<p>Sections are used in two ways in templates. One is to expand some
|
||||
|
@ -722,9 +699,7 @@ otherwise we wish to hide the section and show neither
|
|||
<code>SetValueAndShowSection(name, value, section_name)</code> does
|
||||
exactly that: if value is non-empty, add a single single dictionary to
|
||||
<code>section_name</code> and call <code>section_dict->AddValue(name,
|
||||
value)</code>. There's also <code>SetEscapedValueAndShowSection(name,
|
||||
value, escape_functor, section_name)</code>, which lets you escape
|
||||
<code>value</code>.</p>
|
||||
value)</code>.</p>
|
||||
|
||||
<p>Example:</p>
|
||||
<pre>
|
||||
|
@ -754,8 +729,7 @@ value, escape_functor, section_name)</code>, which lets you escape
|
|||
if (num_prev_searches > 0) {
|
||||
for (int i = 0; i < num_prev_searches; ++i) {
|
||||
TemplateDictionary* sub_dict = dict->AddSectionDictionary("PREV_SEARCHES");
|
||||
sub_dict->SetEscapedValue("PREV_SEARCH", prev_searches[i],
|
||||
TemplateDictionary::html_escape);
|
||||
sub_dict->SetValue("PREV_SEARCH", prev_searches[i]);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
@ -809,7 +783,7 @@ secret-key is of course different every time you expand the
|
|||
webpage.</p>
|
||||
|
||||
<p>To set data that the modifier can use, you call
|
||||
<code>SetModifierData()<code> on a <code>TemplateDictionary</code>.
|
||||
<code>SetModifierData()</code> on a <code>TemplateDictionary</code>.
|
||||
For instance:</p>
|
||||
<pre>
|
||||
TemplateDictionary* dict = new TemplateDictionary("modifier example");
|
||||
|
@ -820,7 +794,7 @@ For instance:</p>
|
|||
|
||||
<p>Your custom modifier is passed all the ModifierData as one of the
|
||||
arguments to <code>Modify</code>: see
|
||||
<code><google/template_modifiers.h><code> for more details.</p>
|
||||
<code><google/template_modifiers.h></code> for more details.</p>
|
||||
|
||||
|
||||
<h3> <A name="expand">Expanding a Template</A> </h3>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<link href="http://www.google.com/favicon.ico" type="image/x-icon"
|
||||
rel="shortcut icon">
|
||||
<link href="designstyle.css" type="text/css" rel="stylesheet">
|
||||
<style>
|
||||
<style type="text/css">
|
||||
<!--
|
||||
ol.bluelist li {
|
||||
color: #3366ff;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
ctemplate (0.9-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Google Inc. <opensource@google.com> Thu, 24 Jan 2008 16:09:43 -0800
|
||||
|
||||
ctemplate (0.8-1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
|
|
@ -156,12 +156,14 @@ void BaseArena::MakeNewBlock() {
|
|||
// allocation -- this is equivalent to not using the arena at all.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void* BaseArena::GetMemoryFallback(const size_t size, const int align) {
|
||||
void* BaseArena::GetMemoryFallback(const size_t size, const int align_as_int) {
|
||||
if (0 == size) {
|
||||
return NULL; // stl/stl_alloc.h says this is okay
|
||||
}
|
||||
// This makes the type-checker happy.
|
||||
const size_t align = static_cast<size_t>(align_as_int);
|
||||
|
||||
assert (align > 0 && 0 == (align & (align - 1))); // must be power of 2
|
||||
assert(align_as_int > 0 && 0 == (align & (align - 1))); // must be power of 2
|
||||
|
||||
// If the object is more than a quarter of the block size, allocate
|
||||
// it separately to avoid wasting too much space in leftover bytes
|
||||
|
@ -181,10 +183,10 @@ void* BaseArena::GetMemoryFallback(const size_t size, const int align) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
const int overage =
|
||||
const size_t overage =
|
||||
(reinterpret_cast<uintptr_t>(freestart_) & (align-1));
|
||||
if (overage) {
|
||||
const int waste = align - overage;
|
||||
const size_t waste = align - overage;
|
||||
freestart_ += waste;
|
||||
if (waste < remaining_) {
|
||||
remaining_ -= waste;
|
||||
|
|
|
@ -105,18 +105,23 @@ class Mutex {
|
|||
// Now the implementation of Mutex for various systems
|
||||
#if defined(NO_THREADS)
|
||||
|
||||
// In debug mode, we'll assert some invariants: we don't unlock if we
|
||||
// didn't lock first, the lock is not held when Lock() is called
|
||||
// (since we're not re-entrant), etc. In non-debug mode, we do
|
||||
// nothing, for efficiency. That's why we do everything in an assert.
|
||||
// When we don't have threads, we can be either reading or writing,
|
||||
// but not both. We can have lots of readers at once (in no-threads
|
||||
// mode, that's most likely to happen in recursive function calls),
|
||||
// but only one writer. We represent this by having mutex_ be -1 when
|
||||
// writing and a number > 0 when reading (and 0 when no lock is held).
|
||||
//
|
||||
// In debug mode, we assert these invariants, while in non-debug mode
|
||||
// we do nothing, for efficiency. That's why everything is in an
|
||||
// assert.
|
||||
#include <assert.h>
|
||||
|
||||
Mutex::Mutex() : mutex_(0) { } // mutex_ counts number of current Lock()s
|
||||
Mutex::Mutex() : mutex_(0) { }
|
||||
Mutex::~Mutex() { assert(mutex_ == 0); }
|
||||
void Mutex::Lock() { assert(mutex_++ == 0); }
|
||||
void Mutex::Unlock() { assert(mutex_-- == 1); }
|
||||
void Mutex::ReaderLock() { Lock(); }
|
||||
void Mutex::ReaderUnlock() { Unlock(); }
|
||||
void Mutex::Lock() { assert(--mutex_ == -1); }
|
||||
void Mutex::Unlock() { assert(mutex_++ == -1); }
|
||||
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
|
||||
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
|
||||
|
||||
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ class @ac_windows_dllexport@ Template {
|
|||
// Template constructor
|
||||
// Reads the template file and parses it into a parse tree of TemplateNodes
|
||||
// by calling the method ReloadIfChanged
|
||||
// The top node is a section node with the arbitrary name "__MAIN__"
|
||||
// The top node is a section node with the arbitrary name "__{{MAIN}}__"
|
||||
// 'Strip' indicates how to handle whitespace when expanding the
|
||||
// template. DO_NOT_STRIP keeps the template exactly as-is.
|
||||
// STRIP_BLANK_LINES elides all blank lines in the template.
|
||||
|
@ -218,8 +218,8 @@ class @ac_windows_dllexport@ Template {
|
|||
// buffer must be big enough to hold the output. It's guaranteed
|
||||
// that the output size is no bigger than the input size.
|
||||
// Used by ReloadIfChanged()
|
||||
int InsertLine(const char *line, int len, char* buffer);
|
||||
int InsertFile(const char *file, size_t len, char* buffer);
|
||||
size_t InsertLine(const char *line, size_t len, char* buffer);
|
||||
size_t InsertFile(const char *file, size_t len, char* buffer);
|
||||
|
||||
|
||||
// The file we read the template from
|
||||
|
@ -227,7 +227,7 @@ class @ac_windows_dllexport@ Template {
|
|||
time_t filename_mtime_; // lastmod time for filename last time we loaded it
|
||||
|
||||
// What to do with whitespace at template-expand time
|
||||
const Strip strip_;
|
||||
Strip strip_;
|
||||
|
||||
// Keeps track of where we are in reloading, or if there was an error loading
|
||||
TemplateState state_;
|
||||
|
|
|
@ -121,25 +121,6 @@ class @ac_windows_dllexport@ TemplateDictionary {
|
|||
#endif
|
||||
; // starts at 3 because of implicit 1st arg 'this'
|
||||
|
||||
// TemplateModifier is defined in template_modifier.h, which also provides
|
||||
// some functors to use (particularly useful ones are also defined below).
|
||||
// NOTE: This method is provided for convenience, but it's better to call
|
||||
// SetValue() and do the escaping in the template itself when possible:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedValue(const TemplateString variable, const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn);
|
||||
|
||||
// NOTE: This method is provided for convenience, but it's better to call
|
||||
// SetFormattedValue() and do the escaping in the template itself:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedFormattedValue(const TemplateString variable,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const char* format, ...)
|
||||
#if @ac_google_attribute@
|
||||
__attribute__((__format__ (__printf__, 4, 5)))
|
||||
#endif
|
||||
; // starts at 4 because of implicit 1st arg 'this'
|
||||
|
||||
// We also let you set values in the 'global' dictionary which is
|
||||
// referenced when all other dictionaries fail. Note this is a
|
||||
// static method: no TemplateDictionary instance needed. Since
|
||||
|
@ -184,16 +165,6 @@ class @ac_windows_dllexport@ TemplateDictionary {
|
|||
const TemplateString value,
|
||||
const TemplateString section_name);
|
||||
|
||||
// In this case, we hide the section if the *escaped* value of the variable
|
||||
// is the empty string.
|
||||
// NOTE: This method is provided for convenience, but it's better to call
|
||||
// SetValueAndShowSection() and do the escaping in the template itself:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedValueAndShowSection(const TemplateString variable,
|
||||
const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const TemplateString section_name);
|
||||
|
||||
|
||||
// --- Routines for TEMPLATE-INCLUDES
|
||||
// Included templates are treated like sections, but they require
|
||||
|
@ -212,18 +183,6 @@ class @ac_windows_dllexport@ TemplateDictionary {
|
|||
// to clear any value previously set.
|
||||
void SetModifierData(const char* key, const void* value);
|
||||
|
||||
// --- ESCAPE FUNCTORS
|
||||
// Some commonly-used escape functors. These just point to the
|
||||
// variable of the same name in template_modifiers.h, and are kept
|
||||
// here for backwards compatibility. For new code, and to get access
|
||||
// to escape functors not listed here, use template_modifiers.h.
|
||||
static const template_modifiers::HtmlEscape& html_escape;
|
||||
static const template_modifiers::PreEscape& pre_escape;
|
||||
static const template_modifiers::XmlEscape& xml_escape;
|
||||
static const template_modifiers::JavascriptEscape& javascript_escape;
|
||||
static const template_modifiers::UrlQueryEscape& url_query_escape;
|
||||
static const template_modifiers::JsonEscape& json_escape;
|
||||
|
||||
|
||||
// --- DEBUGGING TOOLS
|
||||
|
||||
|
@ -241,6 +200,32 @@ class @ac_windows_dllexport@ TemplateDictionary {
|
|||
void SetAnnotateOutput(const char* template_path_start);
|
||||
|
||||
|
||||
// --- DEPRECATED ESCAPING FUNCTIONALITY
|
||||
|
||||
// Escaping in the binary has been deprecated in favor of using modifiers
|
||||
// to do the escaping in the template:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedValue(const TemplateString variable, const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn);
|
||||
void SetEscapedFormattedValue(const TemplateString variable,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const char* format, ...)
|
||||
#if @ac_google_attribute@
|
||||
__attribute__((__format__ (__printf__, 4, 5)))
|
||||
#endif
|
||||
; // starts at 4 because of implicit 1st arg 'this'
|
||||
void SetEscapedValueAndShowSection(const TemplateString variable,
|
||||
const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const TemplateString section_name);
|
||||
static const template_modifiers::HtmlEscape& html_escape;
|
||||
static const template_modifiers::PreEscape& pre_escape;
|
||||
static const template_modifiers::XmlEscape& xml_escape;
|
||||
static const template_modifiers::JavascriptEscape& javascript_escape;
|
||||
static const template_modifiers::UrlQueryEscape& url_query_escape;
|
||||
static const template_modifiers::JsonEscape& json_escape;
|
||||
|
||||
|
||||
private:
|
||||
friend class SectionTemplateNode; // for access to GetSectionValue(), etc.
|
||||
friend class TemplateTemplateNode; // for access to GetSectionValue(), etc.
|
||||
|
|
|
@ -45,15 +45,9 @@
|
|||
//
|
||||
// In addition to the list of modifiers hard-coded in the source code
|
||||
// here, it is possible to dynamicly register modifiers using a long
|
||||
// name starting with "x-".
|
||||
//
|
||||
// In addition to using a modifier within a template, you can also
|
||||
// pass a modifier object to TemplateDictionary::SetEscapedValue() and
|
||||
// similar methods. The built-in modifier objects are defined in this
|
||||
// file (some are also exported in template_dictionary.h for backwards
|
||||
// compatibility). If you wish to define your own modifier class, in
|
||||
// your own source code, just subclass TemplateModifier -- see
|
||||
// template_modifiers.cc for details of how to do that.
|
||||
// name starting with "x-". If you wish to define your own modifier
|
||||
// class, in your own source code, just subclass TemplateModifier --
|
||||
// see template_modifiers.cc for details of how to do that.
|
||||
//
|
||||
// Adding a new built-in modifier, to this file, takes several steps,
|
||||
// both in this .h file and in the corresponding .cc file:
|
||||
|
@ -96,9 +90,18 @@ class ModifierData;
|
|||
class @ac_windows_dllexport@ TemplateModifier {
|
||||
public:
|
||||
// This function takes a string as input, a char*/size_t pair, and
|
||||
// appends the modified version to the end of outbuf. "arg" is
|
||||
// used for modifiers that take a modifier-value argument; for
|
||||
// modifiers that take no argument, arg will always be "".
|
||||
// appends the modified version to the end of outbuf. In addition
|
||||
// to the variable-value to modify (specified via in/inlen), each
|
||||
// Modify passes in two pieces of user-supplied data:
|
||||
// 1) arg: this is the modifier-value, for modifiers that take a
|
||||
// value (e.g. "{{VAR:modifier=value}}"). This value
|
||||
// comes from the template file. For modifiers that take
|
||||
// no modval argument, arg will always be "". For modifiers
|
||||
// that do take such an argument, arg will always start with "=".
|
||||
// 2) per_expand_data: this is a set of data that the application can
|
||||
// associate with a TemplateDictionary, and is passed in to
|
||||
// every variable expanded using that dictionary. This value
|
||||
// comes from the source code.
|
||||
virtual void Modify(const char* in, size_t inlen,
|
||||
const ModifierData* per_expand_data,
|
||||
ExpandEmitter* outbuf,
|
||||
|
@ -186,53 +189,78 @@ extern @ac_windows_dllexport@ UrlQueryEscape url_query_escape;
|
|||
class @ac_windows_dllexport@ JsonEscape : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern @ac_windows_dllexport@ JsonEscape json_escape;
|
||||
|
||||
// A dispatch routine that calls pre_escape, snippet_escape,
|
||||
// cleanse_attribute, or validate_url, depending on the value of the arg.
|
||||
class @ac_windows_dllexport@ HtmlEscapeWithArg : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern @ac_windows_dllexport@ HtmlEscapeWithArg html_escape_with_arg;
|
||||
|
||||
// A similar dispatch routine for URLS.
|
||||
// Calls validate_url_and_javascript_escape, validate_url_and_html_escape,
|
||||
// or url_query_escape depending on the value of the argument..
|
||||
class @ac_windows_dllexport@ UrlEscapeWithArg : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern @ac_windows_dllexport@ UrlEscapeWithArg url_escape_with_arg;
|
||||
// Inserts the given prefix (given as the argument to this modifier)
|
||||
// after every newline in the text. Note that it does *not* insert
|
||||
// prefix at the very beginning of the text -- in its expected use,
|
||||
// that prefix will already be present before this text, in the
|
||||
// template. This is meant to be used internally, and is not exported
|
||||
// via the g_modifiers list.
|
||||
class @ac_windows_dllexport@ PrefixLine : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern @ac_windows_dllexport@ PrefixLine prefix_line;
|
||||
|
||||
|
||||
#undef MODIFY_SIGNATURE_
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// These are used by template.cc and when registering new modifiers.
|
||||
// (Or more exactly, registering new modifier/value pairs.)
|
||||
// They are not intended for any other users.
|
||||
|
||||
// Does this modifier take an argument? Note we do not have
|
||||
// MODVAL_OPTIONAL: we prefer the clarity of an arg either always
|
||||
// taking an argument, or never (ie, no "default arguments").
|
||||
// MODVAL_UNKNOWN is only for internal use and cannot be used when
|
||||
// registering a new modifier.
|
||||
enum ModvalStatus { MODVAL_FORBIDDEN, MODVAL_REQUIRED, MODVAL_UNKNOWN };
|
||||
|
||||
// TODO(csilvers): collapse this into the TemplateModifier class?
|
||||
struct ModifierInfo {
|
||||
ModifierInfo(std::string ln, char sn, ModvalStatus vs,
|
||||
const TemplateModifier *m)
|
||||
|
||||
// longname should end in an '=' iff the modifier takes a value
|
||||
// (same as in getopt(3)).
|
||||
// To specialize -- add a modifier that applies only when we see the name
|
||||
// with a particular value -- specify longname like so: "longname=value".
|
||||
// (See example in the comment-doc below, for AddModifier.)
|
||||
// sn can be '\0' if there is no associated shortname.
|
||||
// m should be NULL *only if* default-registering a user-defined longname
|
||||
// that the user neglected to register themselves. In this case, we
|
||||
// use the null modifier as the actual modifier.
|
||||
ModifierInfo(std::string ln, char sn, const TemplateModifier *m)
|
||||
: long_name(ln), short_name(sn),
|
||||
value_status(vs), modifier(m) { }
|
||||
modval_required(strchr(ln.c_str(), '=') != NULL),
|
||||
is_registered(m != NULL),
|
||||
modifier(m ? m : &null_modifier) { }
|
||||
std::string long_name;
|
||||
char short_name;
|
||||
ModvalStatus value_status;
|
||||
bool modval_required; // true iff ln has an '=' in it
|
||||
bool is_registered; // true for built-in and AddModifier mods
|
||||
const TemplateModifier* modifier;
|
||||
};
|
||||
|
||||
// Returns whether or not candidate can be safely (w.r.t XSS)
|
||||
// used in lieu of our ModifierInfo. This is true iff:
|
||||
// 1. Both have the same modifier function OR
|
||||
// 2. Candidate's modifier function is in our ModifierInfo's
|
||||
// list (vector) of safe alternative modifier functions.
|
||||
// Note that this function is not commutative therefore
|
||||
// IsSafeXSSAlternative(a, b) may not be equal to IsSafeXSSAlternative(b, a).
|
||||
bool @ac_windows_dllexport@ IsSafeXSSAlternative(const ModifierInfo& our,
|
||||
const ModifierInfo& candidate);
|
||||
|
||||
// Registers a new template modifier.
|
||||
// long_name must start with "x-".
|
||||
extern @ac_windows_dllexport@ bool AddModifier(const char* long_name,
|
||||
ModvalStatus value_status,
|
||||
const TemplateModifier* modifier);
|
||||
// If the modifier takes a value (eg "{{VAR:x-name=value}}"), then
|
||||
// long_name should end with "=". This is similar to getopt(3) syntax.
|
||||
// We also allow value-specializations, with specific values specified
|
||||
// as part of long-name. For instance:
|
||||
// AddModifier("x-mod=", &my_modifierA);
|
||||
// AddModifier("x-mod=bar", &my_modifierB);
|
||||
// AddModifier("x-mod2", &my_modifierC);
|
||||
// For the template
|
||||
// {{VAR1:x-mod=foo}} {{VAR2:x-mod=bar}} {{VAR3:x-mod=baz}} {{VAR4:x-mod2}}
|
||||
// VAR1 and VAR3 would get modified by my_modifierA, VAR2 by my_modifierB,
|
||||
// and VAR4 by my_modifierC. The order of the AddModifier calls is not
|
||||
// significant.
|
||||
extern @ac_windows_dllexport@ bool AddModifier(const char* long_name, const TemplateModifier* modifier);
|
||||
|
||||
// modname is the name of the modifier (shortname or longname).
|
||||
// value is the modifier-value (empty string if there is no modval).
|
||||
// Returns a pointer into g_modifiers, or NULL if not found.
|
||||
extern @ac_windows_dllexport@ const ModifierInfo* FindModifier(const char* modname,
|
||||
size_t modname_len);
|
||||
extern @ac_windows_dllexport@ const ModifierInfo* FindModifier(const char* modname, size_t modname_len,
|
||||
const char* modval, size_t modval_len);
|
||||
|
||||
// This class holds per-expand data which is available to
|
||||
// custom modifiers.
|
||||
|
|
|
@ -47,15 +47,25 @@
|
|||
|
||||
|
||||
# Open template file
|
||||
(my $template_name = shift) || usage ("Need to specify template variable name.");
|
||||
(my $template_name = shift) || usage("Need to specify template variable name.");
|
||||
|
||||
# Get base name of template file
|
||||
# If a second argument is supplied, treat it as an input filename.
|
||||
if (my $infile = shift) {
|
||||
open(STDIN, "<", $infile) or usage("Can't open $infile for reading.");
|
||||
}
|
||||
|
||||
# If a third argument is supplied, treat it as an output filename.
|
||||
if (my $outfile = shift) {
|
||||
open(STDOUT, ">", $outfile) or usage("Can't open $outfile for writing.");
|
||||
}
|
||||
|
||||
# Get base name of template file
|
||||
$base_name = $template_name;
|
||||
$base_name =~ s|^.*/([^/]*)$|$1|; # Strip out directory name
|
||||
$base_name =~ s|\.h$||; # Strip out suffix, if it's .h
|
||||
$base_name =~ tr|A-Za-z0-9_|_|c; # Sanitize name to remove non-letters/nums
|
||||
|
||||
# Print header
|
||||
# Print header
|
||||
print "// This file automatically generated by template-converter\n";
|
||||
print "// DO NOT EDIT!\n\n";
|
||||
print "#ifndef _" . uc($base_name) . "_H\n";
|
||||
|
@ -66,7 +76,7 @@ print "const string ${base_name} (\n";
|
|||
while (<>) {
|
||||
chomp;
|
||||
my $escaped_line = escape_line($_);
|
||||
print "\"$escaped_line\\n\"\n";
|
||||
print "\"$escaped_line\\n\"\n";
|
||||
}
|
||||
print ");\n\n";
|
||||
|
||||
|
@ -78,7 +88,8 @@ exit(0);
|
|||
sub usage {
|
||||
my $msg = shift;
|
||||
print STDERR "\n$msg\n";
|
||||
print STDERR "Usage: template-converter <template-varname>\n\n" ;
|
||||
print STDERR "Usage: template-converter <template-varname>",
|
||||
" [infile] [outfile]\n\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h> // for isspace()
|
||||
#include <sys/stat.h>
|
||||
|
@ -87,8 +88,18 @@ namespace {
|
|||
static Mutex g_static_mutex;
|
||||
static Mutex g_cache_mutex;
|
||||
static Mutex g_header_mutex;
|
||||
|
||||
// It's not great to have a global variable with a constructor, but
|
||||
// it's safe in this case: the constructor is trivial and does not
|
||||
// depend on any other global constructors running first, and the
|
||||
// variable is used in only one place below, always after main() has
|
||||
// started.
|
||||
static const template_modifiers::ModifierInfo g_prefix_line_info(
|
||||
"", '\0', &template_modifiers::prefix_line);
|
||||
|
||||
const char * const kDefaultTemplateDirectory = ctemplate::kCWD; // "./"
|
||||
const char * const kMainSectionName = "__MAIN__";
|
||||
// Note this name is syntactically impossible for a user to accidentally use.
|
||||
const char * const kMainSectionName = "__{{MAIN}}__";
|
||||
static vector<TemplateDictionary*>* g_use_current_dict; // vector == {NULL}
|
||||
|
||||
// Type, var, and mutex used to store template objects in the internal cache
|
||||
|
@ -174,7 +185,7 @@ static void WriteOneHeaderEntry(string *outstring,
|
|||
prefix = "k";
|
||||
bool take_next = true;
|
||||
|
||||
for (int i=0; i < filename.length(); i++) {
|
||||
for (string::size_type i = 0; i < filename.length(); i++) {
|
||||
if (filename[i] == '.') {
|
||||
// stop when we find the dot
|
||||
break;
|
||||
|
@ -258,9 +269,8 @@ struct TemplateToken {
|
|||
it != modifier_plus_values.end(); ++it) {
|
||||
const string& modname = it->first->long_name;
|
||||
retval += string(":") + modname;
|
||||
if (it->first->value_status == template_modifiers::MODVAL_UNKNOWN) {
|
||||
if (!it->first->is_registered)
|
||||
retval += "<not registered>";
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -654,6 +664,12 @@ class SectionTemplateNode : public TemplateNode {
|
|||
protected:
|
||||
const TemplateToken token_; // text is the name of the section
|
||||
NodeList node_list_; // The list of subnodes in the section
|
||||
// When the last node read was literal text that ends with "\n? +"
|
||||
// (that is, leading whitespace on a line), this stores the leading
|
||||
// whitespace. This is used to properly indent included
|
||||
// sub-templates.
|
||||
string indentation_;
|
||||
|
||||
|
||||
// A protected method used in parsing the template file
|
||||
// Finds the next token in the file and return it. Anything not inside
|
||||
|
@ -686,7 +702,7 @@ class SectionTemplateNode : public TemplateNode {
|
|||
// --- constructor and destructor, Expand, Dump, and WriteHeaderEntries
|
||||
|
||||
SectionTemplateNode::SectionTemplateNode(const TemplateToken& token)
|
||||
: token_(token) {
|
||||
: token_(token), indentation_("\n") {
|
||||
VLOG(2) << "Constructing SectionTemplateNode: "
|
||||
<< string(token_.text, token_.textlen) << endl;
|
||||
}
|
||||
|
@ -716,8 +732,8 @@ bool SectionTemplateNode::Expand(ExpandEmitter *output_buffer,
|
|||
|
||||
const string variable(token_.text, token_.textlen);
|
||||
|
||||
// The section named __MAIN__ is special: you always expand it exactly
|
||||
// once using the containing (main) dictionary.
|
||||
// The section named __{{MAIN}}__ is special: you always expand it
|
||||
// exactly once using the containing (main) dictionary.
|
||||
if (token_.text == kMainSectionName) {
|
||||
dv = g_use_current_dict; // 'expand once, using the passed in dictionary'
|
||||
} else {
|
||||
|
@ -809,6 +825,33 @@ void SectionTemplateNode::AddTemplateNode(const TemplateToken& token,
|
|||
node_list_.push_back(new TemplateTemplateNode(token, my_template->strip_));
|
||||
}
|
||||
|
||||
// If "text" ends with a newline followed by whitspace, returns a
|
||||
// string holding that whitespace. Otherwise, returns the empty
|
||||
// string. If implicit_newline is true, also consider the text to be
|
||||
// an indentation if it consists entirely of whitespace; this is set
|
||||
// when we know that right before this text there was a newline, or
|
||||
// this text is the beginning of a document.
|
||||
static string GetIndentation(const char* text, size_t textlen,
|
||||
bool implicit_newline) {
|
||||
const char* nextline; // points to one char past the last newline
|
||||
for (nextline = text + textlen; nextline > text; --nextline)
|
||||
if (nextline[-1] == '\n') break;
|
||||
if (nextline == text && !implicit_newline)
|
||||
return ""; // no newline found, so no indentation
|
||||
|
||||
bool prefix_is_whitespace = true;
|
||||
for (const char* p = nextline; p < text + textlen; ++p) {
|
||||
if (*p != ' ' && *p != '\t') {
|
||||
prefix_is_whitespace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prefix_is_whitespace && text + textlen > nextline)
|
||||
return string(nextline, text + textlen - nextline);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
bool SectionTemplateNode::AddSubnode(Template *my_template) {
|
||||
// Don't proceed if we already found an error
|
||||
if (my_template->state() == TS_ERROR) {
|
||||
|
@ -832,12 +875,17 @@ bool SectionTemplateNode::AddSubnode(Template *my_template) {
|
|||
switch (token.type) {
|
||||
case TOKENTYPE_TEXT:
|
||||
this->AddTextNode(token.text, token.textlen);
|
||||
// Store the indentation (trailing whitespace after a newline), if any.
|
||||
this->indentation_ = GetIndentation(token.text, token.textlen,
|
||||
indentation_ == "\n");
|
||||
break;
|
||||
case TOKENTYPE_VARIABLE:
|
||||
this->AddVariableNode(token);
|
||||
this->indentation_.clear(); // clear whenever last read wasn't whitespace
|
||||
break;
|
||||
case TOKENTYPE_SECTION_START:
|
||||
this->AddSectionNode(token, my_template);
|
||||
this->indentation_.clear(); // clear whenever last read wasn't whitespace
|
||||
break;
|
||||
case TOKENTYPE_SECTION_END:
|
||||
// Don't add a node. Just make sure we are ending the right section
|
||||
|
@ -850,10 +898,21 @@ bool SectionTemplateNode::AddSubnode(Template *my_template) {
|
|||
<< "\nIn: " << string(token_.text, token_.textlen) << endl;
|
||||
my_template->set_state(TS_ERROR);
|
||||
}
|
||||
this->indentation_.clear(); // clear whenever last read wasn't whitespace
|
||||
return false;
|
||||
break;
|
||||
case TOKENTYPE_TEMPLATE:
|
||||
// If this template is indented (eg, " {{>SUBTPL}}"), make sure
|
||||
// every line of the expanded template is indented, not just the
|
||||
// first one. We do this by adding a modifier that applies to
|
||||
// the entire template node, that inserts spaces after newlines.
|
||||
if (!this->indentation_.empty()) {
|
||||
token.modifier_plus_values.push_back(
|
||||
pair<const template_modifiers::ModifierInfo*, string>(
|
||||
&g_prefix_line_info, this->indentation_));
|
||||
}
|
||||
this->AddTemplateNode(token, my_template);
|
||||
this->indentation_.clear(); // clear whenever last read wasn't whitespace
|
||||
break;
|
||||
case TOKENTYPE_COMMENT:
|
||||
// Do nothing. Comments just drop out of the file altogether.
|
||||
|
@ -1052,22 +1111,19 @@ TemplateToken SectionTemplateNode::GetNextToken(Template *my_template) {
|
|||
string value_string(value, mod_end - value);
|
||||
// Convert the string to a functor, and error out if we can't.
|
||||
const template_modifiers::ModifierInfo* modstruct =
|
||||
template_modifiers::FindModifier(mod, value - mod);
|
||||
template_modifiers::FindModifier(mod, value - mod,
|
||||
value, mod_end - value);
|
||||
// There are various ways a modifier syntax can be illegal.
|
||||
if (modstruct == NULL) {
|
||||
FAIL("Unknown modifier for variable "
|
||||
<< string(token_start, mod_start - token_start) << ": "
|
||||
<< "'" << string(mod, value - mod) << "'");
|
||||
} else if ((modstruct->value_status
|
||||
== template_modifiers::MODVAL_FORBIDDEN) &&
|
||||
value < mod_end) {
|
||||
} else if (!modstruct->modval_required && value < mod_end) {
|
||||
FAIL("Modifier for variable "
|
||||
<< string(token_start, mod_start - token_start) << ":"
|
||||
<< string(mod, value - mod) << " "
|
||||
<< "has illegal mod-value '" << value_string << "'");
|
||||
} else if ((modstruct->value_status
|
||||
== template_modifiers::MODVAL_REQUIRED) &&
|
||||
value == mod_end) {
|
||||
} else if (modstruct->modval_required && value == mod_end) {
|
||||
FAIL("Modifier for variable "
|
||||
<< string(token_start, mod_start - token_start) << ":"
|
||||
<< string(mod, value - mod) << " "
|
||||
|
@ -1137,9 +1193,9 @@ Template::Template(const string& filename, Strip strip)
|
|||
|
||||
// Preserve whitespace in Javascript files because carriage returns
|
||||
// can convey meaning for comment termination and closures
|
||||
if ( strip == STRIP_WHITESPACE && filename.length() >= 3 &&
|
||||
if ( strip_ == STRIP_WHITESPACE && filename.length() >= 3 &&
|
||||
!strcmp(filename.c_str() + filename.length() - 3, ".js") ) {
|
||||
strip = STRIP_BLANK_LINES;
|
||||
strip_ = STRIP_BLANK_LINES;
|
||||
}
|
||||
|
||||
ReloadIfChangedLocked();
|
||||
|
@ -1392,7 +1448,7 @@ bool Template::ReloadIfChangedLocked() {
|
|||
// Parse the input one line at a time to get the "stripped" input.
|
||||
// Note stripping only makes smaller, so st_size is a safe upper bound.
|
||||
char* input_buffer = new char[statbuf.st_size];
|
||||
const int buflen = InsertFile(file_buffer, statbuf.st_size, input_buffer);
|
||||
const size_t buflen = InsertFile(file_buffer, statbuf.st_size, input_buffer);
|
||||
delete[] file_buffer;
|
||||
|
||||
// Now parse the template we just read. BuildTree takes over ownership
|
||||
|
@ -1485,13 +1541,15 @@ void Template::ClearCache() {
|
|||
// of bytes they wrote to the output buffer.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static void StripWhiteSpace(const char** str, int* len) {
|
||||
// strip off trailing whitespace
|
||||
// We define our own version rather than using the one in strtuil, mostly
|
||||
// so we can take a size_t instead of an int. The code is simple enough.
|
||||
static void StripTemplateWhiteSpace(const char** str, size_t* len) {
|
||||
// Strip off trailing whitespace.
|
||||
while ((*len) > 0 && isspace((*str)[(*len)-1])) {
|
||||
(*len)--;
|
||||
}
|
||||
|
||||
// strip off leading whitespace
|
||||
// Strip off leading whitespace.
|
||||
while ((*len) > 0 && isspace((*str)[0])) {
|
||||
(*len)--;
|
||||
(*str)++;
|
||||
|
@ -1499,16 +1557,16 @@ static void StripWhiteSpace(const char** str, int* len) {
|
|||
}
|
||||
|
||||
// Adjusts line and length iff condition is met, and RETURNS true.
|
||||
static bool IsBlankOrOnlyHasOneRemovableMarker(const char** line, int* len) {
|
||||
static bool IsBlankOrOnlyHasOneRemovableMarker(const char** line, size_t* len) {
|
||||
const char *clean_line = *line;
|
||||
int new_len = *len;
|
||||
StripWhiteSpace(&clean_line, &new_len);
|
||||
size_t new_len = *len;
|
||||
StripTemplateWhiteSpace(&clean_line, &new_len);
|
||||
|
||||
// If there was only white space on the line, new_len will now be zero.
|
||||
// In that case the line should be removed, so return true.
|
||||
if (new_len == 0) {
|
||||
(*line) = clean_line;
|
||||
(*len) = new_len;
|
||||
*line = clean_line;
|
||||
*len = new_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1518,13 +1576,13 @@ static bool IsBlankOrOnlyHasOneRemovableMarker(const char** line, int* len) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (clean_line[0] != '{' // if first two chars are not "{{"
|
||||
if (clean_line[0] != '{' // if first two chars are not "{{"
|
||||
|| clean_line[1] != '{'
|
||||
|| (clean_line[2] != '#' // or next char marks neither section start
|
||||
&& clean_line[2] != '/' // nor section end
|
||||
&& clean_line[2] != '>' // nor template include
|
||||
&& clean_line[2] != '!')) { // nor comment
|
||||
return false; // then not what we are looking for.
|
||||
|| (clean_line[2] != '#' // or next char marks not section start
|
||||
&& clean_line[2] != '/' // nor section end
|
||||
&& clean_line[2] != '>' // nor template include
|
||||
&& clean_line[2] != '!')) { // nor comment
|
||||
return false; // then not what we are looking for.
|
||||
}
|
||||
|
||||
const char *end_marker = strstr(clean_line, "}}");
|
||||
|
@ -1537,20 +1595,18 @@ static bool IsBlankOrOnlyHasOneRemovableMarker(const char** line, int* len) {
|
|||
// else return the line stripped of its white space chars so when the
|
||||
// marker is removed in expansion, no white space is left from the line
|
||||
// that has now been removed
|
||||
(*line) = clean_line;
|
||||
(*len) = new_len;
|
||||
*line = clean_line;
|
||||
*len = new_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(csilvers): this should take a size_t as well, but StripWhiteSpace
|
||||
// wants an int* argument. I hope no single template line is >2G!
|
||||
int Template::InsertLine(const char *line, int len, char* buffer) {
|
||||
size_t Template::InsertLine(const char *line, size_t len, char* buffer) {
|
||||
bool add_newline = (len > 0 && line[len-1] == '\n');
|
||||
if (add_newline)
|
||||
len--; // so we ignore the newline from now on
|
||||
|
||||
if (strip_ >= STRIP_WHITESPACE) {
|
||||
StripWhiteSpace(&line, &len);
|
||||
StripTemplateWhiteSpace(&line, &len);
|
||||
add_newline = false;
|
||||
}
|
||||
|
||||
|
@ -1572,7 +1628,7 @@ int Template::InsertLine(const char *line, int len, char* buffer) {
|
|||
return len;
|
||||
}
|
||||
|
||||
int Template::InsertFile(const char *file, size_t len, char* buffer) {
|
||||
size_t Template::InsertFile(const char *file, size_t len, char* buffer) {
|
||||
const char* prev_pos = file;
|
||||
const char* next_pos;
|
||||
char* write_pos = buffer;
|
||||
|
@ -1580,16 +1636,15 @@ int Template::InsertFile(const char *file, size_t len, char* buffer) {
|
|||
while ( (next_pos=(char*)memchr(prev_pos, '\n', file+len - prev_pos)) ) {
|
||||
next_pos++; // include the newline
|
||||
write_pos += InsertLine(prev_pos, next_pos - prev_pos, write_pos);
|
||||
assert(write_pos - buffer <= len); // an invariant we guarantee
|
||||
assert(write_pos >= buffer && static_cast<size_t>(write_pos-buffer) <= len);
|
||||
prev_pos = next_pos;
|
||||
}
|
||||
if (prev_pos < file + len) { // last line doesn't end in a newline
|
||||
// TODO(csilvers): have InsertLine take a size_t
|
||||
write_pos += InsertLine(prev_pos, static_cast<int>(file+len - prev_pos),
|
||||
write_pos);
|
||||
assert(write_pos - buffer <= len);
|
||||
write_pos += InsertLine(prev_pos, file+len - prev_pos, write_pos);
|
||||
assert(write_pos >= buffer && static_cast<size_t>(write_pos-buffer) <= len);
|
||||
}
|
||||
return write_pos - buffer;
|
||||
assert(write_pos >= buffer);
|
||||
return static_cast<size_t>(write_pos - buffer);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
|
|
@ -687,12 +687,13 @@ void TemplateDictionary::DumpToString(string* out, int indent) const {
|
|||
for (map<string, const DictVector*>::const_iterator it =
|
||||
sorted_include_dict.begin();
|
||||
it != sorted_include_dict.end(); ++it) {
|
||||
for (int i = 0; i < it->second->size(); ++i) {
|
||||
for (vector<TemplateDictionary*>::size_type i = 0;
|
||||
i < it->second->size(); ++i) {
|
||||
TemplateDictionary* dict = (*it->second)[i];
|
||||
IndentLine(out, indent + kIndent);
|
||||
char dictnum[128]; // enough for two ints
|
||||
snprintf(dictnum, sizeof(dictnum), "dict %d of %"PRIuS,
|
||||
i + 1, it->second->size());
|
||||
static_cast<int>(i + 1), it->second->size());
|
||||
out->append("include-template ");
|
||||
out->append(it->first);
|
||||
out->append(" (");
|
||||
|
|
|
@ -65,8 +65,8 @@ TemplateFromString::TemplateFromString(const string& cache_key,
|
|||
// We know that InsertFile never writes more output than it gets input.
|
||||
// While we allocate buffer here, BuildTree takes ownership and deletes it.
|
||||
char* buffer = new char[template_text.size()];
|
||||
const int buflen = InsertFile(template_text.data(), template_text.size(),
|
||||
buffer);
|
||||
const size_t buflen = InsertFile(template_text.data(), template_text.size(),
|
||||
buffer);
|
||||
if ( BuildTree(buffer, buffer + buflen) ) {
|
||||
assert(state() == TS_READY);
|
||||
} else {
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
// version of the string to outbuf. Outbuf is an ExpandEmitter, as
|
||||
// defined in template_modifiers.h. It's a very simple type that
|
||||
// supports appending to a data stream.
|
||||
//
|
||||
// Be very careful editing an existing modifier. Subtle changes can
|
||||
// introduce the possibility for cross-site scripting attacks. If you
|
||||
// do change a modifier, be careful that it does not affect
|
||||
// the list of Safe XSS Alternatives.
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
|
@ -65,7 +70,6 @@ TemplateModifier::~TemplateModifier() {}
|
|||
void NullModifier::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
out->Emit(in, inlen);
|
||||
}
|
||||
NullModifier null_modifier;
|
||||
|
@ -73,8 +77,7 @@ NullModifier null_modifier;
|
|||
void HtmlEscape::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
switch (in[i]) {
|
||||
case '&': APPEND("&"); break;
|
||||
case '"': APPEND("""); break;
|
||||
|
@ -92,8 +95,7 @@ HtmlEscape html_escape;
|
|||
void PreEscape::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
switch (in[i]) {
|
||||
case '&': APPEND("&"); break;
|
||||
case '"': APPEND("""); break;
|
||||
|
@ -110,7 +112,6 @@ PreEscape pre_escape;
|
|||
void SnippetEscape::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
bool inside_b = false;
|
||||
const char * const end = in + inlen;
|
||||
for (const char *c = in; c < end; ++c) {
|
||||
|
@ -178,8 +179,7 @@ SnippetEscape snippet_escape;
|
|||
void CleanseAttribute::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
char c = in[i];
|
||||
switch (c) {
|
||||
case '-':
|
||||
|
@ -207,8 +207,7 @@ CleanseAttribute cleanse_attribute;
|
|||
void CleanseCss::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
char c = in[i];
|
||||
switch (c) {
|
||||
case ' ':
|
||||
|
@ -238,7 +237,6 @@ CleanseCss cleanse_css;
|
|||
void ValidateUrl::Modify(const char* in, size_t inlen,
|
||||
const ModifierData* per_expand_data,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
const char* slashpos = (char*)memchr(in, '/', inlen);
|
||||
if (slashpos == NULL)
|
||||
slashpos = in + inlen;
|
||||
|
@ -265,7 +263,6 @@ ValidateUrl validate_url_and_javascript_escape(javascript_escape);
|
|||
void XmlEscape::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
const char* end = in + inlen;
|
||||
const char* pos = in;
|
||||
for (const char* next_amp = static_cast<const char*>(memchr(in, '&', inlen));
|
||||
|
@ -287,8 +284,7 @@ XmlEscape xml_escape;
|
|||
void JavascriptEscape::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
switch (in[i]) {
|
||||
case '"': APPEND("\\x22"); break;
|
||||
case '\'': APPEND("\\x27"); break;
|
||||
|
@ -316,8 +312,7 @@ void UrlQueryEscape::Modify(const char* in, size_t inlen,
|
|||
0x00000000L, 0x00000000L, 0x00000000L, 0x00000000L
|
||||
};
|
||||
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
unsigned char c = in[i];
|
||||
if (c == ' ') {
|
||||
out->Emit('+');
|
||||
|
@ -335,8 +330,7 @@ UrlQueryEscape url_query_escape;
|
|||
void JsonEscape::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
assert(arg.empty()); // We're a no-arg modifier
|
||||
for (int i = 0; i < inlen; ++i) {
|
||||
for (size_t i = 0; i < inlen; ++i) {
|
||||
switch (in[i]) {
|
||||
case '"': APPEND("\\\""); break;
|
||||
case '\\': APPEND("\\\\"); break;
|
||||
|
@ -352,75 +346,41 @@ void JsonEscape::Modify(const char* in, size_t inlen,
|
|||
}
|
||||
JsonEscape json_escape;
|
||||
|
||||
void HtmlEscapeWithArg::Modify(const char* in, size_t inlen,
|
||||
const ModifierData* per_expand_data,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
if (!arg.empty()) {
|
||||
switch (arg[1]) {
|
||||
case 's':
|
||||
return snippet_escape.Modify(in, inlen, per_expand_data, out, "");
|
||||
case 'p':
|
||||
return pre_escape.Modify(in, inlen, per_expand_data, out, "");
|
||||
case 'a':
|
||||
return cleanse_attribute.Modify(in, inlen, per_expand_data, out, "");
|
||||
case 'u':
|
||||
return validate_url_and_html_escape.Modify(in, inlen,
|
||||
per_expand_data, out, "");
|
||||
default:
|
||||
break;
|
||||
void PrefixLine::Modify(const char* in, size_t inlen,
|
||||
const ModifierData*,
|
||||
ExpandEmitter* out, const string& arg) const {
|
||||
while (inlen > 0) {
|
||||
const char* nl = (const char*)memchr(in, '\n', inlen);
|
||||
const char* cr = (const char*)memchr(in, '\r', nl ? nl - in : inlen);
|
||||
size_t linelen;
|
||||
if (nl == NULL && cr == NULL) {
|
||||
// We're at the last line
|
||||
out->Emit(in, inlen);
|
||||
break;
|
||||
} else {
|
||||
// One or both of \r and \n is set; point to the first char past
|
||||
// the newline. Note for \r\n, that's the char after the \n,
|
||||
// otherwise, it's the char past the \r or the \n we see.
|
||||
if ((nl == NULL) != (cr == NULL)) // one is set, the other is NULL
|
||||
linelen = (nl ? nl : cr) + 1 - in;
|
||||
else if (nl == cr + 1 || nl < cr) // \r\n, or \n comes first
|
||||
linelen = nl + 1 - in;
|
||||
else
|
||||
linelen = cr + 1 - in;
|
||||
}
|
||||
}
|
||||
return html_escape.Modify(in, inlen, per_expand_data, out, "");
|
||||
}
|
||||
HtmlEscapeWithArg html_escape_with_arg;
|
||||
|
||||
void UrlEscapeWithArg::Modify(const char* in, size_t inlen,
|
||||
const ModifierData* per_expand_data,
|
||||
ExpandEmitter* out,
|
||||
const string& arg) const {
|
||||
if (!arg.empty()) {
|
||||
switch (arg[1]) {
|
||||
case 'j':
|
||||
return validate_url_and_javascript_escape.Modify(in, inlen,
|
||||
per_expand_data,
|
||||
out, "");
|
||||
case 'h':
|
||||
return validate_url_and_html_escape.Modify(in, inlen,
|
||||
per_expand_data,
|
||||
out, "");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return url_query_escape.Modify(in, inlen, per_expand_data, out, "");
|
||||
}
|
||||
UrlEscapeWithArg url_escape_with_arg;
|
||||
|
||||
static vector<ModifierInfo> g_extension_modifiers;
|
||||
static vector<ModifierInfo> g_unknown_modifiers;
|
||||
|
||||
static inline bool IsExtensionModifier(const char* long_name) {
|
||||
return memcmp(long_name, "x-", 2) == 0;
|
||||
}
|
||||
|
||||
bool AddModifier(const char* long_name,
|
||||
ModvalStatus value_status,
|
||||
const TemplateModifier* modifier) {
|
||||
if (!IsExtensionModifier(long_name) ||
|
||||
(value_status != MODVAL_FORBIDDEN && value_status != MODVAL_REQUIRED)) {
|
||||
return false;
|
||||
}
|
||||
const ModifierInfo *existing_modifier = FindModifier(long_name,
|
||||
strlen(long_name));
|
||||
if (!existing_modifier || existing_modifier->value_status == MODVAL_UNKNOWN) {
|
||||
g_extension_modifiers.push_back(ModifierInfo(long_name, '\0',
|
||||
value_status, modifier));
|
||||
return true;
|
||||
} else {
|
||||
// A modifier has already been registered with this name.
|
||||
return false;
|
||||
out->Emit(in, linelen);
|
||||
out->Emit(arg); // a new line, so emit the prefix
|
||||
in += linelen;
|
||||
inlen -= linelen;
|
||||
assert(inlen >= 0);
|
||||
}
|
||||
}
|
||||
PrefixLine prefix_line;
|
||||
|
||||
|
||||
// Must be at least one more than the maximum number of alternative modifiers
|
||||
// specified in any given element of g_modifiers.
|
||||
# define MAX_SAFE_ALTERNATIVES 10 // If the compiler complains, increase it.
|
||||
|
||||
// Use the empty string if you want a modifier not to have a long-name.
|
||||
// Use '\0' if you want a modifier not to have a short-name.
|
||||
|
@ -428,55 +388,228 @@ bool AddModifier(const char* long_name,
|
|||
// 1) SnippetEscape: use html_escape_with_arg=snippet to get this
|
||||
// 2) CleanseAttribute: use html_escape_with_arg=attribute to get this
|
||||
// 3) ValidateUrl: use html_escape_with_arg=url to get this
|
||||
static ModifierInfo g_modifiers[] = {
|
||||
ModifierInfo("html_escape", 'h', MODVAL_FORBIDDEN, &html_escape),
|
||||
ModifierInfo("html_escape_with_arg", 'H', MODVAL_REQUIRED,
|
||||
&html_escape_with_arg),
|
||||
ModifierInfo("javascript_escape", 'j', MODVAL_FORBIDDEN, &javascript_escape),
|
||||
ModifierInfo("json_escape", 'o', MODVAL_FORBIDDEN, &json_escape),
|
||||
ModifierInfo("pre_escape", 'p', MODVAL_FORBIDDEN, &pre_escape),
|
||||
ModifierInfo("url_query_escape", 'u', MODVAL_FORBIDDEN, &url_query_escape),
|
||||
ModifierInfo("url_escape_with_arg", 'U', MODVAL_REQUIRED,
|
||||
&url_escape_with_arg),
|
||||
ModifierInfo("cleanse_css", 'c', MODVAL_FORBIDDEN, &cleanse_css),
|
||||
ModifierInfo("none", '\0', MODVAL_FORBIDDEN, &null_modifier),
|
||||
//
|
||||
// Some modifiers define other modifiers that are safe replacements
|
||||
// from an XSS perspective. Replacements are not commutative so for
|
||||
// example H=pre considers H=attribute a safe replacement to it
|
||||
// but H=attribute has no safe replacements.
|
||||
// This struct is not pretty but allows the definitions to be
|
||||
// done without the need for a global initialization method.
|
||||
// Be very careful making a change to g_modifiers as modifiers
|
||||
// point to other ones within that same array so elements
|
||||
// may not be re-ordered easily.
|
||||
static struct ModifierWithAlternatives {
|
||||
ModifierInfo modifier_info;
|
||||
ModifierInfo* safe_alt_mods[MAX_SAFE_ALTERNATIVES];
|
||||
} g_modifiers[] = {
|
||||
/* 0 */ { ModifierInfo("cleanse_css", 'c', &cleanse_css), {} },
|
||||
/* 1 */ { ModifierInfo("html_escape", 'h', &html_escape),
|
||||
{&g_modifiers[2].modifier_info, // html_escape_with_arg=snippet
|
||||
&g_modifiers[3].modifier_info, // html_escape_with_arg=pre
|
||||
&g_modifiers[4].modifier_info, // html_escape_with_arg=attribute
|
||||
&g_modifiers[8].modifier_info} }, // pre_escape
|
||||
/* 2 */ { ModifierInfo("html_escape_with_arg=snippet", 'H', &snippet_escape),
|
||||
{&g_modifiers[1].modifier_info, // html_escape
|
||||
&g_modifiers[3].modifier_info, // html_escape_with_arg=pre
|
||||
&g_modifiers[4].modifier_info, // html_escape_with_arg=attribute
|
||||
&g_modifiers[8].modifier_info} }, // pre_escape
|
||||
/* 3 */ { ModifierInfo("html_escape_with_arg=pre", 'H', &pre_escape),
|
||||
{&g_modifiers[1].modifier_info, // html_escape
|
||||
&g_modifiers[2].modifier_info, // html_escape_with_arg=snippet
|
||||
&g_modifiers[4].modifier_info, // html_escape_with_arg=attribute
|
||||
&g_modifiers[8].modifier_info} }, // pre_escape
|
||||
/* 4 */ { ModifierInfo("html_escape_with_arg=attribute",
|
||||
'H', &cleanse_attribute), {} },
|
||||
/* 5 */ { ModifierInfo("html_escape_with_arg=url",
|
||||
'H', &validate_url_and_html_escape), {} },
|
||||
/* 6 */ { ModifierInfo("javascript_escape", 'j', &javascript_escape), {} },
|
||||
/* 7 */ { ModifierInfo("json_escape", 'o', &json_escape),
|
||||
{&g_modifiers[6].modifier_info} }, // javascript_escape
|
||||
/* 8 */ { ModifierInfo("pre_escape", 'p', &pre_escape),
|
||||
{&g_modifiers[1].modifier_info, // html_escape
|
||||
&g_modifiers[2].modifier_info, // html_escape_with_arg=snippet
|
||||
&g_modifiers[3].modifier_info, // html_escape_with_arg=pre
|
||||
&g_modifiers[4].modifier_info} }, // html_escape_with_arg=attr...
|
||||
/* 9 */ { ModifierInfo("url_query_escape", 'u', &url_query_escape), {} },
|
||||
/* 10 */ { ModifierInfo("url_escape_with_arg=javascript", 'U',
|
||||
&validate_url_and_javascript_escape), {} },
|
||||
/* 11 */ { ModifierInfo("url_escape_with_arg=html",
|
||||
'U', &validate_url_and_html_escape), {} },
|
||||
/* 12 */ { ModifierInfo("url_escape_with_arg=query",
|
||||
'U', &url_query_escape), {} },
|
||||
/* 13 */ { ModifierInfo("none", '\0', &null_modifier), {} },
|
||||
};
|
||||
|
||||
const ModifierInfo* FindModifier(const char* modname, size_t modname_len) {
|
||||
if (modname_len >= 2 && IsExtensionModifier(modname)) {
|
||||
for (vector<ModifierInfo>::iterator mod = g_extension_modifiers.begin();
|
||||
mod != g_extension_modifiers.end();
|
||||
++mod) {
|
||||
if (modname_len == mod->long_name.size() &&
|
||||
!memcmp(modname, mod->long_name.data(), modname_len)) {
|
||||
return &*mod;
|
||||
}
|
||||
}
|
||||
for (vector<ModifierInfo>::iterator mod = g_unknown_modifiers.begin();
|
||||
mod != g_unknown_modifiers.end();
|
||||
++mod) {
|
||||
if (modname_len == mod->long_name.size() &&
|
||||
!memcmp(modname, mod->long_name.data(), modname_len)) {
|
||||
return &*mod;
|
||||
}
|
||||
}
|
||||
static NullModifier unknown_modifier;
|
||||
g_unknown_modifiers.push_back(ModifierInfo(string(modname, modname_len),
|
||||
'\0', MODVAL_UNKNOWN,
|
||||
&unknown_modifier));
|
||||
return &g_unknown_modifiers.back();
|
||||
} else {
|
||||
for (ModifierInfo* mod = g_modifiers;
|
||||
mod < g_modifiers + sizeof(g_modifiers)/sizeof(*g_modifiers);
|
||||
++mod) {
|
||||
if ((modname_len == 1 && *modname == mod->short_name) ||
|
||||
(modname_len == mod->long_name.size() &&
|
||||
!memcmp(modname, mod->long_name.data(), modname_len))) {
|
||||
return mod;
|
||||
static vector<ModifierInfo> g_extension_modifiers;
|
||||
static vector<ModifierInfo> g_unknown_modifiers;
|
||||
|
||||
// Returns whether or not candidate can be safely (w.r.t XSS)
|
||||
// used in lieu of our ModifierInfo. This is true iff:
|
||||
// 1. Both have the same modifier function OR
|
||||
// 2. Candidate's modifier function is in our ModifierInfo's
|
||||
// list (vector) of safe alternative modifier functions.
|
||||
//
|
||||
// This is used with the auto-escaping code, which automatically
|
||||
// figures out which modifier to apply to a variable based on the
|
||||
// variable's context (in an html "<A HREF", for instance). Some
|
||||
// built-in modifiers are considered safe alternatives from the perspective
|
||||
// of preventing XSS (cross-site-scripting) attacks, in which case
|
||||
// the auto-escaper should allow the choice of which to use in the
|
||||
// template. This is intended only for internal use as it is dangerous
|
||||
// and complicated to figure out which modifier is an XSS-safe
|
||||
// replacement for a given one. Custom modifiers currently may not
|
||||
// indicate safe replacements, only built-in ones may do so.
|
||||
//
|
||||
// Note that this function is not commutative therefore
|
||||
// IsSafeXSSAlternative(a, b) may not be equal to IsSafeXSSAlternative(b, a).
|
||||
bool IsSafeXSSAlternative(const ModifierInfo& our,
|
||||
const ModifierInfo& candidate) {
|
||||
// Succeeds even for non built-in modifiers but no harm.
|
||||
if (our.modifier == candidate.modifier)
|
||||
return true;
|
||||
|
||||
for (const ModifierWithAlternatives* mod_with_alts = g_modifiers;
|
||||
mod_with_alts < g_modifiers + sizeof(g_modifiers)/sizeof(*g_modifiers);
|
||||
++mod_with_alts) {
|
||||
if (mod_with_alts->modifier_info.long_name == our.long_name)
|
||||
// We found our Modifier in the built-in array g_modifiers.
|
||||
for (int i = 0; mod_with_alts->safe_alt_mods[i] != NULL &&
|
||||
i < MAX_SAFE_ALTERNATIVES; ++i)
|
||||
if (mod_with_alts->safe_alt_mods[i]->long_name == candidate.long_name)
|
||||
// We found candidate in our Modifier's list of safe alternatives.
|
||||
return true;
|
||||
}
|
||||
// our is not built-in or candidate is not a safe replacement to our.
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsExtensionModifier(const char* long_name) {
|
||||
return memcmp(long_name, "x-", 2) == 0;
|
||||
}
|
||||
|
||||
bool AddModifier(const char* long_name,
|
||||
const TemplateModifier* modifier) {
|
||||
if (!IsExtensionModifier(long_name))
|
||||
return false;
|
||||
|
||||
for (vector<ModifierInfo>::const_iterator mod = g_extension_modifiers.begin();
|
||||
mod != g_extension_modifiers.end();
|
||||
++mod) {
|
||||
// Check if mod has the same name as us. For modifiers that also take
|
||||
// values, this is everything before the =. The only time it's ok to
|
||||
// have the same name is when we have different modval specializations:
|
||||
// "foo=bar" and "foo=baz" are both valid names. Note "foo" and
|
||||
// "foo=bar" is not valid: foo has no modval, but "foo=bar" does.
|
||||
const size_t new_modifier_namelen = strcspn(long_name, "=");
|
||||
const size_t existing_modifier_namelen = strcspn(mod->long_name.c_str(), "=");
|
||||
if (new_modifier_namelen == existing_modifier_namelen &&
|
||||
memcmp(long_name, mod->long_name.c_str(), new_modifier_namelen) == 0) {
|
||||
if (long_name[new_modifier_namelen] == '=' &&
|
||||
mod->long_name[existing_modifier_namelen] == '=' &&
|
||||
mod->long_name != long_name) {
|
||||
// It's ok, we're different specializations!
|
||||
} else {
|
||||
// It's not ok: we have the same name and no good excuse.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
g_extension_modifiers.push_back(ModifierInfo(long_name, '\0', modifier));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If candidate_match is a better match for modname/modval than bestmatch,
|
||||
// update bestmatch. To be a better match, two conditions must be met:
|
||||
// 1) The candidate's name must match modname
|
||||
// 2) If the candidate is a specialization (that is, name is of the form
|
||||
// "foo=bar", then modval matches the specialization value).
|
||||
// 3) If the candidate is not a specialization, bestmatch isn't a
|
||||
// specialization either.
|
||||
// Condition (3) makes sure that if we match the ModifierInfo with name
|
||||
// "foo=bar", we don't claim the ModifierInfo "foo=" is a better match.
|
||||
// Recall that by definition, modval will always start with a '=' if present.
|
||||
static void UpdateBestMatch(const char* modname, size_t modname_len,
|
||||
const char* modval, size_t modval_len,
|
||||
const ModifierInfo* candidate_match,
|
||||
const ModifierInfo** best_match) {
|
||||
// It's easiest to handle the two case differently: (1) candidate_match
|
||||
// refers to a modifier that expects a modifier-value; (2) it doesn't.
|
||||
if (candidate_match->modval_required) {
|
||||
// To be a match, we have to fulfill three requirements: we have a
|
||||
// modval, our modname matches candidate_match's modname (either
|
||||
// shortname or longname), and our modval is consistent with the
|
||||
// value specified in the longname (whatever might follow the =).
|
||||
const char* const longname_start = candidate_match->long_name.c_str();
|
||||
const char* const equals = strchr(longname_start, '=');
|
||||
assert(equals != NULL);
|
||||
if (modval_len > 0 &&
|
||||
((modname_len == 1 && *modname == candidate_match->short_name) ||
|
||||
(modname_len == equals - longname_start &&
|
||||
memcmp(modname, longname_start, modname_len) == 0)) &&
|
||||
((equals[1] == '\0') || // name is "foo=" (not a specialization)
|
||||
(modval_len
|
||||
== longname_start + candidate_match->long_name.size() - equals &&
|
||||
memcmp(modval, equals, modval_len) == 0))) {
|
||||
// Condition (3) above is satisfied iff our longname is longer than
|
||||
// best-match's longname (so we prefer "foo=bar" to "foo=").
|
||||
if (*best_match == NULL ||
|
||||
candidate_match->long_name.size() > (*best_match)->long_name.size())
|
||||
*best_match = candidate_match;
|
||||
}
|
||||
} else {
|
||||
// In this case, to be a match: we must *not* have a modval. Our
|
||||
// modname still must match modifno's modname (either short or long).
|
||||
if (modval_len == 0 &&
|
||||
((modname_len == 1 && *modname == candidate_match->short_name) ||
|
||||
(modname_len == candidate_match->long_name.size() &&
|
||||
!memcmp(modname, candidate_match->long_name.data(), modname_len)))) {
|
||||
// In the no-modval case, only one match should exist.
|
||||
assert(*best_match == NULL);
|
||||
*best_match = candidate_match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ModifierInfo* FindModifier(const char* modname, size_t modname_len,
|
||||
const char* modval, size_t modval_len) {
|
||||
// More than one modifier can match, in the case of modval specializations
|
||||
// (e.g., the modifier "foo=" and "foo=bar" will both match on input of
|
||||
// modname="foo", modval="bar"). In that case, we take the ModifierInfo
|
||||
// with the longest longname, since that's the most specialized match.
|
||||
const ModifierInfo* best_match = NULL;
|
||||
if (modname_len >= 2 && IsExtensionModifier(modname)) {
|
||||
for (vector<ModifierInfo>::const_iterator mod = g_extension_modifiers.begin();
|
||||
mod != g_extension_modifiers.end();
|
||||
++mod) {
|
||||
UpdateBestMatch(modname, modname_len, modval, modval_len,
|
||||
&*mod, &best_match);
|
||||
}
|
||||
if (best_match != NULL)
|
||||
return best_match;
|
||||
|
||||
for (vector<ModifierInfo>::const_iterator mod = g_unknown_modifiers.begin();
|
||||
mod != g_unknown_modifiers.end();
|
||||
++mod) {
|
||||
UpdateBestMatch(modname, modname_len, modval, modval_len,
|
||||
&*mod, &best_match);
|
||||
}
|
||||
if (best_match != NULL)
|
||||
return best_match;
|
||||
// This is the only situation where we can pass in a modifier of NULL.
|
||||
// It means "we don't know about this modifier-name."
|
||||
g_unknown_modifiers.push_back(ModifierInfo(string(modname, modname_len),
|
||||
'\0', NULL));
|
||||
return &g_unknown_modifiers.back();
|
||||
} else {
|
||||
for (const ModifierWithAlternatives* mod_with_alts = g_modifiers;
|
||||
mod_with_alts < g_modifiers + sizeof(g_modifiers)/sizeof(*g_modifiers);
|
||||
++mod_with_alts) {
|
||||
UpdateBestMatch(modname, modname_len, modval, modval_len,
|
||||
&mod_with_alts->modifier_info, &best_match);
|
||||
}
|
||||
return best_match;
|
||||
}
|
||||
}
|
||||
|
||||
const void* ModifierData::Lookup(const char* key) const {
|
||||
|
|
|
@ -353,44 +353,155 @@ class TemplateModifiersUnittest {
|
|||
ASSERT_STREQ(peer.GetSectionValue("query escape 6"), "%22%27%3A");
|
||||
}
|
||||
|
||||
static void TestPrefixLine() {
|
||||
TemplateDictionary dict("TestPrefixLine", NULL);
|
||||
// These don't escape: we don't put the prefix before the first line
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1", " ").c_str(),
|
||||
"pt 1");
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1", "::").c_str(),
|
||||
"pt 1");
|
||||
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\npt 2", ":").c_str(),
|
||||
"pt 1\n:pt 2");
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\npt 2", " ").c_str(),
|
||||
"pt 1\n pt 2");
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\npt 2", "\n").c_str(),
|
||||
"pt 1\n\npt 2");
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\npt 2\n", " ").c_str(),
|
||||
"pt 1\n pt 2\n ");
|
||||
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\rpt 2\n", ":").c_str(),
|
||||
"pt 1\r:pt 2\n:");
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\npt 2\r", ":").c_str(),
|
||||
"pt 1\n:pt 2\r:");
|
||||
ASSERT_STREQ(template_modifiers::prefix_line("pt 1\r\npt 2\r", ":").c_str(),
|
||||
"pt 1\r\n:pt 2\r:");
|
||||
}
|
||||
|
||||
static void TestFindModifier() {
|
||||
const template_modifiers::ModifierInfo* info;
|
||||
ASSERT(info = template_modifiers::FindModifier("html_escape", 11, "", 0));
|
||||
ASSERT(info->modifier == &template_modifiers::html_escape);
|
||||
ASSERT(info = template_modifiers::FindModifier("h", 1, "", 0));
|
||||
ASSERT(info->modifier == &template_modifiers::html_escape);
|
||||
|
||||
ASSERT(info = template_modifiers::FindModifier("html_escape_with_arg", 20,
|
||||
"=pre", 4));
|
||||
ASSERT(info->modifier == &template_modifiers::pre_escape);
|
||||
ASSERT(info = template_modifiers::FindModifier("H", 1, "=pre", 4));
|
||||
ASSERT(info->modifier == &template_modifiers::pre_escape);
|
||||
// html_escape_with_arg doesn't have a default value, so these should fail.
|
||||
ASSERT(!template_modifiers::FindModifier("H", 1, "=pre", 2)); // "=p"
|
||||
ASSERT(!template_modifiers::FindModifier("H", 1, "=pree", 5));
|
||||
ASSERT(!template_modifiers::FindModifier("H", 1, "=notpresent", 11));
|
||||
|
||||
// If we don't have a modifier-value when we ought, we should fail.
|
||||
ASSERT(!template_modifiers::FindModifier("html_escape", 11, "=p", 2));
|
||||
ASSERT(!template_modifiers::FindModifier("h", 1, "=p", 2));
|
||||
|
||||
ASSERT(!template_modifiers::FindModifier("html_escape_with_arg", 20,
|
||||
"", 0));
|
||||
ASSERT(!template_modifiers::FindModifier("H", 1, "", 0));
|
||||
|
||||
// Test with added modifiers as well.
|
||||
template_modifiers::NullModifier foo_modifier1;
|
||||
template_modifiers::NullModifier foo_modifier2;
|
||||
template_modifiers::NullModifier foo_modifier3;
|
||||
template_modifiers::NullModifier foo_modifier4;
|
||||
ASSERT(template_modifiers::AddModifier("x-test", &foo_modifier1));
|
||||
ASSERT(template_modifiers::AddModifier("x-test-arg=", &foo_modifier2));
|
||||
ASSERT(template_modifiers::AddModifier("x-test-arg=h", &foo_modifier3));
|
||||
ASSERT(template_modifiers::AddModifier("x-test-arg=json", &foo_modifier4));
|
||||
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test", 6, "", 0));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier1);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test", 6, "=h", 2));
|
||||
ASSERT(!info->is_registered);
|
||||
// This tests default values
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10, "=p", 2));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier2);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10, "=h", 2));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier3);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10,
|
||||
"=html", 5));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier2);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10,
|
||||
"=json", 5));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier4);
|
||||
// The value is required to start with an '=' to match the
|
||||
// specialization. If it doesn't, it will match the default.
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10,
|
||||
"json", 4));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier2);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10,
|
||||
"=jsonnabbe", 5));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier4);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10,
|
||||
"=jsonnabbe", 6));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier2);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test-arg", 10,
|
||||
"=jsonnabbe", 4));
|
||||
ASSERT(info->is_registered);
|
||||
ASSERT(info->modifier == &foo_modifier2);
|
||||
|
||||
// If we try to find an x- modifier that wasn't added, we should get
|
||||
// a legit but "unknown" modifier back.
|
||||
ASSERT(info = template_modifiers::FindModifier("x-foo", 5, "", 0));
|
||||
ASSERT(!info->is_registered);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-bar", 5, "=p", 2));
|
||||
ASSERT(!info->is_registered);
|
||||
}
|
||||
|
||||
static void TestAddModifier() {
|
||||
ASSERT(template_modifiers::AddModifier(
|
||||
"x-test",
|
||||
template_modifiers::MODVAL_FORBIDDEN,
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier(
|
||||
"x-test-arg",
|
||||
template_modifiers::MODVAL_REQUIRED,
|
||||
&template_modifiers::html_escape_with_arg));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest-arg=",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest-arg=h",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest-arg=html",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest-arg=json",
|
||||
&template_modifiers::json_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest-arg=j",
|
||||
&template_modifiers::json_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-atest-arg=J",
|
||||
&template_modifiers::json_escape));
|
||||
|
||||
// Make sure AddModifier fails with an invalid name.
|
||||
ASSERT(!template_modifiers::AddModifier(
|
||||
"test",
|
||||
template_modifiers::MODVAL_FORBIDDEN,
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(!template_modifiers::AddModifier("test",
|
||||
&template_modifiers::html_escape));
|
||||
|
||||
// Make sure AddModifier fails with a duplicate name.
|
||||
ASSERT(!template_modifiers::AddModifier(
|
||||
"x-test",
|
||||
template_modifiers::MODVAL_FORBIDDEN,
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(!template_modifiers::AddModifier("x-atest",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(!template_modifiers::AddModifier("x-atest-arg=",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(!template_modifiers::AddModifier("x-atest-arg=h",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(!template_modifiers::AddModifier("x-atest-arg=html",
|
||||
&template_modifiers::html_escape));
|
||||
|
||||
const template_modifiers::ModifierInfo* info;
|
||||
ASSERT(info = template_modifiers::FindModifier("x-test", 6));
|
||||
ASSERT(info->value_status == template_modifiers::MODVAL_FORBIDDEN);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-atest", 7, "", 0));
|
||||
ASSERT(info->modval_required == false);
|
||||
|
||||
// Make sure we can still add a modifier after having already
|
||||
// searched for it.
|
||||
ASSERT(info = template_modifiers::FindModifier("x-foo", 5));
|
||||
ASSERT(info->value_status == template_modifiers::MODVAL_UNKNOWN);
|
||||
ASSERT(info = template_modifiers::FindModifier("x-foo", 5, "", 0));
|
||||
ASSERT(!info->is_registered);
|
||||
|
||||
template_modifiers::NullModifier foo_modifier;
|
||||
ASSERT(template_modifiers::AddModifier(
|
||||
"x-foo",
|
||||
template_modifiers::MODVAL_FORBIDDEN,
|
||||
&foo_modifier));
|
||||
ASSERT(info = template_modifiers::FindModifier("x-foo", 5));
|
||||
ASSERT(info->value_status == template_modifiers::MODVAL_FORBIDDEN);
|
||||
ASSERT(template_modifiers::AddModifier("x-foo", &foo_modifier));
|
||||
ASSERT(info = template_modifiers::FindModifier("x-foo", 5, "", 0));
|
||||
ASSERT(info->modifier == &foo_modifier);
|
||||
}
|
||||
|
||||
|
@ -413,6 +524,62 @@ class TemplateModifiersUnittest {
|
|||
ASSERT(data_b == data_copy.Lookup("b"));
|
||||
}
|
||||
|
||||
// Helper function. Determines whether the Modifier specified by
|
||||
// alt_modname/alt_modval is a safe XSS alternative to
|
||||
// the Modifier specified by modname/modval.
|
||||
static bool CheckXSSAlternative(const string& modname, const string& modval,
|
||||
const string& alt_modname,
|
||||
const string& alt_modval) {
|
||||
const template_modifiers::ModifierInfo *mod, *alt_mod;
|
||||
mod = template_modifiers::FindModifier(modname.c_str(), modname.length(),
|
||||
modval.c_str(), modval.length());
|
||||
alt_mod = template_modifiers::FindModifier(alt_modname.c_str(),
|
||||
alt_modname.length(),
|
||||
alt_modval.c_str(),
|
||||
alt_modval.length());
|
||||
ASSERT(mod != NULL && alt_mod != NULL);
|
||||
return IsSafeXSSAlternative(*mod, *alt_mod);
|
||||
}
|
||||
|
||||
static void TestXSSAlternatives() {
|
||||
|
||||
// A modifier is always a safe replacement to itself, even non built-in.
|
||||
ASSERT(CheckXSSAlternative("h", "", "h", ""));
|
||||
ASSERT(CheckXSSAlternative("url_escape_with_arg", "=javascript",
|
||||
"url_escape_with_arg", "=javascript"));
|
||||
ASSERT(CheckXSSAlternative("x-bla", "", "x-bla", ""));
|
||||
|
||||
// A built-in modifier is always a safe replacement to
|
||||
// another with the same function.
|
||||
ASSERT(CheckXSSAlternative("H", "=pre", "p", ""));
|
||||
ASSERT(CheckXSSAlternative("url_query_escape", "",
|
||||
"url_escape_with_arg", "=query"));
|
||||
|
||||
// H=pre, H=snippet, H=attribute and p are all alternatives to h.
|
||||
ASSERT(CheckXSSAlternative("h", "", "H", "=pre"));
|
||||
ASSERT(CheckXSSAlternative("h", "", "H", "=snippet"));
|
||||
ASSERT(CheckXSSAlternative("h", "", "H", "=attribute"));
|
||||
ASSERT(CheckXSSAlternative("h", "", "p", ""));
|
||||
|
||||
// But h is not an alternative to H=attribute
|
||||
// nor are u or json_escape alternatives to h.
|
||||
ASSERT(!CheckXSSAlternative("H", "=attribute", "h", ""));
|
||||
ASSERT(!CheckXSSAlternative("h", "", "u", ""));
|
||||
ASSERT(!CheckXSSAlternative("h", "", "json_escape", ""));
|
||||
|
||||
// H=snippet and H=attribute are alternatives to H=pre
|
||||
// But H=pre is not an alternative to H=attribute.
|
||||
ASSERT(CheckXSSAlternative("H", "=pre", "H", "=snippet"));
|
||||
ASSERT(CheckXSSAlternative("H", "=pre", "H", "=attribute"));
|
||||
ASSERT(!CheckXSSAlternative("H", "=attribute", "H", "=pre"));
|
||||
|
||||
// javascript_escape is an alternative to json_escape but not the opposite.
|
||||
ASSERT(CheckXSSAlternative("json_escape", "", "javascript_escape", ""));
|
||||
ASSERT(!CheckXSSAlternative("javascript_escape", "", "json_escape", ""));
|
||||
|
||||
// Extended modifier should not match any other except itself.
|
||||
ASSERT(!CheckXSSAlternative("x-bla", "", "x-foo", ""));
|
||||
}
|
||||
};
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
@ -431,8 +598,11 @@ int main(int argc, char** argv) {
|
|||
TemplateModifiersUnittest::TestJavascriptEscape();
|
||||
TemplateModifiersUnittest::TestJsonEscape();
|
||||
TemplateModifiersUnittest::TestUrlQueryEscape();
|
||||
TemplateModifiersUnittest::TestPrefixLine();
|
||||
TemplateModifiersUnittest::TestFindModifier();
|
||||
TemplateModifiersUnittest::TestAddModifier();
|
||||
TemplateModifiersUnittest::TestModifierData();
|
||||
TemplateModifiersUnittest::TestXSSAlternatives();
|
||||
|
||||
printf("DONE\n");
|
||||
return 0;
|
||||
|
|
|
@ -182,14 +182,15 @@ static vector<Testdata> ReadDataFiles(const char* testdata_dir) {
|
|||
GetNamelist(testdata_dir, &namelist);
|
||||
sort(namelist.begin(), namelist.end());
|
||||
|
||||
for (size_t i = 0; i < namelist.size(); ++i) {
|
||||
for (vector<string>::const_iterator it = namelist.begin();
|
||||
it != namelist.end(); ++it) {
|
||||
vector<string>* new_output = NULL;
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof(fname), "%s/%s", testdata_dir, namelist[i].c_str());
|
||||
snprintf(fname, sizeof(fname), "%s/%s", testdata_dir, it->c_str());
|
||||
// happily, due to strncmp above, we know namelist[i] is bigger than 20
|
||||
if (!strcmp(fname + strlen(fname) - 3, ".in")) {
|
||||
retval.push_back(Testdata());
|
||||
retval.back().input_template_name = namelist[i];
|
||||
retval.back().input_template_name = *it;
|
||||
ReadToString(fname, &retval.back().input_template);
|
||||
} else if (!strcmp(fname + strlen(fname) - 4, ".out")) {
|
||||
new_output = &retval.back().output;
|
||||
|
@ -200,14 +201,14 @@ static vector<Testdata> ReadDataFiles(const char* testdata_dir) {
|
|||
}
|
||||
if (new_output) { // the .out and .anno_out cases
|
||||
ASSERT(!retval.empty()); // an .out without any corresponding .in?
|
||||
ASSERT(namelist[i].length() >
|
||||
retval.back().input_template_name.length() + 4);
|
||||
ASSERT(it->length() > retval.back().input_template_name.length() + 4);
|
||||
// input file is foo.in, and output is foo_dictYY.out. This gets to YY.
|
||||
const char* dictnum_pos = (namelist[i].c_str() +
|
||||
const char* dictnum_pos = (it->c_str() +
|
||||
retval.back().input_template_name.length() + 2);
|
||||
int dictnum = atoi(dictnum_pos); // just ignore chars after the YY
|
||||
ASSERT(dictnum); // dictnums should start with 01
|
||||
for (size_t i = new_output->size(); i < dictnum; ++i)
|
||||
while (new_output->size() <
|
||||
static_cast<vector<string>::size_type>(dictnum))
|
||||
new_output->push_back(string());
|
||||
ReadToString(fname, &((*new_output)[dictnum-1]));
|
||||
}
|
||||
|
|
|
@ -266,14 +266,12 @@ class TemplateUnittest {
|
|||
AssertExpandIs(tpl, &dict, "hi yo_yo # <b>foo & bar</b> lo", true);
|
||||
|
||||
// Test with custom modifier
|
||||
ASSERT(template_modifiers::AddModifier(
|
||||
"x-test",
|
||||
template_modifiers::MODVAL_FORBIDDEN,
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier(
|
||||
"x-test-arg",
|
||||
template_modifiers::MODVAL_REQUIRED,
|
||||
&template_modifiers::html_escape_with_arg));
|
||||
ASSERT(template_modifiers::AddModifier("x-test",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-test-arg=",
|
||||
&template_modifiers::html_escape));
|
||||
ASSERT(template_modifiers::AddModifier("x-test-arg=snippet",
|
||||
&template_modifiers::snippet_escape));
|
||||
|
||||
tpl = StringToTemplate("hi {{VAR:x-test}} lo", STRIP_WHITESPACE);
|
||||
AssertExpandIs(tpl, &dict, "hi yo&yo lo", true);
|
||||
|
@ -285,10 +283,7 @@ class TemplateUnittest {
|
|||
|
||||
// Test with a modifier taking per-expand data
|
||||
DynamicModifier dynamic_modifier;
|
||||
ASSERT(template_modifiers::AddModifier(
|
||||
"x-dynamic",
|
||||
template_modifiers::MODVAL_FORBIDDEN,
|
||||
&dynamic_modifier));
|
||||
ASSERT(template_modifiers::AddModifier("x-dynamic", &dynamic_modifier));
|
||||
tpl = StringToTemplate("hi {{VAR:x-dynamic}} lo", STRIP_WHITESPACE);
|
||||
AssertExpandIs(tpl, &dict, "hi lo", true);
|
||||
dict.SetModifierData("value", "foo");
|
||||
|
@ -399,7 +394,7 @@ class TemplateUnittest {
|
|||
|
||||
static void TestInclude() {
|
||||
string incname = StringToTemplateFile("include file\n");
|
||||
string incname2 = StringToTemplateFile("inc2\n");
|
||||
string incname2 = StringToTemplateFile("inc2a\ninc2b\n");
|
||||
string incname_bad = StringToTemplateFile("{{syntax_error");
|
||||
Template* tpl = StringToTemplate("hi {{>INC}} bar\n", STRIP_WHITESPACE);
|
||||
TemplateDictionary dict("dict");
|
||||
|
@ -418,12 +413,44 @@ class TemplateUnittest {
|
|||
dict.AddIncludeDictionary("inc")->SetFilename(incname);
|
||||
AssertExpandIs(tpl, &dict, "hi include fileinclude file bar", false);
|
||||
dict.AddIncludeDictionary("INC")->SetFilename(incname2);
|
||||
AssertExpandIs(tpl, &dict, "hi include fileinclude fileinc2 bar", false);
|
||||
AssertExpandIs(tpl, &dict,
|
||||
"hi include fileinclude fileinc2ainc2b bar", false);
|
||||
|
||||
// Now test that includes preserve Strip
|
||||
Template* tpl2 = StringToTemplate("hi {{>INC}} bar", DO_NOT_STRIP);
|
||||
AssertExpandIs(tpl2, &dict, "hi include file\ninclude file\ninc2\n bar",
|
||||
AssertExpandIs(tpl2, &dict,
|
||||
"hi include file\ninclude file\ninc2a\ninc2b\n bar", false);
|
||||
|
||||
// Test that if we indent the include, every line on the include
|
||||
// is indented.
|
||||
Template* tpl3 = StringToTemplate("hi\n {{>INC}} bar", DO_NOT_STRIP);
|
||||
AssertExpandIs(tpl3, &dict,
|
||||
"hi\n include file\n include file\n"
|
||||
" inc2a\n inc2b\n bar",
|
||||
false);
|
||||
// But obviously, if we strip leading whitespace, no indentation.
|
||||
Template* tpl4 = StringToTemplate("hi\n {{>INC}} bar", STRIP_WHITESPACE);
|
||||
AssertExpandIs(tpl4, &dict,
|
||||
"hiinclude fileinclude fileinc2ainc2b bar", false);
|
||||
// And if it's not a whitespace indent, we don't indent either.
|
||||
Template* tpl5 = StringToTemplate("hi\n - {{>INC}} bar", DO_NOT_STRIP);
|
||||
AssertExpandIs(tpl5, &dict,
|
||||
"hi\n - include file\ninclude file\n"
|
||||
"inc2a\ninc2b\n bar",
|
||||
false);
|
||||
// Make sure we indent properly at the beginning.
|
||||
Template* tpl6 = StringToTemplate(" {{>INC}}\nbar", DO_NOT_STRIP);
|
||||
AssertExpandIs(tpl6, &dict,
|
||||
" include file\n include file\n"
|
||||
" inc2a\n inc2b\n \nbar",
|
||||
false);
|
||||
// And deal correctly when we include twice in a row.
|
||||
Template* tpl7 = StringToTemplate(" {{>INC}}-{{>INC}}", DO_NOT_STRIP);
|
||||
AssertExpandIs(tpl7, &dict,
|
||||
" include file\n include file\n inc2a\n inc2b\n "
|
||||
"-include file\ninclude file\ninc2a\ninc2b\n",
|
||||
false);
|
||||
|
||||
}
|
||||
|
||||
static void TestIncludeWithModifiers() {
|
||||
|
@ -438,6 +465,10 @@ class TemplateUnittest {
|
|||
Template* tpl3 = StringToTemplate("hi {{>INC:pre_escape}} bar\n",
|
||||
DO_NOT_STRIP);
|
||||
Template* tpl4 = StringToTemplate("hi {{>INC:u}} bar\n", DO_NOT_STRIP);
|
||||
// Test that if we include the same template twice, once with a modifer
|
||||
// and once without, they each get applied properly.
|
||||
Template* tpl5 = StringToTemplate("hi {{>INC:h}} bar {{>INC}} baz\n",
|
||||
DO_NOT_STRIP);
|
||||
|
||||
TemplateDictionary dict("dict");
|
||||
AssertExpandIs(tpl1, &dict, "hi bar\n", true);
|
||||
|
@ -454,17 +485,24 @@ class TemplateUnittest {
|
|||
AssertExpandIs(tpl4, &dict,
|
||||
"hi include+%26+print+file%0Ainc2%0Ayo%26yo bar\n",
|
||||
true);
|
||||
AssertExpandIs(tpl5, &dict,
|
||||
"hi include & print file inc2 yo&yo bar "
|
||||
"include & print file\ninc2\nyo&yo baz\n",
|
||||
true);
|
||||
|
||||
// Don't test modifier syntax here; that's in TestVariableWithModifiers()
|
||||
}
|
||||
|
||||
// Make sure we don't deadlock when a template includes itself.
|
||||
// This also tests we handle recursive indentation properly.
|
||||
static void TestRecursiveInclude() {
|
||||
string incname = StringToTemplateFile("hi {{>INC}} bar\n");
|
||||
Template* tpl = Template::GetTemplate(incname, STRIP_WHITESPACE);
|
||||
string incname = StringToTemplateFile("hi {{>INC}} bar\n {{>INC}}!");
|
||||
Template* tpl = Template::GetTemplate(incname, DO_NOT_STRIP);
|
||||
TemplateDictionary dict("dict");
|
||||
dict.AddIncludeDictionary("INC")->SetFilename(incname);
|
||||
AssertExpandIs(tpl, &dict, "hi hi bar bar", true);
|
||||
// Note the last line is indented 4 spaces instead of 2. This is
|
||||
// because the last sub-include is indented.
|
||||
AssertExpandIs(tpl, &dict, "hi hi bar\n ! bar\n hi bar\n !!", true);
|
||||
}
|
||||
|
||||
// Tests that vars inherit/override their parents properly
|
||||
|
@ -535,12 +573,12 @@ class TemplateUnittest {
|
|||
dict.SetAnnotateOutput("");
|
||||
char expected[10240]; // 10k should be big enough!
|
||||
snprintf(expected, sizeof(expected),
|
||||
"{{#FILE=%s003}}{{#SEC=__MAIN__}}boo!\n"
|
||||
"{{#FILE=%s003}}{{#SEC=__{{MAIN}}__}}boo!\n"
|
||||
"{{#INC=INC}}{{#FILE=%s001}}"
|
||||
"{{#SEC=__MAIN__}}include {{#SEC=ISEC}}file{{/SEC}}\n"
|
||||
"{{#SEC=__{{MAIN}}__}}include {{#SEC=ISEC}}file{{/SEC}}\n"
|
||||
"{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"{{#INC=INC}}{{#FILE=%s002}}"
|
||||
"{{#SEC=__MAIN__}}include #2\n{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"{{#SEC=__{{MAIN}}__}}include #2\n{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"\nhi {{#SEC=SEC}}lo{{/SEC}} bar "
|
||||
"{{#VAR=VAR:x-foo<not registered>}}var{{/VAR}}{{/SEC}}{{/FILE}}",
|
||||
(FLAGS_test_tmpdir + slash_tpl).c_str(),
|
||||
|
@ -550,12 +588,12 @@ class TemplateUnittest {
|
|||
|
||||
dict.SetAnnotateOutput(slash_tpl.c_str());
|
||||
snprintf(expected, sizeof(expected),
|
||||
"{{#FILE=%s003}}{{#SEC=__MAIN__}}boo!\n"
|
||||
"{{#FILE=%s003}}{{#SEC=__{{MAIN}}__}}boo!\n"
|
||||
"{{#INC=INC}}{{#FILE=%s001}}"
|
||||
"{{#SEC=__MAIN__}}include {{#SEC=ISEC}}file{{/SEC}}\n"
|
||||
"{{#SEC=__{{MAIN}}__}}include {{#SEC=ISEC}}file{{/SEC}}\n"
|
||||
"{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"{{#INC=INC}}{{#FILE=%s002}}"
|
||||
"{{#SEC=__MAIN__}}include #2\n{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"{{#SEC=__{{MAIN}}__}}include #2\n{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"\nhi {{#SEC=SEC}}lo{{/SEC}} bar "
|
||||
"{{#VAR=VAR:x-foo<not registered>}}var{{/VAR}}{{/SEC}}{{/FILE}}",
|
||||
(slash_tpl).c_str(),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{#FILE=template_unittest_test_html.in}}{{#SEC=__MAIN__}}<html>
|
||||
{{#FILE=template_unittest_test_html.in}}{{#SEC=__{{MAIN}}__}}<html>
|
||||
<head>
|
||||
<script>{{#VAR=BI_NEWLINE}}
|
||||
{{/VAR}}
|
||||
|
@ -51,7 +51,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{/SEC}}{{#INC=FOOTER}}{{#FILE=template_unittest_test_footer.in}}{{#SEC=__MAIN__}}<center><p><hr class=z>
|
||||
{{/SEC}}{{#INC=FOOTER}}{{#FILE=template_unittest_test_footer.in}}{{#SEC=__{{MAIN}}__}}<center><p><hr class=z>
|
||||
<table width=100% cellpadding=2 cellspacing=0 border=0>
|
||||
<tr>
|
||||
<td align=center{{#VAR=FOOTER_BAR_ATTRIBUTES}}{{/VAR}}><font size=-1>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{#FILE=template_unittest_test_modifiers.in}}{{#SEC=__MAIN__}}<html>
|
||||
{{#FILE=template_unittest_test_modifiers.in}}{{#SEC=__{{MAIN}}__}}<html>
|
||||
<body>
|
||||
{{#SEC=UPDATE_SECTION}} {{#VAR=UPDATE}}monday & tuesday{{/VAR}}
|
||||
{{#VAR=UPDATE:html_escape}}monday &amp; tuesday{{/VAR}}
|
||||
|
@ -6,6 +6,6 @@
|
|||
{{#VAR=UPDATE:html_escape:url_query_escape}}monday+%26amp%3Bamp%3B+tuesday{{/VAR}}
|
||||
{{/SEC}} <IMG src=foo.jpg align={{#VAR=ALIGNMENT}}"right"{{/VAR}}>
|
||||
<IMG src="mouseover() {img=\'foo.jpg\' align={{#VAR=ALIGNMENT:javascript_escape}}\x22right\x22{{/VAR}}}">
|
||||
{{#INC=SIMPLE:html_escape}}{{#FILE=template_unittest_test_simple.in}}{{#SEC=__MAIN__}}<html> <head> {{#VAR=HEAD}}{{/VAR}} </head> <body> {{#VAR=BODY}}{{/VAR}} </body> </html>{{#VAR=BI_NEWLINE}} {{/VAR}}{{/SEC}}{{/FILE}}{{/INC}}</body>
|
||||
{{#INC=SIMPLE:html_escape}}{{#FILE=template_unittest_test_simple.in}}{{#SEC=__{{MAIN}}__}}<html> <head> {{#VAR=HEAD}}{{/VAR}} </head> <body> {{#VAR=BODY}}{{/VAR}} </body> </html>{{#VAR=BI_NEWLINE}} {{/VAR}}{{/SEC}}{{/FILE}}{{/INC}}</body>
|
||||
</html>{{#VAR=BI_NEWLINE}}
|
||||
{{/VAR}}{{/SEC}}{{/FILE}}
|
|
@ -180,7 +180,7 @@ class CTEMPLATE_DLL_DECL Template {
|
|||
// Template constructor
|
||||
// Reads the template file and parses it into a parse tree of TemplateNodes
|
||||
// by calling the method ReloadIfChanged
|
||||
// The top node is a section node with the arbitrary name "__MAIN__"
|
||||
// The top node is a section node with the arbitrary name "__{{MAIN}}__"
|
||||
// 'Strip' indicates how to handle whitespace when expanding the
|
||||
// template. DO_NOT_STRIP keeps the template exactly as-is.
|
||||
// STRIP_BLANK_LINES elides all blank lines in the template.
|
||||
|
@ -223,8 +223,8 @@ class CTEMPLATE_DLL_DECL Template {
|
|||
// buffer must be big enough to hold the output. It's guaranteed
|
||||
// that the output size is no bigger than the input size.
|
||||
// Used by ReloadIfChanged()
|
||||
int InsertLine(const char *line, int len, char* buffer);
|
||||
int InsertFile(const char *file, size_t len, char* buffer);
|
||||
size_t InsertLine(const char *line, size_t len, char* buffer);
|
||||
size_t InsertFile(const char *file, size_t len, char* buffer);
|
||||
|
||||
|
||||
// The file we read the template from
|
||||
|
@ -232,7 +232,7 @@ class CTEMPLATE_DLL_DECL Template {
|
|||
time_t filename_mtime_; // lastmod time for filename last time we loaded it
|
||||
|
||||
// What to do with whitespace at template-expand time
|
||||
const Strip strip_;
|
||||
Strip strip_;
|
||||
|
||||
// Keeps track of where we are in reloading, or if there was an error loading
|
||||
TemplateState state_;
|
||||
|
|
|
@ -126,25 +126,6 @@ class CTEMPLATE_DLL_DECL TemplateDictionary {
|
|||
#endif
|
||||
; // starts at 3 because of implicit 1st arg 'this'
|
||||
|
||||
// TemplateModifier is defined in template_modifier.h, which also provides
|
||||
// some functors to use (particularly useful ones are also defined below).
|
||||
// NOTE: This method is provided for convenience, but it's better to call
|
||||
// SetValue() and do the escaping in the template itself when possible:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedValue(const TemplateString variable, const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn);
|
||||
|
||||
// NOTE: This method is provided for convenience, but it's better to call
|
||||
// SetFormattedValue() and do the escaping in the template itself:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedFormattedValue(const TemplateString variable,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const char* format, ...)
|
||||
#if 0
|
||||
__attribute__((__format__ (__printf__, 4, 5)))
|
||||
#endif
|
||||
; // starts at 4 because of implicit 1st arg 'this'
|
||||
|
||||
// We also let you set values in the 'global' dictionary which is
|
||||
// referenced when all other dictionaries fail. Note this is a
|
||||
// static method: no TemplateDictionary instance needed. Since
|
||||
|
@ -189,16 +170,6 @@ class CTEMPLATE_DLL_DECL TemplateDictionary {
|
|||
const TemplateString value,
|
||||
const TemplateString section_name);
|
||||
|
||||
// In this case, we hide the section if the *escaped* value of the variable
|
||||
// is the empty string.
|
||||
// NOTE: This method is provided for convenience, but it's better to call
|
||||
// SetValueAndShowSection() and do the escaping in the template itself:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedValueAndShowSection(const TemplateString variable,
|
||||
const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const TemplateString section_name);
|
||||
|
||||
|
||||
// --- Routines for TEMPLATE-INCLUDES
|
||||
// Included templates are treated like sections, but they require
|
||||
|
@ -217,18 +188,6 @@ class CTEMPLATE_DLL_DECL TemplateDictionary {
|
|||
// to clear any value previously set.
|
||||
void SetModifierData(const char* key, const void* value);
|
||||
|
||||
// --- ESCAPE FUNCTORS
|
||||
// Some commonly-used escape functors. These just point to the
|
||||
// variable of the same name in template_modifiers.h, and are kept
|
||||
// here for backwards compatibility. For new code, and to get access
|
||||
// to escape functors not listed here, use template_modifiers.h.
|
||||
static const template_modifiers::HtmlEscape& html_escape;
|
||||
static const template_modifiers::PreEscape& pre_escape;
|
||||
static const template_modifiers::XmlEscape& xml_escape;
|
||||
static const template_modifiers::JavascriptEscape& javascript_escape;
|
||||
static const template_modifiers::UrlQueryEscape& url_query_escape;
|
||||
static const template_modifiers::JsonEscape& json_escape;
|
||||
|
||||
|
||||
// --- DEBUGGING TOOLS
|
||||
|
||||
|
@ -246,6 +205,32 @@ class CTEMPLATE_DLL_DECL TemplateDictionary {
|
|||
void SetAnnotateOutput(const char* template_path_start);
|
||||
|
||||
|
||||
// --- DEPRECATED ESCAPING FUNCTIONALITY
|
||||
|
||||
// Escaping in the binary has been deprecated in favor of using modifiers
|
||||
// to do the escaping in the template:
|
||||
// "...{{MYVAR:html_escape}}..."
|
||||
void SetEscapedValue(const TemplateString variable, const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn);
|
||||
void SetEscapedFormattedValue(const TemplateString variable,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const char* format, ...)
|
||||
#if 0
|
||||
__attribute__((__format__ (__printf__, 4, 5)))
|
||||
#endif
|
||||
; // starts at 4 because of implicit 1st arg 'this'
|
||||
void SetEscapedValueAndShowSection(const TemplateString variable,
|
||||
const TemplateString value,
|
||||
const template_modifiers::TemplateModifier& escfn,
|
||||
const TemplateString section_name);
|
||||
static const template_modifiers::HtmlEscape& html_escape;
|
||||
static const template_modifiers::PreEscape& pre_escape;
|
||||
static const template_modifiers::XmlEscape& xml_escape;
|
||||
static const template_modifiers::JavascriptEscape& javascript_escape;
|
||||
static const template_modifiers::UrlQueryEscape& url_query_escape;
|
||||
static const template_modifiers::JsonEscape& json_escape;
|
||||
|
||||
|
||||
private:
|
||||
friend class SectionTemplateNode; // for access to GetSectionValue(), etc.
|
||||
friend class TemplateTemplateNode; // for access to GetSectionValue(), etc.
|
||||
|
|
|
@ -45,15 +45,9 @@
|
|||
//
|
||||
// In addition to the list of modifiers hard-coded in the source code
|
||||
// here, it is possible to dynamicly register modifiers using a long
|
||||
// name starting with "x-".
|
||||
//
|
||||
// In addition to using a modifier within a template, you can also
|
||||
// pass a modifier object to TemplateDictionary::SetEscapedValue() and
|
||||
// similar methods. The built-in modifier objects are defined in this
|
||||
// file (some are also exported in template_dictionary.h for backwards
|
||||
// compatibility). If you wish to define your own modifier class, in
|
||||
// your own source code, just subclass TemplateModifier -- see
|
||||
// template_modifiers.cc for details of how to do that.
|
||||
// name starting with "x-". If you wish to define your own modifier
|
||||
// class, in your own source code, just subclass TemplateModifier --
|
||||
// see template_modifiers.cc for details of how to do that.
|
||||
//
|
||||
// Adding a new built-in modifier, to this file, takes several steps,
|
||||
// both in this .h file and in the corresponding .cc file:
|
||||
|
@ -101,9 +95,18 @@ class ModifierData;
|
|||
class CTEMPLATE_DLL_DECL TemplateModifier {
|
||||
public:
|
||||
// This function takes a string as input, a char*/size_t pair, and
|
||||
// appends the modified version to the end of outbuf. "arg" is
|
||||
// used for modifiers that take a modifier-value argument; for
|
||||
// modifiers that take no argument, arg will always be "".
|
||||
// appends the modified version to the end of outbuf. In addition
|
||||
// to the variable-value to modify (specified via in/inlen), each
|
||||
// Modify passes in two pieces of user-supplied data:
|
||||
// 1) arg: this is the modifier-value, for modifiers that take a
|
||||
// value (e.g. "{{VAR:modifier=value}}"). This value
|
||||
// comes from the template file. For modifiers that take
|
||||
// no modval argument, arg will always be "". For modifiers
|
||||
// that do take such an argument, arg will always start with "=".
|
||||
// 2) per_expand_data: this is a set of data that the application can
|
||||
// associate with a TemplateDictionary, and is passed in to
|
||||
// every variable expanded using that dictionary. This value
|
||||
// comes from the source code.
|
||||
virtual void Modify(const char* in, size_t inlen,
|
||||
const ModifierData* per_expand_data,
|
||||
ExpandEmitter* outbuf,
|
||||
|
@ -191,53 +194,78 @@ extern CTEMPLATE_DLL_DECL UrlQueryEscape url_query_escape;
|
|||
class CTEMPLATE_DLL_DECL JsonEscape : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern CTEMPLATE_DLL_DECL JsonEscape json_escape;
|
||||
|
||||
// A dispatch routine that calls pre_escape, snippet_escape,
|
||||
// cleanse_attribute, or validate_url, depending on the value of the arg.
|
||||
class CTEMPLATE_DLL_DECL HtmlEscapeWithArg : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern CTEMPLATE_DLL_DECL HtmlEscapeWithArg html_escape_with_arg;
|
||||
|
||||
// A similar dispatch routine for URLS.
|
||||
// Calls validate_url_and_javascript_escape, validate_url_and_html_escape,
|
||||
// or url_query_escape depending on the value of the argument..
|
||||
class CTEMPLATE_DLL_DECL UrlEscapeWithArg : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern CTEMPLATE_DLL_DECL UrlEscapeWithArg url_escape_with_arg;
|
||||
// Inserts the given prefix (given as the argument to this modifier)
|
||||
// after every newline in the text. Note that it does *not* insert
|
||||
// prefix at the very beginning of the text -- in its expected use,
|
||||
// that prefix will already be present before this text, in the
|
||||
// template. This is meant to be used internally, and is not exported
|
||||
// via the g_modifiers list.
|
||||
class CTEMPLATE_DLL_DECL PrefixLine : public TemplateModifier { MODIFY_SIGNATURE_; };
|
||||
extern CTEMPLATE_DLL_DECL PrefixLine prefix_line;
|
||||
|
||||
|
||||
#undef MODIFY_SIGNATURE_
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// These are used by template.cc and when registering new modifiers.
|
||||
// (Or more exactly, registering new modifier/value pairs.)
|
||||
// They are not intended for any other users.
|
||||
|
||||
// Does this modifier take an argument? Note we do not have
|
||||
// MODVAL_OPTIONAL: we prefer the clarity of an arg either always
|
||||
// taking an argument, or never (ie, no "default arguments").
|
||||
// MODVAL_UNKNOWN is only for internal use and cannot be used when
|
||||
// registering a new modifier.
|
||||
enum ModvalStatus { MODVAL_FORBIDDEN, MODVAL_REQUIRED, MODVAL_UNKNOWN };
|
||||
|
||||
// TODO(csilvers): collapse this into the TemplateModifier class?
|
||||
struct ModifierInfo {
|
||||
ModifierInfo(std::string ln, char sn, ModvalStatus vs,
|
||||
const TemplateModifier *m)
|
||||
|
||||
// longname should end in an '=' iff the modifier takes a value
|
||||
// (same as in getopt(3)).
|
||||
// To specialize -- add a modifier that applies only when we see the name
|
||||
// with a particular value -- specify longname like so: "longname=value".
|
||||
// (See example in the comment-doc below, for AddModifier.)
|
||||
// sn can be '\0' if there is no associated shortname.
|
||||
// m should be NULL *only if* default-registering a user-defined longname
|
||||
// that the user neglected to register themselves. In this case, we
|
||||
// use the null modifier as the actual modifier.
|
||||
ModifierInfo(std::string ln, char sn, const TemplateModifier *m)
|
||||
: long_name(ln), short_name(sn),
|
||||
value_status(vs), modifier(m) { }
|
||||
modval_required(strchr(ln.c_str(), '=') != NULL),
|
||||
is_registered(m != NULL),
|
||||
modifier(m ? m : &null_modifier) { }
|
||||
std::string long_name;
|
||||
char short_name;
|
||||
ModvalStatus value_status;
|
||||
bool modval_required; // true iff ln has an '=' in it
|
||||
bool is_registered; // true for built-in and AddModifier mods
|
||||
const TemplateModifier* modifier;
|
||||
};
|
||||
|
||||
// Returns whether or not candidate can be safely (w.r.t XSS)
|
||||
// used in lieu of our ModifierInfo. This is true iff:
|
||||
// 1. Both have the same modifier function OR
|
||||
// 2. Candidate's modifier function is in our ModifierInfo's
|
||||
// list (vector) of safe alternative modifier functions.
|
||||
// Note that this function is not commutative therefore
|
||||
// IsSafeXSSAlternative(a, b) may not be equal to IsSafeXSSAlternative(b, a).
|
||||
bool CTEMPLATE_DLL_DECL IsSafeXSSAlternative(const ModifierInfo& our,
|
||||
const ModifierInfo& candidate);
|
||||
|
||||
// Registers a new template modifier.
|
||||
// long_name must start with "x-".
|
||||
extern CTEMPLATE_DLL_DECL bool AddModifier(const char* long_name,
|
||||
ModvalStatus value_status,
|
||||
const TemplateModifier* modifier);
|
||||
// If the modifier takes a value (eg "{{VAR:x-name=value}}"), then
|
||||
// long_name should end with "=". This is similar to getopt(3) syntax.
|
||||
// We also allow value-specializations, with specific values specified
|
||||
// as part of long-name. For instance:
|
||||
// AddModifier("x-mod=", &my_modifierA);
|
||||
// AddModifier("x-mod=bar", &my_modifierB);
|
||||
// AddModifier("x-mod2", &my_modifierC);
|
||||
// For the template
|
||||
// {{VAR1:x-mod=foo}} {{VAR2:x-mod=bar}} {{VAR3:x-mod=baz}} {{VAR4:x-mod2}}
|
||||
// VAR1 and VAR3 would get modified by my_modifierA, VAR2 by my_modifierB,
|
||||
// and VAR4 by my_modifierC. The order of the AddModifier calls is not
|
||||
// significant.
|
||||
extern CTEMPLATE_DLL_DECL bool AddModifier(const char* long_name, const TemplateModifier* modifier);
|
||||
|
||||
// modname is the name of the modifier (shortname or longname).
|
||||
// value is the modifier-value (empty string if there is no modval).
|
||||
// Returns a pointer into g_modifiers, or NULL if not found.
|
||||
extern CTEMPLATE_DLL_DECL const ModifierInfo* FindModifier(const char* modname,
|
||||
size_t modname_len);
|
||||
extern CTEMPLATE_DLL_DECL const ModifierInfo* FindModifier(const char* modname, size_t modname_len,
|
||||
const char* modval, size_t modval_len);
|
||||
|
||||
// This class holds per-expand data which is available to
|
||||
// custom modifiers.
|
||||
|
|
|
@ -54,12 +54,11 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i)
|
||||
// 4244: otherwise we get problems when substracting two size_t's to an int
|
||||
// 4251: it's complaining about a private struct I've chosen not to dllexport
|
||||
// 4715: for some reason VC++ stopped realizing you can't return after abort()
|
||||
// 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
|
||||
#pragma warning(disable:4018 4244 4251 4715 4996)
|
||||
#pragma warning(disable:4244 4251 4715 4996)
|
||||
|
||||
// file I/O
|
||||
#define PATH_MAX 1024
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
OutputFile="$(OutDir)/libctemplate-debug.dll"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/libctemplate.pdb"
|
||||
ProgramDatabaseFile="$(OutDir)/libctemplate-debug.pdb"
|
||||
SubSystem="2"
|
||||
ImportLibrary="$(OutDir)/libctemplate.lib"
|
||||
ImportLibrary="$(OutDir)/libctemplate-debug.lib"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
|
|
Loading…
Reference in New Issue
Block a user