[yelp/yelp-3-0] [yelp-docbook-document] Adding DocBook support into libyelp
- From: Shaun McCance <shaunm src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [yelp/yelp-3-0] [yelp-docbook-document] Adding DocBook support into libyelp
- Date: Sun, 15 Nov 2009 22:37:27 +0000 (UTC)
commit 2311a1568af07235722302f9a1936a8b05699cf4
Author: Shaun McCance <shaunm gnome org>
Date: Sun Nov 15 16:36:27 2009 -0600
[yelp-docbook-document] Adding DocBook support into libyelp
libyelp/Makefile.am | 2 +
libyelp/yelp-docbook-document.c | 803 +++++++++++++++++++++++++++++++++++++++
libyelp/yelp-docbook-document.h | 51 +++
libyelp/yelp-document.c | 213 +----------
libyelp/yelp-transform.c | 52 ++-
src/yelp-docbook.c | 788 --------------------------------------
src/yelp-docbook.h | 53 ---
stylesheets/db2html.xsl.in | 3 +-
8 files changed, 897 insertions(+), 1068 deletions(-)
---
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index 6ab86f1..ed79d0c 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -3,6 +3,7 @@ lib_LTLIBRARIES = libyelp.la
libyelp_la_SOURCES = \
yelp-debug.c \
yelp-error.c \
+ yelp-docbook-document.c \
yelp-document.c \
yelp-location-entry.c \
yelp-mallard-document.c \
@@ -22,6 +23,7 @@ libyelp_la_LIBADD = \
$(YELP_LIBS)
libyelp_headers = \
+ yelp-docbook-document.h \
yelp-document.h \
yelp-location-entry.h \
yelp-mallard-document.h \
diff --git a/libyelp/yelp-docbook-document.c b/libyelp/yelp-docbook-document.c
new file mode 100644
index 0000000..028646e
--- /dev/null
+++ b/libyelp/yelp-docbook-document.c
@@ -0,0 +1,803 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003-2009 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/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xinclude.h>
+
+#include "yelp-docbook-document.h"
+#include "yelp-error.h"
+#include "yelp-settings.h"
+#include "yelp-transform.h"
+#include "yelp-debug.h"
+
+#define STYLESHEET DATADIR"/yelp/xslt/db2html.xsl"
+
+typedef enum {
+ DOCBOOK_STATE_BLANK, /* Brand new, run transform as needed */
+ DOCBOOK_STATE_PARSING, /* Parsing/transforming document, please wait */
+ DOCBOOK_STATE_PARSED, /* All done, if we ain't got it, it ain't here */
+ DOCBOOK_STATE_STOP /* Stop everything now, object to be disposed */
+} DocbookState;
+
+enum {
+ DOCBOOK_COLUMN_ID,
+ DOCBOOK_COLUMN_TITLE
+};
+
+static void yelp_docbook_document_class_init (YelpDocbookDocumentClass *klass);
+static void yelp_docbook_document_init (YelpDocbookDocument *docbook);
+static void yelp_docbook_document_dispose (GObject *object);
+static void yelp_docbook_document_finalize (GObject *object);
+
+static gboolean docbook_request_page (YelpDocument *document,
+ const gchar *page_id,
+ GCancellable *cancellable,
+ YelpDocumentCallback callback,
+ gpointer user_data);
+
+static void docbook_process (YelpDocbookDocument *docbook);
+static void docbook_disconnect (YelpDocbookDocument *docbook);
+
+static void docbook_walk (YelpDocbookDocument *docbook);
+static gboolean docbook_walk_chunkQ (YelpDocbookDocument *docbook);
+static gboolean docbook_walk_divisionQ (YelpDocbookDocument *docbook);
+static gchar * docbook_walk_get_title (YelpDocbookDocument *docbook);
+
+static void transform_chunk_ready (YelpTransform *transform,
+ gchar *chunk_id,
+ YelpDocbookDocument *docbook);
+static void transform_finished (YelpTransform *transform,
+ YelpDocbookDocument *docbook);
+static void transform_error (YelpTransform *transform,
+ YelpDocbookDocument *docbook);
+static void transform_finalized (YelpDocbookDocument *docbook,
+ gpointer transform);
+
+/* FIXME */
+#if 0
+/* static gpointer docbook_get_sections (YelpDocument *document); */
+#endif
+
+G_DEFINE_TYPE (YelpDocbookDocument, yelp_docbook_document, YELP_TYPE_DOCUMENT);
+#define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_DOCBOOK_DOCUMENT, YelpDocbookDocumentPrivate))
+
+typedef struct _YelpDocbookDocumentPrivate YelpDocbookDocumentPrivate;
+struct _YelpDocbookDocumentPrivate {
+ YelpUri *uri;
+
+ DocbookState state;
+
+ GMutex *mutex;
+ GThread *thread;
+
+ gboolean process_running;
+ gboolean transform_running;
+
+ YelpTransform *transform;
+ guint chunk_ready;
+ guint finished;
+ guint error;
+
+ /* FIXME: all */
+ GtkTreeModel *sections;
+ GtkTreeIter *sections_iter; /* On the stack, do not free */
+
+ xmlDocPtr xmldoc;
+ xmlNodePtr xmlcur;
+ gint max_depth;
+ gint cur_depth;
+ gchar *cur_page_id;
+ gchar *cur_prev_id;
+};
+
+/******************************************************************************/
+
+static void
+yelp_docbook_document_class_init (YelpDocbookDocumentClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass);
+
+ object_class->dispose = yelp_docbook_document_dispose;
+ object_class->finalize = yelp_docbook_document_finalize;
+
+ document_class->request_page = docbook_request_page;
+ /*document_class->get_sections = docbook_get_sections;*/
+
+ g_type_class_add_private (klass, sizeof (YelpDocbookDocumentPrivate));
+}
+
+static void
+yelp_docbook_document_init (YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+
+ priv->sections = NULL;
+
+ priv->state = DOCBOOK_STATE_BLANK;
+
+ priv->mutex = g_mutex_new ();
+}
+
+static void
+yelp_docbook_document_dispose (GObject *object)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (object);
+
+ g_object_unref (priv->uri);
+
+ g_object_unref (priv->sections);
+
+ G_OBJECT_CLASS (yelp_docbook_document_parent_class)->dispose (object);
+}
+
+static void
+yelp_docbook_document_finalize (GObject *object)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (object);
+
+ if (priv->xmldoc)
+ xmlFreeDoc (priv->xmldoc);
+
+ g_free (priv->cur_page_id);
+ g_free (priv->cur_prev_id);
+
+ g_mutex_free (priv->mutex);
+
+ G_OBJECT_CLASS (yelp_docbook_document_parent_class)->finalize (object);
+}
+
+/******************************************************************************/
+
+YelpDocument *
+yelp_docbook_document_new (YelpUri *uri)
+{
+ YelpDocbookDocument *docbook;
+ YelpDocbookDocumentPrivate *priv;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ docbook = (YelpDocbookDocument *) g_object_new (YELP_TYPE_DOCBOOK_DOCUMENT, NULL);
+ priv = GET_PRIV (docbook);
+
+ priv->uri = g_object_ref (uri);
+
+ yelp_document_set_page_id (YELP_DOCUMENT (docbook), "//about", "//about");
+
+ priv->sections =
+ GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING));
+
+ return (YelpDocument *) docbook;
+}
+
+/******************************************************************************/
+
+/** YelpDocument **************************************************************/
+
+/* static gpointer */
+/* docbook_get_sections (YelpDocument *document) */
+/* { */
+/* YelpDocbook *db = (YelpDocbook *) document; */
+
+/* return (gpointer) (db->priv->sections); */
+/* } */
+
+static gboolean
+docbook_request_page (YelpDocument *document,
+ const gchar *page_id,
+ GCancellable *cancellable,
+ YelpDocumentCallback callback,
+ gpointer user_data)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (document);
+ gchar *docuri;
+ GError *error;
+ gboolean handled;
+
+ debug_print (DB_FUNCTION, "entering\n");
+ debug_print (DB_ARG, " page_id=\"%s\"\n", page_id);
+
+ if (page_id == NULL)
+ page_id = "//index";
+
+ handled =
+ YELP_DOCUMENT_CLASS (yelp_docbook_document_parent_class)->request_page (document,
+ page_id,
+ cancellable,
+ callback,
+ user_data);
+ if (handled) {
+ return;
+ }
+
+ g_mutex_lock (priv->mutex);
+
+ switch (priv->state) {
+ case DOCBOOK_STATE_BLANK:
+ priv->state = DOCBOOK_STATE_PARSING;
+ priv->process_running = TRUE;
+ g_object_ref (document);
+ priv->thread = g_thread_create ((GThreadFunc) docbook_process,
+ document, FALSE, NULL);
+ break;
+ case DOCBOOK_STATE_PARSING:
+ break;
+ case DOCBOOK_STATE_PARSED:
+ case DOCBOOK_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);
+}
+
+/******************************************************************************/
+
+static void
+docbook_process (YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ YelpDocument *document = YELP_DOCUMENT (docbook);
+ GFile *file = NULL;
+ gchar *filepath = NULL;
+ xmlDocPtr xmldoc = NULL;
+ xmlChar *id = NULL;
+ xmlParserCtxtPtr parserCtxt = NULL;
+ GError *error;
+ gint params_i = 0;
+ gchar **params = NULL;
+
+ debug_print (DB_FUNCTION, "entering\n");
+
+ 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 (document, 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 (document, error);
+ g_error_free (error);
+ goto done;
+ }
+
+ parserCtxt = xmlNewParserCtxt ();
+ xmldoc = xmlCtxtReadFile (parserCtxt,
+ filepath, NULL,
+ XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
+ XML_PARSE_NOENT | XML_PARSE_NONET );
+
+ if (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 XML document."),
+ filepath);
+ yelp_document_error_pending (document, error);
+ g_error_free (error);
+ goto done;
+ }
+
+ if (xmlXIncludeProcessFlags (xmldoc,
+ XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
+ XML_PARSE_NOENT | XML_PARSE_NONET )
+ < 0) {
+ error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
+ _("The file â??%sâ?? could not be parsed because"
+ " one or more of its included files is not"
+ " a well-formed XML document."),
+ filepath);
+ yelp_document_error_pending (document, error);
+ g_error_free (error);
+ goto done;
+ }
+
+ g_mutex_lock (priv->mutex);
+ if (!xmlStrcmp (xmlDocGetRootElement (xmldoc)->name, BAD_CAST "book"))
+ priv->max_depth = 2;
+ else
+ priv->max_depth = 1;
+
+ priv->xmldoc = xmldoc;
+ priv->xmlcur = xmlDocGetRootElement (xmldoc);
+
+ id = xmlGetProp (priv->xmlcur, BAD_CAST "id");
+ if (id) {
+ yelp_document_set_page_id (document, NULL, (gchar *) id);
+ yelp_document_set_page_id (document, "//index", (gchar *) id);
+ yelp_document_set_prev_id (document, (gchar *) id, "//about");
+ yelp_document_set_next_id (document, "//about", (gchar *) id);
+ }
+ else {
+ yelp_document_set_page_id (document, NULL, "//index");
+ yelp_document_set_prev_id (document, "//index", "//about");
+ yelp_document_set_next_id (document, "//about", "//index");
+ /* add the id attribute to the root element with value "index"
+ * so when we try to load the document later, it doesn't fail */
+ xmlNewProp (priv->xmlcur, BAD_CAST "id", BAD_CAST "//index");
+ }
+ g_mutex_unlock (priv->mutex);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->state == DOCBOOK_STATE_STOP) {
+ g_mutex_unlock (priv->mutex);
+ goto done;
+ }
+ g_mutex_unlock (priv->mutex);
+
+ docbook_walk (docbook);
+
+ g_mutex_lock (priv->mutex);
+ if (priv->state == DOCBOOK_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,
+ docbook);
+ priv->finished =
+ g_signal_connect (priv->transform, "finished",
+ (GCallback) transform_finished,
+ docbook);
+ priv->error =
+ g_signal_connect (priv->transform, "error",
+ (GCallback) transform_error,
+ docbook);
+
+ params = yelp_settings_get_all_params (yelp_settings_get_default (), 2, ¶ms_i);
+ params[params_i++] = g_strdup ("db.chunk.max_depth");
+ params[params_i++] = g_strdup_printf ("%i", priv->max_depth);
+ params[params_i] = NULL;
+
+ 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);
+ if (id)
+ xmlFree (id);
+ if (parserCtxt)
+ xmlFreeParserCtxt (parserCtxt);
+
+ priv->process_running = FALSE;
+ g_object_unref (docbook);
+}
+
+static void
+docbook_disconnect (YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ 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;
+}
+
+/******************************************************************************/
+
+static void
+docbook_walk (YelpDocbookDocument *docbook)
+{
+ static gint autoid = 0;
+ gchar autoidstr[20];
+ xmlChar *id = NULL;
+ xmlChar *title = NULL;
+ gchar *old_page_id = NULL;
+ xmlNodePtr cur, old_cur;
+ GtkTreeIter iter;
+ GtkTreeIter *old_iter = NULL;
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ YelpDocument *document = YELP_DOCUMENT (docbook);
+
+ debug_print (DB_FUNCTION, "entering\n");
+ debug_print (DB_DEBUG, " priv->xmlcur->name: %s\n", priv->xmlcur->name);
+
+ /* Check for the db.chunk.max_depth PI and set max chunk depth */
+ if (priv->cur_depth == 0)
+ for (cur = priv->xmlcur; cur; cur = cur->prev)
+ if (cur->type == XML_PI_NODE)
+ if (!xmlStrcmp (cur->name, (const xmlChar *) "db.chunk.max_depth")) {
+ gint max = atoi ((gchar *) cur->content);
+ if (max)
+ priv->max_depth = max;
+ break;
+ }
+
+ id = xmlGetProp (priv->xmlcur, BAD_CAST "id");
+
+ if (docbook_walk_divisionQ (docbook) && !id) {
+ /* If id attribute is not present, autogenerate a
+ * unique value, and insert it into the in-memory tree */
+ g_snprintf (autoidstr, 20, "//autoid-%d", ++autoid);
+ xmlNewProp (priv->xmlcur, BAD_CAST "id", BAD_CAST autoidstr);
+ id = xmlGetProp (priv->xmlcur, BAD_CAST "id");
+ }
+
+ if (docbook_walk_chunkQ (docbook)) {
+ title = BAD_CAST docbook_walk_get_title (docbook);
+
+ debug_print (DB_DEBUG, " id: \"%s\"\n", id);
+ debug_print (DB_DEBUG, " title: \"%s\"\n", title);
+
+ yelp_document_set_title (document, (gchar *) id, (gchar *) title);
+
+ gdk_threads_enter ();
+ gtk_tree_store_append (GTK_TREE_STORE (priv->sections),
+ &iter,
+ priv->sections_iter);
+ gtk_tree_store_set (GTK_TREE_STORE (priv->sections),
+ &iter,
+ DOCBOOK_COLUMN_ID, id,
+ DOCBOOK_COLUMN_TITLE, title,
+ -1);
+ gdk_threads_leave ();
+
+ if (priv->cur_prev_id) {
+ yelp_document_set_prev_id (document, (gchar *) id, priv->cur_prev_id);
+ yelp_document_set_next_id (document, priv->cur_prev_id, (gchar *) id);
+ g_free (priv->cur_prev_id);
+ }
+ priv->cur_prev_id = g_strdup ((gchar *) id);
+
+ if (priv->cur_page_id)
+ yelp_document_set_up_id (document, (gchar *) id, priv->cur_page_id);
+ old_page_id = priv->cur_page_id;
+ priv->cur_page_id = g_strdup ((gchar *) id);
+
+ old_iter = priv->sections_iter;
+ if (priv->xmlcur->parent->type != XML_DOCUMENT_NODE)
+ priv->sections_iter = &iter;
+ }
+
+ old_cur = priv->xmlcur;
+ priv->cur_depth++;
+ if (id)
+ yelp_document_set_page_id (document, (gchar *) id, priv->cur_page_id);
+
+ for (cur = priv->xmlcur->children; cur; cur = cur->next) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ priv->xmlcur = cur;
+ docbook_walk (docbook);
+ }
+ }
+ priv->cur_depth--;
+ priv->xmlcur = old_cur;
+
+ if (docbook_walk_chunkQ (docbook)) {
+ priv->sections_iter = old_iter;
+ g_free (priv->cur_page_id);
+ priv->cur_page_id = old_page_id;
+ }
+
+ if (priv->cur_depth == 0) {
+ g_free (priv->cur_prev_id);
+ priv->cur_prev_id = NULL;
+
+ g_free (priv->cur_page_id);
+ priv->cur_page_id = NULL;
+ }
+
+ if (id != NULL)
+ xmlFree (id);
+ if (title != NULL)
+ xmlFree (title);
+}
+
+static gboolean
+docbook_walk_chunkQ (YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ if (priv->cur_depth <= priv->max_depth)
+ return docbook_walk_divisionQ (docbook);
+ else
+ return FALSE;
+}
+
+static gboolean
+docbook_walk_divisionQ (YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ xmlNodePtr node = priv->xmlcur;
+ return (!xmlStrcmp (node->name, (const xmlChar *) "appendix") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "article") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "book") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "bibliography") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "chapter") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "colophon") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "glossary") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "index") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "part") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "preface") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "reference") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "refentry") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "refsect1") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "refsect2") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "refsect3") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "refsection") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "sect1") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "sect2") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "sect3") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "sect4") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "sect5") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "section") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "set") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "setindex") ||
+ !xmlStrcmp (node->name, (const xmlChar *) "simplesect") );
+}
+
+static gchar *
+docbook_walk_get_title (YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ gchar *infoname = NULL;
+ xmlNodePtr child = NULL;
+ xmlNodePtr title = NULL;
+ xmlNodePtr title_tmp = NULL;
+
+ if (!xmlStrcmp (priv->xmlcur->name, BAD_CAST "refentry")) {
+ /* The title for a refentry element can come from the following:
+ * refmeta/refentrytitle
+ * refentryinfo/title[abbrev]
+ * refnamediv/refname
+ * We take the first one we find.
+ */
+ for (child = priv->xmlcur->children; child; child = child->next) {
+ if (!xmlStrcmp (child->name, BAD_CAST "refmeta")) {
+ for (title = child->children; title; title = title->next) {
+ if (!xmlStrcmp (title->name, BAD_CAST "refentrytitle"))
+ break;
+ }
+ if (title)
+ goto done;
+ }
+ else if (!xmlStrcmp (child->name, BAD_CAST "refentryinfo")) {
+ for (title = child->children; title; title = title->next) {
+ if (!xmlStrcmp (title->name, BAD_CAST "titleabbrev"))
+ break;
+ else if (!xmlStrcmp (title->name, BAD_CAST "title"))
+ title_tmp = title;
+ }
+ if (title)
+ goto done;
+ else if (title_tmp) {
+ title = title_tmp;
+ goto done;
+ }
+ }
+ else if (!xmlStrcmp (child->name, BAD_CAST "refnamediv")) {
+ for (title = child->children; title; title = title->next) {
+ if (!xmlStrcmp (title->name, BAD_CAST "refname"))
+ break;
+ else if (!xmlStrcmp (title->name, BAD_CAST "refpurpose")) {
+ title = NULL;
+ break;
+ }
+ }
+ if (title)
+ goto done;
+ }
+ else if (!xmlStrncmp (child->name, BAD_CAST "refsect", 7))
+ break;
+ }
+ }
+ else {
+ /* The title for other elements appears in the following:
+ * title[abbrev]
+ * *info/title[abbrev]
+ * blockinfo/title[abbrev]
+ * objectinfo/title[abbrev]
+ * We take them in that order.
+ */
+ xmlNodePtr infos[3] = {NULL, NULL, NULL};
+ int i;
+
+ infoname = g_strdup_printf ("%sinfo", priv->xmlcur->name);
+
+ for (child = priv->xmlcur->children; child; child = child->next) {
+ if (!xmlStrcmp (child->name, BAD_CAST "titleabbrev")) {
+ title = child;
+ goto done;
+ }
+ else if (!xmlStrcmp (child->name, BAD_CAST "title"))
+ title_tmp = child;
+ else if (!xmlStrcmp (child->name, BAD_CAST infoname))
+ infos[0] = child;
+ else if (!xmlStrcmp (child->name, BAD_CAST "blockinfo"))
+ infos[1] = child;
+ else if (!xmlStrcmp (child->name, BAD_CAST "objectinfo"))
+ infos[2] = child;
+ }
+
+ if (title_tmp) {
+ title = title_tmp;
+ goto done;
+ }
+
+ for (i = 0; i < 3; i++) {
+ child = infos[i];
+ if (child) {
+ for (title = child->children; title; title = title->next) {
+ if (!xmlStrcmp (title->name, BAD_CAST "titleabbrev"))
+ goto done;
+ else if (!xmlStrcmp (title->name, BAD_CAST "title"))
+ title_tmp = title;
+ }
+ if (title_tmp) {
+ title = title_tmp;
+ goto done;
+ }
+ }
+ }
+ }
+
+ done:
+ g_free (infoname);
+
+ if (title)
+ return (gchar *) xmlNodeGetContent (title);
+ else
+ return g_strdup (_("Unknown"));
+}
+
+/******************************************************************************/
+
+static void
+transform_chunk_ready (YelpTransform *transform,
+ gchar *chunk_id,
+ YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ gchar *content;
+
+ debug_print (DB_FUNCTION, "entering\n");
+ g_assert (transform == priv->transform);
+
+ if (priv->state == DOCBOOK_STATE_STOP) {
+ docbook_disconnect (docbook);
+ return;
+ }
+
+ content = yelp_transform_take_chunk (transform, chunk_id);
+ yelp_document_give_contents (YELP_DOCUMENT (docbook),
+ chunk_id,
+ content,
+ "application/xhtml+xml");
+
+ yelp_document_signal (YELP_DOCUMENT (docbook),
+ chunk_id,
+ YELP_DOCUMENT_SIGNAL_CONTENTS,
+ NULL);
+}
+
+static void
+transform_finished (YelpTransform *transform,
+ YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ gchar *docuri;
+ GError *error;
+
+ debug_print (DB_FUNCTION, "entering\n");
+ g_assert (transform == priv->transform);
+
+ if (priv->state == DOCBOOK_STATE_STOP) {
+ docbook_disconnect (docbook);
+ return;
+ }
+
+ docbook_disconnect (docbook);
+
+ /* 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 (transform,
+ transform_finalized,
+ docbook);
+
+ 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 *) docbook, error);
+ g_error_free (error);
+}
+
+static void
+transform_error (YelpTransform *transform,
+ YelpDocbookDocument *docbook)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+ GError *error;
+
+ debug_print (DB_FUNCTION, "entering\n");
+ g_assert (transform == priv->transform);
+
+ if (priv->state == DOCBOOK_STATE_STOP) {
+ docbook_disconnect (docbook);
+ return;
+ }
+
+ error = yelp_transform_get_error (transform);
+ yelp_document_error_pending ((YelpDocument *) docbook, error);
+ g_error_free (error);
+
+ docbook_disconnect (docbook);
+}
+
+static void
+transform_finalized (YelpDocbookDocument *docbook,
+ gpointer transform)
+{
+ YelpDocbookDocumentPrivate *priv = GET_PRIV (docbook);
+
+ debug_print (DB_FUNCTION, "entering\n");
+
+ if (priv->xmldoc)
+ xmlFreeDoc (priv->xmldoc);
+ priv->xmldoc = NULL;
+
+}
diff --git a/libyelp/yelp-docbook-document.h b/libyelp/yelp-docbook-document.h
new file mode 100644
index 0000000..3e0f184
--- /dev/null
+++ b/libyelp/yelp-docbook-document.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2003-2009 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_DOCBOOK_DOCUMENT_H__
+#define __YELP_DOCBOOK_DOCUMENT_H__
+
+#include <glib-object.h>
+
+#include "yelp-document.h"
+
+#define YELP_TYPE_DOCBOOK_DOCUMENT (yelp_docbook_document_get_type ())
+#define YELP_DOCBOOK_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_DOCBOOK_DOCUMENT, YelpDocbookDocument))
+#define YELP_DOCBOOK_DOCUMENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_DOCBOOK_DOCUMENT, YelpDocbookDocumentClass))
+#define YELP_IS_DOCBOOK_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_DOCBOOK_DOCUMENT))
+#define YELP_IS_DOCBOOK_DOCUMENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_DOCBOOK_DOCUMENT))
+#define YELP_DOCBOOK_DOCUMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_DOCBOOK_DOCUMENT, YelpDocbookDocumentClass))
+
+typedef struct _YelpDocbookDocument YelpDocbookDocument;
+typedef struct _YelpDocbookDocumentClass YelpDocbookDocumentClass;
+
+struct _YelpDocbookDocument {
+ YelpDocument parent;
+};
+
+struct _YelpDocbookDocumentClass {
+ YelpDocumentClass parent_class;
+};
+
+GType yelp_docbook_document_get_type (void);
+YelpDocument * yelp_docbook_document_new (YelpUri *uri);
+
+#endif /* __YELP_DOCBOOK_DOCUMENT_H__ */
diff --git a/libyelp/yelp-document.c b/libyelp/yelp-document.c
index 53ba5a2..899aae6 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-docbook-document.h"
#include "yelp-mallard-document.h"
#include "yelp-simple-document.h"
@@ -71,9 +72,6 @@ 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 */
-
- GMutex *str_mutex;
- GHashTable *str_refs;
};
G_DEFINE_TYPE (YelpDocument, yelp_document, G_TYPE_OBJECT);
@@ -124,12 +122,6 @@ static void request_free (Request *request);
static const gchar * str_ref (const gchar *str);
static void str_unref (const gchar *str);
-#if 0
-static gboolean request_idle_error (Request *request);
-static gboolean request_idle_final (YelpDocument *document);
-
-#endif
-
GStaticMutex str_mutex = G_STATIC_MUTEX_INIT;
GHashTable *str_refs = NULL;
@@ -166,7 +158,7 @@ yelp_document_get_for_uri (YelpUri *uri)
document = yelp_simple_document_new (uri);
break;
case YELP_URI_DOCUMENT_TYPE_DOCBOOK:
- /* FIXME */
+ document = yelp_docbook_document_new (uri);
break;
case YELP_URI_DOCUMENT_TYPE_MALLARD:
document = yelp_mallard_document_new (uri);
@@ -853,6 +845,7 @@ static gboolean
request_idle_contents (Request *request)
{
YelpDocument *document;
+ YelpDocumentPriv *priv;
YelpDocumentCallback callback = NULL;
gpointer user_data = user_data;
@@ -864,9 +857,12 @@ request_idle_contents (Request *request)
}
document = g_object_ref (request->document);
+ priv = GET_PRIV (document);
g_mutex_lock (document->priv->mutex);
+ priv->reqs_pending = g_slist_remove (priv->reqs_pending, request);
+
callback = request->callback;
user_data = request->user_data;
request->idle_funcs--;
@@ -1024,200 +1020,3 @@ str_unref (const gchar *str)
g_static_mutex_unlock (&str_mutex);
}
-#if 0
-
-void
-yelp_document_add_page (YelpDocument *document, gchar *page_id, const gchar *contents)
-{
- GSList *reqs, *cur;
- Request *request;
- YelpDocumentPriv *priv;
-
- g_assert (document != NULL && YELP_IS_DOCUMENT (document));
-
- debug_print (DB_FUNCTION, "entering\n");
- debug_print (DB_ARG, " page_id = \"%s\"\n", page_id);
- priv = document->priv;
-
- g_mutex_lock (priv->mutex);
-
- hashh_replace (priv->contents,
- g_strdup (page_id),
- str_ref ((gchar *) contents));
-
- reqs = g_hash_table_lookup (priv->reqs_by_page_id, page_id);
- for (cur = reqs; cur != NULL; cur = cur->next) {
- if (cur->data) {
- request = (Request *) cur->data;
- request->idle_funcs++;
- g_idle_add ((GSourceFunc) request_idle_page, request);
- }
- }
-
- g_mutex_unlock (priv->mutex);
-}
-
-gboolean
-yelp_document_has_page (YelpDocument *document, gchar *page_id)
-{
- gchar *content;
- g_assert (document != NULL && YELP_IS_DOCUMENT (document));
- content = g_hash_table_lookup (document->priv->contents, page_id);
- return !(content == NULL);
-}
-
-void
-yelp_document_error_request (YelpDocument *document, gint req_id, YelpError *error)
-{
- Request *request;
- YelpDocumentPriv *priv;
-
- g_assert (document != NULL && YELP_IS_DOCUMENT (document));
-
- debug_print (DB_FUNCTION, "entering\n");
- priv = document->priv;
-
- g_mutex_lock (priv->mutex);
-
- request = g_hash_table_lookup (priv->reqs_by_req_id,
- GINT_TO_POINTER (req_id));
- if (request) {
- request->error = error;
- request->idle_funcs++;
- g_idle_add ((GSourceFunc) request_idle_error, request);
- } else {
- yelp_error_free (error);
- }
-
- g_mutex_unlock (priv->mutex);
-}
-
-void
-yelp_document_error_page (YelpDocument *document, gchar *page_id, YelpError *error)
-{
- GSList *requests;
- Request *request = NULL;
- YelpDocumentPriv *priv;
-
- g_assert (document != NULL && YELP_IS_DOCUMENT (document));
-
- debug_print (DB_FUNCTION, "entering\n");
- priv = document->priv;
- g_mutex_lock (priv->mutex);
-
- requests = g_hash_table_lookup (priv->reqs_by_page_id, page_id);
- while (requests) {
- request = (Request *) requests->data;
- if (request && request->error == NULL) {
- request->error = yelp_error_copy (error);
- request->idle_funcs++;
- g_idle_add ((GSourceFunc) request_idle_error, request);
- }
- requests = requests->next;
- }
-
- yelp_error_free (error);
-
- g_mutex_unlock (priv->mutex);
-}
-
-void
-yelp_document_final_pending (YelpDocument *document, YelpError *error)
-{
- YelpDocumentPriv *priv;
-
- g_assert (document != NULL && YELP_IS_DOCUMENT (document));
-
- debug_print (DB_FUNCTION, "entering\n");
- priv = document->priv;
-
- g_mutex_lock (priv->mutex);
- if (priv->reqs_pending) {
- priv->final_error = error;
- g_idle_add ((GSourceFunc) request_idle_final, document);
- } else {
- yelp_error_free (error);
- }
-
- g_mutex_unlock (priv->mutex);
-}
-
-
-/******************************************************************************/
-
-
-
-static gboolean
-request_idle_final (YelpDocument *document)
-{
- YelpDocumentPriv *priv;
- YelpDocumentFunc func = NULL;
- YelpError *error = NULL;
- gint req_id = 0;
- gpointer user_data = user_data;
- Request *request = NULL;
- GSList *cur = NULL;
-
- debug_print (DB_FUNCTION, "entering\n");
-
- priv = document->priv;
-
- g_mutex_lock (priv->mutex);
-
- if (priv->reqs_pending == NULL) {
- /*
- Time to bail as we shouldn't be here anyway.
- */
- g_mutex_unlock (priv->mutex);
- return FALSE;
- }
-
- for (cur = priv->reqs_pending; cur; cur = cur->next) {
- request = cur->data;
- if (request->idle_funcs != 0) {
- /*
- While there are outstanding requests, we should wait for them
- to complete before signalling the error
- */
- request->idle_funcs++;
- g_mutex_unlock (priv->mutex);
- return TRUE;
- }
- }
-
- for (cur = priv->reqs_pending; cur; cur = cur->next) {
- request = cur->data;
-
- if (cur->next)
- request->error = yelp_error_copy (priv->final_error);
- else
- request->error = error;
-
- if (request->error) {
- func = request->func;
- req_id = request->req_id;
- user_data = request->user_data;
- error = request->error;
- request->error = NULL;
-
- priv->reqs_pending = g_slist_remove (priv->reqs_pending, request);
- }
-
-
- if (func)
- func (document,
- YELP_DOCUMENT_SIGNAL_ERROR,
- req_id,
- error,
- user_data);
- }
- g_mutex_unlock (priv->mutex);
-
- g_object_unref (document);
- return FALSE;
-}
-
-/******************************************************************************/
-
-
-#endif
diff --git a/libyelp/yelp-transform.c b/libyelp/yelp-transform.c
index 1d02338..eecfe6a 100644
--- a/libyelp/yelp-transform.c
+++ b/libyelp/yelp-transform.c
@@ -145,11 +145,11 @@ yelp_transform_class_init (YelpTransformClass *klass)
object_class->set_property = yelp_transform_set_property;
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);
+ 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,
@@ -181,6 +181,8 @@ yelp_transform_dispose (GObject *object)
{
YelpTransformPrivate *priv = GET_PRIV (object);
+ debug_print (DB_FUNCTION, "entering\n");
+
if (priv->queue) {
gchar *chunk_id;
while ((chunk_id = (gchar *) g_async_queue_try_pop (priv->queue)))
@@ -189,6 +191,32 @@ yelp_transform_dispose (GObject *object)
priv->queue = NULL;
}
+ /* We do not free input or aux. They belong to the caller, which
+ must ensure they exist for the lifetime of the transform. We
+ have to set priv->aux_xslt->doc (which is priv->aux) to NULL
+ before xsltFreeTransformContext. Otherwise it will be freed,
+ which we don't want.
+ */
+ if (priv->aux_xslt)
+ priv->aux_xslt->doc = NULL;
+
+ /* We free these in dispose to make absolutely certain that they're
+ freed by the time any weak notify callbacks are called. These
+ may be used elsewhere to free resources like the input document.
+ */
+ if (priv->context) {
+ xsltFreeTransformContext (priv->context);
+ priv->context = NULL;
+ }
+ if (priv->stylesheet) {
+ xsltFreeStylesheet (priv->stylesheet);
+ priv->stylesheet = NULL;
+ }
+ if (priv->output) {
+ xmlFreeDoc (priv->output);
+ priv->output = NULL;
+ }
+
G_OBJECT_CLASS (yelp_transform_parent_class)->dispose (object);
}
@@ -202,20 +230,6 @@ yelp_transform_finalize (GObject *object)
debug_print (DB_FUNCTION, "entering\n");
- if (priv->output)
- xmlFreeDoc (priv->output);
- if (priv->stylesheet)
- xsltFreeStylesheet (priv->stylesheet);
- /* We do not free input or aux. They belong to the caller, which
- must ensure they exist for the lifetime of the transform. We
- have to set priv->aux_xslt->doc (which is priv->aux) to NULL
- before xsltFreeTransformContext. Otherwise it will be freed,
- which we don't want.
- */
- if (priv->aux_xslt)
- priv->aux_xslt->doc = NULL;
- if (priv->context)
- xsltFreeTransformContext (priv->context);
if (priv->error)
g_error_free (priv->error);
diff --git a/stylesheets/db2html.xsl.in b/stylesheets/db2html.xsl.in
index cfd681d..67111ed 100644
--- a/stylesheets/db2html.xsl.in
+++ b/stylesheets/db2html.xsl.in
@@ -14,9 +14,10 @@
<xsl:param name="db.chunk.chunk_top" select="true()"/>
<xsl:param name="db.chunk.extension" select="''"/>
-<xsl:param name="db.chunk.info_basename" select="'__yelp_info'"/>
+<xsl:param name="db.chunk.info_basename" select="'//about'"/>
<xsl:param name="db2html.navbar.top" select="false()"/>
+<xsl:param name="db2html.sidenav" select="false()"/>
<!-- == db.number == -->
<!--
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]