]> git.ipfire.org Git - thirdparty/git.git/blobdiff - git.c
git-stash: don't complain when listing in a repo with no stash
[thirdparty/git.git] / git.c
diff --git a/git.c b/git.c
index dde4d07e8fbb830791417d422e4b9204373935e4..cfec5d70ee42852f3819fe46e99ebc70f089ccc7 100644 (file)
--- a/git.c
+++ b/git.c
@@ -66,6 +66,7 @@ static int handle_options(const char*** argv, int* argc)
                        setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
                        (*argv)++;
                        (*argc)--;
+                       handled++;
                } else if (!prefixcmp(cmd, "--git-dir=")) {
                        setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
                } else if (!strcmp(cmd, "--bare")) {
@@ -99,7 +100,7 @@ static int split_cmdline(char *cmdline, const char ***argv)
        int src, dst, count = 0, size = 16;
        char quoted = 0;
 
-       *argv = malloc(sizeof(char*) * size);
+       *argv = xmalloc(sizeof(char*) * size);
 
        /* split alias_string */
        (*argv)[count++] = cmdline;
@@ -215,24 +216,65 @@ const char git_version_string[] = GIT_VERSION;
  */
 #define NOT_BARE       (1<<2)
 
-static void handle_internal_command(int argc, const char **argv, char **envp)
+struct cmd_struct {
+       const char *cmd;
+       int (*fn)(int, const char **, const char *);
+       int option;
+};
+
+static int run_command(struct cmd_struct *p, int argc, const char **argv)
+{
+       int status;
+       struct stat st;
+       const char *prefix;
+
+       prefix = NULL;
+       if (p->option & RUN_SETUP)
+               prefix = setup_git_directory();
+       if (p->option & USE_PAGER)
+               setup_pager();
+       if (p->option & NOT_BARE) {
+               if (is_bare_repository() || is_inside_git_dir())
+                       die("%s must be run in a work tree", p->cmd);
+       }
+       trace_argv_printf(argv, argc, "trace: built-in: git");
+
+       status = p->fn(argc, argv, prefix);
+       if (status)
+               return status;
+
+       /* Somebody closed stdout? */
+       if (fstat(fileno(stdout), &st))
+               return 0;
+       /* Ignore write errors for pipes and sockets.. */
+       if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
+               return 0;
+
+       /* Check for ENOSPC and EIO errors.. */
+       if (fflush(stdout))
+               die("write failure on standard output: %s", strerror(errno));
+       if (ferror(stdout))
+               die("unknown write failure on standard output");
+       if (fclose(stdout))
+               die("close failed on standard output: %s", strerror(errno));
+       return 0;
+}
+
+static void handle_internal_command(int argc, const char **argv)
 {
        const char *cmd = argv[0];
-       static struct cmd_struct {
-               const char *cmd;
-               int (*fn)(int, const char **, const char *);
-               int option;
-       } commands[] = {
+       static struct cmd_struct commands[] = {
                { "add", cmd_add, RUN_SETUP | NOT_BARE },
-               { "annotate", cmd_annotate, USE_PAGER },
+               { "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
                { "apply", cmd_apply },
-               { "archive", cmd_archive, RUN_SETUP },
+               { "archive", cmd_archive },
                { "blame", cmd_blame, RUN_SETUP },
                { "branch", cmd_branch, RUN_SETUP },
                { "bundle", cmd_bundle },
                { "cat-file", cmd_cat_file, RUN_SETUP },
                { "checkout-index", cmd_checkout_index, RUN_SETUP },
                { "check-ref-format", cmd_check_ref_format },
+               { "check-attr", cmd_check_attr, RUN_SETUP | NOT_BARE },
                { "cherry", cmd_cherry, RUN_SETUP },
                { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE },
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
@@ -249,6 +291,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "format-patch", cmd_format_patch, RUN_SETUP },
                { "fsck", cmd_fsck, RUN_SETUP },
                { "fsck-objects", cmd_fsck, RUN_SETUP },
+               { "gc", cmd_gc, RUN_SETUP },
                { "get-tar-commit-id", cmd_get_tar_commit_id },
                { "grep", cmd_grep, RUN_SETUP | USE_PAGER },
                { "help", cmd_help },
@@ -304,25 +347,13 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                struct cmd_struct *p = commands+i;
-               const char *prefix;
                if (strcmp(p->cmd, cmd))
                        continue;
-
-               prefix = NULL;
-               if (p->option & RUN_SETUP)
-                       prefix = setup_git_directory();
-               if (p->option & USE_PAGER)
-                       setup_pager();
-               if ((p->option & NOT_BARE) &&
-                               (is_bare_repository() || is_inside_git_dir()))
-                       die("%s must be run in a work tree", cmd);
-               trace_argv_printf(argv, argc, "trace: built-in: git");
-
-               exit(p->fn(argc, argv, prefix));
+               exit(run_command(p, argc, argv));
        }
 }
 
-int main(int argc, const char **argv, char **envp)
+int main(int argc, const char **argv)
 {
        const char *cmd = argv[0] ? argv[0] : "git-help";
        char *slash = strrchr(cmd, '/');
@@ -355,7 +386,7 @@ int main(int argc, const char **argv, char **envp)
        if (!prefixcmp(cmd, "git-")) {
                cmd += 4;
                argv[0] = cmd;
-               handle_internal_command(argc, argv, envp);
+               handle_internal_command(argc, argv);
                die("cannot handle %s internally", cmd);
        }
 
@@ -387,7 +418,7 @@ int main(int argc, const char **argv, char **envp)
 
        while (1) {
                /* See if it's an internal command */
-               handle_internal_command(argc, argv, envp);
+               handle_internal_command(argc, argv);
 
                /* .. then try the external ones */
                execv_git_cmd(argv);