};
static const char * const builtin_help_usage[] = {
- "git-help [--all] [--man|--web|--info] [command]",
+ "git help [--all] [--man|--web|--info] [command]",
NULL
};
warning("failed to exec '%s': %s", path, strerror(errno));
}
-static void do_add_man_viewer(const char *name)
+static void exec_man_cmd(const char *cmd, const char *page)
+{
+ struct strbuf shell_cmd = STRBUF_INIT;
+ strbuf_addf(&shell_cmd, "%s %s", cmd, page);
+ execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
+ warning("failed to exec '%s': %s", cmd, strerror(errno));
+}
+
+static void add_man_viewer(const char *name)
{
struct man_viewer_list **p = &man_viewer_list;
size_t len = strlen(name);
!strncasecmp("konqueror", name, len));
}
-static int add_man_viewer(const char *value)
-{
- 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)
if (supported_man_viewer(name, len))
do_add_man_viewer_info(name, len, value);
else
- warning("'%s': path for unsupported man viewer.", name);
+ warning("'%s': path for unsupported man viewer.\n"
+ "Please consider using 'man.<tool>.cmd' instead.",
+ name);
+
+ return 0;
+}
+
+static int add_man_viewer_cmd(const char *name,
+ size_t len,
+ const char *value)
+{
+ if (supported_man_viewer(name, len))
+ warning("'%s': cmd for supported man viewer.\n"
+ "Please consider using 'man.<tool>.path' instead.",
+ name);
+ else
+ do_add_man_viewer_info(name, len, value);
return 0;
}
return config_error_nonbool(var);
return add_man_viewer_path(name, subkey - name, value);
}
+ if (!strcmp(subkey, ".cmd")) {
+ if (!value)
+ return config_error_nonbool(var);
+ return add_man_viewer_cmd(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)
+static int git_help_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "help.format")) {
if (!value)
if (!strcmp(var, "man.viewer")) {
if (!value)
return config_error_nonbool(var);
- return add_man_viewer(value);
+ add_man_viewer(value);
+ return 0;
}
if (!prefixcmp(var, "man."))
return add_man_viewer_info(var, value);
- return git_default_config(var, value);
+ return git_default_config(var, value, cb);
}
/* most GUI terminals set COLUMNS (although some don't export it) */
}
}
+static int is_executable(const char *name)
+{
+ struct stat st;
+
+ if (stat(name, &st) || /* stat, not lstat */
+ !S_ISREG(st.st_mode))
+ return 0;
+
+#ifdef __MINGW32__
+ /* cannot trust the executable bit, peek into the file instead */
+ char buf[3] = { 0 };
+ int n;
+ int fd = open(name, O_RDONLY);
+ st.st_mode &= ~S_IXUSR;
+ if (fd >= 0) {
+ n = read(fd, buf, 2);
+ if (n == 2)
+ /* DOS executables start with "MZ" */
+ if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
+ st.st_mode |= S_IXUSR;
+ close(fd);
+ }
+#endif
+ return st.st_mode & S_IXUSR;
+}
+
static unsigned int list_commands_in_dir(struct cmdnames *cmds,
const char *path)
{
int prefix_len = strlen(prefix);
DIR *dir = opendir(path);
struct dirent *de;
+ struct strbuf buf = STRBUF_INIT;
+ int len;
- if (!dir || chdir(path))
+ if (!dir)
return 0;
+ strbuf_addf(&buf, "%s/", path);
+ len = buf.len;
+
while ((de = readdir(dir)) != NULL) {
- struct stat st;
int entlen;
if (prefixcmp(de->d_name, prefix))
continue;
- if (stat(de->d_name, &st) || /* stat, not lstat */
- !S_ISREG(st.st_mode) ||
- !(st.st_mode & S_IXUSR))
+ strbuf_setlen(&buf, len);
+ strbuf_addstr(&buf, de->d_name);
+ if (!is_executable(buf.buf))
continue;
entlen = strlen(de->d_name) - prefix_len;
add_cmdname(cmds, de->d_name + prefix_len, entlen);
}
closedir(dir);
+ strbuf_release(&buf);
return longest;
}
path = paths = xstrdup(env_path);
while (1) {
- if ((colon = strchr(path, ':')))
+ if ((colon = strchr(path, PATH_SEP)))
*colon = 0;
len = list_commands_in_dir(&other_cmds, path);
{
load_command_list();
return is_in_cmdlist(&main_cmds, s) ||
- is_in_cmdlist(&other_cmds, s);
+ is_in_cmdlist(&other_cmds, s) ||
+ !strcmp(s, "help");
+}
+
+static const char *prepend(const char *prefix, const char *cmd)
+{
+ size_t pre_len = strlen(prefix);
+ size_t cmd_len = strlen(cmd);
+ char *p = xmalloc(pre_len + cmd_len + 1);
+ memcpy(p, prefix, pre_len);
+ strcpy(p + pre_len, cmd);
+ return p;
}
static const char *cmd_to_page(const char *git_cmd)
return "git";
else if (!prefixcmp(git_cmd, "git"))
return git_cmd;
- else {
- int page_len = strlen(git_cmd) + 4;
- char *p = xmalloc(page_len + 1);
- strcpy(p, "git-");
- strcpy(p + 4, git_cmd);
- p[page_len] = 0;
- return p;
- }
+ else if (is_git_command(git_cmd))
+ return prepend("git-", git_cmd);
+ else
+ return prepend("git", git_cmd);
}
static void setup_man_path(void)
static void exec_viewer(const char *name, const char *page)
{
- const char *path = get_man_viewer_info(name);
+ const char *info = get_man_viewer_info(name);
if (!strcasecmp(name, "man"))
- exec_man_man(path, page);
+ exec_man_man(info, page);
else if (!strcasecmp(name, "woman"))
- exec_woman_emacs(path, page);
+ exec_woman_emacs(info, page);
else if (!strcasecmp(name, "konqueror"))
- exec_man_konqueror(path, page);
+ exec_man_konqueror(info, page);
+ else if (info)
+ exec_man_cmd(info, page);
else
- warning("'%s': unsupported man viewer.", name);
+ warning("'%s': unknown man viewer.", name);
}
static void show_man_page(const char *git_cmd)
static void get_html_page_path(struct strbuf *page_path, const char *page)
{
struct stat st;
+ const char *html_path = system_path(GIT_HTML_PATH);
/* Check that we have a git documentation directory. */
- if (stat(GIT_HTML_PATH "/git.html", &st) || !S_ISREG(st.st_mode))
- die("'%s': not a documentation directory.", GIT_HTML_PATH);
+ if (stat(mkpath("%s/git.html", html_path), &st)
+ || !S_ISREG(st.st_mode))
+ die("'%s': not a documentation directory.", html_path);
strbuf_init(page_path, 0);
- strbuf_addf(page_path, GIT_HTML_PATH "/%s.html", page);
+ strbuf_addf(page_path, "%s/%s.html", html_path, page);
+}
+
+/*
+ * If open_html is not defined in a platform-specific way (see for
+ * example compat/mingw.h), we use the script web--browse to display
+ * HTML.
+ */
+#ifndef open_html
+void open_html(const char *path)
+{
+ execl_git_cmd("web--browse", "-c", "help.browser", path, NULL);
}
+#endif
static void show_html_page(const char *git_cmd)
{
get_html_page_path(&page_path, page);
- execl_git_cmd("web--browse", "-c", "help.browser", page_path.buf, NULL);
+ open_html(page_path.buf);
}
void help_unknown_cmd(const char *cmd)
const char *alias;
setup_git_directory_gently(&nongit);
- git_config(git_help_config);
+ git_config(git_help_config, NULL);
argc = parse_options(argc, argv, builtin_help_options,
builtin_help_usage, 0);
if (show_all) {
printf("usage: %s\n\n", git_usage_string);
list_commands();
+ printf("%s\n", git_more_info_string);
return 0;
}
if (!argv[0]) {
printf("usage: %s\n\n", git_usage_string);
list_common_cmds_help();
+ printf("\n%s\n", git_more_info_string);
return 0;
}