help: implement multi-valued "man.viewer" config option
authorChristian Couder <chriscool@tuxfamily.org>
Tue, 11 Mar 2008 07:51:12 +0000 (08:51 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 12 Mar 2008 06:02:01 +0000 (23:02 -0700)
This allows multiple viewer candidates to be listed in the configuration
file, like this:

        [man]
                viewer = woman
                viewer = konqueror
                viewer = man

The candidates are tried in the order listed in the configuration file,
and the first suitable one (e.g. konqueror cannot be used outside windowed
environment) is used.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Tested-by: Xavier Maillard <xma@gnu.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
help.c

diff --git a/help.c b/help.c
index 2cb152d2e10cad363c639a8e65f37cbd6fc42d64..5da8c9c415fa9bbd93470ddb27e748079be4ef79 100644 (file)
--- a/help.c
+++ b/help.c
 #include "parse-options.h"
 #include "run-command.h"
 
-static const char *man_viewer;
+static struct man_viewer_list {
+       void (*exec)(const char *);
+       struct man_viewer_list *next;
+} *man_viewer_list;
 
 enum help_format {
        HELP_FORMAT_MAN,
@@ -45,6 +48,102 @@ static enum help_format parse_help_format(const char *format)
        die("unrecognized help format '%s'", format);
 }
 
+static int check_emacsclient_version(void)
+{
+       struct strbuf buffer = STRBUF_INIT;
+       struct child_process ec_process;
+       const char *argv_ec[] = { "emacsclient", "--version", NULL };
+       int version;
+
+       /* emacsclient prints its version number on stderr */
+       memset(&ec_process, 0, sizeof(ec_process));
+       ec_process.argv = argv_ec;
+       ec_process.err = -1;
+       ec_process.stdout_to_stderr = 1;
+       if (start_command(&ec_process)) {
+               fprintf(stderr, "Failed to start emacsclient.\n");
+               return -1;
+       }
+       strbuf_read(&buffer, ec_process.err, 20);
+       close(ec_process.err);
+
+       /*
+        * Don't bother checking return value, because "emacsclient --version"
+        * seems to always exits with code 1.
+        */
+       finish_command(&ec_process);
+
+       if (prefixcmp(buffer.buf, "emacsclient")) {
+               fprintf(stderr, "Failed to parse emacsclient version.\n");
+               strbuf_release(&buffer);
+               return -1;
+       }
+
+       strbuf_remove(&buffer, 0, strlen("emacsclient"));
+       version = atoi(buffer.buf);
+
+       if (version < 22) {
+               fprintf(stderr,
+                       "emacsclient version '%d' too old (< 22).\n",
+                       version);
+               strbuf_release(&buffer);
+               return -1;
+       }
+
+       strbuf_release(&buffer);
+       return 0;
+}
+
+static void exec_woman_emacs(const char *page)
+{
+       if (!check_emacsclient_version()) {
+               /* This works only with emacsclient version >= 22. */
+               struct strbuf man_page = STRBUF_INIT;
+               strbuf_addf(&man_page, "(woman \"%s\")", page);
+               execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
+       }
+}
+
+static void exec_man_konqueror(const char *page)
+{
+       const char *display = getenv("DISPLAY");
+       if (display && *display) {
+               struct strbuf man_page = STRBUF_INIT;
+               strbuf_addf(&man_page, "man:%s(1)", page);
+               execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
+       }
+}
+
+static void exec_man_man(const char *page)
+{
+       execlp("man", "man", page, NULL);
+}
+
+static void do_add_man_viewer(void (*exec)(const char *))
+{
+       struct man_viewer_list **p = &man_viewer_list;
+
+       while (*p)
+               p = &((*p)->next);
+       *p = xmalloc(sizeof(**p));
+       (*p)->next = NULL;
+       (*p)->exec = exec;
+}
+
+static int add_man_viewer(const char *value)
+{
+       if (!strcasecmp(value, "man"))
+               do_add_man_viewer(exec_man_man);
+       else if (!strcasecmp(value, "woman"))
+               do_add_man_viewer(exec_woman_emacs);
+       else if (!strcasecmp(value, "konqueror"))
+               do_add_man_viewer(exec_man_konqueror);
+       else
+               return error("'%s': unsupported man viewer.", value);
+
+       return 0;
+}
+
 static int git_help_config(const char *var, const char *value)
 {
        if (!strcmp(var, "help.format")) {
@@ -53,8 +152,11 @@ static int git_help_config(const char *var, const char *value)
                help_format = parse_help_format(value);
                return 0;
        }
-       if (!strcmp(var, "man.viewer"))
-               return git_config_string(&man_viewer, var, value);
+       if (!strcmp(var, "man.viewer")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               return add_man_viewer(value);
+       }
        return git_default_config(var, value);
 }
 
@@ -350,85 +452,18 @@ static void setup_man_path(void)
        strbuf_release(&new_path);
 }
 
-static int check_emacsclient_version(void)
-{
-       struct strbuf buffer = STRBUF_INIT;
-       struct child_process ec_process;
-       const char *argv_ec[] = { "emacsclient", "--version", NULL };
-       int version;
-
-       /* emacsclient prints its version number on stderr */
-       memset(&ec_process, 0, sizeof(ec_process));
-       ec_process.argv = argv_ec;
-       ec_process.err = -1;
-       ec_process.stdout_to_stderr = 1;
-       if (start_command(&ec_process)) {
-               fprintf(stderr, "Failed to start emacsclient.\n");
-               return -1;
-       }
-       strbuf_read(&buffer, ec_process.err, 20);
-       close(ec_process.err);
-
-       /*
-        * Don't bother checking return value, because "emacsclient --version"
-        * seems to always exits with code 1.
-        */
-       finish_command(&ec_process);
-
-       if (prefixcmp(buffer.buf, "emacsclient")) {
-               fprintf(stderr, "Failed to parse emacsclient version.\n");
-               strbuf_release(&buffer);
-               return -1;
-       }
-
-       strbuf_remove(&buffer, 0, strlen("emacsclient"));
-       version = atoi(buffer.buf);
-
-       if (version < 22) {
-               fprintf(stderr,
-                       "emacsclient version '%d' too old (< 22).\n",
-                       version);
-               strbuf_release(&buffer);
-               return -1;
-       }
-
-       strbuf_release(&buffer);
-       return 0;
-}
-
-static void exec_woman_emacs(const char *page)
-{
-       if (!check_emacsclient_version()) {
-               /* This works only with emacsclient version >= 22. */
-               struct strbuf man_page = STRBUF_INIT;
-               strbuf_addf(&man_page, "(woman \"%s\")", page);
-               execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
-       } else
-               execlp("man", "man", page, NULL);
-}
-
-static void exec_man_konqueror(const char *page)
-{
-       const char *display = getenv("DISPLAY");
-       if (display && *display) {
-               struct strbuf man_page = STRBUF_INIT;
-               strbuf_addf(&man_page, "man:%s(1)", page);
-               execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
-       } else
-               execlp("man", "man", page, NULL);
-}
-
 static void show_man_page(const char *git_cmd)
 {
+       struct man_viewer_list *viewer;
        const char *page = cmd_to_page(git_cmd);
+
        setup_man_path();
-       if (!man_viewer || !strcmp(man_viewer, "man"))
-               execlp("man", "man", page, NULL);
-       if (!strcmp(man_viewer, "woman"))
-               exec_woman_emacs(page);
-       if (!strcmp(man_viewer, "konqueror"))
-               exec_man_konqueror(page);
-       die("'%s': unsupported man viewer.", man_viewer);
+       for (viewer = man_viewer_list; viewer; viewer = viewer->next)
+       {
+               viewer->exec(page); /* will return when unable */
+       }
+       exec_man_man(page);
+       die("no man viewer handled the request");
 }
 
 static void show_info_page(const char *git_cmd)