{"thread":{"id":"10483","subject":"[PATCH 4/7] list_commands(): simplify code by using chdir()","startedAt":"2007-10-27T08:36:49Z","lastAt":"2007-10-30T03:00:24Z","messageCount":25,"participants":["Scott R Parish","Junio C Hamano","Adam Roben","Scott Parish","Johannes Schindelin","David Symonds"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"57336","messageId":"1193474215-6728-1-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":null,"subject":"[PATCH 1/7] \"git\" returns 1; \"git help\" and \"git help -a\" return 0","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:49Z","receivedAt":"2007-10-27T08:36:49Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Signed-off-by: Scott R Parish <srp@srparish.net>\n---\n builtin.h |    1 +\n git.c     |    7 ++++---\n help.c    |    6 +++---\n 3 files changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin.h b/builtin.h\nindex 65cc0fb..9a6213a 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -6,6 +6,7 @@\n extern const char git_version_string[];\n extern const char git_usage_string[];\n \n+extern void list_common_cmds_help(void);\n extern void help_unknown_cmd(const char *cmd);\n extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);\n extern void prune_packed_objects(int);\ndiff --git a/git.c b/git.c\nindex 23a430c..efed91c 100644\n--- a/git.c\n+++ b/git.c\n@@ -450,9 +450,10 @@ int main(int argc, const char **argv)\n \t\tif (!prefixcmp(argv[0], \"--\"))\n \t\t\targv[0] += 2;\n \t} else {\n-\t\t/* Default command: \"help\" */\n-\t\targv[0] = \"help\";\n-\t\targc = 1;\n+\t\t/* The user didn't specify a command; give them help */\n+\t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n+\t\tlist_common_cmds_help();\n+\t\texit(1);\n \t}\n \tcmd = argv[0];\n \ndiff --git a/help.c b/help.c\nindex 1cd33ec..d4b1818 100644\n--- a/help.c\n+++ b/help.c\n@@ -147,7 +147,7 @@ static void list_commands(const char *exec_path, const char *pattern)\n \tputchar('\\n');\n }\n \n-static void list_common_cmds_help(void)\n+void list_common_cmds_help(void)\n {\n \tint i, longest = 0;\n \n@@ -204,14 +204,14 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \tif (!help_cmd) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n \t\tlist_common_cmds_help();\n-\t\texit(1);\n+\t\texit(0);\n \t}\n \n \telse if (!strcmp(help_cmd, \"--all\") || !strcmp(help_cmd, \"-a\")) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n \t\tif(exec_path)\n \t\t\tlist_commands(exec_path, \"git-*\");\n-\t\texit(1);\n+\t\texit(0);\n \t}\n \n \telse\n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57339","messageId":"1193474215-6728-2-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-1-git-send-email-srp@srparish.net","subject":"[PATCH 2/7] remove unused/unneeded \"pattern\" argument of list_commands","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:50Z","receivedAt":"2007-10-27T08:36:50Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"list_commands() currently accepts and ignores a \"pattern\" argument,\nand then hard codes a prefix as well as some magic numbers. This\nhardcodes the prefix inside of the function and removes the magic\nnumbers.\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n help.c |   14 ++++++++------\n 1 files changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex d4b1818..b636774 100644\n--- a/help.c\n+++ b/help.c\n@@ -93,10 +93,12 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \t}\n }\n \n-static void list_commands(const char *exec_path, const char *pattern)\n+static void list_commands(const char *exec_path)\n {\n \tunsigned int longest = 0;\n \tchar path[PATH_MAX];\n+\tconst char *prefix = \"git-\";\n+\tint prefix_len = strlen(prefix);\n \tint dirlen;\n \tDIR *dir = opendir(exec_path);\n \tstruct dirent *de;\n@@ -120,7 +122,7 @@ static void list_commands(const char *exec_path, const char *pattern)\n \t\tstruct stat st;\n \t\tint entlen;\n \n-\t\tif (prefixcmp(de->d_name, \"git-\"))\n+\t\tif (prefixcmp(de->d_name, prefix))\n \t\t\tcontinue;\n \t\tstrcpy(path+dirlen, de->d_name);\n \t\tif (stat(path, &st) || /* stat, not lstat */\n@@ -128,14 +130,14 @@ static void list_commands(const char *exec_path, const char *pattern)\n \t\t    !(st.st_mode & S_IXUSR))\n \t\t\tcontinue;\n \n-\t\tentlen = strlen(de->d_name);\n+\t\tentlen = strlen(de->d_name) - prefix_len;\n \t\tif (has_extension(de->d_name, \".exe\"))\n \t\t\tentlen -= 4;\n \n \t\tif (longest < entlen)\n \t\t\tlongest = entlen;\n \n-\t\tadd_cmdname(de->d_name + 4, entlen-4);\n+\t\tadd_cmdname(de->d_name + prefix_len, entlen);\n \t}\n \tclosedir(dir);\n \n@@ -143,7 +145,7 @@ static void list_commands(const char *exec_path, const char *pattern)\n \tprintf(\"----------------------------\");\n \tmput_char('-', strlen(exec_path));\n \tputchar('\\n');\n-\tpretty_print_string_list(cmdname, longest - 4);\n+\tpretty_print_string_list(cmdname, longest);\n \tputchar('\\n');\n }\n \n@@ -210,7 +212,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \telse if (!strcmp(help_cmd, \"--all\") || !strcmp(help_cmd, \"-a\")) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n \t\tif(exec_path)\n-\t\t\tlist_commands(exec_path, \"git-*\");\n+\t\t\tlist_commands(exec_path);\n \t\texit(0);\n \t}\n \n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57337","messageId":"1193474215-6728-3-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-2-git-send-email-srp@srparish.net","subject":"[PATCH 3/7] \"current_exec_path\" is a misleading name, use \"argv_exec_path\"","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:51Z","receivedAt":"2007-10-27T08:36:51Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Signed-off-by: Scott R Parish <srp@srparish.net>\n---\n exec_cmd.c |   12 ++++++------\n exec_cmd.h |    2 +-\n git.c      |    2 +-\n 3 files changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex 9b74ed2..8b681d0 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -5,11 +5,11 @@\n \n extern char **environ;\n static const char *builtin_exec_path = GIT_EXEC_PATH;\n-static const char *current_exec_path;\n+static const char *argv_exec_path = 0;\n \n-void git_set_exec_path(const char *exec_path)\n+void git_set_argv_exec_path(const char *exec_path)\n {\n-\tcurrent_exec_path = exec_path;\n+\targv_exec_path = exec_path;\n }\n \n \n@@ -18,8 +18,8 @@ const char *git_exec_path(void)\n {\n \tconst char *env;\n \n-\tif (current_exec_path)\n-\t\treturn current_exec_path;\n+\tif (argv_exec_path)\n+\t\treturn argv_exec_path;\n \n \tenv = getenv(EXEC_PATH_ENVIRONMENT);\n \tif (env && *env) {\n@@ -34,7 +34,7 @@ int execv_git_cmd(const char **argv)\n {\n \tchar git_command[PATH_MAX + 1];\n \tint i;\n-\tconst char *paths[] = { current_exec_path,\n+\tconst char *paths[] = { argv_exec_path,\n \t\t\t\tgetenv(EXEC_PATH_ENVIRONMENT),\n \t\t\t\tbuiltin_exec_path };\n \ndiff --git a/exec_cmd.h b/exec_cmd.h\nindex 849a839..da99287 100644\n--- a/exec_cmd.h\n+++ b/exec_cmd.h\n@@ -1,7 +1,7 @@\n #ifndef GIT_EXEC_CMD_H\n #define GIT_EXEC_CMD_H\n \n-extern void git_set_exec_path(const char *exec_path);\n+extern void git_set_argv_exec_path(const char *exec_path);\n extern const char* git_exec_path(void);\n extern int execv_git_cmd(const char **argv); /* NULL terminated */\n extern int execl_git_cmd(const char *cmd, ...);\ndiff --git a/git.c b/git.c\nindex efed91c..c7cabf5 100644\n--- a/git.c\n+++ b/git.c\n@@ -51,7 +51,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)\n \t\tif (!prefixcmp(cmd, \"--exec-path\")) {\n \t\t\tcmd += 11;\n \t\t\tif (*cmd == '=')\n-\t\t\t\tgit_set_exec_path(cmd + 1);\n+\t\t\t\tgit_set_argv_exec_path(cmd + 1);\n \t\t\telse {\n \t\t\t\tputs(git_exec_path());\n \t\t\t\texit(0);\n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57335","messageId":"1193474215-6728-4-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-3-git-send-email-srp@srparish.net","subject":"[PATCH 4/7] list_commands(): simplify code by using chdir()","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:52Z","receivedAt":"2007-10-27T08:36:52Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"The current code builds absolute path strings for each file to\nstat(), this can easily be avoided by chdir()ing into the directory.\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n help.c |   18 +++---------------\n 1 files changed, 3 insertions(+), 15 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex b636774..ce3d795 100644\n--- a/help.c\n+++ b/help.c\n@@ -96,36 +96,24 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n static void list_commands(const char *exec_path)\n {\n \tunsigned int longest = 0;\n-\tchar path[PATH_MAX];\n \tconst char *prefix = \"git-\";\n \tint prefix_len = strlen(prefix);\n-\tint dirlen;\n \tDIR *dir = opendir(exec_path);\n \tstruct dirent *de;\n \n-\tif (!dir) {\n+\tif (!dir || chdir(exec_path)) {\n \t\tfprintf(stderr, \"git: '%s': %s\\n\", exec_path, strerror(errno));\n \t\texit(1);\n \t}\n \n-\tdirlen = strlen(exec_path);\n-\tif (PATH_MAX - 20 < dirlen) {\n-\t\tfprintf(stderr, \"git: insanely long exec-path '%s'\\n\",\n-\t\t\texec_path);\n-\t\texit(1);\n-\t}\n-\n-\tmemcpy(path, exec_path, dirlen);\n-\tpath[dirlen++] = '/';\n-\n \twhile ((de = readdir(dir)) != NULL) {\n \t\tstruct stat st;\n \t\tint entlen;\n \n \t\tif (prefixcmp(de->d_name, prefix))\n \t\t\tcontinue;\n-\t\tstrcpy(path+dirlen, de->d_name);\n-\t\tif (stat(path, &st) || /* stat, not lstat */\n+\n+\t\tif (stat(de->d_name, &st) || /* stat, not lstat */\n \t\t    !S_ISREG(st.st_mode) ||\n \t\t    !(st.st_mode & S_IXUSR))\n \t\t\tcontinue;\n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57338","messageId":"1193474215-6728-5-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-4-git-send-email-srp@srparish.net","subject":"[PATCH 5/7] use only the $PATH for exec'ing git commands","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:53Z","receivedAt":"2007-10-27T08:36:53Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"We need to correctly set up $PATH for non-c based git commands.\nSince we already do this, we can just use that $PATH and execvp,\ninstead of looping over the paths with execve.\n\nThis patch adds a setup_path() function to exec_cmd.c, which sets\nthe $PATH order correctly for our search order. execv_git_cmd() is\nstripped down to setting up argv and calling execvp(). git.c's\nmain() only only needs to call setup_path().\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n exec_cmd.c |  121 ++++++++++++++++++++++++++----------------------------------\n exec_cmd.h |    1 +\n git.c      |   43 +++------------------\n 3 files changed, 60 insertions(+), 105 deletions(-)\n\ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex 8b681d0..c228dbf 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -29,85 +29,68 @@ const char *git_exec_path(void)\n \treturn builtin_exec_path;\n }\n \n+static void add_path(struct strbuf *out, const char *path)\n+{\n+\tif (path && strlen(path)) {\n+\t\tif (is_absolute_path(path))\n+\t\t\tstrbuf_addstr(out, path);\n+\t\telse\n+\t\t\tstrbuf_addstr(out, make_absolute_path(path));\n+\n+\t\tstrbuf_addch(out, ':');\n+\t}\n+}\n+\n+void setup_path(const char *cmd_path)\n+{\n+\tconst char *old_path = getenv(\"PATH\");\n+\tstruct strbuf new_path;\n+\n+\tstrbuf_init(&new_path, 0);\n+\n+\tadd_path(&new_path, argv_exec_path);\n+\tadd_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));\n+\tadd_path(&new_path, builtin_exec_path);\n+\tadd_path(&new_path, cmd_path);\n+\n+\tif (old_path)\n+\t\tstrbuf_addstr(&new_path, old_path);\n+\telse\n+\t\tstrbuf_addstr(&new_path, \"/usr/local/bin:/usr/bin:/bin\");\n+\n+\tsetenv(\"PATH\", new_path.buf, 1);\n+\n+\tstrbuf_release(&new_path);\n+}\n \n int execv_git_cmd(const char **argv)\n {\n-\tchar git_command[PATH_MAX + 1];\n-\tint i;\n-\tconst char *paths[] = { argv_exec_path,\n-\t\t\t\tgetenv(EXEC_PATH_ENVIRONMENT),\n-\t\t\t\tbuiltin_exec_path };\n-\n-\tfor (i = 0; i < ARRAY_SIZE(paths); ++i) {\n-\t\tsize_t len;\n-\t\tint rc;\n-\t\tconst char *exec_dir = paths[i];\n-\t\tconst char *tmp;\n-\n-\t\tif (!exec_dir || !*exec_dir) continue;\n-\n-\t\tif (*exec_dir != '/') {\n-\t\t\tif (!getcwd(git_command, sizeof(git_command))) {\n-\t\t\t\tfprintf(stderr, \"git: cannot determine \"\n-\t\t\t\t\t\"current directory: %s\\n\",\n-\t\t\t\t\tstrerror(errno));\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tlen = strlen(git_command);\n-\n-\t\t\t/* Trivial cleanup */\n-\t\t\twhile (!prefixcmp(exec_dir, \"./\")) {\n-\t\t\t\texec_dir += 2;\n-\t\t\t\twhile (*exec_dir == '/')\n-\t\t\t\t\texec_dir++;\n-\t\t\t}\n-\n-\t\t\trc = snprintf(git_command + len,\n-\t\t\t\t      sizeof(git_command) - len, \"/%s\",\n-\t\t\t\t      exec_dir);\n-\t\t\tif (rc < 0 || rc >= sizeof(git_command) - len) {\n-\t\t\t\tfprintf(stderr, \"git: command name given \"\n-\t\t\t\t\t\"is too long.\\n\");\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (strlen(exec_dir) + 1 > sizeof(git_command)) {\n-\t\t\t\tfprintf(stderr, \"git: command name given \"\n-\t\t\t\t\t\"is too long.\\n\");\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tstrcpy(git_command, exec_dir);\n-\t\t}\n-\n-\t\tlen = strlen(git_command);\n-\t\trc = snprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t      \"/git-%s\", argv[0]);\n-\t\tif (rc < 0 || rc >= sizeof(git_command) - len) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"git: command name given is too long.\\n\");\n-\t\t\tbreak;\n-\t\t}\n+\tstruct strbuf cmd;\n+\tconst char *tmp;\n \n-\t\t/* argv[0] must be the git command, but the argv array\n-\t\t * belongs to the caller, and my be reused in\n-\t\t * subsequent loop iterations. Save argv[0] and\n-\t\t * restore it on error.\n-\t\t */\n+\tstrbuf_init(&cmd, 0);\n+\tstrbuf_addf(&cmd, \"git-%s\", argv[0]);\n \n-\t\ttmp = argv[0];\n-\t\targv[0] = git_command;\n+\t/* argv[0] must be the git command, but the argv array\n+\t * belongs to the caller, and my be reused in\n+\t * subsequent loop iterations. Save argv[0] and\n+\t * restore it on error.\n+\t */\n+\ttmp = argv[0];\n+\targv[0] = cmd.buf;\n \n-\t\ttrace_argv_printf(argv, -1, \"trace: exec:\");\n+\ttrace_argv_printf(argv, -1, \"trace: exec:\");\n \n-\t\t/* execve() can only ever return if it fails */\n-\t\texecve(git_command, (char **)argv, environ);\n+\t/* execvp() can only ever return if it fails */\n+\texecvp(cmd.buf, (char **)argv);\n \n-\t\ttrace_printf(\"trace: exec failed: %s\\n\", strerror(errno));\n+\ttrace_printf(\"trace: exec failed: %s\\n\", strerror(errno));\n \n-\t\targv[0] = tmp;\n-\t}\n-\treturn -1;\n+\targv[0] = tmp;\n \n+\tstrbuf_release(&cmd);\n+\n+\treturn -1;\n }\n \n \ndiff --git a/exec_cmd.h b/exec_cmd.h\nindex da99287..a892355 100644\n--- a/exec_cmd.h\n+++ b/exec_cmd.h\n@@ -3,6 +3,7 @@\n \n extern void git_set_argv_exec_path(const char *exec_path);\n extern const char* git_exec_path(void);\n+extern void setup_path(const char *);\n extern int execv_git_cmd(const char **argv); /* NULL terminated */\n extern int execl_git_cmd(const char *cmd, ...);\n \ndiff --git a/git.c b/git.c\nindex c7cabf5..4e10581 100644\n--- a/git.c\n+++ b/git.c\n@@ -6,28 +6,6 @@\n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]\";\n \n-static void prepend_to_path(const char *dir, int len)\n-{\n-\tconst char *old_path = getenv(\"PATH\");\n-\tchar *path;\n-\tint path_len = len;\n-\n-\tif (!old_path)\n-\t\told_path = \"/usr/local/bin:/usr/bin:/bin\";\n-\n-\tpath_len = len + strlen(old_path) + 1;\n-\n-\tpath = xmalloc(path_len + 1);\n-\n-\tmemcpy(path, dir, len);\n-\tpath[len] = ':';\n-\tmemcpy(path + len + 1, old_path, path_len - len);\n-\n-\tsetenv(\"PATH\", path, 1);\n-\n-\tfree(path);\n-}\n-\n static int handle_options(const char*** argv, int* argc, int* envchanged)\n {\n \tint handled = 0;\n@@ -408,7 +386,7 @@ int main(int argc, const char **argv)\n {\n \tconst char *cmd = argv[0] ? argv[0] : \"git-help\";\n \tchar *slash = strrchr(cmd, '/');\n-\tconst char *exec_path = NULL;\n+\tconst char *cmd_path = NULL;\n \tint done_alias = 0;\n \n \t/*\n@@ -418,10 +396,7 @@ int main(int argc, const char **argv)\n \t */\n \tif (slash) {\n \t\t*slash++ = 0;\n-\t\tif (*cmd == '/')\n-\t\t\texec_path = cmd;\n-\t\telse\n-\t\t\texec_path = xstrdup(make_absolute_path(cmd));\n+\t\tcmd_path = cmd;\n \t\tcmd = slash;\n \t}\n \n@@ -458,16 +433,12 @@ int main(int argc, const char **argv)\n \tcmd = argv[0];\n \n \t/*\n-\t * We execute external git command via execv_git_cmd(),\n-\t * which looks at \"--exec-path\" option, GIT_EXEC_PATH\n-\t * environment, and $(gitexecdir) in Makefile while built,\n-\t * in this order.  For scripted commands, we prepend\n-\t * the value of the exec_path variable to the PATH.\n+\t * We use PATH to find git commands, but we prepend some higher\n+\t * precidence paths: the \"--exec-path\" option, the GIT_EXEC_PATH\n+\t * environment, and the $(gitexecdir) from the Makefile at build\n+\t * time.\n \t */\n-\tif (exec_path)\n-\t\tprepend_to_path(exec_path, strlen(exec_path));\n-\texec_path = git_exec_path();\n-\tprepend_to_path(exec_path, strlen(exec_path));\n+\tsetup_path(cmd_path);\n \n \twhile (1) {\n \t\t/* See if it's an internal command */\n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57340","messageId":"1193474215-6728-6-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-5-git-send-email-srp@srparish.net","subject":"[PATCH 6/7] walk $PATH to generate list of commands for \"help -a\"","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:54Z","receivedAt":"2007-10-27T08:36:54Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Git had previously been using the $PATH for scripts--a previous\npatch moved exec'ed commands to also use the $PATH. For consistancy\n\"help -a\" should also use the $PATH.\n\nWe walk all the paths in $PATH collecting the names of \"git-*\"\ncommands. To help distinguish between the main git commands\nand commands picked up elsewhere (probably extensions) we\nprint them seperately. The main commands are the ones that\nare found in the first directory in $PATH that contains the\n\"git\" binary.\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n help.c |  158 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------\n 1 files changed, 125 insertions(+), 33 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex ce3d795..ee4fce0 100644\n--- a/help.c\n+++ b/help.c\n@@ -37,24 +37,29 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdname {\n-\tsize_t len;\n-\tchar name[1];\n-} **cmdname;\n-static int cmdname_alloc, cmdname_cnt;\n-\n-static void add_cmdname(const char *name, int len)\n+static struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tchar *dir;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[1];\n+\t} **names;\n+} main_cmds, other_cmds;\n+\n+static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n-\tif (cmdname_alloc <= cmdname_cnt) {\n-\t\tcmdname_alloc = cmdname_alloc + 200;\n-\t\tcmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname));\n+\tif (cmds->alloc <= cmds->cnt) {\n+\t\tcmds->alloc = cmds->alloc + 200;\n+\t\tcmds->names = xrealloc(cmds->names,\n+\t\t\t\t       cmds->alloc * sizeof(*cmds->names));\n \t}\n \tent = xmalloc(sizeof(*ent) + len);\n \tent->len = len;\n \tmemcpy(ent->name, name, len);\n \tent->name[len] = 0;\n-\tcmdname[cmdname_cnt++] = ent;\n+\tcmds->names[cmds->cnt++] = ent;\n }\n \n static int cmdname_compare(const void *a_, const void *b_)\n@@ -64,7 +69,42 @@ static int cmdname_compare(const void *a_, const void *b_)\n \treturn strcmp(a->name, b->name);\n }\n \n-static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n+static void uniq(struct cmdnames *cmds)\n+{\n+\tint i, j;\n+\n+\tif (!cmds->cnt)\n+\t\treturn;\n+\n+\tfor (i = j = 1; i < cmds->cnt; i++) {\n+\t\tif (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) {\n+\t\t\tcmds->names[j++] = cmds->names[i];\n+\t\t}\n+\t}\n+\n+\tcmds->cnt = j;\n+}\n+\n+static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n+\tint ai, aj, bi;\n+\n+\tai = aj = bi = 0;\n+\twhile (ai < a->cnt && bi < b->cnt) {\n+\t\tif (0 > strcmp(a->names[ai]->name, b->names[bi]->name))\n+\t\t\ta->names[aj++] = a->names[ai++];\n+\t\telse if (0 > strcmp(a->names[ai]->name, b->names[bi]->name))\n+\t\t\tbi++;\n+\t\telse\n+\t\t\tai++, bi++;\n+\t}\n+\n+\twhile (ai < a->cnt)\n+\t\ta->names[aj++] = a->names[ai++];\n+\n+\ta->cnt = aj;\n+}\n+\n+static void pretty_print_string_list(struct cmdnames *cmds, int longest)\n {\n \tint cols = 1, rows;\n \tint space = longest + 1; /* min 1 SP between words */\n@@ -73,9 +113,7 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \n \tif (space < max_cols)\n \t\tcols = max_cols / space;\n-\trows = (cmdname_cnt + cols - 1) / cols;\n-\n-\tqsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);\n+\trows = (cmds->cnt + cols - 1) / cols;\n \n \tfor (i = 0; i < rows; i++) {\n \t\tprintf(\"  \");\n@@ -83,31 +121,39 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \t\tfor (j = 0; j < cols; j++) {\n \t\t\tint n = j * rows + i;\n \t\t\tint size = space;\n-\t\t\tif (n >= cmdname_cnt)\n+\t\t\tif (n >= cmds->cnt)\n \t\t\t\tbreak;\n-\t\t\tif (j == cols-1 || n + rows >= cmdname_cnt)\n+\t\t\tif (j == cols-1 || n + rows >= cmds->cnt)\n \t\t\t\tsize = 1;\n-\t\t\tprintf(\"%-*s\", size, cmdname[n]->name);\n+\t\t\tprintf(\"%-*s\", size, cmds->names[n]->name);\n \t\t}\n \t\tputchar('\\n');\n \t}\n }\n \n-static void list_commands(const char *exec_path)\n+static unsigned int list_commands_in_dir(const char *dir)\n {\n \tunsigned int longest = 0;\n \tconst char *prefix = \"git-\";\n \tint prefix_len = strlen(prefix);\n-\tDIR *dir = opendir(exec_path);\n+\tDIR *dirp = opendir(dir);\n+\tstruct cmdnames *cmds;\n \tstruct dirent *de;\n+\tstruct stat st;\n \n-\tif (!dir || chdir(exec_path)) {\n-\t\tfprintf(stderr, \"git: '%s': %s\\n\", exec_path, strerror(errno));\n-\t\texit(1);\n+\tif (!dirp || chdir(dir))\n+\t\treturn 0;\n+\n+\tif (!main_cmds.cnt &&\n+\t    !stat(\"git\", &st) &&\n+\t    S_ISREG(st.st_mode) && (st.st_mode & S_IXUSR)) {\n+\t\tcmds = &main_cmds;\n+\t\tcmds->dir = xstrdup(dir);\n \t}\n+\telse\n+\t\tcmds = &other_cmds;\n \n-\twhile ((de = readdir(dir)) != NULL) {\n-\t\tstruct stat st;\n+\twhile ((de = readdir(dirp)) != NULL) {\n \t\tint entlen;\n \n \t\tif (prefixcmp(de->d_name, prefix))\n@@ -122,18 +168,66 @@ static void list_commands(const char *exec_path)\n \t\tif (has_extension(de->d_name, \".exe\"))\n \t\t\tentlen -= 4;\n \n+\t\tif (has_extension(de->d_name, \".perl\") ||\n+\t\t    has_extension(de->d_name, \".sh\"))\n+\t\t\tcontinue;\n+\n \t\tif (longest < entlen)\n \t\t\tlongest = entlen;\n \n-\t\tadd_cmdname(de->d_name + prefix_len, entlen);\n+\t\tadd_cmdname(cmds, de->d_name + prefix_len, entlen);\n+\t}\n+\tclosedir(dirp);\n+\n+\treturn longest;\n+}\n+\n+static void list_commands()\n+{\n+\tunsigned int longest = 0;\n+\tunsigned int len;\n+\tconst char *env_path = getenv(\"PATH\");\n+\tchar *paths, *path, *colon;\n+\n+\tif (!env_path) {\n+\t\tfprintf(stderr, \"PATH not set\\n\");\n+\t\texit(1);\n \t}\n-\tclosedir(dir);\n \n-\tprintf(\"git commands available in '%s'\\n\", exec_path);\n+\tpath = paths = xstrdup(env_path);\n+\twhile ((char *)1 != path) {\n+\t\tif ((colon = strchr(path, ':')))\n+\t\t\t*colon = 0;\n+\n+\t\tlen = list_commands_in_dir(path);\n+\t\tlongest = MAX(longest, len);\n+\n+\t\tpath = colon + 1;\n+\t}\n+\tfree(paths);\n+\n+\tqsort(main_cmds.names, main_cmds.cnt,\n+\t      sizeof(*main_cmds.names), cmdname_compare);\n+\tuniq(&main_cmds);\n+\n+\tqsort(other_cmds.names, other_cmds.cnt,\n+\t      sizeof(*other_cmds.names), cmdname_compare);\n+\tuniq(&other_cmds);\n+\tsubtract_cmds(&other_cmds, &main_cmds);\n+\n+\tprintf(\"available git commands in '%s'\\n\", main_cmds.dir);\n \tprintf(\"----------------------------\");\n-\tmput_char('-', strlen(exec_path));\n+\tmput_char('-', strlen(main_cmds.dir));\n+\tputchar('\\n');\n+\tpretty_print_string_list(&main_cmds, longest);\n \tputchar('\\n');\n-\tpretty_print_string_list(cmdname, longest);\n+\n+\tif (!other_cmds.cnt)\n+\t\treturn;\n+\n+\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n+\tprintf(\"---------------------------------------------------\\n\");\n+\tpretty_print_string_list(&other_cmds, longest);\n \tputchar('\\n');\n }\n \n@@ -189,7 +283,6 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tconst char *help_cmd = argc > 1 ? argv[1] : NULL;\n-\tconst char *exec_path = git_exec_path();\n \n \tif (!help_cmd) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n@@ -199,8 +292,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \telse if (!strcmp(help_cmd, \"--all\") || !strcmp(help_cmd, \"-a\")) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tif(exec_path)\n-\t\t\tlist_commands(exec_path);\n+\t\tlist_commands();\n \t\texit(0);\n \t}\n \n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57341","messageId":"1193474215-6728-7-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-6-git-send-email-srp@srparish.net","subject":"[PATCH 7/7] shell should call the new setup_path() to setup $PATH","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-27T08:36:55Z","receivedAt":"2007-10-27T08:36:55Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Shell currently does its own manual thing for setting up the $PATH;\nit can now call setup_path().\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n shell.c |    8 +-------\n 1 files changed, 1 insertions(+), 7 deletions(-)\n\ndiff --git a/shell.c b/shell.c\nindex cfe372b..9826109 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -24,17 +24,11 @@ static int do_cvs_cmd(const char *me, char *arg)\n \tconst char *cvsserver_argv[3] = {\n \t\t\"cvsserver\", \"server\", NULL\n \t};\n-\tconst char *oldpath = getenv(\"PATH\");\n-\tstruct strbuf newpath = STRBUF_INIT;\n \n \tif (!arg || strcmp(arg, \"server\"))\n \t\tdie(\"git-cvsserver only handles server: %s\", arg);\n \n-\tstrbuf_addstr(&newpath, git_exec_path());\n-\tstrbuf_addch(&newpath, ':');\n-\tstrbuf_addstr(&newpath, oldpath);\n-\n-\tsetenv(\"PATH\", strbuf_detach(&newpath, NULL), 1);\n+\tsetup_path(NULL);\n \n \treturn execv_git_cmd(cvsserver_argv);\n }\n-- \ngitgui.0.8.4.11178.g9a1bf-dirty\n"},{"id":"57388","messageId":"7vsl3vzrs5.fsf@gitster.siamese.dyndns.org","threadId":"10483","inReplyTo":"1193474215-6728-6-git-send-email-srp@srparish.net","subject":"Re: [PATCH 6/7] walk $PATH to generate list of commands for \"help -a\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-28T06:18:02Z","receivedAt":"2007-10-28T06:18:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Scott R Parish <srp@srparish.net> writes:\n\n> Git had previously been using the $PATH for scripts--a previous\n> patch moved exec'ed commands to also use the $PATH. For consistancy\n> \"help -a\" should also use the $PATH.\n\ns/consistancy/consistency/\n\n> We walk all the paths in $PATH collecting the names of \"git-*\"\n> commands. To help distinguish between the main git commands\n> and commands picked up elsewhere (probably extensions) we\n> print them seperately. The main commands are the ones that\n> are found in the first directory in $PATH that contains the\n> \"git\" binary.\n\nThis is not right.  $(gitexecdir) in Makefile is designed to\nallow distros to move git-* commands out of the primary user\n$PATH directories and install only \"git\" wrapper in /usr/bin.\n\"Use the directory 'git' is in\" rule breaks this.\n\nThe \"main commands\" should be the first of argv_exec_path,\nEXEC_PATH_ENVIRONMENT or builtin_exec_path.\n\n> diff --git a/help.c b/help.c\n> index ce3d795..ee4fce0 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -64,7 +69,42 @@ static int cmdname_compare(const void *a_, const void *b_)\n> ...\n> +static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n> +\tint ai, aj, bi;\n> +\n> +\tai = aj = bi = 0;\n> +\twhile (ai < a->cnt && bi < b->cnt) {\n> +\t\tif (0 > strcmp(a->names[ai]->name, b->names[bi]->name))\n> +\t\t\ta->names[aj++] = a->names[ai++];\n> +\t\telse if (0 > strcmp(a->names[ai]->name, b->names[bi]->name))\n> +\t\t\tbi++;\n> +\t\telse\n> +\t\t\tai++, bi++;\n\nIn general, xxxcmp(a, b) is designed to return the same sign as\n\"a - b\" (subtract b from a, using an appropriate definition of\n\"subtract\" in the domain of a and b).  It is a good habit to\nwrite:\n\n\tstrcmp(a, b) < 0\tstrcmp(a, b) > 0\n\nbecause these give the same sign as\n\n\ta < b\t\t\ta > b\n\nand makes your program easier to read.\n\n> @@ -122,18 +168,66 @@ static void list_commands(const char *exec_path)\n>  \t\tif (has_extension(de->d_name, \".exe\"))\n>  \t\t\tentlen -= 4;\n>  \n> +\t\tif (has_extension(de->d_name, \".perl\") ||\n> +\t\t    has_extension(de->d_name, \".sh\"))\n> +\t\t\tcontinue;\n> +\n\nThis needs a good justification.\n\nIf you have \".\" on PATH, and you run ./git in a freshly built\nsource directory, \"git relink.perl\" would try to run\n./git-relink.perl.\n\nI do not think excluding these is necessary nor is a good idea.\n\n> +static void list_commands()\n> +{\n\nANSI.  \"static void list_commands(void)\".\n\n> +\tpath = paths = xstrdup(env_path);\n> +\twhile ((char *)1 != path) {\n> +\t\tif ((colon = strchr(path, ':')))\n> +\t\t\t*colon = 0;\n> +\n> +\t\tlen = list_commands_in_dir(path);\n> +\t\tlongest = MAX(longest, len);\n> +\n> +\t\tpath = colon + 1;\n> +\t}\n\nI know that on modern architectures bit representation of\n(char*) NULL is the same as integer 0 of the same size as a\npointer, and adding 1 to it would yield (char *)1, but the above\nfeels _dirty_.\n\n\twhile (1) {\n        \t...\n                if (!colon)\n\t                break;\n\t\tpath = colon + 1;\n\t}\n"},{"id":"57387","messageId":"7vlk9nzrrv.fsf@gitster.siamese.dyndns.org","threadId":"10483","inReplyTo":"1193474215-6728-5-git-send-email-srp@srparish.net","subject":"Re: [PATCH 5/7] use only the $PATH for exec'ing git commands","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-28T06:18:12Z","receivedAt":"2007-10-28T06:18:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Scott R Parish <srp@srparish.net> writes:\n\n> diff --git a/exec_cmd.c b/exec_cmd.c\n> index 8b681d0..c228dbf 100644\n> --- a/exec_cmd.c\n> +++ b/exec_cmd.c\n> @@ -29,85 +29,68 @@ const char *git_exec_path(void)\n>  \treturn builtin_exec_path;\n>  }\n>  \n> +static void add_path(struct strbuf *out, const char *path)\n> +{\n> +\tif (path && strlen(path)) {\n\nI wonder if s/strlen(path)/*path/ micro-optimization is worth\ndoing.  Ideally, if built-in strlen() is used, the compiler\nshould be clever enough to notice it, though...\n"},{"id":"57389","messageId":"47242A08.3050503@apple.com","threadId":"10483","inReplyTo":"7vlk9nzrrv.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 5/7] use only the $PATH for exec'ing git commands","fromName":"Adam Roben","fromEmail":"aroben@apple.com","sentAt":"2007-10-28T06:19:52Z","receivedAt":"2007-10-28T06:19:52Z","isPatch":true,"sender":{"key":"aroben@apple.com","avatar":"https://gravatar.com/avatar/9d3697e1de53890adf241331f4b970bdd2b18962b2ff0b8028ebb00e085807f8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Scott R Parish <srp@srparish.net> writes:\n>\n>   \n>> diff --git a/exec_cmd.c b/exec_cmd.c\n>> index 8b681d0..c228dbf 100644\n>> --- a/exec_cmd.c\n>> +++ b/exec_cmd.c\n>> @@ -29,85 +29,68 @@ const char *git_exec_path(void)\n>>  \treturn builtin_exec_path;\n>>  }\n>>  \n>> +static void add_path(struct strbuf *out, const char *path)\n>> +{\n>> +\tif (path && strlen(path)) {\n>>     \n>\n> I wonder if s/strlen(path)/*path/ micro-optimization is worth\n> doing.  Ideally, if built-in strlen() is used, the compiler\n> should be clever enough to notice it, though...\n>   \n\nYou could always just check path[0] instead of calling strlen.\n\n-Adam\n"},{"id":"57407","messageId":"20071028094530.GA7749@srparish.net","threadId":"10483","inReplyTo":"7vsl3vzrs5.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 6/7] walk $PATH to generate list of commands for \"help -a\"","fromName":"Scott Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-28T09:45:31Z","receivedAt":"2007-10-28T09:45:31Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"On Sat, Oct 27, 2007 at 11:18:02PM -0700, Junio C Hamano wrote:\n\n> > We walk all the paths in $PATH collecting the names of \"git-*\"\n> > commands. To help distinguish between the main git commands\n> > and commands picked up elsewhere (probably extensions) we\n> > print them seperately. The main commands are the ones that\n> > are found in the first directory in $PATH that contains the\n> > \"git\" binary.\n> \n> This is not right.  $(gitexecdir) in Makefile is designed to\n> allow distros to move git-* commands out of the primary user\n> $PATH directories and install only \"git\" wrapper in /usr/bin.\n> \"Use the directory 'git' is in\" rule breaks this.\n> \n> The \"main commands\" should be the first of argv_exec_path,\n> EXEC_PATH_ENVIRONMENT or builtin_exec_path.\n\nThis is after we've already prepended the above three paths (if\nthey're specified) to $PATH, so yes, generally they should be in\none of those directories, but more generally, it will be in one of\nthe directories in $PATH.\n\nIts not clear to me what exactly you're looking for me to change,\njust the wording i'm using in my comment? Or are you refering to\nthe approach?\n\nWhen i email the changes, should i keep emailing the whole\npatch series, or just the few patches that have changed?\n\nThanks\nsRp\n\n-- \nScott Parish\nhttp://srparish.net/\n"},{"id":"57411","messageId":"7vodejv9gt.fsf@gitster.siamese.dyndns.org","threadId":"10483","inReplyTo":"20071028094530.GA7749@srparish.net","subject":"Re: [PATCH 6/7] walk $PATH to generate list of commands for \"help -a\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-28T10:07:14Z","receivedAt":"2007-10-28T10:07:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Scott Parish <sRp@srparish.net> writes:\n\n> On Sat, Oct 27, 2007 at 11:18:02PM -0700, Junio C Hamano wrote:\n>\n>> > We walk all the paths in $PATH collecting the names of \"git-*\"\n>> > commands. To help distinguish between the main git commands\n>> > and commands picked up elsewhere (probably extensions) we\n>> > print them seperately. The main commands are the ones that\n>> > are found in the first directory in $PATH that contains the\n>> > \"git\" binary.\n>> ...\n> Its not clear to me what exactly you're looking for me to change,\n> just the wording i'm using in my comment? Or are you refering to\n> the approach?\n\n\"git\" binary will be found as /usr/bin/git while git-foo will be\nfound as /usr/libexec/git/git-foo in such an installation that\ntakes advantage of $(gitexecdir).  And /usr/libexec/git/git will\nnot exist.  Using existence of /usr/bin/git (I am referring to\nyour 'first directory on $PATH that contains the \"git\" binary'\nabove) as the cue for the location of \"main commands\" is wrong.\n\n> When i email the changes, should i keep emailing the whole\n> patch series, or just the few patches that have changed?\n\nIt's up to you.  Obviously, if you are replacing 2 patches out\nof 100-patch series, you would not want to resend the whole\nthing, though ;-)\n"},{"id":"57418","messageId":"20071028111517.GB7749@srparish.net","threadId":"10483","inReplyTo":"7vodejv9gt.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 6/7] walk $PATH to generate list of commands for \"help -a\"","fromName":"Scott Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-28T11:15:18Z","receivedAt":"2007-10-28T11:15:18Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"On Sun, Oct 28, 2007 at 03:07:14AM -0700, Junio C Hamano wrote:\n\n> Scott Parish <sRp@srparish.net> writes:\n> \n> > On Sat, Oct 27, 2007 at 11:18:02PM -0700, Junio C Hamano wrote:\n> >\n> >> > We walk all the paths in $PATH collecting the names of \"git-*\"\n> >> > commands. To help distinguish between the main git commands\n> >> > and commands picked up elsewhere (probably extensions) we\n> >> > print them seperately. The main commands are the ones that\n> >> > are found in the first directory in $PATH that contains the\n> >> > \"git\" binary.\n> >> ...\n> > Its not clear to me what exactly you're looking for me to change,\n> > just the wording i'm using in my comment? Or are you refering to\n> > the approach?\n> \n> \"git\" binary will be found as /usr/bin/git while git-foo will be\n> found as /usr/libexec/git/git-foo in such an installation that\n> takes advantage of $(gitexecdir).  And /usr/libexec/git/git will\n> not exist.  Using existence of /usr/bin/git (I am referring to\n> your 'first directory on $PATH that contains the \"git\" binary'\n> above) as the cue for the location of \"main commands\" is wrong.\n\nThanks for the clarification, that would be a problem. I've modified\nthe patch to list the main commands from git_exec_path(); i have\nmixed feelings, but curious what you think.\n\nsRp\n\n-- \nScott Parish\nhttp://srparish.net/\n"},{"id":"57419","messageId":"1193570240-11629-1-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-5-git-send-email-srp@srparish.net","subject":"[PATCH 5/7] use only the $PATH for exec'ing git commands","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-28T11:17:20Z","receivedAt":"2007-10-28T11:17:20Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"We need to correctly set up $PATH for non-c based git commands.\nSince we already do this, we can just use that $PATH and execvp,\ninstead of looping over the paths with execve.\n\nThis patch adds a setup_path() function to exec_cmd.c, which sets\nthe $PATH order correctly for our search order. execv_git_cmd() is\nstripped down to setting up argv and calling execvp(). git.c's\nmain() only only needs to call setup_path().\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n exec_cmd.c |  121 ++++++++++++++++++++++++++----------------------------------\n exec_cmd.h |    1 +\n git.c      |   43 +++------------------\n 3 files changed, 60 insertions(+), 105 deletions(-)\n\ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex 8b681d0..53d0f3c 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -29,85 +29,68 @@ const char *git_exec_path(void)\n \treturn builtin_exec_path;\n }\n \n+static void add_path(struct strbuf *out, const char *path)\n+{\n+\tif (path && *path) {\n+\t\tif (is_absolute_path(path))\n+\t\t\tstrbuf_addstr(out, path);\n+\t\telse\n+\t\t\tstrbuf_addstr(out, make_absolute_path(path));\n+\n+\t\tstrbuf_addch(out, ':');\n+\t}\n+}\n+\n+void setup_path(const char *cmd_path)\n+{\n+\tconst char *old_path = getenv(\"PATH\");\n+\tstruct strbuf new_path;\n+\n+\tstrbuf_init(&new_path, 0);\n+\n+\tadd_path(&new_path, argv_exec_path);\n+\tadd_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));\n+\tadd_path(&new_path, builtin_exec_path);\n+\tadd_path(&new_path, cmd_path);\n+\n+\tif (old_path)\n+\t\tstrbuf_addstr(&new_path, old_path);\n+\telse\n+\t\tstrbuf_addstr(&new_path, \"/usr/local/bin:/usr/bin:/bin\");\n+\n+\tsetenv(\"PATH\", new_path.buf, 1);\n+\n+\tstrbuf_release(&new_path);\n+}\n \n int execv_git_cmd(const char **argv)\n {\n-\tchar git_command[PATH_MAX + 1];\n-\tint i;\n-\tconst char *paths[] = { argv_exec_path,\n-\t\t\t\tgetenv(EXEC_PATH_ENVIRONMENT),\n-\t\t\t\tbuiltin_exec_path };\n-\n-\tfor (i = 0; i < ARRAY_SIZE(paths); ++i) {\n-\t\tsize_t len;\n-\t\tint rc;\n-\t\tconst char *exec_dir = paths[i];\n-\t\tconst char *tmp;\n-\n-\t\tif (!exec_dir || !*exec_dir) continue;\n-\n-\t\tif (*exec_dir != '/') {\n-\t\t\tif (!getcwd(git_command, sizeof(git_command))) {\n-\t\t\t\tfprintf(stderr, \"git: cannot determine \"\n-\t\t\t\t\t\"current directory: %s\\n\",\n-\t\t\t\t\tstrerror(errno));\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tlen = strlen(git_command);\n-\n-\t\t\t/* Trivial cleanup */\n-\t\t\twhile (!prefixcmp(exec_dir, \"./\")) {\n-\t\t\t\texec_dir += 2;\n-\t\t\t\twhile (*exec_dir == '/')\n-\t\t\t\t\texec_dir++;\n-\t\t\t}\n-\n-\t\t\trc = snprintf(git_command + len,\n-\t\t\t\t      sizeof(git_command) - len, \"/%s\",\n-\t\t\t\t      exec_dir);\n-\t\t\tif (rc < 0 || rc >= sizeof(git_command) - len) {\n-\t\t\t\tfprintf(stderr, \"git: command name given \"\n-\t\t\t\t\t\"is too long.\\n\");\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif (strlen(exec_dir) + 1 > sizeof(git_command)) {\n-\t\t\t\tfprintf(stderr, \"git: command name given \"\n-\t\t\t\t\t\"is too long.\\n\");\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tstrcpy(git_command, exec_dir);\n-\t\t}\n-\n-\t\tlen = strlen(git_command);\n-\t\trc = snprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t      \"/git-%s\", argv[0]);\n-\t\tif (rc < 0 || rc >= sizeof(git_command) - len) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"git: command name given is too long.\\n\");\n-\t\t\tbreak;\n-\t\t}\n+\tstruct strbuf cmd;\n+\tconst char *tmp;\n \n-\t\t/* argv[0] must be the git command, but the argv array\n-\t\t * belongs to the caller, and my be reused in\n-\t\t * subsequent loop iterations. Save argv[0] and\n-\t\t * restore it on error.\n-\t\t */\n+\tstrbuf_init(&cmd, 0);\n+\tstrbuf_addf(&cmd, \"git-%s\", argv[0]);\n \n-\t\ttmp = argv[0];\n-\t\targv[0] = git_command;\n+\t/* argv[0] must be the git command, but the argv array\n+\t * belongs to the caller, and my be reused in\n+\t * subsequent loop iterations. Save argv[0] and\n+\t * restore it on error.\n+\t */\n+\ttmp = argv[0];\n+\targv[0] = cmd.buf;\n \n-\t\ttrace_argv_printf(argv, -1, \"trace: exec:\");\n+\ttrace_argv_printf(argv, -1, \"trace: exec:\");\n \n-\t\t/* execve() can only ever return if it fails */\n-\t\texecve(git_command, (char **)argv, environ);\n+\t/* execvp() can only ever return if it fails */\n+\texecvp(cmd.buf, (char **)argv);\n \n-\t\ttrace_printf(\"trace: exec failed: %s\\n\", strerror(errno));\n+\ttrace_printf(\"trace: exec failed: %s\\n\", strerror(errno));\n \n-\t\targv[0] = tmp;\n-\t}\n-\treturn -1;\n+\targv[0] = tmp;\n \n+\tstrbuf_release(&cmd);\n+\n+\treturn -1;\n }\n \n \ndiff --git a/exec_cmd.h b/exec_cmd.h\nindex da99287..a892355 100644\n--- a/exec_cmd.h\n+++ b/exec_cmd.h\n@@ -3,6 +3,7 @@\n \n extern void git_set_argv_exec_path(const char *exec_path);\n extern const char* git_exec_path(void);\n+extern void setup_path(const char *);\n extern int execv_git_cmd(const char **argv); /* NULL terminated */\n extern int execl_git_cmd(const char *cmd, ...);\n \ndiff --git a/git.c b/git.c\nindex c7cabf5..4e10581 100644\n--- a/git.c\n+++ b/git.c\n@@ -6,28 +6,6 @@\n const char git_usage_string[] =\n \t\"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]\";\n \n-static void prepend_to_path(const char *dir, int len)\n-{\n-\tconst char *old_path = getenv(\"PATH\");\n-\tchar *path;\n-\tint path_len = len;\n-\n-\tif (!old_path)\n-\t\told_path = \"/usr/local/bin:/usr/bin:/bin\";\n-\n-\tpath_len = len + strlen(old_path) + 1;\n-\n-\tpath = xmalloc(path_len + 1);\n-\n-\tmemcpy(path, dir, len);\n-\tpath[len] = ':';\n-\tmemcpy(path + len + 1, old_path, path_len - len);\n-\n-\tsetenv(\"PATH\", path, 1);\n-\n-\tfree(path);\n-}\n-\n static int handle_options(const char*** argv, int* argc, int* envchanged)\n {\n \tint handled = 0;\n@@ -408,7 +386,7 @@ int main(int argc, const char **argv)\n {\n \tconst char *cmd = argv[0] ? argv[0] : \"git-help\";\n \tchar *slash = strrchr(cmd, '/');\n-\tconst char *exec_path = NULL;\n+\tconst char *cmd_path = NULL;\n \tint done_alias = 0;\n \n \t/*\n@@ -418,10 +396,7 @@ int main(int argc, const char **argv)\n \t */\n \tif (slash) {\n \t\t*slash++ = 0;\n-\t\tif (*cmd == '/')\n-\t\t\texec_path = cmd;\n-\t\telse\n-\t\t\texec_path = xstrdup(make_absolute_path(cmd));\n+\t\tcmd_path = cmd;\n \t\tcmd = slash;\n \t}\n \n@@ -458,16 +433,12 @@ int main(int argc, const char **argv)\n \tcmd = argv[0];\n \n \t/*\n-\t * We execute external git command via execv_git_cmd(),\n-\t * which looks at \"--exec-path\" option, GIT_EXEC_PATH\n-\t * environment, and $(gitexecdir) in Makefile while built,\n-\t * in this order.  For scripted commands, we prepend\n-\t * the value of the exec_path variable to the PATH.\n+\t * We use PATH to find git commands, but we prepend some higher\n+\t * precidence paths: the \"--exec-path\" option, the GIT_EXEC_PATH\n+\t * environment, and the $(gitexecdir) from the Makefile at build\n+\t * time.\n \t */\n-\tif (exec_path)\n-\t\tprepend_to_path(exec_path, strlen(exec_path));\n-\texec_path = git_exec_path();\n-\tprepend_to_path(exec_path, strlen(exec_path));\n+\tsetup_path(cmd_path);\n \n \twhile (1) {\n \t\t/* See if it's an internal command */\n-- \n1.5.3.4.401.g19778-dirty\n"},{"id":"57420","messageId":"1193570329-11656-1-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-6-git-send-email-srp@srparish.net","subject":"[PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-28T11:18:49Z","receivedAt":"2007-10-28T11:18:49Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Git had previously been using the $PATH for scripts--a previous\npatch moved exec'ed commands to also use the $PATH. For consistency\n\"help -a\" should also list commands in the $PATH.\n\nThe main commands are still listed from the git_exec_path(), but\nthe $PATH is walked and other git commands (probably extensions) are\nlisted.\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n help.c |  162 +++++++++++++++++++++++++++++++++++++++++++++++++---------------\n 1 files changed, 124 insertions(+), 38 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 34ac5db..2534bf0 100644\n--- a/help.c\n+++ b/help.c\n@@ -37,24 +37,28 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdname {\n-\tsize_t len;\n-\tchar name[1];\n-} **cmdname;\n-static int cmdname_alloc, cmdname_cnt;\n-\n-static void add_cmdname(const char *name, int len)\n+static struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[1];\n+\t} **names;\n+} main_cmds, other_cmds;\n+\n+static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n-\tif (cmdname_alloc <= cmdname_cnt) {\n-\t\tcmdname_alloc = cmdname_alloc + 200;\n-\t\tcmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname));\n+\tif (cmds->alloc <= cmds->cnt) {\n+\t\tcmds->alloc = cmds->alloc + 200;\n+\t\tcmds->names = xrealloc(cmds->names,\n+\t\t\t\t       cmds->alloc * sizeof(*cmds->names));\n \t}\n \tent = xmalloc(sizeof(*ent) + len);\n \tent->len = len;\n \tmemcpy(ent->name, name, len);\n \tent->name[len] = 0;\n-\tcmdname[cmdname_cnt++] = ent;\n+\tcmds->names[cmds->cnt++] = ent;\n }\n \n static int cmdname_compare(const void *a_, const void *b_)\n@@ -64,7 +68,44 @@ static int cmdname_compare(const void *a_, const void *b_)\n \treturn strcmp(a->name, b->name);\n }\n \n-static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n+static void uniq(struct cmdnames *cmds)\n+{\n+\tint i, j;\n+\n+\tif (!cmds->cnt)\n+\t\treturn;\n+\n+\tfor (i = j = 1; i < cmds->cnt; i++) {\n+\t\tif (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) {\n+\t\t\tcmds->names[j++] = cmds->names[i];\n+\t\t}\n+\t}\n+\n+\tcmds->cnt = j;\n+}\n+\n+static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n+\tint ai, aj, bi;\n+\tint cmp;\n+\n+\tai = aj = bi = 0;\n+\twhile (ai < a->cnt && bi < b->cnt) {\n+\t\tcmp = strcmp(a->names[ai]->name, b->names[bi]->name);\n+\t\tif (cmp < 0)\n+\t\t\ta->names[aj++] = a->names[ai++];\n+\t\telse if (cmp == 0)\n+\t\t\tai++, bi++;\n+\t\telse if (cmp > 0)\n+\t\t\tbi++;\n+\t}\n+\n+\twhile (ai < a->cnt)\n+\t\ta->names[aj++] = a->names[ai++];\n+\n+\ta->cnt = aj;\n+}\n+\n+static void pretty_print_string_list(struct cmdnames *cmds, int longest)\n {\n \tint cols = 1, rows;\n \tint space = longest + 1; /* min 1 SP between words */\n@@ -73,9 +114,7 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \n \tif (space < max_cols)\n \t\tcols = max_cols / space;\n-\trows = (cmdname_cnt + cols - 1) / cols;\n-\n-\tqsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);\n+\trows = (cmds->cnt + cols - 1) / cols;\n \n \tfor (i = 0; i < rows; i++) {\n \t\tprintf(\"  \");\n@@ -83,31 +122,29 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \t\tfor (j = 0; j < cols; j++) {\n \t\t\tint n = j * rows + i;\n \t\t\tint size = space;\n-\t\t\tif (n >= cmdname_cnt)\n+\t\t\tif (n >= cmds->cnt)\n \t\t\t\tbreak;\n-\t\t\tif (j == cols-1 || n + rows >= cmdname_cnt)\n+\t\t\tif (j == cols-1 || n + rows >= cmds->cnt)\n \t\t\t\tsize = 1;\n-\t\t\tprintf(\"%-*s\", size, cmdname[n]->name);\n+\t\t\tprintf(\"%-*s\", size, cmds->names[n]->name);\n \t\t}\n \t\tputchar('\\n');\n \t}\n }\n \n-static void list_commands(const char *exec_path)\n+static unsigned int list_commands_in_dir(struct cmdnames *cmds, const char *dir)\n {\n \tunsigned int longest = 0;\n \tconst char *prefix = \"git-\";\n \tint prefix_len = strlen(prefix);\n-\tDIR *dir = opendir(exec_path);\n+\tDIR *dirp = opendir(dir);\n \tstruct dirent *de;\n+\tstruct stat st;\n \n-\tif (!dir || chdir(exec_path)) {\n-\t\tfprintf(stderr, \"git: '%s': %s\\n\", exec_path, strerror(errno));\n-\t\texit(1);\n-\t}\n+\tif (!dirp || chdir(dir))\n+\t\treturn 0;\n \n-\twhile ((de = readdir(dir)) != NULL) {\n-\t\tstruct stat st;\n+\twhile ((de = readdir(dirp)) != NULL) {\n \t\tint entlen;\n \n \t\tif (prefixcmp(de->d_name, prefix))\n@@ -125,16 +162,67 @@ static void list_commands(const char *exec_path)\n \t\tif (longest < entlen)\n \t\t\tlongest = entlen;\n \n-\t\tadd_cmdname(de->d_name + prefix_len, entlen);\n+\t\tadd_cmdname(cmds, de->d_name + prefix_len, entlen);\n+\t}\n+\tclosedir(dirp);\n+\n+\treturn longest;\n+}\n+\n+static void list_commands(void)\n+{\n+\tunsigned int longest = 0;\n+\tunsigned int len;\n+\tconst char *env_path = getenv(\"PATH\");\n+\tchar *paths, *path, *colon;\n+\tconst char *exec_path = git_exec_path();\n+\n+\tif (exec_path)\n+\t\tlongest = list_commands_in_dir(&main_cmds, exec_path);\n+\n+\tif (!env_path) {\n+\t\tfprintf(stderr, \"PATH not set\\n\");\n+\t\texit(1);\n+\t}\n+\n+\tpath = paths = xstrdup(env_path);\n+\twhile (1) {\n+\t\tif ((colon = strchr(path, ':')))\n+\t\t\t*colon = 0;\n+\n+\t\tlen = list_commands_in_dir(&other_cmds, path);\n+\t\tlongest = MAX(longest, len);\n+\n+\t\tif (!colon)\n+\t\t\tbreak;\n+\t\tpath = colon + 1;\n+\t}\n+\tfree(paths);\n+\n+\tqsort(main_cmds.names, main_cmds.cnt,\n+\t      sizeof(*main_cmds.names), cmdname_compare);\n+\tuniq(&main_cmds);\n+\n+\tqsort(other_cmds.names, other_cmds.cnt,\n+\t      sizeof(*other_cmds.names), cmdname_compare);\n+\tuniq(&other_cmds);\n+\tsubtract_cmds(&other_cmds, &main_cmds);\n+\n+\tif (main_cmds.cnt) {\n+\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n+\t\tprintf(\"----------------------------\");\n+\t\tmput_char('-', strlen(exec_path));\n+\t\tputchar('\\n');\n+\t\tpretty_print_string_list(&main_cmds, longest);\n+\t\tputchar('\\n');\n+\t}\n+\n+\tif (other_cmds.cnt) {\n+\t\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n+\t\tprintf(\"---------------------------------------------------\\n\");\n+\t\tpretty_print_string_list(&other_cmds, longest);\n+\t\tputchar('\\n');\n \t}\n-\tclosedir(dir);\n-\n-\tprintf(\"git commands available in '%s'\\n\", exec_path);\n-\tprintf(\"----------------------------\");\n-\tmput_char('-', strlen(exec_path));\n-\tputchar('\\n');\n-\tpretty_print_string_list(cmdname, longest);\n-\tputchar('\\n');\n }\n \n void list_common_cmds_help(void)\n@@ -188,7 +276,6 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tconst char *help_cmd = argc > 1 ? argv[1] : NULL;\n-\tconst char *exec_path = git_exec_path();\n \n \tif (!help_cmd) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n@@ -198,8 +285,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \telse if (!strcmp(help_cmd, \"--all\") || !strcmp(help_cmd, \"-a\")) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tif(exec_path)\n-\t\t\tlist_commands(exec_path);\n+\t\tlist_commands();\n \t\texit(0);\n \t}\n \n-- \n1.5.3.4.401.g19778-dirty\n"},{"id":"57422","messageId":"7vk5p7v5j7.fsf@gitster.siamese.dyndns.org","threadId":"10483","inReplyTo":"1193570329-11656-1-git-send-email-srp@srparish.net","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-28T11:32:12Z","receivedAt":"2007-10-28T11:32:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Scott R Parish <srp@srparish.net> writes:\n\n> +\twhile (1) {\n> +\t\tif ((colon = strchr(path, ':')))\n> +\t\t\t*colon = 0;\n> +\n> +\t\tlen = list_commands_in_dir(&other_cmds, path);\n> +\t\tlongest = MAX(longest, len);\n\nWhere do we borrow this MAX() macro?\n\nOn Linux with glibc, /usr/include/sys/param.h which is included\nby git-compat-util.h (meaning, for everybody) is where we find\nit, but that somehow does not sound portable assumption.\n"},{"id":"57426","messageId":"20071028143924.GA11693@srparish.net","threadId":"10483","inReplyTo":"7vk5p7v5j7.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Scott Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-28T14:39:25Z","receivedAt":"2007-10-28T14:39:25Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"On Sun, Oct 28, 2007 at 04:32:12AM -0700, Junio C Hamano wrote:\n\n> Scott R Parish <srp@srparish.net> writes:\n> \n> > +\twhile (1) {\n> > +\t\tif ((colon = strchr(path, ':')))\n> > +\t\t\t*colon = 0;\n> > +\n> > +\t\tlen = list_commands_in_dir(&other_cmds, path);\n> > +\t\tlongest = MAX(longest, len);\n> \n> Where do we borrow this MAX() macro?\n> \n> On Linux with glibc, /usr/include/sys/param.h which is included\n> by git-compat-util.h (meaning, for everybody) is where we find\n> it, but that somehow does not sound portable assumption.\n\nAwesome catch\n\nsRp\n\n-- \nScott Parish\nhttp://srparish.net/\n"},{"id":"57427","messageId":"1193582654-12100-1-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-6-git-send-email-srp@srparish.net","subject":"[PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-28T14:44:14Z","receivedAt":"2007-10-28T14:44:14Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Git had previously been using the $PATH for scripts--a previous\npatch moved exec'ed commands to also use the $PATH. For consistency\n\"help -a\" should also list commands in the $PATH.\n\nThe main commands are still listed from the git_exec_path(), but\nthe $PATH is walked and other git commands (probably extensions) are\nlisted.\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n help.c |  163 +++++++++++++++++++++++++++++++++++++++++++++++++---------------\n 1 files changed, 125 insertions(+), 38 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 34ac5db..07cf67a 100644\n--- a/help.c\n+++ b/help.c\n@@ -37,24 +37,28 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdname {\n-\tsize_t len;\n-\tchar name[1];\n-} **cmdname;\n-static int cmdname_alloc, cmdname_cnt;\n-\n-static void add_cmdname(const char *name, int len)\n+static struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[1];\n+\t} **names;\n+} main_cmds, other_cmds;\n+\n+static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n \tstruct cmdname *ent;\n-\tif (cmdname_alloc <= cmdname_cnt) {\n-\t\tcmdname_alloc = cmdname_alloc + 200;\n-\t\tcmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname));\n+\tif (cmds->alloc <= cmds->cnt) {\n+\t\tcmds->alloc = cmds->alloc + 200;\n+\t\tcmds->names = xrealloc(cmds->names,\n+\t\t\t\t       cmds->alloc * sizeof(*cmds->names));\n \t}\n \tent = xmalloc(sizeof(*ent) + len);\n \tent->len = len;\n \tmemcpy(ent->name, name, len);\n \tent->name[len] = 0;\n-\tcmdname[cmdname_cnt++] = ent;\n+\tcmds->names[cmds->cnt++] = ent;\n }\n \n static int cmdname_compare(const void *a_, const void *b_)\n@@ -64,7 +68,44 @@ static int cmdname_compare(const void *a_, const void *b_)\n \treturn strcmp(a->name, b->name);\n }\n \n-static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n+static void uniq(struct cmdnames *cmds)\n+{\n+\tint i, j;\n+\n+\tif (!cmds->cnt)\n+\t\treturn;\n+\n+\tfor (i = j = 1; i < cmds->cnt; i++) {\n+\t\tif (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) {\n+\t\t\tcmds->names[j++] = cmds->names[i];\n+\t\t}\n+\t}\n+\n+\tcmds->cnt = j;\n+}\n+\n+static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n+\tint ai, aj, bi;\n+\tint cmp;\n+\n+\tai = aj = bi = 0;\n+\twhile (ai < a->cnt && bi < b->cnt) {\n+\t\tcmp = strcmp(a->names[ai]->name, b->names[bi]->name);\n+\t\tif (cmp < 0)\n+\t\t\ta->names[aj++] = a->names[ai++];\n+\t\telse if (cmp == 0)\n+\t\t\tai++, bi++;\n+\t\telse if (cmp > 0)\n+\t\t\tbi++;\n+\t}\n+\n+\twhile (ai < a->cnt)\n+\t\ta->names[aj++] = a->names[ai++];\n+\n+\ta->cnt = aj;\n+}\n+\n+static void pretty_print_string_list(struct cmdnames *cmds, int longest)\n {\n \tint cols = 1, rows;\n \tint space = longest + 1; /* min 1 SP between words */\n@@ -73,9 +114,7 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \n \tif (space < max_cols)\n \t\tcols = max_cols / space;\n-\trows = (cmdname_cnt + cols - 1) / cols;\n-\n-\tqsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);\n+\trows = (cmds->cnt + cols - 1) / cols;\n \n \tfor (i = 0; i < rows; i++) {\n \t\tprintf(\"  \");\n@@ -83,31 +122,29 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \t\tfor (j = 0; j < cols; j++) {\n \t\t\tint n = j * rows + i;\n \t\t\tint size = space;\n-\t\t\tif (n >= cmdname_cnt)\n+\t\t\tif (n >= cmds->cnt)\n \t\t\t\tbreak;\n-\t\t\tif (j == cols-1 || n + rows >= cmdname_cnt)\n+\t\t\tif (j == cols-1 || n + rows >= cmds->cnt)\n \t\t\t\tsize = 1;\n-\t\t\tprintf(\"%-*s\", size, cmdname[n]->name);\n+\t\t\tprintf(\"%-*s\", size, cmds->names[n]->name);\n \t\t}\n \t\tputchar('\\n');\n \t}\n }\n \n-static void list_commands(const char *exec_path)\n+static unsigned int list_commands_in_dir(struct cmdnames *cmds, const char *dir)\n {\n \tunsigned int longest = 0;\n \tconst char *prefix = \"git-\";\n \tint prefix_len = strlen(prefix);\n-\tDIR *dir = opendir(exec_path);\n+\tDIR *dirp = opendir(dir);\n \tstruct dirent *de;\n+\tstruct stat st;\n \n-\tif (!dir || chdir(exec_path)) {\n-\t\tfprintf(stderr, \"git: '%s': %s\\n\", exec_path, strerror(errno));\n-\t\texit(1);\n-\t}\n+\tif (!dirp || chdir(dir))\n+\t\treturn 0;\n \n-\twhile ((de = readdir(dir)) != NULL) {\n-\t\tstruct stat st;\n+\twhile ((de = readdir(dirp)) != NULL) {\n \t\tint entlen;\n \n \t\tif (prefixcmp(de->d_name, prefix))\n@@ -125,16 +162,68 @@ static void list_commands(const char *exec_path)\n \t\tif (longest < entlen)\n \t\t\tlongest = entlen;\n \n-\t\tadd_cmdname(de->d_name + prefix_len, entlen);\n+\t\tadd_cmdname(cmds, de->d_name + prefix_len, entlen);\n+\t}\n+\tclosedir(dirp);\n+\n+\treturn longest;\n+}\n+\n+static void list_commands(void)\n+{\n+\tunsigned int longest = 0;\n+\tunsigned int len;\n+\tconst char *env_path = getenv(\"PATH\");\n+\tchar *paths, *path, *colon;\n+\tconst char *exec_path = git_exec_path();\n+\n+\tif (exec_path)\n+\t\tlongest = list_commands_in_dir(&main_cmds, exec_path);\n+\n+\tif (!env_path) {\n+\t\tfprintf(stderr, \"PATH not set\\n\");\n+\t\texit(1);\n+\t}\n+\n+\tpath = paths = xstrdup(env_path);\n+\twhile (1) {\n+\t\tif ((colon = strchr(path, ':')))\n+\t\t\t*colon = 0;\n+\n+\t\tlen = list_commands_in_dir(&other_cmds, path);\n+\t\tif (len > longest)\n+\t\t\tlongest = len;\n+\n+\t\tif (!colon)\n+\t\t\tbreak;\n+\t\tpath = colon + 1;\n+\t}\n+\tfree(paths);\n+\n+\tqsort(main_cmds.names, main_cmds.cnt,\n+\t      sizeof(*main_cmds.names), cmdname_compare);\n+\tuniq(&main_cmds);\n+\n+\tqsort(other_cmds.names, other_cmds.cnt,\n+\t      sizeof(*other_cmds.names), cmdname_compare);\n+\tuniq(&other_cmds);\n+\tsubtract_cmds(&other_cmds, &main_cmds);\n+\n+\tif (main_cmds.cnt) {\n+\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n+\t\tprintf(\"----------------------------\");\n+\t\tmput_char('-', strlen(exec_path));\n+\t\tputchar('\\n');\n+\t\tpretty_print_string_list(&main_cmds, longest);\n+\t\tputchar('\\n');\n+\t}\n+\n+\tif (other_cmds.cnt) {\n+\t\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n+\t\tprintf(\"---------------------------------------------------\\n\");\n+\t\tpretty_print_string_list(&other_cmds, longest);\n+\t\tputchar('\\n');\n \t}\n-\tclosedir(dir);\n-\n-\tprintf(\"git commands available in '%s'\\n\", exec_path);\n-\tprintf(\"----------------------------\");\n-\tmput_char('-', strlen(exec_path));\n-\tputchar('\\n');\n-\tpretty_print_string_list(cmdname, longest);\n-\tputchar('\\n');\n }\n \n void list_common_cmds_help(void)\n@@ -188,7 +277,6 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tconst char *help_cmd = argc > 1 ? argv[1] : NULL;\n-\tconst char *exec_path = git_exec_path();\n \n \tif (!help_cmd) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n@@ -198,8 +286,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \telse if (!strcmp(help_cmd, \"--all\") || !strcmp(help_cmd, \"-a\")) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tif(exec_path)\n-\t\t\tlist_commands(exec_path);\n+\t\tlist_commands();\n \t\texit(0);\n \t}\n \n-- \n1.5.3.4.401.g19778-dirty\n"},{"id":"57437","messageId":"Pine.LNX.4.64.0710281642220.4362@racer.site","threadId":"10483","inReplyTo":"1193582654-12100-1-git-send-email-srp@srparish.net","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-28T16:51:00Z","receivedAt":"2007-10-28T16:51:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 28 Oct 2007, Scott R Parish wrote:\n\n> diff --git a/help.c b/help.c\n> index 34ac5db..07cf67a 100644\n> --- a/help.c\n> +++ b/help.c\n> @@ -37,24 +37,28 @@ static inline void mput_char(char c, unsigned int num)\n>  \t\tputchar(c);\n>  }\n>  \n> -static struct cmdname {\n> -\tsize_t len;\n> -\tchar name[1];\n> -} **cmdname;\n> -static int cmdname_alloc, cmdname_cnt;\n> -\n> -static void add_cmdname(const char *name, int len)\n> +static struct cmdnames {\n> +\tint alloc;\n> +\tint cnt;\n> +\tstruct cmdname {\n> +\t\tsize_t len;\n> +\t\tchar name[1];\n> +\t} **names;\n> +} main_cmds, other_cmds;\n> +\n> +static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n>  {\n>  \tstruct cmdname *ent;\n> -\tif (cmdname_alloc <= cmdname_cnt) {\n> -\t\tcmdname_alloc = cmdname_alloc + 200;\n> -\t\tcmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname));\n> +\tif (cmds->alloc <= cmds->cnt) {\n> +\t\tcmds->alloc = cmds->alloc + 200;\n> +\t\tcmds->names = xrealloc(cmds->names,\n> +\t\t\t\t       cmds->alloc * sizeof(*cmds->names));\n\nLooks like a candidate for ALLOC_GROW() ...\n\n> @@ -64,7 +68,44 @@ static int cmdname_compare(const void *a_, const void *b_)\n>  \treturn strcmp(a->name, b->name);\n>  }\n>  \n> -static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n> +static void uniq(struct cmdnames *cmds)\n> +{\n> +\tint i, j;\n> +\n> +\tif (!cmds->cnt)\n> +\t\treturn;\n> +\n> +\tfor (i = j = 1; i < cmds->cnt; i++) {\n> +\t\tif (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) {\n> +\t\t\tcmds->names[j++] = cmds->names[i];\n> +\t\t}\n> +\t}\n\nLosing the curly brackets would make this look much nicer.\n\n> +\n> +\tcmds->cnt = j;\n> +}\n> +\n> +static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n\nMaybe \"exclude_cmds()\", and choose more suggestive names for the \nparameters?\n\n> -\tDIR *dir = opendir(exec_path);\n> +\tDIR *dirp = opendir(dir);\n\nI am not sure that a rename from \"dir\" to \"dirp\" is needed here.  It \ndistracts a little from the real content of your patch.\n\nThanks,\nDscho\n"},{"id":"57458","messageId":"20071029024431.GA12459@srparish.net","threadId":"10483","inReplyTo":"Pine.LNX.4.64.0710281642220.4362@racer.site","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Scott Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-29T02:44:32Z","receivedAt":"2007-10-29T02:44:32Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"On Sun, Oct 28, 2007 at 04:51:00PM +0000, Johannes Schindelin wrote:\n\n> > +static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n> \n> Maybe \"exclude_cmds()\", and choose more suggestive names for the \n> parameters?\n\nI was thinking set operations when i named this (hense \"a\" and \"b\"),\nbut i'll try this out.\n\nsRp\n\n-- \nScott Parish\nhttp://srparish.net/\n"},{"id":"57460","messageId":"1193628652-15647-1-git-send-email-srp@srparish.net","threadId":"10483","inReplyTo":"1193474215-6728-6-git-send-email-srp@srparish.net","subject":"[PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Scott R Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-29T03:30:52Z","receivedAt":"2007-10-29T03:30:52Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"Git had previously been using the $PATH for scripts--a previous\npatch moved exec'ed commands to also use the $PATH. For consistency\n\"help -a\" should also list commands in the $PATH.\n\nThe main commands are still listed from the git_exec_path(), but\nthe $PATH is walked and other git commands (probably extensions) are\nlisted.\n\nSigned-off-by: Scott R Parish <srp@srparish.net>\n---\n help.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++---------------\n 1 files changed, 120 insertions(+), 37 deletions(-)\n\ndiff --git a/help.c b/help.c\nindex 34ac5db..855aeef 100644\n--- a/help.c\n+++ b/help.c\n@@ -37,24 +37,25 @@ static inline void mput_char(char c, unsigned int num)\n \t\tputchar(c);\n }\n \n-static struct cmdname {\n-\tsize_t len;\n-\tchar name[1];\n-} **cmdname;\n-static int cmdname_alloc, cmdname_cnt;\n-\n-static void add_cmdname(const char *name, int len)\n+static struct cmdnames {\n+\tint alloc;\n+\tint cnt;\n+\tstruct cmdname {\n+\t\tsize_t len;\n+\t\tchar name[1];\n+\t} **names;\n+} main_cmds, other_cmds;\n+\n+static void add_cmdname(struct cmdnames *cmds, const char *name, int len)\n {\n-\tstruct cmdname *ent;\n-\tif (cmdname_alloc <= cmdname_cnt) {\n-\t\tcmdname_alloc = cmdname_alloc + 200;\n-\t\tcmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname));\n-\t}\n-\tent = xmalloc(sizeof(*ent) + len);\n+\tstruct cmdname *ent = xmalloc(sizeof(*ent) + len);\n+\n \tent->len = len;\n \tmemcpy(ent->name, name, len);\n \tent->name[len] = 0;\n-\tcmdname[cmdname_cnt++] = ent;\n+\n+\tALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);\n+\tcmds->names[cmds->cnt++] = ent;\n }\n \n static int cmdname_compare(const void *a_, const void *b_)\n@@ -64,7 +65,42 @@ static int cmdname_compare(const void *a_, const void *b_)\n \treturn strcmp(a->name, b->name);\n }\n \n-static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n+static void uniq(struct cmdnames *cmds)\n+{\n+\tint i, j;\n+\n+\tif (!cmds->cnt)\n+\t\treturn;\n+\n+\tfor (i = j = 1; i < cmds->cnt; i++)\n+\t\tif (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))\n+\t\t\tcmds->names[j++] = cmds->names[i];\n+\n+\tcmds->cnt = j;\n+}\n+\n+static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) {\n+\tint ci, cj, ei;\n+\tint cmp;\n+\n+\tci = cj = ei = 0;\n+\twhile (ci < cmds->cnt && ei < excludes->cnt) {\n+\t\tcmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);\n+\t\tif (cmp < 0)\n+\t\t\tcmds->names[cj++] = cmds->names[ci++];\n+\t\telse if (cmp == 0)\n+\t\t\tci++, ei++;\n+\t\telse if (cmp > 0)\n+\t\t\tei++;\n+\t}\n+\n+\twhile (ci < cmds->cnt)\n+\t\tcmds->names[cj++] = cmds->names[ci++];\n+\n+\tcmds->cnt = cj;\n+}\n+\n+static void pretty_print_string_list(struct cmdnames *cmds, int longest)\n {\n \tint cols = 1, rows;\n \tint space = longest + 1; /* min 1 SP between words */\n@@ -73,9 +109,7 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \n \tif (space < max_cols)\n \t\tcols = max_cols / space;\n-\trows = (cmdname_cnt + cols - 1) / cols;\n-\n-\tqsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);\n+\trows = (cmds->cnt + cols - 1) / cols;\n \n \tfor (i = 0; i < rows; i++) {\n \t\tprintf(\"  \");\n@@ -83,28 +117,27 @@ static void pretty_print_string_list(struct cmdname **cmdname, int longest)\n \t\tfor (j = 0; j < cols; j++) {\n \t\t\tint n = j * rows + i;\n \t\t\tint size = space;\n-\t\t\tif (n >= cmdname_cnt)\n+\t\t\tif (n >= cmds->cnt)\n \t\t\t\tbreak;\n-\t\t\tif (j == cols-1 || n + rows >= cmdname_cnt)\n+\t\t\tif (j == cols-1 || n + rows >= cmds->cnt)\n \t\t\t\tsize = 1;\n-\t\t\tprintf(\"%-*s\", size, cmdname[n]->name);\n+\t\t\tprintf(\"%-*s\", size, cmds->names[n]->name);\n \t\t}\n \t\tputchar('\\n');\n \t}\n }\n \n-static void list_commands(const char *exec_path)\n+static unsigned int list_commands_in_dir(struct cmdnames *cmds,\n+\t\t\t\t\t const char *path)\n {\n \tunsigned int longest = 0;\n \tconst char *prefix = \"git-\";\n \tint prefix_len = strlen(prefix);\n-\tDIR *dir = opendir(exec_path);\n+\tDIR *dir = opendir(path);\n \tstruct dirent *de;\n \n-\tif (!dir || chdir(exec_path)) {\n-\t\tfprintf(stderr, \"git: '%s': %s\\n\", exec_path, strerror(errno));\n-\t\texit(1);\n-\t}\n+\tif (!dir || chdir(path))\n+\t\treturn 0;\n \n \twhile ((de = readdir(dir)) != NULL) {\n \t\tstruct stat st;\n@@ -125,16 +158,68 @@ static void list_commands(const char *exec_path)\n \t\tif (longest < entlen)\n \t\t\tlongest = entlen;\n \n-\t\tadd_cmdname(de->d_name + prefix_len, entlen);\n+\t\tadd_cmdname(cmds, de->d_name + prefix_len, entlen);\n \t}\n \tclosedir(dir);\n \n-\tprintf(\"git commands available in '%s'\\n\", exec_path);\n-\tprintf(\"----------------------------\");\n-\tmput_char('-', strlen(exec_path));\n-\tputchar('\\n');\n-\tpretty_print_string_list(cmdname, longest);\n-\tputchar('\\n');\n+\treturn longest;\n+}\n+\n+static void list_commands(void)\n+{\n+\tunsigned int longest = 0;\n+\tunsigned int len;\n+\tconst char *env_path = getenv(\"PATH\");\n+\tchar *paths, *path, *colon;\n+\tconst char *exec_path = git_exec_path();\n+\n+\tif (exec_path)\n+\t\tlongest = list_commands_in_dir(&main_cmds, exec_path);\n+\n+\tif (!env_path) {\n+\t\tfprintf(stderr, \"PATH not set\\n\");\n+\t\texit(1);\n+\t}\n+\n+\tpath = paths = xstrdup(env_path);\n+\twhile (1) {\n+\t\tif ((colon = strchr(path, ':')))\n+\t\t\t*colon = 0;\n+\n+\t\tlen = list_commands_in_dir(&other_cmds, path);\n+\t\tif (len > longest)\n+\t\t\tlongest = len;\n+\n+\t\tif (!colon)\n+\t\t\tbreak;\n+\t\tpath = colon + 1;\n+\t}\n+\tfree(paths);\n+\n+\tqsort(main_cmds.names, main_cmds.cnt,\n+\t      sizeof(*main_cmds.names), cmdname_compare);\n+\tuniq(&main_cmds);\n+\n+\tqsort(other_cmds.names, other_cmds.cnt,\n+\t      sizeof(*other_cmds.names), cmdname_compare);\n+\tuniq(&other_cmds);\n+\texclude_cmds(&other_cmds, &main_cmds);\n+\n+\tif (main_cmds.cnt) {\n+\t\tprintf(\"available git commands in '%s'\\n\", exec_path);\n+\t\tprintf(\"----------------------------\");\n+\t\tmput_char('-', strlen(exec_path));\n+\t\tputchar('\\n');\n+\t\tpretty_print_string_list(&main_cmds, longest);\n+\t\tputchar('\\n');\n+\t}\n+\n+\tif (other_cmds.cnt) {\n+\t\tprintf(\"git commands available from elsewhere on your $PATH\\n\");\n+\t\tprintf(\"---------------------------------------------------\\n\");\n+\t\tpretty_print_string_list(&other_cmds, longest);\n+\t\tputchar('\\n');\n+\t}\n }\n \n void list_common_cmds_help(void)\n@@ -188,7 +273,6 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n int cmd_help(int argc, const char **argv, const char *prefix)\n {\n \tconst char *help_cmd = argc > 1 ? argv[1] : NULL;\n-\tconst char *exec_path = git_exec_path();\n \n \tif (!help_cmd) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n@@ -198,8 +282,7 @@ int cmd_help(int argc, const char **argv, const char *prefix)\n \n \telse if (!strcmp(help_cmd, \"--all\") || !strcmp(help_cmd, \"-a\")) {\n \t\tprintf(\"usage: %s\\n\\n\", git_usage_string);\n-\t\tif(exec_path)\n-\t\t\tlist_commands(exec_path);\n+\t\tlist_commands();\n \t\texit(0);\n \t}\n \n-- \n1.5.3.4.401.g19778-dirty\n"},{"id":"57477","messageId":"Pine.LNX.4.64.0710291129250.4362@racer.site","threadId":"10483","inReplyTo":"20071029024431.GA12459@srparish.net","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-29T11:30:29Z","receivedAt":"2007-10-29T11:30:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 28 Oct 2007, Scott Parish wrote:\n\n> On Sun, Oct 28, 2007 at 04:51:00PM +0000, Johannes Schindelin wrote:\n> \n> > > +static void subtract_cmds(struct cmdnames *a, struct cmdnames *b) {\n> > \n> > Maybe \"exclude_cmds()\", and choose more suggestive names for the \n> > parameters?\n> \n> I was thinking set operations when i named this (hense \"a\" and \"b\"),\n> but i'll try this out.\n\nYes, I guessed that.  But in that case, \"subtract\" is actively wrong, \nsince you cannot guarantee (and indeed do not want to assume) that one is \nthe subset of the other.\n\nCiao,\nDscho\n"},{"id":"57478","messageId":"ee77f5c20710290445y553fc9fo90c6e4df9b2aa1a7@mail.gmail.com","threadId":"10483","inReplyTo":"Pine.LNX.4.64.0710291129250.4362@racer.site","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"David Symonds","fromEmail":"dsymonds@gmail.com","sentAt":"2007-10-29T11:45:31Z","receivedAt":"2007-10-29T11:45:31Z","isPatch":true,"sender":{"key":"dsymonds@gmail.com","avatar":"https://gravatar.com/avatar/b22f5051cbfc11836e36cf7a690e6cde4e225d835e13295ff98d15c7a9ee3c0f?d=mp&s=160"},"body":"On 10/29/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Hi,\n>\n> On Sun, 28 Oct 2007, Scott Parish wrote:\n>\n> > I was thinking set operations when i named this (hense \"a\" and \"b\"),\n> > but i'll try this out.\n>\n> Yes, I guessed that.  But in that case, \"subtract\" is actively wrong,\n> since you cannot guarantee (and indeed do not want to assume) that one is\n> the subset of the other.\n\nThe nearest set theory operation would be \"difference\" (or\n\"complement\"); that does not require that the subtrahend is a subset\nof the minuend.\n\n\nDave.\n"},{"id":"57490","messageId":"7vir4ptyc9.fsf@gitster.siamese.dyndns.org","threadId":"10483","inReplyTo":"1193628652-15647-1-git-send-email-srp@srparish.net","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-29T21:17:26Z","receivedAt":"2007-10-29T21:17:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Scott R Parish <srp@srparish.net> writes:\n\n> Git had previously been using the $PATH for scripts--a previous\n> patch moved exec'ed commands to also use the $PATH. For consistency\n> \"help -a\" should also list commands in the $PATH.\n>\n> The main commands are still listed from the git_exec_path(), but\n> the $PATH is walked and other git commands (probably extensions) are\n> listed.\n>\n> Signed-off-by: Scott R Parish <srp@srparish.net>\n> ---\n>  help.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++---------------\n>  1 files changed, 120 insertions(+), 37 deletions(-)\n\nThanks.\n\nIt's easier to read if you briefly describe the differences\nbetween the replacement patch and the previous version of the\npatch below the three-dash lines.  See for example Lars Knoll's\npatch from today <200710290959.32538.lars@trolltech.com>.\n"},{"id":"57515","messageId":"20071030030022.GA2906@srparish.net","threadId":"10483","inReplyTo":"7vir4ptyc9.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 6/7] include $PATH in generating list of commands for \"help -a\"","fromName":"Scott Parish","fromEmail":"srp@srparish.net","sentAt":"2007-10-30T03:00:24Z","receivedAt":"2007-10-30T03:00:24Z","isPatch":true,"sender":{"key":"srp@srparish.net","avatar":"https://gravatar.com/avatar/870e5b6fc4f710cf4db5684bd9af7f2cee5734b3dab3209b13e00cf64f6c9f0e?d=mp&s=160"},"body":"On Mon, Oct 29, 2007 at 02:17:26PM -0700, Junio C Hamano wrote:\n\n> It's easier to read if you briefly describe the differences\n> between the replacement patch and the previous version of the\n> patch below the three-dash lines.  See for example Lars Knoll's\n> patch from today <200710290959.32538.lars@trolltech.com>.\n\nOh, that's useful information!\n\nFor the above patch, were basically what Johannes Schindelin suggested:\n\n + add_cmdname() now uses ALLOC_GROW and has its lines reordered to be\n   somewhat cleanre\n + uniq() has lost the curly brackets\n + s/subtract_cmds/exclude_cmds/\n + exclude_cmds() uses an arg name of \"path\" instead of \"dir\"\n + exclude_cmd() no longer renames \"dir\" to \"dirp\"\n + exclude_cmds() an earlier patch moved the \"struct stat\" declaration\n   for no-longer relevant reasons. change removed.\n\nsRp\n\n-- \nScott Parish\nhttp://srparish.net/\n"}]}