Update Chinese (China) translation
[yelp.git] / libyelp / yelp-help-list.c
blobcbac98bf33fed9f0da8d1aca7f72297f15a3ae70
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2010 Shaun McCance <shaunm@gnome.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Shaun McCance <shaunm@gnome.org>
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <gio/gio.h>
26 #include <gio/gdesktopappinfo.h>
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <libxml/parser.h>
30 #include <libxml/xinclude.h>
31 #include <libxml/xpath.h>
32 #include <libxml/xpathInternals.h>
34 #include "yelp-help-list.h"
35 #include "yelp-settings.h"
37 typedef struct _HelpListEntry HelpListEntry;
39 static void yelp_help_list_dispose (GObject *object);
40 static void yelp_help_list_finalize (GObject *object);
42 static gboolean help_list_request_page (YelpDocument *document,
43 const gchar *page_id,
44 GCancellable *cancellable,
45 YelpDocumentCallback callback,
46 gpointer user_data,
47 GDestroyNotify notify);
48 static void help_list_think (YelpHelpList *list);
49 static void help_list_handle_page (YelpHelpList *list,
50 const gchar *page_id);
51 static void help_list_process_docbook (YelpHelpList *list,
52 HelpListEntry *entry);
53 static void help_list_process_mallard (YelpHelpList *list,
54 HelpListEntry *entry);
56 static const char*const known_vendor_prefixes[] = { "gnome",
57 "fedora",
58 "mozilla",
59 NULL };
61 struct _HelpListEntry
63 gchar *id;
64 gchar *title;
65 gchar *desc;
66 gchar *icon;
68 gchar *filename;
69 YelpUriDocumentType type;
71 static void
72 help_list_entry_free (HelpListEntry *entry)
74 g_free (entry->id);
75 g_free (entry->title);
76 g_free (entry->desc);
77 g_free (entry);
79 static gint
80 help_list_entry_cmp (HelpListEntry *a, HelpListEntry *b)
82 gchar *as, *bs;
83 as = a->title ? a->title : strchr (a->id, ':') + 1;
84 bs = b->title ? b->title : strchr (b->id, ':') + 1;
85 return g_utf8_collate (as, bs);
88 G_DEFINE_TYPE (YelpHelpList, yelp_help_list, YELP_TYPE_DOCUMENT)
89 #define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_HELP_LIST, YelpHelpListPrivate))
91 typedef struct _YelpHelpListPrivate YelpHelpListPrivate;
92 struct _YelpHelpListPrivate {
93 GMutex mutex;
94 GThread *thread;
96 gboolean process_running;
97 gboolean process_ran;
99 GHashTable *entries;
100 GList *all_entries;
101 GSList *pending;
103 xmlXPathCompExprPtr get_docbook_title;
104 xmlXPathCompExprPtr get_mallard_title;
105 xmlXPathCompExprPtr get_mallard_desc;
108 static void
109 yelp_help_list_class_init (YelpHelpListClass *klass)
111 GObjectClass *object_class = G_OBJECT_CLASS (klass);
112 YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass);
114 object_class->dispose = yelp_help_list_dispose;
115 object_class->finalize = yelp_help_list_finalize;
117 document_class->request_page = help_list_request_page;
119 g_type_class_add_private (klass, sizeof (YelpHelpListPrivate));
122 static void
123 yelp_help_list_init (YelpHelpList *list)
125 YelpHelpListPrivate *priv = GET_PRIV (list);
127 g_mutex_init (&priv->mutex);
128 priv->entries = g_hash_table_new_full (g_str_hash, g_str_equal,
129 g_free,
130 (GDestroyNotify) help_list_entry_free);
132 priv->get_docbook_title = xmlXPathCompile (BAD_CAST "normalize-space("
133 "( /*/title | /*/db:title"
134 "| /*/articleinfo/title"
135 "| /*/bookinfo/title"
136 "| /*/db:info/db:title"
137 ")[1])");
138 priv->get_mallard_title = xmlXPathCompile (BAD_CAST "normalize-space((/mal:page/mal:info/mal:title[@type='text'] |"
139 " /mal:page/mal:title)[1])");
140 priv->get_mallard_desc = xmlXPathCompile (BAD_CAST "normalize-space(/mal:page/mal:info/mal:desc[1])");
142 yelp_document_set_page_id ((YelpDocument *) list, NULL, "index");
143 yelp_document_set_page_id ((YelpDocument *) list, "index", "index");
146 static void
147 yelp_help_list_dispose (GObject *object)
149 G_OBJECT_CLASS (yelp_help_list_parent_class)->dispose (object);
152 static void
153 yelp_help_list_finalize (GObject *object)
155 YelpHelpListPrivate *priv = GET_PRIV (object);
157 g_hash_table_destroy (priv->entries);
158 g_mutex_clear (&priv->mutex);
160 if (priv->get_docbook_title)
161 xmlXPathFreeCompExpr (priv->get_docbook_title);
162 if (priv->get_mallard_title)
163 xmlXPathFreeCompExpr (priv->get_mallard_title);
164 if (priv->get_mallard_desc)
165 xmlXPathFreeCompExpr (priv->get_mallard_desc);
167 G_OBJECT_CLASS (yelp_help_list_parent_class)->finalize (object);
170 YelpDocument *
171 yelp_help_list_new (YelpUri *uri)
173 return g_object_new (YELP_TYPE_HELP_LIST, NULL);
176 /******************************************************************************/
178 static gboolean
179 help_list_request_page (YelpDocument *document,
180 const gchar *page_id,
181 GCancellable *cancellable,
182 YelpDocumentCallback callback,
183 gpointer user_data,
184 GDestroyNotify notify)
186 gboolean handled;
187 YelpHelpListPrivate *priv = GET_PRIV (document);
189 if (page_id == NULL)
190 page_id = "index";
192 handled =
193 YELP_DOCUMENT_CLASS (yelp_help_list_parent_class)->request_page (document,
194 page_id,
195 cancellable,
196 callback,
197 user_data,
198 notify);
199 if (handled) {
200 return TRUE;
203 g_mutex_lock (&priv->mutex);
204 if (priv->process_ran) {
205 help_list_handle_page ((YelpHelpList *) document, page_id);
206 return TRUE;
209 if (!priv->process_running) {
210 priv->process_running = TRUE;
211 g_object_ref (document);
212 priv->thread = g_thread_new ("helplist-page",
213 (GThreadFunc)(GCallback) help_list_think,
214 document);
216 priv->pending = g_slist_prepend (priv->pending, g_strdup (page_id));
217 g_mutex_unlock (&priv->mutex);
218 return TRUE;
221 static void
222 help_list_think (YelpHelpList *list)
224 const gchar * const *sdatadirs = g_get_system_data_dirs ();
225 const gchar * const *langs = g_get_language_names ();
226 YelpHelpListPrivate *priv = GET_PRIV (list);
227 /* The strings are still owned by GLib; we just own the array. */
228 gchar **datadirs;
229 gint datadir_i, lang_i;
230 GList *cur;
231 GtkIconTheme *theme;
233 datadirs = g_new0 (gchar *, g_strv_length ((gchar **) sdatadirs) + 2);
234 datadirs[0] = (gchar *) g_get_user_data_dir ();
235 for (datadir_i = 0; sdatadirs[datadir_i]; datadir_i++)
236 datadirs[datadir_i + 1] = (gchar *) sdatadirs[datadir_i];
238 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
239 gchar *helpdirname = g_build_filename (datadirs[datadir_i], "gnome", "help", NULL);
240 GFile *helpdir = g_file_new_for_path (helpdirname);
241 GFileEnumerator *children = g_file_enumerate_children (helpdir,
242 G_FILE_ATTRIBUTE_STANDARD_TYPE","
243 G_FILE_ATTRIBUTE_STANDARD_NAME,
244 G_FILE_QUERY_INFO_NONE,
245 NULL, NULL);
246 GFileInfo *child;
247 if (children == NULL) {
248 g_object_unref (helpdir);
249 g_free (helpdirname);
250 continue;
252 while ((child = g_file_enumerator_next_file (children, NULL, NULL))) {
253 gchar *docid;
254 HelpListEntry *entry = NULL;
256 if (g_file_info_get_file_type (child) != G_FILE_TYPE_DIRECTORY) {
257 g_object_unref (child);
258 continue;
261 docid = g_strconcat ("ghelp:", g_file_info_get_name (child), NULL);
262 if (g_hash_table_lookup (priv->entries, docid)) {
263 g_free (docid);
264 g_object_unref (child);
265 continue;
268 for (lang_i = 0; langs[lang_i]; lang_i++) {
269 gchar *filename, *tmp;
271 filename = g_build_filename (helpdirname,
272 g_file_info_get_name (child),
273 langs[lang_i],
274 "index.page",
275 NULL);
276 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
277 entry = g_new0 (HelpListEntry, 1);
278 entry->id = g_strdup (docid);
279 entry->filename = filename;
280 entry->type = YELP_URI_DOCUMENT_TYPE_MALLARD;
281 break;
283 g_free (filename);
285 tmp = g_strdup_printf ("%s.xml", g_file_info_get_name (child));
286 filename = g_build_filename (helpdirname,
287 g_file_info_get_name (child),
288 langs[lang_i],
289 tmp,
290 NULL);
291 g_free (tmp);
292 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
293 entry = g_new0 (HelpListEntry, 1);
294 entry->id = g_strdup (docid);
295 entry->filename = filename;
296 entry->type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
297 break;
299 g_free (filename);
302 if (entry != NULL) {
303 g_hash_table_insert (priv->entries, docid, entry);
304 priv->all_entries = g_list_prepend (priv->all_entries, entry);
306 else
307 g_free (docid);
308 g_object_unref (child);
310 g_object_unref (children);
311 g_object_unref (helpdir);
312 g_free (helpdirname);
314 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
315 for (lang_i = 0; langs[lang_i]; lang_i++) {
316 gchar *langdirname = g_build_filename (datadirs[datadir_i], "help", langs[lang_i], NULL);
317 GFile *langdir = g_file_new_for_path (langdirname);
318 GFileEnumerator *children = g_file_enumerate_children (langdir,
319 G_FILE_ATTRIBUTE_STANDARD_TYPE","
320 G_FILE_ATTRIBUTE_STANDARD_NAME,
321 G_FILE_QUERY_INFO_NONE,
322 NULL, NULL);
323 GFileInfo *child;
324 if (children == NULL) {
325 g_object_unref (langdir);
326 g_free (langdirname);
327 continue;
329 while ((child = g_file_enumerator_next_file (children, NULL, NULL))) {
330 gchar *docid, *filename;
331 HelpListEntry *entry = NULL;
332 if (g_file_info_get_file_type (child) != G_FILE_TYPE_DIRECTORY) {
333 g_object_unref (child);
334 continue;
337 docid = g_strconcat ("help:", g_file_info_get_name (child), NULL);
338 if (g_hash_table_lookup (priv->entries, docid) != NULL) {
339 g_free (docid);
340 continue;
343 filename = g_build_filename (langdirname,
344 g_file_info_get_name (child),
345 "index.page",
346 NULL);
347 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
348 entry = g_new0 (HelpListEntry, 1);
349 entry->id = docid;
350 entry->filename = filename;
351 entry->type = YELP_URI_DOCUMENT_TYPE_MALLARD;
352 goto found;
354 g_free (filename);
356 filename = g_build_filename (langdirname,
357 g_file_info_get_name (child),
358 "index.docbook",
359 NULL);
360 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
361 entry = g_new0 (HelpListEntry, 1);
362 entry->id = docid;
363 entry->filename = filename;
364 entry->type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
365 goto found;
367 g_free (filename);
369 g_free (docid);
370 found:
371 g_object_unref (child);
372 if (entry != NULL) {
373 g_hash_table_insert (priv->entries, docid, entry);
374 priv->all_entries = g_list_prepend (priv->all_entries, entry);
378 g_object_unref (children);
381 g_free (datadirs);
383 theme = gtk_icon_theme_get_default ();
384 for (cur = priv->all_entries; cur != NULL; cur = cur->next) {
385 GDesktopAppInfo *app;
386 gchar *tmp;
387 HelpListEntry *entry = (HelpListEntry *) cur->data;
388 const gchar *entryid = strchr (entry->id, ':') + 1;
390 if (entry->type == YELP_URI_DOCUMENT_TYPE_MALLARD)
391 help_list_process_mallard (list, entry);
392 else if (entry->type == YELP_URI_DOCUMENT_TYPE_DOCBOOK)
393 help_list_process_docbook (list, entry);
395 tmp = g_strconcat (entryid, ".desktop", NULL);
396 app = g_desktop_app_info_new (tmp);
397 g_free (tmp);
399 if (app == NULL) {
400 char **prefix;
401 for (prefix = (char **) known_vendor_prefixes; *prefix; prefix++) {
402 tmp = g_strconcat (*prefix, "-", entryid, ".desktop", NULL);
403 app = g_desktop_app_info_new (tmp);
404 g_free (tmp);
405 if (app)
406 break;
410 if (app != NULL) {
411 GIcon *icon = g_app_info_get_icon ((GAppInfo *) app);
412 if (icon != NULL) {
413 GtkIconInfo *info = gtk_icon_theme_lookup_by_gicon (theme,
414 icon, 22,
415 GTK_ICON_LOOKUP_NO_SVG);
416 if (info != NULL) {
417 const gchar *iconfile = gtk_icon_info_get_filename (info);
418 if (iconfile)
419 entry->icon = g_filename_to_uri (iconfile, NULL, NULL);
420 g_object_unref (info);
423 g_object_unref (app);
427 g_mutex_lock (&priv->mutex);
428 priv->process_running = FALSE;
429 priv->process_ran = TRUE;
430 while (priv->pending) {
431 gchar *page_id = (gchar *) priv->pending->data;
432 help_list_handle_page (list, page_id);
433 g_free (page_id);
434 priv->pending = g_slist_delete_link (priv->pending, priv->pending);
436 g_mutex_unlock (&priv->mutex);
438 g_object_unref (list);
441 /* This function expects to be called inside a locked mutex */
442 static void
443 help_list_handle_page (YelpHelpList *list,
444 const gchar *page_id)
446 gchar **colors, *tmp;
447 GList *cur;
448 YelpHelpListPrivate *priv = GET_PRIV (list);
449 GtkTextDirection direction = gtk_widget_get_default_direction ();
450 GString *string = g_string_new
451 ("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><style type='text/css'>\n"
452 "html { height: 100%; }\n"
453 "body { margin: 0; padding: 0; max-width: 100%;");
454 colors = yelp_settings_get_colors (yelp_settings_get_default ());
456 tmp = g_markup_printf_escaped (" background-color: %s; color: %s;"
457 " direction: %s; }\n",
458 colors[YELP_SETTINGS_COLOR_BASE],
459 colors[YELP_SETTINGS_COLOR_TEXT],
460 (direction == GTK_TEXT_DIR_RTL) ? "rtl" : "ltr");
461 g_string_append (string, tmp);
462 g_free (tmp);
464 g_string_append (string,
465 "div.body { margin: 0 12px 0 12px; padding: 0;"
466 " max-width: 60em; min-height: 20em; }\n"
467 "div.header { max-width: 100%; width: 100%;"
468 " padding: 0; margin: 0 0 1em 0; }\n"
469 "div.footer { max-width: 60em; }\n"
470 "div.sect { margin-top: 1.72em; }\n"
471 "div.trails { margin: 0; padding: 0.2em 12px 0 12px;");
473 tmp = g_markup_printf_escaped (" background-color: %s;"
474 " border-bottom: solid 1px %s; }\n",
475 colors[YELP_SETTINGS_COLOR_GRAY_BASE],
476 colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
477 g_string_append (string, tmp);
478 g_free (tmp);
480 g_string_append (string,
481 "div.trail { margin: 0 1em 0.2em 1em; padding: 0; text-indent: -1em;");
483 tmp = g_markup_printf_escaped (" color: %s; }\n",
484 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT]);
485 g_string_append (string, tmp);
486 g_free (tmp);
488 g_string_append (string,
489 "a.trail { white-space: nowrap; }\n"
490 "div.hgroup { margin: 0 0 0.5em 0;");
492 tmp = g_markup_printf_escaped (" color: %s;"
493 " border-bottom: solid 1px %s; }\n",
494 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
495 colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
496 g_string_append (string, tmp);
497 g_free (tmp);
499 tmp = g_markup_printf_escaped ("div.title { margin: 0 0 0.2em 0; font-weight: bold; color: %s; }\n"
500 "div.desc { margin: 0 0 0.2em 0; }\n"
501 "div.linkdiv div.inner { padding-%s: 30px; min-height: 24px;"
502 " background-position: top %s; background-repeat: no-repeat;"
503 " -webkit-background-size: 22px 22px; }\n"
504 "div.linkdiv div.title {font-size: 1em; color: inherit; }\n"
505 "div.linkdiv div.desc { color: %s; }\n"
506 "div.linkdiv { margin: 0; padding: 0.5em; }\n"
507 "a:hover div.linkdiv {"
508 " text-decoration: none;"
509 " outline: solid 1px %s;"
510 " background: -webkit-gradient(linear, left top, left 80,"
511 " from(%s), to(%s)); }\n",
512 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
513 ((direction == GTK_TEXT_DIR_RTL) ? "right" : "left"),
514 ((direction == GTK_TEXT_DIR_RTL) ? "right" : "left"),
515 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
516 colors[YELP_SETTINGS_COLOR_BLUE_BASE],
517 colors[YELP_SETTINGS_COLOR_BLUE_BASE],
518 colors[YELP_SETTINGS_COLOR_BASE]);
519 g_string_append (string, tmp);
520 g_free (tmp);
522 g_string_append (string,
523 "h1, h2, h3, h4, h5, h6, h7 { margin: 0; padding: 0; font-weight: bold; }\n"
524 "h1 { font-size: 1.44em; }\n"
525 "h2 { font-size: 1.2em; }"
526 "h3.title, h4.title, h5.title, h6.title, h7.title { font-size: 1.2em; }"
527 "h3, h4, h5, h6, h7 { font-size: 1em; }"
528 "p { line-height: 1.72em; }"
529 "div, pre, p { margin: 1em 0 0 0; padding: 0; }"
530 "div:first-child, pre:first-child, p:first-child { margin-top: 0; }"
531 "div.inner, div.contents, pre.contents { margin-top: 0; }"
532 "p img { vertical-align: middle; }"
533 "a {"
534 " text-decoration: none;");
536 tmp = g_markup_printf_escaped (" color: %s; } a:visited { color: %s; }",
537 colors[YELP_SETTINGS_COLOR_LINK],
538 colors[YELP_SETTINGS_COLOR_LINK_VISITED]);
539 g_string_append (string, tmp);
540 g_free (tmp);
542 g_string_append (string,
543 "a:hover { text-decoration: underline; }\n"
544 "a img { border: none; }\n"
545 "</style>\n");
547 tmp = g_markup_printf_escaped ("<title>%s</title>",
548 _("All Help Documents"));
549 g_string_append (string, tmp);
550 g_free (tmp);
552 g_string_append (string,
553 "</head><body>"
554 "<div class='header'></div>"
555 "<div class='body'><div class='hgroup'>");
556 tmp = g_markup_printf_escaped ("<h1>%s</h1></div>\n",
557 _("All Help Documents"));
558 g_string_append (string, tmp);
559 g_free (tmp);
561 priv->all_entries = g_list_sort (priv->all_entries,
562 (GCompareFunc) help_list_entry_cmp);
563 for (cur = priv->all_entries; cur != NULL; cur = cur->next) {
564 HelpListEntry *entry = (HelpListEntry *) cur->data;
565 gchar *title = entry->title ? entry->title : (strchr (entry->id, ':') + 1);
566 const gchar *desc = entry->desc ? entry->desc : "";
568 tmp = g_markup_printf_escaped ("<a href='%s'><div class='linkdiv'>",
569 entry->id);
570 g_string_append (string, tmp);
571 g_free (tmp);
573 if (entry->icon) {
574 tmp = g_markup_printf_escaped ("<div class='inner' style='background-image: url(%s);'>",
575 entry->icon);
576 g_string_append (string, tmp);
577 g_free (tmp);
579 else
580 g_string_append (string, "<div class='inner'>");
582 tmp = g_markup_printf_escaped ("<div class='title'>%s</div>"
583 "<div class='desc'>%s</div>"
584 "</div></div></a>",
585 title, desc);
586 g_string_append (string, tmp);
587 g_free (tmp);
590 g_string_append (string,
591 "</div>"
592 "<div class='footer'></div>"
593 "</body></html>");
595 yelp_document_give_contents (YELP_DOCUMENT (list), page_id,
596 string->str,
597 "application/xhtml+xml");
598 g_strfreev (colors);
599 g_string_free (string, FALSE);
600 yelp_document_signal (YELP_DOCUMENT (list), page_id,
601 YELP_DOCUMENT_SIGNAL_CONTENTS, NULL);
605 static void
606 help_list_process_docbook (YelpHelpList *list,
607 HelpListEntry *entry)
609 xmlParserCtxtPtr parserCtxt;
610 xmlDocPtr xmldoc;
611 xmlXPathContextPtr xpath;
612 xmlXPathObjectPtr obj = NULL;
613 YelpHelpListPrivate *priv = GET_PRIV (list);
615 parserCtxt = xmlNewParserCtxt ();
616 xmldoc = xmlCtxtReadFile (parserCtxt,
617 (const char *) entry->filename, NULL,
618 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
619 XML_PARSE_NOENT | XML_PARSE_NONET );
620 xmlFreeParserCtxt (parserCtxt);
621 if (xmldoc == NULL)
622 return;
624 xmlXIncludeProcessFlags (xmldoc,
625 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
626 XML_PARSE_NOENT | XML_PARSE_NONET );
628 xpath = xmlXPathNewContext (xmldoc);
629 xmlXPathRegisterNs (xpath, BAD_CAST "db",
630 BAD_CAST "http://docbook.org/ns/docbook");
631 obj = xmlXPathCompiledEval (priv->get_docbook_title, xpath);
632 if (obj) {
633 if (obj->stringval)
634 entry->title = g_strdup ((const gchar *) obj->stringval);
635 xmlXPathFreeObject (obj);
638 if (xmldoc)
639 xmlFreeDoc (xmldoc);
640 if (xpath)
641 xmlXPathFreeContext (xpath);
644 static void
645 help_list_process_mallard (YelpHelpList *list,
646 HelpListEntry *entry)
648 xmlParserCtxtPtr parserCtxt;
649 xmlDocPtr xmldoc;
650 xmlXPathContextPtr xpath;
651 xmlXPathObjectPtr obj = NULL;
652 YelpHelpListPrivate *priv = GET_PRIV (list);
654 parserCtxt = xmlNewParserCtxt ();
655 xmldoc = xmlCtxtReadFile (parserCtxt,
656 (const char *) entry->filename, NULL,
657 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
658 XML_PARSE_NOENT | XML_PARSE_NONET );
659 xmlFreeParserCtxt (parserCtxt);
660 if (xmldoc == NULL)
661 return;
663 xmlXIncludeProcessFlags (xmldoc,
664 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
665 XML_PARSE_NOENT | XML_PARSE_NONET );
667 xpath = xmlXPathNewContext (xmldoc);
668 xmlXPathRegisterNs (xpath, BAD_CAST "mal",
669 BAD_CAST "http://projectmallard.org/1.0/");
671 obj = xmlXPathCompiledEval (priv->get_mallard_title, xpath);
672 if (obj) {
673 if (obj->stringval)
674 entry->title = g_strdup ((const gchar *) obj->stringval);
675 xmlXPathFreeObject (obj);
678 obj = xmlXPathCompiledEval (priv->get_mallard_desc, xpath);
679 if (obj) {
680 if (obj->stringval)
681 entry->desc = g_strdup ((const gchar *) obj->stringval);
682 xmlXPathFreeObject (obj);
685 if (xmldoc)
686 xmlFreeDoc (xmldoc);
687 if (xpath)
688 xmlXPathFreeContext (xpath);