1
0
mirror of https://github.com/OlafvdSpek/ctemplate.git synced 2025-09-28 19:05:49 +08:00

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 hygenie to avoid potential deadlock (csilvers)
This commit is contained in:
csilvers 2007-06-22 00:58:05 +00:00
parent f0a3fceb99
commit cf4599bd94
19 changed files with 436 additions and 262 deletions

View File

@ -51,3 +51,10 @@ Sat Jun 9 22:34:52 2007 Google Inc. <opensource@google.com>
* New modifiers for url-escaping, attribute-cleansing, etc (ribrdb) * New modifiers for url-escaping, attribute-cleansing, etc (ribrdb)
* Annotations now include modifier information (csilvers) * Annotations now include modifier information (csilvers)
* Support embedded NULs in template names and values (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 hygenie to avoid potential deadlock (csilvers)

70
INSTALL
View File

@ -1,16 +1,14 @@
Installation Instructions Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
************************* Foundation, Inc.
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free This file is free documentation; the Free Software Foundation gives
Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it. unlimited permission to copy, distribute and modify it.
Basic Installation Basic Installation
================== ==================
These are generic installation instructions. These are generic installation instructions.
The `configure' shell script attempts to guess correct values for The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses various system-dependent variables used during compilation. It uses
@ -70,9 +68,9 @@ The simplest way to compile this package is:
Compilers and Options Compilers and Options
===================== =====================
Some systems require unusual options for compilation or linking that the Some systems require unusual options for compilation or linking that
`configure' script does not know about. Run `./configure --help' for the `configure' script does not know about. Run `./configure --help'
details on some of the pertinent environment variables. for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here by setting variables in the command line or in the environment. Here
@ -85,7 +83,7 @@ is an example:
Compiling For Multiple Architectures Compiling For Multiple Architectures
==================================== ====================================
You can compile the package for more than one kind of computer at the You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the supports the `VPATH' variable, such as GNU `make'. `cd' to the
@ -102,19 +100,19 @@ for another architecture.
Installation Names Installation Names
================== ==================
By default, `make install' installs the package's commands under By default, `make install' will install the package's files in
`/usr/local/bin', include files under `/usr/local/include', etc. You `/usr/local/bin', `/usr/local/man', etc. You can specify an
can specify an installation prefix other than `/usr/local' by giving installation prefix other than `/usr/local' by giving `configure' the
`configure' the option `--prefix=PREFIX'. option `--prefix=PATH'.
You can specify separate installation prefixes for You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses give `configure' the option `--exec-prefix=PATH', the package will use
PREFIX as the prefix for installing programs and libraries. PATH as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix. Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. you can set and what kinds of files go in them.
@ -125,7 +123,7 @@ option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features Optional Features
================= =================
Some packages pay attention to `--enable-FEATURE' options to Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package. `configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The is something like `gnu-as' or `x' (for the X Window System). The
@ -140,11 +138,11 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type Specifying the System Type
========================== ==========================
There may be some features `configure' cannot figure out automatically, There may be some features `configure' cannot figure out
but needs to determine by the type of machine the package will run on. automatically, but needs to determine by the type of machine the package
Usually, assuming the package is built to be run on the _same_ will run on. Usually, assuming the package is built to be run on the
architectures, `configure' can figure that out, but if it prints a _same_ architectures, `configure' can figure that out, but if it prints
message saying it cannot guess the machine type, give it the a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system `--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form: type, such as `sun4', or a canonical name which has the form:
@ -159,7 +157,7 @@ where SYSTEM can have one of these forms:
need to know the machine type. need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will use the `--target=TYPE' option to select the type of system they will
produce code for. produce code for.
If you want to _use_ a cross compiler, that generates code for a If you want to _use_ a cross compiler, that generates code for a
@ -170,9 +168,9 @@ eventually be run) with `--host=TYPE'.
Sharing Defaults Sharing Defaults
================ ================
If you want to set default values for `configure' scripts to share, you If you want to set default values for `configure' scripts to share,
can create a site shell script called `config.site' that gives default you can create a site shell script called `config.site' that gives
values for variables like `CC', `cache_file', and `prefix'. default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then `configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the `PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script. `CONFIG_SITE' environment variable to the location of the site script.
@ -181,7 +179,7 @@ A warning: not all `configure' scripts look for a site script.
Defining Variables Defining Variables
================== ==================
Variables not defined in a site shell script can be set in the Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set variables may be lost. In order to avoid this problem, you should set
@ -189,18 +187,14 @@ them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc ./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script). Here is a another example: overridden in the site shell script).
/bin/bash ./configure CONFIG_SHELL=/bin/bash
Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
configuration-related scripts to be executed by `/bin/bash'.
`configure' Invocation `configure' Invocation
====================== ======================
`configure' recognizes the following options to control how it operates. `configure' recognizes the following options to control how it
operates.
`--help' `--help'
`-h' `-h'

View File

@ -64,7 +64,7 @@ CTEMPLATE_SYMBOLS = '[^A-Za-z](Template|TemplateDictionary|TemplateNamelist|Temp
lib_LTLIBRARIES += libctemplate.la lib_LTLIBRARIES += libctemplate.la
libctemplate_la_SOURCES = $(googleinclude_HEADERS) src/config.h \ libctemplate_la_SOURCES = $(googleinclude_HEADERS) src/config.h \
src/base/arena.h src/base/arena.cc src/base/mutex.h src/base/mutex.cc \ src/base/arena.h src/base/arena.cc src/base/mutex.h \
src/template.cc src/template_dictionary.cc src/template_modifiers.cc \ src/template.cc src/template_dictionary.cc src/template_modifiers.cc \
src/template_namelist.cc src/template_from_string.cc src/template_namelist.cc src/template_from_string.cc
libctemplate_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG libctemplate_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG

View File

@ -90,7 +90,7 @@ am__DEPENDENCIES_1 =
libctemplate_la_DEPENDENCIES = $(am__DEPENDENCIES_1) libctemplate_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am__objects_1 = am__objects_1 =
am_libctemplate_la_OBJECTS = $(am__objects_1) libctemplate_la-arena.lo \ am_libctemplate_la_OBJECTS = $(am__objects_1) libctemplate_la-arena.lo \
libctemplate_la-mutex.lo libctemplate_la-template.lo \ libctemplate_la-template.lo \
libctemplate_la-template_dictionary.lo \ libctemplate_la-template_dictionary.lo \
libctemplate_la-template_modifiers.lo \ libctemplate_la-template_modifiers.lo \
libctemplate_la-template_namelist.lo \ libctemplate_la-template_namelist.lo \
@ -98,7 +98,6 @@ am_libctemplate_la_OBJECTS = $(am__objects_1) libctemplate_la-arena.lo \
libctemplate_la_OBJECTS = $(am_libctemplate_la_OBJECTS) libctemplate_la_OBJECTS = $(am_libctemplate_la_OBJECTS)
libctemplate_nothreads_la_LIBADD = libctemplate_nothreads_la_LIBADD =
am__objects_2 = $(am__objects_1) libctemplate_nothreads_la-arena.lo \ am__objects_2 = $(am__objects_1) libctemplate_nothreads_la-arena.lo \
libctemplate_nothreads_la-mutex.lo \
libctemplate_nothreads_la-template.lo \ libctemplate_nothreads_la-template.lo \
libctemplate_nothreads_la-template_dictionary.lo \ libctemplate_nothreads_la-template_dictionary.lo \
libctemplate_nothreads_la-template_modifiers.lo \ libctemplate_nothreads_la-template_modifiers.lo \
@ -326,6 +325,7 @@ ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@ ac_ct_STRIP = @ac_ct_STRIP@
ac_cv_cxx_hash_map = @ac_cv_cxx_hash_map@ ac_cv_cxx_hash_map = @ac_cv_cxx_hash_map@
ac_cv_cxx_hash_namespace = @ac_cv_cxx_hash_namespace@ ac_cv_cxx_hash_namespace = @ac_cv_cxx_hash_namespace@
ac_cv_cxx_hash_set = @ac_cv_cxx_hash_set@
ac_google_attribute = @ac_google_attribute@ ac_google_attribute = @ac_google_attribute@
ac_google_end_namespace = @ac_google_end_namespace@ ac_google_end_namespace = @ac_google_end_namespace@
ac_google_namespace = @ac_google_namespace@ ac_google_namespace = @ac_google_namespace@
@ -435,7 +435,7 @@ noinst_SCRIPTS = src/tests/make_tpl_varnames_h_unittest.sh
# These are the symbols (classes, mostly) we want to export from our library # These are the symbols (classes, mostly) we want to export from our library
CTEMPLATE_SYMBOLS = '[^A-Za-z](Template|TemplateDictionary|TemplateNamelist|TemplateFromString|TemplateString|TemplateState|Strip)[^A-Za-z]' CTEMPLATE_SYMBOLS = '[^A-Za-z](Template|TemplateDictionary|TemplateNamelist|TemplateFromString|TemplateString|TemplateState|Strip)[^A-Za-z]'
libctemplate_la_SOURCES = $(googleinclude_HEADERS) src/config.h \ libctemplate_la_SOURCES = $(googleinclude_HEADERS) src/config.h \
src/base/arena.h src/base/arena.cc src/base/mutex.h src/base/mutex.cc \ src/base/arena.h src/base/arena.cc src/base/mutex.h \
src/template.cc src/template_dictionary.cc src/template_modifiers.cc \ src/template.cc src/template_dictionary.cc src/template_modifiers.cc \
src/template_namelist.cc src/template_from_string.cc src/template_namelist.cc src/template_from_string.cc
@ -723,14 +723,12 @@ distclean-compile:
-rm -f *.tab.c -rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-arena.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-mutex.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.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_dictionary.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_dictionary.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_from_string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_from_string.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_la-template_modifiers.Plo@am__quote@ @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_namelist.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-arena.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-mutex.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.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-template_dictionary.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-template_dictionary.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-template_from_string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctemplate_nothreads_la-template_from_string.Plo@am__quote@
@ -779,13 +777,6 @@ libctemplate_la-arena.lo: src/base/arena.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @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_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc
libctemplate_la-mutex.lo: src/base/mutex.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_la-mutex.lo -MD -MP -MF "$(DEPDIR)/libctemplate_la-mutex.Tpo" -c -o libctemplate_la-mutex.lo `test -f 'src/base/mutex.cc' || echo '$(srcdir)/'`src/base/mutex.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_la-mutex.Tpo" "$(DEPDIR)/libctemplate_la-mutex.Plo"; else rm -f "$(DEPDIR)/libctemplate_la-mutex.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/mutex.cc' object='libctemplate_la-mutex.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_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_la-mutex.lo `test -f 'src/base/mutex.cc' || echo '$(srcdir)/'`src/base/mutex.cc
libctemplate_la-template.lo: src/template.cc libctemplate_la-template.lo: src/template.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_la-template.lo -MD -MP -MF "$(DEPDIR)/libctemplate_la-template.Tpo" -c -o libctemplate_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc; \ @am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libctemplate_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_la-template.lo -MD -MP -MF "$(DEPDIR)/libctemplate_la-template.Tpo" -c -o libctemplate_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_la-template.Tpo" "$(DEPDIR)/libctemplate_la-template.Plo"; else rm -f "$(DEPDIR)/libctemplate_la-template.Tpo"; exit 1; fi @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_la-template.Tpo" "$(DEPDIR)/libctemplate_la-template.Plo"; else rm -f "$(DEPDIR)/libctemplate_la-template.Tpo"; exit 1; fi
@ -828,13 +819,6 @@ libctemplate_nothreads_la-arena.lo: src/base/arena.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @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_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_la-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc @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-arena.lo `test -f 'src/base/arena.cc' || echo '$(srcdir)/'`src/base/arena.cc
libctemplate_nothreads_la-mutex.lo: src/base/mutex.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-mutex.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_la-mutex.Tpo" -c -o libctemplate_nothreads_la-mutex.lo `test -f 'src/base/mutex.cc' || echo '$(srcdir)/'`src/base/mutex.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_la-mutex.Tpo" "$(DEPDIR)/libctemplate_nothreads_la-mutex.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_la-mutex.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/mutex.cc' object='libctemplate_nothreads_la-mutex.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_la_CXXFLAGS) $(CXXFLAGS) -c -o libctemplate_nothreads_la-mutex.lo `test -f 'src/base/mutex.cc' || echo '$(srcdir)/'`src/base/mutex.cc
libctemplate_nothreads_la-template.lo: src/template.cc libctemplate_nothreads_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_la_CXXFLAGS) $(CXXFLAGS) -MT libctemplate_nothreads_la-template.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_la-template.Tpo" -c -o libctemplate_nothreads_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.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-template.lo -MD -MP -MF "$(DEPDIR)/libctemplate_nothreads_la-template.Tpo" -c -o libctemplate_nothreads_la-template.lo `test -f 'src/template.cc' || echo '$(srcdir)/'`src/template.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_la-template.Tpo" "$(DEPDIR)/libctemplate_nothreads_la-template.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_la-template.Tpo"; exit 1; fi @am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/libctemplate_nothreads_la-template.Tpo" "$(DEPDIR)/libctemplate_nothreads_la-template.Plo"; else rm -f "$(DEPDIR)/libctemplate_nothreads_la-template.Tpo"; exit 1; fi

24
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59 for ctemplate 0.6. # Generated by GNU Autoconf 2.59 for ctemplate 0.6.1.
# #
# Report bugs to <opensource@google.com>. # Report bugs to <opensource@google.com>.
# #
@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='ctemplate' PACKAGE_NAME='ctemplate'
PACKAGE_TARNAME='ctemplate' PACKAGE_TARNAME='ctemplate'
PACKAGE_VERSION='0.6' PACKAGE_VERSION='0.6.1'
PACKAGE_STRING='ctemplate 0.6' PACKAGE_STRING='ctemplate 0.6.1'
PACKAGE_BUGREPORT='opensource@google.com' PACKAGE_BUGREPORT='opensource@google.com'
ac_unique_file="README" ac_unique_file="README"
@ -465,7 +465,7 @@ ac_includes_default="\
# include <unistd.h> # include <unistd.h>
#endif" #endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS ac_google_namespace ac_google_start_namespace ac_google_end_namespace ac_cv_cxx_hash_namespace ac_cv_cxx_hash_map ac_google_attribute LIBOBJS LTLIBOBJS' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE build build_cpu build_vendor build_os host host_cpu host_vendor host_os EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBTOOL_DEPS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS ac_google_namespace ac_google_start_namespace ac_google_end_namespace ac_cv_cxx_hash_namespace ac_cv_cxx_hash_map ac_cv_cxx_hash_set ac_google_attribute LIBOBJS LTLIBOBJS'
ac_subst_files='' ac_subst_files=''
# Initialize some variables set by options. # Initialize some variables set by options.
@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures ctemplate 0.6 to adapt to many kinds of systems. \`configure' configures ctemplate 0.6.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1020,7 +1020,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of ctemplate 0.6:";; short | recursive ) echo "Configuration of ctemplate 0.6.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1163,7 +1163,7 @@ fi
test -n "$ac_init_help" && exit 0 test -n "$ac_init_help" && exit 0
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
ctemplate configure 0.6 ctemplate configure 0.6.1
generated by GNU Autoconf 2.59 generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc. Copyright (C) 2003 Free Software Foundation, Inc.
@ -1177,7 +1177,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by ctemplate $as_me 0.6, which was It was created by ctemplate $as_me 0.6.1, which was
generated by GNU Autoconf 2.59. Invocation command line was generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@ $ $0 $@
@ -1823,7 +1823,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='ctemplate' PACKAGE='ctemplate'
VERSION='0.6' VERSION='0.6.1'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -20613,6 +20613,7 @@ echo "$as_me: WARNING: could not find an STL hash_map" >&2;}
if test "$ac_cv___attribute__" == "yes"; then if test "$ac_cv___attribute__" == "yes"; then
ac_google_attribute=1 ac_google_attribute=1
@ -21007,7 +21008,7 @@ _ASBOX
} >&5 } >&5
cat >&5 <<_CSEOF cat >&5 <<_CSEOF
This file was extended by ctemplate $as_me 0.6, which was This file was extended by ctemplate $as_me 0.6.1, which was
generated by GNU Autoconf 2.59. Invocation command line was generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -21070,7 +21071,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\ ac_cs_version="\\
ctemplate config.status 0.6 ctemplate config.status 0.6.1
configured by $0, generated by GNU Autoconf 2.59, configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@ -21351,6 +21352,7 @@ s,@ac_google_start_namespace@,$ac_google_start_namespace,;t t
s,@ac_google_end_namespace@,$ac_google_end_namespace,;t t s,@ac_google_end_namespace@,$ac_google_end_namespace,;t t
s,@ac_cv_cxx_hash_namespace@,$ac_cv_cxx_hash_namespace,;t t s,@ac_cv_cxx_hash_namespace@,$ac_cv_cxx_hash_namespace,;t t
s,@ac_cv_cxx_hash_map@,$ac_cv_cxx_hash_map,;t t s,@ac_cv_cxx_hash_map@,$ac_cv_cxx_hash_map,;t t
s,@ac_cv_cxx_hash_set@,$ac_cv_cxx_hash_set,;t t
s,@ac_google_attribute@,$ac_google_attribute,;t t s,@ac_google_attribute@,$ac_google_attribute,;t t
s,@LIBOBJS@,$LIBOBJS,;t t s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t

View File

@ -4,7 +4,7 @@
# make sure we're interpreted by some minimal autoconf # make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT(ctemplate, 0.6, opensource@google.com) AC_INIT(ctemplate, 0.6.1, opensource@google.com)
# The argument here is just something that should be in the current directory # The argument here is just something that should be in the current directory
# (for sanity checking) # (for sanity checking)
AC_CONFIG_SRCDIR(README) AC_CONFIG_SRCDIR(README)
@ -58,6 +58,7 @@ AC_SUBST(ac_google_start_namespace)
AC_SUBST(ac_google_end_namespace) AC_SUBST(ac_google_end_namespace)
AC_SUBST(ac_cv_cxx_hash_namespace) AC_SUBST(ac_cv_cxx_hash_namespace)
AC_SUBST(ac_cv_cxx_hash_map) AC_SUBST(ac_cv_cxx_hash_map)
AC_SUBST(ac_cv_cxx_hash_set)
if test "$ac_cv___attribute__" == "yes"; then if test "$ac_cv___attribute__" == "yes"; then
AC_SUBST(ac_google_attribute, 1) AC_SUBST(ac_google_attribute, 1)
else else

View File

@ -32,6 +32,75 @@
<br> <br>
<h2> Simple Example </h2>
<p>One reason this example is so simple is that it doesn't even
require a separate template file, but instead uses
<code>TemplateFromString</code>. It also doesn't use sections or
template-includes.</p>
<pre class=example>
int main() {
static const char template_text[] =
"ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}: {{ERROR_MESSAGE}}\n";
Template* tpl = TemplateFromString::GetTemplate("error_msg_tpl", template_text,
DO_NOT_STRIP);
FILE* fp = fopen(argv[1], "r");
if (fp == NULL) {
int err_no = errno; // squirrel this away
TemplateDictionary dict("error_msg: fopen()");
dict.SetValue("FUNCTION", "fopen");
dict.SetValue("ARGS", argv[1]);
dict.SetIntValue("ERROR_CODE", err_no);
dict.SetValue("ERROR_MESSAGE", strerror(err_no));
string error_text;
tpl->Expand(&error_text, &dict);
puts(error_text.c_str());
}
}
</pre>
<p>This example is only slightly more complicated: we only print the
": &lt;error message&gt;" part when the error message isn't the empty
string.</p>
<pre class=example>
int main() {
static const char template_text[] =
"ERROR: {{FUNCTION}}({{ARGS}}) returned {{ERROR_CODE}}"
"{{#MSG_SECTION}}: {{ERROR_MESSAGE}}{{/MSG_SECTION}}\n";
Template* tpl = TemplateFromString::GetTemplate("error_msg", template_text,
DO_NOT_STRIP);
FILE* fp = fopen(argv[1], "r");
if (fp == NULL) {
int err_no = errno; // squirrel this away
TemplateDictionary dict("file_error_message");
dict.SetValue("FUNCTION", "fopen");
dict.SetValue("ARGS", argv[1]);
dict.SetIntValue("ERROR_CODE", err_no);
if (err_no > 0)
dict.SetValueAndShowSection("ERROR_MESSAGE", strerror(err_no),
"MSG_SECTION");
string error_text;
tpl->Expand(&error_text, &dict);
puts(error_text.c_str());
}
}
</pre>
<p>This maybe-show-text functionality is one way the template
machinery is more powerful than just using <code>printf</code>.
Another nice property of templates is you can reuse the same variable
multiple times in your template string. You can also define the
variable values in any order.</p>
<h2> Search Results Page </h2> <h2> Search Results Page </h2>
<p>Here is an example template that could be used to format a Google <p>Here is an example template that could be used to format a Google

View File

@ -1,3 +1,8 @@
# NOTE(csilvers): This file (ltmain.sh) is taken from
# http://ftp.gnu.org/gnu/libtool/libtool-1.5.22.tar.gz
# with the following patch applied:
# http://www.marcuscom.com/downloads/patch-ltmain.sh
# ltmain.sh - Provide generalized library-building support services. # ltmain.sh - Provide generalized library-building support services.
# NOTE: Changing this file will not affect anything until you rerun configure. # NOTE: Changing this file will not affect anything until you rerun configure.
# #
@ -43,7 +48,7 @@ EXIT_FAILURE=1
PROGRAM=ltmain.sh PROGRAM=ltmain.sh
PACKAGE=libtool PACKAGE=libtool
VERSION="1.5.22 Debian 1.5.22-2" VERSION=1.5.22
TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)" TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)"
# See if we are running on zsh, and set the options which allow our # See if we are running on zsh, and set the options which allow our
@ -1604,11 +1609,18 @@ EOF
compiler_flags="$compiler_flags $arg" compiler_flags="$compiler_flags $arg"
compile_command="$compile_command $arg" compile_command="$compile_command $arg"
finalize_command="$finalize_command $arg" finalize_command="$finalize_command $arg"
deplibs="$deplibs $arg"
continue continue
;; ;;
-module) -module)
module=yes module=yes
case $host in
*-*-freebsd*)
# Do not build the useless static library
build_old_libs=no
;;
esac
continue continue
;; ;;
@ -2082,10 +2094,7 @@ EOF
case $pass in case $pass in
dlopen) libs="$dlfiles" ;; dlopen) libs="$dlfiles" ;;
dlpreopen) libs="$dlprefiles" ;; dlpreopen) libs="$dlprefiles" ;;
link) link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
libs="$deplibs %DEPLIBS%"
test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
;;
esac esac
fi fi
if test "$pass" = dlopen; then if test "$pass" = dlopen; then
@ -2104,6 +2113,29 @@ EOF
else else
compiler_flags="$compiler_flags $deplib" compiler_flags="$compiler_flags $deplib"
fi fi
case $linkmode in
lib)
deplibs="$deplib $deplibs"
test "$pass" = conv && continue
newdependency_libs="$deplib $newdependency_libs"
;;
prog)
if test "$pass" = conv; then
deplibs="$deplib $deplibs"
continue
fi
if test "$pass" = scan; then
deplibs="$deplib $deplibs"
else
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
fi
;;
*)
;;
esac # linkmode
continue continue
;; ;;
-l*) -l*)
@ -3204,11 +3236,6 @@ EOF
age="$number_minor" age="$number_minor"
revision="$number_minor" revision="$number_minor"
;; ;;
*)
$echo "$modename: unknown library version type \`$version_type'" 1>&2
$echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
exit $EXIT_FAILURE
;;
esac esac
;; ;;
no) no)
@ -4713,6 +4740,9 @@ static const void *lt_preloaded_setup() {
;; ;;
esac esac
;; ;;
*-*-freebsd*)
# FreeBSD doesn't need this...
;;
*) *)
$echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
exit $EXIT_FAILURE exit $EXIT_FAILURE
@ -6003,10 +6033,17 @@ relink_command=\"$relink_command\""
fi fi
# Install the pseudo-library for information purposes. # Install the pseudo-library for information purposes.
name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` case $host in
instname="$dir/$name"i *-*-freebsd*)
$show "$install_prog $instname $destdir/$name" # Do not install the useless pseudo-library
$run eval "$install_prog $instname $destdir/$name" || exit $? ;;
*)
name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
instname="$dir/$name"i
$show "$install_prog $instname $destdir/$name"
$run eval "$install_prog $instname $destdir/$name" || exit $?
;;
esac
# Maybe install the static library, too. # Maybe install the static library, too.
test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"

View File

@ -1,3 +1,9 @@
ctemplate (0.6.1-1) unstable; urgency=low
* New upstream release.
-- Google Inc. <opensource@google.com> Thu, 21 Jun 2007 14:02:32 -0700
ctemplate (0.6-1) unstable; urgency=low ctemplate (0.6-1) unstable; urgency=low
* New upstream release. * New upstream release.

View File

@ -1,79 +0,0 @@
/* Copyright (c) 2007, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ---
* Author: Craig Silverstein
*
* A simple mutex wrapper. Right now, it's implemented in terms of
* pthreads, but is meant to be easy to extend to other threads impls.
*/
#include "config.h"
#include "mutex.h"
#if defined(NO_THREADS)
Mutex::Mutex() {}
Mutex::~Mutex() {}
void Mutex::Lock() {}
void Mutex::Unlock() {}
void Mutex::ReaderLock() {}
void Mutex::ReaderUnlock() {}
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#include <stdlib.h> // for abort()
#include <pthread.h>
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
#elif defined(HAVE_PTHREAD)
#include <stdlib.h> // for abort()
#include <pthread.h>
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
Mutex::Mutex() { SAFE_PTHREAD(pthread_mutex_init(&mutex_, NULL)); }
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy(&mutex_)); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock(&mutex_)); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&mutex_)); }
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#else
#error Need to implement mutex.h/cc for your architecture, or #define NO_THREADS
#endif

View File

@ -45,21 +45,25 @@
#ifndef GOOGLE_MUTEX_H__ #ifndef GOOGLE_MUTEX_H__
#define GOOGLE_MUTEX_H__ #define GOOGLE_MUTEX_H__
#include "config.h" // to figure out pthreads support #include "config.h" // to figure out pthreads support
#if defined(NO_THREADS) #if defined(NO_THREADS)
typedef int MutexType; // some dummy type; it won't be used typedef int MutexType; // some dummy type; it won't be used
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
// Needed for pthread_rwlock_*. If it causes problems, you could take // Needed for pthread_rwlock_*. If it causes problems, you could take
// it out, but then you'd have to unset HAVE_RWLOCK (at least on linux). // it out, but then you'd have to unset HAVE_RWLOCK (at least on linux).
# define _XOPEN_SOURCE 500 // needed to get the rwlock calls # define _XOPEN_SOURCE 500 // needed to get the rwlock calls
# include <pthread.h> # include <pthread.h>
typedef pthread_rwlock_t MutexType; typedef pthread_rwlock_t MutexType;
#elif defined(HAVE_PTHREAD) #elif defined(HAVE_PTHREAD)
# include <pthread.h> # include <pthread.h>
typedef pthread_mutex_t MutexType; typedef pthread_mutex_t MutexType;
#elif defined(WIN32)
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#else #else
# error Need to implement mutex.h/cc for your architecture, or #define NO_THREADS # error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif #endif
class Mutex { class Mutex {
@ -68,22 +72,22 @@ class Mutex {
// typically used for Mutexes allocated on the heap or the stack. // typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex // See below for a recommendation for constructing global Mutex
// objects. // objects.
Mutex(); inline Mutex();
// Destructor // Destructor
~Mutex(); inline ~Mutex();
void Lock(); // Block if necessary until free, then acquire exclusively inline void Lock(); // Block if needed until free then acquire exclusively
void Unlock(); // Release. Caller must hold it exclusively (via Lock()) inline void Unlock(); // Release a lock acquired via Lock()
// Note that on systems that don't support read-write locks, these may // Note that on systems that don't support read-write locks, these may
// be implemented as synonyms to Lock() and Unlock(). So you can use // be implemented as synonyms to Lock() and Unlock(). So you can use
// these for efficiency, but don't use them anyplace where being able // these for efficiency, but don't use them anyplace where being able
// to do shared reads is necessary to avoid deadlock. // to do shared reads is necessary to avoid deadlock.
void ReaderLock(); // Block until free or shared, then acquire a share inline void ReaderLock(); // Block until free or shared then acquire a share
void ReaderUnlock(); // Release a read share of this Mutex inline void ReaderUnlock(); // Release a read share of this Mutex
void WriterLock() { Lock(); } // Block until free, then acquire exclusively inline void WriterLock() { Lock(); } // Acquire an exclusive lock
void WriterUnlock() { Unlock(); } // Release the exclusive lock of this Mutex inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
private: private:
MutexType mutex_; MutexType mutex_;
@ -95,6 +99,56 @@ class Mutex {
void operator=(const Mutex&); void operator=(const Mutex&);
}; };
// Now the implementation of Mutex for various systems
#if defined(NO_THREADS)
Mutex::Mutex() {}
Mutex::~Mutex() {}
void Mutex::Lock() {}
void Mutex::Unlock() {}
void Mutex::ReaderLock() {}
void Mutex::ReaderUnlock() {}
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#include <stdlib.h> // for abort()
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
Mutex::Mutex() { SAFE_PTHREAD(pthread_rwlock_init(&mutex_, NULL)); }
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy(&mutex_)); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock(&mutex_)); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock(&mutex_)); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&mutex_)); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#include <stdlib.h> // for abort()
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
Mutex::Mutex() { SAFE_PTHREAD(pthread_mutex_init(&mutex_, NULL)); }
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy(&mutex_)); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock(&mutex_)); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&mutex_)); }
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
#elif defined(WIN32)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { LeaveCriticalSection(&mutex_); }
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#endif
// --------------------------------------------------------------------------
// Some helper classes
// MutexLock(mu) acquires mu when constructed and releases it when destroyed. // MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class MutexLock { class MutexLock {

View File

@ -201,6 +201,10 @@ class Template {
const TemplateDictionary *dictionary, const TemplateDictionary *dictionary,
const TemplateDictionary *force_annotate_dict) const; const TemplateDictionary *force_annotate_dict) const;
// Internal version of ReloadIfChanged, used when the function already
// has a write-lock on mutex_.
bool ReloadIfChangedLocked();
// set_state // set_state
// Sets the state of the template. Used during BuildTree(). // Sets the state of the template. Used during BuildTree().
void set_state(TemplateState new_state); void set_state(TemplateState new_state);

View File

@ -67,28 +67,32 @@ class TemplateFromString : public Template {
/* GetTemplate /* GetTemplate
Parameters: Parameters:
(NOTE: The parameter list is not the same as Template::GetTemplate.) (NOTE: The parameter list is not the same as Template::GetTemplate.)
template_name - a logical name for the template text cache_key - the cache string used for the template text.
template_text - the text of the template containing the template template_text - the text of the template containing the template
code with markers, the very same language that code with markers, the very same language that
would be stored in a file for the parent class would be stored in a file for the parent class
strip - same as the parent class strip - same as the parent class
Description: Description:
Attempts to find an instance of the class with the given template_name Attempts to find an instance of the class with the given cache_key
stored in the cache. If it finds one, it returns it, ignoring the stored in the cache. If it finds one, it returns it, ignoring the
template_text passed to the method. template_text passed to the method.
If it does not find one, it creates a new instance of the class, If it does not find one, it creates a new instance of the class,
stores it in the cache under the template_name, and returns it. stores it in the cache under the template_name, and returns it.
Note: since cache lookup is by name, you can't have two instances Note: since cache lookup is by key, you can't have two instances
with the same name but different text, and expect it to work. with the same key but different text, and expect it to work.
However, if cache_key is the empty string, we ignore the cache,
and always create a new instance of the class (without storing it
in the cache). In this case *only*, you're responsible for
deleting the returned TemplateFromString object when done with it.
*/ */
static TemplateFromString *GetTemplate(const std::string& template_name, static TemplateFromString *GetTemplate(const std::string& cache_key,
const std::string& template_text, const std::string& template_text,
Strip strip); Strip strip);
private: private:
/* This templates constuctor is private just like the parent's is. /* This templates constuctor is private just like the parent's is.
New ones are acquired through TemplateFromString::GetTemplate */ New ones are acquired through TemplateFromString::GetTemplate */
TemplateFromString(const std::string& template_name, TemplateFromString(const std::string& cache_key,
const std::string& template_text, const std::string& template_text,
Strip strip); Strip strip);

View File

@ -46,7 +46,9 @@
#include "config.h" #include "config.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif
#include <stdarg.h> #include <stdarg.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h> #include <errno.h>

View File

@ -40,7 +40,9 @@
#include <time.h> #include <time.h>
#include <ctype.h> // for isspace() #include <ctype.h> // for isspace()
#include <sys/stat.h> #include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> // for stat() and open() and getcwd() #include <unistd.h> // for stat() and open() and getcwd()
#endif
#include <string.h> #include <string.h>
#include <iostream> // for logging #include <iostream> // for logging
#include <iomanip> // for indenting in Dump() #include <iomanip> // for indenting in Dump()
@ -78,6 +80,9 @@ namespace {
// Mutexes protecting the globals below. First protects g_use_current_dict // Mutexes protecting the globals below. First protects g_use_current_dict
// and template_root_directory_, second protects g_template_cache. // and template_root_directory_, second protects g_template_cache.
// Third protects vars_seen in WriteOneHeaderEntry, below. // Third protects vars_seen in WriteOneHeaderEntry, below.
// Lock priority invariant: you should never acquire a Template::mutex_
// while holding one of these mutexes.
// TODO(csilvers): assert this in the codebase.
static Mutex g_static_mutex; static Mutex g_static_mutex;
static Mutex g_cache_mutex; static Mutex g_cache_mutex;
static Mutex g_header_mutex; static Mutex g_header_mutex;
@ -267,24 +272,28 @@ struct TemplateToken {
static void EmitModifiedString(const ModifierAndNonces& modifiers, static void EmitModifiedString(const ModifierAndNonces& modifiers,
const char* in, int inlen, const char* in, int inlen,
ExpandEmitter* outbuf) { ExpandEmitter* outbuf) {
// If there's more than one modifiers, we need to store the string result;
// intermediate results in a temp-buffer. We use a string.
string scratch;
if (modifiers.size() > 1) { if (modifiers.size() > 1) {
// We'll assume that each modifier adds about 12% to the input size. We // If there's more than one modifiers, we need to store the
// should exponentiate by |modifiers| but we just multiply, to save time. // intermediate results in a temp-buffer. We use a string.
scratch.reserve((inlen + inlen/8) * (modifiers.size()-1) + 16); // We'll assume that each modifier adds about 12% to the input
StringEmitter scratchbuf(&scratch); // size.
// Each time through, we append the latest version of the string to result.reserve((inlen + inlen/8) + 16);
// scratch, and keep a pointer pointing to the most recent version. StringEmitter scratchbuf(&result);
// Except for (rare!) vars with 3+ modifiers, this loop at most once. modifiers.front().first->Modify(in, inlen, &scratchbuf,
for (ModifierAndNonces::const_iterator it = modifiers.begin(); modifiers.front().second);
// Only used when modifiers.size() > 2
for (ModifierAndNonces::const_iterator it = modifiers.begin()+1;
it != modifiers.end()-1; ++it) { it != modifiers.end()-1; ++it) {
const int startpos = scratch.size(); // where we start appendend string output_of_this_modifier;
it->first->Modify(in, inlen, &scratchbuf, it->second); output_of_this_modifier.reserve(result.size() + result.size()/8 + 16);
in = scratch.data() + startpos; // point to the new "in" StringEmitter scratchbuf2(&output_of_this_modifier);
inlen = scratch.size() - startpos; it->first->Modify(result.c_str(), result.size(),
&scratchbuf2, it->second);
result.swap(output_of_this_modifier);
} }
in = result.data();
inlen = result.size();
} }
// For the last modifier, we can write directly into outbuf // For the last modifier, we can write directly into outbuf
assert(!modifiers.empty()); assert(!modifiers.empty());
@ -626,6 +635,8 @@ class SectionTemplateNode : public TemplateNode {
// section, or template to the list of nodes contained in this // section, or template to the list of nodes contained in this
// section. Returns true iff we really added a node and didn't just // section. Returns true iff we really added a node and didn't just
// end a section or hit a syntax error in the template file. // end a section or hit a syntax error in the template file.
// You should hold a write-lock on my_template->mutex_ when calling this.
// (unless you're calling it from a constructor).
bool AddSubnode(Template *my_template); bool AddSubnode(Template *my_template);
// Expands a section node as follows: // Expands a section node as follows:
@ -932,6 +943,8 @@ string *Template::template_root_directory_ = NULL;
// inappropriate characters in a name, not finding the closing curly // inappropriate characters in a name, not finding the closing curly
// braces, etc.) an error message is logged, the error state of the // braces, etc.) an error message is logged, the error state of the
// template is set, and a NULL token is returned. Updates parse_state_. // template is set, and a NULL token is returned. Updates parse_state_.
// You should hold a write-lock on my_template->mutex_ when calling this
// (unless you're calling it from a constructor).
TemplateToken SectionTemplateNode::GetNextToken(Template *my_template) { TemplateToken SectionTemplateNode::GetNextToken(Template *my_template) {
Template::ParseState* ps = &my_template->parse_state_; // short abbrev. Template::ParseState* ps = &my_template->parse_state_; // short abbrev.
const char* token_start = ps->bufstart; const char* token_start = ps->bufstart;
@ -1120,9 +1133,11 @@ TemplateToken SectionTemplateNode::GetNextToken(Template *my_template) {
// Template::~Template() // Template::~Template()
// Template::AssureGlobalsInitialized() // Template::AssureGlobalsInitialized()
// Template::GetTemplate() // Template::GetTemplate()
// Calls ReloadIfChanged to load the template the first time. // Calls ReloadIfChanged to load the template the first time. The
// The constructor is private; GetTemplate() is the factory // constructor is private; GetTemplate() is the factory method
// method used to actually construct a new template if needed. // used to actually construct a new template if needed -- it's the
// only thing that calls the template constructor -- and where we
// actually call ReloadIfChanged() (based on state_ == TS_EMPTY).
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Template::Template(const string& filename, Strip strip) Template::Template(const string& filename, Strip strip)
@ -1134,10 +1149,7 @@ Template::Template(const string& filename, Strip strip)
// of calling Expand() or other Template classes that access globals. // of calling Expand() or other Template classes that access globals.
AssureGlobalsInitialized(); AssureGlobalsInitialized();
// phase_ indicates what type of thing we expect next during tokenization. VLOG(2) << "Constructing Template for " << template_file();
// We start off expecting text, hence the initial value is GETTING_TEXT
VLOG(2) << endl << "Constructing Template for " << template_file() << endl;
// Preserve whitespace in Javascript files because carriage returns // Preserve whitespace in Javascript files because carriage returns
// can convey meaning for comment termination and closures // can convey meaning for comment termination and closures
@ -1145,8 +1157,6 @@ Template::Template(const string& filename, Strip strip)
!strcmp(filename.c_str() + filename.length() - 3, ".js") ) { !strcmp(filename.c_str() + filename.length() - 3, ".js") ) {
strip = STRIP_BLANK_LINES; strip = STRIP_BLANK_LINES;
} }
ReloadIfChanged();
} }
Template::~Template() { Template::~Template() {
@ -1173,26 +1183,33 @@ Template *Template::GetTemplate(const string& filename, Strip strip) {
// No need to have the cache-mutex acquired for this step // No need to have the cache-mutex acquired for this step
string abspath(PathJoin(template_root_directory(), filename)); string abspath(PathJoin(template_root_directory(), filename));
MutexLock ml(&g_cache_mutex); Template* tpl = NULL;
if (g_template_cache == NULL) {
g_template_cache = new TemplateCache; MutexLock ml(&g_cache_mutex);
if (g_template_cache == NULL)
g_template_cache = new TemplateCache;
Template *tpl = (*g_template_cache)[pair<string, Strip>(abspath, strip)]; tpl = (*g_template_cache)[pair<string, Strip>(abspath, strip)];
if (tpl) { if (!tpl) {
// Note: if the status is TS_ERROR here, we don't attempt tpl = new Template(abspath, strip);
// to reload the template file, but we don't return (*g_template_cache)[pair<string, Strip>(abspath, strip)] = tpl;
// the template object either
if (tpl->state() == TS_RELOAD) {
tpl->ReloadIfChanged();
} }
} else {
tpl = new Template(abspath, strip);
(*g_template_cache)[pair<string, Strip>(abspath, strip)] = tpl;
} }
// if the statis is not TS_READY, then it is TS_ERROR at this // Even though we only read state() here, not write it, we acquire
// point. If it is TS_ERROR, we leave the state as is, but return // the lock in write-mode in case we have to call ReloadIfChanged.
// NULL. We won't try to load the template file again until the WriterMutexLock ml(tpl->mutex_);
// Note: if the status is TS_ERROR here, we don't attempt to reload
// the template file, but we don't return the template object
// either. If the state is TS_EMPTY, it means tpl was just constructed
// and doesn't have *any* content yet, so we should certainly reload.
if (tpl->state() == TS_RELOAD || tpl->state() == TS_EMPTY) {
tpl->ReloadIfChangedLocked();
}
// If the state is TS_ERROR, we leave the state as is, but return
// NULL. We won't try to load the template file again until the
// state gets changed to TS_RELOAD by another call to // state gets changed to TS_RELOAD by another call to
// ReloadAllIfChanged. // ReloadAllIfChanged.
if (tpl->state() != TS_READY) { if (tpl->state() != TS_READY) {
@ -1214,6 +1231,8 @@ Template *Template::GetTemplate(const string& filename, Strip strip) {
// NOTE: BuildTree takes over ownership of input_buffer, and will delete it. // NOTE: BuildTree takes over ownership of input_buffer, and will delete it.
// It should have been created via new[]. // It should have been created via new[].
// You should hold a write-lock on mutex_ before calling this
// (unless you're calling it from a constructor).
bool Template::BuildTree(const char* input_buffer, bool Template::BuildTree(const char* input_buffer,
const char* input_buffer_end) { const char* input_buffer_end) {
// Assign an arbitrary name to the top-level node // Assign an arbitrary name to the top-level node
@ -1331,6 +1350,7 @@ const char *Template::template_file() const {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Template::ReloadIfChanged() // Template::ReloadIfChanged()
// Template::ReloadIfChangedLocked()
// Template::ReloadAllIfChanged() // Template::ReloadAllIfChanged()
// If one template, try immediately to reload it from disk. If // If one template, try immediately to reload it from disk. If
// all templates, just set all their statuses to TS_RELOAD, so // all templates, just set all their statuses to TS_RELOAD, so
@ -1341,15 +1361,9 @@ const char *Template::template_file() const {
// and parsed it. It never returns true if filename_ is "". // and parsed it. It never returns true if filename_ is "".
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
bool Template::ReloadIfChanged() { bool Template::ReloadIfChangedLocked() {
if (filename_.empty()) return false; if (filename_.empty()) return false;
// This entire routine is protected by mutex_ so when it's called
// from different threads, they don't stomp on tree_ and state_.
// This is still not perfect, since set_filename() could stomp
// on filename_ while we're reading it, but it's good enough.
WriterMutexLock ml(mutex_);
struct stat statbuf; struct stat statbuf;
if (stat(filename_.c_str(), &statbuf) != 0) { if (stat(filename_.c_str(), &statbuf) != 0) {
LOG(WARNING) << "Unable to stat file " << filename_ << endl; LOG(WARNING) << "Unable to stat file " << filename_ << endl;
@ -1403,35 +1417,62 @@ bool Template::ReloadIfChanged() {
} }
} }
bool Template::ReloadIfChanged() {
// ReloadIfChanged() is protected by mutex_ so when it's called from
// different threads, they don't stomp on tree_ and state_.
WriterMutexLock ml(mutex_);
return ReloadIfChangedLocked();
}
void Template::ReloadAllIfChanged() { void Template::ReloadAllIfChanged() {
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache // This is slightly annoying: we copy all the template-pointers to
if (g_template_cache == NULL) { // a vector, so we don't have to hold g_cache_mutex while messing
return; // with the templates (which would violate our lock invariant).
vector<Template*> templates_in_cache;
{
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache
if (g_template_cache == NULL) {
return;
}
for (TemplateCache::const_iterator iter = g_template_cache->begin();
iter != g_template_cache->end();
++iter) {
templates_in_cache.push_back(iter->second);
}
} }
for (TemplateCache::const_iterator iter = g_template_cache->begin(); for (vector<Template*>::iterator iter = templates_in_cache.begin();
iter != g_template_cache->end(); iter != templates_in_cache.end();
++iter) { ++iter) {
(*iter).second->set_state(TS_RELOAD); WriterMutexLock ml((*iter)->mutex_);
(*iter)->set_state(TS_RELOAD);
} }
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Template::ClearCache() // Template::ClearCache()
// Deletes all the objects in the template cache // Deletes all the objects in the template cache. Note: it's
// dangerous to clear the cache if other threads are still
// referencing the templates that are stored in it!
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
void Template::ClearCache() { void Template::ClearCache() {
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache // We clear the cache by swapping it with an empty cache. This lets
if (g_template_cache == NULL) { // us delete the items in the cache at our leisure without needing
return; // to hold g_cache_mutex.
TemplateCache tmp_cache;
{
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache
if (g_template_cache == NULL) {
return;
}
g_template_cache->swap(tmp_cache); // now g_template_cache is empty
} }
for (TemplateCache::const_iterator iter = g_template_cache->begin(); // Now delete everything we've removed from the cache.
iter != g_template_cache->end(); for (TemplateCache::const_iterator iter = tmp_cache.begin();
iter != tmp_cache.end();
++iter) { ++iter) {
delete (*iter).second; delete iter->second;
} }
delete g_template_cache;
g_template_cache = NULL;
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View File

@ -41,6 +41,9 @@
_START_GOOGLE_NAMESPACE_ _START_GOOGLE_NAMESPACE_
// Lock priority invariant: you should never acquire a
// TemplateFromString::mutex_ while holding this mutex.
// TODO(csilvers): assert this in the codebase.
static Mutex g_cache_mutex; static Mutex g_cache_mutex;
using std::string; using std::string;
@ -53,11 +56,11 @@ using HASH_NAMESPACE::hash_map;
// the template text is taken from the second parameter. After that, the // the template text is taken from the second parameter. After that, the
// object is identical to a Template object, except that it cannot be // object is identical to a Template object, except that it cannot be
// "reloaded." // "reloaded."
TemplateFromString::TemplateFromString(const string& template_name, TemplateFromString::TemplateFromString(const string& cache_key,
const string& template_text, const string& template_text,
Strip strip) Strip strip)
: Template("", strip) { : Template("", strip) {
filename_ = template_name; // for cache and reporting purposes only filename_ = cache_key; // for cache and reporting purposes only
// We know that InsertFile never writes more output than it gets input. // We know that InsertFile never writes more output than it gets input.
// While we allocate buffer here, BuildTree takes ownership and deletes it. // While we allocate buffer here, BuildTree takes ownership and deletes it.
@ -94,27 +97,30 @@ static TemplateFromStringCache *g_template_from_string_cache = NULL;
// TemplateFromString::GetTemplate // TemplateFromString::GetTemplate
// Makes sure the template cache has been created and then tries to // Makes sure the template cache has been created and then tries to
// retrieve a TemplateFromString object from it via the template_name. // retrieve a TemplateFromString object from it via the cache_key.
TemplateFromString *TemplateFromString::GetTemplate(const string& template_name, TemplateFromString *TemplateFromString::GetTemplate(const string& cache_key,
const string& template_text, const string& template_text,
Strip strip) { Strip strip) {
// Only perform this method when you have the lock so multiple threads TemplateFromString *tpl = NULL;
// don't conflict over inserting and retrieving into the cache if (cache_key.empty()) { // user doesn't want to use the cache
MutexLock ml(&g_cache_mutex); tpl = new TemplateFromString(cache_key, template_text, strip);
if (g_template_from_string_cache == NULL) { } else {
g_template_from_string_cache = new TemplateFromStringCache; MutexLock ml(&g_cache_mutex);
if (g_template_from_string_cache == NULL) {
g_template_from_string_cache = new TemplateFromStringCache;
}
// If the object isn't really a TemplateFromString this will be a cache miss
tpl = (*g_template_from_string_cache)[pair<string,Strip>(cache_key, strip)];
// If we didn't find one, then create one and store it in the cache
if (!tpl) {
tpl = new TemplateFromString(cache_key, template_text, strip);
(*g_template_from_string_cache)[pair<string, Strip>(cache_key, strip)] =
tpl;
}
} }
// If the object isn't really a TemplateFromString, this will be a cache miss WriterMutexLock ml(tpl->mutex_); // to access state()
TemplateFromString *tpl =
(*g_template_from_string_cache)[pair<string, Strip>(template_name, strip)];
// If we didn't find one, then create one and store it in the cache
if (!tpl) {
tpl = new TemplateFromString(template_name, template_text, strip);
(*g_template_from_string_cache)[pair<string, Strip>(template_name, strip)] =
tpl;
}
// state_ can be TS_RELOAD if ReloadAllIfChanged() touched this file. // state_ can be TS_RELOAD if ReloadAllIfChanged() touched this file.
// That's fine; we'll just ignore the reload directive for this guy. // That's fine; we'll just ignore the reload directive for this guy.

View File

@ -33,7 +33,9 @@
#include "config.h" #include "config.h"
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> // for access() #include <unistd.h> // for access()
#endif
#include <time.h> // for time_t #include <time.h> // for time_t
#include <sys/stat.h> // for stat() #include <sys/stat.h> // for stat()
#include <string> #include <string>

View File

@ -39,13 +39,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif
#include <assert.h> #include <assert.h>
#include <vector> #include <vector>
#include <string> #include <string>
#include <algorithm> // for sort #include <algorithm> // for sort
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h> // for readdir #include <dirent.h> // for readdir
#endif
#include <google/template_from_string.h> #include <google/template_from_string.h>
#include <google/template_dictionary.h> #include <google/template_dictionary.h>
@ -133,6 +137,8 @@ class TemplateFromStringUnittest {
} }
static void TestGetTemplate() { static void TestGetTemplate() {
TemplateDictionary dict("dict");
// Tests the cache // Tests the cache
const char* const tpltext = "{This is perfectly valid} yay!"; const char* const tpltext = "{This is perfectly valid} yay!";
const char* const tpltext2 = "This will be ignored"; const char* const tpltext2 = "This will be ignored";
@ -148,6 +154,22 @@ class TemplateFromStringUnittest {
ASSERT(tpl1 == tpl2); ASSERT(tpl1 == tpl2);
ASSERT(tpl3 == tpl4); ASSERT(tpl3 == tpl4);
ASSERT(tpl1 != tpl3); ASSERT(tpl1 != tpl3);
AssertExpandIs(tpl1, &dict, tpltext);
AssertExpandIs(tpl2, &dict, tpltext);
AssertExpandIs(tpl3, &dict, tpltext);
AssertExpandIs(tpl4, &dict, tpltext);
// Tests our mechanism for ignoring the cache (first arg is empty-string)
Template* tpl1b = TemplateFromString::GetTemplate(
"", tpltext, DO_NOT_STRIP);
Template* tpl2b = TemplateFromString::GetTemplate(
"", tpltext2, DO_NOT_STRIP);
ASSERT(tpl1b != tpl2b);
AssertExpandIs(tpl1b, &dict, tpltext);
AssertExpandIs(tpl2b, &dict, tpltext2);
// When you don't cache the template, you have to delete it!
delete tpl1b;
delete tpl2b;
// Tests that syntax errors cause us to return NULL // Tests that syntax errors cause us to return NULL
Template* tpl5 = StringToTemplate("{{This has spaces in it}}", DO_NOT_STRIP); Template* tpl5 = StringToTemplate("{{This has spaces in it}}", DO_NOT_STRIP);

View File

@ -289,6 +289,24 @@ class TemplateUnittest {
// Check we don't allow modifiers on sections // Check we don't allow modifiers on sections
tpl = StringToTemplate("hi {{#VAR:h}} lo {{/VAR}}", STRIP_WHITESPACE); tpl = StringToTemplate("hi {{#VAR:h}} lo {{/VAR}}", STRIP_WHITESPACE);
ASSERT(tpl == NULL); ASSERT(tpl == NULL);
// Test when expanded grows by more than 12% per modifier.
dict.SetValue("VAR", "http://a.com?b=c&d=e&f=g&q=a>b");
tpl = StringToTemplate("{{VAR:u:j:h}}",
STRIP_WHITESPACE);
AssertExpandIs(tpl, &dict,
"http%3A//a.com%3Fb%3Dc%26d%3De%26f%3Dg%26q%3Da%3Eb",
true);
// As above with 4 modifiers.
dict.SetValue("VAR", "http://a.com?b=c&d=e&f=g&q=a>b");
tpl = StringToTemplate("{{VAR:u:j:h:h}}",
STRIP_WHITESPACE);
AssertExpandIs(tpl, &dict,
"http%3A//a.com%3Fb%3Dc%26d%3De%26f%3Dg%26q%3Da%3Eb",
true);
} }
static void TestSection() { static void TestSection() {