Man page locations



Hot off the press! After playing with the encoding support (which was
actually broken), I thought I'd have a look at the logic for *finding*
man pages.

I noticed the obsolete (and ancient!) bug 95497 and realised that if man
is installed, it should know how to find its pages!

So I cooked up this patch, ripping out our attempts at finding the file
manually and replacing them with code to get man to do it for us. The
result is only ~20 lines shorter, but has lots of comments (and no
gotos!). Also, it allows relative file paths, which the previous version
didn't.

Anyway, here's the patch.

Rupert

From eb46af3dd8f401e5e53e9bd38f0346ec5f25b7e0 Mon Sep 17 00:00:00 2001
From: Rupert Swarbrick <rswarbrick gmail com>
Date: Sun, 12 Dec 2010 12:05:08 +0000
Subject: [PATCH] Use the installed man implementation to search for man pages.

---
 libyelp/yelp-uri.c |  220 +++++++++++++++++++++++-----------------------------
 1 files changed, 98 insertions(+), 122 deletions(-)

diff --git a/libyelp/yelp-uri.c b/libyelp/yelp-uri.c
index 02d1841..cd0595e 100644
--- a/libyelp/yelp-uri.c
+++ b/libyelp/yelp-uri.c
@@ -811,6 +811,51 @@ resolve_help_list_uri (YelpUri *uri)
     priv->tmptype = YELP_URI_DOCUMENT_TYPE_HELP_LIST;
 }
 
+/*
+  Resolve a manual file's path using 'man -w'. section may be NULL,
+  otherwise should be the section of the manual (ie should have dealt
+  with empty strings before calling this!) Returns NULL if the file
+  can't be found.
+*/
+static gchar*
+find_man_path (gchar* name, gchar* section)
+{
+    gchar* argv[] = { "man", "-w", NULL, NULL, NULL };
+    gchar *stdout = NULL;
+    gint status;
+    gchar **lines;
+    GError *error = NULL;
+
+    /* Syntax for man is "man -w <section> <name>", possibly omitting
+       section */
+    if (section) {
+        argv[2] = section;
+        argv[3] = name;
+    } else {
+        argv[2] = name;
+    }
+
+    if (!g_spawn_sync (NULL, argv, NULL,
+                       G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
+                       NULL, NULL,
+                       &stdout, NULL, &status, &error)) {
+        g_warning ("Couldn't find path for %s(%s). Error: %s",
+                   name, section, error->message);
+        g_error_free (error);
+    }
+
+    if (status == 0) {
+        lines = g_strsplit (stdout, "\n", 2);
+        g_free (stdout);
+        stdout = g_strdup (lines[0]);
+        g_strfreev (lines);
+        return stdout;
+    } else {
+        g_free (stdout);
+        return NULL;
+    }
+}
+
 static void
 resolve_man_uri (YelpUri *uri)
 {
@@ -820,145 +865,76 @@ resolve_man_uri (YelpUri *uri)
      * man:name.section
      * man:name
      */
-    static gchar **manpath = NULL;
-    const gchar * const * langs = g_get_language_names ();
-    gchar *newarg = NULL;
-    gchar *section = NULL;
-    gchar *name = NULL;
-    gchar *fullpath = NULL;
 
-    /* not to be freed */
-    gchar *realsection;
-    gchar *colon, *hash;
-    gchar *lbrace = NULL;
-    gchar *rbrace = NULL;
-    gint i, j, k;
+    /* Search via regular expressions for name, name(section) and
+     * name.section (assuming that name doesn't contain forward
+     * slashes or other nasties)
+     *
+     * If these don't match, assume that we were given a filename
+     * (absolute iff it starts with a /).
+     */
+    static GRegex* man_not_path = NULL;
+    GError *error = NULL;
+    GMatchInfo *match_info = NULL;
+    gchar *name, *section, *hash;
+    gchar *path;
+
+    if (!man_not_path) {
+        /* Match group 1 should contain the name; then one of groups 3
+         * and 4 will contain the section if there was one. Group 6
+         * will contain any hash fragment. */
+        man_not_path = g_regex_new ("man:([^ /.()]+)"
+                                    "(\\(([0-9A-Za-z]+)\\)|\\.([0-9A-Za-z]+)|)"
+                                    "(#([^/ ()]+))?",
+                                    0, 0, &error);
+        if (!man_not_path) {
+            g_error ("Error with regex in man uri: %s\n",
+                     error->message);
+        }
+    }
 
-    if (g_str_has_prefix (priv->res_arg, "man:/")) {
+    if (!g_regex_match (man_not_path, priv->res_arg,
+                        0, &match_info)) {
+        /* The regexp didn't match, so treat as a file name. */
         gchar *newuri;
         priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
         newuri = g_strdup_printf ("file:%s", priv->res_arg + 4);
         g_free (priv->res_arg);
         priv->res_arg = newuri;
         resolve_file_uri (uri);
-        return;
-    }
-
-    if (!manpath) {
-        /* Initialize manpath only once */
-        const gchar *env = g_getenv ("MANPATH");
-        if (!env || env[0] == '\0')
-            env = "/usr/share/man:/usr/man:/usr/local/share/man:/usr/local/man";
-        manpath = g_strsplit (env, ":", 0);
     }
-
-    colon = strchr (priv->res_arg, ':');
-    if (colon)
-        colon++;
-    else
-        colon = (gchar *) priv->res_arg;
-
-    hash = strchr (colon, '#');
-    if (hash)
-        newarg = g_strndup (colon, hash - colon);
-    else
-        newarg = g_strdup (colon);
-
-    lbrace = strrchr (newarg, '(');
-    if (lbrace) {
-        rbrace = strrchr (lbrace, ')');
-        if (rbrace) {
-            section = g_strndup (lbrace + 1, rbrace - lbrace - 1);
-            name = g_strndup (newarg, lbrace - newarg);
-        } else {
-            section = NULL;
-            name = strdup (newarg);
+    else {
+        /* The regexp matched, so we've got a name/section pair that
+         * needs resolving. */
+        name = g_match_info_fetch (match_info, 1);
+        section = g_match_info_fetch (match_info, 3);
+        hash = g_match_info_fetch (match_info, 6);
+        if (!name) {
+            g_error ("Error matching strings in man uri '%s'",
+                     priv->res_arg);
         }
-    } else {
-        lbrace = strrchr (newarg, '.');
-        if (lbrace) {
-            section = strdup (lbrace + 1);
-            name = g_strndup (newarg, lbrace - newarg);
-        } else {
-            section = NULL;
-            name = strdup (newarg);
+        if (!section) {
+            section = g_match_info_fetch (match_info, 4);
         }
-    }
 
-    for (i = 0; langs[i]; i++) {
-        for (j = 0; manpath[j]; j++) {
-            gchar *langdir;
-            if (g_str_equal (langs[i], "C"))
-                langdir = g_strdup (manpath[j]);
-            else
-                langdir = g_strconcat (manpath[j], "/", langs[i], NULL);
-            if (!g_file_test (langdir, G_FILE_TEST_IS_DIR)) {
-                g_free (langdir);
-                continue;
-            }
+        path = find_man_path (name, section);
 
-            for (k = 0; section ? k == 0 : mancats[k] != NULL; k++) {
-                if (section)
-                    realsection = section;
-                else
-                    realsection = (gchar *) mancats[k];
-
-                fullpath = g_strconcat (langdir, "/man", realsection,
-                                        "/", name, ".", realsection,
-                                        NULL);
-                if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
-                    goto gotit;
-                g_free (fullpath);
-
-                fullpath = g_strconcat (langdir, "/man", realsection,
-                                        "/", name, ".", realsection, ".gz",
-                                        NULL);
-                if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
-                    goto gotit;
-                g_free (fullpath);
-
-                fullpath = g_strconcat (langdir, "/man", realsection,
-                                        "/", name, ".", realsection, ".bz2",
-                                        NULL);
-                if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
-                    goto gotit;
-                g_free (fullpath);
-
-                fullpath = g_strconcat (langdir, "/man", realsection,
-                                        "/", name, ".", realsection, ".lzma",
-                                        NULL);
-                if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
-                    goto gotit;
-                g_free (fullpath);
-
-                fullpath = NULL;
-            gotit:
-                if (fullpath)
-                    break;
-            }
-            g_free (langdir);
-            if (fullpath)
-                break;
+        if (!path) {
+            priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
+            return;
         }
-        if (fullpath)
-            break;
-    }
-
-    if (fullpath) {
         priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
-        priv->gfile = g_file_new_for_path (fullpath);
-        priv->docuri = g_strconcat ("man:",  name, ".", realsection, NULL);
+        priv->gfile = g_file_new_for_path (path);
+        priv->docuri = g_strconcat ("man:",  name, ".", section, NULL);
         priv->fulluri = g_strdup (priv->docuri);
         resolve_gfile (uri, NULL);
-        g_free (fullpath);
-    } else {
-        priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
-    }
 
-    if (hash)
-        resolve_page_and_frag (uri, hash + 1);
+        if (hash)
+            resolve_page_and_frag (uri, hash + 1);
 
-    g_free (newarg);
+        g_free (path);
+        g_match_info_free (match_info);
+    }
 }
 
 /*
-- 
1.7.2.3

Attachment: pgpTWiyUaPkb3.pgp
Description: PGP signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]