summaryrefslogtreecommitdiff
path: root/help.c
diff options
context:
space:
mode:
Diffstat (limited to 'help.c')
-rw-r--r--help.c106
1 files changed, 71 insertions, 35 deletions
diff --git a/help.c b/help.c
index df7d16d7ce..bc6cd19cf3 100644
--- a/help.c
+++ b/help.c
@@ -11,11 +11,9 @@
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
{
- struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1);
-
+ struct cmdname *ent;
+ FLEX_ALLOC_MEM(ent, name, name, len);
ent->len = len;
- memcpy(ent->name, name, len);
- ent->name[len] = 0;
ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
cmds->names[cmds->cnt++] = ent;
@@ -78,8 +76,7 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
cmds->cnt = cj;
}
-static void pretty_print_string_list(struct cmdnames *cmds,
- unsigned int colopts)
+static void pretty_print_cmdnames(struct cmdnames *cmds, unsigned int colopts)
{
struct string_list list = STRING_LIST_INIT_NODUP;
struct column_options copts;
@@ -108,7 +105,22 @@ static int is_executable(const char *name)
return 0;
#if defined(GIT_WINDOWS_NATIVE)
-{ /* cannot trust the executable bit, peek into the file instead */
+ /*
+ * On Windows there is no executable bit. The file extension
+ * indicates whether it can be run as an executable, and Git
+ * has special-handling to detect scripts and launch them
+ * through the indicated script interpreter. We test for the
+ * file extension first because virus scanners may make
+ * it quite expensive to open many files.
+ */
+ if (ends_with(name, ".exe"))
+ return S_IXUSR;
+
+{
+ /*
+ * Now that we know it does not have an executable extension,
+ * peek into the file instead.
+ */
char buf[3] = { 0 };
int n;
int fd = open(name, O_RDONLY);
@@ -116,8 +128,8 @@ static int is_executable(const char *name)
if (fd >= 0) {
n = read(fd, buf, 2);
if (n == 2)
- /* DOS executables start with "MZ" */
- if (!strcmp(buf, "#!") || !strcmp(buf, "MZ"))
+ /* look for a she-bang */
+ if (!strcmp(buf, "#!"))
st.st_mode |= S_IXUSR;
close(fd);
}
@@ -130,7 +142,6 @@ static void list_commands_in_dir(struct cmdnames *cmds,
const char *path,
const char *prefix)
{
- int prefix_len;
DIR *dir = opendir(path);
struct dirent *de;
struct strbuf buf = STRBUF_INIT;
@@ -140,15 +151,15 @@ static void list_commands_in_dir(struct cmdnames *cmds,
return;
if (!prefix)
prefix = "git-";
- prefix_len = strlen(prefix);
strbuf_addf(&buf, "%s/", path);
len = buf.len;
while ((de = readdir(dir)) != NULL) {
- int entlen;
+ const char *ent;
+ size_t entlen;
- if (!starts_with(de->d_name, prefix))
+ if (!skip_prefix(de->d_name, prefix, &ent))
continue;
strbuf_setlen(&buf, len);
@@ -156,11 +167,10 @@ static void list_commands_in_dir(struct cmdnames *cmds,
if (!is_executable(buf.buf))
continue;
- entlen = strlen(de->d_name) - prefix_len;
- if (has_extension(de->d_name, ".exe"))
- entlen -= 4;
+ entlen = strlen(ent);
+ strip_suffix(ent, ".exe", &entlen);
- add_cmdname(cmds, de->d_name + prefix_len, entlen);
+ add_cmdname(cmds, ent, entlen);
}
closedir(dir);
strbuf_release(&buf);
@@ -175,8 +185,7 @@ void load_command_list(const char *prefix,
if (exec_path) {
list_commands_in_dir(main_cmds, exec_path, prefix);
- qsort(main_cmds->names, main_cmds->cnt,
- sizeof(*main_cmds->names), cmdname_compare);
+ QSORT(main_cmds->names, main_cmds->cnt, cmdname_compare);
uniq(main_cmds);
}
@@ -195,8 +204,7 @@ void load_command_list(const char *prefix,
}
free(paths);
- qsort(other_cmds->names, other_cmds->cnt,
- sizeof(*other_cmds->names), cmdname_compare);
+ QSORT(other_cmds->names, other_cmds->cnt, cmdname_compare);
uniq(other_cmds);
}
exclude_cmds(other_cmds, main_cmds);
@@ -209,29 +217,50 @@ void list_commands(unsigned int colopts,
const char *exec_path = git_exec_path();
printf_ln(_("available git commands in '%s'"), exec_path);
putchar('\n');
- pretty_print_string_list(main_cmds, colopts);
+ pretty_print_cmdnames(main_cmds, colopts);
putchar('\n');
}
if (other_cmds->cnt) {
printf_ln(_("git commands available from elsewhere on your $PATH"));
putchar('\n');
- pretty_print_string_list(other_cmds, colopts);
+ pretty_print_cmdnames(other_cmds, colopts);
putchar('\n');
}
}
+static int cmd_group_cmp(const void *elem1, const void *elem2)
+{
+ const struct cmdname_help *e1 = elem1;
+ const struct cmdname_help *e2 = elem2;
+
+ if (e1->group < e2->group)
+ return -1;
+ if (e1->group > e2->group)
+ return 1;
+ return strcmp(e1->name, e2->name);
+}
+
void list_common_cmds_help(void)
{
int i, longest = 0;
+ int current_grp = -1;
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
if (longest < strlen(common_cmds[i].name))
longest = strlen(common_cmds[i].name);
}
- puts(_("The most commonly used git commands are:"));
+ QSORT(common_cmds, ARRAY_SIZE(common_cmds), cmd_group_cmp);
+
+ puts(_("These are common Git commands used in various situations:"));
+
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+ if (common_cmds[i].group != current_grp) {
+ printf("\n%s\n", _(common_cmd_groups[common_cmds[i].group]));
+ current_grp = common_cmds[i].group;
+ }
+
printf(" %s ", common_cmds[i].name);
mput_char(' ', longest - strlen(common_cmds[i].name));
puts(_(common_cmds[i].help));
@@ -252,11 +281,13 @@ static struct cmdnames aliases;
static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
{
+ const char *p;
+
if (!strcmp(var, "help.autocorrect"))
autocorrect = git_config_int(var,value);
/* Also use aliases for command lookup */
- if (starts_with(var, "alias."))
- add_cmdname(&aliases, var + 6, strlen(var + 6));
+ if (skip_prefix(var, "alias.", &p))
+ add_cmdname(&aliases, p, strlen(p));
return git_default_config(var, value, cb);
}
@@ -305,8 +336,7 @@ const char *help_unknown_cmd(const char *cmd)
add_cmd_list(&main_cmds, &aliases);
add_cmd_list(&main_cmds, &other_cmds);
- qsort(main_cmds.names, main_cmds.cnt,
- sizeof(main_cmds.names), cmdname_compare);
+ QSORT(main_cmds.names, main_cmds.cnt, cmdname_compare);
uniq(&main_cmds);
/* This abuses cmdname->len for levenshtein distance */
@@ -340,8 +370,7 @@ const char *help_unknown_cmd(const char *cmd)
levenshtein(cmd, candidate, 0, 2, 1, 3) + 1;
}
- qsort(main_cmds.names, main_cmds.cnt,
- sizeof(*main_cmds.names), levenshtein_compare);
+ QSORT(main_cmds.names, main_cmds.cnt, levenshtein_compare);
if (!main_cmds.cnt)
die(_("Uh oh. Your system reports no Git commands at all."));
@@ -373,7 +402,7 @@ const char *help_unknown_cmd(const char *cmd)
if (autocorrect > 0) {
fprintf_ln(stderr, _("in %0.1f seconds automatically..."),
(float)autocorrect/10.0);
- poll(NULL, 0, autocorrect * 100);
+ sleep_millisec(autocorrect * 100);
}
return assumed;
}
@@ -400,6 +429,12 @@ int cmd_version(int argc, const char **argv, const char *prefix)
* with external projects that rely on the output of "git version".
*/
printf("git version %s\n", git_version_string);
+ while (*++argv) {
+ if (!strcmp(*argv, "--build-options")) {
+ printf("sizeof-long: %d\n", (int)sizeof(long));
+ /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
+ }
+ }
return 0;
}
@@ -408,16 +443,17 @@ struct similar_ref_cb {
struct string_list *similar_refs;
};
-static int append_similar_ref(const char *refname, const unsigned char *sha1,
+static int append_similar_ref(const char *refname, const struct object_id *oid,
int flags, void *cb_data)
{
struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
char *branch = strrchr(refname, '/') + 1;
+ const char *remote;
+
/* A remote branch of the same name is deemed similar */
- if (starts_with(refname, "refs/remotes/") &&
+ if (skip_prefix(refname, "refs/remotes/", &remote) &&
!strcmp(branch, cb->base_ref))
- string_list_append(cb->similar_refs,
- refname + strlen("refs/remotes/"));
+ string_list_append(cb->similar_refs, remote);
return 0;
}