ctemplate (empty) → 0.1
raw patch · 8 files changed
+219/−0 lines, 8 filesdep +basedep +bytestringsetup-changed
Dependencies added: base, bytestring
Files
- LICENSE +30/−0
- Setup.lhs +3/−0
- Text/CTemplate.hs +90/−0
- cbits/ctemplate.cc +50/−0
- ctemplate.cabal +25/−0
- examples/example.hs +11/−0
- examples/included.tmpl +1/−0
- examples/test.tmpl +9/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) Adam Langley++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. 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.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE 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 AUTHORS 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.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ Text/CTemplate.hs view
@@ -0,0 +1,90 @@+-- | CTemplate is the template system that Google uses for many of their sites,+-- including the search results from the main www.google.com web search. It's+-- simple templating system, but has easy to use escaping functions.+--+-- See <http://goog-ctemplate.sourceforge.net/doc/howto.html> for+-- documentation (esp see the Tips link at the end of that)+module Text.CTemplate+ ( Dictionary(..)+ , Variable(..)+ , Option(..)+ , expand+ , setTemplateRootDirectory+ ) where++import Foreign+import Foreign.C+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as B++-- | This is a dictionary. Relative filenames are resolved in the current+-- directory+data Dictionary = Dictionary FilePath [(String, Variable)] deriving (Show, Eq)++data Variable = StringV String -- ^ a string value (note - no char encoding performed)+ | BSV B.ByteString -- ^ a string value from a ByteString+ | SectionV [[(String, Variable)]] -- ^ a (possibly repeated) section+ | IncludedV Dictionary -- ^ an included dictionary+ deriving (Show, Eq)++data Option = DontStrip+ | StripBlankLines+ | StripWhitespace+ deriving (Show, Eq, Enum)++-- | This is the type of the C-side dictionary object+data Dictionary_+-- | Likewise, this is the type of the C-side template+data Template_++foreign import ccall unsafe "ct_load_template" _load_template :: CString -> CInt -> IO (Ptr Template_)+foreign import ccall unsafe "ct_new_dict" _new_dict :: IO (Ptr Dictionary_)+foreign import ccall unsafe "ct_set_string" _set_string :: Ptr Dictionary_ -> CString -> CString -> IO ()+foreign import ccall unsafe "ct_set_bytes" _set_bytes :: Ptr Dictionary_ -> CString -> Ptr CChar -> CInt -> IO ()+foreign import ccall unsafe "ct_new_section" _new_section :: Ptr Dictionary_ -> CString -> IO (Ptr Dictionary_)+foreign import ccall unsafe "ct_new_included" _new_included :: Ptr Dictionary_ -> CString -> IO (Ptr Dictionary_)+foreign import ccall unsafe "ct_set_filename" _set_filename :: Ptr Dictionary_ -> CString -> IO ()+foreign import ccall unsafe "ct_expand" _expand :: Ptr Template_ -> Ptr Dictionary_ -> IO (Ptr CChar)++translateVariable :: Ptr Dictionary_ -> (String, Variable) -> IO ()+translateVariable dict (v, StringV s) =+ withCString v $ \v ->+ withCString s $ \s ->+ _set_string dict v s++translateVariable dict (v, BSV bs) =+ withCString v $ \v ->+ B.unsafeUseAsCStringLen bs $ \(ptr, len) ->+ _set_bytes dict v ptr $ fromIntegral len++translateVariable dict (v, SectionV varses) =+ withCString v $ \v ->+ flip mapM_ varses $ \vars ->+ _new_section dict v >>= \dict -> mapM_ (translateVariable dict) vars++translateVariable dict (v, IncludedV (Dictionary filename vars)) =+ withCString v $ \v ->+ _new_included dict v >>= \dict ->+ withCString filename $ \ptr ->+ _set_filename dict ptr >> mapM_ (translateVariable dict) vars++-- | Expand a template given the values to fill it+expand :: Option -> Dictionary -> IO (Maybe B.ByteString)+expand option (Dictionary filename vars) = do+ template <- withCString filename $ \ptr -> _load_template ptr $ fromIntegral $ fromEnum option+ if template == nullPtr+ then return Nothing+ else do dict <- _new_dict+ mapM_ (translateVariable dict) vars+ str <- _expand template dict+ bs <- B.packCString str+ free str+ return $ Just bs++foreign import ccall unsafe "ct_set_root" _set_root :: Ptr CChar -> IO ()++-- | Set the directory where templates with non-absolute filenames will be+-- loaded from+setTemplateRootDirectory :: FilePath -> IO ()+setTemplateRootDirectory filename =+ withCString filename $ \ptr -> _set_root ptr
+ cbits/ctemplate.cc view
@@ -0,0 +1,50 @@+#include <string>+#include <stdio.h>+#include <stdlib.h>+#include <google/template.h>++extern "C" {+void *ct_load_template(const char *filename, int option) {+ return google::Template::GetTemplate(filename, (google::Strip) option);+}++void *ct_new_dict() {+ return new google::TemplateDictionary("");+}++void ct_set_string(google::TemplateDictionary *dict, const char *key,+ const char *value) {+ dict->SetValue(key, value);+}++void ct_set_bytes(google::TemplateDictionary *dict, const char *key, const char *bytes,+ const int length) {+ dict->SetValue(key, std::string(bytes, length));+}++void *ct_new_section(google::TemplateDictionary *dict, const char *key) {+ return dict->AddSectionDictionary(key);+}++void *ct_new_included(google::TemplateDictionary *dict, const char *key) {+ return dict->AddIncludeDictionary(key);+}++void ct_set_filename(google::TemplateDictionary *dict, const char *filename) {+ dict->SetFilename(filename);+}++char *ct_expand(google::Template *tmpl, google::TemplateDictionary *dict) {+ std::string result;+ tmpl->Expand(&result, dict);+ char *ret = (char *) malloc(result.size() + 1);+ memcpy(ret, result.c_str(), result.size() + 1);++ return ret;+}++void ct_set_root(const char *path) {+ google::Template::SetTemplateRootDirectory(path);+}++}
+ ctemplate.cabal view
@@ -0,0 +1,25 @@+Name: ctemplate+Synopsis: Binding to the Google ctemplate library+Description:+ CTemplate is the library that Google uses to render most of their sites+ (including the www.google.com search). It's a simple templating system, but+ includes many, easy to use, escaping functions.+Version: 0.1+License: BSD3+License-File: LICENSE+Author: Adam Langley <agl@imperialviolet.org>+Stability: experimental+Homepage: http://darcs.imperialviolet.org/ctemplate+Category: Text+Tested-With: GHC == 6.8.2+Build-Depends: base, bytestring+Exposed-Modules: Text.CTemplate+Extensions: ForeignFunctionInterface, EmptyDataDecls+ghc-options: -Wall -fno-warn-name-shadowing+build-type: Simple+C-Sources: cbits/ctemplate.cc+Extra-Source-Files:+ examples/test.tmpl+ examples/included.tmpl+ examples/example.hs+Extra-Libraries: ctemplate
+ examples/example.hs view
@@ -0,0 +1,11 @@+module Main where++import qualified Data.ByteString as B+import Text.CTemplate++main = do+ Just bs <- expand DontStrip $ Dictionary "test.tmpl"+ [("NAME", StringV "Adam"), ("S", SectionV [[("VALUE", StringV "0")], [("VALUE", StringV "1")]]),+ ("INCLUDED", IncludedV $ Dictionary "included.tmpl" []),+ ("HTML", StringV "<br>")]+ B.putStr bs
+ examples/included.tmpl view
@@ -0,0 +1,1 @@+This is an included template
+ examples/test.tmpl view
@@ -0,0 +1,9 @@+Hello {{NAME}}, NAME is a simple variable,+{{#S}}This is a repeatable section, with a value: {{VALUE}}+{{/S}}++If you don't give a value for a variable, it ends up "{{NONAME}}" (blank)++{{>INCLUDED}}++We can try an include HTML in the following, but it will be escaped: {{HTML:h}}