#include "run-command.h"
static struct man_viewer_list {
- void (*exec)(const char *);
struct man_viewer_list *next;
+ char name[FLEX_ARRAY];
} *man_viewer_list;
+static struct man_viewer_info_list {
+ struct man_viewer_info_list *next;
+ const char *info;
+ char name[FLEX_ARRAY];
+} *man_viewer_info_list;
+
enum help_format {
HELP_FORMAT_MAN,
HELP_FORMAT_INFO,
HELP_FORMAT_WEB),
OPT_SET_INT('i', "info", &help_format, "show info page",
HELP_FORMAT_INFO),
+ OPT_END(),
};
static const char * const builtin_help_usage[] = {
die("unrecognized help format '%s'", format);
}
+static const char *get_man_viewer_info(const char *name)
+{
+ struct man_viewer_info_list *viewer;
+
+ for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
+ {
+ if (!strcasecmp(name, viewer->name))
+ return viewer->info;
+ }
+ return NULL;
+}
+
static int check_emacsclient_version(void)
{
struct strbuf buffer = STRBUF_INIT;
return 0;
}
-static void exec_woman_emacs(const char *page)
+static void exec_woman_emacs(const char* path, const char *page)
{
if (!check_emacsclient_version()) {
/* This works only with emacsclient version >= 22. */
struct strbuf man_page = STRBUF_INIT;
+
+ if (!path)
+ path = "emacsclient";
strbuf_addf(&man_page, "(woman \"%s\")", page);
- execlp("emacsclient", "emacsclient", "-e", man_page.buf, NULL);
+ execlp(path, "emacsclient", "-e", man_page.buf, NULL);
+ warning("failed to exec '%s': %s", path, strerror(errno));
}
}
-static void exec_man_konqueror(const char *page)
+static void exec_man_konqueror(const char* path, const char *page)
{
const char *display = getenv("DISPLAY");
if (display && *display) {
struct strbuf man_page = STRBUF_INIT;
+ const char *filename = "kfmclient";
+
+ /* It's simpler to launch konqueror using kfmclient. */
+ if (path) {
+ const char *file = strrchr(path, '/');
+ if (file && !strcmp(file + 1, "konqueror")) {
+ char *new = xstrdup(path);
+ char *dest = strrchr(new, '/');
+
+ /* strlen("konqueror") == strlen("kfmclient") */
+ strcpy(dest + 1, "kfmclient");
+ path = new;
+ }
+ if (file)
+ filename = file;
+ } else
+ path = "kfmclient";
strbuf_addf(&man_page, "man:%s(1)", page);
- execlp("kfmclient", "kfmclient", "newTab", man_page.buf, NULL);
+ execlp(path, filename, "newTab", man_page.buf, NULL);
+ warning("failed to exec '%s': %s", path, strerror(errno));
}
}
-static void exec_man_man(const char *page)
+static void exec_man_man(const char* path, const char *page)
{
- execlp("man", "man", page, NULL);
+ if (!path)
+ path = "man";
+ execlp(path, "man", page, NULL);
+ warning("failed to exec '%s': %s", path, strerror(errno));
}
-static void do_add_man_viewer(void (*exec)(const char *))
+static void do_add_man_viewer(const char *name)
{
struct man_viewer_list **p = &man_viewer_list;
+ size_t len = strlen(name);
while (*p)
p = &((*p)->next);
- *p = xmalloc(sizeof(**p));
- (*p)->next = NULL;
- (*p)->exec = exec;
+ *p = xcalloc(1, (sizeof(**p) + len + 1));
+ strncpy((*p)->name, name, len);
+}
+
+static int supported_man_viewer(const char *name, size_t len)
+{
+ return (!strncasecmp("man", name, len) ||
+ !strncasecmp("woman", name, len) ||
+ !strncasecmp("konqueror", name, len));
}
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);
+ if (supported_man_viewer(value, strlen(value)))
+ do_add_man_viewer(value);
else
warning("'%s': unsupported man viewer.", value);
return 0;
}
+static void do_add_man_viewer_info(const char *name,
+ size_t len,
+ const char *value)
+{
+ struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1);
+
+ strncpy(new->name, name, len);
+ new->info = xstrdup(value);
+ new->next = man_viewer_info_list;
+ man_viewer_info_list = new;
+}
+
+static int add_man_viewer_path(const char *name,
+ size_t len,
+ const char *value)
+{
+ if (supported_man_viewer(name, len))
+ do_add_man_viewer_info(name, len, value);
+ else
+ warning("'%s': path for unsupported man viewer.", name);
+
+ return 0;
+}
+
+static int add_man_viewer_info(const char *var, const char *value)
+{
+ const char *name = var + 4;
+ const char *subkey = strrchr(name, '.');
+
+ if (!subkey)
+ return error("Config with no key for man viewer: %s", name);
+
+ if (!strcmp(subkey, ".path")) {
+ if (!value)
+ return config_error_nonbool(var);
+ return add_man_viewer_path(name, subkey - name, value);
+ }
+
+ warning("'%s': unsupported man viewer sub key.", subkey);
+ return 0;
+}
+
static int git_help_config(const char *var, const char *value)
{
if (!strcmp(var, "help.format")) {
return config_error_nonbool(var);
return add_man_viewer(value);
}
+ if (!prefixcmp(var, "man."))
+ return add_man_viewer_info(var, value);
+
return git_default_config(var, value);
}
strbuf_release(&new_path);
}
+static void exec_viewer(const char *name, const char *page)
+{
+ const char *path = get_man_viewer_info(name);
+
+ if (!strcasecmp(name, "man"))
+ exec_man_man(path, page);
+ else if (!strcasecmp(name, "woman"))
+ exec_woman_emacs(path, page);
+ else if (!strcasecmp(name, "konqueror"))
+ exec_man_konqueror(path, page);
+ else
+ warning("'%s': unsupported man viewer.", name);
+}
+
static void show_man_page(const char *git_cmd)
{
struct man_viewer_list *viewer;
setup_man_path();
for (viewer = man_viewer_list; viewer; viewer = viewer->next)
{
- viewer->exec(page); /* will return when unable */
+ exec_viewer(viewer->name, page); /* will return when unable */
}
- exec_man_man(page);
+ exec_viewer("man", page);
die("no man viewer handled the request");
}