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)
* 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 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
Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
@ -70,9 +68,9 @@ The simplest way to compile this package is:
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that the
`configure' script does not know about. Run `./configure --help' for
details on some of the pertinent environment variables.
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
@ -85,7 +83,7 @@ is an example:
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
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
@ -102,19 +100,19 @@ for another architecture.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX'.
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
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
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
=================
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.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
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
==========================
There may be some features `configure' cannot figure out automatically,
but needs to determine by the type of machine the package will run on.
Usually, assuming the package is built to be run on the _same_
architectures, `configure' can figure that out, but if it prints a
message saying it cannot guess the machine type, give it the
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
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
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.
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.
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
================
If you want to set default values for `configure' scripts to share, you
can create a site shell script called `config.site' that gives default
values for variables like `CC', `cache_file', and `prefix'.
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`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
==================
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
configure again during the build, and the customized values of these
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
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script). Here is a another example:
/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'.
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it operates.
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'

View File

@ -64,7 +64,7 @@ CTEMPLATE_SYMBOLS = '[^A-Za-z](Template|TemplateDictionary|TemplateNamelist|Temp
lib_LTLIBRARIES += libctemplate.la
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_namelist.cc src/template_from_string.cc
libctemplate_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG

View File

@ -90,7 +90,7 @@ am__DEPENDENCIES_1 =
libctemplate_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am__objects_1 =
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_modifiers.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_nothreads_la_LIBADD =
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_dictionary.lo \
libctemplate_nothreads_la-template_modifiers.lo \
@ -326,6 +325,7 @@ ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
ac_cv_cxx_hash_map = @ac_cv_cxx_hash_map@
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_end_namespace = @ac_google_end_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
CTEMPLATE_SYMBOLS = '[^A-Za-z](Template|TemplateDictionary|TemplateNamelist|TemplateFromString|TemplateString|TemplateState|Strip)[^A-Za-z]'
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_namelist.cc src/template_from_string.cc
@ -723,14 +723,12 @@ distclean-compile:
-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-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_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_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_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_dictionary.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@
@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
@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
@ -828,13 +819,6 @@ libctemplate_nothreads_la-arena.lo: src/base/arena.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-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
@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

24
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.6.
# Generated by GNU Autoconf 2.59 for ctemplate 0.6.1.
#
# 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.6'
PACKAGE_STRING='ctemplate 0.6'
PACKAGE_VERSION='0.6.1'
PACKAGE_STRING='ctemplate 0.6.1'
PACKAGE_BUGREPORT='opensource@google.com'
ac_unique_file="README"
@ -465,7 +465,7 @@ ac_includes_default="\
# include <unistd.h>
#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=''
# 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.
# This message is too long to be a string in the A/UX 3.1 sh.
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]...
@ -1020,7 +1020,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of ctemplate 0.6:";;
short | recursive ) echo "Configuration of ctemplate 0.6.1:";;
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.6
ctemplate configure 0.6.1
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.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
$ $0 $@
@ -1823,7 +1823,7 @@ fi
# Define the identity of the package.
PACKAGE='ctemplate'
VERSION='0.6'
VERSION='0.6.1'
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
ac_google_attribute=1
@ -21007,7 +21008,7 @@ _ASBOX
} >&5
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
CONFIG_FILES = $CONFIG_FILES
@ -21070,7 +21071,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
ctemplate config.status 0.6
ctemplate config.status 0.6.1
configured by $0, generated by GNU Autoconf 2.59,
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_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_set@,$ac_cv_cxx_hash_set,;t t
s,@ac_google_attribute@,$ac_google_attribute,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t

View File

@ -4,7 +4,7 @@
# make sure we're interpreted by some minimal autoconf
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
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
@ -58,6 +58,7 @@ AC_SUBST(ac_google_start_namespace)
AC_SUBST(ac_google_end_namespace)
AC_SUBST(ac_cv_cxx_hash_namespace)
AC_SUBST(ac_cv_cxx_hash_map)
AC_SUBST(ac_cv_cxx_hash_set)
if test "$ac_cv___attribute__" == "yes"; then
AC_SUBST(ac_google_attribute, 1)
else

View File

@ -32,6 +32,75 @@
<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>
<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.
# NOTE: Changing this file will not affect anything until you rerun configure.
#
@ -43,7 +48,7 @@ EXIT_FAILURE=1
PROGRAM=ltmain.sh
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)"
# See if we are running on zsh, and set the options which allow our
@ -1604,11 +1609,18 @@ EOF
compiler_flags="$compiler_flags $arg"
compile_command="$compile_command $arg"
finalize_command="$finalize_command $arg"
deplibs="$deplibs $arg"
continue
;;
-module)
module=yes
case $host in
*-*-freebsd*)
# Do not build the useless static library
build_old_libs=no
;;
esac
continue
;;
@ -2082,10 +2094,7 @@ EOF
case $pass in
dlopen) libs="$dlfiles" ;;
dlpreopen) libs="$dlprefiles" ;;
link)
libs="$deplibs %DEPLIBS%"
test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
;;
link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
esac
fi
if test "$pass" = dlopen; then
@ -2104,6 +2113,29 @@ EOF
else
compiler_flags="$compiler_flags $deplib"
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
;;
-l*)
@ -3204,11 +3236,6 @@ EOF
age="$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
;;
no)
@ -4713,6 +4740,9 @@ static const void *lt_preloaded_setup() {
;;
esac
;;
*-*-freebsd*)
# FreeBSD doesn't need this...
;;
*)
$echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
exit $EXIT_FAILURE
@ -6003,10 +6033,17 @@ relink_command=\"$relink_command\""
fi
# Install the pseudo-library for information purposes.
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 $?
case $host in
*-*-freebsd*)
# Do not install the useless pseudo-library
;;
*)
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.
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
* 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__
#define GOOGLE_MUTEX_H__
#include "config.h" // to figure out pthreads support
#include "config.h" // to figure out pthreads support
#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)
// 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).
# define _XOPEN_SOURCE 500 // needed to get the rwlock calls
# define _XOPEN_SOURCE 500 // needed to get the rwlock calls
# include <pthread.h>
typedef pthread_rwlock_t MutexType;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
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
# 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
class Mutex {
@ -68,22 +72,22 @@ class Mutex {
// typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex
// objects.
Mutex();
inline Mutex();
// Destructor
~Mutex();
inline ~Mutex();
void Lock(); // Block if necessary until free, then acquire exclusively
void Unlock(); // Release. Caller must hold it exclusively (via Lock())
inline void Lock(); // Block if needed until free then acquire exclusively
inline void Unlock(); // Release a lock acquired via Lock()
// 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
// these for efficiency, but don't use them anyplace where being able
// to do shared reads is necessary to avoid deadlock.
void ReaderLock(); // Block until free or shared, then acquire a share
void ReaderUnlock(); // Release a read share of this Mutex
void WriterLock() { Lock(); } // Block until free, then acquire exclusively
void WriterUnlock() { Unlock(); } // Release the exclusive lock of this Mutex
inline void ReaderLock(); // Block until free or shared then acquire a share
inline void ReaderUnlock(); // Release a read share of this Mutex
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
private:
MutexType mutex_;
@ -95,6 +99,56 @@ class 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.
class MutexLock {

View File

@ -201,6 +201,10 @@ class Template {
const TemplateDictionary *dictionary,
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
// Sets the state of the template. Used during BuildTree().
void set_state(TemplateState new_state);

View File

@ -67,28 +67,32 @@ class TemplateFromString : public Template {
/* GetTemplate
Parameters:
(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
code with markers, the very same language that
would be stored in a file for the parent class
strip - same as the parent class
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
template_text passed to the method.
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.
Note: since cache lookup is by name, you can't have two instances
with the same name but different text, and expect it to work.
Note: since cache lookup is by key, you can't have two instances
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,
Strip strip);
private:
/* This templates constuctor is private just like the parent's is.
New ones are acquired through TemplateFromString::GetTemplate */
TemplateFromString(const std::string& template_name,
TemplateFromString(const std::string& cache_key,
const std::string& template_text,
Strip strip);

View File

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

View File

@ -40,7 +40,9 @@
#include <time.h>
#include <ctype.h> // for isspace()
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> // for stat() and open() and getcwd()
#endif
#include <string.h>
#include <iostream> // for logging
#include <iomanip> // for indenting in Dump()
@ -78,6 +80,9 @@ namespace {
// Mutexes protecting the globals below. First protects g_use_current_dict
// and template_root_directory_, second protects g_template_cache.
// 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_cache_mutex;
static Mutex g_header_mutex;
@ -267,24 +272,28 @@ struct TemplateToken {
static void EmitModifiedString(const ModifierAndNonces& modifiers,
const char* in, int inlen,
ExpandEmitter* outbuf) {
// If there's more than one modifiers, we need to store the
// intermediate results in a temp-buffer. We use a string.
string scratch;
string result;
if (modifiers.size() > 1) {
// We'll assume that each modifier adds about 12% to the input size. We
// should exponentiate by |modifiers| but we just multiply, to save time.
scratch.reserve((inlen + inlen/8) * (modifiers.size()-1) + 16);
StringEmitter scratchbuf(&scratch);
// Each time through, we append the latest version of the string to
// scratch, and keep a pointer pointing to the most recent version.
// Except for (rare!) vars with 3+ modifiers, this loop at most once.
for (ModifierAndNonces::const_iterator it = modifiers.begin();
// If there's more than one modifiers, we need to store the
// intermediate results in a temp-buffer. We use a string.
// We'll assume that each modifier adds about 12% to the input
// size.
result.reserve((inlen + inlen/8) + 16);
StringEmitter scratchbuf(&result);
modifiers.front().first->Modify(in, inlen, &scratchbuf,
modifiers.front().second);
// Only used when modifiers.size() > 2
for (ModifierAndNonces::const_iterator it = modifiers.begin()+1;
it != modifiers.end()-1; ++it) {
const int startpos = scratch.size(); // where we start appendend
it->first->Modify(in, inlen, &scratchbuf, it->second);
in = scratch.data() + startpos; // point to the new "in"
inlen = scratch.size() - startpos;
string output_of_this_modifier;
output_of_this_modifier.reserve(result.size() + result.size()/8 + 16);
StringEmitter scratchbuf2(&output_of_this_modifier);
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
assert(!modifiers.empty());
@ -626,6 +635,8 @@ class SectionTemplateNode : public TemplateNode {
// section, or template to the list of nodes contained in this
// 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.
// 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);
// 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
// braces, etc.) an error message is logged, the error state of the
// 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) {
Template::ParseState* ps = &my_template->parse_state_; // short abbrev.
const char* token_start = ps->bufstart;
@ -1120,9 +1133,11 @@ TemplateToken SectionTemplateNode::GetNextToken(Template *my_template) {
// Template::~Template()
// Template::AssureGlobalsInitialized()
// Template::GetTemplate()
// Calls ReloadIfChanged to load the template the first time.
// The constructor is private; GetTemplate() is the factory
// method used to actually construct a new template if needed.
// Calls ReloadIfChanged to load the template the first time. The
// constructor is private; GetTemplate() is the factory method
// 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)
@ -1134,10 +1149,7 @@ Template::Template(const string& filename, Strip strip)
// of calling Expand() or other Template classes that access globals.
AssureGlobalsInitialized();
// phase_ indicates what type of thing we expect next during tokenization.
// We start off expecting text, hence the initial value is GETTING_TEXT
VLOG(2) << endl << "Constructing Template for " << template_file() << endl;
VLOG(2) << "Constructing Template for " << template_file();
// Preserve whitespace in Javascript files because carriage returns
// 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") ) {
strip = STRIP_BLANK_LINES;
}
ReloadIfChanged();
}
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
string abspath(PathJoin(template_root_directory(), filename));
MutexLock ml(&g_cache_mutex);
if (g_template_cache == NULL)
g_template_cache = new TemplateCache;
Template* tpl = NULL;
{
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)];
if (tpl) {
// 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 (tpl->state() == TS_RELOAD) {
tpl->ReloadIfChanged();
tpl = (*g_template_cache)[pair<string, Strip>(abspath, strip)];
if (!tpl) {
tpl = new Template(abspath, strip);
(*g_template_cache)[pair<string, Strip>(abspath, strip)] = tpl;
}
} 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
// point. If it is TS_ERROR, we leave the state as is, but return
// NULL. We won't try to load the template file again until the
// Even though we only read state() here, not write it, we acquire
// the lock in write-mode in case we have to call ReloadIfChanged.
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
// ReloadAllIfChanged.
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.
// 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,
const char* input_buffer_end) {
// Assign an arbitrary name to the top-level node
@ -1331,6 +1350,7 @@ const char *Template::template_file() const {
// ----------------------------------------------------------------------
// Template::ReloadIfChanged()
// Template::ReloadIfChangedLocked()
// Template::ReloadAllIfChanged()
// If one template, try immediately to reload it from disk. If
// 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 "".
// ----------------------------------------------------------------------
bool Template::ReloadIfChanged() {
bool Template::ReloadIfChangedLocked() {
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;
if (stat(filename_.c_str(), &statbuf) != 0) {
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() {
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache
if (g_template_cache == NULL) {
return;
// This is slightly annoying: we copy all the template-pointers to
// a vector, so we don't have to hold g_cache_mutex while messing
// 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();
iter != g_template_cache->end();
for (vector<Template*>::iterator iter = templates_in_cache.begin();
iter != templates_in_cache.end();
++iter) {
(*iter).second->set_state(TS_RELOAD);
WriterMutexLock ml((*iter)->mutex_);
(*iter)->set_state(TS_RELOAD);
}
}
// ----------------------------------------------------------------------
// 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() {
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache
if (g_template_cache == NULL) {
return;
// We clear the cache by swapping it with an empty cache. This lets
// us delete the items in the cache at our leisure without needing
// 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();
iter != g_template_cache->end();
// Now delete everything we've removed from the cache.
for (TemplateCache::const_iterator iter = tmp_cache.begin();
iter != tmp_cache.end();
++iter) {
delete (*iter).second;
delete iter->second;
}
delete g_template_cache;
g_template_cache = NULL;
}
// ----------------------------------------------------------------------

View File

@ -41,6 +41,9 @@
_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;
using std::string;
@ -53,11 +56,11 @@ using HASH_NAMESPACE::hash_map;
// the template text is taken from the second parameter. After that, the
// object is identical to a Template object, except that it cannot be
// "reloaded."
TemplateFromString::TemplateFromString(const string& template_name,
TemplateFromString::TemplateFromString(const string& cache_key,
const string& template_text,
Strip 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.
// 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
// Makes sure the template cache has been created and then tries to
// retrieve a TemplateFromString object from it via the template_name.
TemplateFromString *TemplateFromString::GetTemplate(const string& template_name,
// retrieve a TemplateFromString object from it via the cache_key.
TemplateFromString *TemplateFromString::GetTemplate(const string& cache_key,
const string& template_text,
Strip strip) {
// Only perform this method when you have the lock so multiple threads
// don't conflict over inserting and retrieving into the cache
MutexLock ml(&g_cache_mutex);
if (g_template_from_string_cache == NULL) {
g_template_from_string_cache = new TemplateFromStringCache;
TemplateFromString *tpl = NULL;
if (cache_key.empty()) { // user doesn't want to use the cache
tpl = new TemplateFromString(cache_key, template_text, strip);
} else {
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
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;
}
WriterMutexLock ml(tpl->mutex_); // to access state()
// state_ can be TS_RELOAD if ReloadAllIfChanged() touched this file.
// That's fine; we'll just ignore the reload directive for this guy.

View File

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

View File

@ -39,13 +39,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <assert.h>
#include <vector>
#include <string>
#include <algorithm> // for sort
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h> // for readdir
#endif
#include <google/template_from_string.h>
#include <google/template_dictionary.h>
@ -133,6 +137,8 @@ class TemplateFromStringUnittest {
}
static void TestGetTemplate() {
TemplateDictionary dict("dict");
// Tests the cache
const char* const tpltext = "{This is perfectly valid} yay!";
const char* const tpltext2 = "This will be ignored";
@ -148,6 +154,22 @@ class TemplateFromStringUnittest {
ASSERT(tpl1 == tpl2);
ASSERT(tpl3 == tpl4);
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
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
tpl = StringToTemplate("hi {{#VAR:h}} lo {{/VAR}}", STRIP_WHITESPACE);
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() {