From 1eb056905a2956ca9fabd2edcce05c0a29ce64b1 Mon Sep 17 00:00:00 2001 From: Scott R Parish Date: Sun, 28 Oct 2007 20:30:52 -0700 Subject: [PATCH] include $PATH in generating list of commands for "help -a" Git had previously been using the $PATH for scripts--a previous patch moved exec'ed commands to also use the $PATH. For consistency "help -a" should also list commands in the $PATH. The main commands are still listed from the git_exec_path(), but the $PATH is walked and other git commands (probably extensions) are listed. Signed-off-by: Scott R Parish Signed-off-by: Junio C Hamano --- help.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 120 insertions(+), 37 deletions(-) diff --git a/help.c b/help.c index 34ac5db60..855aeef92 100644 --- a/help.c +++ b/help.c @@ -37,24 +37,25 @@ static inline void mput_char(char c, unsigned int num) putchar(c); } -static struct cmdname { - size_t len; - char name[1]; -} **cmdname; -static int cmdname_alloc, cmdname_cnt; - -static void add_cmdname(const char *name, int len) +static struct cmdnames { + int alloc; + int cnt; + struct cmdname { + size_t len; + char name[1]; + } **names; +} main_cmds, other_cmds; + +static void add_cmdname(struct cmdnames *cmds, const char *name, int len) { - struct cmdname *ent; - if (cmdname_alloc <= cmdname_cnt) { - cmdname_alloc = cmdname_alloc + 200; - cmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname)); - } - ent = xmalloc(sizeof(*ent) + len); + struct cmdname *ent = xmalloc(sizeof(*ent) + len); + ent->len = len; memcpy(ent->name, name, len); ent->name[len] = 0; - cmdname[cmdname_cnt++] = ent; + + ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc); + cmds->names[cmds->cnt++] = ent; } static int cmdname_compare(const void *a_, const void *b_) @@ -64,7 +65,42 @@ static int cmdname_compare(const void *a_, const void *b_) return strcmp(a->name, b->name); } -static void pretty_print_string_list(struct cmdname **cmdname, int longest) +static void uniq(struct cmdnames *cmds) +{ + int i, j; + + if (!cmds->cnt) + return; + + for (i = j = 1; i < cmds->cnt; i++) + if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) + cmds->names[j++] = cmds->names[i]; + + cmds->cnt = j; +} + +static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) { + int ci, cj, ei; + int cmp; + + ci = cj = ei = 0; + while (ci < cmds->cnt && ei < excludes->cnt) { + cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name); + if (cmp < 0) + cmds->names[cj++] = cmds->names[ci++]; + else if (cmp == 0) + ci++, ei++; + else if (cmp > 0) + ei++; + } + + while (ci < cmds->cnt) + cmds->names[cj++] = cmds->names[ci++]; + + cmds->cnt = cj; +} + +static void pretty_print_string_list(struct cmdnames *cmds, int longest) { int cols = 1, rows; int space = longest + 1; /* min 1 SP between words */ @@ -73,9 +109,7 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest) if (space < max_cols) cols = max_cols / space; - rows = (cmdname_cnt + cols - 1) / cols; - - qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare); + rows = (cmds->cnt + cols - 1) / cols; for (i = 0; i < rows; i++) { printf(" "); @@ -83,28 +117,27 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest) for (j = 0; j < cols; j++) { int n = j * rows + i; int size = space; - if (n >= cmdname_cnt) + if (n >= cmds->cnt) break; - if (j == cols-1 || n + rows >= cmdname_cnt) + if (j == cols-1 || n + rows >= cmds->cnt) size = 1; - printf("%-*s", size, cmdname[n]->name); + printf("%-*s", size, cmds->names[n]->name); } putchar('\n'); } } -static void list_commands(const char *exec_path) +static unsigned int list_commands_in_dir(struct cmdnames *cmds, + const char *path) { unsigned int longest = 0; const char *prefix = "git-"; int prefix_len = strlen(prefix); - DIR *dir = opendir(exec_path); + DIR *dir = opendir(path); struct dirent *de; - if (!dir || chdir(exec_path)) { - fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno)); - exit(1); - } + if (!dir || chdir(path)) + return 0; while ((de = readdir(dir)) != NULL) { struct stat st; @@ -125,16 +158,68 @@ static void list_commands(const char *exec_path) if (longest < entlen) longest = entlen; - add_cmdname(de->d_name + prefix_len, entlen); + add_cmdname(cmds, de->d_name + prefix_len, entlen); } closedir(dir); - printf("git commands available in '%s'\n", exec_path); - printf("----------------------------"); - mput_char('-', strlen(exec_path)); - putchar('\n'); - pretty_print_string_list(cmdname, longest); - putchar('\n'); + return longest; +} + +static void list_commands(void) +{ + unsigned int longest = 0; + unsigned int len; + const char *env_path = getenv("PATH"); + char *paths, *path, *colon; + const char *exec_path = git_exec_path(); + + if (exec_path) + longest = list_commands_in_dir(&main_cmds, exec_path); + + if (!env_path) { + fprintf(stderr, "PATH not set\n"); + exit(1); + } + + path = paths = xstrdup(env_path); + while (1) { + if ((colon = strchr(path, ':'))) + *colon = 0; + + len = list_commands_in_dir(&other_cmds, path); + if (len > longest) + longest = len; + + if (!colon) + break; + path = colon + 1; + } + free(paths); + + qsort(main_cmds.names, main_cmds.cnt, + sizeof(*main_cmds.names), cmdname_compare); + uniq(&main_cmds); + + qsort(other_cmds.names, other_cmds.cnt, + sizeof(*other_cmds.names), cmdname_compare); + uniq(&other_cmds); + exclude_cmds(&other_cmds, &main_cmds); + + if (main_cmds.cnt) { + printf("available git commands in '%s'\n", exec_path); + printf("----------------------------"); + mput_char('-', strlen(exec_path)); + putchar('\n'); + pretty_print_string_list(&main_cmds, longest); + putchar('\n'); + } + + if (other_cmds.cnt) { + printf("git commands available from elsewhere on your $PATH\n"); + printf("---------------------------------------------------\n"); + pretty_print_string_list(&other_cmds, longest); + putchar('\n'); + } } void list_common_cmds_help(void) @@ -188,7 +273,6 @@ int cmd_version(int argc, const char **argv, const char *prefix) int cmd_help(int argc, const char **argv, const char *prefix) { const char *help_cmd = argc > 1 ? argv[1] : NULL; - const char *exec_path = git_exec_path(); if (!help_cmd) { printf("usage: %s\n\n", git_usage_string); @@ -198,8 +282,7 @@ int cmd_help(int argc, const char **argv, const char *prefix) else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) { printf("usage: %s\n\n", git_usage_string); - if(exec_path) - list_commands(exec_path); + list_commands(); exit(0); } -- 2.11.0