[yelp/yelp-3-0] [yelp-transform] Adding yelp-transform to libyelp



commit 3a382a0027a627ebd76ed3449df872c73e1874f3
Author: Shaun McCance <shaunm gnome org>
Date:   Mon Oct 12 16:45:37 2009 -0500

    [yelp-transform] Adding yelp-transform to libyelp
    
    I've changed YelpTransform to be a GObject.  This changes considerably the
    way we track references to the object to make sure we don't nuke it while
    there's still a pending idle function or a running thread.

 libyelp/Makefile.am             |    2 +
 libyelp/yelp-error.h            |    3 +-
 libyelp/yelp-transform.c        |  485 +++++++++++++++++++++++++++++++++++++++
 libyelp/yelp-transform.h        |   73 ++++++
 src/yelp-transform.c            |  468 -------------------------------------
 src/yelp-transform.h            |   86 -------
 tests/Makefile.am               |    5 +
 {src => tests}/test-transform.c |  104 +++++----
 8 files changed, 630 insertions(+), 596 deletions(-)
---
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index 89298d6..6599cfd 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -6,12 +6,14 @@ libyelp_la_SOURCES =				\
 	yelp-location-entry.c			\
 	yelp-settings.c				\
 	yelp-simple-document.c			\
+	yelp-transform.c			\
 	yelp-uri.c				\
 	yelp-types.c				\
 	yelp-view.c
 
 libyelp_la_CFLAGS =				\
 	$(YELP_CFLAGS)				\
+	-DDATADIR=\""$(datadir)"\"		\
 	-DGDU_ICON_PATH=\"$(GDU_ICON_PATH)\"
 
 libyelp_la_LIBADD =				\
diff --git a/libyelp/yelp-error.h b/libyelp/yelp-error.h
index 78fbf3d..103f87e 100644
--- a/libyelp/yelp-error.h
+++ b/libyelp/yelp-error.h
@@ -31,7 +31,8 @@ G_BEGIN_DECLS
 
 typedef enum {
     YELP_ERROR_NOT_FOUND,
-    YELP_ERROR_CANT_READ
+    YELP_ERROR_CANT_READ,
+    YELP_ERROR_PROCESSING
 } YelpError;
 
 G_END_DECLS
diff --git a/libyelp/yelp-transform.c b/libyelp/yelp-transform.c
new file mode 100644
index 0000000..919b08a
--- /dev/null
+++ b/libyelp/yelp-transform.c
@@ -0,0 +1,485 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003-2007 Shaun McCance  <shaunm gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Author: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xinclude.h>
+#include <libxml/xpathInternals.h>
+#include <libxslt/documents.h>
+#include <libxslt/xslt.h>
+#include <libexslt/exslt.h>
+#include <libxslt/templates.h>
+#include <libxslt/transform.h>
+#include <libxslt/extensions.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/xsltutils.h>
+
+#include "yelp-debug.h"
+#include "yelp-error.h"
+#include "yelp-transform.h"
+
+#define YELP_NAMESPACE "http://www.gnome.org/yelp/ns";
+
+static void      yelp_transform_init        (YelpTransform           *transform);
+static void      yelp_transform_class_init  (YelpTransformClass      *klass);
+static void      yelp_transform_dispose     (GObject                 *object);
+static void      yelp_transform_finalize    (GObject                 *object);
+
+static void      transform_run              (YelpTransform           *transform);
+static gboolean  transform_free             (YelpTransform           *transform);
+static void      transform_set_error        (YelpTransform           *transform,
+                                             YelpError               *error);
+
+static gboolean  transform_chunk            (YelpTransform           *transform);
+static gboolean  transform_error            (YelpTransform           *transform);
+static gboolean  transform_final            (YelpTransform           *transform);
+
+static void      xslt_yelp_document         (xsltTransformContextPtr  ctxt,
+                                             xmlNodePtr               node,
+                                             xmlNodePtr               inst,
+                                             xsltStylePreCompPtr      comp);
+static void      xslt_yelp_cache            (xsltTransformContextPtr  ctxt,
+                                             xmlNodePtr               node,
+                                             xmlNodePtr               inst,
+                                             xsltStylePreCompPtr      comp);
+static void      xslt_yelp_aux              (xmlXPathParserContextPtr ctxt,
+                                             int                      nargs);
+
+enum {
+    CHUNK_READY,
+    FINISHED,
+    ERROR,
+    LAST_SIGNAL
+};
+static gint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (YelpTransform, yelp_transform, G_TYPE_OBJECT);
+#define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_TRANSFORM, YelpTransformPrivate))
+
+typedef struct _YelpTransformPrivate YelpTransformPrivate;
+struct _YelpTransformPrivate {
+    xmlDocPtr                input;
+    xmlDocPtr                output;
+    xsltStylesheetPtr        stylesheet;
+    xsltTransformContextPtr  context;
+
+    xmlDocPtr                aux;
+    xsltDocumentPtr          aux_xslt;
+
+    gchar                 **params;
+
+    GThread                *thread;
+    GMutex                 *mutex;
+    GAsyncQueue            *queue;
+    GHashTable             *chunks;
+
+    gboolean                running;
+    gboolean                cancelled;
+
+    GError                 *error;
+
+    /* FIXME: remove
+    YelpTransformFunc       func;
+    gpointer                user_data;
+    */
+};
+
+/******************************************************************************/
+
+static void
+yelp_transform_init (YelpTransform *transform)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    priv->queue = g_async_queue_new ();
+    priv->chunks = g_hash_table_new_full (g_str_hash,
+                                          g_str_equal,
+                                          g_free,
+                                          NULL);
+}
+
+static void
+yelp_transform_class_init (YelpTransformClass *klass)
+{
+    exsltRegisterAll ();
+
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->dispose = yelp_transform_dispose;
+    object_class->finalize = yelp_transform_finalize;
+
+    signals[CHUNK_READY] = g_signal_new ("chunk-ready",
+                                   G_TYPE_FROM_CLASS (klass),
+                                   G_SIGNAL_RUN_LAST,
+                                   0, NULL, NULL,
+                                   g_cclosure_marshal_VOID__STRING,
+                                   G_TYPE_NONE, 1, G_TYPE_STRING);
+    signals[FINISHED] = g_signal_new ("finished",
+                                      G_TYPE_FROM_CLASS (klass),
+                                      G_SIGNAL_RUN_LAST,
+                                      0, NULL, NULL,
+                                      g_cclosure_marshal_VOID__VOID,
+                                      G_TYPE_NONE, 0);
+    signals[ERROR] = g_signal_new ("error",
+                                   G_TYPE_FROM_CLASS (klass),
+                                   G_SIGNAL_RUN_LAST,
+                                   0, NULL, NULL,
+                                   g_cclosure_marshal_VOID__VOID,
+                                   G_TYPE_NONE, 0);
+
+    g_type_class_add_private (klass, sizeof (YelpTransformPrivate));
+}
+
+static void
+yelp_transform_dispose (GObject *object)
+{
+    YelpTransformPrivate *priv = GET_PRIV (object);
+
+    if (priv->queue) {
+        gchar *chunk_id;
+        while ((chunk_id = (gchar *) g_async_queue_try_pop (priv->queue)))
+            g_free (chunk_id);
+        g_async_queue_unref (priv->queue);
+        priv->queue = NULL;
+    }
+
+    /* FIXME */
+    GHashTable             *chunks;
+}
+
+static void
+yelp_transform_finalize (GObject *object)
+{
+    YelpTransformPrivate *priv = GET_PRIV (object);
+    /* We do not free input or aux.  They belong to the caller, which
+       must ensure they exist for the lifetime of the transform.
+     */
+    if (priv->output)
+        xmlFreeDoc (priv->output);
+    if (priv->stylesheet)
+        xsltFreeStylesheet (priv->stylesheet);
+    if (priv->context)
+        xsltFreeTransformContext (priv->context);
+    if (priv->aux_xslt)
+        priv->aux_xslt->doc = NULL;
+    if (priv->error)
+        g_error_free (priv->error);
+
+    g_strfreev (priv->params);
+    g_mutex_free (priv->mutex);
+}
+
+/******************************************************************************/
+
+YelpTransform *
+yelp_transform_new ()
+{
+    return (YelpTransform *) g_object_new (YELP_TYPE_TRANSFORM, NULL);
+}
+
+gboolean
+yelp_transform_set_stylesheet (YelpTransform *transform,
+                               const gchar   *stylesheet,
+                               GError       **error)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+
+    priv->stylesheet = xsltParseStylesheetFile (BAD_CAST stylesheet);
+    if (priv->stylesheet == NULL) {
+        if (error)
+            g_set_error(error, YELP_ERROR, YELP_ERROR_PROCESSING,
+                        _("The XSLT stylesheet â??%sâ?? is either missing or not valid."),
+                        stylesheet);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+void
+yelp_transform_set_aux (YelpTransform *transform,
+                        xmlDocPtr      aux)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    priv->aux = aux;
+}
+
+gboolean
+yelp_transform_start (YelpTransform       *transform,
+                      xmlDocPtr            document,
+                      const gchar * const *params,
+                      GError             **error)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+
+    priv->input = document;
+
+    priv->context = xsltNewTransformContext (priv->stylesheet,
+                                             priv->input);
+    if (priv->context == NULL) {
+        if (error)
+            g_set_error (error, YELP_ERROR, YELP_ERROR_PROCESSING,
+                         _("The XSLT stylesheet could not be compiled."));
+        return FALSE;
+    }
+
+    priv->params = g_strdupv ((gchar **) params);
+
+    priv->context->_private = transform;
+    xsltRegisterExtElement (priv->context,
+                            BAD_CAST "document",
+                            BAD_CAST YELP_NAMESPACE,
+                            (xsltTransformFunction) xslt_yelp_document);
+    xsltRegisterExtElement (priv->context,
+                            BAD_CAST "cache",
+                            BAD_CAST YELP_NAMESPACE,
+                            (xsltTransformFunction) xslt_yelp_cache);
+    xsltRegisterExtFunction (priv->context,
+                             BAD_CAST "aux",
+                             BAD_CAST YELP_NAMESPACE,
+                             (xmlXPathFunction) xslt_yelp_aux);
+
+    priv->mutex = g_mutex_new ();
+    g_mutex_lock (priv->mutex);
+    priv->running = TRUE;
+    g_object_ref (transform);
+    priv->thread = g_thread_create ((GThreadFunc) transform_run,
+                                    transform, FALSE, NULL);
+    g_mutex_unlock (priv->mutex);
+
+    return TRUE;
+}
+
+gchar *
+yelp_transform_take_chunk (YelpTransform *transform,
+                           const gchar   *chunk_id)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    gchar *buf;
+
+    g_mutex_lock (priv->mutex);
+
+    buf = g_hash_table_lookup (priv->chunks, chunk_id);
+    if (buf)
+        g_hash_table_remove (priv->chunks, chunk_id);
+
+    g_mutex_unlock (priv->mutex);
+
+    /* The caller assumes ownership of this memory. */
+    return buf;
+}
+
+void
+yelp_transform_cancel (YelpTransform *transform)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    g_mutex_lock (priv->mutex);
+    if (priv->running) {
+        priv->cancelled = TRUE;
+        priv->context->state = XSLT_STATE_STOPPED;
+    }
+    g_mutex_unlock (priv->mutex);
+}
+
+/******************************************************************************/
+
+static void
+transform_run (YelpTransform *transform)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    priv->output = xsltApplyStylesheetUser (priv->stylesheet,
+                                            priv->input,
+                                            (const char **) priv->params,
+                                            NULL, NULL,
+                                            priv->context);
+    g_mutex_lock (priv->mutex);
+    priv->running = FALSE;
+    if (!priv->cancelled) {
+        g_idle_add ((GSourceFunc) transform_final, transform);
+    }
+    else {
+        g_object_unref (transform);
+    }
+    g_mutex_unlock (priv->mutex);
+}
+
+static gboolean
+transform_chunk (YelpTransform *transform)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+    gchar *chunk_id;
+
+    if (priv->cancelled)
+        goto done;
+
+    chunk_id = (gchar *) g_async_queue_try_pop (priv->queue);
+
+    g_signal_emit (transform, signals[CHUNK_READY], 0, chunk_id);
+
+    g_free (chunk_id);
+
+ done:
+    g_object_unref (transform);
+    return FALSE;
+}
+
+static gboolean
+transform_final (YelpTransform *transform)
+{
+    YelpTransformPrivate *priv = GET_PRIV (transform);
+
+    if (priv->cancelled)
+        goto done;
+
+    g_signal_emit (transform, signals[FINISHED], 0);
+
+ done:
+    g_object_unref (transform);
+    return FALSE;
+}
+
+/******************************************************************************/
+
+static void
+xslt_yelp_document (xsltTransformContextPtr ctxt,
+                    xmlNodePtr              node,
+                    xmlNodePtr              inst,
+                    xsltStylePreCompPtr     comp)
+{
+    YelpTransform *transform;
+    YelpTransformPrivate *priv;
+    xmlChar *page_id = NULL;
+    gchar   *temp;
+    xmlChar *page_buf;
+    gint     buf_size;
+    xsltStylesheetPtr style = NULL;
+    const char *old_outfile;
+    xmlDocPtr   new_doc = NULL;
+    xmlDocPtr   old_doc;
+    xmlNodePtr  old_insert;
+
+    debug_print (DB_FUNCTION, "entering\n");
+
+    if (ctxt->state == XSLT_STATE_STOPPED)
+        return;
+
+    if (!ctxt || !node || !inst || !comp)
+        return;
+
+    transform = YELP_TRANSFORM (ctxt->_private);
+    priv = GET_PRIV (transform);
+
+    page_id = xsltEvalAttrValueTemplate (ctxt, inst,
+                                         (const xmlChar *) "href",
+                                         NULL);
+    if (page_id == NULL || *page_id == '\0') {
+        if (page_id)
+            xmlFree (page_id);
+        else
+            xsltTransformError (ctxt, NULL, inst,
+                                _("No href attribute found on "
+                                  "yelp:document\n"));
+        /* FIXME: put a real error here */
+        goto done;
+    }
+    debug_print (DB_ARG, "  page_id = \"%s\"\n", page_id);
+
+    old_outfile = ctxt->outputFile;
+    old_doc     = ctxt->output;
+    old_insert  = ctxt->insert;
+    ctxt->outputFile = (const char *) page_id;
+
+    style = xsltNewStylesheet ();
+    if (style == NULL) {
+        xsltTransformError (ctxt, NULL, inst,
+                            _("Out of memory"));
+        goto done;
+    }
+
+    style->omitXmlDeclaration = TRUE;
+
+    new_doc = xmlNewDoc (BAD_CAST "1.0");
+    new_doc->charset = XML_CHAR_ENCODING_UTF8;
+    new_doc->dict = ctxt->dict;
+    xmlDictReference (new_doc->dict);
+
+    ctxt->output = new_doc;
+    ctxt->insert = (xmlNodePtr) new_doc;
+
+    xsltApplyOneTemplate (ctxt, node, inst->children, NULL, NULL);
+    xsltSaveResultToString (&page_buf, &buf_size, new_doc, style);
+
+    ctxt->outputFile = old_outfile;
+    ctxt->output     = old_doc;
+    ctxt->insert     = old_insert;
+
+    g_mutex_lock (priv->mutex);
+
+    temp = g_strdup ((gchar *) page_id);
+    xmlFree (page_id);
+
+    g_async_queue_push (priv->queue, g_strdup ((gchar *) temp));
+    g_hash_table_insert (priv->chunks, temp, page_buf);
+
+    g_object_ref (transform);
+    g_idle_add ((GSourceFunc) transform_chunk, transform);
+
+    g_mutex_unlock (priv->mutex);
+
+ done:
+    if (new_doc)
+        xmlFreeDoc (new_doc);
+    if (style)
+        xsltFreeStylesheet (style);
+}
+
+static void
+xslt_yelp_cache (xsltTransformContextPtr ctxt,
+                 xmlNodePtr              node,
+                 xmlNodePtr              inst,
+                 xsltStylePreCompPtr     comp)
+{
+}
+
+static void
+xslt_yelp_aux (xmlXPathParserContextPtr ctxt, int nargs)
+{
+    xsltTransformContextPtr tctxt;
+    xmlXPathObjectPtr ret;
+    YelpTransform *transform;
+    YelpTransformPrivate *priv;
+
+    tctxt = xsltXPathGetTransformContext (ctxt);
+    transform = YELP_TRANSFORM (tctxt->_private);
+    priv = GET_PRIV (transform);
+
+    /* FIXME: pretty sure this eats transform->aux, memory corruption will follow */
+    priv->aux_xslt = xsltNewDocument (tctxt, priv->aux);
+
+    ret = xmlXPathNewNodeSet (xmlDocGetRootElement (priv->aux));
+    xsltExtensionInstructionResultRegister (tctxt, ret);
+    valuePush (ctxt, ret);
+}
diff --git a/libyelp/yelp-transform.h b/libyelp/yelp-transform.h
new file mode 100644
index 0000000..3c738bf
--- /dev/null
+++ b/libyelp/yelp-transform.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003-2007 Shaun McCance  <shaunm gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Author: Shaun McCance  <shaunm gnome org>
+ */
+
+#ifndef __YELP_TRANSFORM_H__
+#define __YELP_TRANSFORM_H__
+
+#include <glib.h>
+#include <libxml/tree.h>
+#include <libxslt/xslt.h>
+#include <libxslt/transform.h>
+
+/*
+typedef enum {
+    YELP_TRANSFORM_CHUNK,
+    YELP_TRANSFORM_ERROR,
+    YELP_TRANSFORM_FINAL
+} YelpTransformSignal;
+
+typedef void  (*YelpTransformFunc)  (YelpTransform       *transform,
+				     YelpTransformSignal  signal,
+				     gpointer             func_data,
+				     gpointer             user_data);
+*/
+
+#define YELP_TYPE_TRANSFORM            (yelp_transform_get_type ())
+#define YELP_TRANSFORM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), YELP_TYPE_TRANSFORM, YelpTransform))
+#define YELP_TRANSFORM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), YELP_TYPE_TRANSFORM, YelpTransformClass))
+#define YELP_IS_TRANSFORM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), YELP_TYPE_TRANSFORM))
+#define YELP_IS_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), YELP_TYPE_TRANSFORM))
+
+typedef struct _YelpTransform YelpTransform;
+typedef struct _YelpTransformClass YelpTransformClass;
+struct _YelpTransform {
+    GObject       parent;
+};
+struct _YelpTransformClass {
+    GObjectClass  parent_class;
+};
+
+YelpTransform  * yelp_transform_new            (void);
+gboolean         yelp_transform_set_stylesheet (YelpTransform       *transform,
+                                                const gchar         *stylesheet,
+                                                GError             **error);
+void             yelp_transform_set_aux        (YelpTransform       *transform,
+                                                xmlDocPtr            aux);
+gboolean         yelp_transform_start          (YelpTransform       *transform,
+                                                xmlDocPtr            document,
+                                                const gchar * const *params,
+                                                GError             **error);
+gchar *          yelp_transform_take_chunk     (YelpTransform       *transform,
+                                                const gchar         *chunk_id);
+void             yelp_transform_cancel         (YelpTransform       *transform);
+
+#endif /* __YELP_TRANSFORM_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 14d53e2..d305e34 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,6 +2,7 @@ YELP_COMMON_CFLAGS =				\
 	$(YELP_CFLAGS)				\
 	$(AM_CFLAGS)				\
 	$(YELP_DEFINES)				\
+	-DDATADIR=\""$(datadir)"\"		\
 	-I$(top_srcdir)/libyelp
 YELP_COMMON_LDADD =				\
 	$(YELP_LIBS)				\
@@ -10,6 +11,7 @@ YELP_COMMON_LDADD =				\
 check_PROGRAMS =				\
 	test-location-entry			\
 	test-settings				\
+	test-transform				\
 	test-uri				\
 	test-view
 
@@ -19,6 +21,9 @@ test_location_entry_LDADD = $(YELP_COMMON_LDADD)
 test_settings_CFLAGS = $(YELP_COMMON_CFLAGS)
 test_settings_LDADD = $(YELP_COMMON_LDADD)
 
+test_transform_CFLAGS = $(YELP_COMMON_CFLAGS)
+test_transform_LDADD = $(YELP_COMMON_LDADD)
+
 test_uri_CFLAGS = $(YELP_COMMON_CFLAGS)
 test_uri_LDADD = $(YELP_COMMON_LDADD)
 
diff --git a/src/test-transform.c b/tests/test-transform.c
similarity index 67%
rename from src/test-transform.c
rename to tests/test-transform.c
index ae659be..efda9b8 100644
--- a/src/test-transform.c
+++ b/tests/test-transform.c
@@ -19,6 +19,8 @@
  * Author: Shaun McCance <shaunm gnome org>
  */
 
+#include <config.h>
+
 #include <glib.h>
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
@@ -26,6 +28,9 @@
 #include "yelp-error.h"
 #include "yelp-transform.h"
 
+static gint num_chunks = 0;
+static gboolean freed;
+
 static gint timeout = -1;
 static gboolean random_timeout = FALSE;
 static gchar **files = NULL;
@@ -46,51 +51,60 @@ static const GOptionEntry options[] = {
 
 GMainLoop *loop;
 
-static void
+static gboolean
 transform_release (YelpTransform *transform)
 {
     printf ("\nRELEASE\n");
-    yelp_transform_release (transform);
-    /* Quit after pending things are done.  This helps test
-     * whether YelpTransform takes its release seriously.
-     */
-    g_idle_add ((GSourceFunc) g_main_loop_quit, loop);
+    if (!freed) {
+	yelp_transform_cancel (transform);
+	g_object_unref (transform);
+    }
+    freed = TRUE;
+    return FALSE;
 }
 
 static void
-transform_func (YelpTransform       *transform,
-		YelpTransformSignal  signal,
-		gpointer            *func_data,
-		gpointer             user_data)
+transform_chunk (YelpTransform *transform,
+		 const gchar   *chunk_id,
+		 gpointer       user_data)
 {
-    gchar *chunk_id;
-    gchar *chunk_data;
-    gchar *chunk_short;
-    YelpError *error;
-
-    switch (signal) {
-    case YELP_TRANSFORM_CHUNK:
-	chunk_id = (gchar *) func_data;
-	printf ("\nCHUNK: %s\n", chunk_id);
-
-	chunk_data = yelp_transform_eat_chunk (transform, chunk_id);
-	chunk_short = g_strndup (chunk_data, 300);
-	printf ("%s\n", chunk_short);
-
-	g_free (chunk_short);
-	g_free (chunk_data);
-	g_free (chunk_id);
-	break;
-    case YELP_TRANSFORM_ERROR:
-	error = (YelpError *) func_data;
-	printf ("\nERROR: %s\n", yelp_error_get_title (error));
-	yelp_error_free (error);
-	break;
-    case YELP_TRANSFORM_FINAL:
-	printf ("\nFINAL\n");
-	transform_release (transform);
-	break;
+    gchar *chunk, *small;
+    num_chunks++;
+    printf ("\nCHUNK %i: %s\n", num_chunks, chunk_id);
+
+    chunk = yelp_transform_take_chunk (transform, chunk_id);
+    small = g_strndup (chunk, 300);
+    printf ("%s\n", small);
+
+    g_free (small);
+    g_free (chunk);
+}
+
+static void
+transform_finished (YelpTransform *transform,
+		    gpointer       user_data)
+{
+    printf ("\nFINAL\n");
+    if (!freed) {
+	yelp_transform_cancel (transform);
+	g_object_unref (transform);
     }
+    freed = TRUE;
+}
+
+static void
+transform_error (YelpTransform *transform,
+		 gpointer       user_data)
+{
+    printf ("\nERROR\n");
+}
+
+static void
+transform_destroyed (gpointer  data,
+		     GObject  *object)
+{
+    printf ("\nFREED\n");
+    g_main_loop_quit (loop);
 }
 
 gint 
@@ -104,6 +118,7 @@ main (gint argc, gchar **argv)
     gchar *stylesheet;
     gchar *file;
 
+    g_type_init ();
     g_thread_init (NULL);
 
     context = g_option_context_new ("[STYLESHEET] FILE");
@@ -132,9 +147,15 @@ main (gint argc, gchar **argv)
     params[5] = "2";
     params[6] = NULL;
 
-    transform = yelp_transform_new (stylesheet,
-				    (YelpTransformFunc) transform_func,
-				    NULL);
+    transform = yelp_transform_new ();
+    g_object_weak_ref ((GObject *) transform, transform_destroyed, NULL);
+    if (!yelp_transform_set_stylesheet (transform, stylesheet, NULL))
+	return 1;
+
+    g_signal_connect (transform, "chunk-ready", (GCallback) transform_chunk, NULL);
+    g_signal_connect (transform, "finished", (GCallback) transform_finished, NULL);
+    g_signal_connect (transform, "error", (GCallback) transform_error, NULL);
+
     parser = xmlNewParserCtxt ();
     doc = xmlCtxtReadFile (parser,
 			   file,
@@ -145,7 +166,8 @@ main (gint argc, gchar **argv)
     xmlXIncludeProcessFlags (doc,
 			     XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
 			     XML_PARSE_NOENT   | XML_PARSE_NONET   );
-    yelp_transform_start (transform, doc, params);
+    if (!yelp_transform_start (transform, doc, params, NULL))
+	return 1;
 
     if (random_timeout) {
 	GRand *rand = g_rand_new ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]