[yelp] [libyelp] Adding man page support, some formatting still off



commit 78dbed19c11400d1f9b182acc01a7414dadd191f
Author: Shaun McCance <shaunm gnome org>
Date:   Tue Jun 1 15:01:57 2010 -0500

    [libyelp] Adding man page support, some formatting still off

 configure.ac                                  |    1 +
 libyelp/Makefile.am                           |    4 +
 libyelp/yelp-document.c                       |   70 ++--
 libyelp/yelp-info-document.h                  |    1 -
 libyelp/yelp-info-parser.c                    |    5 -
 libyelp/yelp-man-document.c                   |  506 +++++++++++++++++++++++++
 libyelp/yelp-man-document.h                   |   51 +++
 {src => libyelp}/yelp-man-parser.c            |  126 +++----
 {src => libyelp}/yelp-man-parser.h            |    4 +-
 src/yelp-man.c                                |  490 ------------------------
 src/yelp-man.h                                |   53 ---
 stylesheets/Makefile.am                       |    1 +
 stylesheets/{man2html.xsl => man2html.xsl.in} |   96 ++----
 stylesheets/yelp-common.xsl.in                |    2 +-
 14 files changed, 679 insertions(+), 731 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index c7854a0..3797fb0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -201,6 +201,7 @@ stylesheets/db2html.xsl
 stylesheets/db-title.xsl
 stylesheets/info2html.xsl
 stylesheets/mal2html.xsl
+stylesheets/man2html.xsl
 stylesheets/toc2html.xsl
 stylesheets/yelp-common.xsl
 data/Makefile
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index 077630e..01217d1 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -10,6 +10,8 @@ libyelp_la_SOURCES =				\
 	yelp-location-entry.c			\
 	yelp-magic-decompressor.c		\
 	yelp-mallard-document.c			\
+	yelp-man-document.c			\
+	yelp-man-parser.c			\
 	yelp-marshal.c				\
 	yelp-settings.c				\
 	yelp-simple-document.c			\
@@ -23,6 +25,7 @@ EXTRA_DIST =				\
 	yelp-debug.h			\
 	yelp-error.h			\
 	yelp-info-parser.h		\
+	yelp-man-parser.h		\
 	yelp-lzma-decompressor.h	\
 	yelp-magic-decompressor.h	\
 	yelp-marshal.list
@@ -53,6 +56,7 @@ libyelp_headers =				\
 	yelp-info-document.h			\
 	yelp-location-entry.h			\
 	yelp-mallard-document.h			\
+	yelp-man-document.h			\
 	yelp-settings.h				\
 	yelp-simple-document.h			\
 	yelp-transform.h			\
diff --git a/libyelp/yelp-document.c b/libyelp/yelp-document.c
index 4501777..1a1cbb6 100644
--- a/libyelp/yelp-document.c
+++ b/libyelp/yelp-document.c
@@ -30,9 +30,10 @@
 #include "yelp-debug.h"
 #include "yelp-document.h"
 #include "yelp-error.h"
-#include "yelp-info-document.h"
 #include "yelp-docbook-document.h"
+#include "yelp-info-document.h"
 #include "yelp-mallard-document.h"
+#include "yelp-man-document.h"
 #include "yelp-simple-document.h"
 
 typedef struct _Request Request;
@@ -76,6 +77,8 @@ struct _YelpDocumentPriv {
     Hash   *prev_ids;      /* Mapping of page IDs to "previous page" IDs */
     Hash   *next_ids;      /* Mapping of page IDs to "next page" IDs */
     Hash   *up_ids;        /* Mapping of page IDs to "up page" IDs */
+
+    GError *idle_error;
 };
 
 G_DEFINE_TYPE (YelpDocument, yelp_document, G_TYPE_OBJECT);
@@ -140,14 +143,14 @@ yelp_document_get_for_uri (YelpUri *uri)
     YelpDocument *document = NULL;
 
     if (documents == NULL)
-	documents = g_hash_table_new_full (g_str_hash, g_str_equal,
-					   g_free, g_object_unref);
+        documents = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                           g_free, g_object_unref);
 
     g_return_val_if_fail (yelp_uri_is_resolved (uri), NULL);
 
     docuri = yelp_uri_get_document_uri (uri);
     if (docuri == NULL)
-	return NULL;
+        return NULL;
 
     switch (yelp_uri_get_document_type (uri)) {
     case YELP_URI_DOCUMENT_TYPE_TEXT:
@@ -170,38 +173,38 @@ yelp_document_get_for_uri (YelpUri *uri)
     document = g_hash_table_lookup (documents, docuri);
 
     if (document != NULL) {
-	g_free (docuri);
-	return g_object_ref (document);
+        g_free (docuri);
+        return g_object_ref (document);
     }
 
     switch (yelp_uri_get_document_type (uri)) {
     case YELP_URI_DOCUMENT_TYPE_TEXT:
     case YELP_URI_DOCUMENT_TYPE_HTML:
     case YELP_URI_DOCUMENT_TYPE_XHTML:
-	document = yelp_simple_document_new (uri);
-	break;
+        document = yelp_simple_document_new (uri);
+        break;
     case YELP_URI_DOCUMENT_TYPE_DOCBOOK:
-	document = yelp_docbook_document_new (uri);
-	break;
+        document = yelp_docbook_document_new (uri);
+        break;
     case YELP_URI_DOCUMENT_TYPE_MALLARD:
-	document = yelp_mallard_document_new (uri);
-	break;
+        document = yelp_mallard_document_new (uri);
+        break;
     case YELP_URI_DOCUMENT_TYPE_MAN:
-	/* FIXME */
-	break;
+        document = yelp_man_document_new (uri);
+        break;
     case YELP_URI_DOCUMENT_TYPE_INFO:
-	document = yelp_info_document_new (uri);
-	break;
+        document = yelp_info_document_new (uri);
+        break;
     case YELP_URI_DOCUMENT_TYPE_TOC:
-	/* FIXME */
-	break;
+        /* FIXME */
+        break;
     case YELP_URI_DOCUMENT_TYPE_SEARCH:
-	/* FIXME */
-	break;
+        /* FIXME */
+        break;
     case YELP_URI_DOCUMENT_TYPE_NOT_FOUND:
     case YELP_URI_DOCUMENT_TYPE_EXTERNAL:
     case YELP_URI_DOCUMENT_TYPE_ERROR:
-	break;
+        break;
     }
 
     if (document != NULL) {
@@ -847,22 +850,19 @@ yelp_document_signal (YelpDocument       *document,
     g_mutex_unlock (document->priv->mutex);
 }
 
-void
-yelp_document_error_pending (YelpDocument *document,
-			     const GError *error)
+static gboolean
+yelp_document_error_pending_idle (YelpDocument *document)
 {
     YelpDocumentPriv *priv = GET_PRIV (document);
     GSList *cur;
     Request *request;
 
-    g_assert (document != NULL && YELP_IS_DOCUMENT (document));
-
     g_mutex_lock (priv->mutex);
 
     if (priv->reqs_pending) {
 	for (cur = priv->reqs_pending; cur; cur = cur->next) {
 	    request = cur->data;
-	    request->error = yelp_error_copy ((GError *) error);
+	    request->error = yelp_error_copy ((GError *) priv->idle_error);
 	    request->idle_funcs++;
 	    g_idle_add ((GSourceFunc) request_idle_error, request);
 	}
@@ -872,6 +872,22 @@ yelp_document_error_pending (YelpDocument *document,
     }
 
     g_mutex_unlock (priv->mutex);
+
+    g_object_unref (document);
+    return FALSE;
+}
+
+void
+yelp_document_error_pending (YelpDocument *document,
+			     const GError *error)
+{
+    YelpDocumentPriv *priv = GET_PRIV (document);
+
+    g_assert (document != NULL && YELP_IS_DOCUMENT (document));
+
+    g_object_ref (document);
+    priv->idle_error = g_error_copy (error);
+    g_idle_add ((GSourceFunc) yelp_document_error_pending_idle, document);
 }
 
 /******************************************************************************/
diff --git a/libyelp/yelp-info-document.h b/libyelp/yelp-info-document.h
index 4013944..a3f4a7b 100644
--- a/libyelp/yelp-info-document.h
+++ b/libyelp/yelp-info-document.h
@@ -36,7 +36,6 @@
 
 typedef struct _YelpInfoDocument      YelpInfoDocument;
 typedef struct _YelpInfoDocumentClass YelpInfoDocumentClass;
-typedef struct _YelpInfoPriv  YelpInfoPriv;
 
 struct _YelpInfoDocument {
     YelpDocument      parent;
diff --git a/libyelp/yelp-info-parser.c b/libyelp/yelp-info-parser.c
index cbca0e4..3310794 100644
--- a/libyelp/yelp-info-parser.c
+++ b/libyelp/yelp-info-parser.c
@@ -224,11 +224,6 @@ static char
         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;
 
diff --git a/libyelp/yelp-man-document.c b/libyelp/yelp-man-document.c
new file mode 100644
index 0000000..14ac8cd
--- /dev/null
+++ b/libyelp/yelp-man-document.c
@@ -0,0 +1,506 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2007-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: Shaun McCance <shaunm 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-man-document.h"
+#include "yelp-man-parser.h"
+#include "yelp-transform.h"
+#include "yelp-settings.h"
+
+#define STYLESHEET DATADIR"/yelp/xslt/man2html.xsl"
+
+typedef enum {
+    MAN_STATE_BLANK,   /* Brand new, run transform as needed */
+    MAN_STATE_PARSING, /* Parsing/transforming document, please wait */
+    MAN_STATE_PARSED,  /* All done, if we ain't got it, it ain't here */
+    MAN_STATE_STOP     /* Stop everything now, object to be disposed */
+} ManState;
+
+typedef struct _YelpManDocumentPrivate  YelpManDocumentPrivate;
+struct _YelpManDocumentPrivate {
+    YelpUri    *uri;
+    ManState    state;
+
+    GMutex     *mutex;
+    GThread    *thread;
+
+    xmlDocPtr   xmldoc;
+
+    gboolean    process_running;
+    gboolean    transform_running;
+
+    YelpTransform *transform;
+    guint          chunk_ready;
+    guint          finished;
+    guint          error;
+};
+
+typedef struct _YelpLangEncodings YelpLangEncodings;
+struct _YelpLangEncodings {
+    gchar *language;
+    gchar *encoding;
+};
+/* http://www.w3.org/International/O-charset-lang.html */
+static const YelpLangEncodings langmap[] = {
+    { "C",     "ISO-8859-1" },
+    { "af",    "ISO-8859-1" },
+    { "ar",    "ISO-8859-6" },
+    { "bg",    "ISO-8859-5" },
+    { "be",    "ISO-8859-5" },
+    { "ca",    "ISO-8859-1" },
+    { "cs",    "ISO-8859-2" },
+    { "da",    "ISO-8859-1" },
+    { "de",    "ISO-8859-1" },
+    { "el",    "ISO-8859-7" },
+    { "en",    "ISO-8859-1" },
+    { "eo",    "ISO-8859-3" },
+    { "es",    "ISO-8859-1" },
+    { "et",    "ISO-8859-15" },
+    { "eu",    "ISO-8859-1" },
+    { "fi",    "ISO-8859-1" },
+    { "fo",    "ISO-8859-1" },
+    { "fr",    "ISO-8859-1" },
+    { "ga",    "ISO-8859-1" },
+    { "gd",    "ISO-8859-1" },
+    { "gl",    "ISO-8859-1" },
+    { "hu",    "ISO-8859-2" },
+    { "id",    "ISO-8859-1" }, /* is this right */
+    { "mt",    "ISO-8859-3" },
+    { "is",    "ISO-8859-1" },
+    { "it",    "ISO-8859-1" },
+    { "iw",    "ISO-8859-8" },
+    { "ja",    "EUC-JP" },
+    { "ko",    "EUC-KR" },
+    { "lt",    "ISO-8859-13" },
+    { "lv",    "ISO-8859-13" },
+    { "mk",    "ISO-8859-5" },
+    { "mt",    "ISO-8859-3" },
+    { "no",    "ISO-8859-1" },
+    { "pl",    "ISO-8859-2" },
+    { "pt_BR", "ISO-8859-1" },
+    { "ro",    "ISO-8859-2" },
+    { "ru",    "KOI8-R" },
+    { "sl",    "ISO-8859-2" },
+    { "sr",    "ISO-8859-2" }, /* Latin, not cyrillic */
+    { "sk",    "ISO-8859-2" },
+    { "sv",    "ISO-8859-1" },
+    { "tr",    "ISO-8859-9" },
+    { "uk",    "ISO-8859-5" },
+    { "zh_CN", "BIG5" },
+    { "zh_TW", "BIG5" },
+    { NULL,    NULL },
+};
+
+static void           yelp_man_document_class_init       (YelpManDocumentClass   *klass);
+static void           yelp_man_document_init             (YelpManDocument        *man);
+static void           yelp_man_document_dispose          (GObject                *object);
+static void           yelp_man_document_finalize         (GObject                *object);
+
+/* YelpDocument */
+static gboolean       man_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,
+                                                          YelpManDocument        *man);
+static void           transform_finished                 (YelpTransform          *transform,
+                                                          YelpManDocument        *man);
+static void           transform_error                    (YelpTransform          *transform,
+                                                          YelpManDocument        *man);
+static void           transform_finalized                (YelpManDocument        *man,
+                                                          gpointer                transform);
+
+/* Threaded */
+static void           man_document_process               (YelpManDocument        *man);
+
+static void           man_document_disconnect            (YelpManDocument        *man);
+
+
+G_DEFINE_TYPE (YelpManDocument, yelp_man_document, YELP_TYPE_DOCUMENT);
+#define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_MAN_DOCUMENT, YelpManDocumentPrivate))
+
+static void
+yelp_man_document_class_init (YelpManDocumentClass *klass)
+{
+    GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
+    YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass);
+
+    object_class->dispose = yelp_man_document_dispose;
+    object_class->finalize = yelp_man_document_finalize;
+
+    document_class->request_page = man_request_page;
+
+    g_type_class_add_private (klass, sizeof (YelpManDocumentPrivate));
+}
+
+static void
+yelp_man_document_init (YelpManDocument *man)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+
+    priv->state = MAN_STATE_BLANK;
+    priv->mutex = g_mutex_new ();
+}
+
+static void
+yelp_man_document_dispose (GObject *object)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (object);
+
+    if (priv->uri) {
+        g_object_unref (priv->uri);
+        priv->uri = NULL;
+    }
+
+    G_OBJECT_CLASS (yelp_man_document_parent_class)->dispose (object);
+}
+
+static void
+yelp_man_document_finalize (GObject *object)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (object);
+
+    if (priv->xmldoc)
+	xmlFreeDoc (priv->xmldoc);
+
+    g_mutex_free (priv->mutex);
+
+    G_OBJECT_CLASS (yelp_man_document_parent_class)->finalize (object);
+}
+
+/******************************************************************************/
+
+YelpDocument *
+yelp_man_document_new (YelpUri *uri)
+{
+    YelpManDocument *man;
+    YelpManDocumentPrivate *priv;
+
+    g_return_val_if_fail (uri != NULL, NULL);
+
+    man = (YelpManDocument *) g_object_new (YELP_TYPE_MAN_DOCUMENT, NULL);
+    priv = GET_PRIV (man);
+
+    priv->uri = g_object_ref (uri);
+
+    return (YelpDocument *) man;
+}
+
+
+/******************************************************************************/
+/** YelpDocument **************************************************************/
+
+static gboolean
+man_request_page (YelpDocument         *document,
+                   const gchar          *page_id,
+                   GCancellable         *cancellable,
+                   YelpDocumentCallback  callback,
+                   gpointer              user_data)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (document);
+    gchar *docuri;
+    GError *error;
+    gboolean handled;
+
+    if (page_id == NULL)
+        page_id = "//index";
+
+    handled =
+        YELP_DOCUMENT_CLASS (yelp_man_document_parent_class)->request_page (document,
+                                                                            page_id,
+                                                                            cancellable,
+                                                                            callback,
+                                                                            user_data);
+    if (handled) {
+        return;
+    }
+
+    g_mutex_lock (priv->mutex);
+
+    switch (priv->state) {
+    case MAN_STATE_BLANK:
+	priv->state = MAN_STATE_PARSING;
+	priv->process_running = TRUE;
+        g_object_ref (document);
+        yelp_document_set_page_id (document, NULL, "//index");
+        yelp_document_set_page_id (document, "//index", "//index");
+        yelp_document_set_root_id (document, "//index", "//index");
+	priv->thread = g_thread_create ((GThreadFunc) man_document_process,
+                                        document, FALSE, NULL);
+	break;
+    case MAN_STATE_PARSING:
+	break;
+    case MAN_STATE_PARSED:
+    case MAN_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,
+                       YelpManDocument  *man)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+    gchar *content;
+
+    g_assert (transform == priv->transform);
+
+    if (priv->state == MAN_STATE_STOP) {
+        man_document_disconnect (man);
+        return;
+    }
+
+    content = yelp_transform_take_chunk (transform, chunk_id);
+    yelp_document_give_contents (YELP_DOCUMENT (man),
+                                 chunk_id,
+                                 content,
+                                 "application/xhtml+xml");
+
+    yelp_document_signal (YELP_DOCUMENT (man),
+                          chunk_id,
+                          YELP_DOCUMENT_SIGNAL_INFO,
+                          NULL);
+    yelp_document_signal (YELP_DOCUMENT (man),
+                          chunk_id,
+                          YELP_DOCUMENT_SIGNAL_CONTENTS,
+                          NULL);
+}
+
+static void
+transform_finished (YelpTransform    *transform,
+                    YelpManDocument  *man)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+    gchar *docuri;
+    GError *error;
+
+    g_assert (transform == priv->transform);
+
+    if (priv->state == MAN_STATE_STOP) {
+        man_document_disconnect (man);
+        return;
+    }
+
+    man_document_disconnect (man);
+    priv->state = MAN_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,
+                       man);
+
+    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 *) man, error);
+    g_error_free (error);
+}
+
+static void
+transform_error (YelpTransform    *transform,
+                 YelpManDocument  *man)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+    GError *error;
+
+    g_assert (transform == priv->transform);
+
+    if (priv->state == MAN_STATE_STOP) {
+        man_document_disconnect (man);
+        return;
+    }
+
+    error = yelp_transform_get_error (transform);
+    yelp_document_error_pending ((YelpDocument *) man, error);
+    g_error_free (error);
+
+    man_document_disconnect (man);
+}
+
+static void
+transform_finalized (YelpManDocument  *man,
+                     gpointer          transform)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+ 
+    if (priv->xmldoc)
+	xmlFreeDoc (priv->xmldoc);
+    priv->xmldoc = NULL;
+}
+
+
+/******************************************************************************/
+/** Threaded ******************************************************************/
+
+static void
+man_document_process (YelpManDocument *man)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+    GFile *file = NULL;
+    gchar *filepath = NULL;
+    GError *error;
+    gint  params_i = 0;
+    gchar **params = NULL;
+    YelpManParser *parser;
+    const gchar *language, *encoding;
+
+    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 *) man, 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 *) man, error);
+        g_error_free (error);
+        goto done;
+    }
+
+    /* FIXME: get the language */
+    language = "C";
+
+    /* default encoding if the language doesn't match below */
+    encoding = g_getenv("MAN_ENCODING");
+    if (encoding == NULL)
+	encoding = "ISO-8859-1";
+
+    if (language != NULL) {
+        gint i;
+	for (i = 0; langmap[i].language != NULL; i++) {
+	    if (g_str_equal (language, langmap[i].language)) {
+		encoding = langmap[i].encoding;
+		break;
+	    }
+	}
+    }
+
+    parser = yelp_man_parser_new ();
+    priv->xmldoc = yelp_man_parser_parse_file (parser, filepath, encoding);
+    yelp_man_parser_free (parser);
+
+    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 man page."),
+                             filepath);
+	yelp_document_error_pending ((YelpDocument *) man, error);
+    }
+
+    g_mutex_lock (priv->mutex);
+    if (priv->state == MAN_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,
+                          man);
+    priv->finished =
+        g_signal_connect (priv->transform, "finished",
+                          (GCallback) transform_finished,
+                          man);
+    priv->error =
+        g_signal_connect (priv->transform, "error",
+                          (GCallback) transform_error,
+                          man);
+
+    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 (man);
+}
+
+static void
+man_document_disconnect (YelpManDocument *man)
+{
+    YelpManDocumentPrivate *priv = GET_PRIV (man);
+    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-man-document.h b/libyelp/yelp-man-document.h
new file mode 100644
index 0000000..2379f08
--- /dev/null
+++ b/libyelp/yelp-man-document.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2007-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: Shaun McCance <shaunm gnome org>
+ */
+
+#ifndef __YELP_MAN_DOCUMENT_H__
+#define __YELP_MAN_DOCUMENT_H__
+
+#include <glib-object.h>
+
+#include "yelp-document.h"
+
+#define YELP_TYPE_MAN_DOCUMENT         (yelp_man_document_get_type ())
+#define YELP_MAN_DOCUMENT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_MAN_DOCUMENT, YelpManDocument))
+#define YELP_MAN_DOCUMENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_MAN_DOCUMENT, YelpManDocumentClass))
+#define YELP_IS_MAN_DOCUMENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_MAN_DOCUMENT))
+#define YELP_IS_MAN_DOCUMENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_MAN_DOCUMENT))
+#define YELP_MAN_DOCUMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_MAN_DOCUMENT, YelpManDocumentClass))
+
+typedef struct _YelpManDocument      YelpManDocument;
+typedef struct _YelpManDocumentClass YelpManDocumentClass;
+
+struct _YelpManDocument {
+    YelpDocument      parent;
+};
+
+struct _YelpManDocumentClass {
+    YelpDocumentClass parent_class;
+};
+
+GType           yelp_man_document_get_type     (void);
+YelpDocument *  yelp_man_document_new          (YelpUri  *uri);
+
+#endif /* __YELP_MAN_DOCUMENT_H__ */
diff --git a/src/yelp-man-parser.c b/libyelp/yelp-man-parser.c
similarity index 94%
rename from src/yelp-man-parser.c
rename to libyelp/yelp-man-parser.c
index 933b358..ef1f4d6 100644
--- a/src/yelp-man-parser.c
+++ b/libyelp/yelp-man-parser.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
- * Copyright (C) 2003 Shaun McCance  <shaunm gnome org>
+ * Copyright (C) 2003-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
@@ -17,7 +17,7 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Author: Shaun McCance  <shaunm gnome org>
+ * Author: Shaun McCance <shaunm gnome org>
  */
 
 #ifdef HAVE_CONFIG_H
@@ -29,9 +29,8 @@
 #include <libxml/tree.h>
 #include <string.h>
 
-#include "yelp-debug.h"
-#include "yelp-io-channel.h"
 #include "yelp-man-parser.h"
+#include "yelp-magic-decompressor.h"
 
 #define PARSER_CUR (g_utf8_get_char (parser->cur) != '\0' \
     && (parser->cur - parser->buffer < parser->length))
@@ -69,10 +68,9 @@ struct _YelpManParser {
     xmlNodePtr    ins;           /* The insertion node */
     xmlNodePtr    th_node;       /* The TH node, or NULL if it doesn't exist */
 
-    GIOChannel   *channel;       /* GIOChannel for the entire document */
-
-    gchar        *buffer;        /* The buffer, line at a time */
-    gsize         length;        /* The buffer length */
+    GDataInputStream *stream;    /* The GIO input stream to read from */
+    gchar            *buffer;    /* The buffer, line at a time */
+    gsize             length;    /* The buffer length */
 
     gchar        *anc;           /* The anchor point in the document */
     gchar        *cur;           /* Our current position in the document */
@@ -98,17 +96,18 @@ yelp_man_parser_parse_file (YelpManParser   *parser,
 			    gchar           *file,
 			    const gchar     *encoding)
 {
-    GError *errormsg = NULL;
-    /*gchar *ptr = NULL;*/
-
-    g_return_val_if_fail (parser != NULL, NULL);
-    g_return_val_if_fail (file != NULL, NULL);
-    g_return_val_if_fail (encoding != NULL, NULL);
-	
-    parser->channel = yelp_io_channel_new_file (file, NULL);
-
-    if (!parser->channel)
-	return NULL;
+    GFile *gfile;
+    GConverter *converter;
+    GFileInputStream *file_stream;
+    GInputStream *stream;
+    gchar *line;
+    gsize len;
+
+    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);
+    parser->stream = g_data_input_stream_new (stream);
 
     parser->doc = xmlNewDoc (BAD_CAST "1.0");
     parser->ins = xmlNewNode (NULL, BAD_CAST "Man");
@@ -116,20 +115,14 @@ yelp_man_parser_parse_file (YelpManParser   *parser,
 
     parser->make_links = TRUE;
 
-    while (g_io_channel_read_line (parser->channel,
-				   &(parser->buffer),
-				   &(parser->length),
-				   NULL, &errormsg)
-	   == G_IO_STATUS_NORMAL) {
-
+    while ((parser->buffer = g_data_input_stream_read_line (parser->stream, &(parser->length), NULL, NULL)) != NULL) {
 	/* convert this line from the encoding indicated to UTF-8 */
 	if (!g_str_equal (encoding, "UTF-8")) {
 	    GError *converr = NULL;
 	    gchar *new_buffer = NULL;
 	    gsize bytes_written = 0;
 
-	    /* since our encoding is binary (NULL) in g_io_channel, then
-	     * our returned lined should end with \n.  Therefore we are making the
+	    /* We are making the
 	     * assumption that there are no partial characters at the end of this
 	     * string, and therefore can use calls like g_convert() which do not
 	     * preserve state - someone tell me if I'm wrong here */
@@ -149,23 +142,13 @@ yelp_man_parser_parse_file (YelpManParser   *parser,
 	    parser->buffer = new_buffer;
 	    parser->length = bytes_written;
 	}
-	    
-	/* for debugging, make sure line is valid UTF-8 */
-	/*if (!g_utf8_validate (parser->buffer, (gssize)parser->length, &ptr)) {
-	    g_print ("str = %s\n", parser->buffer);
-	    g_print ("str ptr = %p\n", parser->buffer);
-	    g_print ("invalid char = %p (%c)\n", ptr, *ptr);
-	}*/
-	    
+
 	parser_parse_line (parser);
 
 	g_free (parser->buffer);
     }
 
-    if (errormsg)
-	g_print ("Error in g_io_channel_read_line()\n");
-
-    g_io_channel_shutdown (parser->channel, FALSE, NULL);
+    g_object_unref (parser->stream);
 
     return parser->doc;
 }
@@ -173,9 +156,6 @@ yelp_man_parser_parse_file (YelpManParser   *parser,
 void
 yelp_man_parser_free (YelpManParser *parser)
 {
-    if (parser->channel)
-	g_io_channel_unref (parser->channel);
-    
     g_free (parser);
 }
 
@@ -381,20 +361,20 @@ macro_section_header_handler (YelpManParser *parser, gchar *macro, GSList *args)
 {
     static gint id = 0;
     GIOStatus retval;
-    GError **errormsg = NULL;
+    GError *error = NULL;
     gchar *str = NULL;
     gchar *macro_uc = g_strdup (macro);
     gchar *ptr;
     gchar  idval[20];
     
     if (!args) {
-	retval = g_io_channel_read_line (parser->channel,
-				         &str,
-				         NULL, NULL, errormsg);
-	if (retval != G_IO_STATUS_NORMAL) {
-	    g_warning ("g_io_channel_read_line != G_IO_STATUS_NORMAL\n");
+	str = g_data_input_stream_read_line (parser->stream, NULL, NULL, &error);
+	if (error) {
+	    g_warning ("%s\n", error->message);
+	    g_error_free (error);
 	}
-    } else 
+    }
+    else 
 	str = args_concat_all (args);
 
     for (ptr = macro_uc; *ptr != '\0'; ptr++)
@@ -459,11 +439,8 @@ macro_tp_handler (YelpManParser *parser, gchar *macro, GSList *args)
 
     g_free (parser->buffer);
 
-    if (g_io_channel_read_line (parser->channel,
-                                &(parser->buffer), 
-				&(parser->length), 
-				NULL, errormsg)
-            == G_IO_STATUS_NORMAL) {
+    parser->buffer = g_data_input_stream_read_line (parser->stream, &(parser->length), NULL, NULL);
+    if (parser->buffer != NULL) {
 	parser->ins = parser_append_node (parser, "Tag");
 	parser_parse_line (parser);
 	parser->ins = parser->ins->parent;
@@ -609,7 +586,7 @@ macro_url_handler (YelpManParser *parser, gchar *macro, GSList *args)
 	    tmpNode = parser_stack_pop_node (parser, "UR");
 
 	    if (tmpNode == NULL)
-		debug_print (DB_WARN, "Found unexpected tag: '%s'\n", macro);
+		g_warning ("Found unexpected tag: '%s'\n", macro);
 	    else
 		parser->ins = tmpNode->parent;
 	} else
@@ -706,7 +683,7 @@ macro_mandoc_list_handler (YelpManParser *parser, gchar *macro, GSList *args)
         tmpNode = parser_stack_pop_node (parser, "Bl");
 
         if (tmpNode == NULL)
-	    debug_print (DB_WARN, "Found unexpected tag: '%s'\n", macro);
+	    g_warning ("Found unexpected tag: '%s'\n", macro);
         else
             parser->ins = tmpNode->parent;
     }
@@ -725,7 +702,7 @@ macro_verbatim_handler (YelpManParser *parser, gchar *macro, GSList *args)
 	tmpNode = parser_stack_pop_node (parser, "Verbatim");
 
 	if (tmpNode == NULL)
-	    debug_print (DB_WARN, "Found unexpected tag: '%s'\n", macro);
+	    g_warning ("Found unexpected tag: '%s'\n", macro);
 	else
 	    parser->ins = tmpNode->parent;
     }
@@ -1269,7 +1246,7 @@ get_argument:
     }
     else if (g_str_equal (str, "TE")) {
 	/* We should only see this from within parser_parse_table */
-	debug_print (DB_WARN, "Found unexpected tag: '%s'\n", str);
+	g_warning ("Found unexpected tag: '%s'\n", str);
         g_free (str);
     }
     /* "ie" and "if" are conditional macros in groff
@@ -1454,7 +1431,7 @@ parser_append_given_text_handle_escapes (YelpManParser *parser, gchar *text, gbo
 	        if (g_str_equal (str, "fI") || g_str_equal (str, "fB"))
 		    parser->ins = parser_append_node (parser, str);
 	        else if (!g_str_equal (str, "fR") && !g_str_equal (str, "fP"))
-		    debug_print (DB_WARN, "No rule matching the tag '%s'\n", str);
+		    g_warning ("No rule matching the tag '%s'\n", str);
 
 	        g_free (str);
 	        anc = ptr;
@@ -1754,11 +1731,9 @@ parser_handle_row_options (YelpManParser *parser)
 	
 	g_free (parser->buffer);
 
-    } while (g_io_channel_read_line (parser->channel,
-				     &(parser->buffer),
-				     &(parser->length),
-				     NULL, NULL)
-	     == G_IO_STATUS_NORMAL);
+    } while ((parser->buffer =
+	      g_data_input_stream_read_line (parser->stream, &(parser->length), NULL, NULL))
+	     != NULL);
 }
 
 static void
@@ -1769,11 +1744,8 @@ parser_parse_table (YelpManParser *parser)
 
     table_start = parser->ins;
 
-    if (g_io_channel_read_line (parser->channel,
-				&(parser->buffer),
-				&(parser->length),
-				NULL, NULL)
-	== G_IO_STATUS_NORMAL) {
+    parser->buffer = g_data_input_stream_read_line (parser->stream, &(parser->length), NULL, NULL);
+    if (parser->buffer != NULL) {
 	parser->anc = parser->buffer;
 	parser->cur = parser->buffer;
 	
@@ -1782,11 +1754,8 @@ parser_parse_table (YelpManParser *parser)
 	if (*(parser->cur) == ';') {
 	    parser_handle_table_options (parser);
 
-	    if (g_io_channel_read_line (parser->channel,
-					&(parser->buffer),
-					&(parser->length),
-					NULL, NULL)
-		== G_IO_STATUS_NORMAL) {
+	    parser->buffer = g_data_input_stream_read_line (parser->stream, &(parser->length), NULL, NULL);
+	    if (parser->buffer != NULL) {
 		parser->anc = parser->buffer;
 		parser->cur = parser->buffer;
 	    
@@ -1798,12 +1767,7 @@ parser_parse_table (YelpManParser *parser)
 	parser_handle_row_options (parser);
 
 	/* Now this is where we go through all the rows */
-	while (g_io_channel_read_line (parser->channel,
-				       &(parser->buffer),
-				       &(parser->length),
-				       NULL, NULL)
-	       == G_IO_STATUS_NORMAL) {
-	    
+	while ((parser->buffer = g_data_input_stream_read_line (parser->stream, &(parser->length), NULL, NULL)) != NULL) {
 	    parser->anc = parser->buffer;
 	    parser->cur = parser->buffer;
 	    
@@ -1814,7 +1778,7 @@ parser_parse_table (YelpManParser *parser)
 		if (*(parser->buffer + 1) == 'T'
 		    && *(parser->buffer + 2) == 'E') {
 		    if (parser_stack_pop_node (parser, "TABLE") == NULL)
-			debug_print (DB_WARN, "Found unexpected tag: 'TE'\n");
+			g_warning ("Found unexpected tag: 'TE'\n");
 		    else {
 			parser->ins = table_start;
 			
diff --git a/src/yelp-man-parser.h b/libyelp/yelp-man-parser.h
similarity index 92%
rename from src/yelp-man-parser.h
rename to libyelp/yelp-man-parser.h
index 26976d2..1901f1b 100644
--- a/src/yelp-man-parser.h
+++ b/libyelp/yelp-man-parser.h
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
- * Copyright (C) 2003 Shaun McCance  <shaunm gnome org>
+ * Copyright (C) 2003-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
@@ -17,7 +17,7 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Author: Shaun McCance  <shaunm gnome org>
+ * Author: Shaun McCance <shaunm gnome org>
  */
 
 #ifndef __YELP_MAN_PARSER_H__
diff --git a/stylesheets/Makefile.am b/stylesheets/Makefile.am
index 996b0d0..f64d28f 100644
--- a/stylesheets/Makefile.am
+++ b/stylesheets/Makefile.am
@@ -18,5 +18,6 @@ EXTRA_DIST=			\
 	db-title.xsl.in		\
 	info2html.xsl.in	\
 	mal2html.xsl.in		\
+	man2html.xsl.in		\
 	toc2html.xsl.in		\
 	yelp-common.xsl.in
diff --git a/stylesheets/man2html.xsl b/stylesheets/man2html.xsl.in
similarity index 80%
rename from stylesheets/man2html.xsl
rename to stylesheets/man2html.xsl.in
index e3dd065..5a028ed 100644
--- a/stylesheets/man2html.xsl
+++ b/stylesheets/man2html.xsl.in
@@ -6,86 +6,40 @@
                 extension-element-prefixes="yelp"
                 version="1.0">
 
-<xsl:output method="html" encoding="UTF-8"/>
-
+<xsl:import href="@XSL_GETTEXT@"/>
+<xsl:import href="@XSL_COLOR@"/>
+<xsl:import href="@XSL_ICONS@"/>
+<xsl:import href="@XSL_HTML@"/>
 <xsl:include href="yelp-common.xsl"/>
 
-<xsl:param name="stylesheet_path" select="''"/>
-<xsl:param name="linktrail"/>
-
-<xsl:param name="yelp.javascript"/>
-
-<xsl:param name="yelp.icon.blockquote"/>
-<xsl:param name="yelp.icon.caution"/>
-<xsl:param name="yelp.icon.important"/>
-<xsl:param name="yelp.icon.note"/>
-<xsl:param name="yelp.icon.programlisting"/>
-<xsl:param name="yelp.icon.tip"/>
-<xsl:param name="yelp.icon.warning"/>
-
-<xsl:param name="theme.color.text"/>
-<xsl:param name="theme.color.background"/>
-<xsl:param name="theme.color.text_light"/>
-<xsl:param name="theme.color.link"/>
-<xsl:param name="theme.color.link_visited"/>
-<xsl:param name="theme.color.gray_background"/>
-<xsl:param name="theme.color.gray_border"/>
-<xsl:param name="theme.color.blue_background"/>
-<xsl:param name="theme.color.blue_border"/>
-<xsl:param name="theme.color.red_background"/>
-<xsl:param name="theme.color.red_border"/>
-<xsl:param name="theme.color.yellow_background"/>
-<xsl:param name="theme.color.yellow_border"/>
-
-<xsl:template match="Man">
-  <xsl:choose>
-    <xsl:when test="element-available('yelp:document')">
-      <yelp:document href="index">
-        <xsl:call-template name="html"/>
-      </yelp:document>
-    </xsl:when>
-    <xsl:otherwise>
-      <xsl:call-template name="html"/>
-    </xsl:otherwise>
-  </xsl:choose>
+<xsl:param name="html.basename" select="'//index'"/>
+
+<xsl:param name="linktrail" select="''"/>
+
+<xsl:template mode="html.title.mode" match="Man">
+  <xsl:value-of select="//TH/Title"/>
 </xsl:template>
 
-<xsl:template name="html">
-  <html>
-    <head>
-      <title>
-        <xsl:value-of select="//TH/Title"/>
-      </title>
-      <style type="text/css">
-        <xsl:call-template name="html.css"/>
-      </style>
-      <script type="text/javascript">
-        <xsl:attribute name="src">
-          <xsl:value-of select="concat('file://', $yelp.javascript)"/>
-        </xsl:attribute>
-      </script>
-    </head>
-    <body>
-      <xsl:call-template name="html.linktrail"/>
-      <div class="body">
-        <xsl:apply-templates select="TH"/>
-        <xsl:apply-templates select="SH"/>
-      </div>
-    </body>
-  </html>
-</xsl:template>
-
-<xsl:template name="html.css">
-  <xsl:call-template name="yelp.common.css"/>
-  <xsl:text>
-    div[class~="SH"] { margin-left: 1.2em; }
-    div[class~="SS"] { margin-left: 1.6em; }
-
-    span[class~="R"] { font-family: serif; }
-    span[class~="Section"] { margin-left: 0.4em; }
-  
-    dd { padding-bottom: 10px; }
-  </xsl:text>
+<xsl:template mode="html.css.mode" match="Man">
+  <xsl:param name="direction"/>
+  <xsl:param name="left"/>
+  <xsl:param name="right"/>
+<xsl:text>
+body { font-family: monospace; }
+div.SH { margin-</xsl:text><xsl:value-of select="$left"/><xsl:text>: 1.2em; }
+div.SS { margin-</xsl:text><xsl:value-of select="$left"/><xsl:text>: 1.6em; }
+span.Section { margin-</xsl:text><xsl:value-of select="$left"/><xsl:text>: 0.4em; }
+dd { padding-bottom: 10px; }
+</xsl:text>
+</xsl:template>
+
+<xsl:template mode="html.header.mode" match="Man">
+  <xsl:call-template name="html.linktrail"/>
+</xsl:template>
+
+<xsl:template mode="html.body.mode" match="Man">
+  <xsl:apply-templates select="TH"/>
+  <xsl:apply-templates select="SH"/>
 </xsl:template>
 
 <xsl:template name="html.linktrail">
diff --git a/stylesheets/yelp-common.xsl.in b/stylesheets/yelp-common.xsl.in
index 6d6f891..306ce44 100644
--- a/stylesheets/yelp-common.xsl.in
+++ b/stylesheets/yelp-common.xsl.in
@@ -30,7 +30,7 @@
       </xsl:otherwise>
     </xsl:choose>
   </xsl:param>
-  <yelp:document href="{$node/@id}">
+  <yelp:document href="{$href}">
     <xsl:call-template name="html.page">
       <xsl:with-param name="node" select="$node"/>
     </xsl:call-template>



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