From d8a524caf459b1203e6a7ea134380f5ca4af4f1a Mon Sep 17 00:00:00 2001 From: Shaun McCance Date: Thu, 12 Apr 2007 20:48:06 +0000 Subject: - Made man pages work with YelpDocument * src/Makefile.am: * src/yelp-man.c: * src/yelp-man.h: * src/test-document.c: - Made man pages work with YelpDocument * src/yelp-docbook.c: * src/yelp-document.c: - General clean up svn path=/branches/yelp-document/; revision=2802 --- ChangeLog | 12 ++ src/Makefile.am | 5 +- src/test-document.c | 20 ++- src/yelp-docbook.c | 37 ++-- src/yelp-document.c | 1 + src/yelp-man.c | 481 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/yelp-man.h | 53 ++++++ 7 files changed, 585 insertions(+), 24 deletions(-) create mode 100644 src/yelp-man.c create mode 100644 src/yelp-man.h diff --git a/ChangeLog b/ChangeLog index 58b284ae..13d318c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2007-04-12 Shaun McCance + + * src/Makefile.am: + * src/yelp-man.c: + * src/yelp-man.h: + * src/test-document.c: + - Made man pages work with YelpDocument + + * src/yelp-docbook.c: + * src/yelp-document.c: + - General clean up + 2007-04-12 Shaun McCance * src/yelp-document.c: diff --git a/src/Makefile.am b/src/Makefile.am index f2fe1987..62f810cb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,11 +112,14 @@ test_document_SOURCES = \ yelp-docbook.c yelp-docbook.h \ yelp-document.c yelp-document.h \ yelp-error.c yelp-error.h \ + yelp-io-channel.c yelp-io-channel.h \ + yelp-man.c yelp-man.h \ + yelp-man-parser.c yelp-man-parser.h \ yelp-page.c yelp-page.h \ yelp-transform.c yelp-transform.h \ test-document.c test_document_CFLAGS = $(YELP_CFLAGS) $(AM_CFLAGS) $(YELP_DEFINES) -test_document_LDADD = $(YELP_LIBS) +test_document_LDADD = $(YELP_LIBS) $(Z_LIBS) $(BZ_LIBS) test_document_LDFLAGS = $(AM_LDFLAGS) test_man_parser_SOURCES = \ diff --git a/src/test-document.c b/src/test-document.c index 70cae327..2bd17c65 100644 --- a/src/test-document.c +++ b/src/test-document.c @@ -27,8 +27,13 @@ #include "yelp-error.h" #include "yelp-docbook.h" +static gchar *mode = NULL; static gchar **files = NULL; static const GOptionEntry options[] = { + { "mode", 'm', + 0, G_OPTION_ARG_STRING, + &mode, + "One of man or docbook", "MODE" }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &files, NULL, NULL }, @@ -77,6 +82,7 @@ document_func (YelpDocument *document, case YELP_DOCUMENT_SIGNAL_ERROR: error = (YelpError *) func_data; printf ("ERROR: %s\n", yelp_error_get_title (error)); + printf (" %s\n", yelp_error_get_message (error)); yelp_error_free (error); break; } @@ -99,15 +105,21 @@ main (gint argc, gchar **argv) g_option_context_add_main_entries (context, options, NULL); g_option_context_parse (context, &argc, &argv, NULL); - if (files == NULL || files[0] == NULL || files[1] == NULL) { + if (files == NULL || files[0] == NULL) { g_printerr ("Usage: test-docbook FILE PAGE_IDS...\n"); return 1; } - document = yelp_docbook_new (files[0]); + if (g_str_equal (mode, "man")) + document = yelp_man_new (files[0]); + else + document = yelp_docbook_new (files[0]); - for (i = 1; files[i]; i++) - yelp_document_get_page (document, files[i], (YelpDocumentFunc) document_func, NULL); + if (files[1] == NULL) + yelp_document_get_page (document, "x-yelp-index", (YelpDocumentFunc) document_func, NULL); + else + for (i = 1; files[i]; i++) + yelp_document_get_page (document, files[i], (YelpDocumentFunc) document_func, NULL); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); diff --git a/src/yelp-docbook.c b/src/yelp-docbook.c index c7db98dc..384c6a40 100644 --- a/src/yelp-docbook.c +++ b/src/yelp-docbook.c @@ -41,19 +41,6 @@ #define YELP_DOCBOOK_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_DOCBOOK, YelpDocbookPriv)) -typedef struct _Request Request; -struct _Request { - YelpDocbook *document; - YelpDocumentFunc func; - gpointer user_data; - - gint req_id; - gchar *page_id; - - gint idle_funcs; - gboolean cancel; -}; - typedef enum { DOCBOOK_STATE_BLANK, /* Brand new, run transform as needed */ DOCBOOK_STATE_PARSING, /* Parsing/transforming document, please wait */ @@ -348,6 +335,7 @@ transform_page_func (YelpTransform *transform, debug_print (DB_FUNCTION, "entering\n"); priv = docbook->priv; + g_mutex_lock (priv->mutex); content = yelp_transform_eat_chunk (transform, page_id); @@ -451,26 +439,36 @@ docbook_process (YelpDocbook *docbook) priv->xmlcur = xmlDocGetRootElement (xmldoc); id = xmlGetProp (priv->xmlcur, BAD_CAST "id"); - if (id) + if (id) { yelp_document_set_root_id (document, (gchar *) id); + yelp_document_add_page_id (document, "x-yelp-index", (gchar *) id); + yelp_document_add_prev_id (document, (gchar *) id, "x-yelp-titlepage"); + yelp_document_add_next_id (document, "x-yelp-titlepage", (gchar *) id); + } else { - yelp_document_set_root_id (document, "index"); + yelp_document_set_root_id (document, "x-yelp-index"); + yelp_document_add_page_id (document, "x-yelp-index", "x-yelp-index"); + yelp_document_add_prev_id (document, "x-yelp-index", "x-yelp-titlepage"); + yelp_document_add_next_id (document, "x-yelp-titlepage", "x-yelp-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"); + xmlNewProp (priv->xmlcur, BAD_CAST "id", BAD_CAST "x-yelp-index"); } g_mutex_unlock (priv->mutex); g_mutex_lock (priv->mutex); - if (priv->state == DOCBOOK_STATE_STOP) + 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) + if (priv->state == DOCBOOK_STATE_STOP) { + g_mutex_unlock (priv->mutex); goto done; + } priv->transform = yelp_transform_new (STYLESHEET, (YelpTransformFunc) transform_func, @@ -489,6 +487,7 @@ docbook_process (YelpDocbook *docbook) xmlFreeParserCtxt (parserCtxt); priv->process_running = FALSE; + g_object_unref (docbook); } diff --git a/src/yelp-document.c b/src/yelp-document.c index 07a5f063..bce10d05 100644 --- a/src/yelp-document.c +++ b/src/yelp-document.c @@ -439,6 +439,7 @@ yelp_document_add_page (YelpDocument *document, gchar *page_id, const gchar *con 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); diff --git a/src/yelp-man.c b/src/yelp-man.c new file mode 100644 index 00000000..2b8d1084 --- /dev/null +++ b/src/yelp-man.c @@ -0,0 +1,481 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2007 Shaun McCance + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "yelp-error.h" +#include "yelp-man.h" +#include "yelp-man-parser.h" +#include "yelp-transform.h" +#include "yelp-debug.h" + +#define STYLESHEET DATADIR"/yelp/xslt/man2html.xsl" + +#define YELP_MAN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_MAN, YelpManPriv)) + +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; + +struct _YelpManPriv { + gchar *filename; + ManState state; + + GMutex *mutex; + GThread *thread; + + xmlDocPtr xmldoc; + + gboolean process_running; + gboolean transform_running; + + YelpTransform *transform; +}; + +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 man_class_init (YelpManClass *klass); +static void man_init (YelpMan *man); +static void man_try_dispose (GObject *object); +static void man_dispose (GObject *object); + +/* YelpDocument */ +static void man_request (YelpDocument *document, + gint req_id, + gboolean handled, + gchar *page_id, + YelpDocumentFunc func, + gpointer user_data); + +/* YelpTransform */ +static void transform_func (YelpTransform *transform, + YelpTransformSignal signal, + gpointer func_data, + YelpMan *man); +static void transform_page_func (YelpTransform *transform, + gchar *page_id, + YelpMan *man); +static void transform_final_func (YelpTransform *transform, + YelpMan *man); + +/* Threaded */ +static void man_process (YelpMan *man); + +static YelpDocumentClass *parent_class; + +GType +yelp_man_get_type (void) +{ + static GType type = 0; + if (!type) { + static const GTypeInfo info = { + sizeof (YelpManClass), + NULL, NULL, + (GClassInitFunc) man_class_init, + NULL, NULL, + sizeof (YelpMan), + 0, + (GInstanceInitFunc) man_init, + }; + type = g_type_register_static (YELP_TYPE_DOCUMENT, + "YelpMan", + &info, 0); + } + return type; +} + +static void +man_class_init (YelpManClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->dispose = man_try_dispose; + + document_class->request = man_request; + document_class->cancel = NULL; + + g_type_class_add_private (klass, sizeof (YelpManPriv)); +} + +static void +man_init (YelpMan *man) +{ + YelpManPriv *priv; + + priv = man->priv = YELP_MAN_GET_PRIVATE (man); + + priv->state = MAN_STATE_BLANK; + + priv->mutex = g_mutex_new (); +} + +static void +man_try_dispose (GObject *object) +{ + YelpManPriv *priv; + + g_assert (object != NULL && YELP_IS_MAN (object)); + priv = YELP_MAN (object)->priv; + + g_mutex_lock (priv->mutex); + if (priv->process_running || priv->transform_running) { + priv->state = MAN_STATE_STOP; + g_idle_add ((GSourceFunc) man_try_dispose, object); + g_mutex_unlock (priv->mutex); + } else { + g_mutex_unlock (priv->mutex); + man_dispose (object); + } +} + +static void +man_dispose (GObject *object) +{ + YelpMan *man = YELP_MAN (object); + + g_free (man->priv->filename); + + if (man->priv->xmldoc) + xmlFreeDoc (man->priv->xmldoc); + + g_mutex_free (man->priv->mutex); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +/******************************************************************************/ + +YelpDocument * +yelp_man_new (gchar *filename) +{ + YelpMan *man; + + g_return_val_if_fail (filename != NULL, NULL); + + man = (YelpMan *) g_object_new (YELP_TYPE_MAN, NULL); + man->priv->filename = g_strdup (filename); + + debug_print (DB_FUNCTION, "entering\n"); + debug_print (DB_ARG, " filename = \"%s\"\n", filename); + + yelp_document_add_page_id (YELP_DOCUMENT (man), "x-yelp-index", "index"); + + return (YelpDocument *) man; +} + + +/******************************************************************************/ +/** YelpDocument **************************************************************/ + +static void +man_request (YelpDocument *document, + gint req_id, + gboolean handled, + gchar *page_id, + YelpDocumentFunc func, + gpointer user_data) +{ + YelpMan *man; + YelpManPriv *priv; + YelpError *error; + + debug_print (DB_FUNCTION, "entering\n"); + debug_print (DB_ARG, " req_id = %i\n", req_id); + debug_print (DB_ARG, " page_id = \"%s\"\n", page_id); + + g_assert (document != NULL && YELP_IS_MAN (document)); + + if (handled) + return; + + man = YELP_MAN (document); + priv = man->priv; + + g_mutex_lock (priv->mutex); + + switch (priv->state) { + case MAN_STATE_BLANK: + priv->state = MAN_STATE_PARSING; + priv->process_running = TRUE; + priv->thread = g_thread_create ((GThreadFunc) man_process, man, FALSE, NULL); + break; + case MAN_STATE_PARSING: + break; + case MAN_STATE_PARSED: + case MAN_STATE_STOP: + error = yelp_error_new (_("Page not found"), + _("The page %s was not found in the document %s."), + page_id, priv->filename); + yelp_document_error_request (document, req_id, error); + break; + } + + g_mutex_unlock (priv->mutex); +} + + +/******************************************************************************/ +/** YelpTransform *************************************************************/ + +static void +transform_func (YelpTransform *transform, + YelpTransformSignal signal, + gpointer func_data, + YelpMan *man) +{ + YelpManPriv *priv; + + debug_print (DB_FUNCTION, "entering\n"); + + g_assert (man != NULL && YELP_IS_MAN (man)); + + priv = man->priv; + + g_assert (transform == priv->transform); + + if (priv->state == MAN_STATE_STOP) { + switch (signal) { + case YELP_TRANSFORM_CHUNK: + g_free (func_data); + break; + case YELP_TRANSFORM_ERROR: + yelp_error_free ((YelpError *) func_data); + break; + case YELP_TRANSFORM_FINAL: + break; + } + yelp_transform_release (transform); + priv->transform = NULL; + priv->transform_running = FALSE; + return; + } + + switch (signal) { + case YELP_TRANSFORM_CHUNK: + transform_page_func (transform, (gchar *) func_data, man); + break; + case YELP_TRANSFORM_ERROR: + yelp_document_error_pending (YELP_DOCUMENT (man), (YelpError *) func_data); + yelp_transform_release (transform); + priv->transform = NULL; + priv->transform_running = FALSE; + break; + case YELP_TRANSFORM_FINAL: + transform_final_func (transform, man); + break; + } +} + +static void +transform_page_func (YelpTransform *transform, + gchar *page_id, + YelpMan *man) +{ + YelpManPriv *priv; + gchar *content; + + debug_print (DB_FUNCTION, "entering\n"); + + priv = man->priv; + g_mutex_lock (priv->mutex); + + content = yelp_transform_eat_chunk (transform, page_id); + + yelp_document_add_page (YELP_DOCUMENT (man), page_id, content); + + g_free (page_id); + + g_mutex_unlock (priv->mutex); +} + +static void +transform_final_func (YelpTransform *transform, YelpMan *man) +{ + YelpError *error; + YelpManPriv *priv = man->priv; + + debug_print (DB_FUNCTION, "entering\n"); + + g_mutex_lock (priv->mutex); + + error = yelp_error_new (_("Page not found"), + _("The requested page was not found in the document %s."), + priv->filename); + yelp_document_error_pending (YELP_DOCUMENT (man), error); + + yelp_transform_release (transform); + priv->transform = NULL; + priv->transform_running = FALSE; + + if (priv->xmldoc) + xmlFreeDoc (priv->xmldoc); + priv->xmldoc = NULL; + + g_mutex_unlock (priv->mutex); +} + + +/******************************************************************************/ +/** Threaded ******************************************************************/ + +static void +man_process (YelpMan *man) +{ + YelpManPriv *priv; + const gchar *language; + const gchar *encoding; + YelpManParser *parser; + YelpError *error = NULL; + YelpDocument *document; + gint i; + + debug_print (DB_FUNCTION, "entering\n"); + + g_assert (man != NULL && YELP_IS_MAN (man)); + g_object_ref (man); + priv = man->priv; + document = YELP_DOCUMENT (man); + + if (!g_file_test (priv->filename, G_FILE_TEST_IS_REGULAR)) { + error = yelp_error_new (_("File not found"), + _("The file ā€˜%sā€™ does not exist."), + priv->filename); + yelp_document_error_pending (document, 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) { + 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, priv->filename, encoding); + yelp_man_parser_free (parser); + + if (priv->xmldoc == NULL) { + error = yelp_error_new (_("Could not parse file"), + _("The file ā€˜%sā€™ could not be parsed because it is" + " not a well-formed man page."), + priv->filename); + yelp_document_error_pending (document, 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, + (YelpTransformFunc) transform_func, + man); + priv->transform_running = TRUE; + /* FIXME: we probably need to set our own params */ + yelp_transform_start (priv->transform, + priv->xmldoc, + NULL); + g_mutex_unlock (priv->mutex); + + done: + priv->process_running = FALSE; + g_object_unref (man); +} diff --git a/src/yelp-man.h b/src/yelp-man.h new file mode 100644 index 00000000..844c44ab --- /dev/null +++ b/src/yelp-man.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2007 Shaun McCance + * + * 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 + */ + +#ifndef __YELP_MAN_H__ +#define __YELP_MAN_H__ + +#include + +#include "yelp-document.h" + +#define YELP_TYPE_MAN (yelp_man_get_type ()) +#define YELP_MAN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), YELP_TYPE_MAN, YelpMan)) +#define YELP_MAN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), YELP_TYPE_MAN, YelpManClass)) +#define YELP_IS_MAN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), YELP_TYPE_MAN)) +#define YELP_IS_MAN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), YELP_TYPE_MAN)) +#define YELP_MAN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_MAN, YelpManClass)) + +typedef struct _YelpMan YelpMan; +typedef struct _YelpManClass YelpManClass; +typedef struct _YelpManPriv YelpManPriv; + +struct _YelpMan { + YelpDocument parent; + YelpManPriv *priv; +}; + +struct _YelpManClass { + YelpDocumentClass parent_class; +}; + +GType yelp_man_get_type (void); +YelpDocument * yelp_man_new (gchar *uri); + +#endif /* __YELP_MAN_H__ */ -- cgit v1.2.1