1
0
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:
csilvers 2008-01-25 20:27:55 +00:00
parent bb570c29d4
commit 896bd2ef9c
28 changed files with 1203 additions and 602 deletions

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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'`\\"

View File

@ -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)

View File

@ -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>&amp;</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>
&lt;html>&lt;body>&lt;pre>{{BODY:H=pre}}&lt/pre>&lt;/body>&lt;/html>
&lt;html>&lt;body>&lt;pre>{{BODY:H=pre}}&lt;/pre>&lt;/body>&lt;/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>&lt;template_modifiers.h&gt;</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>&lt;template_modifiers.h&gt;</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&amp; 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>&lt;</code>, <code>&gt;</code>, <code>&amp;</code>, and
<code>&quot;</code> with the appropriate html entity;
<code>xml_escape</code>, which deals with the
<code>&amp;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>&lt;google/template_modifiers.h&gt;<code> for more details.</p>
<code>&lt;google/template_modifiers.h&gt;</code> for more details.</p>
<h3> <A name="expand">Expanding a Template</A> </h3>

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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)

View File

@ -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_;

View File

@ -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.

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}
// ----------------------------------------------------------------------

View File

@ -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(" (");

View File

@ -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 {

View File

@ -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("&amp;"); break;
case '"': APPEND("&quot;"); 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("&amp;"); break;
case '"': APPEND("&quot;"); 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 {

View File

@ -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;

View File

@ -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]));
}

View File

@ -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&amp;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 &amp; print file inc2 yo&amp;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(),

View File

@ -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>

View File

@ -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 &amp; tuesday{{/VAR}}
{{#VAR=UPDATE:html_escape}}monday &amp;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__}}&lt;html&gt; &lt;head&gt; {{#VAR=HEAD}}{{/VAR}} &lt;/head&gt; &lt;body&gt; {{#VAR=BODY}}{{/VAR}} &lt;/body&gt; &lt;/html&gt;{{#VAR=BI_NEWLINE}} {{/VAR}}{{/SEC}}{{/FILE}}{{/INC}}</body>
{{#INC=SIMPLE:html_escape}}{{#FILE=template_unittest_test_simple.in}}{{#SEC=__{{MAIN}}__}}&lt;html&gt; &lt;head&gt; {{#VAR=HEAD}}{{/VAR}} &lt;/head&gt; &lt;body&gt; {{#VAR=BODY}}{{/VAR}} &lt;/body&gt; &lt;/html&gt;{{#VAR=BI_NEWLINE}} {{/VAR}}{{/SEC}}{{/FILE}}{{/INC}}</body>
</html>{{#VAR=BI_NEWLINE}}
{{/VAR}}{{/SEC}}{{/FILE}}

View 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_;

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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"/>