1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Copyright (C) 2009 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>
32 #include "yelp-settings.h"
34 static void yelp_uri_dispose (GObject
*object
);
35 static void yelp_uri_finalize (GObject
*object
);
37 static void resolve_start (YelpUri
*uri
);
38 static void resolve_sync (YelpUri
*uri
);
39 static void resolve_async (YelpUri
*uri
);
40 static gboolean
resolve_final (YelpUri
*uri
);
42 static void resolve_file_uri (YelpUri
*uri
);
43 static void resolve_file_path (YelpUri
*uri
);
44 static void resolve_data_dirs (YelpUri
*uri
,
49 static void resolve_ghelp_uri (YelpUri
*uri
);
50 static void resolve_help_uri (YelpUri
*uri
);
51 static void resolve_help_list_uri (YelpUri
*uri
);
52 static void resolve_man_uri (YelpUri
*uri
);
53 static void resolve_info_uri (YelpUri
*uri
);
54 static void resolve_xref_uri (YelpUri
*uri
);
55 static void resolve_page_and_frag (YelpUri
*uri
,
57 static void resolve_gfile (YelpUri
*uri
,
61 static gboolean
is_man_path (const gchar
*uri
,
62 const gchar
*encoding
);
64 G_DEFINE_TYPE (YelpUri
, yelp_uri
, G_TYPE_OBJECT
)
65 #define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_URI, YelpUriPrivate))
67 typedef struct _YelpUriPrivate YelpUriPrivate
;
68 struct _YelpUriPrivate
{
71 YelpUriDocumentType doctype
;
72 YelpUriDocumentType tmptype
;
93 static guint uri_signals
[LAST_SIGNAL
] = {0,};
95 /******************************************************************************/
97 static const gchar
*mancats
[] = {
99 "1", "1p", "1g", "1t", "1x", "1ssl", "1m",
101 "3", "3o", "3t", "3p", "3blt", "3nas", "3form", "3menu", "3tiff", "3ssl", "3readline",
102 "3ncurses", "3curses", "3f", "3pm", "3perl", "3qt", "3x", "3X11",
104 "5", "5snmp", "5x", "5ssl",
106 "7", "7gcc", "7x", "7ssl",
107 "8", "8l", "9", "0p",
111 static const gchar
*infosuffix
[] = {
113 ".info.gz", ".info.bz2", ".info.lzma",
114 ".gz", ".bz2", ".lzma",
118 static const gchar default_info_path
[] =
119 "/usr/info:/usr/share/info:/usr/local/info:/usr/local/share/info";
121 /******************************************************************************/
124 yelp_uri_class_init (YelpUriClass
*klass
)
126 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
128 object_class
->dispose
= yelp_uri_dispose
;
129 object_class
->finalize
= yelp_uri_finalize
;
131 uri_signals
[RESOLVED
] =
132 g_signal_new ("resolved",
133 G_OBJECT_CLASS_TYPE (klass
),
136 g_cclosure_marshal_VOID__VOID
,
139 g_type_class_add_private (klass
, sizeof (YelpUriPrivate
));
143 yelp_uri_init (YelpUri
*uri
)
145 YelpUriPrivate
*priv
= GET_PRIV (uri
);
147 priv
->query
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
153 yelp_uri_dispose (GObject
*object
)
155 YelpUriPrivate
*priv
= GET_PRIV (object
);
158 g_object_unref (priv
->gfile
);
162 if (priv
->res_base
) {
163 g_object_unref (priv
->res_base
);
164 priv
->res_base
= NULL
;
168 g_hash_table_destroy (priv
->query
);
172 G_OBJECT_CLASS (yelp_uri_parent_class
)->dispose (object
);
176 yelp_uri_finalize (GObject
*object
)
178 YelpUriPrivate
*priv
= GET_PRIV (object
);
180 g_free (priv
->docuri
);
181 g_free (priv
->fulluri
);
182 g_strfreev (priv
->search_path
);
183 g_free (priv
->page_id
);
184 g_free (priv
->frag_id
);
185 g_free (priv
->res_arg
);
187 G_OBJECT_CLASS (yelp_uri_parent_class
)->finalize (object
);
190 /******************************************************************************/
193 yelp_uri_new (const gchar
*arg
)
195 return yelp_uri_new_relative (NULL
, arg
);
199 yelp_uri_new_relative (YelpUri
*base
, const gchar
*arg
)
202 YelpUriPrivate
*priv
;
204 uri
= (YelpUri
*) g_object_new (YELP_TYPE_URI
, NULL
);
206 priv
= GET_PRIV (uri
);
207 priv
->doctype
= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
;
209 priv
->res_base
= g_object_ref (base
);
210 priv
->res_arg
= g_strdup (arg
);
216 yelp_uri_new_search (YelpUri
*base
,
220 YelpUriPrivate
*priv
;
223 uri
= (YelpUri
*) g_object_new (YELP_TYPE_URI
, NULL
);
225 priv
= GET_PRIV (uri
);
226 priv
->doctype
= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
;
228 priv
->res_base
= g_object_ref (base
);
229 tmp
= g_uri_escape_string (text
, NULL
, FALSE
);
230 priv
->res_arg
= g_strconcat("xref:search=", tmp
, NULL
);
236 /******************************************************************************/
239 yelp_uri_resolve (YelpUri
*uri
)
241 YelpUriPrivate
*priv
= GET_PRIV (uri
);
243 if (priv
->res_base
&& !yelp_uri_is_resolved (priv
->res_base
)) {
244 g_signal_connect_swapped (priv
->res_base
, "resolved",
245 G_CALLBACK (resolve_start
),
247 yelp_uri_resolve (priv
->res_base
);
255 yelp_uri_resolve_sync (YelpUri
*uri
)
257 YelpUriPrivate
*priv
= GET_PRIV (uri
);
259 if (priv
->doctype
!= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
263 yelp_uri_resolve_sync (priv
->res_base
);
270 /* We want code to be able to do something like this:
272 * if (yelp_uri_get_document_type (uri) != YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
273 * g_signal_connect (uri, "resolve", callback, data);
274 * yelp_uri_resolve (uri);
277 * Resolving happens in a separate thread, though, so if that thread can change
278 * the document type, we have a race condition. So here's the rules we play by:
280 * 1) None of the getters except the document type getter can return real data
281 * while the URI is unresolved. They all do a resolved check first, and
282 * return NULL if the URI is not resolved.
284 * 2) The threaded resolver functions can modify anything but the document
285 * type. They are the only things that are allowed to modify that data.
287 * 3) The resolver thread is not allowed to modify the document type. When
288 * it's done, it queues an async function to set the document type and
289 * emit "resolved" in the main thread.
291 * 4) Once a URI is resolved, it is immutable.
294 resolve_start (YelpUri
*uri
)
296 YelpUriPrivate
*priv
= GET_PRIV (uri
);
298 if (priv
->resolver
== NULL
) {
300 priv
->resolver
= g_thread_new ("uri-resolve",
301 (GThreadFunc
) resolve_async
,
307 resolve_sync (YelpUri
*uri
)
309 YelpUriPrivate
*priv
= GET_PRIV (uri
);
311 if (g_str_has_prefix (priv
->res_arg
, "ghelp:")
312 || g_str_has_prefix (priv
->res_arg
, "gnome-help:")) {
313 resolve_ghelp_uri (uri
);
315 else if (g_str_has_prefix (priv
->res_arg
, "help:")) {
316 resolve_help_uri (uri
);
318 else if (g_str_has_prefix (priv
->res_arg
, "help-list:")) {
319 resolve_help_list_uri (uri
);
321 else if (g_str_has_prefix (priv
->res_arg
, "file:")) {
322 resolve_file_uri (uri
);
324 else if (g_str_has_prefix (priv
->res_arg
, "man:")) {
325 resolve_man_uri (uri
);
327 else if (g_str_has_prefix (priv
->res_arg
, "info:")) {
328 resolve_info_uri (uri
);
330 else if (g_str_has_prefix (priv
->res_arg
, "xref:")) {
331 YelpUriPrivate
*base_priv
;
332 if (priv
->res_base
== NULL
) {
333 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_ERROR
;
336 base_priv
= GET_PRIV (priv
->res_base
);
337 switch (base_priv
->doctype
) {
338 case YELP_URI_DOCUMENT_TYPE_UNRESOLVED
:
340 case YELP_URI_DOCUMENT_TYPE_DOCBOOK
:
341 case YELP_URI_DOCUMENT_TYPE_MALLARD
:
342 case YELP_URI_DOCUMENT_TYPE_INFO
:
343 resolve_xref_uri (uri
);
345 case YELP_URI_DOCUMENT_TYPE_MAN
: {
346 gchar
*tmp
= g_strconcat ("man:", priv
->res_arg
+ 5, NULL
);
347 g_free (priv
->res_arg
);
349 resolve_man_uri (uri
);
352 case YELP_URI_DOCUMENT_TYPE_TEXT
:
353 case YELP_URI_DOCUMENT_TYPE_HTML
:
354 case YELP_URI_DOCUMENT_TYPE_XHTML
:
355 resolve_file_path (uri
);
357 case YELP_URI_DOCUMENT_TYPE_HELP_LIST
:
358 /* FIXME: what do we do? */
360 case YELP_URI_DOCUMENT_TYPE_NOT_FOUND
:
361 case YELP_URI_DOCUMENT_TYPE_EXTERNAL
:
362 case YELP_URI_DOCUMENT_TYPE_ERROR
:
365 g_assert_not_reached ();
369 else if (strchr (priv
->res_arg
, ':')) {
370 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_EXTERNAL
;
373 resolve_file_path (uri
);
376 /* We _always_ want to have a non-null fulluri, so check for it
377 * having been set here and, if we can't think of something
378 * better, set it to res_arg. */
379 if (!priv
->fulluri
) {
380 priv
->fulluri
= g_strdup (priv
->res_arg
);
385 resolve_async (YelpUri
*uri
)
388 g_idle_add ((GSourceFunc
) resolve_final
, uri
);
392 resolve_final (YelpUri
*uri
)
394 YelpUriPrivate
*priv
= GET_PRIV (uri
);
396 priv
->resolver
= NULL
;
398 if (priv
->tmptype
!= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
399 priv
->doctype
= priv
->tmptype
;
401 priv
->doctype
= YELP_URI_DOCUMENT_TYPE_ERROR
;
403 if (priv
->res_base
) {
404 g_object_unref (priv
->res_base
);
405 priv
->res_base
= NULL
;
409 g_free (priv
->res_arg
);
410 priv
->res_arg
= NULL
;
413 g_signal_emit (uri
, uri_signals
[RESOLVED
], 0);
414 g_object_unref (uri
);
418 /******************************************************************************/
421 yelp_uri_is_resolved (YelpUri
*uri
)
423 YelpUriPrivate
*priv
= GET_PRIV (uri
);
424 return priv
->doctype
!= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
;
428 yelp_uri_get_document_type (YelpUri
*uri
)
430 YelpUriPrivate
*priv
= GET_PRIV (uri
);
431 return priv
->doctype
;
435 yelp_uri_get_document_uri (YelpUri
*uri
)
437 YelpUriPrivate
*priv
= GET_PRIV (uri
);
438 if (priv
->doctype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
441 /* There's some client code where it makes sense to want a
442 * document uri, whether or not it conforms to a scheme we really
443 * understand. For example, we might want to look up whether the
444 * given page is currently being visited. */
445 if ((!priv
->docuri
) && priv
->fulluri
) {
446 return g_strdup (priv
->fulluri
);
449 return g_strdup (priv
->docuri
);
453 yelp_uri_get_canonical_uri (YelpUri
*uri
)
455 YelpUriPrivate
*priv
= GET_PRIV (uri
);
456 if (priv
->doctype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
458 return g_strdup (priv
->fulluri
);
462 yelp_uri_get_file (YelpUri
*uri
)
464 YelpUriPrivate
*priv
= GET_PRIV (uri
);
465 if (priv
->doctype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
467 return priv
->gfile
? g_object_ref (priv
->gfile
) : NULL
;
471 yelp_uri_get_search_path (YelpUri
*uri
)
473 YelpUriPrivate
*priv
= GET_PRIV (uri
);
474 if (priv
->doctype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
476 return g_strdupv (priv
->search_path
);
480 yelp_uri_get_page_id (YelpUri
*uri
)
482 YelpUriPrivate
*priv
= GET_PRIV (uri
);
483 if (priv
->doctype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
485 return g_strdup (priv
->page_id
);
489 yelp_uri_get_frag_id (YelpUri
*uri
)
491 YelpUriPrivate
*priv
= GET_PRIV (uri
);
492 if (priv
->doctype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
494 return g_strdup (priv
->frag_id
);
498 yelp_uri_get_query (YelpUri
*uri
,
501 YelpUriPrivate
*priv
= GET_PRIV (uri
);
502 const gchar
*ret
= g_hash_table_lookup (priv
->query
, key
);
504 return g_strdup (ret
);
509 /******************************************************************************/
512 yelp_uri_locate_file_uri (YelpUri
*uri
,
513 const gchar
*filename
)
515 YelpUriPrivate
*priv
= GET_PRIV (uri
);
518 gchar
*returi
= NULL
;
521 if (g_path_is_absolute (filename
)) {
522 if (g_file_test (filename
, G_FILE_TEST_EXISTS
))
523 return g_filename_to_uri (filename
, NULL
, NULL
);
527 for (i
= 0; priv
->search_path
[i
] != NULL
; i
++) {
528 fullpath
= g_strconcat (priv
->search_path
[i
],
532 if (g_file_test (fullpath
, G_FILE_TEST_EXISTS
)) {
533 gfile
= g_file_new_for_path (fullpath
);
534 returi
= g_file_get_uri (gfile
);
535 g_object_unref (gfile
);
544 /******************************************************************************/
547 resolve_file_uri (YelpUri
*uri
)
549 YelpUriPrivate
*priv
= GET_PRIV (uri
);
551 const gchar
*hash
= strchr (priv
->res_arg
, '#');
554 uristr
= g_strndup (priv
->res_arg
, hash
- priv
->res_arg
);
558 uristr
= priv
->res_arg
;
560 priv
->gfile
= g_file_new_for_uri (uristr
);
562 resolve_gfile (uri
, NULL
, hash
);
566 resolve_file_path (YelpUri
*uri
)
568 YelpUriPrivate
*base_priv
= NULL
;
569 YelpUriPrivate
*priv
= GET_PRIV (uri
);
573 /* Treat xref: URIs like relative file paths */
574 if (g_str_has_prefix (priv
->res_arg
, "xref:")) {
575 gchar
*tmp
= g_strdup (priv
->res_arg
+ 5);
576 g_free (priv
->res_arg
);
581 base_priv
= GET_PRIV (priv
->res_base
);
583 hash
= strchr (priv
->res_arg
, '#');
585 path
= g_strndup (priv
->res_arg
, hash
- priv
->res_arg
);
589 path
= priv
->res_arg
;
591 if (priv
->res_arg
[0] == '/') {
592 priv
->gfile
= g_file_new_for_path (path
);
594 else if (base_priv
&& base_priv
->gfile
) {
596 info
= g_file_query_info (base_priv
->gfile
,
597 G_FILE_ATTRIBUTE_STANDARD_TYPE
,
598 G_FILE_QUERY_INFO_NONE
,
600 if (g_file_info_get_file_type (info
) == G_FILE_TYPE_REGULAR
) {
601 GFile
*parent
= g_file_get_parent (base_priv
->gfile
);
602 priv
->gfile
= g_file_resolve_relative_path (parent
, path
);
603 g_object_unref (parent
);
606 priv
->gfile
= g_file_resolve_relative_path (base_priv
->gfile
, path
);
612 cur
= g_get_current_dir ();
613 curfile
= g_file_new_for_path (cur
);
614 priv
->gfile
= g_file_resolve_relative_path (curfile
, path
);
615 g_object_unref (curfile
);
619 resolve_gfile (uri
, NULL
, hash
);
623 resolve_data_dirs (YelpUri
*ret
,
629 const gchar
* const *sdatadirs
= g_get_system_data_dirs ();
630 const gchar
* const *langs
= g_get_language_names ();
631 /* The strings are still owned by GLib; we just own the array. */
633 YelpUriPrivate
*priv
= GET_PRIV (ret
);
634 gchar
*filename
= NULL
;
635 gchar
**searchpath
= NULL
;
636 gint searchi
, searchmax
;
637 gint datadir_i
, lang_i
;
639 datadirs
= g_new0 (gchar
*, g_strv_length ((gchar
**) sdatadirs
) + 2);
640 datadirs
[0] = (gchar
*) g_get_user_data_dir ();
641 for (datadir_i
= 0; sdatadirs
[datadir_i
]; datadir_i
++)
642 datadirs
[datadir_i
+ 1] = (gchar
*) sdatadirs
[datadir_i
];
646 searchpath
= g_new0 (gchar
*, 10);
648 for (datadir_i
= 0; datadirs
[datadir_i
]; datadir_i
++) {
649 for (lang_i
= 0; langs
[lang_i
]; lang_i
++) {
650 gchar
*helpdir
= g_build_filename (datadirs
[datadir_i
],
652 langfirst
? langs
[lang_i
] : docid
,
653 langfirst
? docid
: langs
[lang_i
],
655 if (!g_file_test (helpdir
, G_FILE_TEST_IS_DIR
)) {
660 if (searchi
+ 1 >= searchmax
) {
662 searchpath
= g_renew (gchar
*, searchpath
, searchmax
);
664 searchpath
[searchi
] = helpdir
;
665 searchpath
[++searchi
] = NULL
;
667 if (priv
->tmptype
!= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
)
668 /* We've already found it. We're just adding to the search path now. */
671 filename
= g_strdup_printf ("%s/index.page", helpdir
);
672 if (g_file_test (filename
, G_FILE_TEST_IS_REGULAR
)) {
673 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MALLARD
;
675 filename
= g_strdup (helpdir
);
681 filename
= g_strdup_printf ("%s/index.docbook", helpdir
);
682 if (g_file_test (filename
, G_FILE_TEST_IS_REGULAR
)) {
683 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_DOCBOOK
;
689 filename
= g_strdup_printf ("%s/%s.xml", helpdir
, pageid
);
690 if (g_file_test (filename
, G_FILE_TEST_IS_REGULAR
)) {
691 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_DOCBOOK
;
697 filename
= g_strdup_printf ("%s/%s.html", helpdir
, pageid
);
698 if (g_file_test (filename
, G_FILE_TEST_IS_REGULAR
)) {
699 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_HTML
;
704 filename
= g_strdup_printf ("%s/%s.xhtml", helpdir
, pageid
);
705 if (g_file_test (filename
, G_FILE_TEST_IS_REGULAR
)) {
706 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_XHTML
;
710 } /* end for langs */
711 } /* end for datadirs */
714 if (priv
->tmptype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
) {
715 g_strfreev (searchpath
);
716 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_NOT_FOUND
;
719 priv
->gfile
= g_file_new_for_path (filename
);
720 priv
->search_path
= searchpath
;
725 build_ghelp_fulluri (YelpUri
*uri
)
727 YelpUriPrivate
*priv
= GET_PRIV (uri
);
729 g_assert (priv
->tmptype
!= YELP_URI_DOCUMENT_TYPE_UNRESOLVED
);
730 g_assert (priv
->docuri
!= NULL
);
731 priv
->fulluri
= g_strconcat (priv
->docuri
,
732 priv
->tmptype
== YELP_URI_DOCUMENT_TYPE_MALLARD
? "/" : "",
733 priv
->page_id
? "?" : "",
734 priv
->page_id
? priv
->page_id
: "",
735 priv
->frag_id
? "#" : "",
736 priv
->frag_id
? priv
->frag_id
: "",
741 resolve_ghelp_uri (YelpUri
*uri
)
743 /* ghelp:/path/to/file
744 * ghelp:document[/file][?page][#frag]
746 YelpUriPrivate
*priv
= GET_PRIV (uri
);
747 gchar
*document
, *slash
, *query
, *hash
;
748 gchar
*colon
, *c
; /* do not free */
750 colon
= strchr (priv
->res_arg
, ':');
752 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_ERROR
;
756 slash
= query
= hash
= NULL
;
757 for (c
= colon
; *c
!= '\0'; c
++) {
758 if (*c
== '#' && hash
== NULL
)
760 else if (*c
== '?' && query
== NULL
&& hash
== NULL
)
762 else if (*c
== '/' && slash
== NULL
&& query
== NULL
&& hash
== NULL
)
766 if (slash
|| query
|| hash
)
767 document
= g_strndup (colon
+ 1,
768 (slash
? slash
: (query
? query
: hash
)) - colon
- 1);
770 document
= g_strdup (colon
+ 1);
772 if (slash
&& (query
|| hash
))
773 slash
= g_strndup (slash
+ 1,
774 (query
? query
: hash
) - slash
- 1);
776 slash
= g_strdup (slash
+ 1);
779 query
= g_strndup (query
+ 1,
782 query
= g_strdup (query
+ 1);
785 hash
= g_strdup (hash
+ 1);
787 if (*(colon
+ 1) == '/') {
790 path
= g_build_filename ("/", slash
, NULL
);
791 if (g_file_test (path
, G_FILE_TEST_EXISTS
)) {
792 priv
->gfile
= g_file_new_for_path (path
);
793 resolve_gfile (uri
, query
, hash
);
795 gchar
*dirname
= g_path_get_dirname (path
);
796 gchar
*basename
= g_path_get_basename (path
);
798 priv
->gfile
= g_file_new_for_path (dirname
);
800 resolve_gfile (uri
, basename
, hash
);
812 resolve_data_dirs (uri
, "gnome/help", document
, slash
? slash
: document
, FALSE
);
815 priv
->page_id
= query
;
816 priv
->frag_id
= hash
;
819 priv
->page_id
= query
;
820 if (priv
->tmptype
!= YELP_URI_DOCUMENT_TYPE_MALLARD
)
821 priv
->frag_id
= g_strdup (query
);
824 priv
->page_id
= hash
;
825 priv
->frag_id
= g_strdup (hash
);
828 if (priv
->frag_id
&& g_str_has_prefix (priv
->frag_id
, "search=")) {
829 g_free (priv
->frag_id
);
830 priv
->frag_id
= NULL
;
833 priv
->docuri
= g_strconcat ("ghelp:", document
,
837 build_ghelp_fulluri (uri
);
845 resolve_help_uri (YelpUri
*uri
)
847 /* help:document[/page][?query][#frag]
849 YelpUriPrivate
*priv
= GET_PRIV (uri
);
850 gchar
*document
, *slash
, *query
, *hash
;
851 gchar
*colon
, *c
; /* do not free */
853 colon
= strchr (priv
->res_arg
, ':');
855 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_ERROR
;
859 slash
= query
= hash
= NULL
;
860 for (c
= colon
; *c
!= '\0'; c
++) {
861 if (*c
== '#' && hash
== NULL
)
863 else if (*c
== '?' && query
== NULL
&& hash
== NULL
)
865 else if (*c
== '/' && slash
== NULL
&& query
== NULL
&& hash
== NULL
)
869 if (slash
|| query
|| hash
)
870 document
= g_strndup (colon
+ 1,
871 (slash
? slash
: (query
? query
: hash
)) - colon
- 1);
873 document
= g_strdup (colon
+ 1);
875 if (slash
&& (query
|| hash
))
876 slash
= g_strndup (slash
+ 1,
877 (query
? query
: hash
) - slash
- 1);
879 slash
= g_strdup (slash
+ 1);
882 query
= g_strndup (query
+ 1,
885 query
= g_strdup (query
+ 1);
888 gchar
**keyvals
= g_strsplit (query
, "&", 0);
891 for (i
= 0; keyvals
[i
]; i
++) {
893 val
= strchr (keyvals
[i
], '=');
896 key
= g_uri_unescape_segment (keyvals
[i
], val
, NULL
);
897 val
= g_uri_unescape_string (val
+ 1, NULL
);
899 g_hash_table_insert (priv
->query
, key
, val
);
902 g_strfreev (keyvals
);
906 hash
= g_strdup (hash
+ 1);
908 priv
->page_id
= (slash
? slash
: g_strdup ("index"));
909 resolve_data_dirs (uri
, "help", document
, priv
->page_id
, TRUE
);
912 priv
->frag_id
= hash
;
913 if (priv
->frag_id
&& g_str_has_prefix (priv
->frag_id
, "search=")) {
914 g_free (priv
->frag_id
);
915 priv
->frag_id
= NULL
;
918 priv
->docuri
= g_strconcat ("help:", document
, NULL
);
920 priv
->fulluri
= g_strconcat (priv
->docuri
,
921 priv
->page_id
? "/" : "",
922 priv
->page_id
? priv
->page_id
: "",
925 priv
->frag_id
? "#" : "",
926 priv
->frag_id
? priv
->frag_id
: "",
935 resolve_help_list_uri (YelpUri
*uri
)
937 YelpUriPrivate
*priv
= GET_PRIV (uri
);
938 priv
->docuri
= g_strdup ("help-list:");
939 priv
->fulluri
= g_strdup (priv
->res_arg
);
940 priv
->page_id
= g_strdup ("index");
941 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_HELP_LIST
;
945 Resolve a manual file's path using 'man -w'. section may be NULL,
946 otherwise should be the section of the manual (ie should have dealt
947 with empty strings before calling this!) Returns NULL if the file
951 find_man_path (gchar
* name
, gchar
* section
)
953 const gchar
* argv
[] = { "man", "-w", NULL
, NULL
, NULL
};
955 gchar
*ystdout
= NULL
;
958 GError
*error
= NULL
;
960 /* Syntax for man is "man -w <section> <name>", possibly omitting
969 /* g_strdupv() should accept a "const gchar **". */
970 my_argv
= g_strdupv ((gchar
**) argv
);
972 if (!g_spawn_sync (NULL
, my_argv
, NULL
,
973 G_SPAWN_SEARCH_PATH
| G_SPAWN_STDERR_TO_DEV_NULL
,
975 &ystdout
, NULL
, &status
, &error
)) {
976 g_warning ("Couldn't find path for %s(%s). Error: %s",
977 name
, section
, error
->message
);
978 g_error_free (error
);
981 g_strfreev (my_argv
);
984 lines
= g_strsplit (ystdout
, "\n", 2);
986 ystdout
= g_strdup (lines
[0]);
997 build_man_uris (YelpUri
*uri
, const char *name
, const char *section
)
999 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1001 g_assert (priv
->tmptype
== YELP_URI_DOCUMENT_TYPE_MAN
);
1002 priv
->docuri
= g_strdup ("man:");
1003 priv
->fulluri
= g_strconcat ("man:", name
,
1005 section
? section
: "",
1007 priv
->page_id
= g_strconcat (name
,
1009 section
? section
: "",
1014 resolve_man_uri (YelpUri
*uri
)
1016 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1017 /* man:/path/to/file
1023 /* Search via regular expressions for name, name(section) and
1024 * name.section (assuming that name doesn't contain forward
1025 * slashes or other nasties)
1027 * If these don't match, assume that we were given a filename
1028 * (absolute iff it starts with a /).
1030 static GRegex
* man_not_path
= NULL
;
1031 GError
*error
= NULL
;
1032 GMatchInfo
*match_info
= NULL
;
1033 gchar
*name
, *section
, *hash
;
1036 if (!man_not_path
) {
1037 /* Match group 1 should contain the name; then one of groups 3
1038 * and 4 will contain the section if there was one. Group 6
1039 * will contain any hash fragment. */
1040 man_not_path
= g_regex_new ("man:((?:[^ /.()#]|\\.(?=[^0-9]))+)"
1041 "(\\(([0-9A-Za-z]+)\\)|\\.([0-9A-Za-z]+)|)"
1044 if (!man_not_path
) {
1045 g_error ("Error with regex in man uri: %s\n",
1050 if (!g_regex_match (man_not_path
, priv
->res_arg
,
1052 /* The regexp didn't match, so treat as a file name. */
1054 static const char *man_suffixes
[] = { "gz", "bz2", "lzma", NULL
};
1056 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1057 priv
->gfile
= g_file_new_for_path (priv
->res_arg
+ 4);
1058 name
= g_file_get_basename (priv
->gfile
);
1059 for (i
= 0; i
< G_N_ELEMENTS (man_suffixes
); i
++) {
1060 if (is_man_path (name
, man_suffixes
[i
])) {
1061 if (man_suffixes
[i
])
1062 name
[strlen (name
) - strlen (man_suffixes
[i
]) - 1] = '\0';
1066 build_man_uris (uri
, name
, NULL
);
1069 /* The regexp matched, so we've got a name/section pair that
1070 * needs resolving. */
1071 name
= g_match_info_fetch (match_info
, 1);
1072 section
= g_match_info_fetch (match_info
, 3);
1073 hash
= g_match_info_fetch (match_info
, 6);
1075 g_error ("Error matching strings in man uri '%s'",
1078 if ((!section
) || (section
[0] == '\0')) {
1079 section
= g_match_info_fetch (match_info
, 4);
1081 if (section
&& section
[0] == '\0') section
= NULL
;
1083 path
= find_man_path (name
, section
);
1086 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_NOT_FOUND
;
1089 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1090 priv
->gfile
= g_file_new_for_path (path
);
1091 build_man_uris (uri
, name
, section
);
1093 if (hash
&& hash
[0] != '\0')
1094 resolve_page_and_frag (uri
, hash
+ 1);
1097 g_match_info_free (match_info
);
1102 build_info_uris (YelpUri
*uri
, const char *name
, const char *section
)
1104 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1106 g_assert (priv
->tmptype
== YELP_URI_DOCUMENT_TYPE_INFO
);
1107 priv
->docuri
= g_strconcat ("info:", name
, NULL
);
1108 priv
->fulluri
= g_strconcat (priv
->docuri
,
1110 section
? section
: "",
1112 priv
->page_id
= g_strdup (section
);
1113 priv
->frag_id
= g_strdup (section
);
1117 resolve_info_uri (YelpUri
*uri
)
1119 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1120 /* info:/path/to/file
1126 static gchar
**infopath
= NULL
;
1129 gchar
*fullpath
= NULL
;
1132 gint infopath_i
, suffix_i
;
1134 if (g_str_has_prefix (priv
->res_arg
, "info:/")) {
1137 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1139 hash
= strchr (priv
->res_arg
+ 5, '#');
1143 path
= g_strndup (priv
->res_arg
+ 5, hash
- (priv
->res_arg
+ 5));
1144 priv
->gfile
= g_file_new_for_path (path
);
1146 sect
= g_strdup (hash
+ 1);
1149 priv
->gfile
= g_file_new_for_path (priv
->res_arg
+ 5);
1151 name
= g_file_get_basename (priv
->gfile
);
1152 for (suffix_i
= 0; infosuffix
[suffix_i
]; suffix_i
++) {
1153 if (g_str_has_suffix (name
, infosuffix
[suffix_i
])) {
1154 name
[strlen (name
) - strlen (infosuffix
[suffix_i
])] = '\0';
1159 build_info_uris (uri
, name
, sect
);
1166 /* Initialize infopath only once */
1168 /* Use the same logic as the info program. If INFOPATH is not
1169 specified, use the default. If it is specified, just use it
1170 unless it ends with a colon, in which case we add the
1171 default as a suffix.
1173 const gchar
*env
= g_getenv ("INFOPATH");
1175 if (!env
|| env
[0] == '\0')
1176 paths
= g_strdup (default_info_path
);
1177 else if (env
[strlen (env
)-1] == ':')
1178 paths
= g_strconcat (env
, default_info_path
, NULL
);
1180 paths
= g_strdup (env
);
1182 infopath
= g_strsplit (paths
, ":", 0);
1187 colon
= strchr (priv
->res_arg
, ':');
1191 colon
= (gchar
*) priv
->res_arg
;
1193 if (colon
[0] == '(') {
1194 const gchar
*rbrace
= strchr (colon
, ')');
1196 name
= g_strndup (colon
+ 1, rbrace
- colon
- 1);
1197 sect
= g_strdup (rbrace
+ 1);
1201 const gchar
*hash
= strchr (colon
, '#');
1203 name
= g_strndup (colon
, hash
- colon
);
1204 sect
= g_strdup (hash
+ 1);
1207 name
= g_strdup (colon
);
1212 for (infopath_i
= 0; infopath
[infopath_i
]; infopath_i
++) {
1213 if (!g_file_test (infopath
[infopath_i
], G_FILE_TEST_IS_DIR
))
1215 for (suffix_i
= 0; infosuffix
[suffix_i
]; suffix_i
++) {
1216 fullpath
= g_strconcat (infopath
[infopath_i
], "/",
1217 name
, infosuffix
[suffix_i
], NULL
);
1218 if (g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
))
1223 if (fullpath
!= NULL
)
1228 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1229 priv
->gfile
= g_file_new_for_path (fullpath
);
1230 build_info_uris (uri
, name
, sect
);
1232 gchar
*res_arg
= priv
->res_arg
;
1233 priv
->res_arg
= g_strconcat ("man:", name
, NULL
);
1234 resolve_man_uri (uri
);
1235 if (priv
->tmptype
== YELP_URI_DOCUMENT_TYPE_MAN
) {
1236 g_free (priv
->res_arg
);
1237 priv
->res_arg
= res_arg
;
1241 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_NOT_FOUND
;
1250 resolve_xref_uri (YelpUri
*uri
)
1252 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1253 const gchar
*arg
= priv
->res_arg
+ 5;
1254 YelpUriPrivate
*base_priv
= GET_PRIV (priv
->res_base
);
1256 priv
->tmptype
= base_priv
->doctype
;
1257 priv
->gfile
= g_object_ref (base_priv
->gfile
);
1258 priv
->search_path
= g_strdupv (base_priv
->search_path
);
1259 priv
->docuri
= g_strdup (base_priv
->docuri
);
1261 if (arg
[0] == '#') {
1262 priv
->page_id
= g_strdup (base_priv
->page_id
);
1263 priv
->frag_id
= g_strdup (arg
+ 1);
1266 gchar
*hash
= strchr (arg
, '#');
1268 priv
->page_id
= g_strndup (arg
, hash
- arg
);
1269 priv
->frag_id
= g_strdup (hash
+ 1);
1272 priv
->page_id
= g_strdup (arg
);
1273 priv
->frag_id
= NULL
;
1276 if (priv
->page_id
&& priv
->page_id
[0] == '\0') {
1277 g_free (priv
->page_id
);
1278 if (g_str_has_prefix (priv
->docuri
, "help:"))
1279 priv
->page_id
= g_strdup ("index");
1281 priv
->page_id
= NULL
;
1284 if (priv
->page_id
&&
1285 g_str_has_prefix (priv
->docuri
, "info:")) {
1287 Special characters get url-encoded when they get clicked on
1288 as links. Info files, at least, don't want that so decode
1291 gchar
* tmp
= priv
->page_id
;
1292 priv
->page_id
= g_uri_unescape_string (tmp
, NULL
);
1296 if (g_str_has_prefix (priv
->docuri
, "ghelp:"))
1297 build_ghelp_fulluri (uri
);
1298 else if (g_str_has_prefix (priv
->docuri
, "help:"))
1299 priv
->fulluri
= g_strconcat (priv
->docuri
,
1300 priv
->page_id
? "/" : "",
1301 priv
->page_id
? priv
->page_id
: "",
1302 priv
->frag_id
? "#" : "",
1303 priv
->frag_id
? priv
->frag_id
: "",
1305 else if (g_str_has_prefix (priv
->docuri
, "file:") ||
1306 g_str_has_prefix (priv
->docuri
, "info:") )
1307 priv
->fulluri
= g_strconcat (priv
->docuri
,
1308 (priv
->page_id
|| priv
->frag_id
) ? "#" : "",
1309 priv
->page_id
? priv
->page_id
: "",
1310 priv
->frag_id
? "#" : "",
1314 /* FIXME: other URI schemes */
1315 priv
->fulluri
= g_strconcat (priv
->docuri
,
1316 priv
->page_id
? "#" : "",
1322 resolve_page_and_frag (YelpUri
*uri
, const gchar
*arg
)
1324 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1327 if (!arg
|| arg
[0] == '\0')
1330 hash
= strchr (arg
, '#');
1332 priv
->page_id
= g_strndup (arg
, hash
- arg
);
1333 priv
->frag_id
= g_strdup (hash
+ 1);
1335 priv
->page_id
= g_strdup (arg
);
1336 priv
->frag_id
= g_strdup (arg
);
1342 resolve_gfile (YelpUri
*uri
, const gchar
*query
, const gchar
*hash
)
1344 YelpUriPrivate
*priv
= GET_PRIV (uri
);
1346 GError
*error
= NULL
;
1348 info
= g_file_query_info (priv
->gfile
,
1349 G_FILE_ATTRIBUTE_STANDARD_TYPE
","
1350 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE
,
1351 G_FILE_QUERY_INFO_NONE
,
1354 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
)) {
1355 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_NOT_FOUND
;
1358 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_ERROR
;
1359 g_error_free (error
);
1363 if (priv
->search_path
== NULL
) {
1364 if (g_file_info_get_attribute_uint32 (info
, G_FILE_ATTRIBUTE_STANDARD_TYPE
) ==
1365 G_FILE_TYPE_DIRECTORY
) {
1366 priv
->search_path
= g_new0 (gchar
*, 2);
1367 priv
->search_path
[0] = g_file_get_path (priv
->gfile
);
1369 GFile
*parent
= g_file_get_parent (priv
->gfile
);
1370 priv
->search_path
= g_new0 (gchar
*, 2);
1371 priv
->search_path
[0] = g_file_get_path (parent
);
1372 g_object_unref (parent
);
1376 if (priv
->tmptype
== YELP_URI_DOCUMENT_TYPE_UNRESOLVED
) {
1377 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_EXTERNAL
;
1379 if (g_file_info_get_attribute_uint32 (info
, G_FILE_ATTRIBUTE_STANDARD_TYPE
) ==
1380 G_FILE_TYPE_DIRECTORY
) {
1381 GFile
*child
= g_file_get_child (priv
->gfile
, "index.page");
1382 if (g_file_query_exists (child
, NULL
)) {
1385 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MALLARD
;
1386 if (priv
->page_id
== NULL
)
1387 priv
->page_id
= g_strdup (query
);
1388 if (priv
->frag_id
== NULL
)
1389 priv
->frag_id
= g_strdup (hash
);
1391 path
= g_file_get_path (priv
->gfile
);
1392 priv
->docuri
= g_strconcat ("ghelp:", path
, NULL
);
1393 build_ghelp_fulluri (uri
);
1396 else if (yelp_settings_get_editor_mode (yelp_settings_get_default ())) {
1397 g_object_unref (child
);
1398 child
= g_file_get_child (priv
->gfile
, "index.page.stub");
1399 if (g_file_query_exists (child
, NULL
)) {
1400 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MALLARD
;
1401 if (priv
->page_id
== NULL
)
1402 priv
->page_id
= g_strdup (query
);
1403 if (priv
->frag_id
== NULL
)
1404 priv
->frag_id
= g_strdup (hash
);
1407 g_object_unref (child
);
1411 const gchar
*mime_type
= g_file_info_get_attribute_string (info
,
1412 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE
);
1413 basename
= g_file_get_basename (priv
->gfile
);
1414 if (g_str_has_suffix (basename
, ".page")) {
1418 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MALLARD
;
1420 priv
->gfile
= g_file_get_parent (old
);
1421 if (priv
->page_id
== NULL
) {
1422 /* File names aren't really page IDs, so we stick an illegal character
1423 on the beginning so it can't possibly be confused with a real page
1424 ID. Then we let YelpMallardDocument map file names to pages IDs.
1426 gchar
*tmp
= g_file_get_basename (old
);
1427 priv
->page_id
= g_strconcat (G_DIR_SEPARATOR_S
, tmp
, NULL
);
1431 if (priv
->frag_id
== NULL
)
1432 priv
->frag_id
= g_strdup (hash
);
1433 path
= g_file_get_path (priv
->gfile
);
1434 priv
->docuri
= g_strconcat ("ghelp:", path
, NULL
);
1435 build_ghelp_fulluri (uri
);
1437 g_object_unref (old
);
1439 else if (g_str_equal (mime_type
, "text/xml") ||
1440 g_str_equal (mime_type
, "application/docbook+xml") ||
1441 g_str_equal (mime_type
, "application/xml") ||
1442 g_str_has_suffix (basename
, ".docbook")) {
1445 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_DOCBOOK
;
1447 if (priv
->page_id
== NULL
)
1448 priv
->page_id
= g_strdup (query
);
1449 if (priv
->frag_id
== NULL
)
1450 priv
->frag_id
= g_strdup (hash
);
1452 path
= g_file_get_path (priv
->gfile
);
1453 priv
->docuri
= g_strconcat ("ghelp:", path
, NULL
);
1454 build_ghelp_fulluri (uri
);
1457 else if (g_str_equal (mime_type
, "text/html") ||
1458 g_str_equal (mime_type
, "application/xhtml+xml")) {
1459 GFile
*parent
= g_file_get_parent (priv
->gfile
);
1460 priv
->docuri
= g_file_get_uri (parent
);
1461 g_object_unref (parent
);
1462 priv
->tmptype
= mime_type
[0] == 't' ? YELP_URI_DOCUMENT_TYPE_HTML
: YELP_URI_DOCUMENT_TYPE_XHTML
;
1463 if (priv
->page_id
== NULL
)
1464 priv
->page_id
= g_strdup (basename
);
1465 if (priv
->frag_id
== NULL
)
1466 priv
->frag_id
= g_strdup (hash
);
1467 if (priv
->fulluri
== NULL
) {
1469 fulluri
= g_file_get_uri (priv
->gfile
);
1470 priv
->fulluri
= g_strconcat (fulluri
,
1471 priv
->frag_id
? "#" : NULL
,
1477 else if (g_str_equal (mime_type
, "application/x-gzip") ||
1478 g_str_equal (mime_type
, "application/gzip")) {
1479 if (g_str_has_suffix (basename
, ".info.gz")) {
1480 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1481 basename
[strlen (basename
) - strlen (".info.gz")] = '\0';
1482 build_info_uris (uri
, basename
, hash
);
1484 else if (is_man_path (basename
, "gz")) {
1485 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1486 basename
[strlen (basename
) - strlen ("gz") - 1] = '\0';
1487 build_man_uris (uri
, basename
, NULL
);
1490 else if (g_str_equal (mime_type
, "application/x-bzip")) {
1491 if (g_str_has_suffix (basename
, ".info.bz2")) {
1492 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1493 basename
[strlen (basename
) - strlen (".info.bz2")] = '\0';
1494 build_info_uris (uri
, basename
, hash
);
1496 else if (is_man_path (basename
, "bz2")) {
1497 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1498 basename
[strlen (basename
) - strlen ("bz2") - 1] = '\0';
1499 build_man_uris (uri
, basename
, NULL
);
1502 else if (g_str_equal (mime_type
, "application/x-lzma")) {
1503 if (g_str_has_suffix (basename
, ".info.lzma")) {
1504 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1505 basename
[strlen (basename
) - strlen (".info.lzma")] = '\0';
1506 build_info_uris (uri
, basename
, hash
);
1508 else if (is_man_path (basename
, "lzma")) {
1509 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1510 basename
[strlen (basename
) - strlen ("lzma") - 1] = '\0';
1511 build_man_uris (uri
, basename
, NULL
);
1514 else if (g_str_equal (mime_type
, "application/octet-stream")) {
1515 if (g_str_has_suffix (basename
, ".info")) {
1516 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1517 basename
[strlen (basename
) - strlen (".info")] = '\0';
1518 build_info_uris (uri
, basename
, hash
);
1520 else if (is_man_path (basename
, NULL
)) {
1521 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1522 build_man_uris (uri
, basename
, NULL
);
1525 else if (g_str_equal (mime_type
, "text/plain")) {
1526 if (g_str_has_suffix (basename
, ".info")) {
1527 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_INFO
;
1528 basename
[strlen (basename
) - strlen (".info")] = '\0';
1529 build_info_uris (uri
, basename
, hash
);
1531 else if (is_man_path (basename
, NULL
)) {
1532 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_MAN
;
1533 build_man_uris (uri
, basename
, NULL
);
1535 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_TEXT
;
1536 if (priv
->frag_id
== NULL
)
1537 priv
->frag_id
= g_strdup (hash
);
1539 else if (g_str_equal (mime_type
, "text/x-readme")) {
1540 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_TEXT
;
1543 priv
->tmptype
= YELP_URI_DOCUMENT_TYPE_EXTERNAL
;
1549 if (priv
->docuri
== NULL
)
1550 priv
->docuri
= g_file_get_uri (priv
->gfile
);
1552 if (priv
->fulluri
== NULL
)
1553 priv
->fulluri
= g_strconcat (priv
->docuri
,
1554 (priv
->page_id
|| priv
->frag_id
) ? "#" : NULL
,
1555 priv
->page_id
? priv
->page_id
: "",
1556 priv
->frag_id
? "#" : NULL
,
1557 priv
->frag_id
? priv
->frag_id
: NULL
,
1560 g_object_unref (info
);
1564 is_man_path (const gchar
*path
, const gchar
*encoding
)
1566 gchar
**iter
= (gchar
**) mancats
;
1568 if (encoding
&& *encoding
) {
1569 while (iter
&& *iter
) {
1570 gchar
*ending
= g_strdup_printf ("%s.%s", *iter
, encoding
);
1571 if (g_str_has_suffix (path
, ending
)) {
1579 while (iter
&& *iter
) {
1580 if (g_str_has_suffix (path
, *iter
)) {