OSDN Git Service

Import from darcs trunk
authorHiroki Hattori (seagull) <seagull@mitsuki.no-ip.com>
Thu, 27 Dec 2007 08:09:05 +0000 (17:09 +0900)
committerHiroki Hattori (seagull) <seagull@mitsuki.no-ip.com>
Thu, 27 Dec 2007 08:09:05 +0000 (17:09 +0900)
Thu Aug 23 09:55:48 JST 2007  seagull@mitsuki.no-ip.com
  * misc changes

Mon Jul 30 14:22:20 JST 2007  seagull@mitsuki.no-ip.com
  * Add new function

Mon Jul 30 10:56:02 JST 2007  seagull@mitsuki.no-ip.com
  * Cleanup

Fri Jul 27 16:31:11 JST 2007  seagull@mitsuki.no-ip.com
  * add CR:include tag

Thu Jul 26 23:01:46 JST 2007  seagull@mitsuki.no-ip.com
  * Add new feature.

  Add template loader class.

  Template loader manages set of templates.

Thu Jul 26 09:20:24 JST 2007  seagull@mitsuki.no-ip.com
  * Fix invalid macro names.

Mon Jul 23 15:44:04 JST 2007  seagull@mitsuki.no-ip.com
  * Add G_BEGIN_DECLS to each headers.

F

42 files changed:
.gitignore [new file with mode: 0644]
NEWS
TODO
bindings/haskell/Text/TemplateEngine/CoolRain/Internal.hs [new file with mode: 0644]
bindings/haskell/Text/TemplateEngine/CoolRain/Loader.hs [new file with mode: 0644]
bindings/haskell/Text/TemplateEngine/CoolRain/Writer.hs [new file with mode: 0644]
configure.ac
examples/greeting_2.template [new file with mode: 0644]
examples/inctest.template [new file with mode: 0644]
examples/inctest_1.template [new file with mode: 0644]
examples/inctest_2.template [new file with mode: 0644]
examples/runcoolrain.c
include/CoolRain/CoolRain.h
include/CoolRain/CoolRain.hpp
include/CoolRain/Makefile.am
include/CoolRain/error.h
include/CoolRain/fragment.h
include/CoolRain/loader.h [new file with mode: 0644]
include/CoolRain/memory.h
include/CoolRain/refstring.h
include/CoolRain/stash.h
include/CoolRain/tagset.h
include/CoolRain/template.h
include/CoolRain/thread.h
include/CoolRain/variant.h
include/CoolRain/version.h.in
include/CoolRain/writer.h
src/Makefile.am
src/builtin_tag.c
src/builtin_tag_gkeyfile.c
src/fragment.c
src/loader.c [new file with mode: 0644]
src/stash.c
src/tagset.c
src/template.c
src/variant.c
src/writer_fcgi.c [new file with mode: 0644]
tests/Makefile.am
tests/runtest.c
tests/templates/t1.template [new file with mode: 0644]
tests/test_loader.c [new file with mode: 0644]
tests/test_stash.c

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..05fcf21
--- /dev/null
@@ -0,0 +1,14 @@
+*~
+*.bak
+stamp-h1
+Makefile.in
+configure
+aclocal.m4
+*.cache
+config.guess
+config.h.in
+config.sub
+compile
+depcomp
+install-sh
+missing
diff --git a/NEWS b/NEWS
index e55f860..4a2c039 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,15 +1,17 @@
 
-coolrain-0.3.1
-================
-
-       * Add new plugin tags to manipulate keyfile  'CR:KF:with', 'CR:KF:withLocale' and 'CR:KF:value'.
-         See examples/greeting.template
 
+coolrain-0.3.x
+=================
 
+       == 0.3.2 ==
+       * Add template loader. The loader manage set of templates.
+       * Add new tags 'CR:include' and 'CR:param' to include other template module.
 
-coolrain-0.3.0
-=================
+       == 0.3.1 ==
+       * Add new tags to manipulate keyfile  'CR:KF:with', 'CR:KF:withLocale' and 'CR:KF:value'.
+         See examples/greeting.template
 
+       == 0.3.0 ==
        * Fix bugs.
        * Add builtin tag
                'CR:pass', 'CR:ignore', 'CR:loop', 'CR:let' and 'CR:var' is present.
diff --git a/TODO b/TODO
index 0cc3901..7c4e179 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2,8 +2,6 @@
 
 New subsystem
 ==============
-* Template repository (Template factory)
-* I18N message catalog. (gettext / keyfile)
 * Global error handler.
 
 
@@ -55,4 +53,7 @@ Language binding
 * C++ class wrapper
 
 
+Test
+============
+* マルチスレッド動作の検証を行う。
 
diff --git a/bindings/haskell/Text/TemplateEngine/CoolRain/Internal.hs b/bindings/haskell/Text/TemplateEngine/CoolRain/Internal.hs
new file mode 100644 (file)
index 0000000..bc950a5
--- /dev/null
@@ -0,0 +1,25 @@
+--
+--
+--
+module Text.TemplateEngine.CoolRain.Internal (
+    isArch32, dptrsize, cptrsize, archAlignmentSize,
+    ) where
+
+import Foreign.Ptr
+
+{-# INLINE #-}
+isArch32 = case dptrsize of
+                4 -> True
+                8 -> False
+                otherwise -> error "Unknown architecture"
+
+{-# INLINE #-}
+dptrsize = sizeOf nullPtr
+
+{-# INLINE #-}
+cptrsize = sizeOf nullFunPtr
+
+{-# INLINE #-}
+archAlignmentSize = dptrsize
+
+
diff --git a/bindings/haskell/Text/TemplateEngine/CoolRain/Loader.hs b/bindings/haskell/Text/TemplateEngine/CoolRain/Loader.hs
new file mode 100644 (file)
index 0000000..68e68f9
--- /dev/null
@@ -0,0 +1,107 @@
+--
+--
+--
+--
+module Text.TemplateEngine.CoolRain.Loader (
+        --
+        LoaderOps,
+
+        --
+        Loader,
+        newFileLoader,
+        getTagset, loadTemplate, processTemplate
+
+    ) where
+--
+
+import Control.Monad
+import Foreign.Ptr
+import Foreign.ForeignPtr
+import Foreign.Storable
+import Foreign.Type
+
+import Text.TemplateEngine.CoolRain.Internal
+import Text.TemplateEngine.CoolRain.Tagset
+import Text.TemplateEngine.CoolRain.Stash
+import Text.TemplateEngine.CoolRain.Writer
+
+
+--
+data LoaderOps =
+    LoaderOps {
+        loader_ops_load         : FunPtr (Ptr Loader' -> Ptr Template -> CString -> IO Int),
+        loader_ops_destroy      : FunPtr (Ptr Loader' -> IO ())
+    }
+
+instance Storable LoaderOps where
+    sizeOf _    = dptrsize * 2
+    alignment _ = archAlignmentSize
+    peek x      = return LoadOps
+        `ap` peekElementOf x 0
+        `ap` peekElementOf x 1
+    poke x y    = do
+        pokeElementOf x 0 $ loader_ops_loader y
+        pokeElementOf x 1 $ loader_ops_destroy y
+
+
+--
+--
+--
+newtype Loader = Loader ForeignPtr ()
+
+
+mallocLoader :: IO Loader
+mallocLoader = do
+    x <- mallocForeignPtrBytes (if isArch32 then 16 else 28)
+    return $ Loader x
+
+withLoaderPtr (Loader x) = withForeignPtr x
+
+
+
+
+newFileLoader :: Maybe Tagset -> String -> IO (Either Loader Int)
+newFileLoader tagset basedir = do
+    x <- mallocLoader
+    r <- withCString basedir (\c_basedir -> withForeignPtr x (\p ->
+        coolrain_file_loader_initialize p (maybe nullPtr unsafeForeignPtrToPtr tagset) c_basedir))
+    if r == 0
+        then do
+            addForeignPtrFinalizer coolrain_loader_destroy x
+            return $ Left $ Loader x
+        else Right r
+
+
+
+getTagset :: Loader -> Tagset
+getTagset loader = withLoaderPtr loader (\loader' -> unsafePerformIO $ newForepginPtr $ peekByteOff loader' (isArch32 12 24))
+
+
+
+loadTemplate :: Loader -> Template -> String -> IO Int
+loadTemplate loader tmpl name =
+    return $ withCString name $ withForeignPtr template $ withLoaderPtr loader coolrain_loader_load_template
+
+
+processTemplate :: Loader -> String -> Stash -> Writer -> IO Int
+processTemplate loader name stash writer =
+    return $ withForeignPtr writer $ withForeignPtr stash $ withCString name $ withLoaderPtr loader coolrain_loader_process_template
+
+
+--
+--
+--
+
+-- Foreign import ccall "CoolRain/CoolRain.h coolrain_loader_initialize" coolrain_file_loader_initialize :: Ptr () -> Ptr () -> Ptr () -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_loader_destroy" coolrain_loader_destroy :: Ptr () -> IO ()
+
+
+-- Foreign import ccall "CoolRain/CoolRain.h coolrain_file_loader_set_error_handler" coolrain_file_loader_initialize :: Ptr () -> 
+
+Foreign import ccall "CoolRain/CoolRain.h coolrain_loader_load_template" coolrain_loader_load_template :: Ptr () -> Ptr () -> CString -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_loader_process_template" coolrain_loader_process_template :: Ptr () -> CString -> Ptr () -> Ptr () -> IO CInt
+
+Foreign import ccall "CoolRain/CoolRain.h coolrain_file_loader_initialize" coolrain_file_loader_initialize :: Ptr () -> Ptr () -> CString -> IO CInt
+
+
+
diff --git a/bindings/haskell/Text/TemplateEngine/CoolRain/Writer.hs b/bindings/haskell/Text/TemplateEngine/CoolRain/Writer.hs
new file mode 100644 (file)
index 0000000..b8f5fb4
--- /dev/null
@@ -0,0 +1,51 @@
+--
+--
+--
+module Text.TemplateEngine.CoolRain.Writer (
+    ) where
+
+
+--
+import Foreing.Ptr
+import Foreign.ForeignPtr
+
+
+import Text.TemplateEngine.CoolRain.Internal
+
+--
+newtype Writer = Writer (ForeignPtr ())
+
+type WriterBufferFullHandler    = Writer -> IO Int
+type WriterBufferFullHandler'   = Ptr () -> IO Int
+type WriterDestroyHandler       = Writer -> IO ()
+type WriterDestroyHandler'      = Ptr () -> IO ()
+type WriterWriteHandler         = Writer -> CString -> CUInt -> IO Int
+type WriterWriteHandler'        = Ptr () -> CString -> CUInt -> IO Int
+
+
+mallocWriter : IO ForeignPtr ()
+mallocWriter = mallocForeignPtr (isArch32 
+
+newBufferWriter : CString -> CUInt -> IO Writer
+newBufferWriter buffer len =
+
+newFDWriter : CUInt -> Bool -> IO Writer
+newFDWriter fd autoclose =
+
+
+--
+
+
+
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_initialize" coolrain_writer_initialize : Ptr () -> Char () -> CUInt -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_destroy" coolrain_writer_destroy : Ptr () -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_chain" coolrain_writer_chain : Ptr () -> Ptr () -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_write" coolrain_writer_write : Ptr () -> CString -> CUInt -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_flush" coolrain_writer_flush : Ptr () -> IO CInt
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_drop" coolrain_writer_drop : Ptr () -> CUInt -> IO CInt
+
+Foreign import ccall "CoolRain/CoolRain.h coolrain_writer_reserve" coolrain_writer_resetve : Ptr () -> CUInt -> IO CString
+
+Foreign import ccall "CoolRain/CoolRain.h coolrain_fd_writer_initialize" coolrain_fd_writer_initialize : Ptr () -> CInt -> CInt -> IO CInt
+-- Foreign import ccall "CoolRain/CoolRain.h coolrain_FCGI_writer_initialize" coolrain_FCGI_writer_initialize : 
+
index f0eb466..e5760f7 100644 (file)
@@ -49,7 +49,7 @@ if test "$enable_debug" == "yes"; then
 AC_DEFINE(COOLRAIN_ENABLE_DEBUG, 1, [Enable debug build])
 CFLAGS="$CFLAGS -O0 -g"
 else
-CFLAGS="$CFLAGS -O99"
+CFLAGS="$CFLAGS -O3 -fno-schedule-insns2"
 fi
 
 dnl
@@ -114,7 +114,7 @@ AC_CHECK_HEADERS([fcgiapp.h])
 
 
 if test "$GCC" = "yes"; then
-  CFLAGS="$CFLAGS -Wall -Wextra -ffunction-sections"
+  CFLAGS="$CFLAGS -Wall -Wextra -ffunction-sections -Wstrict-prototypes"
   LDFLAGS="-Wl,--gc-sections"
 fi
 
diff --git a/examples/greeting_2.template b/examples/greeting_2.template
new file mode 100644 (file)
index 0000000..761c723
--- /dev/null
@@ -0,0 +1,17 @@
+<CR:loop from="0" to="10" step="1">
+
+  <CR:KF:value name="Greeting.Say" />, <CR:KF:value name="Greeting.Ack" />
+  <CR:KF:value name='Visible.Colors' />
+
+  <CR:KF:withLocale lang="ja">
+    <CR:KF:value name="Greeting.Say" />, <CR:KF:value name="Greeting.Ack" />
+    <CR:KF:value name='Visible.Colors' />
+  </CR:KF:withLocale>
+
+  <CR:KF:withLocale lang="en">
+    <CR:KF:value name="Greeting.Say" />, <CR:KF:value name="Greeting.Ack" />
+    <CR:KF:value name='Visible.Colors' />
+  </CR:KF:withLocale>
+
+</CR:loop>
+
diff --git a/examples/inctest.template b/examples/inctest.template
new file mode 100644 (file)
index 0000000..c7bb5f8
--- /dev/null
@@ -0,0 +1,11 @@
+<CR:let foo="OOF" bar="RAB" baz="ZAB">
+<CR:include href="inctest_1.template" />
+</CR:let>
+
+<CR:let hoge="I love lexycal scopeing rule.">
+<CR:include href="inctest_1.template">
+  <CR:param name="foo">FOO_1</CR:param>
+  <CR:param name="bar"><CR:include href="inctest_2.template" /></CR:param>
+  <CR:param name="baz">${hoge}</CR:param>
+</CR:include>
+</CR:let>
diff --git a/examples/inctest_1.template b/examples/inctest_1.template
new file mode 100644 (file)
index 0000000..215c1c8
--- /dev/null
@@ -0,0 +1,5 @@
+-------< BEGIN inctest_1.template
+${foo}
+${bar}
+<CR:let hoge="Fuckin dynamic scoping!">${baz}</CR:let>
+-------< END inctest_1.template
diff --git a/examples/inctest_2.template b/examples/inctest_2.template
new file mode 100644 (file)
index 0000000..ce4bc53
--- /dev/null
@@ -0,0 +1 @@
+<<INCTEST_2.TEMPLATE>>
index dac9eaf..48a23d8 100644 (file)
@@ -24,8 +24,9 @@ static void my_error_handler(struct coolrain_template *tmpl G_GNUC_UNUSED, char
 int main(int argc, char *argv[])
 {
        int r;
+       struct coolrain_loader loader;
+
        struct coolrain_template tmpl;
-       struct coolrain_tagset tagset;
        struct coolrain_stash stash;
        struct coolrain_writer writer;
        struct coolrain_stash_value_list *gkeyfile_vl = NULL;
@@ -35,16 +36,17 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        }
 
-       coolrain_tagset_initialize(&tagset);
-       coolrain_tagset_register_tags(&tagset, coolrain_tagset_default_tags);
-       coolrain_tagset_register_tags(&tagset, coolrain_tagset_gkeyfile_tags);
-       coolrain_tagset_register_filters(&tagset, coolrain_tagset_default_filters);
 
-       coolrain_template_initialize(&tmpl, &tagset);
+       coolrain_file_loader_initialize(&loader, NULL, ".");
+
+       coolrain_tagset_register_tags(loader.tagset, coolrain_tagset_default_tags);
+       coolrain_tagset_register_tags(loader.tagset, coolrain_tagset_gkeyfile_tags);
+       coolrain_tagset_register_filters(loader.tagset, coolrain_tagset_default_filters);
+
+       coolrain_template_initialize(&tmpl, loader.tagset);
        coolrain_template_set_error_handler(&tmpl, my_error_handler, NULL);
-       if (coolrain_template_compile(&tmpl, argv[1]) != COOLRAIN_SUCCESS) {
+       if (coolrain_loader_load_template(&loader, &tmpl, argv[1]) != COOLRAIN_SUCCESS) {
                coolrain_template_destroy(&tmpl);
-               coolrain_tagset_destroy(&tagset);
                return EXIT_FAILURE;
        }
 
@@ -54,7 +56,6 @@ int main(int argc, char *argv[])
                if (gkeyfile_vl == NULL) {
                        fprintf(stderr, "%s: Could'nt open file.", argv[2]);
                        coolrain_template_destroy(&tmpl);
-                       coolrain_tagset_destroy(&tagset);
                        coolrain_stash_destroy(&stash);
                        return EXIT_FAILURE;
                }
@@ -71,7 +72,7 @@ int main(int argc, char *argv[])
        coolrain_writer_destroy(&writer);
        coolrain_stash_destroy(&stash);
        coolrain_template_destroy(&tmpl);
-       coolrain_tagset_destroy(&tagset);
+       coolrain_loader_destroy(&loader);
 
        return (r == COOLRAIN_SUCCESS)? EXIT_SUCCESS : EXIT_FAILURE;
 }
index e7f5950..23a55d0 100644 (file)
@@ -2,8 +2,8 @@
  *
  */
 
-#if !defined(__COOLRAIN__COOLRAIN__H__)
-#define __COOLRAIN__COOLRAIN__H__
+#if !defined(COOLRAIN__COOLRAIN__H__)
+#define COOLRAIN__COOLRAIN__H__
 
 #include <CoolRain/thread.h>
 #include <CoolRain/error.h>
@@ -13,6 +13,7 @@
 #include <CoolRain/template.h>
 #include <CoolRain/stash.h>
 #include <CoolRain/writer.h>
+#include <CoolRain/loader.h>
 
 #endif
 
index f01fa66..4e9170b 100644 (file)
@@ -2,8 +2,8 @@
  * \brief C++ wrapper of CoolRain templat engine.
  *
  */
-#if !defined(__COORAIN__COOLRAIN__HXX__)
-#define __COOLRAIN__COOLRAIN__HXX__
+#if !defined(COORAIN__COOLRAIN__HXX__)
+#define COOLRAIN__COOLRAIN__HXX__
 
 #include <boost/noncopyable.hxx>
 #include <stdarg.h>
index d15c4ab..c0c9cba 100644 (file)
@@ -12,6 +12,7 @@ CoolRain_include_HEADERS=\
        variant.h \
        memory.h \
        version.h \
+       loader.h \
        CoolRain.h
 
 
index eac2185..b9c3039 100644 (file)
@@ -28,8 +28,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#if !defined(__COOLRAIN__ERROR__H__)
-#define __COOLRAIN__ERROR__H__
+#if !defined(COOLRAIN__ERROR__H__)
+#define COOLRAIN__ERROR__H__
 
 /** @{ \name Error codes */
 #define COOLRAIN_SUCCESS               (0)     /*!< No error */
@@ -43,6 +43,8 @@
 #define COOLRAIN_ERROR_UNBUFFERED      (-8)    /*!< Target buffer is unbuffered */
 #define COOLRAIN_ERROR_IO              (-9)    /*!< IO Error */
 #define COOLRAIN_ERROR_RUNTIME         (-10)   /*!< Runtime error */
+#define COOLRAIN_ERROR_NO_LOADER       (-11)   /*!< Template has no loader. (Loaded as standalone) */
+#define COOLRAIN_ERROR_NO_ATTRIBUTE    (-12)   /*!< Missing required attribute */
 /** @} */
 
 #endif
index b7a11c9..5bb571d 100644 (file)
@@ -1,12 +1,14 @@
 /**
  *
  */
-#if !defined(__COOLRAIN__FRAGMENT__H__)
-#define __COOLRAIN__FRAGMENT__H__
+#if !defined(COOLRAIN__FRAGMENT__H__)
+#define COOLRAIN__FRAGMENT__H__
 
 
+#include <glib/gmacros.h>
 #include <CoolRain/refstring.h>
 
+G_BEGIN_DECLS;
 
 struct coolrain_tag_desc;
 
@@ -14,10 +16,13 @@ struct coolrain_tag_desc;
 /*
  *
  */
+#define COOLRAIN_FRAGMENT_ATTR_FLAGS_CSTRING   (1)
+
 struct coolrain_fragment_attribute {
        struct coolrain_fragment_attribute *next;
        coolrain_refstring_t    name;
        coolrain_refstring_t    value;
+       unsigned long           flags;
 };
 
 
@@ -56,14 +61,17 @@ struct coolrain_fragment {
 };
 
 
-struct coolrain_fragment_attribute *coolrain_fragment_attribute_alloc();
+struct coolrain_fragment_attribute *coolrain_fragment_attribute_alloc(void);
 void coolrain_fragment_attribute_free(struct coolrain_fragment_attribute *attrs);
 
 
 struct coolrain_fragment *coolrain_fragment_alloc(coolrain_fragment_type type);
 void coolrain_fragment_free(struct coolrain_fragment *fragment);
 
-coolrain_refstring_t const *coolrain_fragment_find_attribute(struct coolrain_fragment const* fragment, char const *name);
+coolrain_refstring_t const *coolrain_fragment_find_attribute(struct coolrain_fragment const* __restrict fragment, char const * __restrict name);
+char const* coolrain_fragment_find_attribute_as_cstring(struct coolrain_fragment const * __restrict fragment, char const * __restrict name);
+
+G_END_DECLS;
 
 #endif
 
diff --git a/include/CoolRain/loader.h b/include/CoolRain/loader.h
new file mode 100644 (file)
index 0000000..66d1d33
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * \brief Template repository and loader module for CoolRain template engine.
+ *
+ * Copyright (c) HATTORI, Hiroki
+ * 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 University 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 REGENTS 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 REGENTS 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.
+ */
+#if !defined(COOLRAIN__LOADER__H__)
+#define COOLRAIN__LOADER__H__
+
+#include <glib/gmacros.h>
+
+#include <CoolRain/thread.h>
+#include <CoolRain/template.h>
+
+G_BEGIN_DECLS;
+
+
+struct coolrain_stash;
+struct coolrain_writer;
+struct coolrain_tagset;
+struct coolrain_loader;
+
+
+
+struct coolrain_loader_ops {
+       int     (*load)(struct coolrain_loader * __restrict loader, struct coolrain_template * __restrict tmpl, char const * __restrict name);
+       void    (*destroy)(struct coolrain_loader *loader);
+};
+
+
+#define COOLRAIN_LOADER_FLAGS_AUTO_FREE_TAGSET (0)
+#define COOLRAIN_LOADER_FLAGS_BINNARY_LOADER   (1)
+
+
+struct coolrain_loader {
+       struct coolrain_loader_ops *ops;
+       void    *driver_data;
+       unsigned long flags;
+
+       struct coolrain_tagset *tagset;
+       coolrain_template_error_handler_t error_handler;
+       void    *error_user_data;
+
+       void    *user_data;
+       int     (*preprocess)(struct coolrain_eval_context * __restrict cntx, void ** __restrict preproc_data);
+       void    (*postprocess)(struct coolrain_eval_context * __restrict cntx, void * __restrict preproc_data);
+};
+
+
+int coolrain_loader_initialize(struct coolrain_loader * __restrict loader, struct coolrain_loader_ops * __restrict ops, struct coolrain_tagset * __restrict tagset);
+void coolrain_loader_destroy(struct coolrain_loader *loader);
+
+
+static inline void coolrain_loader_set_error_handler(
+       struct coolrain_loader * __restrict loader,
+       coolrain_template_error_handler_t handler,
+       void * __restrict user_data)
+{
+       loader->error_handler = handler;
+       loader->error_user_data = user_data;
+}
+
+int coolrain_loader_load_template(struct coolrain_loader * __restrict loader, struct coolrain_template * __restrict tmpl, char const * __restrict name);
+int coolrain_loader_process_template(struct coolrain_loader * __restrict loader, char const * __restrict name, struct coolrain_stash * __restrict stash, struct coolrain_writer * __restrict writer);
+
+
+int coolrain_file_loader_initialize(struct coolrain_loader * __restrict loader, struct coolrain_tagset * __restrict tagset, char const * __restrict base_dir);
+
+
+G_END_DECLS;
+
+#endif
+
+
index 39e0f97..be1aeaf 100644 (file)
@@ -2,8 +2,8 @@
  * \brief Memory management module for CoolRain template engine.
  *
  */
-#if !defined(__COOLRAIN__MEMORY__H__)
-#define __COOLRAIN__MEMORY__H__
+#if !defined(COOLRAIN__MEMORY__H__)
+#define COOLRAIN__MEMORY__H__
 
 
 #  if COOLRAIN_USE_GLIB
 #    include <glib/gstrfuncs.h>
 
 
-#define coolrain_malloc                g_malloc
-#define coolrain_free          g_free
-#define coolrain_strdup                g_strdup
+#    define coolrain_malloc            g_malloc
+#    define coolrain_free              g_free
+#    define coolrain_strdup            g_strdup
+#    define coolrain_strfreev  g_strfeev
 
 
 #  else
-#   error "No memory library."
+
+#    include <stdlib.h>
+#    include <stdio.h>
+#    include <string.h>
+
+static inline void *coolrain_malloc(size_t n)
+{
+       void *p = malloc(n);
+       if (p == NULL) {
+               perror("coolrain_malloc:");
+               abort();
+       }
+       return p;
+}
+
+#    define coolrain_free              free
+
+static inline char *coolrain_strdup(char const* str)
+{
+       char *p = strdup(str);
+       if (p == NULL) {
+               perror("coolrain_strdup:");
+               abort();
+       }
+       return p;
+}
+
+static inline void coolrain_strfreev(char** p)
+{
+       if (p != NULL) {
+               char **tmp = p;
+               while (*tmp != NULL) {
+                       coolrain_free(*tmp);
+                       tmp++;
+               }
+               coolrain_free(p);
+       }
+}
+
 #endif
 
 
index d52e546..9058448 100644 (file)
@@ -1,8 +1,8 @@
 /**
  * \brief RefString object module for CoolRain.
  */
-#if !defined(__COOLRAIN__REFSTRING__H__)
-#define __COOLRAIN__REFSTRING__H__
+#if !defined(COOLRAIN__REFSTRING__H__)
+#define COOLRAIN__REFSTRING__H__
 
 #include <string.h>
 #include <stdlib.h>
@@ -12,6 +12,8 @@
 #include <CoolRain/memory.h>
 
 
+G_BEGIN_DECLS;
+
 /**
  *
  */
@@ -103,7 +105,7 @@ static inline char *coolrain_refstring_dup(coolrain_refstring_t const *str)
 {
        if (str != NULL) {
                size_t len = coolrain_refstring_length(str);
-               char *r = coolrain_malloc(len + 1);
+               char *r = (char*)coolrain_malloc(len + 1);
                memcpy(r, str->begin, len);
                r[len] = '\0';
                return r;
@@ -111,5 +113,7 @@ static inline char *coolrain_refstring_dup(coolrain_refstring_t const *str)
        return NULL;
 }
 
+G_END_DECLS;
+
 #endif
 
index dd35421..67882c0 100644 (file)
@@ -2,8 +2,8 @@
  * \par Threading:
  * The stash object is no thread safe.
  */
-#if !defined(__COOLRAIN__STASH__H__)
-#define __COOLRAIN__STASH__H__
+#if !defined(COOLRAIN__STASH__H__)
+#define COOLRAIN__STASH__H__
 
 #include <glib/gtypes.h>
 #include <glib/ghash.h>
 #include <CoolRain/error.h>
 #include <CoolRain/variant.h>
 
+G_BEGIN_DECLS;
+
 /**
  *
  */
-typedef int (*coolrain_stash_lookup_handler_t)(coolrain_variant_t * restrict value, coolrain_refstring_t const * restrict key);
+typedef int (*coolrain_stash_lookup_handler_t)(coolrain_variant_t * __restrict value, coolrain_refstring_t const * __restrict key);
 
 struct coolrain_stash {
        coolrain_mutex_t        mutex;
@@ -34,9 +36,9 @@ void coolrain_stash_destroy(struct coolrain_stash *stash);
 
 
 
-coolrain_variant_t const *coolrain_stash_get_value(struct coolrain_stash * restrict stash, coolrain_refstring_t const * restrict key);
+coolrain_variant_t const *coolrain_stash_get_value(struct coolrain_stash * __restrict stash, coolrain_refstring_t const * __restrict key);
 
-static inline coolrain_variant_t const *coolrain_stash_get_value_(struct coolrain_stash * restrict stash, char const * restrict key)
+static inline coolrain_variant_t const *coolrain_stash_get_value_(struct coolrain_stash * __restrict stash, char const * __restrict key)
 {
        coolrain_refstring_t k;
        k.begin = key;
@@ -55,14 +57,20 @@ struct coolrain_stash_value_list {
 };
 #define COOLRAIN_STASH_VALUE_INITIALIZER { { NULL, NULL }, COOLRAIN_VARIANT_INITIALIZER, NULL }
 
-void coolrain_stash_set_values(struct coolrain_stash * restrict stash, struct coolrain_stash_value_list * restrict values, size_t count);
-void coolrain_stash_restore(struct coolrain_stash * restrict stash, struct coolrain_stash_value_list * restrict values, size_t count);
+void coolrain_stash_set_values(struct coolrain_stash * __restrict stash, struct coolrain_stash_value_list * __restrict values, size_t count);
+void coolrain_stash_restore(struct coolrain_stash * __restrict stash, struct coolrain_stash_value_list * __restrict values, size_t count);
 
 
-static inline void coolrain_stash_set_lookup_handler(struct coolrain_stash * restrict stash, coolrain_stash_lookup_handler_t handler)
+static inline void coolrain_stash_set_lookup_handler(struct coolrain_stash * __restrict stash, coolrain_stash_lookup_handler_t handler)
 {
        stash->lookup_handler = handler;
 }
 
+
+void coolrain_stash_value_list_unset(struct coolrain_stash_value_list * __restrict values, size_t count);
+
+
+G_END_DECLS;
+
 #endif
 
index 8301b17..2924caa 100644 (file)
@@ -1,11 +1,12 @@
 /**
  *
  */
-#if !defined(__COOLRAIN__TAGSET__H__)
-#define __COOLRAIN__TAGSET__H__
+#if !defined(COOLRAIN__TAGSET__H__)
+#define COOLRAIN__TAGSET__H__
 
 
 #include <glib/ghash.h>
+#include <glib/gmacros.h>
 
 #include <CoolRain/error.h>
 #include <CoolRain/thread.h>
@@ -13,6 +14,7 @@
 #include <CoolRain/stash.h>
 #include <CoolRain/writer.h>
 
+G_BEGIN_DECLS;
 
 struct coolrain_fragment;
 struct coolrain_template;
@@ -97,6 +99,8 @@ int coolrain_builtin_tag_handler_ignore(struct coolrain_eval_context const *cntx
 int coolrain_builtin_tag_handler_let(struct coolrain_eval_context const *cntx);
 int coolrain_builtin_tag_handler_var(struct coolrain_eval_context const *cntx);
 int coolrain_builtin_tag_handler_loop(struct coolrain_eval_context const *cntx);
+int coolrain_builtin_tag_handler_include(struct coolrain_eval_context const *cntx);
+int coolrain_builtin_tag_handler_include_param(struct coolrain_eval_context const *cntx);
 /* !} */
 
 
@@ -108,5 +112,7 @@ void coolrain_gkeyfile_restore(
        struct coolrain_stash *stash,
        struct coolrain_stash_value_list *vl);
 
+G_END_DECLS;
+
 #endif
 
index 21e364e..3ccc22e 100644 (file)
@@ -1,11 +1,12 @@
 /**
  *
  */
-#if !defined(__COOLRAIN__TEMPLATE__H__)
-#define __COOLRAIN__TEMPLATE__H__
+#if !defined(COOLRAIN__TEMPLATE__H__)
+#define COOLRAIN__TEMPLATE__H__
 
 #include <limits.h>
 #include <stdarg.h>
+#include <glib/gmacros.h>
 
 #include <CoolRain/refstring.h>
 #include <CoolRain/thread.h>
 #include <CoolRain/stash.h>
 #include <CoolRain/fragment.h>
 
+G_BEGIN_DECLS;
+
 typedef void (*coolrain_template_error_handler_t)(
        struct coolrain_template *tmpl, char const *message);
 
+struct coolrain_loader;
+
 struct coolrain_template {
        coolrain_mutex_t        mutex;
 
        struct coolrain_fragment        *root;
        struct coolrain_tagset          *tagset;
 
-       char    name[PATH_MAX];
+       struct coolrain_loader          *loader;
+       char const      *name;
        coolrain_refstring_t    source;
 
        struct {
@@ -46,21 +52,17 @@ struct coolrain_eval_context {
        struct coolrain_writer          *writer;
 };
 
-static inline void coolrain_eval_context_copy(struct coolrain_eval_context *dst, struct coolrain_eval_context const *src)
-{
-       dst->tmpl     = src->tmpl;
-       dst->stash    = src->stash;
-       dst->fragment = src->fragment;
-       dst->writer   = src->writer;
-}
-
-
 
 
 int coolrain_template_initialize(struct coolrain_template *tmpl, struct coolrain_tagset *tagset);
 int coolrain_template_destroy(struct coolrain_template *tmpl);
 int coolrain_template_clear(struct coolrain_template *tmpl);
 
+
+void coolrain_template_set_name(
+       struct coolrain_template * __restrict templ,
+       char const * __restrict name);
+
 int coolrain_template_set_error_handler(
        struct coolrain_template *tmpl,
        coolrain_template_error_handler_t handler,
@@ -86,12 +88,22 @@ int coolrain_template_parse(
        void* destroy_data);
 
 int coolrain_template_eval_block(struct coolrain_eval_context const *cntx);
-int coolrain_template_eval_content(struct coolrain_eval_context const *cntx);
+
+
+static inline int coolrain_template_eval_content(struct coolrain_eval_context const *cntx)
+{
+       struct coolrain_eval_context new_cntx = *cntx;
+       new_cntx.fragment = new_cntx.fragment->data.tag.content;
+       return coolrain_template_eval_block(&new_cntx);
+}
+
 
 int coolrain_template_run(
        struct coolrain_template *tmpl,
        struct coolrain_stash *stash,
        struct coolrain_writer *writer);
 
+G_END_DECLS;
+
 #endif
 
index 380a2d1..a007fb3 100644 (file)
@@ -2,11 +2,13 @@
  * Threading wrapper module of CoolRain
  *
  */
-#if !defined(__COOLRAIN__THREAD__H__)
-#define __COOLRAIN__THREAD__H__
+#if !defined(COOLRAIN__THREAD__H__)
+#define COOLRAIN__THREAD__H__
 
 #include <stdbool.h>
+#include <glib/gmacros.h>
 
+G_BEGIN_DECLS;
 
 #if COOLRAIN_USE_GTHREAD
 
@@ -142,6 +144,7 @@ typedef int coolrain_mutex_t[0];
 
 #endif
 
+G_END_DECLS;
 
 #endif
 
index edac8d0..39a9f2f 100644 (file)
@@ -2,12 +2,15 @@
  *
  *
  */
-#if !defined(__COOLRAIN__VARIANT__H__)
-#define __COOLRAIN__VARIANT__H__
+#if !defined(COOLRAIN__VARIANT__H__)
+#define COOLRAIN__VARIANT__H__
 
+#include <glib/gmacros.h>
 #include <CoolRain/refstring.h>
 #include <CoolRain/memory.h>
 
+G_BEGIN_DECLS;
+
 struct coolrain_writer;
 
 
@@ -18,6 +21,10 @@ struct coolrain_writer;
 #define COOLRAIN_VARIANT_TYPE_STATIC_STRING    (4)
 #define COOLRAIN_VARIANT_TYPE_DYNAMIC_STRING   (5)
 #define COOLRAIN_VARIANT_TYPE_POINTER          (6)
+#define COOLRAIN_VARIANT_TYPE_STATIC_CONTEXT   (7)
+#define COOLRAIN_VARIANT_TYPE_DYNAMIC_CONTEXT  (8)
+
+
 
 typedef struct {
        int     type;
@@ -31,6 +38,7 @@ typedef struct {
                        void    *p;
                        void (*destroy_handler)(void *data);
                } v_pointer;
+               struct coolrain_eval_context *v_cntx;
        } data;
 } coolrain_variant_t;
 
@@ -134,11 +142,20 @@ static inline void coolrain_variant_set_pointer(coolrain_variant_t *v, void *new
 }
 
 
+
+void coolrain_variant_set_static_context(coolrain_variant_t *v, struct coolrain_eval_context *cntx);
+void coolrain_variant_set_dynamic_context(coolrain_variant_t *v, struct coolrain_eval_context const *cntx);
+
+
+
+/* */
 void coolrain_variant_copy(coolrain_variant_t *dst, coolrain_variant_t const *src);
 
 
 /* */
 int coolrain_variant_write(coolrain_variant_t const *v, struct coolrain_writer *writer);
 
+G_END_DECLS;
+
 #endif
 
index 639a33d..9729c9b 100644 (file)
@@ -2,10 +2,10 @@
  *
  *
  */
-#if !defined(__COOLRAIN__VERSION__H__)
-#define __COOLRAIN__VERSION__H__
+#if !defined(COOLRAIN__VERSION__H__)
+#define COOLRAIN__VERSION__H__
 
-#define COOLRAIN_NAME @PACKAGE_NAME@
+#define COOLRAIN_NAME "@PACKAGE_NAME@"
 #define COOLRAIN_VERSION @PACKAGE_VERSION@
 
 #endif
index 2598b5b..daf2c46 100644 (file)
@@ -2,17 +2,21 @@
  *
  *
  */
-#if !defined(__COOLRAIN__WRITER__H__)
-#define __COOLRAIN__WRITER__H__
+#if !defined(COOLRAIN__WRITER__H__)
+#define COOLRAIN__WRITER__H__
 
 #include <stddef.h>
 #include <stdbool.h>
 
 #include <stdbool.h>
 
+#include <glib/gmacros.h>
+
 #include <CoolRain/error.h>
 #include <CoolRain/thread.h>
 
+G_BEGIN_DECLS;
+
 struct coolrain_writer;
 
 typedef int (*coolrain_writer_buffer_full_handler_t)(struct coolrain_writer *writer);
@@ -167,5 +171,7 @@ int coolrain_html_filter(struct coolrain_writer *writer, char const **pbuffer, s
 int coolrain_url_filter(struct coolrain_writer *writer, char const **pbufferr, size_t length);
 int coolrain_javascript_filter(struct coolrain_writer *writer, char const **pbuffer, size_t length);
 
+G_END_DECLS;
+
 #endif
 
index ad26006..9d4c279 100644 (file)
@@ -1,7 +1,7 @@
 
 lib_LIBRARIES=
 
-SOURCES= builtin_tag_gkeyfile.c builtin_tag.c template.c fragment.c tagset.c stash.c variant.c writer_fd.c writer_fcgi.c writer.c filter.c
+SOURCES= builtin_tag_gkeyfile.c builtin_tag.c loader.c template.c fragment.c tagset.c stash.c variant.c writer_fd.c writer_fcgi.c writer.c filter.c
 
 if HAVE_GLIB
 lib_LIBRARIES+= libcoolrain-glib-nonthread.a
index 5facb43..f50bf50 100644 (file)
@@ -72,9 +72,8 @@ int coolrain_builtin_tag_handler_let(struct coolrain_eval_context const *cntx)
        r = coolrain_template_eval_content(cntx);
 
        coolrain_stash_restore(cntx->stash, vl, count);
+       coolrain_stash_value_list_unset(vl, count);
 
-       for (i = 0; i < count; i++)
-               coolrain_variant_destroy(&vl[i].value);
        coolrain_free(vl);
 
        return r;
@@ -149,8 +148,111 @@ int coolrain_builtin_tag_handler_loop(struct coolrain_eval_context const *cntx)
                }
        }
        coolrain_stash_restore(cntx->stash, vlist, 1);
+       coolrain_stash_value_list_unset(vlist, 1);
 
        return COOLRAIN_SUCCESS;
 }
 
 
+
+
+
+
+int coolrain_builtin_tag_handler_include_param(struct coolrain_eval_context const *cntx G_GNUC_UNUSED)
+{
+       return COOLRAIN_SUCCESS;
+}
+
+
+
+
+/**
+ *
+ */
+int coolrain_builtin_tag_handler_include(struct coolrain_eval_context const *cntx)
+{
+       char *href_cstr;
+       int r;
+       int param_count = 0;
+       struct coolrain_stash_value_list *vlist = NULL;
+       char* tagname;
+
+       if (cntx->tmpl->loader == NULL) {
+               coolrain_template_raise_error(cntx->tmpl, "Template %s has no loader.\n", cntx->tmpl->name);
+               return COOLRAIN_ERROR_NO_LOADER;
+       }
+
+
+       /* */
+       {
+               coolrain_refstring_t const* href = coolrain_fragment_find_attribute(cntx->fragment, "href");
+               if (href == NULL) {
+                       tagname = coolrain_refstring_dup(&cntx->fragment->data.tag.tagdesc->name);
+                       coolrain_template_raise_error(cntx->tmpl, "No 'href' attribute on %s tag\n", tagname);
+                       coolrain_free(tagname);
+                       return COOLRAIN_ERROR_NO_ATTRIBUTE;
+               }
+               href_cstr = coolrain_refstring_dup(href);
+       }
+
+
+       /* Bind all parameters */
+       {
+               struct coolrain_fragment *child;
+               coolrain_refstring_t const* name;
+               int n;
+
+               for (child = cntx->fragment->data.tag.content; child != NULL; child = child->next) {
+                       if (child->type != COOLRAIN_FRAGMENT_TYPE_TAG ||
+                           child->data.tag.tagdesc->handler != coolrain_builtin_tag_handler_include_param)
+                               continue;
+                       param_count++;
+               }
+
+               if (param_count > 0) {
+                       vlist = coolrain_malloc(sizeof(struct coolrain_stash_value_list) * param_count);
+
+                       n = 0;
+                       for (child = cntx->fragment->data.tag.content; n < param_count && child != NULL; child = child->next) {
+                               if (child->type != COOLRAIN_FRAGMENT_TYPE_TAG ||
+                                   child->data.tag.tagdesc->handler != coolrain_builtin_tag_handler_include_param)
+                                       continue;
+
+                               name = coolrain_fragment_find_attribute(child, "name");
+                               if (name == NULL) continue;
+
+                               vlist[n].name = *name;
+                               coolrain_variant_initialize(&vlist[n].value);
+                               coolrain_variant_set_dynamic_context(&vlist[n].value, cntx);
+                               vlist[n].value.data.v_cntx->fragment = child;
+                               vlist[n].old_value = NULL;
+                               n++;
+                       }
+
+                       param_count = n;
+                       coolrain_stash_set_values(cntx->stash, vlist, param_count);
+               }
+       }
+
+
+       /* Process included template */
+       r = coolrain_loader_process_template(cntx->tmpl->loader, href_cstr, cntx->stash, cntx->writer);
+       coolrain_free(href_cstr);
+       if (r != 0) {
+               coolrain_template_raise_error(cntx->tmpl, "  include from %s\n", cntx->tmpl->name);
+       }
+
+
+       /* Reelase memories */
+       if (vlist != NULL) {
+               if (param_count > 0)
+                       coolrain_stash_restore(cntx->stash, vlist, param_count);
+               coolrain_stash_value_list_unset(vlist, param_count);
+
+               coolrain_free(vlist);
+       }
+
+       return r;
+}
+
+
index 59a413a..e890c8f 100644 (file)
@@ -92,7 +92,6 @@ static int coolrain_builtin_tag_gkeyfile_with_key_file_tag_handler(struct coolra
 
 static int coolrain_builtin_tag_gkeyfile_with_locale_tag_handler(struct coolrain_eval_context const *cntx)
 {
-       coolrain_refstring_t const *locale;
        int r;
        struct coolrain_stash_value_list vl[1] = {
                { { ".CR.Keyfile.locale", NULL }, COOLRAIN_VARIANT_INITIALIZER, NULL }
index 6151a7a..3bc36c5 100644 (file)
@@ -15,7 +15,8 @@ struct coolrain_fragment_attribute *coolrain_fragment_attribute_alloc(void)
        struct coolrain_fragment_attribute *attr =
                coolrain_malloc(sizeof(struct coolrain_fragment_attribute));
        if (attr != NULL){
-               attr->next = NULL;
+               attr->next      = NULL;
+               attr->flags     = 0;
        }
        return attr;
 }
@@ -25,6 +26,8 @@ void coolrain_fragment_attribute_free(struct coolrain_fragment_attribute *attrs)
 {
        while (attrs != NULL) {
                struct coolrain_fragment_attribute *next = attrs->next;
+               if (attrs->flags & (1 << COOLRAIN_FRAGMENT_ATTR_FLAGS_CSTRING))
+                       coolrain_free((char*)attrs->value.begin);
                coolrain_free(attrs);
                attrs = next;
        }
@@ -65,7 +68,9 @@ void coolrain_fragment_free(struct coolrain_fragment *fragment)
 
 
 
-coolrain_refstring_t const *coolrain_fragment_find_attribute(struct coolrain_fragment const* fragment, char const *name)
+coolrain_refstring_t const *coolrain_fragment_find_attribute(
+       struct coolrain_fragment const * restrict fragment,
+       char const * restrict name)
 {
        struct coolrain_fragment_attribute const *attr;
        coolrain_refstring_t tmp;
@@ -86,3 +91,42 @@ coolrain_refstring_t const *coolrain_fragment_find_attribute(struct coolrain_fra
 }
 
 
+
+char const *coolrain_fragment_find_attribute_as_cstring(
+       struct coolrain_fragment const * restrict fragment,
+       char const * restrict name)
+{
+       struct coolrain_fragment_attribute *attr;
+       coolrain_refstring_t tmp;
+
+       if (fragment->type != COOLRAIN_FRAGMENT_TYPE_TAG)
+               return NULL;
+
+       tmp.begin = name;
+       tmp.end = name + strlen(name);
+
+       attr = fragment->data.tag.attrs;
+       for (attr = fragment->data.tag.attrs; attr != NULL; attr = attr->next) {
+               if (! coolrain_refstring_equal(&attr->name, &tmp)) continue;
+
+               if (! (attr->flags & (1 << COOLRAIN_FRAGMENT_ATTR_FLAGS_CSTRING)) ) {
+                       /* Create duplicate string */
+                       size_t len = coolrain_refstring_length(&attr->value);
+                       char * newstr = coolrain_malloc(len + 1);
+                       memcpy(newstr, attr->value.begin, len);
+                       newstr[len] = '\0';
+
+                       /* Replace pointer */
+                       attr->value.begin       = newstr;
+                       attr->value.end         = newstr + len;
+                       attr->flags             |= 1 << COOLRAIN_FRAGMENT_ATTR_FLAGS_CSTRING;
+               }
+               return &attr->value.begin;
+       }
+
+       return NULL;
+}
+
+
+
+
diff --git a/src/loader.c b/src/loader.c
new file mode 100644 (file)
index 0000000..babacae
--- /dev/null
@@ -0,0 +1,198 @@
+/**
+ * \brief Template repository and loader module for CoolRain template engine.
+ *
+ * Copyright (c) HATTORI, Hiroki
+ * 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 University 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 REGENTS 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 REGENTS 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.
+ */
+
+#if defined(HAVE_CONFIG_H)
+#  include "../config.h"
+#endif
+
+#include <CoolRain/loader.h>
+#include <CoolRain/template.h>
+#include <CoolRain/tagset.h>
+#include <CoolRain/memory.h>
+
+
+
+/**
+ * Initialize loader
+ * \param loader       Pointer to memory for New loader object.
+ * \param ops          VTBL of template class.
+ * \param tagset       Tagset object for templates on repository.
+ * \return Error code.
+ */
+int coolrain_loader_initialize(
+       struct coolrain_loader * restrict loader,
+       struct coolrain_loader_ops * restrict ops,
+       struct coolrain_tagset * restrict tagset)
+{
+       loader->ops             = ops;
+       loader->driver_data     = NULL;
+       loader->flags           = 0;
+
+       if (tagset == NULL) {
+               loader->tagset = coolrain_malloc(sizeof(struct coolrain_tagset));
+               coolrain_tagset_initialize(loader->tagset);
+               loader->flags |= 1 << COOLRAIN_LOADER_FLAGS_AUTO_FREE_TAGSET;
+       } else {
+               loader->tagset  = tagset;
+       }
+
+       loader->error_handler   = NULL;
+       loader->error_user_data = NULL;
+
+       loader->user_data       = NULL;
+       loader->preprocess      = NULL;
+       loader->postprocess     = NULL;
+
+       return COOLRAIN_SUCCESS;
+}
+
+
+
+/**
+ * Destroy loader.
+ * \param loader       Loader object.
+ */
+void coolrain_loader_destroy(struct coolrain_loader *loader)
+{
+       loader->ops->destroy(loader);
+       if (loader->flags & (1 << COOLRAIN_LOADER_FLAGS_AUTO_FREE_TAGSET)) {
+               coolrain_tagset_destroy(loader->tagset);
+               coolrain_free(loader->tagset);
+       }
+}
+
+
+
+/**
+ * Load template from repository.
+ * \param loader       Loader object.
+ * \param tmpl         Template object
+ * \param name         Name of template to load.
+ * \return Error code
+ */
+int coolrain_loader_load_template(
+       struct coolrain_loader * restrict loader,
+       struct coolrain_template * restrict tmpl,
+       char const * restrict name)
+{
+       int r = loader->ops->load(loader, tmpl, name);
+       tmpl->loader = loader;
+       return r;
+}
+
+
+
+/**
+ * Load template and run it.
+ * \param loader       Template object.
+ * \param name         Name of template to load.
+ * \param stash                Stash object
+ * \param write                Writer object to output.
+ * \return Error code
+ */
+int coolrain_loader_process_template(
+       struct coolrain_loader * restrict loader,
+       char const * restrict name,
+       struct coolrain_stash * restrict stash,
+       struct coolrain_writer * restrict writer)
+{
+       int r;
+       struct coolrain_template tmpl;
+
+       r = coolrain_template_initialize(&tmpl, loader->tagset);
+       if (r == COOLRAIN_SUCCESS) {
+               coolrain_template_set_error_handler(&tmpl, loader->error_handler, loader->error_user_data);
+
+               r = coolrain_loader_load_template(loader, &tmpl, name);
+               if (r == COOLRAIN_SUCCESS)
+                       r = coolrain_template_run(&tmpl, stash, writer);
+
+               coolrain_template_destroy(&tmpl);
+       }
+
+       return r;
+}
+
+
+
+
+
+static int file_loader_load(
+       struct coolrain_loader * restrict loader,
+       struct coolrain_template * restrict tmpl,
+       char const* restrict name)
+{
+       char path[PATH_MAX];
+       size_t dirlen = strlen(loader->driver_data);
+
+       memcpy(path, loader->driver_data, dirlen);
+       path[dirlen] = '/';
+       strcpy(path + dirlen + 1, name);
+
+       return coolrain_template_compile(tmpl, path);
+}
+
+
+
+
+static void file_loader_destroy(struct coolrain_loader *loader)
+{
+       coolrain_free(loader->driver_data);
+}
+
+
+static struct coolrain_loader_ops file_loader_ops = {
+       .load           = file_loader_load,
+       .destroy        = file_loader_destroy,
+};
+
+
+
+/**
+ * Initialize file based template loader.
+ * \param loader       Pointer to memory for new loader object.
+ * \param tagset       Tagset object.
+ * \param base_dir     Base directory of templates.
+ * \return Error code.
+ */
+int coolrain_file_loader_initialize(
+       struct coolrain_loader * restrict loader,
+       struct coolrain_tagset * restrict tagset,
+       char const * restrict base_dir)
+{
+       int r = coolrain_loader_initialize(loader, &file_loader_ops, tagset);
+       if (r == COOLRAIN_SUCCESS)
+               loader->driver_data = coolrain_strdup(base_dir);
+
+       return r;
+}
+
+
index e35f98d..9f1380f 100644 (file)
@@ -1,5 +1,32 @@
 /**
+ * \brief Stash variable module for CoolRain template engine.
  *
+ * Copyright (c) HATTORI, Hiroki
+ * 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 University 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 REGENTS 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 REGENTS 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.
  */
 #if defined(HAVE_CONFIG_H)
 #  include "../config.h"
@@ -94,6 +121,8 @@ void coolrain_stash_set_values(
 
        while (count--) {
                coolrain_variant_t const *v = g_hash_table_lookup(stash->hash, (gpointer)&values->name);
+               g_assert(values->old_value == NULL);
+
                values->old_value = v;
                g_hash_table_insert(stash->hash, &values->name, (gpointer)&values->value);
 
@@ -114,8 +143,10 @@ void coolrain_stash_restore(
        while (count--) {
                if (values->old_value == NULL)
                        g_hash_table_remove(stash->hash, &values->name);
-               else
+               else {
                        g_hash_table_insert(stash->hash, &values->name, (gpointer)values->old_value);
+                       values->old_value = NULL;
+               }
 
                values++;
        }
@@ -124,3 +155,17 @@ void coolrain_stash_restore(
 }
 
 
+
+
+/**
+ *
+ */
+void coolrain_stash_value_list_unset(struct coolrain_stash_value_list * restrict values, size_t count)
+{
+       while (count--) {
+               coolrain_variant_unset(&values->value);
+               values++;
+       }
+}
+
+
index 7929f81..cc45ff8 100644 (file)
@@ -284,6 +284,8 @@ struct coolrain_tag_desc coolrain_tagset_default_tags[] = {
        { { "CR:let", NULL }, coolrain_builtin_tag_handler_let, 0 },
        { { "CR:var", NULL }, coolrain_builtin_tag_handler_var, 0 },
        { { "CR:loop", NULL }, coolrain_builtin_tag_handler_loop, 0 },
+       { { "CR:include", NULL }, coolrain_builtin_tag_handler_include, 0 },
+       { { "CR:param", NULL }, coolrain_builtin_tag_handler_include_param, 0 },
        { { NULL, NULL }, NULL, 0 }
 };
 
index a1e12ca..99fbd98 100644 (file)
@@ -27,6 +27,7 @@
 #include <CoolRain/tagset.h>
 #include <CoolRain/template.h>
 #include <CoolRain/memory.h>
+#include <CoolRain/loader.h>
 
 
 
@@ -51,6 +52,8 @@ static void munmap_handler(struct coolrain_template *tmpl)
 
 
 
+static char dummy_empty_str[] = "<UNTITLED>";
+
 
 /**
  * Initialize template object
@@ -62,20 +65,21 @@ int coolrain_template_initialize(struct coolrain_template *tmpl, struct coolrain
 {
        coolrain_mutex_init(&tmpl->mutex);
 
-       tmpl->root = NULL;
+       tmpl->root              = NULL;
 
-       tmpl->name[0] = '\0';
-       tmpl->source.begin = NULL;
-       tmpl->source.end   = NULL;
+       tmpl->loader            = NULL;
+       tmpl->name              = dummy_empty_str;
+       tmpl->source.begin      = NULL;
+       tmpl->source.end        = NULL;
        tmpl->parser_state.lineno = 0;
 
-       tmpl->destroy_callback = NULL;
-       tmpl->destroy_data = NULL;
+       tmpl->destroy_callback  = NULL;
+       tmpl->destroy_data      = NULL;
 
-       tmpl->tagset = tagset;
+       tmpl->tagset            = tagset;
 
-       tmpl->error_handler = default_error_handler;
-       tmpl->error_user_data = NULL;
+       tmpl->error_handler     = default_error_handler;
+       tmpl->error_user_data   = NULL;
 
        return COOLRAIN_SUCCESS;
 }
@@ -109,7 +113,8 @@ static int coolrain_template_clear_(struct coolrain_template *tmpl)
        if (tmpl->destroy_callback != NULL)
                (*tmpl->destroy_callback)(tmpl);
 
-       tmpl->name[0] = '\0';
+       coolrain_template_set_name(tmpl, NULL);
+
        tmpl->source.begin = NULL;
        tmpl->source.end   = NULL;
        tmpl->parser_state.lineno = 0;
@@ -140,6 +145,16 @@ int coolrain_template_clear(struct coolrain_template *tmpl)
 
 
 
+void coolrain_template_set_name(
+       struct coolrain_template * restrict tmpl,
+       char const * restrict new_name)
+{
+       if (tmpl->name != dummy_empty_str)
+               coolrain_free((void*)tmpl->name);
+       tmpl->name = (new_name == NULL)? dummy_empty_str : coolrain_strdup(new_name);
+}
+
+
 
 /**
  * Assign error callback handler.
@@ -220,24 +235,20 @@ void coolrain_template_vraise_error(
  */
 int coolrain_template_compile(struct coolrain_template *tmpl, char const *path)
 {
-       off_t length;
-       char *p;
-       int     fd = open(path, O_RDONLY);
-       int     r;
-       if (fd < 0) return COOLRAIN_ERROR_NOFILE;
-
-       length = lseek(fd, 0, SEEK_END);
-       if (length < 0) {
+       int r = COOLRAIN_ERROR_NOFILE;
+       int fd = open(path, O_RDONLY);
+
+       if (fd >= 0) {
+               off_t length = lseek(fd, 0, SEEK_END);
+               r = COOLRAIN_ERROR_CANT_READ;
+               if (length > 0) {
+                       char *p = mmap(0, (size_t)length, PROT_READ, MAP_PRIVATE, fd, 0);
+                       if (p != NULL)
+                               r = coolrain_template_parse(tmpl, path, p, (size_t)length, munmap_handler, NULL);
+               }
+
                close(fd);
-               return COOLRAIN_ERROR_BAD_LENGTH;
        }
-
-       p = mmap(0, (size_t)length, PROT_READ, MAP_PRIVATE, fd, 0);
-       close(fd);
-       if (p == NULL) return COOLRAIN_ERROR_CANT_READ;
-
-       r = coolrain_template_parse(tmpl, path, p, (size_t)length, munmap_handler, NULL);
-
        return r;
 }
 
@@ -568,7 +579,8 @@ int coolrain_template_parse(
 
        coolrain_template_clear_(tmpl);
 
-       strncpy(tmpl->name, name, PATH_MAX);
+       coolrain_template_set_name(tmpl, name);
+
        tmpl->source.begin = source;
        tmpl->source.end = source + length;
        tmpl->destroy_callback = destroy_callback;
@@ -599,6 +611,7 @@ int coolrain_template_run(
 {
        int r;
        struct coolrain_eval_context cntx;
+       void *preproc_data = NULL;
 
        cntx.tmpl     = tmpl;
        cntx.fragment = tmpl->root;
@@ -608,7 +621,20 @@ int coolrain_template_run(
        // FIXME: Check recursive call
 
        coolrain_mutex_lock(&tmpl->mutex);
+
+       if (tmpl->loader != NULL && tmpl->loader->preprocess != NULL) {
+               r = tmpl->loader->preprocess(&cntx, &preproc_data);
+               if (r != COOLRAIN_SUCCESS) {
+                       coolrain_mutex_unlock(&tmpl->mutex);
+                       return r;
+               }
+       }
+
        r = coolrain_template_eval_block(&cntx);
+
+       if (tmpl->loader != NULL && tmpl->loader->postprocess != NULL)
+               tmpl->loader->postprocess(&cntx, preproc_data);
+
        coolrain_mutex_unlock(&tmpl->mutex);
 
        return r;
@@ -621,8 +647,7 @@ int coolrain_template_eval_block(struct coolrain_eval_context const *cntx)
        int r = COOLRAIN_SUCCESS;
        struct coolrain_eval_context my_cntx;
 
-       coolrain_eval_context_copy(&my_cntx, cntx);
-
+       my_cntx = *cntx;
 
        for (; my_cntx.fragment != NULL && r >= 0; my_cntx.fragment = my_cntx.fragment->next) {
                switch (my_cntx.fragment->type) {
@@ -690,14 +715,13 @@ int coolrain_template_eval_block(struct coolrain_eval_context const *cntx)
        return COOLRAIN_SUCCESS;
 }
 
-
+#if 0
 int coolrain_template_eval_content(struct coolrain_eval_context const *cntx)
 {
-       struct coolrain_eval_context new_cntx;
-       coolrain_eval_context_copy(&new_cntx, cntx);
+       struct coolrain_eval_context new_cntx = *cntx;
        new_cntx.fragment = new_cntx.fragment->data.tag.content;
 
        return coolrain_template_eval_block(&new_cntx);
 }
-
+#endif
 
index 5a956c6..600cd23 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <glib/gmessages.h>
 
+#include <CoolRain/template.h>
 #include <CoolRain/variant.h>
 #include <CoolRain/memory.h>
 #include <CoolRain/writer.h>
@@ -26,6 +27,9 @@ void coolrain_variant_unset(coolrain_variant_t *v)
        case COOLRAIN_VARIANT_TYPE_POINTER:
                v->data.v_pointer.destroy_handler(v->data.v_pointer.p);
                break;
+       case COOLRAIN_VARIANT_TYPE_DYNAMIC_CONTEXT:
+               coolrain_free(v->data.v_cntx);
+               break;
        }
 
        v->type = COOLRAIN_VARIANT_TYPE_NULL;
@@ -75,6 +79,26 @@ char const *coolrain_variant_get_string(coolrain_variant_t const *v)
 
 
 
+void coolrain_variant_set_static_context(coolrain_variant_t *v, struct coolrain_eval_context *cntx)
+{
+       coolrain_variant_unset(v);
+       v->type = COOLRAIN_VARIANT_TYPE_STATIC_CONTEXT;
+       v->data.v_cntx = cntx;
+}
+
+
+void coolrain_variant_set_dynamic_context(coolrain_variant_t *v, struct coolrain_eval_context const *cntx)
+{
+       coolrain_variant_unset(v);
+       v->type = COOLRAIN_VARIANT_TYPE_STATIC_CONTEXT;
+       v->data.v_cntx = coolrain_malloc(sizeof(struct coolrain_eval_context));
+       *v->data.v_cntx = *cntx;
+}
+
+
+
+
+
 /**
  *
  */
@@ -104,6 +128,13 @@ void coolrai_variant_copy(coolrain_variant_t *dst, coolrain_variant_t const *src
        case COOLRAIN_VARIANT_TYPE_POINTER:
                dst->data.v_pointer = src->data.v_pointer;
                break;
+       case COOLRAIN_VARIANT_TYPE_STATIC_CONTEXT:
+               dst->data.v_cntx = src->data.v_cntx;
+               break;
+       case COOLRAIN_VARIANT_TYPE_DYNAMIC_CONTEXT:
+               dst->data.v_cntx = coolrain_malloc(sizeof(struct coolrain_eval_context));
+               *dst->data.v_cntx = *src->data.v_cntx;
+               break;
        default:
                g_assert_not_reached();
        }
@@ -133,6 +164,19 @@ int coolrain_variant_write(coolrain_variant_t const *v, struct coolrain_writer *
                return coolrain_writer_write(writer, v->data.v_static_string, -1);
        case COOLRAIN_VARIANT_TYPE_DYNAMIC_STRING:
                return coolrain_writer_write(writer, v->data.v_dynamic_string, -1);
+       case COOLRAIN_VARIANT_TYPE_POINTER:
+#if 0
+               if (v->data.v_pointer.rendering_handler != NULL)
+                       return v->data.v_pointer.rendering_handler(writer, v->data.v_pointer.p);
+               else
+                       return COOLRAIN_SUCCESS;
+#else
+               return COOLRAIN_SUCCESS;
+#endif
+
+       case COOLRAIN_VARIANT_TYPE_STATIC_CONTEXT:
+       case COOLRAIN_VARIANT_TYPE_DYNAMIC_CONTEXT:
+               return coolrain_template_eval_content(v->data.v_cntx);
        }
        return COOLRAIN_SUCCESS;
 }
diff --git a/src/writer_fcgi.c b/src/writer_fcgi.c
new file mode 100644 (file)
index 0000000..73f887a
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ *
+ */
+#if HAVE_CONFIG_H
+#  include "../config.h"
+#endif
+
+#include <glib/gmessages.h>
+#include <glib/gmacros.h>
+
+#include <CoolRain/error.h>
+#include <CoolRain/thread.h>
+#include <CoolRain/writer.h>
+
+
+static char dummy_buffer[1];
+
+static int dummy_handler(struct coolrain_writer *writer G_GNUC_UNUSED)
+{
+       return COOLRAIN_SUCCESS;
+}
+
+
+static int write_handler(struct coolrain_writer *writer, char const **buffer, size_t length)
+{
+       int r = (length == (size_t)-1)?
+               FCGX_PutS(*buffer, writer->write_handler_data.pointee) :
+               FCGX_PutStr(*buffer, length, writer->write_handler_data.pointee);
+
+       if (r == -1) return COOLRAIN_ERROR_IO;
+
+       *buffer += r;
+       return COOLRAIN_SUCCESS;
+}
+
+int coolrain_FCGI_writer_initialize(struct coolrain_writer *writer, FCGX_Stream *stream)
+{
+       int r = coolrain_writer_initialize(writer, dummy_buffer, 1);
+       if (r == COOLRAIN_SUCCESS) {
+               writer->write_handler_data.pointee = stream;
+               writer->write_handler = write_handler;
+               writer->buffer_full_handler = dummy_handler;
+               writer->destroy_handler = dummy_handler;
+       }
+
+       return COOLRAIN_SUCCESS;
+}
+
+
+
index 73172c7..5d304f1 100644 (file)
@@ -1,7 +1,7 @@
 
 check_PROGRAMS=
 TESTS=${check_PROGRAMS}
-SOURCES= runtest.c test_writer.c test_tagset.c test_stash.c test_template.c
+SOURCES= runtest.c test_writer.c test_tagset.c test_stash.c test_template.c test_loader.c
 LIBS= -L${top_builddir}/src -lcunit
 
 CONFIG_CLEAN_FILES=CUnitAutomated-Listing.xml CUnitAutomated-Results.xml
index 0d7ede4..4e95dcc 100644 (file)
@@ -17,6 +17,7 @@ extern bool setup_test_writer(void);
 extern bool setup_test_tagset(void);
 extern bool setup_test_template(void);
 extern bool setup_test_stash(void);
+extern bool setup_test_loader(void);
 
 int main(int argc, char *argv[])
 {
@@ -29,7 +30,8 @@ int main(int argc, char *argv[])
        if (! setup_test_writer() ||
            ! setup_test_tagset() ||
            ! setup_test_stash() ||
-           ! setup_test_template()
+           ! setup_test_template() ||
+           ! setup_test_loader()
            ) {
                CU_cleanup_registry();
                return CU_get_error();
diff --git a/tests/templates/t1.template b/tests/templates/t1.template
new file mode 100644 (file)
index 0000000..dd7b3a1
--- /dev/null
@@ -0,0 +1,5 @@
+This is t1.template.
+foo=${foo}
+bar=${bar}
+<CR:loop name="i" from="0" to="10">#${i} </CR:loop>
+
diff --git a/tests/test_loader.c b/tests/test_loader.c
new file mode 100644 (file)
index 0000000..a92142a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ */
+#include <stdbool.h>
+#include <CUnit/Basic.h>
+#include <CoolRain/CoolRain.h>
+
+
+
+static struct coolrain_loader loader;
+
+
+static int preproc(struct coolrain_eval_context * restrict cntx, void ** restrict preproc_data)
+{
+       return COOLRAIN_SUCCESS;
+}
+
+static void postproc(struct coolrain_eval_context * restrict cntx, void * restrict preproc_data)
+{
+}
+
+
+int init_test_loader(void)
+{
+       int r;
+       r = coolrain_file_loader_initialize(&loader, NULL, "templates");
+       if (r != 0) return r;
+
+       loader.user_data = NULL;
+       loader.preprocess = preproc;
+       loader.postprocess = postproc;
+
+       coolrain_tagset_register_filters(loader.tagset, coolrain_tagset_default_filters);
+       coolrain_tagset_register_tags(loader.tagset, coolrain_tagset_default_tags);
+       coolrain_tagset_register_tags(loader.tagset, coolrain_tagset_gkeyfile_tags);
+
+       return 0;
+}
+
+int clean_test_loader(void)
+{
+       coolrain_loader_destroy(&loader);
+       return 0;
+}
+
+
+static char obuffer[4096];
+
+
+
+void test_loader_simple(void)
+{
+       struct coolrain_stash    stash;
+       struct coolrain_writer   writer;
+       static char result[] = "This is t1.template.\nfoo=\nbar=\n#0 #1 #2 #3 #4 #5 #6 #7 #8 #9 #10 \n\n";
+
+       CU_ASSERT_EQUAL_FATAL(coolrain_stash_initialize(&stash), COOLRAIN_SUCCESS);
+       CU_ASSERT_EQUAL_FATAL(coolrain_writer_initialize(&writer, obuffer, sizeof(obuffer)), COOLRAIN_SUCCESS);
+
+       CU_ASSERT_EQUAL(coolrain_loader_process_template(&loader, "t1.template", &stash, &writer), COOLRAIN_SUCCESS);
+
+       coolrain_stash_destroy(&stash);
+       coolrain_writer_destroy(&writer);
+
+       CU_ASSERT_NSTRING_EQUAL(obuffer, result, strlen(result));
+}
+
+
+
+
+bool setup_test_loader(void)
+{
+
+       CU_pSuite s = CU_add_suite("Loader", init_test_loader, clean_test_loader);
+       if (NULL == s) return false;
+
+       if (NULL == CU_add_test(s, "parse", test_loader_simple)
+          )
+               return false;
+       return true;
+}
+
+
index 7ff6d5a..51c6a54 100644 (file)
@@ -50,6 +50,8 @@ void test_stash_simple(void)
        coolrain_stash_restore(&stash, vl, sizeof(vl) / sizeof(vl[0]));
 
        coolrain_stash_destroy(&stash);
+
+       coolrain_variant_unset(&v[2]);
 }