X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git.c;h=01b7e28b8c459c677a340f195a969a67a6d21792;hb=2b11e3170e919866c7f5554dd4089289a1bb6726;hp=fc4e4292781d0aab39abaede2e872fce557a434b;hpb=78fff6ebbafe2d23464a2b059104954bfe8732c7;p=git.git diff --git a/git.c b/git.c index fc4e4292..88544724 100644 --- a/git.c +++ b/git.c @@ -8,218 +8,11 @@ #include #include #include -#include #include "git-compat-util.h" #include "exec_cmd.h" -#include "common-cmds.h" - #include "cache.h" -#include "commit.h" -#include "diff.h" -#include "revision.h" -#include "log-tree.h" - -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif - -static const char git_usage[] = - "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; - -/* most gui terms set COLUMNS (although some don't export it) */ -static int term_columns(void) -{ - char *col_string = getenv("COLUMNS"); - int n_cols = 0; - - if (col_string && (n_cols = atoi(col_string)) > 0) - return n_cols; - -#ifdef TIOCGWINSZ - { - struct winsize ws; - if (!ioctl(1, TIOCGWINSZ, &ws)) { - if (ws.ws_col) - return ws.ws_col; - } - } -#endif - - return 80; -} - -static void oom(void) -{ - fprintf(stderr, "git: out of memory\n"); - exit(1); -} - -static inline void mput_char(char c, unsigned int num) -{ - while(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) -{ - struct cmdname *ent; - if (cmdname_alloc <= cmdname_cnt) { - cmdname_alloc = cmdname_alloc + 200; - cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname)); - if (!cmdname) - oom(); - } - ent = malloc(sizeof(*ent) + len); - if (!ent) - oom(); - ent->len = len; - memcpy(ent->name, name, len); - ent->name[len] = 0; - cmdname[cmdname_cnt++] = ent; -} - -static int cmdname_compare(const void *a_, const void *b_) -{ - struct cmdname *a = *(struct cmdname **)a_; - struct cmdname *b = *(struct cmdname **)b_; - return strcmp(a->name, b->name); -} - -static void pretty_print_string_list(struct cmdname **cmdname, int longest) -{ - int cols = 1, rows; - int space = longest + 1; /* min 1 SP between words */ - int max_cols = term_columns() - 1; /* don't print *on* the edge */ - int i, j; - - if (space < max_cols) - cols = max_cols / space; - rows = (cmdname_cnt + cols - 1) / cols; - - qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare); - - for (i = 0; i < rows; i++) { - printf(" "); - - for (j = 0; j < cols; j++) { - int n = j * rows + i; - int size = space; - if (n >= cmdname_cnt) - break; - if (j == cols-1 || n + rows >= cmdname_cnt) - size = 1; - printf("%-*s", size, cmdname[n]->name); - } - putchar('\n'); - } -} - -static void list_commands(const char *exec_path, const char *pattern) -{ - unsigned int longest = 0; - char path[PATH_MAX]; - int dirlen; - DIR *dir = opendir(exec_path); - struct dirent *de; - - if (!dir) { - fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno)); - exit(1); - } - - dirlen = strlen(exec_path); - if (PATH_MAX - 20 < dirlen) { - fprintf(stderr, "git: insanely long exec-path '%s'\n", - exec_path); - exit(1); - } - - memcpy(path, exec_path, dirlen); - path[dirlen++] = '/'; - - while ((de = readdir(dir)) != NULL) { - struct stat st; - int entlen; - - if (strncmp(de->d_name, "git-", 4)) - continue; - strcpy(path+dirlen, de->d_name); - if (stat(path, &st) || /* stat, not lstat */ - !S_ISREG(st.st_mode) || - !(st.st_mode & S_IXUSR)) - continue; - - entlen = strlen(de->d_name); - if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe")) - entlen -= 4; - - if (longest < entlen) - longest = entlen; - - add_cmdname(de->d_name + 4, entlen-4); - } - 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 - 4); - putchar('\n'); -} - -static void list_common_cmds_help(void) -{ - int i, longest = 0; - 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:"); - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - printf(" %s", common_cmds[i].name); - mput_char(' ', longest - strlen(common_cmds[i].name) + 4); - puts(common_cmds[i].help); - } - puts("(use 'git help -a' to get a list of all installed git commands)"); -} - -#ifdef __GNUC__ -static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) - __attribute__((__format__(__printf__, 3, 4), __noreturn__)); -#endif -static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - - va_start(ap, fmt); - printf("git: "); - vprintf(fmt, ap); - va_end(ap); - putchar('\n'); - } - else - puts(git_usage); - - if (exec_path) { - putchar('\n'); - if (show_all) - list_commands(exec_path, "git-*"); - else - list_common_cmds_help(); - } - - exit(1); -} +#include "builtin.h" static void prepend_to_path(const char *dir, int len) { @@ -240,156 +33,114 @@ static void prepend_to_path(const char *dir, int len) setenv("PATH", path, 1); } -static void show_man_page(const char *git_cmd) +static const char *alias_command; +static char *alias_string = NULL; + +static int git_alias_config(const char *var, const char *value) { - const char *page; - - if (!strncmp(git_cmd, "git", 3)) - page = git_cmd; - else { - int page_len = strlen(git_cmd) + 4; - char *p = malloc(page_len + 1); - strcpy(p, "git-"); - strcpy(p + 4, git_cmd); - p[page_len] = 0; - page = p; + if (!strncmp(var, "alias.", 6) && !strcmp(var + 6, alias_command)) { + alias_string = strdup(value); } - - execlp("man", "man", page, NULL); + return 0; } -static int cmd_version(int argc, const char **argv, char **envp) +static int split_cmdline(char *cmdline, const char ***argv) { - printf("git version %s\n", GIT_VERSION); - return 0; + int src, dst, count = 0, size = 16; + char quoted = 0; + + *argv = malloc(sizeof(char*) * size); + + /* split alias_string */ + (*argv)[count++] = cmdline; + for (src = dst = 0; cmdline[src];) { + char c = cmdline[src]; + if (!quoted && isspace(c)) { + cmdline[dst++] = 0; + while (cmdline[++src] + && isspace(cmdline[src])) + ; /* skip */ + if (count >= size) { + size += 16; + *argv = realloc(*argv, sizeof(char*) * size); + } + (*argv)[count++] = cmdline + dst; + } else if(!quoted && (c == '\'' || c == '"')) { + quoted = c; + src++; + } else if (c == quoted) { + quoted = 0; + src++; + } else { + if (c == '\\' && quoted != '\'') { + src++; + c = cmdline[src]; + if (!c) { + free(*argv); + *argv = NULL; + return error("cmdline ends with \\"); + } + } + cmdline[dst++] = c; + src++; + } + } + + cmdline[dst] = 0; + + if (quoted) { + free(*argv); + *argv = NULL; + return error("unclosed quote"); + } + + return count; } -static int cmd_help(int argc, const char **argv, char **envp) +static int handle_alias(int *argcp, const char ***argv) { - const char *help_cmd = argv[1]; - if (!help_cmd) - cmd_usage(0, git_exec_path(), NULL); - else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) - cmd_usage(1, git_exec_path(), NULL); - else - show_man_page(help_cmd); - return 0; -} + int nongit = 0, ret = 0; + const char *subdir; -#define LOGSIZE (65536) + subdir = setup_git_directory_gently(&nongit); + if (!nongit) { + int count; + const char** new_argv; -static int cmd_log_wc(int argc, const char **argv, char **envp, - struct rev_info *rev) -{ - struct commit *commit; - char *buf = xmalloc(LOGSIZE); - const char *commit_prefix = "commit "; - int shown = 0; - - rev->abbrev = DEFAULT_ABBREV; - rev->commit_format = CMIT_FMT_DEFAULT; - argc = setup_revisions(argc, argv, rev, "HEAD"); - - if (argc > 1) - die("unrecognized argument: %s", argv[1]); - if (rev->commit_format == CMIT_FMT_ONELINE) - commit_prefix = ""; - - prepare_revision_walk(rev); - setup_pager(); - while ((commit = get_revision(rev)) != NULL) { - unsigned long ofs = 0; - - if (shown && rev->diff && - rev->commit_format != CMIT_FMT_ONELINE) - putchar('\n'); - - ofs = sprintf(buf, "%s", commit_prefix); - if (rev->abbrev_commit && rev->abbrev) - ofs += sprintf(buf + ofs, "%s", - find_unique_abbrev(commit->object.sha1, - rev->abbrev)); - else - ofs += sprintf(buf + ofs, "%s", - sha1_to_hex(commit->object.sha1)); - if (rev->parents) { - struct commit_list *parents = commit->parents; - while (parents) { - struct object *o = &(parents->item->object); - parents = parents->next; - if (o->flags & TMP_MARK) - continue; - ofs += sprintf(buf + ofs, " %s", - sha1_to_hex(o->sha1)); - o->flags |= TMP_MARK; + alias_command = (*argv)[0]; + git_config(git_alias_config); + if (alias_string) { + + count = split_cmdline(alias_string, &new_argv); + + if (count < 1) + die("empty alias for %s", alias_command); + + if (!strcmp(alias_command, new_argv[0])) + die("recursive alias: %s", alias_command); + + /* insert after command name */ + if (*argcp > 1) { + new_argv = realloc(new_argv, sizeof(char*) * + (count + *argcp - 1)); + memcpy(new_argv + count, *argv, sizeof(char*) * + (*argcp - 1)); } - /* TMP_MARK is a general purpose flag that can - * be used locally, but the user should clean - * things up after it is done with them. - */ - for (parents = commit->parents; - parents; - parents = parents->next) - parents->item->object.flags &= ~TMP_MARK; - } - buf[ofs++] = - (rev->commit_format == CMIT_FMT_ONELINE) ? ' ' : '\n'; - ofs += pretty_print_commit(rev->commit_format, commit, ~0, - buf + ofs, - LOGSIZE - ofs - 20, - rev->abbrev); - - if (rev->diff) { - rev->use_precomputed_header = buf; - strcpy(buf + ofs, "\n---\n"); - log_tree_commit(rev, commit); + + *argv = new_argv; + *argcp += count - 1; + + ret = 1; } - else - printf("%s\n", buf); - shown = 1; - free(commit->buffer); - commit->buffer = NULL; } - free(buf); - return 0; -} - -static int cmd_wc(int argc, const char **argv, char **envp) -{ - struct rev_info rev; - init_revisions(&rev); - rev.diff = 1; - rev.diffopt.recursive = 1; - return cmd_log_wc(argc, argv, envp, &rev); -} + if (subdir) + chdir(subdir); -static int cmd_show(int argc, const char **argv, char **envp) -{ - struct rev_info rev; - - init_revisions(&rev); - rev.diff = 1; - rev.diffopt.recursive = 1; - rev.combine_merges = 1; - rev.dense_combined_merges = 1; - rev.always_show_header = 1; - rev.ignore_merges = 0; - rev.no_walk = 1; - return cmd_log_wc(argc, argv, envp, &rev); + return ret; } -static int cmd_log(int argc, const char **argv, char **envp) -{ - struct rev_info rev; - - init_revisions(&rev); - rev.always_show_header = 1; - rev.diffopt.recursive = 1; - rev.combine_merges = 1; - rev.ignore_merges = 0; - return cmd_log_wc(argc, argv, envp, &rev); -} +const char git_version_string[] = GIT_VERSION; static void handle_internal_command(int argc, const char **argv, char **envp) { @@ -401,8 +152,33 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "version", cmd_version }, { "help", cmd_help }, { "log", cmd_log }, - { "whatchanged", cmd_wc }, + { "whatchanged", cmd_whatchanged }, { "show", cmd_show }, + { "push", cmd_push }, + { "format-patch", cmd_format_patch }, + { "count-objects", cmd_count_objects }, + { "diff", cmd_diff }, + { "grep", cmd_grep }, + { "rm", cmd_rm }, + { "add", cmd_add }, + { "rev-list", cmd_rev_list }, + { "init-db", cmd_init_db }, + { "tar-tree", cmd_tar_tree }, + { "upload-tar", cmd_upload_tar }, + { "check-ref-format", cmd_check_ref_format }, + { "ls-files", cmd_ls_files }, + { "ls-tree", cmd_ls_tree }, + { "tar-tree", cmd_tar_tree }, + { "read-tree", cmd_read_tree }, + { "commit-tree", cmd_commit_tree }, + { "apply", cmd_apply }, + { "show-branch", cmd_show_branch }, + { "diff-files", cmd_diff_files }, + { "diff-index", cmd_diff_index }, + { "diff-stages", cmd_diff_stages }, + { "diff-tree", cmd_diff_tree }, + { "cat-file", cmd_cat_file }, + { "rev-parse", cmd_rev_parse } }; int i; @@ -453,6 +229,7 @@ int main(int argc, const char **argv, char **envp) if (!strncmp(cmd, "git-", 4)) { cmd += 4; argv[0] = cmd; + handle_alias(&argc, &argv); handle_internal_command(argc, argv, envp); die("cannot handle %s internally", cmd); } @@ -510,6 +287,8 @@ int main(int argc, const char **argv, char **envp) exec_path = git_exec_path(); prepend_to_path(exec_path, strlen(exec_path)); + handle_alias(&argc, &argv); + /* See if it's an internal command */ handle_internal_command(argc, argv, envp);