mirror of
https://github.com/OlafvdSpek/ctemplate.git
synced 2025-10-05 19:16:54 +08:00
Mon May 14 17:27:10 2007 Google Inc. <opensource@google.com>
* ctemplate: version 0.5 release * Add new MakeCopy() method to copy template dictionaries (csilvers) * Add JSON-escaping (mikepurvis) * Internal change that should ease thread-handling a bit (csilvers) * Fix url_query_escape to avoid stack overflow (csilvers)
This commit is contained in:
parent
73dd30e487
commit
422d6f7443
|
@ -33,3 +33,11 @@ Mon Jan 15 14:10:42 2007 Google Inc. <opensource@google.com>
|
|||
* Add support for "pre" escaping, which preserves whitespace (dboswell)
|
||||
* Typo fixes in documentation (csilvers)
|
||||
* Expand() returns false if a template file failed to load (jmittleman)
|
||||
|
||||
Mon May 14 17:27:10 2007 Google Inc. <opensource@google.com>
|
||||
|
||||
* ctemplate: version 0.5 release
|
||||
* Add new MakeCopy() method to copy template dictionaries (csilvers)
|
||||
* Add JSON-escaping (mikepurvis)
|
||||
* Internal change that should ease thread-handling a bit (csilvers)
|
||||
* Fix url_query_escape to avoid stack overflow (csilvers)
|
||||
|
|
|
@ -62,13 +62,16 @@ noinst_SCRIPTS = src/tests/make_tpl_varnames_h_unittest.sh
|
|||
|
||||
## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
|
||||
|
||||
# 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]'
|
||||
|
||||
lib_LTLIBRARIES += libctemplate.la
|
||||
libctemplate_la_SOURCES = $(googleinclude_HEADERS) src/config.h \
|
||||
src/base/arena.h src/base/arena.cc \
|
||||
src/base/arena.h src/base/arena.cc src/base/mutex.h src/base/mutex.cc \
|
||||
src/template.cc src/template_dictionary.cc src/template_namelist.cc \
|
||||
src/template_from_string.cc
|
||||
libctemplate_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG
|
||||
libctemplate_la_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||
libctemplate_la_LDFLAGS = $(PTHREAD_CFLAGS) -export-symbols-regex $(CTEMPLATE_SYMBOLS)
|
||||
libctemplate_la_LIBADD = $(PTHREAD_LIBS)
|
||||
|
||||
# automake will make different .o files for this library, which is good,
|
||||
|
@ -76,6 +79,7 @@ libctemplate_la_LIBADD = $(PTHREAD_LIBS)
|
|||
lib_LTLIBRARIES += libctemplate_nothreads.la
|
||||
libctemplate_nothreads_la_SOURCES = $(libctemplate_la_SOURCES)
|
||||
libctemplate_nothreads_la_CXXFLAGS = -DNDEBUG -DNO_THREADS
|
||||
libctemplate_nothreads_la_LDFLAGS = -export-symbols-regex $(CTEMPLATE_SYMBOLS)
|
||||
|
||||
# Helper apps
|
||||
bin_PROGRAMS += make_tpl_varnames_h
|
||||
|
|
1431
trunk/Makefile.in
1431
trunk/Makefile.in
File diff suppressed because it is too large
Load Diff
8000
trunk/aclocal.m4
vendored
8000
trunk/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
947
trunk/config.guess
vendored
947
trunk/config.guess
vendored
File diff suppressed because it is too large
Load Diff
189
trunk/config.sub
vendored
189
trunk/config.sub
vendored
|
@ -1,9 +1,9 @@
|
|||
#! /bin/sh
|
||||
# Configuration validation subroutine script.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2003-06-18'
|
||||
timestamp='2005-07-08'
|
||||
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
|
@ -21,14 +21,15 @@ timestamp='2003-06-18'
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA.
|
||||
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
|
||||
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||
# diff and a properly formatted ChangeLog entry.
|
||||
#
|
||||
|
@ -70,7 +71,7 @@ Report bugs and patches to <config-patches@gnu.org>."
|
|||
version="\
|
||||
GNU config.sub ($timestamp)
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
|
@ -83,11 +84,11 @@ Try \`$me --help' for more information."
|
|||
while test $# -gt 0 ; do
|
||||
case $1 in
|
||||
--time-stamp | --time* | -t )
|
||||
echo "$timestamp" ; exit 0 ;;
|
||||
echo "$timestamp" ; exit ;;
|
||||
--version | -v )
|
||||
echo "$version" ; exit 0 ;;
|
||||
echo "$version" ; exit ;;
|
||||
--help | --h* | -h )
|
||||
echo "$usage"; exit 0 ;;
|
||||
echo "$usage"; exit ;;
|
||||
-- ) # Stop option processing
|
||||
shift; break ;;
|
||||
- ) # Use stdin as input.
|
||||
|
@ -99,7 +100,7 @@ while test $# -gt 0 ; do
|
|||
*local*)
|
||||
# First pass through any local machine types.
|
||||
echo $1
|
||||
exit 0;;
|
||||
exit ;;
|
||||
|
||||
* )
|
||||
break ;;
|
||||
|
@ -118,7 +119,8 @@ esac
|
|||
# Here we must recognize all the valid KERNEL-OS combinations.
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
|
||||
kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
|
@ -144,7 +146,7 @@ case $os in
|
|||
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
||||
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
||||
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
||||
-apple | -axis)
|
||||
-apple | -axis | -knuth | -cray)
|
||||
os=
|
||||
basic_machine=$1
|
||||
;;
|
||||
|
@ -228,14 +230,16 @@ case $basic_machine in
|
|||
| a29k \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| am33_2.0 \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||
| bfin \
|
||||
| c4x | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k \
|
||||
| m32r | m68000 | m68k | m88k | mcore \
|
||||
| ip2k | iq2000 \
|
||||
| m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
|
||||
| mips | mipsbe | mipseb | mipsel | mipsle \
|
||||
| mips16 \
|
||||
| mips64 | mips64el \
|
||||
|
@ -244,31 +248,37 @@ case $basic_machine in
|
|||
| mips64vr4100 | mips64vr4100el \
|
||||
| mips64vr4300 | mips64vr4300el \
|
||||
| mips64vr5000 | mips64vr5000el \
|
||||
| mips64vr5900 | mips64vr5900el \
|
||||
| mipsisa32 | mipsisa32el \
|
||||
| mipsisa32r2 | mipsisa32r2el \
|
||||
| mipsisa64 | mipsisa64el \
|
||||
| mipsisa64r2 | mipsisa64r2el \
|
||||
| mipsisa64sb1 | mipsisa64sb1el \
|
||||
| mipsisa64sr71k | mipsisa64sr71kel \
|
||||
| mipstx39 | mipstx39el \
|
||||
| mn10200 | mn10300 \
|
||||
| ms1 \
|
||||
| msp430 \
|
||||
| ns16k | ns32k \
|
||||
| openrisc | or32 \
|
||||
| or32 \
|
||||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
|
||||
| pyramid \
|
||||
| s390 | s390x \
|
||||
| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
|
||||
| sh64 | sh64le \
|
||||
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
|
||||
| sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
|
||||
| sparcv8 | sparcv9 | sparcv9b \
|
||||
| strongarm \
|
||||
| tahoe | thumb | tic4x | tic80 | tron \
|
||||
| v850 | v850e \
|
||||
| we32k \
|
||||
| x86 | xscale | xstormy16 | xtensa \
|
||||
| x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
|
||||
| z8k)
|
||||
basic_machine=$basic_machine-unknown
|
||||
;;
|
||||
m32c)
|
||||
basic_machine=$basic_machine-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12)
|
||||
# Motorola 68HC11/12.
|
||||
basic_machine=$basic_machine-unknown
|
||||
|
@ -296,19 +306,19 @@ case $basic_machine in
|
|||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* \
|
||||
| bs2000-* \
|
||||
| bfin-* | bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
|
||||
| clipper-* | cydra-* \
|
||||
| clipper-* | craynv-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* \
|
||||
| m32r-* \
|
||||
| ip2k-* | iq2000-* \
|
||||
| m32r-* | m32rle-* \
|
||||
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||
| m88110-* | m88k-* | mcore-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* \
|
||||
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
|
||||
| mips16-* \
|
||||
| mips64-* | mips64el-* \
|
||||
|
@ -317,34 +327,40 @@ case $basic_machine in
|
|||
| mips64vr4100-* | mips64vr4100el-* \
|
||||
| mips64vr4300-* | mips64vr4300el-* \
|
||||
| mips64vr5000-* | mips64vr5000el-* \
|
||||
| mips64vr5900-* | mips64vr5900el-* \
|
||||
| mipsisa32-* | mipsisa32el-* \
|
||||
| mipsisa32r2-* | mipsisa32r2el-* \
|
||||
| mipsisa64-* | mipsisa64el-* \
|
||||
| mipsisa64r2-* | mipsisa64r2el-* \
|
||||
| mipsisa64sb1-* | mipsisa64sb1el-* \
|
||||
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
|
||||
| mipstx39-* | mipstx39el-* \
|
||||
| mmix-* \
|
||||
| ms1-* \
|
||||
| msp430-* \
|
||||
| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
|
||||
| none-* | np1-* | ns16k-* | ns32k-* \
|
||||
| orion-* \
|
||||
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
|
||||
| pyramid-* \
|
||||
| romp-* | rs6000-* \
|
||||
| s390-* | s390x-* \
|
||||
| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
|
||||
| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
|
||||
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
|
||||
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
|
||||
| sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
|
||||
| sparclite-* \
|
||||
| sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
|
||||
| tahoe-* | thumb-* \
|
||||
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||
| tron-* \
|
||||
| v850-* | v850e-* | vax-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
|
||||
| xtensa-* \
|
||||
| x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
|
||||
| xstormy16-* | xtensa-* \
|
||||
| ymp-* \
|
||||
| z8k-*)
|
||||
;;
|
||||
m32c-*)
|
||||
;;
|
||||
# Recognize the various machine names and aliases which stand
|
||||
# for a CPU type and a company and sometimes even an OS.
|
||||
386bsd)
|
||||
|
@ -361,6 +377,9 @@ case $basic_machine in
|
|||
basic_machine=a29k-amd
|
||||
os=-udi
|
||||
;;
|
||||
abacus)
|
||||
basic_machine=abacus-unknown
|
||||
;;
|
||||
adobe68k)
|
||||
basic_machine=m68010-adobe
|
||||
os=-scout
|
||||
|
@ -378,6 +397,9 @@ case $basic_machine in
|
|||
amd64)
|
||||
basic_machine=x86_64-pc
|
||||
;;
|
||||
amd64-*)
|
||||
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
amdahl)
|
||||
basic_machine=580-amdahl
|
||||
os=-sysv
|
||||
|
@ -437,12 +459,27 @@ case $basic_machine in
|
|||
basic_machine=j90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
craynv)
|
||||
basic_machine=craynv-cray
|
||||
os=-unicosmp
|
||||
;;
|
||||
cr16c)
|
||||
basic_machine=cr16c-unknown
|
||||
os=-elf
|
||||
;;
|
||||
crds | unos)
|
||||
basic_machine=m68k-crds
|
||||
;;
|
||||
crisv32 | crisv32-* | etraxfs*)
|
||||
basic_machine=crisv32-axis
|
||||
;;
|
||||
cris | cris-* | etrax*)
|
||||
basic_machine=cris-axis
|
||||
;;
|
||||
crx)
|
||||
basic_machine=crx-unknown
|
||||
os=-elf
|
||||
;;
|
||||
da30 | da30-*)
|
||||
basic_machine=m68k-da30
|
||||
;;
|
||||
|
@ -465,6 +502,10 @@ case $basic_machine in
|
|||
basic_machine=m88k-motorola
|
||||
os=-sysv3
|
||||
;;
|
||||
djgpp)
|
||||
basic_machine=i586-pc
|
||||
os=-msdosdjgpp
|
||||
;;
|
||||
dpx20 | dpx20-*)
|
||||
basic_machine=rs6000-bull
|
||||
os=-bosx
|
||||
|
@ -643,10 +684,6 @@ case $basic_machine in
|
|||
mips3*)
|
||||
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
|
||||
;;
|
||||
mmix*)
|
||||
basic_machine=mmix-knuth
|
||||
os=-mmixware
|
||||
;;
|
||||
monitor)
|
||||
basic_machine=m68k-rom68k
|
||||
os=-coff
|
||||
|
@ -727,10 +764,6 @@ case $basic_machine in
|
|||
np1)
|
||||
basic_machine=np1-gould
|
||||
;;
|
||||
nv1)
|
||||
basic_machine=nv1-cray
|
||||
os=-unicosmp
|
||||
;;
|
||||
nsr-tandem)
|
||||
basic_machine=nsr-tandem
|
||||
;;
|
||||
|
@ -738,9 +771,12 @@ case $basic_machine in
|
|||
basic_machine=hppa1.1-oki
|
||||
os=-proelf
|
||||
;;
|
||||
or32 | or32-*)
|
||||
openrisc | openrisc-*)
|
||||
basic_machine=or32-unknown
|
||||
os=-coff
|
||||
;;
|
||||
os400)
|
||||
basic_machine=powerpc-ibm
|
||||
os=-os400
|
||||
;;
|
||||
OSE68000 | ose68000)
|
||||
basic_machine=m68000-ericsson
|
||||
|
@ -833,6 +869,12 @@ case $basic_machine in
|
|||
rtpc | rtpc-*)
|
||||
basic_machine=romp-ibm
|
||||
;;
|
||||
s390 | s390-*)
|
||||
basic_machine=s390-ibm
|
||||
;;
|
||||
s390x | s390x-*)
|
||||
basic_machine=s390x-ibm
|
||||
;;
|
||||
sa29200)
|
||||
basic_machine=a29k-amd
|
||||
os=-udi
|
||||
|
@ -956,6 +998,10 @@ case $basic_machine in
|
|||
tower | tower-32)
|
||||
basic_machine=m68k-ncr
|
||||
;;
|
||||
tpf)
|
||||
basic_machine=s390x-ibm
|
||||
os=-tpf
|
||||
;;
|
||||
udi29k)
|
||||
basic_machine=a29k-amd
|
||||
os=-udi
|
||||
|
@ -999,6 +1045,10 @@ case $basic_machine in
|
|||
basic_machine=hppa1.1-winbond
|
||||
os=-proelf
|
||||
;;
|
||||
xbox)
|
||||
basic_machine=i686-pc
|
||||
os=-mingw32
|
||||
;;
|
||||
xps | xps100)
|
||||
basic_machine=xps100-honeywell
|
||||
;;
|
||||
|
@ -1029,6 +1079,9 @@ case $basic_machine in
|
|||
romp)
|
||||
basic_machine=romp-ibm
|
||||
;;
|
||||
mmix)
|
||||
basic_machine=mmix-knuth
|
||||
;;
|
||||
rs6000)
|
||||
basic_machine=rs6000-ibm
|
||||
;;
|
||||
|
@ -1045,13 +1098,10 @@ case $basic_machine in
|
|||
we32k)
|
||||
basic_machine=we32k-att
|
||||
;;
|
||||
sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||
basic_machine=sh-unknown
|
||||
;;
|
||||
sh64)
|
||||
basic_machine=sh64-unknown
|
||||
;;
|
||||
sparc | sparcv9 | sparcv9b)
|
||||
sparc | sparcv8 | sparcv9 | sparcv9b)
|
||||
basic_machine=sparc-sun
|
||||
;;
|
||||
cydra)
|
||||
|
@ -1124,19 +1174,21 @@ case $os in
|
|||
| -aos* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
|
||||
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
|
||||
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
|
||||
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* \
|
||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
| -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
|
||||
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
|
||||
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
|
||||
| -skyos* | -haiku*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
|
@ -1154,12 +1206,15 @@ case $os in
|
|||
os=`echo $os | sed -e 's|nto|nto-qnx|'`
|
||||
;;
|
||||
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
|
||||
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
|
||||
| -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
|
||||
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
|
||||
;;
|
||||
-mac*)
|
||||
os=`echo $os | sed -e 's|mac|macos|'`
|
||||
;;
|
||||
-linux-dietlibc)
|
||||
os=-linux-dietlibc
|
||||
;;
|
||||
-linux*)
|
||||
os=`echo $os | sed -e 's|linux|linux-gnu|'`
|
||||
;;
|
||||
|
@ -1172,6 +1227,9 @@ case $os in
|
|||
-opened*)
|
||||
os=-openedition
|
||||
;;
|
||||
-os400*)
|
||||
os=-os400
|
||||
;;
|
||||
-wince*)
|
||||
os=-wince
|
||||
;;
|
||||
|
@ -1193,6 +1251,9 @@ case $os in
|
|||
-atheos*)
|
||||
os=-atheos
|
||||
;;
|
||||
-syllable*)
|
||||
os=-syllable
|
||||
;;
|
||||
-386bsd)
|
||||
os=-bsd
|
||||
;;
|
||||
|
@ -1215,6 +1276,9 @@ case $os in
|
|||
-sinix*)
|
||||
os=-sysv4
|
||||
;;
|
||||
-tpf*)
|
||||
os=-tpf
|
||||
;;
|
||||
-triton*)
|
||||
os=-sysv3
|
||||
;;
|
||||
|
@ -1251,6 +1315,9 @@ case $os in
|
|||
-kaos*)
|
||||
os=-kaos
|
||||
;;
|
||||
-zvmoe)
|
||||
os=-zvmoe
|
||||
;;
|
||||
-none)
|
||||
;;
|
||||
*)
|
||||
|
@ -1282,9 +1349,9 @@ case $basic_machine in
|
|||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
# This must come before the *-dec entry.
|
||||
pdp10-*)
|
||||
os=-tops20
|
||||
|
@ -1328,9 +1395,15 @@ case $basic_machine in
|
|||
*-be)
|
||||
os=-beos
|
||||
;;
|
||||
*-haiku)
|
||||
os=-haiku
|
||||
;;
|
||||
*-ibm)
|
||||
os=-aix
|
||||
;;
|
||||
*-knuth)
|
||||
os=-mmixware
|
||||
;;
|
||||
*-wec)
|
||||
os=-proelf
|
||||
;;
|
||||
|
@ -1463,9 +1536,15 @@ case $basic_machine in
|
|||
-mvs* | -opened*)
|
||||
vendor=ibm
|
||||
;;
|
||||
-os400*)
|
||||
vendor=ibm
|
||||
;;
|
||||
-ptx*)
|
||||
vendor=sequent
|
||||
;;
|
||||
-tpf*)
|
||||
vendor=ibm
|
||||
;;
|
||||
-vxsim* | -vxworks* | -windiss*)
|
||||
vendor=wrs
|
||||
;;
|
||||
|
@ -1490,7 +1569,7 @@ case $basic_machine in
|
|||
esac
|
||||
|
||||
echo $basic_machine$os
|
||||
exit 0
|
||||
exit
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
|
|
2284
trunk/configure
vendored
2284
trunk/configure
vendored
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
|||
# make sure we're interpreted by some minimal autoconf
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
AC_INIT(ctemplate, 0.4, opensource@google.com)
|
||||
AC_INIT(ctemplate, 0.5, opensource@google.com)
|
||||
# The argument here is just something that should be in the current directory
|
||||
# (for sanity checking)
|
||||
AC_CONFIG_SRCDIR(README)
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
/* This file is duplicated at http://www.corp.google.com/css/designstyle.css
|
||||
* If you change this file, copy it to ~web/html/css/designstyle.css
|
||||
*/
|
||||
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
color: black;
|
||||
|
|
|
@ -319,8 +319,19 @@ are the modifiers that are supported:</p>
|
|||
<td>javascript-escapes the variable before output
|
||||
(eg <code>"</code> -> <code>\"</code>)</td>
|
||||
</tr>
|
||||
|
||||
<tr><td><code>:json_escape</code></td><td><code>:o</code></td>
|
||||
<td>json-escapes a variable before output as a string in json;
|
||||
similar to javascript escaping, but ignores characters such
|
||||
as <code>=</code> and <code>&</code>.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p><strong>NOTE:</strong> At the moment, there are no filters for handling XML
|
||||
attributes and text nodes. For HTML snippets, use the html filter; in other
|
||||
situations, it may be appropriate to use CDATA blocks.</p>
|
||||
|
||||
|
||||
<h3> <A NAME="inheritence">Details on Dictionary Lookup</A> </h3>
|
||||
|
||||
|
@ -742,6 +753,24 @@ using a normal, file-based template, and then switch to
|
|||
template-from-string later if you so desire.</p>
|
||||
|
||||
|
||||
<h3> Copying a Template Dictionary </h3>
|
||||
|
||||
<p>You can use the <code>MakeCopy()</code> method on a template
|
||||
dictionary to make a "deep" copy of the template. This can be useful
|
||||
for situations like the following: you want to fill a template several
|
||||
times, each time with 90% of the values the same, but the last 10%
|
||||
different. Computing the values is slow. Here's how you can use
|
||||
<code>MakeCopy()</code> to do it:</p>
|
||||
<ol>
|
||||
<li> fill dict with 90%
|
||||
<li> <code>newdict1 = dict->MakeCopy();</code>
|
||||
<li> fill newdict1 with last 10%
|
||||
<li> <code>newdict2 = dict->MakeCopy();</code>
|
||||
<li> fill newdict2 with last 10%
|
||||
<li> etc.
|
||||
</ol>
|
||||
|
||||
|
||||
<h2>Security Considerations</h2>
|
||||
|
||||
<p>Like all web applications, programs that use the Google Template System
|
||||
|
|
|
@ -1,3 +1,27 @@
|
|||
ctemplate (0.5) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Google Inc. <opensource@google.com> Mon, 14 May 2007 17:27:10 -0700
|
||||
|
||||
ctemplate (0.4) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Google Inc. <opensource@google.com> Mon, 15 Jan 2007 14:10:42 -0800
|
||||
|
||||
ctemplate (0.3) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Google Inc. <opensource@google.com> Mon, 21 Aug 2006 17:44:32 -0700
|
||||
|
||||
ctemplate (0.2) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Google Inc. <opensource@google.com> Wed, 14 Jun 2006 14:56:04 -0700
|
||||
|
||||
ctemplate (0.1-1) unstable; urgency=low
|
||||
|
||||
* Initial release.
|
||||
|
|
|
@ -10,18 +10,18 @@ Section: libdevel
|
|||
Architecture: any
|
||||
Depends: libctemplate0 (= ${Source-Version})
|
||||
Description: This package contains a library implementing a simple but
|
||||
powerful template language for C++. It emphasizes separating logic
|
||||
from presentation: it is impossible to embed application logic in this
|
||||
template language. The devel package contains static and debug
|
||||
libraries and header files for developing applications that use the
|
||||
ctemplate package.
|
||||
powerful template language for C++. It emphasizes separating logic
|
||||
from presentation: it is impossible to embed application logic in this
|
||||
template language. The devel package contains static and debug
|
||||
libraries and header files for developing applications that use the
|
||||
ctemplate package.
|
||||
|
||||
Package: libctemplate0
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Description: This package contains a library implementing a simple but
|
||||
powerful template language for C++. It emphasizes separating logic
|
||||
from presentation: it is impossible to embed application logic in this
|
||||
template language. This limits the power of the template language
|
||||
without limiting the power of the template *system*. Indeed, Google's
|
||||
"main" web search uses this system exclusively for formatting output.
|
||||
powerful template language for C++. It emphasizes separating logic
|
||||
from presentation: it is impossible to embed application logic in this
|
||||
template language. This limits the power of the template language
|
||||
without limiting the power of the template *system*. Indeed, Google's
|
||||
"main" web search uses this system exclusively for formatting output.
|
||||
|
|
|
@ -9,3 +9,7 @@ doc/index.html
|
|||
doc/howto.html
|
||||
doc/tips.html
|
||||
doc/example.html
|
||||
doc/xss_resources.html
|
||||
contrib/README.contrib
|
||||
contrib/highlighting.vim
|
||||
contrib/tpl-mode.el
|
||||
|
|
|
@ -65,7 +65,6 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%defattr(-,root,root)
|
||||
|
||||
%{prefix}/include/google
|
||||
%{prefix}/lib/debug
|
||||
%{prefix}/lib/libctemplate.a
|
||||
%{prefix}/lib/libctemplate.la
|
||||
%{prefix}/lib/libctemplate.so
|
||||
|
|
79
trunk/src/base/mutex.cc
Normal file
79
trunk/src/base/mutex.cc
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* 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
|
134
trunk/src/base/mutex.h
Normal file
134
trunk/src/base/mutex.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* 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, supporting locks and read-write locks.
|
||||
*
|
||||
* To use: you should define the following macros in your configure.ac:
|
||||
* ACX_PTHREAD
|
||||
* AC_RWLOCK
|
||||
* The latter is defined in ../autoconf.
|
||||
*
|
||||
* This class is meant to be internal-only, so it's defined in the
|
||||
* global namespace. If you want to expose it, you'll want to move
|
||||
* it to the Google namespace.
|
||||
*/
|
||||
|
||||
#include "config.h" // to figure out pthreads support
|
||||
|
||||
#if defined(NO_THREADS)
|
||||
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
|
||||
# include <pthread.h>
|
||||
typedef pthread_rwlock_t MutexType;
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
# include <pthread.h>
|
||||
typedef pthread_mutex_t MutexType;
|
||||
#else
|
||||
# error Need to implement mutex.h/cc for your architecture, or #define NO_THREADS
|
||||
#endif
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
// Create a Mutex that is not held by anybody. This constructor is
|
||||
// typically used for Mutexes allocated on the heap or the stack.
|
||||
// See below for a recommendation for constructing global Mutex
|
||||
// objects.
|
||||
Mutex();
|
||||
|
||||
// Destructor
|
||||
~Mutex();
|
||||
|
||||
void Lock(); // Block if necessary until free, then acquire exclusively
|
||||
void Unlock(); // Release. Caller must hold it exclusively (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
|
||||
|
||||
private:
|
||||
MutexType mutex_;
|
||||
|
||||
// Catch the error of writing Mutex when intending MutexLock.
|
||||
Mutex(Mutex *ignored) {}
|
||||
// Disallow "evil" constructors
|
||||
Mutex(const Mutex&);
|
||||
void operator=(const Mutex&);
|
||||
};
|
||||
|
||||
|
||||
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
|
||||
class MutexLock {
|
||||
public:
|
||||
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
|
||||
~MutexLock() { mu_->Unlock(); }
|
||||
private:
|
||||
Mutex * const mu_;
|
||||
// Disallow "evil" constructors
|
||||
MutexLock(const MutexLock&);
|
||||
void operator=(const MutexLock&);
|
||||
};
|
||||
|
||||
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
|
||||
class ReaderMutexLock {
|
||||
public:
|
||||
explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
|
||||
~ReaderMutexLock() { mu_->ReaderUnlock(); }
|
||||
private:
|
||||
Mutex * const mu_;
|
||||
// Disallow "evil" constructors
|
||||
ReaderMutexLock(const ReaderMutexLock&);
|
||||
void operator=(const ReaderMutexLock&);
|
||||
};
|
||||
|
||||
class WriterMutexLock {
|
||||
public:
|
||||
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
|
||||
~WriterMutexLock() { mu_->WriterUnlock(); }
|
||||
private:
|
||||
Mutex * const mu_;
|
||||
// Disallow "evil" constructors
|
||||
WriterMutexLock(const WriterMutexLock&);
|
||||
void operator=(const WriterMutexLock&);
|
||||
};
|
||||
|
||||
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
|
||||
#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
|
||||
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
|
||||
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
|
|
@ -13,12 +13,6 @@
|
|||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* define if the compiler has hash_map */
|
||||
#undef HAVE_EXT_HASH_MAP
|
||||
|
||||
/* define if the compiler has hash_set */
|
||||
#undef HAVE_EXT_HASH_SET
|
||||
|
||||
/* Define to 1 if you have the `getopt_long' function. */
|
||||
#undef HAVE_GETOPT_LONG
|
||||
|
||||
|
@ -102,9 +96,15 @@
|
|||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* printf format code for printing a size_t */
|
||||
/* printf format code for printing a size_t and ssize_t */
|
||||
#undef PRIdS
|
||||
|
||||
/* printf format code for printing a size_t and ssize_t */
|
||||
#undef PRIuS
|
||||
|
||||
/* printf format code for printing a size_t and ssize_t */
|
||||
#undef PRIxS
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
#undef PTHREAD_CREATE_JOINABLE
|
||||
|
|
|
@ -245,7 +245,7 @@ class Template {
|
|||
// The mutex object used during ReloadIfChanged to prevent the same
|
||||
// object from reloading the template file in parallel by different
|
||||
// threads.
|
||||
mutable class RWLock* mutex_; // RWLock defined in template.cc
|
||||
mutable class Mutex* mutex_;
|
||||
|
||||
// The root directory for all templates. Defaults to "./" until
|
||||
// SetTemplateRootDirectory changes it
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
|
||||
@ac_google_start_namespace@
|
||||
|
||||
class UnsafeArena;
|
||||
|
||||
// Most methods below take a TemplateString rather than a C++ string.
|
||||
// This is for efficiency: it can avoid extra string copies.
|
||||
// For any argument that takes a TemplateString, you can pass in any of:
|
||||
|
@ -88,10 +90,18 @@ class TemplateDictionary {
|
|||
// arena is used to store all names and values. It can be NULL (the
|
||||
// default), in which case we create own own arena.
|
||||
explicit TemplateDictionary(const std::string& name,
|
||||
class UnsafeArena* arena=NULL);
|
||||
UnsafeArena* arena=NULL);
|
||||
~TemplateDictionary();
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
// Returns a recursive copy of this dictionary. This dictionary
|
||||
// *must* be a "top-level" dictionary (that is, not created via
|
||||
// AddSectionDictionary() or AddIncludeDictionary()). Caller owns
|
||||
// the resulting dict, and must delete it. If arena is NULL, we
|
||||
// create our own. Returns NULL if the copy fails (probably because
|
||||
// the "top-level" rule was violated).
|
||||
TemplateDictionary* MakeCopy(const std::string& name_of_copy,
|
||||
UnsafeArena* arena=NULL);
|
||||
|
||||
// --- Routines for VARIABLES
|
||||
// These are the five main routines used to set the value of a variable.
|
||||
|
@ -285,10 +295,18 @@ class TemplateDictionary {
|
|||
// Helps set up the static stuff
|
||||
static GlobalDict* SetupGlobalDictUnlocked();
|
||||
|
||||
// This is true iff this template was created via the public constructor,
|
||||
// and not the private one used for subsidiary dicts (section/include)
|
||||
bool is_rootlevel_template() const { return template_global_dict_owner_; }
|
||||
|
||||
// Utility functions for copying a string into the arena.
|
||||
const char *Memdup(const char* s, int slen);
|
||||
const char *Memdup(const TemplateString& s) {return Memdup(s.ptr_, s.length_);}
|
||||
|
||||
// Used for recursive MakeCopy calls.
|
||||
TemplateDictionary* InternalMakeCopy(const std::string& name_of_copy,
|
||||
UnsafeArena* arena);
|
||||
|
||||
// Used to do the formatting for the SetFormatted*() functions
|
||||
static int StringAppendV(char* space, char** out,
|
||||
const char* format, va_list ap);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#ifndef TEMPLATE_FROM_STRING_H
|
||||
#define TEMPLATE_FROM_STRING_H
|
||||
|
||||
#include <string>
|
||||
#include <google/template.h>
|
||||
|
||||
@ac_google_start_namespace@
|
||||
|
|
|
@ -33,10 +33,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
// 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
|
||||
|
||||
#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
@ -45,9 +42,6 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h> // for stat() and open()
|
||||
#include <string.h>
|
||||
#if defined(HAVE_PTHREAD) && !defined(NO_THREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
#include <iostream> // for logging
|
||||
#include <iomanip> // for indenting in Dump()
|
||||
#include <string>
|
||||
|
@ -70,58 +64,14 @@ using HASH_NAMESPACE::hash;
|
|||
|
||||
const int kIndent = 2; // num spaces to indent each level
|
||||
|
||||
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
|
||||
|
||||
#if defined(HAVE_PTHREAD) && !defined(NO_THREADS)
|
||||
# ifdef HAVE_RWLOCK
|
||||
// Easiest to use a wrapper class for the read-write mutex
|
||||
class RWLock {
|
||||
public:
|
||||
RWLock() { SAFE_PTHREAD(pthread_rwlock_init(&lock_, NULL)); }
|
||||
~RWLock() { SAFE_PTHREAD(pthread_rwlock_destroy(&lock_)); }
|
||||
void LockRO() { SAFE_PTHREAD(pthread_rwlock_rdlock(&lock_)); }
|
||||
void LockRW() { SAFE_PTHREAD(pthread_rwlock_wrlock(&lock_)); }
|
||||
void Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock(&lock_)); }
|
||||
private:
|
||||
pthread_rwlock_t lock_;
|
||||
};
|
||||
# else
|
||||
// Not as efficient, but the best we can do if !HAVE_RWLOCK
|
||||
class RWLock {
|
||||
public:
|
||||
RWLock() { SAFE_PTHREAD(pthread_mutex_init(&lock_, NULL)); }
|
||||
~RWLock() { SAFE_PTHREAD(pthread_mutex_destroy(&lock_)); }
|
||||
void LockRO() { SAFE_PTHREAD(pthread_mutex_lock(&lock_)); }
|
||||
void LockRW() { SAFE_PTHREAD(pthread_mutex_lock(&lock_)); }
|
||||
void Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&lock_)); }
|
||||
private:
|
||||
pthread_mutex_t lock_;
|
||||
};
|
||||
# endif
|
||||
|
||||
// Mutexes protecting the globals below. First protects g_use_current_dict
|
||||
// and template_root_directory_, second protects g_template_cache.
|
||||
static pthread_mutex_t g_static_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t g_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
// This protects vars_seen in WriteOneHeaderEntry, below.
|
||||
static pthread_mutex_t g_header_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
# define LOCK(m) SAFE_PTHREAD(pthread_mutex_lock(m))
|
||||
# define UNLOCK(m) SAFE_PTHREAD(pthread_mutex_unlock(m))
|
||||
#else
|
||||
class RWLock { // since mutex_ has this type
|
||||
public:
|
||||
RWLock() {}
|
||||
void LockRO() {}
|
||||
void LockRW() {}
|
||||
void Unlock() {}
|
||||
};
|
||||
# define LOCK(m)
|
||||
# define UNLOCK(m)
|
||||
#endif
|
||||
|
||||
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.
|
||||
static Mutex g_static_mutex;
|
||||
static Mutex g_cache_mutex;
|
||||
static Mutex g_header_mutex;
|
||||
const char * const kDefaultTemplateDirectory = "./";
|
||||
const char * const kMainSectionName = "__MAIN__";
|
||||
static vector<TemplateDictionary*>* g_use_current_dict; // vector == {NULL}
|
||||
|
@ -187,23 +137,31 @@ static string HtmlModifier(const string& input, const string&) {
|
|||
return TemplateDictionary::html_escape(input);
|
||||
}
|
||||
|
||||
static string PreModifier(const string& input, const string&) {
|
||||
return TemplateDictionary::pre_escape(input);
|
||||
}
|
||||
|
||||
static string JavascriptModifier(const string& input, const string&) {
|
||||
return TemplateDictionary::javascript_escape(input);
|
||||
}
|
||||
|
||||
static string JsonModifier(const string& input, const string&) {
|
||||
return TemplateDictionary::json_escape(input);
|
||||
}
|
||||
|
||||
static string PreModifier(const string& input, const string&) {
|
||||
return TemplateDictionary::pre_escape(input);
|
||||
}
|
||||
|
||||
static string UrlQueryEscapeModifier(const string& input, const string&) {
|
||||
return TemplateDictionary::url_query_escape(input);
|
||||
}
|
||||
|
||||
// Using "o" for JSON is not really very intuitive; template authors should
|
||||
// either use json_escape in full, or provide a comment explaining the
|
||||
// non-intuitive shortening.
|
||||
static const Modifier g_modifiers[] = {
|
||||
{ "html_escape", 'h', MODVAL_FORBIDDEN, &HtmlModifier },
|
||||
{ "pre_escape", 'p', MODVAL_FORBIDDEN, &PreModifier },
|
||||
{ "javascript_escape", 'j', MODVAL_FORBIDDEN, &JavascriptModifier },
|
||||
{ "url_query_escape", 'u', MODVAL_FORBIDDEN, &UrlQueryEscapeModifier },
|
||||
{ "json_escape", 'o', MODVAL_FORBIDDEN, &JsonModifier },
|
||||
{ "pre_escape", 'p', MODVAL_FORBIDDEN, &PreModifier },
|
||||
{ "url_query_escape", 'u', MODVAL_FORBIDDEN, &UrlQueryEscapeModifier }
|
||||
};
|
||||
|
||||
|
||||
|
@ -245,7 +203,7 @@ class HeaderEntryStringHash { // not all STL implementations define this...
|
|||
static void WriteOneHeaderEntry(string *outstring,
|
||||
const string& variable,
|
||||
const string& full_pathname) {
|
||||
LOCK(&g_header_mutex);
|
||||
MutexLock ml(&g_header_mutex);
|
||||
|
||||
// we use hash_map instead of hash_set just to keep the stl size down
|
||||
static hash_map<string, bool, HeaderEntryStringHash> vars_seen;
|
||||
|
@ -303,7 +261,6 @@ static void WriteOneHeaderEntry(string *outstring,
|
|||
}
|
||||
vars_seen[variable] = true;
|
||||
}
|
||||
UNLOCK(&g_header_mutex);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -869,7 +826,7 @@ void SectionTemplateNode::Dump(int level) const {
|
|||
// --- AddSubnode and its sub-routines
|
||||
|
||||
void SectionTemplateNode::AddTextNode(const char* text, int textlen) {
|
||||
if (text != "") { // ignore null text sections
|
||||
if (textlen > 0) { // ignore null text sections
|
||||
node_list_.push_back(new TextTemplateNode(text, textlen));
|
||||
}
|
||||
}
|
||||
|
@ -1216,7 +1173,7 @@ Template::Template(const string& filename, Strip strip)
|
|||
: filename_(filename), filename_mtime_(0), strip_(strip),
|
||||
state_(TS_EMPTY),
|
||||
template_text_(NULL), template_text_len_(0), tree_(NULL),
|
||||
parse_state_(), mutex_(new RWLock) {
|
||||
parse_state_(), mutex_(new Mutex) {
|
||||
// Make sure g_use_current_dict, etc. are initted before any possbility
|
||||
// of calling Expand() or other Template classes that access globals.
|
||||
AssureGlobalsInitialized();
|
||||
|
@ -1247,21 +1204,20 @@ Template::~Template() {
|
|||
// NOTE: This function must be called by any static function that
|
||||
// accesses any of the variables set here.
|
||||
void Template::AssureGlobalsInitialized() {
|
||||
LOCK(&g_static_mutex); // protects all the vars defined here
|
||||
MutexLock ml(&g_static_mutex); // protects all the vars defined here
|
||||
if (template_root_directory_ == NULL) { // only need to run this once!
|
||||
template_root_directory_ = new string(kDefaultTemplateDirectory);
|
||||
// this_dict is a dictionary with a single NULL entry in it
|
||||
g_use_current_dict = new vector<TemplateDictionary*>;
|
||||
g_use_current_dict->push_back(NULL);
|
||||
}
|
||||
UNLOCK(&g_static_mutex);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
LOCK(&g_cache_mutex);
|
||||
MutexLock ml(&g_cache_mutex);
|
||||
if (g_template_cache == NULL)
|
||||
g_template_cache = new TemplateCache;
|
||||
|
||||
|
@ -1277,7 +1233,6 @@ Template *Template::GetTemplate(const string& filename, Strip strip) {
|
|||
tpl = new Template(abspath, strip);
|
||||
(*g_template_cache)[pair<string, Strip>(abspath, strip)] = tpl;
|
||||
}
|
||||
UNLOCK(&g_cache_mutex); // we're done messing with g_template_cache
|
||||
|
||||
// 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
|
||||
|
@ -1374,7 +1329,7 @@ bool Template::SetTemplateRootDirectory(const string& directory) {
|
|||
AssureGlobalsInitialized();
|
||||
|
||||
// This is needed since we access/modify template_root_directory_
|
||||
LOCK(&g_static_mutex);
|
||||
MutexLock ml(&g_static_mutex);
|
||||
// make sure it ends with '/'
|
||||
if (directory.length() == 0 || directory[directory.length()-1] != '/') {
|
||||
*template_root_directory_ = directory + '/';
|
||||
|
@ -1383,7 +1338,6 @@ bool Template::SetTemplateRootDirectory(const string& directory) {
|
|||
}
|
||||
VLOG(2) << "Setting Template directory to " << *template_root_directory_
|
||||
<< endl;
|
||||
UNLOCK(&g_static_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1391,10 +1345,8 @@ bool Template::SetTemplateRootDirectory(const string& directory) {
|
|||
string Template::template_root_directory() {
|
||||
// Make sure template_root_directory_ has been initialized
|
||||
AssureGlobalsInitialized();
|
||||
LOCK(&g_static_mutex); // protects the static var template_root_directory_
|
||||
string retval = *template_root_directory_;
|
||||
UNLOCK(&g_static_mutex);
|
||||
return retval;
|
||||
MutexLock ml(&g_static_mutex); // protects the static var t_r_d_
|
||||
return *template_root_directory_;
|
||||
}
|
||||
|
||||
void Template::set_state(TemplateState new_state) {
|
||||
|
@ -1428,21 +1380,19 @@ bool Template::ReloadIfChanged() {
|
|||
// 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.
|
||||
mutex_->LockRW();
|
||||
WriterMutexLock ml(mutex_);
|
||||
|
||||
struct stat statbuf;
|
||||
if (stat(filename_.c_str(), &statbuf) != 0) {
|
||||
LOG(WARNING) << "Unable to stat file " << filename_ << endl;
|
||||
// We keep the old tree if there is one, otherwise we're in error
|
||||
set_state(tree_ ? TS_READY : TS_ERROR);
|
||||
mutex_->Unlock();
|
||||
return false;
|
||||
}
|
||||
if (statbuf.st_mtime == filename_mtime_ && filename_mtime_ > 0
|
||||
&& tree_) { // force a reload if we don't already have a tree_
|
||||
VLOG(1) << "Not reloading file " << filename_ << ": no new mod-time" << endl;
|
||||
set_state(TS_READY);
|
||||
mutex_->Unlock();
|
||||
return false; // file's timestamp hasn't changed, so no need to reload
|
||||
}
|
||||
|
||||
|
@ -1451,7 +1401,6 @@ bool Template::ReloadIfChanged() {
|
|||
LOG(ERROR) << "Can't find file " << filename_ << "; skipping" << endl;
|
||||
// We keep the old tree if there is one, otherwise we're in error
|
||||
set_state(tree_ ? TS_READY : TS_ERROR);
|
||||
mutex_->Unlock();
|
||||
return false;
|
||||
}
|
||||
char* file_buffer = new char[statbuf.st_size];
|
||||
|
@ -1462,7 +1411,6 @@ bool Template::ReloadIfChanged() {
|
|||
delete[] file_buffer;
|
||||
// We could just keep the old tree, but probably safer to say 'error'
|
||||
set_state(TS_ERROR);
|
||||
mutex_->Unlock();
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
@ -1480,19 +1428,16 @@ bool Template::ReloadIfChanged() {
|
|||
// of input_buffer in every case, and will eventually delete it.
|
||||
if ( BuildTree(input_buffer, input_buffer + buflen) ) {
|
||||
assert(state() == TS_READY);
|
||||
mutex_->Unlock();
|
||||
return true;
|
||||
} else {
|
||||
assert(state() != TS_READY);
|
||||
mutex_->Unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Template::ReloadAllIfChanged() {
|
||||
LOCK(&g_cache_mutex); // this protects the static g_template_cache
|
||||
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache
|
||||
if (g_template_cache == NULL) {
|
||||
UNLOCK(&g_cache_mutex);
|
||||
return;
|
||||
}
|
||||
for (TemplateCache::const_iterator iter = g_template_cache->begin();
|
||||
|
@ -1500,7 +1445,6 @@ void Template::ReloadAllIfChanged() {
|
|||
++iter) {
|
||||
(*iter).second->set_state(TS_RELOAD);
|
||||
}
|
||||
UNLOCK(&g_cache_mutex);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -1509,9 +1453,8 @@ void Template::ReloadAllIfChanged() {
|
|||
// ----------------------------------------------------------------------
|
||||
|
||||
void Template::ClearCache() {
|
||||
LOCK(&g_cache_mutex); // this protects the static g_template_cache
|
||||
MutexLock ml(&g_cache_mutex); // this protects the static g_template_cache
|
||||
if (g_template_cache == NULL) {
|
||||
UNLOCK(&g_cache_mutex);
|
||||
return;
|
||||
}
|
||||
for (TemplateCache::const_iterator iter = g_template_cache->begin();
|
||||
|
@ -1521,7 +1464,6 @@ void Template::ClearCache() {
|
|||
}
|
||||
delete g_template_cache;
|
||||
g_template_cache = NULL;
|
||||
UNLOCK(&g_cache_mutex);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -1668,11 +1610,10 @@ bool Template::Expand(ExpandEmitter *expand_emitter,
|
|||
// tree_, and we want to make sure it doesn't do that (in another
|
||||
// thread) while we're expanding. We also protect state_, etc.
|
||||
// Note we only need a read-lock here, so many expands can go on at once.
|
||||
mutex_->LockRO();
|
||||
ReaderMutexLock ml(mutex_);
|
||||
|
||||
if (state() != TS_READY) {
|
||||
// We'd like to reload if state_ == TS_RELOAD, but we're a const method
|
||||
mutex_->Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1701,8 +1642,6 @@ bool Template::Expand(ExpandEmitter *expand_emitter,
|
|||
expand_emitter->Emit(TemplateNode::CloseAnnotation("FILE"));
|
||||
}
|
||||
|
||||
mutex_->Unlock();
|
||||
|
||||
return error_free;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,18 +33,11 @@
|
|||
// Based on the 'old' TemplateDictionary by Frank Jernigan.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// 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
|
||||
|
||||
#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h> // for varargs with StringAppendV
|
||||
#if defined(HAVE_PTHREAD) && !defined(NO_THREADS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <algorithm> // for sort
|
||||
#include <vector>
|
||||
|
@ -59,31 +52,7 @@ using std::string;
|
|||
using std::pair;
|
||||
using HASH_NAMESPACE::hash_map;
|
||||
|
||||
#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
|
||||
|
||||
#if defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) && !defined(NO_THREADS)
|
||||
# define STATIC_ROLOCK SAFE_PTHREAD(pthread_rwlock_rdlock(&g_static_mutex))
|
||||
# define STATIC_RWLOCK SAFE_PTHREAD(pthread_rwlock_wrlock(&g_static_mutex))
|
||||
# define STATIC_UNLOCK SAFE_PTHREAD(pthread_rwlock_unlock(&g_static_mutex))
|
||||
// PTHREAD_RWLOCK_INITIALIZER isn't defined on OS X, at least as of 6/1/06.
|
||||
// We use a static class instance to force initialization at program-start time.
|
||||
static pthread_rwlock_t g_static_mutex;
|
||||
namespace { // keep this class name from polluting the global namespace
|
||||
struct StaticMutexInit {
|
||||
StaticMutexInit() { SAFE_PTHREAD(pthread_rwlock_init(&g_static_mutex, NULL)); }
|
||||
};
|
||||
static StaticMutexInit g_static_mutex_initializer; // constructs early
|
||||
}
|
||||
#elif defined(HAVE_PTHREAD) && !defined(NO_THREADS)
|
||||
# define STATIC_ROLOCK SAFE_PTHREAD(pthread_mutex_lock(&g_static_mutex))
|
||||
# define STATIC_RWLOCK SAFE_PTHREAD(pthread_mutex_lock(&g_static_mutex))
|
||||
# define STATIC_UNLOCK SAFE_PTHREAD(pthread_mutex_unlock(&g_static_mutex))
|
||||
static pthread_mutex_t g_static_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#else
|
||||
# define STATIC_ROLOCK
|
||||
# define STATIC_RWLOCK
|
||||
# define STATIC_UNLOCK
|
||||
#endif
|
||||
static Mutex g_static_mutex;
|
||||
|
||||
/*static*/ TemplateDictionary::GlobalDict* TemplateDictionary::global_dict_
|
||||
= NULL;
|
||||
|
@ -133,10 +102,9 @@ TemplateDictionary::TemplateDictionary(const string& name, UnsafeArena* arena)
|
|||
parent_dict_(NULL),
|
||||
filename_(NULL),
|
||||
template_path_start_for_annotations_(NULL) {
|
||||
STATIC_RWLOCK;
|
||||
MutexLock ml(&g_static_mutex);
|
||||
if (global_dict_ == NULL)
|
||||
global_dict_ = SetupGlobalDictUnlocked();
|
||||
STATIC_UNLOCK;
|
||||
}
|
||||
|
||||
TemplateDictionary::TemplateDictionary(const string& name, UnsafeArena* arena,
|
||||
|
@ -154,10 +122,9 @@ TemplateDictionary::TemplateDictionary(const string& name, UnsafeArena* arena,
|
|||
parent_dict_(parent_dict),
|
||||
filename_(NULL),
|
||||
template_path_start_for_annotations_(NULL) {
|
||||
STATIC_RWLOCK;
|
||||
MutexLock ml(&g_static_mutex);
|
||||
if (global_dict_ == NULL)
|
||||
global_dict_ = SetupGlobalDictUnlocked();
|
||||
STATIC_UNLOCK;
|
||||
}
|
||||
|
||||
TemplateDictionary::~TemplateDictionary() {
|
||||
|
@ -190,10 +157,84 @@ TemplateDictionary::~TemplateDictionary() {
|
|||
if (template_global_dict_owner_) {
|
||||
delete template_global_dict_;
|
||||
}
|
||||
if (should_delete_arena_)
|
||||
if (should_delete_arena_) {
|
||||
delete arena_;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// TemplateDictionary::MakeCopy()
|
||||
// Makes a recursive copy: so we copy any include dictionaries and
|
||||
// section dictionaries we see as well. InternalMakeCopy() is
|
||||
// needed just so we can ensure that if we're doing a copy of a
|
||||
// subtree, it's due to a recursive call.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
TemplateDictionary* TemplateDictionary::InternalMakeCopy(
|
||||
const string& name_of_copy, UnsafeArena* arena) {
|
||||
TemplateDictionary* newdict;
|
||||
if (is_rootlevel_template()) { // rootlevel uses public constructor
|
||||
newdict = new TemplateDictionary(name_of_copy, arena);
|
||||
} else { // recursve calls use private contructor
|
||||
// Note: we always use our own arena, even when we have a parent
|
||||
newdict = new TemplateDictionary(name_of_copy, arena,
|
||||
parent_dict_, template_global_dict_);
|
||||
}
|
||||
|
||||
// Copy the variable dictionary
|
||||
for (VariableDict::const_iterator it = variable_dict_->begin();
|
||||
it != variable_dict_->end(); ++it) {
|
||||
newdict->SetValue(it->first, it->second);
|
||||
}
|
||||
// ...and the template-global-dict, if we're the owner of it
|
||||
if (template_global_dict_owner_) {
|
||||
for (VariableDict::const_iterator it = template_global_dict_->begin();
|
||||
it != template_global_dict_->end(); ++it) {
|
||||
newdict->SetTemplateGlobalValue(it->first, it->second);
|
||||
}
|
||||
}
|
||||
// Copy the section dictionary
|
||||
for (SectionDict::iterator it = section_dict_->begin();
|
||||
it != section_dict_->end(); ++it) {
|
||||
DictVector* dicts = new DictVector;
|
||||
(*newdict->section_dict_)[newdict->Memdup(it->first)] = dicts;
|
||||
for (DictVector::iterator it2 = it->second->begin();
|
||||
it2 != it->second->end(); ++it2) {
|
||||
TemplateDictionary* subdict = *it2;
|
||||
dicts->push_back(subdict->InternalMakeCopy(subdict->name(),
|
||||
newdict->arena_));
|
||||
}
|
||||
}
|
||||
// Copy the includes-dictionary
|
||||
for (IncludeDict::iterator it = include_dict_->begin();
|
||||
it != include_dict_->end(); ++it) {
|
||||
DictVector* dicts = new DictVector;
|
||||
(*newdict->include_dict_)[newdict->Memdup(it->first)] = dicts;
|
||||
for (DictVector::iterator it2 = it->second->begin();
|
||||
it2 != it->second->end(); ++it2) {
|
||||
TemplateDictionary* subdict = *it2;
|
||||
dicts->push_back(subdict->InternalMakeCopy(subdict->name(),
|
||||
newdict->arena_));
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, copy everything else not set properly by the constructor
|
||||
newdict->filename_ = newdict->Memdup(filename_);
|
||||
newdict->template_path_start_for_annotations_ =
|
||||
newdict->Memdup(template_path_start_for_annotations_);
|
||||
|
||||
return newdict;
|
||||
}
|
||||
|
||||
TemplateDictionary* TemplateDictionary::MakeCopy(const string& name_of_copy,
|
||||
UnsafeArena* arena) {
|
||||
if (!is_rootlevel_template()) { // we're not at the root, which is illegal
|
||||
return NULL;
|
||||
}
|
||||
return InternalMakeCopy(name_of_copy, arena);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// TemplateDictionary::StringAppendV()
|
||||
// Does an snprintf to a string. Idea is to grow string as needed.
|
||||
|
@ -325,11 +366,10 @@ void TemplateDictionary::SetTemplateGlobalValue(const TemplateString variable,
|
|||
memcpy(value_copy, value.ptr_, value.length_);
|
||||
value_copy[value.length_] = '\0';
|
||||
|
||||
STATIC_RWLOCK;
|
||||
MutexLock ml(&g_static_mutex);
|
||||
if (global_dict_ == NULL)
|
||||
global_dict_ = SetupGlobalDictUnlocked();
|
||||
(*global_dict_)[variable_copy] = value_copy;
|
||||
STATIC_UNLOCK;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -485,9 +525,8 @@ void TemplateDictionary::DumpToString(string* out, int indent) const {
|
|||
|
||||
vector<pair<const char*, const char*> > sorted_global_dict;
|
||||
{
|
||||
STATIC_ROLOCK;
|
||||
ReaderMutexLock ml(&g_static_mutex);
|
||||
SortByStringKeyInto(*global_dict_, &sorted_global_dict);
|
||||
STATIC_UNLOCK;
|
||||
}
|
||||
for (vector<pair<const char*, const char*> >::const_iterator it
|
||||
= sorted_global_dict.begin();
|
||||
|
@ -682,12 +721,11 @@ const char *TemplateDictionary::GetSectionValue(const string& variable) const {
|
|||
|
||||
// No match in dict tree or template-global dict. Last chance: global dict.
|
||||
{
|
||||
STATIC_ROLOCK;
|
||||
ReaderMutexLock ml(&g_static_mutex);
|
||||
GlobalDict::const_iterator it = global_dict_->find(variable.c_str());
|
||||
const char* retval = ""; // what we'll return if global lookup fails
|
||||
if (it != global_dict_->end())
|
||||
retval = it->second;
|
||||
STATIC_UNLOCK;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
@ -842,26 +880,22 @@ string TemplateDictionary::UrlQueryEscape::operator()(const string& in) const {
|
|||
0x00000000L, 0x00000000L, 0x00000000L, 0x00000000L
|
||||
};
|
||||
|
||||
int max_string_length = in.size() * 3 + 1;
|
||||
char out[max_string_length];
|
||||
string out;
|
||||
out.reserve(in.size() * 3 + 1);
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0, j = 0; i < in.size(); i++) {
|
||||
for (int i = 0; i < in.size(); i++) {
|
||||
unsigned char c = in[i];
|
||||
if (c == ' ') {
|
||||
out[j++] = '+';
|
||||
out += '+';
|
||||
} else if ((_safe_characters[(c)>>5] & (1 << ((c) & 31)))) {
|
||||
out[j++] = c;
|
||||
out += c;
|
||||
} else {
|
||||
out[j++] = '%';
|
||||
out[j++] = ((c>>4) < 10 ? ((c>>4) + '0') : (((c>>4) - 10) + 'A'));
|
||||
out[j++] = ((c&0xf) < 10 ? ((c&0xf) + '0') : (((c&0xf) - 10) + 'A'));
|
||||
out += '%';
|
||||
out += ((c>>4) < 10 ? ((c>>4) + '0') : (((c>>4) - 10) + 'A'));
|
||||
out += ((c&0xf) < 10 ? ((c&0xf) + '0') : (((c&0xf) - 10) + 'A'));
|
||||
}
|
||||
}
|
||||
out[j++] = '\0';
|
||||
return string(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Escapes " / \ <BS> <FF> <CR> <LF> <TAB> to \" \/ \\ \b \f \r \n \t
|
||||
|
|
|
@ -32,10 +32,8 @@
|
|||
//
|
||||
|
||||
#include "config.h"
|
||||
#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
|
||||
#include <assert.h>
|
||||
#if defined(HAVE_PTHREAD) && !defined(NO_THREADS)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <google/ctemplate/hash_map.h>
|
||||
#include <google/template_from_string.h>
|
||||
|
@ -43,21 +41,12 @@
|
|||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
#if defined(HAVE_PTHREAD) && !defined(NO_THREADS)
|
||||
# define LOCK(m) pthread_mutex_lock(m)
|
||||
# define UNLOCK(m) pthread_mutex_unlock(m)
|
||||
// This is used to protect g_template_from_string_cache, below
|
||||
static pthread_mutex_t g_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#else
|
||||
# define LOCK(m)
|
||||
# define UNLOCK(m)
|
||||
#endif
|
||||
static Mutex g_cache_mutex;
|
||||
|
||||
using std::string;
|
||||
using std::pair;
|
||||
using HASH_NAMESPACE::hash_map;
|
||||
|
||||
|
||||
// TemplateFromString Constructor
|
||||
// Calls its parent with an empty string for filename so the parent's
|
||||
// constructor will not try to "load" the template from a file. Instead,
|
||||
|
@ -111,7 +100,7 @@ TemplateFromString *TemplateFromString::GetTemplate(const string& template_name,
|
|||
Strip strip) {
|
||||
// Only perform this method when you have the lock so multiple threads
|
||||
// don't conflict over inserting and retrieving into the cache
|
||||
LOCK(&g_cache_mutex);
|
||||
MutexLock ml(&g_cache_mutex);
|
||||
if (g_template_from_string_cache == NULL) {
|
||||
g_template_from_string_cache = new TemplateFromStringCache;
|
||||
}
|
||||
|
@ -126,7 +115,6 @@ TemplateFromString *TemplateFromString::GetTemplate(const string& template_name,
|
|||
(*g_template_from_string_cache)[pair<string, Strip>(template_name, strip)] =
|
||||
tpl;
|
||||
}
|
||||
UNLOCK(&g_cache_mutex); // done messing with the cache
|
||||
|
||||
// state_ can be TS_RELOAD if ReloadAllIfChanged() touched this file.
|
||||
// That's fine; we'll just ignore the reload directive for this guy.
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include <string>
|
||||
#include <vector> // that's MissingListType, SyntaxListType
|
||||
#include <iostream> // for cerr
|
||||
#include <algorithm> // for find()
|
||||
#include <algorithm> // for binary_search
|
||||
#include <google/ctemplate/hash_set.h> // that's NameListType
|
||||
#include <google/template_namelist.h>
|
||||
#include <google/template.h> // for Strip, GetTemplate(), etc.
|
||||
|
@ -96,6 +96,7 @@ const TemplateNamelist::NameListType& TemplateNamelist::GetList() {
|
|||
// and adds to the list any that are missing
|
||||
// On subsequent calls, if refresh is false it merely returns the
|
||||
// list created in the prior call that refreshed the list.
|
||||
// Returns a sorted list of missing templates.
|
||||
const TemplateNamelist::MissingListType& TemplateNamelist::GetMissingList(
|
||||
bool refresh) {
|
||||
if (!missing_list_) {
|
||||
|
@ -158,11 +159,9 @@ const TemplateNamelist::SyntaxListType& TemplateNamelist::GetBadSyntaxList(
|
|||
++iter) {
|
||||
Template *tpl = Template::GetTemplate((*iter), strip);
|
||||
if (!tpl) {
|
||||
MissingListType::const_iterator pos =
|
||||
find(missing_list.begin(), missing_list.end(), (*iter));
|
||||
// If it's not in the missing list, then we're here because it caused
|
||||
// an error during parsing
|
||||
if (pos == missing_list.end()) {
|
||||
if (!binary_search(missing_list.begin(), missing_list.end(), *iter)) {
|
||||
// If it's not in the missing list, then we're here because
|
||||
// it caused an error during parsing
|
||||
bad_syntax_list_->push_back(*iter);
|
||||
std::cerr << "ERROR loading template: " << (*iter) << std::endl;
|
||||
}
|
||||
|
|
|
@ -771,6 +771,57 @@ class TemplateDictionaryUnittest {
|
|||
"}\n");
|
||||
ASSERT_STREQ(dump.c_str(), expected);
|
||||
}
|
||||
|
||||
static void TestMakeCopy(bool use_local_arena) {
|
||||
UnsafeArena local_arena(1024);
|
||||
UnsafeArena* arena = NULL;
|
||||
if (use_local_arena)
|
||||
arena = &local_arena;
|
||||
|
||||
// First, let's make a non-trivial template dictionary (We use
|
||||
// 'new' because later we'll test deleting this dict but keeping
|
||||
// around the copy.)
|
||||
TemplateDictionary* dict = new TemplateDictionary("testdict", arena);
|
||||
|
||||
dict->SetValue("TOPLEVEL", "foo");
|
||||
|
||||
dict->SetTemplateGlobalValue("TEMPLATELEVEL", "foo3");
|
||||
|
||||
TemplateDictionary* subdict_1a = dict->AddIncludeDictionary("include1");
|
||||
subdict_1a->SetFilename("incfile1a");
|
||||
subdict_1a->SetValue("SUBLEVEL", "subfoo");
|
||||
TemplateDictionary* subdict_1b = dict->AddIncludeDictionary("include1");
|
||||
// Let's try not calling SetFilename on this one.
|
||||
subdict_1b->SetValue("SUBLEVEL", "subbar");
|
||||
|
||||
TemplateDictionary* subdict_2a = dict->AddSectionDictionary("section1");
|
||||
TemplateDictionary* subdict_2b = dict->AddSectionDictionary("section1");
|
||||
subdict_2a->SetValue("SUBLEVEL", "subfoo");
|
||||
subdict_2b->SetValue("SUBLEVEL", "subbar");
|
||||
TemplateDictionary* subdict_3 = dict->AddSectionDictionary("section2");
|
||||
subdict_3->SetValue("TOPLEVEL", "bar"); // overriding top dict
|
||||
TemplateDictionary* subdict_3_1 = subdict_3->AddSectionDictionary("sub");
|
||||
subdict_3_1->SetIntValue("GLOBAL", 21); // overrides value in setUp()
|
||||
|
||||
string orig;
|
||||
dict->DumpToString(&orig);
|
||||
|
||||
// Make a copy
|
||||
TemplateDictionary* dict_copy = dict->MakeCopy("testdict", NULL);
|
||||
// Make sure it doesn't work to copy a sub-dictionary
|
||||
ASSERT(subdict_1a->MakeCopy("copy of subdict") == NULL);
|
||||
ASSERT(subdict_2a->MakeCopy("copy of subdict") == NULL);
|
||||
|
||||
// Delete the original dict, to make sure the copy really is independent
|
||||
delete dict;
|
||||
dict = NULL;
|
||||
string copy;
|
||||
dict_copy->DumpToString(©);
|
||||
delete dict_copy;
|
||||
|
||||
ASSERT_STREQ(orig.c_str(), copy.c_str());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
@ -792,6 +843,9 @@ int main(int argc, char** argv) {
|
|||
TemplateDictionaryUnittest::TestSetTemplateGlobalValue();
|
||||
TemplateDictionaryUnittest::TestAddIncludeDictionary();
|
||||
|
||||
TemplateDictionaryUnittest::TestMakeCopy(true); // use our own arena
|
||||
TemplateDictionaryUnittest::TestMakeCopy(false); // use fake arena
|
||||
|
||||
printf("DONE.\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -47,17 +47,17 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#if HAVE_DIRENT_H
|
||||
#include <dirent.h> // for opendir() etc
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h> // for opendir() etc
|
||||
#else
|
||||
# define dirent direct
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
|
|
@ -40,17 +40,17 @@
|
|||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h> // for mkdir
|
||||
#if HAVE_DIRENT_H
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h> // for readdir
|
||||
#else
|
||||
# define dirent direct
|
||||
# if HAVE_SYS_NDIR_H
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if HAVE_SYS_DIR_H
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# if HAVE_NDIR_H
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue
Block a user