1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2010-2020 Shaun McCance <shaunm@gnome.org>
4 *
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.
9 *
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.
14 *
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/>.
17 *
18 * Author: Shaun McCance <shaunm@gnome.org>
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
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>
33
34 #include "yelp-help-list.h"
35 #include "yelp-settings.h"
36
37 typedef struct _HelpListEntry HelpListEntry;
38
39 static void yelp_help_list_dispose (GObject *object);
40 static void yelp_help_list_finalize (GObject *object);
41
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);
55
56 static const char*const known_vendor_prefixes[] = { "gnome",
57 "fedora",
58 "mozilla",
59 NULL };
60
61 struct _HelpListEntry
62 {
63 gchar *id;
64 gchar *title;
65 gchar *desc;
66 gchar *icon;
67
68 gchar *filename;
69 YelpUriDocumentType type;
70 };
71 static void
help_list_entry_free(HelpListEntry * entry)72 help_list_entry_free (HelpListEntry *entry)
73 {
74 g_free (entry->id);
75 g_free (entry->title);
76 g_free (entry->desc);
77 g_free (entry);
78 }
79 static gint
help_list_entry_cmp(HelpListEntry * a,HelpListEntry * b)80 help_list_entry_cmp (HelpListEntry *a, HelpListEntry *b)
81 {
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);
86 }
87
88 typedef struct _YelpHelpListPrivate YelpHelpListPrivate;
89 struct _YelpHelpListPrivate {
90 GMutex mutex;
91 GThread *thread;
92
93 gboolean process_running;
94 gboolean process_ran;
95
96 GHashTable *entries;
97 GList *all_entries;
98 GSList *pending;
99
100 xmlXPathCompExprPtr get_docbook_title;
101 xmlXPathCompExprPtr get_mallard_title;
102 xmlXPathCompExprPtr get_mallard_desc;
103 };
104
G_DEFINE_TYPE_WITH_PRIVATE(YelpHelpList,yelp_help_list,YELP_TYPE_DOCUMENT)105 G_DEFINE_TYPE_WITH_PRIVATE (YelpHelpList, yelp_help_list, YELP_TYPE_DOCUMENT)
106
107 static void
108 yelp_help_list_class_init (YelpHelpListClass *klass)
109 {
110 GObjectClass *object_class = G_OBJECT_CLASS (klass);
111 YelpDocumentClass *document_class = YELP_DOCUMENT_CLASS (klass);
112
113 object_class->dispose = yelp_help_list_dispose;
114 object_class->finalize = yelp_help_list_finalize;
115
116 document_class->request_page = help_list_request_page;
117 }
118
119 static void
yelp_help_list_init(YelpHelpList * list)120 yelp_help_list_init (YelpHelpList *list)
121 {
122 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (list);
123
124 g_mutex_init (&priv->mutex);
125 priv->entries = g_hash_table_new_full (g_str_hash, g_str_equal,
126 g_free,
127 (GDestroyNotify) help_list_entry_free);
128
129 priv->get_docbook_title = xmlXPathCompile (BAD_CAST "normalize-space("
130 "( /*/title | /*/db:title"
131 "| /*/articleinfo/title"
132 "| /*/bookinfo/title"
133 "| /*/db:info/db:title"
134 ")[1])");
135 priv->get_mallard_title = xmlXPathCompile (BAD_CAST "normalize-space((/mal:page/mal:info/mal:title[@type='text'] |"
136 " /mal:page/mal:title)[1])");
137 priv->get_mallard_desc = xmlXPathCompile (BAD_CAST "normalize-space(/mal:page/mal:info/mal:desc[1])");
138
139 yelp_document_set_page_id ((YelpDocument *) list, NULL, "index");
140 yelp_document_set_page_id ((YelpDocument *) list, "index", "index");
141 }
142
143 static void
yelp_help_list_dispose(GObject * object)144 yelp_help_list_dispose (GObject *object)
145 {
146 G_OBJECT_CLASS (yelp_help_list_parent_class)->dispose (object);
147 }
148
149 static void
yelp_help_list_finalize(GObject * object)150 yelp_help_list_finalize (GObject *object)
151 {
152 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (YELP_HELP_LIST (object));
153
154 g_hash_table_destroy (priv->entries);
155 g_mutex_clear (&priv->mutex);
156
157 if (priv->get_docbook_title)
158 xmlXPathFreeCompExpr (priv->get_docbook_title);
159 if (priv->get_mallard_title)
160 xmlXPathFreeCompExpr (priv->get_mallard_title);
161 if (priv->get_mallard_desc)
162 xmlXPathFreeCompExpr (priv->get_mallard_desc);
163
164 G_OBJECT_CLASS (yelp_help_list_parent_class)->finalize (object);
165 }
166
167 YelpDocument *
yelp_help_list_new(YelpUri * uri)168 yelp_help_list_new (YelpUri *uri)
169 {
170 return g_object_new (YELP_TYPE_HELP_LIST, NULL);
171 }
172
173 /******************************************************************************/
174
175 static gboolean
help_list_request_page(YelpDocument * document,const gchar * page_id,GCancellable * cancellable,YelpDocumentCallback callback,gpointer user_data,GDestroyNotify notify)176 help_list_request_page (YelpDocument *document,
177 const gchar *page_id,
178 GCancellable *cancellable,
179 YelpDocumentCallback callback,
180 gpointer user_data,
181 GDestroyNotify notify)
182 {
183 gboolean handled;
184 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (YELP_HELP_LIST (document));
185
186 if (page_id == NULL)
187 page_id = "index";
188
189 handled =
190 YELP_DOCUMENT_CLASS (yelp_help_list_parent_class)->request_page (document,
191 page_id,
192 cancellable,
193 callback,
194 user_data,
195 notify);
196 if (handled) {
197 return TRUE;
198 }
199
200 g_mutex_lock (&priv->mutex);
201 if (priv->process_ran) {
202 help_list_handle_page ((YelpHelpList *) document, page_id);
203 return TRUE;
204 }
205
206 if (!priv->process_running) {
207 priv->process_running = TRUE;
208 g_object_ref (document);
209 priv->thread = g_thread_new ("helplist-page",
210 (GThreadFunc)(GCallback) help_list_think,
211 document);
212 }
213 priv->pending = g_slist_prepend (priv->pending, g_strdup (page_id));
214 g_mutex_unlock (&priv->mutex);
215 return TRUE;
216 }
217
218 static void
help_list_think(YelpHelpList * list)219 help_list_think (YelpHelpList *list)
220 {
221 const gchar * const *sdatadirs = g_get_system_data_dirs ();
222 const gchar * const *langs = g_get_language_names ();
223 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (list);
224 /* The strings are still owned by GLib; we just own the array. */
225 gchar **datadirs;
226 gint datadir_i, lang_i;
227 GList *cur;
228 GtkIconTheme *theme;
229
230 datadirs = g_new0 (gchar *, g_strv_length ((gchar **) sdatadirs) + 2);
231 datadirs[0] = (gchar *) g_get_user_data_dir ();
232 for (datadir_i = 0; sdatadirs[datadir_i]; datadir_i++)
233 datadirs[datadir_i + 1] = (gchar *) sdatadirs[datadir_i];
234
235 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
236 gchar *helpdirname = g_build_filename (datadirs[datadir_i], "gnome", "help", NULL);
237 GFile *helpdir = g_file_new_for_path (helpdirname);
238 GFileEnumerator *children = g_file_enumerate_children (helpdir,
239 G_FILE_ATTRIBUTE_STANDARD_TYPE","
240 G_FILE_ATTRIBUTE_STANDARD_NAME,
241 G_FILE_QUERY_INFO_NONE,
242 NULL, NULL);
243 GFileInfo *child;
244 if (children == NULL) {
245 g_object_unref (helpdir);
246 g_free (helpdirname);
247 continue;
248 }
249 while ((child = g_file_enumerator_next_file (children, NULL, NULL))) {
250 gchar *docid;
251 HelpListEntry *entry = NULL;
252
253 if (g_file_info_get_file_type (child) != G_FILE_TYPE_DIRECTORY) {
254 g_object_unref (child);
255 continue;
256 }
257
258 docid = g_strconcat ("ghelp:", g_file_info_get_name (child), NULL);
259 if (g_hash_table_lookup (priv->entries, docid)) {
260 g_free (docid);
261 g_object_unref (child);
262 continue;
263 }
264
265 for (lang_i = 0; langs[lang_i]; lang_i++) {
266 gchar *filename, *tmp;
267
268 filename = g_build_filename (helpdirname,
269 g_file_info_get_name (child),
270 langs[lang_i],
271 "index.page",
272 NULL);
273 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
274 entry = g_new0 (HelpListEntry, 1);
275 entry->id = g_strdup (docid);
276 entry->filename = filename;
277 entry->type = YELP_URI_DOCUMENT_TYPE_MALLARD;
278 break;
279 }
280 g_free (filename);
281
282 tmp = g_strdup_printf ("%s.xml", g_file_info_get_name (child));
283 filename = g_build_filename (helpdirname,
284 g_file_info_get_name (child),
285 langs[lang_i],
286 tmp,
287 NULL);
288 g_free (tmp);
289 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
290 entry = g_new0 (HelpListEntry, 1);
291 entry->id = g_strdup (docid);
292 entry->filename = filename;
293 entry->type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
294 break;
295 }
296 g_free (filename);
297 }
298
299 if (entry != NULL) {
300 g_hash_table_insert (priv->entries, docid, entry);
301 priv->all_entries = g_list_prepend (priv->all_entries, entry);
302 }
303 else
304 g_free (docid);
305 g_object_unref (child);
306 }
307 g_object_unref (children);
308 g_object_unref (helpdir);
309 g_free (helpdirname);
310 }
311 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
312 for (lang_i = 0; langs[lang_i]; lang_i++) {
313 gchar *langdirname = g_build_filename (datadirs[datadir_i], "help", langs[lang_i], NULL);
314 GFile *langdir = g_file_new_for_path (langdirname);
315 GFileEnumerator *children = g_file_enumerate_children (langdir,
316 G_FILE_ATTRIBUTE_STANDARD_TYPE","
317 G_FILE_ATTRIBUTE_STANDARD_NAME,
318 G_FILE_QUERY_INFO_NONE,
319 NULL, NULL);
320 GFileInfo *child;
321 if (children == NULL) {
322 g_object_unref (langdir);
323 g_free (langdirname);
324 continue;
325 }
326 while ((child = g_file_enumerator_next_file (children, NULL, NULL))) {
327 gchar *docid, *filename;
328 HelpListEntry *entry = NULL;
329 if (g_file_info_get_file_type (child) != G_FILE_TYPE_DIRECTORY) {
330 g_object_unref (child);
331 continue;
332 }
333
334 docid = g_strconcat ("help:", g_file_info_get_name (child), NULL);
335 if (g_hash_table_lookup (priv->entries, docid) != NULL) {
336 g_free (docid);
337 continue;
338 }
339
340 filename = g_build_filename (langdirname,
341 g_file_info_get_name (child),
342 "index.page",
343 NULL);
344 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
345 entry = g_new0 (HelpListEntry, 1);
346 entry->id = docid;
347 entry->filename = filename;
348 entry->type = YELP_URI_DOCUMENT_TYPE_MALLARD;
349 goto found;
350 }
351 g_free (filename);
352
353 filename = g_build_filename (langdirname,
354 g_file_info_get_name (child),
355 "index.docbook",
356 NULL);
357 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
358 entry = g_new0 (HelpListEntry, 1);
359 entry->id = docid;
360 entry->filename = filename;
361 entry->type = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
362 goto found;
363 }
364 g_free (filename);
365
366 g_free (docid);
367 found:
368 g_object_unref (child);
369 if (entry != NULL) {
370 g_hash_table_insert (priv->entries, docid, entry);
371 priv->all_entries = g_list_prepend (priv->all_entries, entry);
372 }
373 }
374
375 g_object_unref (children);
376 }
377 }
378 g_free (datadirs);
379
380 theme = gtk_icon_theme_get_default ();
381 for (cur = priv->all_entries; cur != NULL; cur = cur->next) {
382 GDesktopAppInfo *app;
383 gchar *tmp;
384 HelpListEntry *entry = (HelpListEntry *) cur->data;
385 const gchar *entryid = strchr (entry->id, ':') + 1;
386
387 if (entry->type == YELP_URI_DOCUMENT_TYPE_MALLARD)
388 help_list_process_mallard (list, entry);
389 else if (entry->type == YELP_URI_DOCUMENT_TYPE_DOCBOOK)
390 help_list_process_docbook (list, entry);
391
392 tmp = g_strconcat (entryid, ".desktop", NULL);
393 app = g_desktop_app_info_new (tmp);
394 g_free (tmp);
395
396 if (app == NULL) {
397 char **prefix;
398 for (prefix = (char **) known_vendor_prefixes; *prefix; prefix++) {
399 tmp = g_strconcat (*prefix, "-", entryid, ".desktop", NULL);
400 app = g_desktop_app_info_new (tmp);
401 g_free (tmp);
402 if (app)
403 break;
404 }
405 }
406
407 if (app != NULL) {
408 GIcon *icon = g_app_info_get_icon ((GAppInfo *) app);
409 if (icon != NULL) {
410 GtkIconInfo *info = gtk_icon_theme_lookup_by_gicon (theme,
411 icon, 22,
412 GTK_ICON_LOOKUP_NO_SVG);
413 if (info != NULL) {
414 const gchar *iconfile = gtk_icon_info_get_filename (info);
415 if (iconfile)
416 entry->icon = g_filename_to_uri (iconfile, NULL, NULL);
417 g_object_unref (info);
418 }
419 }
420 g_object_unref (app);
421 }
422 }
423
424 g_mutex_lock (&priv->mutex);
425 priv->process_running = FALSE;
426 priv->process_ran = TRUE;
427 while (priv->pending) {
428 gchar *page_id = (gchar *) priv->pending->data;
429 help_list_handle_page (list, page_id);
430 g_free (page_id);
431 priv->pending = g_slist_delete_link (priv->pending, priv->pending);
432 }
433 g_mutex_unlock (&priv->mutex);
434
435 g_object_unref (list);
436 }
437
438 /* This function expects to be called inside a locked mutex */
439 static void
help_list_handle_page(YelpHelpList * list,const gchar * page_id)440 help_list_handle_page (YelpHelpList *list,
441 const gchar *page_id)
442 {
443 gchar **colors, *tmp;
444 GList *cur;
445 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (list);
446 GtkTextDirection direction = gtk_widget_get_default_direction ();
447 GString *string = g_string_new
448 ("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><style type='text/css'>\n"
449 "html { height: 100%; }\n"
450 "body { margin: 0; padding: 0; max-width: 100%;");
451 colors = yelp_settings_get_colors (yelp_settings_get_default ());
452
453 tmp = g_markup_printf_escaped (" background-color: %s; color: %s;"
454 " direction: %s; }\n",
455 colors[YELP_SETTINGS_COLOR_BASE],
456 colors[YELP_SETTINGS_COLOR_TEXT],
457 (direction == GTK_TEXT_DIR_RTL) ? "rtl" : "ltr");
458 g_string_append (string, tmp);
459 g_free (tmp);
460
461 g_string_append (string,
462 "div.body { margin: 0 12px 0 12px; padding: 0;"
463 " max-width: 60em; min-height: 20em; }\n"
464 "div.header { max-width: 100%; width: 100%;"
465 " padding: 0; margin: 0 0 1em 0; }\n"
466 "div.footer { max-width: 60em; }\n"
467 "div.sect { margin-top: 1.72em; }\n"
468 "div.trails { margin: 0; padding: 0.2em 12px 0 12px;");
469
470 tmp = g_markup_printf_escaped (" background-color: %s;"
471 " border-bottom: solid 1px %s; }\n",
472 colors[YELP_SETTINGS_COLOR_GRAY_BASE],
473 colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
474 g_string_append (string, tmp);
475 g_free (tmp);
476
477 g_string_append (string,
478 "div.trail { margin: 0 1em 0.2em 1em; padding: 0; text-indent: -1em;");
479
480 tmp = g_markup_printf_escaped (" color: %s; }\n",
481 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT]);
482 g_string_append (string, tmp);
483 g_free (tmp);
484
485 g_string_append (string,
486 "a.trail { white-space: nowrap; }\n"
487 "div.hgroup { margin: 0 0 0.5em 0;");
488
489 tmp = g_markup_printf_escaped (" color: %s;"
490 " border-bottom: solid 1px %s; }\n",
491 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
492 colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
493 g_string_append (string, tmp);
494 g_free (tmp);
495
496 tmp = g_markup_printf_escaped ("div.title { margin: 0 0 0.2em 0; font-weight: bold; color: %s; }\n"
497 "div.desc { margin: 0 0 0.2em 0; }\n"
498 "div.linkdiv div.inner { padding-%s: 30px; min-height: 24px;"
499 " background-position: top %s; background-repeat: no-repeat;"
500 " -webkit-background-size: 22px 22px; }\n"
501 "div.linkdiv div.title {font-size: 1em; color: inherit; }\n"
502 "div.linkdiv div.desc { color: %s; }\n"
503 "div.linkdiv { margin: 0; padding: 0.5em; }\n"
504 "a:hover div.linkdiv {"
505 " text-decoration: none;"
506 " outline: solid 1px %s;"
507 " background: -webkit-gradient(linear, left top, left 80,"
508 " from(%s), to(%s)); }\n",
509 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
510 ((direction == GTK_TEXT_DIR_RTL) ? "right" : "left"),
511 ((direction == GTK_TEXT_DIR_RTL) ? "right" : "left"),
512 colors[YELP_SETTINGS_COLOR_TEXT_LIGHT],
513 colors[YELP_SETTINGS_COLOR_BLUE_BASE],
514 colors[YELP_SETTINGS_COLOR_BLUE_BASE],
515 colors[YELP_SETTINGS_COLOR_BASE]);
516 g_string_append (string, tmp);
517 g_free (tmp);
518
519 g_string_append (string,
520 "h1, h2, h3, h4, h5, h6, h7 { margin: 0; padding: 0; font-weight: bold; }\n"
521 "h1 { font-size: 1.44em; }\n"
522 "h2 { font-size: 1.2em; }"
523 "h3.title, h4.title, h5.title, h6.title, h7.title { font-size: 1.2em; }"
524 "h3, h4, h5, h6, h7 { font-size: 1em; }"
525 "p { line-height: 1.72em; }"
526 "div, pre, p { margin: 1em 0 0 0; padding: 0; }"
527 "div:first-child, pre:first-child, p:first-child { margin-top: 0; }"
528 "div.inner, div.contents, pre.contents { margin-top: 0; }"
529 "p img { vertical-align: middle; }"
530 "a {"
531 " text-decoration: none;");
532
533 tmp = g_markup_printf_escaped (" color: %s; } a:visited { color: %s; }",
534 colors[YELP_SETTINGS_COLOR_LINK],
535 colors[YELP_SETTINGS_COLOR_LINK_VISITED]);
536 g_string_append (string, tmp);
537 g_free (tmp);
538
539 g_string_append (string,
540 "a:hover { text-decoration: underline; }\n"
541 "a img { border: none; }\n"
542 "</style>\n");
543
544 tmp = g_markup_printf_escaped ("<title>%s</title>",
545 _("All Help Documents"));
546 g_string_append (string, tmp);
547 g_free (tmp);
548
549 g_string_append (string,
550 "</head><body>"
551 "<div class='header'></div>"
552 "<div class='body'><div class='hgroup'>");
553 tmp = g_markup_printf_escaped ("<h1>%s</h1></div>\n",
554 _("All Help Documents"));
555 g_string_append (string, tmp);
556 g_free (tmp);
557
558 priv->all_entries = g_list_sort (priv->all_entries,
559 (GCompareFunc) help_list_entry_cmp);
560 for (cur = priv->all_entries; cur != NULL; cur = cur->next) {
561 HelpListEntry *entry = (HelpListEntry *) cur->data;
562 gchar *title = entry->title ? entry->title : (strchr (entry->id, ':') + 1);
563 const gchar *desc = entry->desc ? entry->desc : "";
564
565 tmp = g_markup_printf_escaped ("<a href='%s'><div class='linkdiv'>",
566 entry->id);
567 g_string_append (string, tmp);
568 g_free (tmp);
569
570 if (entry->icon) {
571 tmp = g_markup_printf_escaped ("<div class='inner' style='background-image: url(%s);'>",
572 entry->icon);
573 g_string_append (string, tmp);
574 g_free (tmp);
575 }
576 else
577 g_string_append (string, "<div class='inner'>");
578
579 tmp = g_markup_printf_escaped ("<div class='title'>%s</div>"
580 "<div class='desc'>%s</div>"
581 "</div></div></a>",
582 title, desc);
583 g_string_append (string, tmp);
584 g_free (tmp);
585 }
586
587 g_string_append (string,
588 "</div>"
589 "<div class='footer'></div>"
590 "</body></html>");
591
592 yelp_document_give_contents (YELP_DOCUMENT (list), page_id,
593 string->str,
594 "application/xhtml+xml");
595 g_strfreev (colors);
596 g_string_free (string, FALSE);
597 yelp_document_signal (YELP_DOCUMENT (list), page_id,
598 YELP_DOCUMENT_SIGNAL_CONTENTS, NULL);
599 }
600
601
602 static void
help_list_process_docbook(YelpHelpList * list,HelpListEntry * entry)603 help_list_process_docbook (YelpHelpList *list,
604 HelpListEntry *entry)
605 {
606 xmlParserCtxtPtr parserCtxt;
607 xmlDocPtr xmldoc;
608 xmlXPathContextPtr xpath;
609 xmlXPathObjectPtr obj = NULL;
610 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (list);
611
612 parserCtxt = xmlNewParserCtxt ();
613 xmldoc = xmlCtxtReadFile (parserCtxt,
614 (const char *) entry->filename, NULL,
615 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
616 XML_PARSE_NOENT | XML_PARSE_NONET );
617 xmlFreeParserCtxt (parserCtxt);
618 if (xmldoc == NULL)
619 return;
620
621 xmlXIncludeProcessFlags (xmldoc,
622 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
623 XML_PARSE_NOENT | XML_PARSE_NONET );
624
625 xpath = xmlXPathNewContext (xmldoc);
626 xmlXPathRegisterNs (xpath, BAD_CAST "db",
627 BAD_CAST "http://docbook.org/ns/docbook");
628 obj = xmlXPathCompiledEval (priv->get_docbook_title, xpath);
629 if (obj) {
630 if (obj->stringval)
631 entry->title = g_strdup ((const gchar *) obj->stringval);
632 xmlXPathFreeObject (obj);
633 }
634
635 if (xmldoc)
636 xmlFreeDoc (xmldoc);
637 if (xpath)
638 xmlXPathFreeContext (xpath);
639 }
640
641 static void
help_list_process_mallard(YelpHelpList * list,HelpListEntry * entry)642 help_list_process_mallard (YelpHelpList *list,
643 HelpListEntry *entry)
644 {
645 xmlParserCtxtPtr parserCtxt;
646 xmlDocPtr xmldoc;
647 xmlXPathContextPtr xpath;
648 xmlXPathObjectPtr obj = NULL;
649 YelpHelpListPrivate *priv = yelp_help_list_get_instance_private (list);
650
651 parserCtxt = xmlNewParserCtxt ();
652 xmldoc = xmlCtxtReadFile (parserCtxt,
653 (const char *) entry->filename, NULL,
654 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
655 XML_PARSE_NOENT | XML_PARSE_NONET );
656 xmlFreeParserCtxt (parserCtxt);
657 if (xmldoc == NULL)
658 return;
659
660 xmlXIncludeProcessFlags (xmldoc,
661 XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA |
662 XML_PARSE_NOENT | XML_PARSE_NONET );
663
664 xpath = xmlXPathNewContext (xmldoc);
665 xmlXPathRegisterNs (xpath, BAD_CAST "mal",
666 BAD_CAST "http://projectmallard.org/1.0/");
667
668 obj = xmlXPathCompiledEval (priv->get_mallard_title, xpath);
669 if (obj) {
670 if (obj->stringval)
671 entry->title = g_strdup ((const gchar *) obj->stringval);
672 xmlXPathFreeObject (obj);
673 }
674
675 obj = xmlXPathCompiledEval (priv->get_mallard_desc, xpath);
676 if (obj) {
677 if (obj->stringval)
678 entry->desc = g_strdup ((const gchar *) obj->stringval);
679 xmlXPathFreeObject (obj);
680 }
681
682 if (xmldoc)
683 xmlFreeDoc (xmldoc);
684 if (xpath)
685 xmlXPathFreeContext (xpath);
686 }
687