Updated French translation
[yelp.git] / libyelp / yelp-help-list.c
blob4a5c8705f4102e9f4c6504ee0cc697a24a43b405
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>
33 #include "yelp-help-list.h"
34 #include "yelp-settings.h"
36 typedef struct _HelpListEntry HelpListEntry;
38 static void yelp_help_list_class_init (YelpHelpListClass *klass);
39 static void yelp_help_list_init (YelpHelpList *list);
40 static void yelp_help_list_dispose (GObject *object);
41 static void yelp_help_list_finalize (GObject *object);
43 static gboolean help_list_request_page (YelpDocument *document,
44 const gchar *page_id,
45 GCancellable *cancellable,
46 YelpDocumentCallback callback,
47 gpointer user_data);
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 ("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 ("normalize-space((/mal:page/mal:info/mal:title[@type='text'] |"
139 " /mal:page/mal:title)[1])");
140 priv->get_mallard_desc = xmlXPathCompile ("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)
185 gboolean handled;
186 YelpHelpListPrivate *priv = GET_PRIV (document);
188 if (page_id == NULL)
189 page_id = "index";
191 handled =
192 YELP_DOCUMENT_CLASS (yelp_help_list_parent_class)->request_page (document,
193 page_id,
194 cancellable,
195 callback,
196 user_data);
197 if (handled) {
198 return TRUE;
201 g_mutex_lock (&priv->mutex);
202 if (priv->process_ran) {
203 help_list_handle_page ((YelpHelpList *) document, page_id);
204 return TRUE;
207 if (!priv->process_running) {
208 priv->process_running = TRUE;
209 g_object_ref (document);
210 priv->thread = g_thread_new ("helplist-page",
211 (GThreadFunc) help_list_think,
212 document);
214 priv->pending = g_slist_prepend (priv->pending, g_strdup (page_id));
215 g_mutex_unlock (&priv->mutex);
216 return TRUE;
219 static void
220 help_list_think (YelpHelpList *list)
222 const gchar * const *sdatadirs = g_get_system_data_dirs ();
223 const gchar * const *langs = g_get_language_names ();
224 YelpHelpListPrivate *priv = GET_PRIV (list);
225 /* The strings are still owned by GLib; we just own the array. */
226 gchar **datadirs;
227 gint datadir_i, subdir_i, lang_i;
228 GList *cur;
229 GtkIconTheme *theme;
231 datadirs = g_new0 (gchar *, g_strv_length ((gchar **) sdatadirs) + 2);
232 datadirs[0] = (gchar *) g_get_user_data_dir ();
233 for (datadir_i = 0; sdatadirs[datadir_i]; datadir_i++)
234 datadirs[datadir_i + 1] = (gchar *) sdatadirs[datadir_i];
236 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
237 gchar *helpdirname = g_build_filename (datadirs[datadir_i], "gnome", "help", NULL);
238 GFile *helpdir = g_file_new_for_path (helpdirname);
239 GFileEnumerator *children = g_file_enumerate_children (helpdir,
240 G_FILE_ATTRIBUTE_STANDARD_TYPE","
241 G_FILE_ATTRIBUTE_STANDARD_NAME,
242 G_FILE_QUERY_INFO_NONE,
243 NULL, NULL);
244 GFileInfo *child;
245 if (children == NULL) {
246 g_object_unref (helpdir);
247 g_free (helpdirname);
248 continue;
250 while (child = g_file_enumerator_next_file (children, NULL, NULL)) {
251 gchar *docid;
252 HelpListEntry *entry = NULL;
254 if (g_file_info_get_file_type (child) != G_FILE_TYPE_DIRECTORY) {
255 g_object_unref (child);
256 continue;
259 docid = g_strconcat ("ghelp:", g_file_info_get_name (child), NULL);
260 if (g_hash_table_lookup (priv->entries, docid)) {
261 g_free (docid);
262 g_object_unref (child);
263 continue;
266 for (lang_i = 0; langs[lang_i]; lang_i++) {
267 gchar *filename, *tmp;
269 filename = g_build_filename (helpdirname,
270 g_file_info_get_name (child),
271 langs[lang_i],
272 "index.page",
273 NULL);
274 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
275 entry = g_new0 (HelpListEntry, 1);
276 entry->id = g_strdup (docid);
277 entry->filename = filename;
278 entry->type = YELP_URI_DOCUMENT_TYPE_MALLARD;
279 break;
281 g_free (filename);
283 tmp = g_strdup_printf ("%s.xml", g_file_info_get_name (child));
284 filename = g_build_filename (helpdirname,
285 g_file_info_get_name (child),
286 langs[lang_i],
287 tmp,
288 NULL);
289 g_free (tmp);
290 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
291 entry = g_new0 (HelpListEntry, 1);
292 entry->id = g_strdup (docid);
293 entry->filename = filename;
294 entry->type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
295 break;
297 g_free (filename);
300 if (entry != NULL) {
301 g_hash_table_insert (priv->entries, docid, entry);
302 priv->all_entries = g_list_prepend (priv->all_entries, entry);
304 else
305 g_free (docid);
306 g_object_unref (child);
308 g_object_unref (children);
309 g_object_unref (helpdir);
310 g_free (helpdirname);
312 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
313 for (lang_i = 0; langs[lang_i]; lang_i++) {
314 gchar *langdirname = g_build_filename (datadirs[datadir_i], "help", langs[lang_i], NULL);
315 GFile *langdir = g_file_new_for_path (langdirname);
316 GFileEnumerator *children = g_file_enumerate_children (langdir,
317 G_FILE_ATTRIBUTE_STANDARD_TYPE","
318 G_FILE_ATTRIBUTE_STANDARD_NAME,
319 G_FILE_QUERY_INFO_NONE,
320 NULL, NULL);
321 GFileInfo *child;
322 if (children == NULL) {
323 g_object_unref (langdir);
324 g_free (langdirname);
325 continue;
327 while (child = g_file_enumerator_next_file (children, NULL, NULL)) {
328 gchar *docid, *filename;
329 HelpListEntry *entry = NULL;
330 if (g_file_info_get_file_type (child) != G_FILE_TYPE_DIRECTORY) {
331 g_object_unref (child);
332 continue;
335 docid = g_strconcat ("help:", g_file_info_get_name (child), NULL);
336 if (g_hash_table_lookup (priv->entries, docid) != NULL) {
337 g_free (docid);
338 continue;
341 filename = g_build_filename (langdirname,
342 g_file_info_get_name (child),
343 "index.page",
344 NULL);
345 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
346 entry = g_new0 (HelpListEntry, 1);
347 entry->id = docid;
348 entry->filename = filename;
349 entry->type = YELP_URI_DOCUMENT_TYPE_MALLARD;
350 goto found;
352 g_free (filename);
354 filename = g_build_filename (langdirname,
355 g_file_info_get_name (child),
356 "index.docbook",
357 NULL);
358 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
359 entry = g_new0 (HelpListEntry, 1);
360 entry->id = docid;
361 entry->filename = filename;
362 entry->type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
363 goto found;
365 g_free (filename);
367 g_free (docid);
368 found:
369 g_object_unref (child);
370 if (entry != NULL) {
371 g_hash_table_insert (priv->entries, docid, entry);
372 priv->all_entries = g_list_prepend (priv->all_entries, entry);
376 g_object_unref (children);
379 g_free (datadirs);
381 theme = gtk_icon_theme_get_default ();
382 for (cur = priv->all_entries; cur != NULL; cur = cur->next) {
383 GDesktopAppInfo *app;
384 gchar *tmp;
385 HelpListEntry *entry = (HelpListEntry *) cur->data;
386 const gchar *entryid = strchr (entry->id, ':') + 1;
388 if (entry->type == YELP_URI_DOCUMENT_TYPE_MALLARD)
389 help_list_process_mallard (list, entry);
390 else if (entry->type == YELP_URI_DOCUMENT_TYPE_DOCBOOK)
391 help_list_process_docbook (list, entry);
393 tmp = g_strconcat (entryid, ".desktop", NULL);
394 app = g_desktop_app_info_new (tmp);
395 g_free (tmp);
397 if (app == NULL) {
398 char **prefix;
399 for (prefix = (char **) known_vendor_prefixes; *prefix; prefix++) {
400 tmp = g_strconcat (*prefix, "-", entryid, ".desktop", NULL);
401 app = g_desktop_app_info_new (tmp);
402 g_free (tmp);
403 if (app)
404 break;
408 if (app != NULL) {
409 GIcon *icon = g_app_info_get_icon ((GAppInfo *) app);
410 if (icon != NULL) {
411 GtkIconInfo *info = gtk_icon_theme_lookup_by_gicon (theme,
412 icon, 22,
413 GTK_ICON_LOOKUP_NO_SVG);
414 if (info != NULL) {
415 const gchar *iconfile = gtk_icon_info_get_filename (info);
416 if (iconfile)
417 entry->icon = g_filename_to_uri (iconfile, NULL, NULL);
418 g_object_unref (info);
421 g_object_unref (app);
425 g_mutex_lock (&priv->mutex);
426 priv->process_running = FALSE;
427 priv->process_ran = TRUE;
428 while (priv->pending) {
429 gchar *page_id = (gchar *) priv->pending->data;
430 help_list_handle_page (list, page_id);
431 g_free (page_id);
432 priv->pending = g_slist_delete_link (priv->pending, priv->pending);
434 g_mutex_unlock (&priv->mutex);
436 g_object_unref (list);
439 /* This function expects to be called inside a locked mutex */
440 static void
441 help_list_handle_page (YelpHelpList *list,
442 const gchar *page_id)
444 gchar **colors, *tmp;
445 GList *cur;
446 YelpHelpListPrivate *priv = GET_PRIV (list);
447 GtkTextDirection direction = gtk_widget_get_default_direction ();
448 GString *string = g_string_new
449 ("<html><head><style type='text/css'>\n"
450 "html { height: 100%; }\n"
451 "body { margin: 0; padding: 0; max-width: 100%;");
452 colors = yelp_settings_get_colors (yelp_settings_get_default ());
454 tmp = g_markup_printf_escaped (" background-color: %s; color: %s;"
455 " direction: %s; }\n",
456 colors[YELP_SETTINGS_COLOR_BASE],
457 colors[YELP_SETTINGS_COLOR_TEXT],
458 (direction == GTK_TEXT_DIR_RTL) ? "rtl" : "ltr");
459 g_string_append (string, tmp);
460 g_free (tmp);
462 g_string_append (string,
463 "div.body { margin: 0 12px 0 12px; padding: 0;"
464 " max-width: 60em; min-height: 20em; }\n"
465 "div.header { max-width: 100%; width: 100%;"
466 " padding: 0; margin: 0 0 1em 0; }\n"
467 "div.footer { max-width: 60em; }\n"
468 "div.sect { margin-top: 1.72em; }\n"
469 "div.trails { margin: 0; padding: 0.2em 12px 0 12px;");
471 tmp = g_markup_printf_escaped (" background-color: %s;"
472 " border-bottom: solid 1px %s; }\n",
473 colors[YELP_SETTINGS_COLOR_GRAY_BASE],
474 colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
475 g_string_append (string, tmp);
476 g_free (tmp);
478 g_string_append (string,
479 "div.trail { margin: 0 1em 0.2em 1em; padding: 0; text-indent: -1em;");
481 tmp = g_markup_printf_escaped (" color: %s; }\n",
482 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT]);
483 g_string_append (string, tmp);
484 g_free (tmp);
486 g_string_append (string,
487 "a.trail { white-space: nowrap; }\n"
488 "div.hgroup { margin: 0 0 0.5em 0;");
490 tmp = g_markup_printf_escaped (" color: %s;"
491 " border-bottom: solid 1px %s; }\n",
492 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
493 colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
494 g_string_append (string, tmp);
495 g_free (tmp);
497 tmp = g_markup_printf_escaped ("div.title { margin: 0 0 0.2em 0; font-weight: bold; color: %s; }\n"
498 "div.desc { margin: 0 0 0.2em 0; }\n"
499 "div.linkdiv div.inner { padding-%s: 30px; min-height: 24px;"
500 " background-position: top %s; background-repeat: no-repeat;"
501 " -webkit-background-size: 22px 22px; }\n"
502 "div.linkdiv div.title {font-size: 1em; color: inherit; }\n"
503 "div.linkdiv div.desc { color: %s; }\n"
504 "div.linkdiv { margin: 0; padding: 0.5em; }\n"
505 "a:hover div.linkdiv {"
506 " text-decoration: none;"
507 " outline: solid 1px %s;"
508 " background: -webkit-gradient(linear, left top, left 80,"
509 " from(%s), to(%s)); }\n",
510 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
511 ((direction == GTK_TEXT_DIR_RTL) ? "right" : "left"),
512 ((direction == GTK_TEXT_DIR_RTL) ? "right" : "left"),
513 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
514 colors[YELP_SETTINGS_COLOR_BLUE_BASE],
515 colors[YELP_SETTINGS_COLOR_BLUE_BASE],
516 colors[YELP_SETTINGS_COLOR_BASE]);
517 g_string_append (string, tmp);
518 g_free (tmp);
520 g_string_append (string,
521 "h1, h2, h3, h4, h5, h6, h7 { margin: 0; padding: 0; font-weight: bold; }\n"
522 "h1 { font-size: 1.44em; }\n"
523 "h2 { font-size: 1.2em; }"
524 "h3.title, h4.title, h5.title, h6.title, h7.title { font-size: 1.2em; }"
525 "h3, h4, h5, h6, h7 { font-size: 1em; }"
526 "p { line-height: 1.72em; }"
527 "div, pre, p { margin: 1em 0 0 0; padding: 0; }"
528 "div:first-child, pre:first-child, p:first-child { margin-top: 0; }"
529 "div.inner, div.contents, pre.contents { margin-top: 0; }"
530 "p img { vertical-align: middle; }"
531 "a {"
532 " text-decoration: none;");
534 tmp = g_markup_printf_escaped (" color: %s; } a:visited { color: %s; }",
535 colors[YELP_SETTINGS_COLOR_LINK],
536 colors[YELP_SETTINGS_COLOR_LINK_VISITED]);
537 g_string_append (string, tmp);
538 g_free (tmp);
540 g_string_append (string,
541 "a:hover { text-decoration: underline; }\n"
542 "a img { border: none; }\n"
543 "</style>\n");
545 tmp = g_markup_printf_escaped ("<title>%s</title>",
546 _("All Help Documents"));
547 g_string_append (string, tmp);
548 g_free (tmp);
550 g_string_append (string,
551 "</head><body>"
552 "<div class='header'></div>"
553 "<div class='body'><div class='hgroup'>");
554 tmp = g_markup_printf_escaped ("<h1>%s</h1></div>\n",
555 _("All Help Documents"));
556 g_string_append (string, tmp);
557 g_free (tmp);
559 priv->all_entries = g_list_sort (priv->all_entries,
560 (GCompareFunc) help_list_entry_cmp);
561 for (cur = priv->all_entries; cur != NULL; cur = cur->next) {
562 HelpListEntry *entry = (HelpListEntry *) cur->data;
563 gchar *title = entry->title ? entry->title : (strchr (entry->id, ':') + 1);
564 gchar *desc = entry->desc ? entry->desc : "";
566 tmp = g_markup_printf_escaped ("<a href='%s'><div class='linkdiv'>",
567 entry->id);
568 g_string_append (string, tmp);
569 g_free (tmp);
571 if (entry->icon) {
572 tmp = g_markup_printf_escaped ("<div class='inner' style='background-image: url(%s);'>",
573 entry->icon);
574 g_string_append (string, tmp);
575 g_free (tmp);
577 else
578 g_string_append (string, "<div class='inner'>");
580 tmp = g_markup_printf_escaped ("<div class='title'>%s</div>"
581 "<div class='desc'>%s</div>"
582 "</div></div></a>",
583 title, desc);
584 g_string_append (string, tmp);
585 g_free (tmp);
588 g_string_append (string,
589 "</div>"
590 "<div class='footer'></div>"
591 "</body></html>");
593 yelp_document_give_contents (YELP_DOCUMENT (list), page_id,
594 string->str,
595 "text/html");
596 g_strfreev (colors);
597 g_string_free (string, FALSE);
598 yelp_document_signal (YELP_DOCUMENT (list), page_id,
599 YELP_DOCUMENT_SIGNAL_CONTENTS, NULL);
603 static void
604 help_list_process_docbook (YelpHelpList *list,
605 HelpListEntry *entry)
607 xmlParserCtxtPtr parserCtxt;
608 xmlDocPtr xmldoc;
609 xmlXPathContextPtr xpath;
610 xmlXPathObjectPtr obj = NULL;
611 YelpHelpListPrivate *priv = GET_PRIV (list);
613 parserCtxt = xmlNewParserCtxt ();
614 xmldoc = xmlCtxtReadFile (parserCtxt,
615 (const char *) entry->filename, NULL,
616 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
617 XML_PARSE_NOENT | XML_PARSE_NONET );
618 xmlFreeParserCtxt (parserCtxt);
619 if (xmldoc == NULL)
620 return;
622 xmlXIncludeProcessFlags (xmldoc,
623 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
624 XML_PARSE_NOENT | XML_PARSE_NONET );
626 xpath = xmlXPathNewContext (xmldoc);
627 xmlXPathRegisterNs (xpath, BAD_CAST "db",
628 BAD_CAST "http://docbook.org/ns/docbook");
629 obj = xmlXPathCompiledEval (priv->get_docbook_title, xpath);
630 if (obj) {
631 if (obj->stringval)
632 entry->title = g_strdup (obj->stringval);
633 xmlXPathFreeObject (obj);
636 if (xmldoc)
637 xmlFreeDoc (xmldoc);
638 if (xpath)
639 xmlXPathFreeContext (xpath);
642 static void
643 help_list_process_mallard (YelpHelpList *list,
644 HelpListEntry *entry)
646 xmlParserCtxtPtr parserCtxt;
647 xmlDocPtr xmldoc;
648 xmlXPathContextPtr xpath;
649 xmlXPathObjectPtr obj = NULL;
650 YelpHelpListPrivate *priv = GET_PRIV (list);
652 parserCtxt = xmlNewParserCtxt ();
653 xmldoc = xmlCtxtReadFile (parserCtxt,
654 (const char *) entry->filename, NULL,
655 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
656 XML_PARSE_NOENT | XML_PARSE_NONET );
657 xmlFreeParserCtxt (parserCtxt);
658 if (xmldoc == NULL)
659 return;
661 xmlXIncludeProcessFlags (xmldoc,
662 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
663 XML_PARSE_NOENT | XML_PARSE_NONET );
665 xpath = xmlXPathNewContext (xmldoc);
666 xmlXPathRegisterNs (xpath, BAD_CAST "mal",
667 BAD_CAST "http://projectmallard.org/1.0/");
669 obj = xmlXPathCompiledEval (priv->get_mallard_title, xpath);
670 if (obj) {
671 if (obj->stringval)
672 entry->title = g_strdup (obj->stringval);
673 xmlXPathFreeObject (obj);
676 obj = xmlXPathCompiledEval (priv->get_mallard_desc, xpath);
677 if (obj) {
678 if (obj->stringval)
679 entry->desc = g_strdup (obj->stringval);
680 xmlXPathFreeObject (obj);
683 if (xmldoc)
684 xmlFreeDoc (xmldoc);
685 if (xpath)
686 xmlXPathFreeContext (xpath);