[yelp] [libyelp] Adding info documents; still a few problems, but it mostly works



commit 04c47abd3669dd5522091e9cfed4466183c4c5ef
Author: Shaun McCance <shaunm gnome org>
Date:   Mon Apr 26 18:02:32 2010 -0500

    [libyelp] Adding info documents; still a few problems, but it mostly works

 libyelp/Makefile.am                 |    4 +
 libyelp/yelp-docbook-document.c     |   13 +-
 libyelp/yelp-document.c             |    3 +-
 libyelp/yelp-info-document.c        |  482 +++++++++++++++++++++++++++++++++++
 libyelp/yelp-info-document.h        |   52 ++++
 {src => libyelp}/yelp-info-parser.c |  113 ++++----
 {src => libyelp}/yelp-info-parser.h |   10 +-
 libyelp/yelp-magic-decompressor.c   |    5 +-
 libyelp/yelp-uri.c                  |    7 +-
 src/yelp-info.c                     |  436 -------------------------------
 src/yelp-info.h                     |   53 ----
 11 files changed, 621 insertions(+), 557 deletions(-)
---
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index 770ce02..880b94b 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -6,6 +6,8 @@ libyelp_la_SOURCES =				\
 	yelp-error.c				\
 	yelp-docbook-document.c			\
 	yelp-document.c				\
+	yelp-info-document.c			\
+	yelp-info-parser.c			\
 	yelp-io-channel.c			\
 	yelp-location-entry.c			\
 	yelp-lzma-decompressor.c		\
@@ -30,6 +32,7 @@ libyelp_la_LIBADD =				\
 libyelp_headers =				\
 	yelp-docbook-document.h			\
 	yelp-document.h				\
+	yelp-info-document.h			\
 	yelp-location-entry.h			\
 	yelp-mallard-document.h			\
 	yelp-settings.h				\
@@ -55,6 +58,7 @@ EXTRA_DIST =				\
 	yelp-bz2-decompressor.h		\
 	yelp-debug.h			\
 	yelp-error.h			\
+	yelp-info-parser.h		\
 	yelp-io-channel.h		\
 	yelp-lzma-decompressor.h	\
 	yelp-magic-decompressor.h	\
diff --git a/libyelp/yelp-docbook-document.c b/libyelp/yelp-docbook-document.c
index 3849f53..a9c097c 100644
--- a/libyelp/yelp-docbook-document.c
+++ b/libyelp/yelp-docbook-document.c
@@ -152,9 +152,15 @@ yelp_docbook_document_dispose (GObject *object)
 {
     YelpDocbookDocumentPrivate *priv = GET_PRIV (object);
 
-    g_object_unref (priv->uri);
+    if (priv->uri) {
+        g_object_unref (priv->uri);
+        priv->uri = NULL;
+    }
 
-    g_object_unref (priv->sections);
+    if (priv->sections) {
+        g_object_unref (priv->sections);
+        priv->sections = NULL;
+    }
 
     G_OBJECT_CLASS (yelp_docbook_document_parent_class)->dispose (object);
 }
@@ -807,10 +813,9 @@ transform_finalized (YelpDocbookDocument *docbook,
 {
     YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
  
-   debug_print (DB_FUNCTION, "entering\n");
+    debug_print (DB_FUNCTION, "entering\n");
 
     if (priv->xmldoc)
 	xmlFreeDoc (priv->xmldoc);
     priv->xmldoc = NULL;
-
 }
diff --git a/libyelp/yelp-document.c b/libyelp/yelp-document.c
index d30e402..af93cc6 100644
--- a/libyelp/yelp-document.c
+++ b/libyelp/yelp-document.c
@@ -30,6 +30,7 @@
 #include "yelp-debug.h"
 #include "yelp-document.h"
 #include "yelp-error.h"
+#include "yelp-info-document.h"
 #include "yelp-docbook-document.h"
 #include "yelp-mallard-document.h"
 #include "yelp-simple-document.h"
@@ -170,7 +171,7 @@ yelp_document_get_for_uri (YelpUri *uri)
 	/* FIXME */
 	break;
     case YELP_URI_DOCUMENT_TYPE_INFO:
-	/* FIXME */
+	document = yelp_info_document_new (uri);
 	break;
     case YELP_URI_DOCUMENT_TYPE_TOC:
 	/* FIXME */
diff --git a/libyelp/yelp-info-document.c b/libyelp/yelp-info-document.c
new file mode 100644
index 0000000..13358a3
--- /dev/null
+++ b/libyelp/yelp-info-document.c
@@ -0,0 +1,482 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2007 Don Scorgie <dscorgie svn gnome org>
+ * Copyright (C) 2010 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: Don Scorgie <dscorgie svn gnome org>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libxml/tree.h>
+
+#include "yelp-error.h"
+#include "yelp-info-document.h"
+#include "yelp-info-parser.h"
+#include "yelp-transform.h"
+#include "yelp-debug.h"
+#include "yelp-settings.h"
+
+#define STYLESHEET DATADIR"/yelp/xslt/info2html.xsl"
+
+typedef enum {
+    INFO_STATE_BLANK,   /* Brand new, run transform as needed */
+    INFO_STATE_PARSING, /* Parsing/transforming document, please wait */
+    INFO_STATE_PARSED,  /* All done, if we ain't got it, it ain't here */
+    INFO_STATE_STOP     /* Stop everything now, object to be disposed */
+} InfoState;
+
+typedef struct _YelpInfoDocumentPrivate  YelpInfoDocumentPrivate;
+struct _YelpInfoDocumentPrivate {
+    YelpUri       *uri;
+    InfoState    state;
+
+    GMutex     *mutex;
+    GThread    *thread;
+
+    xmlDocPtr   xmldoc;
+    GtkTreeModel  *sections;
+
+    gboolean    process_running;
+    gboolean    transform_running;
+
+    YelpTransform *transform;
+    guint          chunk_ready;
+    guint          finished;
+    guint          error;
+
+    gchar   *root_id;
+    gchar   *visit_prev_id;
+};
+
+
+static void           yelp_info_document_class_init       (YelpInfoDocumentClass  *klass);
+static void           yelp_info_document_init             (YelpInfoDocument       *info);
+static void           yelp_info_document_dispose          (GObject                *object);
+static void           yelp_info_document_finalize         (GObject                *object);
+
+/* YelpDocument */
+static gboolean       info_request_page                   (YelpDocument         *document,
+                                                           const gchar          *page_id,
+                                                           GCancellable         *cancellable,
+                                                           YelpDocumentCallback  callback,
+                                                           gpointer              user_data);
+
+/* YelpTransform */
+static void           transform_chunk_ready     (YelpTransform        *transform,
+                                                 gchar                *chunk_id,
+                                                 YelpInfoDocument     *info);
+static void           transform_finished        (YelpTransform        *transform,
+                                                 YelpInfoDocument     *info);
+static void           transform_error           (YelpTransform        *transform,
+                                                 YelpInfoDocument     *info);
+static void           transform_finalized       (YelpInfoDocument     *info,
+                                                 gpointer              transform);
+
+static void           info_document_process     (YelpInfoDocument     *info);
+static gboolean       info_sections_visit       (GtkTreeModel         *model,
+                                                 GtkTreePath          *path,
+                                                 GtkTreeIter          *iter,
+                                                 YelpInfoDocument     *info);
+static void           info_document_disconnect  (YelpInfoDocument     *info);
+
+
+G_DEFINE_TYPE (YelpInfoDocument, yelp_info_document, YELP_TYPE_DOCUMENT);
+#define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_INFO_DOCUMENT, YelpInfoDocumentPrivate))
+
+static void
+yelp_info_document_class_init (YelpInfoDocumentClass *klass)
+{
+    GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
+    YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass);
+
+    object_class->dispose = yelp_info_document_dispose;
+    object_class->finalize = yelp_info_document_finalize;
+
+    document_class->request_page = info_request_page;
+
+    g_type_class_add_private (klass, sizeof (YelpInfoDocumentPrivate));
+}
+
+static void
+yelp_info_document_init (YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+
+    priv->state = INFO_STATE_BLANK;
+    priv->xmldoc = NULL;
+    priv->mutex = g_mutex_new ();
+}
+
+static void
+yelp_info_document_dispose (GObject *object)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (object);
+
+    if (priv->uri) {
+        g_object_unref (priv->uri);
+        priv->uri = NULL;
+    }
+
+    if (priv->sections) {
+        g_object_unref (priv->sections);
+        priv->sections = NULL;
+    }
+
+    if (priv->transform) {
+        g_object_unref (priv->transform);
+        priv->transform = NULL;
+    }
+
+    G_OBJECT_CLASS (yelp_info_document_parent_class)->dispose (object);
+}
+
+static void
+yelp_info_document_finalize (GObject *object)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (object);
+
+    if (priv->xmldoc)
+        xmlFreeDoc (priv->xmldoc);
+
+    g_free (priv->root_id);
+    g_free (priv->visit_prev_id);
+
+    g_mutex_free (priv->mutex);
+
+    G_OBJECT_CLASS (yelp_info_document_parent_class)->finalize (object);
+}
+
+/******************************************************************************/
+
+YelpDocument *
+yelp_info_document_new (YelpUri *uri)
+{
+    YelpInfoDocument *info;
+    YelpInfoDocumentPrivate *priv;
+
+    g_return_val_if_fail (uri != NULL, NULL);
+
+    info = (YelpInfoDocument *) g_object_new (YELP_TYPE_INFO_DOCUMENT, NULL);
+    priv = GET_PRIV (info);
+
+    priv->uri = g_object_ref (uri);
+
+    return (YelpDocument *) info;
+}
+
+
+/******************************************************************************/
+/** YelpDocument **************************************************************/
+
+static gboolean
+info_request_page (YelpDocument         *document,
+                   const gchar          *page_id,
+                   GCancellable         *cancellable,
+                   YelpDocumentCallback  callback,
+                   gpointer              user_data)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (document);
+    gchar *docuri;
+    GError *error;
+    gboolean handled;
+
+    if (page_id == NULL)
+        page_id = priv->root_id;
+
+    handled =
+        YELP_DOCUMENT_CLASS (yelp_info_document_parent_class)->request_page (document,
+                                                                             page_id,
+                                                                             cancellable,
+                                                                             callback,
+                                                                             user_data);
+    if (handled) {
+        return;
+    }
+
+    g_mutex_lock (priv->mutex);
+
+    switch (priv->state) {
+    case INFO_STATE_BLANK:
+	priv->state = INFO_STATE_PARSING;
+	priv->process_running = TRUE;
+        g_object_ref (document);
+	priv->thread = g_thread_create ((GThreadFunc) info_document_process,
+                                        document, FALSE, NULL);
+	break;
+    case INFO_STATE_PARSING:
+	break;
+    case INFO_STATE_PARSED:
+    case INFO_STATE_STOP:
+        docuri = yelp_uri_get_document_uri (priv->uri);
+        error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+                             _("The page â??%sâ?? was not found in the document â??%sâ??."),
+                             page_id, docuri);
+        g_free (docuri);
+        yelp_document_signal (document, page_id,
+                              YELP_DOCUMENT_SIGNAL_ERROR,
+                              error);
+        g_error_free (error);
+        break;
+    }
+
+    g_mutex_unlock (priv->mutex);
+}
+
+
+/******************************************************************************/
+/** YelpTransform *************************************************************/
+
+static void
+transform_chunk_ready (YelpTransform    *transform,
+                       gchar            *chunk_id,
+                       YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+    gchar *content;
+
+    g_assert (transform == priv->transform);
+
+    if (priv->state == INFO_STATE_STOP) {
+        info_document_disconnect (info);
+        return;
+    }
+
+    content = yelp_transform_take_chunk (transform, chunk_id);
+    yelp_document_give_contents (YELP_DOCUMENT (info),
+                                 chunk_id,
+                                 content,
+                                 "application/xhtml+xml");
+
+    yelp_document_signal (YELP_DOCUMENT (info),
+                          chunk_id,
+                          YELP_DOCUMENT_SIGNAL_CONTENTS,
+                          NULL);
+}
+
+static void
+transform_finished (YelpTransform    *transform,
+                    YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+    gchar *docuri;
+    GError *error;
+
+    g_assert (transform == priv->transform);
+
+    if (priv->state == INFO_STATE_STOP) {
+        info_document_disconnect (info);
+        return;
+    }
+
+    info_document_disconnect (info);
+    priv->state = INFO_STATE_PARSED;
+
+    /* We want to free priv->xmldoc, but we can't free it before transform
+       is finalized.   Otherwise, we could crash when YelpTransform frees
+       its libxslt resources.
+     */
+    g_object_weak_ref ((GObject *) transform,
+                       (GWeakNotify) transform_finalized,
+                       info);
+
+    docuri = yelp_uri_get_document_uri (priv->uri);
+    error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+                         _("The requested page was not found in the document â??%sâ??."),
+                         docuri);
+    g_free (docuri);
+    yelp_document_error_pending ((YelpDocument *) info, error);
+    g_error_free (error);
+}
+
+static void
+transform_error (YelpTransform    *transform,
+                 YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+    GError *error;
+
+    g_assert (transform == priv->transform);
+
+    if (priv->state == INFO_STATE_STOP) {
+        info_document_disconnect (info);
+        return;
+    }
+
+    error = yelp_transform_get_error (transform);
+    yelp_document_error_pending ((YelpDocument *) info, error);
+    g_error_free (error);
+
+    info_document_disconnect (info);
+}
+
+static void
+transform_finalized (YelpInfoDocument *info,
+                     gpointer          transform)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+ 
+    if (priv->xmldoc)
+	xmlFreeDoc (priv->xmldoc);
+    priv->xmldoc = NULL;
+}
+
+
+
+/******************************************************************************/
+/** Threaded ******************************************************************/
+
+static void
+info_document_process (YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+    GFile *file = NULL;
+    gchar *filepath = NULL;
+    GError *error;
+    gint  params_i = 0;
+    gchar **params = NULL;
+
+    file = yelp_uri_get_file (priv->uri);
+    if (file == NULL) {
+        error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+                             _("The file does not exist."));
+        yelp_document_error_pending ((YelpDocument *) info, error);
+        g_error_free (error);
+        goto done;
+    }
+
+    filepath = g_file_get_path (file);
+    g_object_unref (file);
+    if (!g_file_test (filepath, G_FILE_TEST_IS_REGULAR)) {
+        error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+                             _("The file â??%sâ?? does not exist."),
+                             filepath);
+        yelp_document_error_pending ((YelpDocument *) info, error);
+        g_error_free (error);
+        goto done;
+    }
+
+    priv->sections = (GtkTreeModel *) yelp_info_parser_parse_file (filepath);
+    gtk_tree_model_foreach (priv->sections,
+                            (GtkTreeModelForeachFunc) info_sections_visit,
+                            info);
+    priv->xmldoc = yelp_info_parser_parse_tree ((GtkTreeStore *) priv->sections);
+
+    if (priv->xmldoc == NULL) {
+	error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
+                             _("The file â??%sâ?? could not be parsed because it is"
+                               " not a well-formed info page."),
+                             filepath);
+	yelp_document_error_pending ((YelpDocument *) info, error);
+        goto done;
+    }
+
+    g_mutex_lock (priv->mutex);
+    if (priv->state == INFO_STATE_STOP) {
+	g_mutex_unlock (priv->mutex);
+	goto done;
+    }
+
+    priv->transform = yelp_transform_new (STYLESHEET);
+    priv->chunk_ready =
+        g_signal_connect (priv->transform, "chunk-ready",
+                          (GCallback) transform_chunk_ready,
+                          info);
+    priv->finished =
+        g_signal_connect (priv->transform, "finished",
+                          (GCallback) transform_finished,
+                          info);
+    priv->error =
+        g_signal_connect (priv->transform, "error",
+                          (GCallback) transform_error,
+                          info);
+
+    params = yelp_settings_get_all_params (yelp_settings_get_default (), 0, &params_i);
+
+    priv->transform_running = TRUE;
+    yelp_transform_start (priv->transform,
+                          priv->xmldoc,
+                          NULL,
+			  (const gchar * const *) params);
+    g_strfreev (params);
+    g_mutex_unlock (priv->mutex);
+
+ done:
+    g_free (filepath);
+    priv->process_running = FALSE;
+    g_object_unref (info);
+}
+
+static gboolean
+info_sections_visit (GtkTreeModel     *model,
+                     GtkTreePath      *path,
+                     GtkTreeIter      *iter,
+                     YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+    gchar *page_id, *title;
+
+    gtk_tree_model_get (model, iter,
+                        INFO_PARSER_COLUMN_PAGE_NO, &page_id,
+                        INFO_PARSER_COLUMN_PAGE_NAME, &title,
+                        -1);
+    yelp_document_set_page_id ((YelpDocument *) info, page_id, page_id);
+    yelp_document_set_page_title ((YelpDocument *) info, page_id, title);
+
+    if (priv->root_id == NULL) {
+        priv->root_id = g_strdup (page_id);
+        yelp_document_set_page_id ((YelpDocument *) info, NULL, page_id);
+    }
+    yelp_document_set_root_id ((YelpDocument *) info, page_id, priv->root_id);
+
+    if (priv->visit_prev_id != NULL) {
+        yelp_document_set_prev_id ((YelpDocument *) info, page_id, priv->visit_prev_id);
+        yelp_document_set_next_id ((YelpDocument *) info, priv->visit_prev_id, page_id);
+        g_free (priv->visit_prev_id);
+    }
+    priv->visit_prev_id = page_id;
+    g_free (title);
+    return FALSE;
+}
+
+static void
+info_document_disconnect (YelpInfoDocument *info)
+{
+    YelpInfoDocumentPrivate *priv = GET_PRIV (info);
+    if (priv->chunk_ready) {
+        g_signal_handler_disconnect (priv->transform, priv->chunk_ready);
+        priv->chunk_ready = 0;
+    }
+    if (priv->finished) {
+        g_signal_handler_disconnect (priv->transform, priv->finished);
+        priv->finished = 0;
+    }
+    if (priv->error) {
+        g_signal_handler_disconnect (priv->transform, priv->error);
+        priv->error = 0;
+    }
+    yelp_transform_cancel (priv->transform);
+    g_object_unref (priv->transform);
+    priv->transform = NULL;
+    priv->transform_running = FALSE;
+}
diff --git a/libyelp/yelp-info-document.h b/libyelp/yelp-info-document.h
new file mode 100644
index 0000000..4013944
--- /dev/null
+++ b/libyelp/yelp-info-document.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2007 Don Scorgie <dscorgie svn 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: Don Scorgie <dscorgie svn gnome org>
+ */
+
+#ifndef __YELP_INFO_DOCUMENT_H__
+#define __YELP_INFO_DOCUMENT_H__
+
+#include <glib-object.h>
+
+#include "yelp-document.h"
+
+#define YELP_TYPE_INFO_DOCUMENT         (yelp_info_document_get_type ())
+#define YELP_INFO_DOCUMENT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_INFO_DOCUMENT, YelpInfoDocument))
+#define YELP_INFO_DOCUMENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_INFO_DOCUMENT, YelpInfoDocumentClass))
+#define YELP_IS_INFO_DOCUMENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_INFO_DOCUMENT))
+#define YELP_IS_INFO_DOCUMENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_INFO_DOCUMENT))
+#define YELP_INFO_DOCUMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_INFO_DOCUMENT, YelpInfoDocumentClass))
+
+typedef struct _YelpInfoDocument      YelpInfoDocument;
+typedef struct _YelpInfoDocumentClass YelpInfoDocumentClass;
+typedef struct _YelpInfoPriv  YelpInfoPriv;
+
+struct _YelpInfoDocument {
+    YelpDocument      parent;
+};
+
+struct _YelpInfoDocumentClass {
+    YelpDocumentClass parent_class;
+};
+
+GType           yelp_info_document_get_type     (void);
+YelpDocument *  yelp_info_document_new          (YelpUri  *uri);
+
+#endif /* __YELP_INFO_DOCUMENT_H__ */
diff --git a/src/yelp-info-parser.c b/libyelp/yelp-info-parser.c
similarity index 94%
rename from src/yelp-info-parser.c
rename to libyelp/yelp-info-parser.c
index 276d878..e6f58df 100644
--- a/src/yelp-info-parser.c
+++ b/libyelp/yelp-info-parser.c
@@ -1,5 +1,6 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
- * Copyright (C) 2005 Davyd Madeley  <davyd madeley id au>
+ * Copyright (C) 2005 Davyd Madeley <davyd madeley id au>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -27,9 +28,8 @@
 #include <gtk/gtk.h>
 #include <string.h>
 
-#include "yelp-io-channel.h"
 #include "yelp-info-parser.h"
-#include "yelp-utils.h"
+#include "yelp-magic-decompressor.h"
 #include "yelp-debug.h"
 
 
@@ -186,15 +186,6 @@ enum
 	PAGE_OTHER
 };
 
-enum
-{
-	COLUMN_PAGE_NO,
-	COLUMN_PAGE_NAME,
-	COLUMN_PAGE_CONTENT,
-	
-	N_COLUMNS
-};
-
 static int
 page_type (char *page)
 {
@@ -213,32 +204,42 @@ page_type (char *page)
 static char
 *open_info_file (char *file)
 {
-	GIOChannel *channel = NULL;
-	int i;
-	gsize len;
-	char *str;
-	GError *error = NULL;
-	GIOStatus result = G_IO_STATUS_NORMAL;
-
-	debug_print (DB_DEBUG, "!! Opening %s...\n", file);
-	
-	channel = yelp_io_channel_new_file (file, &error);
-	if (!channel) {
-	  return NULL;
-	}
-	result = g_io_channel_read_to_end (channel, &str, &len, &error);
-	if (result != G_IO_STATUS_NORMAL) {
-	  return NULL;
-	}
-	g_io_channel_shutdown (channel, FALSE, NULL);
-	g_io_channel_unref (channel);
-
-	/* C/glib * cannot really handle \0 in strings, convert. */
-	for (i = 0; i < (len - 1); i++)
-	  if (str[i] == INFO_TAG_OPEN[0] && str[i+1] == INFO_TAG_OPEN[1])
-	    str[i] = INFO_C_TAG_OPEN[0];
-
-	return str;
+    GFile *gfile;
+    GConverter *converter;
+    GFileInputStream *file_stream;
+    GInputStream *stream;
+    gchar buf[1024];
+    gssize bytes;
+    GString *string;
+    gchar *str;
+    int i;
+
+    gfile = g_file_new_for_path (file);
+    file_stream = g_file_read (gfile, NULL, NULL);
+    converter = (GConverter *) yelp_magic_decompressor_new ();
+    stream = g_converter_input_stream_new ((GInputStream *) file_stream, converter);
+    string = g_string_new (NULL);
+
+    while ((bytes = g_input_stream_read (stream, buf, 1024, NULL, NULL)) > 0)
+        g_string_append_len (string, buf, bytes);
+
+    g_object_unref (stream);
+    /*
+    g_object_unref (converter);
+    g_object_unref (file_stream);
+    g_object_unref (file);
+    */
+
+    str = string->str;
+
+    /* C/glib * cannot really handle \0 in strings, convert. */
+    for (i = 0; i < (string->len - 1); i++)
+        if (str[i] == INFO_TAG_OPEN[0] && str[i+1] == INFO_TAG_OPEN[1])
+            str[i] = INFO_C_TAG_OPEN[0];
+
+    g_string_free (string, FALSE);
+
+    return str;
 }
 
 static gchar *
@@ -628,9 +629,9 @@ process_page (GtkTreeStore *tree, GHashTable *nodes2offsets,
 	tmp = g_strdup (node);
 	tmp = g_strdelimit (tmp, " ", '_');
 	gtk_tree_store_set (tree, iter,
-			    COLUMN_PAGE_NO, tmp,
-			    COLUMN_PAGE_NAME, node,
-			    COLUMN_PAGE_CONTENT, parts[2],
+			    INFO_PARSER_COLUMN_PAGE_NO, tmp,
+			    INFO_PARSER_COLUMN_PAGE_NAME, node,
+			    INFO_PARSER_COLUMN_PAGE_CONTENT, parts[2],
 			    -1);
 
 	g_free (tmp);
@@ -788,7 +789,7 @@ GtkTreeStore
 	 * rather then consolidating these into one dictionary, we'll just
 	 * chain our lookups */
 	processed_table = g_malloc0 (pages * sizeof (int));
-	tree = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
+	tree = gtk_tree_store_new (INFO_PARSER_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
 			G_TYPE_STRING);
 	nodes2iters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
 					     (GDestroyNotify) gtk_tree_iter_free);
@@ -828,9 +829,9 @@ parse_tree_level (GtkTreeStore *tree, xmlNodePtr *node, GtkTreeIter iter)
 	do
 	{
 		gtk_tree_model_get (GTK_TREE_MODEL (tree), &iter,
-				COLUMN_PAGE_NO, &page_no,
-				COLUMN_PAGE_NAME, &page_name,
-				COLUMN_PAGE_CONTENT, &page_content,
+				INFO_PARSER_COLUMN_PAGE_NO, &page_no,
+				INFO_PARSER_COLUMN_PAGE_NAME, &page_name,
+				INFO_PARSER_COLUMN_PAGE_CONTENT, &page_content,
 				-1);
 		debug_print (DB_DEBUG, "Got Section: %s\n", page_name);
 		if (strstr (page_content, "*Note") || 
@@ -914,8 +915,8 @@ resolve_frag_id (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
   gchar **xref = data;
 
   gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
-		      COLUMN_PAGE_NO, &page_no,
-		      COLUMN_PAGE_NAME, &page_name,
+		      INFO_PARSER_COLUMN_PAGE_NO, &page_no,
+		      INFO_PARSER_COLUMN_PAGE_NAME, &page_name,
 		      -1);
   if (g_str_equal (page_name, *xref)) {
     g_free (*xref);
@@ -1029,9 +1030,9 @@ yelp_info_parse_menu (GtkTreeStore *tree, xmlNodePtr *node,
 	ref1 = xmlNewTextChild (mholder, NULL, BAD_CAST "a",
 				BAD_CAST tmp);
 	g_free (tmp);
-	tmp = g_strconcat ("?", xref, NULL);
+        tmp = g_strconcat ("xref:", xref, NULL);
 	xmlNewProp (ref1, BAD_CAST "href", BAD_CAST tmp);
-	g_free (tmp);
+        g_free (tmp);
       } else { /* Indexy type menu  - we gotta do a  little work to fix the
 		* spacing
 		*/
@@ -1047,19 +1048,19 @@ yelp_info_parse_menu (GtkTreeStore *tree, xmlNodePtr *node,
 	
 	ref1 = xmlNewTextChild (mholder, NULL, BAD_CAST "a",
 					BAD_CAST title);
-	tmp = g_strconcat ("?", xref, NULL);
+        tmp = g_strconcat ("xref:", xref, NULL);
 	xmlNewProp (ref1, BAD_CAST "href", BAD_CAST tmp);
-	g_free (tmp);
+        g_free (tmp);
 	xmlNewTextChild (mholder, NULL, BAD_CAST "spacing",
 			 BAD_CAST sp);
 	tmp = g_strconcat (g_strstrip(ref), ".", NULL);
 	ref1 = xmlNewTextChild (mholder, NULL, BAD_CAST "a",
 				BAD_CAST tmp);
 	g_free (tmp);
-	tmp = g_strconcat ("?", xref, NULL);
+        tmp = g_strconcat ("xref:", xref, NULL);
 	xmlNewProp (ref1, BAD_CAST "href", BAD_CAST tmp);
 
-	g_free (tmp);	
+        g_free (tmp);
 	g_free (sp);
       }
       xmlNewTextChild (mholder, NULL, BAD_CAST "para",
@@ -1214,7 +1215,7 @@ info_process_text_notes (xmlNodePtr *node, gchar *content, GtkTreeStore *tree)
 	  link = g_strstrip (link);
 	  length = strlen (link) - 1;
 	  link[length] = '\0';	  
-	  href = g_strconcat ("?", link, NULL);
+	  href = g_strconcat ("xref:", link, NULL);
 	  link[length] = 'a';
 	  g_free (link);
 
@@ -1249,8 +1250,8 @@ info_process_text_notes (xmlNodePtr *node, gchar *content, GtkTreeStore *tree)
 	  frag = g_strndup (url, tmp1 - url);
 	g_strstrip (frag);
 	gtk_tree_model_foreach (GTK_TREE_MODEL (tree), resolve_frag_id, &frag);
-	href = g_strconcat ("?", frag, NULL);
-	g_free (frag);
+	href = g_strconcat ("xref:", frag, NULL);
+        g_free (frag);
       }
       for (ulink = urls; *ulink != NULL; ulink++) {
 	if (ulink == urls)
diff --git a/src/yelp-info-parser.h b/libyelp/yelp-info-parser.h
similarity index 83%
rename from src/yelp-info-parser.h
rename to libyelp/yelp-info-parser.h
index 23eb71a..d338a59 100644
--- a/src/yelp-info-parser.h
+++ b/libyelp/yelp-info-parser.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * Copyright (C) 2004, Davyd Madeley
  *
@@ -27,7 +27,13 @@
 #include <gtk/gtk.h>
 #include <libxml/tree.h>
 
-#include "yelp-utils.h"
+enum {
+    INFO_PARSER_COLUMN_PAGE_NO,
+    INFO_PARSER_COLUMN_PAGE_NAME,
+    INFO_PARSER_COLUMN_PAGE_CONTENT,
+    INFO_PARSER_N_COLUMNS
+};
+
 
 GtkTreeStore          *yelp_info_parser_parse_file  (char           *file);
 xmlDocPtr	       yelp_info_parser_parse_tree  (GtkTreeStore   *tree);
diff --git a/libyelp/yelp-magic-decompressor.c b/libyelp/yelp-magic-decompressor.c
index cf1b09b..f1bf5a0 100644
--- a/libyelp/yelp-magic-decompressor.c
+++ b/libyelp/yelp-magic-decompressor.c
@@ -49,7 +49,10 @@ yelp_magic_decompressor_dispose (GObject *object)
 {
     YelpMagicDecompressor *decompressor;
 
-    g_object_unref (decompressor->magic_decoder_ring);
+    if (decompressor->magic_decoder_ring) {
+        g_object_unref (decompressor->magic_decoder_ring);
+        decompressor->magic_decoder_ring = NULL;
+    }
 
     G_OBJECT_CLASS (yelp_magic_decompressor_parent_class)->dispose (object);
 }
diff --git a/libyelp/yelp-uri.c b/libyelp/yelp-uri.c
index 4ea70d5..fa2497e 100644
--- a/libyelp/yelp-uri.c
+++ b/libyelp/yelp-uri.c
@@ -279,14 +279,12 @@ resolve_async (YelpUri *uri)
             break;
         case YELP_URI_DOCUMENT_TYPE_DOCBOOK:
         case YELP_URI_DOCUMENT_TYPE_MALLARD:
+        case YELP_URI_DOCUMENT_TYPE_INFO:
             resolve_xref_uri (uri);
             break;
         case YELP_URI_DOCUMENT_TYPE_MAN:
             /* FIXME: what do we do? */
             break;
-        case YELP_URI_DOCUMENT_TYPE_INFO:
-            /* FIXME: what do we do? */
-            break;
         case YELP_URI_DOCUMENT_TYPE_TEXT:
         case YELP_URI_DOCUMENT_TYPE_HTML:
         case YELP_URI_DOCUMENT_TYPE_XHTML:
@@ -968,7 +966,8 @@ resolve_xref_uri (YelpUri *uri)
                                      priv->frag_id ? "#" : "",
                                      priv->frag_id ? priv->frag_id : "",
                                      NULL);
-    else if (g_str_has_prefix (priv->docuri, "file:"))
+    else if (g_str_has_prefix (priv->docuri, "file:") ||
+             g_str_has_prefix (priv->docuri, "info:") )
         priv->fulluri = g_strconcat (priv->docuri,
                                      (priv->page_id || priv->frag_id) ? "#" : "",
                                      priv->page_id ? priv->page_id : "",



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