xdiff/xhistogram: move index allocation into find_lcs
[gitweb.git] / setup.c
diff --git a/setup.c b/setup.c
index 1a374f2bf4f986b00727ee04da6a65f8f914e35f..fe572b82c355390e6101aea15d2d53ec5b3b1e15 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -5,7 +5,9 @@
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 static int work_tree_config_is_bogus;
-static struct string_list unknown_extensions = STRING_LIST_INIT_DUP;
+
+static struct startup_info the_startup_info;
+struct startup_info *startup_info = &the_startup_info;
 
 /*
  * The input parameter must contain an absolute path, and it must already be
@@ -88,7 +90,7 @@ char *prefix_path_gently(const char *prefix, int len,
        const char *orig = path;
        char *sanitized;
        if (is_absolute_path(orig)) {
-               sanitized = xmalloc(strlen(path) + 1);
+               sanitized = xmallocz(strlen(path));
                if (remaining_prefix)
                        *remaining_prefix = 0;
                if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
@@ -100,10 +102,7 @@ char *prefix_path_gently(const char *prefix, int len,
                        return NULL;
                }
        } else {
-               sanitized = xmalloc(len + strlen(path) + 1);
-               if (len)
-                       memcpy(sanitized, prefix, len);
-               strcpy(sanitized + len, path);
+               sanitized = xstrfmt("%.*s%s", len, len ? prefix : "", path);
                if (remaining_prefix)
                        *remaining_prefix = len;
                if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
@@ -142,9 +141,7 @@ int check_filename(const char *prefix, const char *arg)
                if (arg[2] == '\0') /* ":/" is root dir, always exists */
                        return 1;
                name = arg + 2;
-       } else if (!no_wildcard(arg))
-               return 1;
-       else if (prefix)
+       } else if (prefix)
                name = prefix_filename(prefix, strlen(prefix), arg);
        else
                name = arg;
@@ -160,8 +157,8 @@ static void NORETURN die_verify_filename(const char *prefix,
                                         int diagnose_misspelt_rev)
 {
        if (!diagnose_misspelt_rev)
-               die("%s: no such path in the working tree.\n"
-                   "Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
+               die(_("%s: no such path in the working tree.\n"
+                     "Use 'git <command> -- <path>...' to specify paths that do not exist locally."),
                    arg);
        /*
         * Saying "'(icase)foo' does not exist in the index" when the
@@ -173,9 +170,9 @@ static void NORETURN die_verify_filename(const char *prefix,
                maybe_die_on_misspelt_object_name(arg, prefix);
 
        /* ... or fall back the most general message. */
-       die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
-           "Use '--' to separate paths from revisions, like this:\n"
-           "'git <command> [<revision>...] -- [<file>...]'", arg);
+       die(_("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
+             "Use '--' to separate paths from revisions, like this:\n"
+             "'git <command> [<revision>...] -- [<file>...]'"), arg);
 
 }
 
@@ -205,7 +202,7 @@ void verify_filename(const char *prefix,
 {
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
-       if (check_filename(prefix, arg))
+       if (check_filename(prefix, arg) || !no_wildcard(arg))
                return;
        die_verify_filename(prefix, arg, diagnose_misspelt_rev);
 }
@@ -223,9 +220,9 @@ void verify_non_filename(const char *prefix, const char *arg)
                return; /* flag */
        if (!check_filename(prefix, arg))
                return;
-       die("ambiguous argument '%s': both revision and filename\n"
-           "Use '--' to separate paths from revisions, like this:\n"
-           "'git <command> [<revision>...] -- [<file>...]'", arg);
+       die(_("ambiguous argument '%s': both revision and filename\n"
+             "Use '--' to separate paths from revisions, like this:\n"
+             "'git <command> [<revision>...] -- [<file>...]'"), arg);
 }
 
 int get_common_dir(struct strbuf *sb, const char *gitdir)
@@ -315,6 +312,23 @@ int is_git_directory(const char *suspect)
        return ret;
 }
 
+int is_nonbare_repository_dir(struct strbuf *path)
+{
+       int ret = 0;
+       int gitfile_error;
+       size_t orig_path_len = path->len;
+       assert(orig_path_len != 0);
+       strbuf_complete(path, '/');
+       strbuf_addstr(path, ".git");
+       if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
+               ret = 1;
+       if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
+           gitfile_error == READ_GITFILE_ERR_READ_FAILED)
+               ret = 1;
+       strbuf_setlen(path, orig_path_len);
+       return ret;
+}
+
 int is_inside_git_dir(void)
 {
        if (inside_git_dir < 0)
@@ -358,14 +372,13 @@ void setup_work_tree(void)
        initialized = 1;
 }
 
-static int check_repo_format(const char *var, const char *value, void *cb)
+static int check_repo_format(const char *var, const char *value, void *vdata)
 {
+       struct repository_format *data = vdata;
        const char *ext;
 
        if (strcmp(var, "core.repositoryformatversion") == 0)
-               repository_format_version = git_config_int(var, value);
-       else if (strcmp(var, "core.sharedrepository") == 0)
-               shared_repository = git_config_perm(var, value);
+               data->version = git_config_int(var, value);
        else if (skip_prefix(var, "extensions.", &ext)) {
                /*
                 * record any known extensions here; otherwise,
@@ -375,9 +388,15 @@ static int check_repo_format(const char *var, const char *value, void *cb)
                if (!strcmp(ext, "noop"))
                        ;
                else if (!strcmp(ext, "preciousobjects"))
-                       repository_format_precious_objects = git_config_bool(var, value);
+                       data->precious_objects = git_config_bool(var, value);
                else
-                       string_list_append(&unknown_extensions, ext);
+                       string_list_append(&data->unknown_extensions, ext);
+       } else if (strcmp(var, "core.bare") == 0) {
+               data->is_bare = git_config_bool(var, value);
+       } else if (strcmp(var, "core.worktree") == 0) {
+               if (!value)
+                       return config_error_nonbool(var);
+               data->work_tree = xstrdup(value);
        }
        return 0;
 }
@@ -385,67 +404,84 @@ static int check_repo_format(const char *var, const char *value, void *cb)
 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
        struct strbuf sb = STRBUF_INIT;
-       const char *repo_config;
-       config_fn_t fn;
-       int ret = 0;
-
-       string_list_clear(&unknown_extensions, 0);
+       struct strbuf err = STRBUF_INIT;
+       struct repository_format candidate;
+       int has_common;
 
-       if (get_common_dir(&sb, gitdir))
-               fn = check_repo_format;
-       else
-               fn = check_repository_format_version;
+       has_common = get_common_dir(&sb, gitdir);
        strbuf_addstr(&sb, "/config");
-       repo_config = sb.buf;
+       read_repository_format(&candidate, sb.buf);
+       strbuf_release(&sb);
 
        /*
-        * git_config() can't be used here because it calls git_pathdup()
-        * to get $GIT_CONFIG/config. That call will make setup_git_env()
-        * set git_dir to ".git".
-        *
-        * We are in gitdir setup, no git dir has been found useable yet.
-        * Use a gentler version of git_config() to check if this repo
-        * is a good one.
+        * For historical use of check_repository_format() in git-init,
+        * we treat a missing config as a silent "ok", even when nongit_ok
+        * is unset.
         */
-       git_config_early(fn, NULL, repo_config);
-       if (GIT_REPO_VERSION_READ < repository_format_version) {
-               if (!nongit_ok)
-                       die ("Expected git repo version <= %d, found %d",
-                            GIT_REPO_VERSION_READ, repository_format_version);
-               warning("Expected git repo version <= %d, found %d",
-                       GIT_REPO_VERSION_READ, repository_format_version);
-               warning("Please upgrade Git");
-               *nongit_ok = -1;
-               ret = -1;
-       }
-
-       if (repository_format_version >= 1 && unknown_extensions.nr) {
-               int i;
+       if (candidate.version < 0)
+               return 0;
 
-               if (!nongit_ok)
-                       die("unknown repository extension: %s",
-                           unknown_extensions.items[0].string);
+       if (verify_repository_format(&candidate, &err) < 0) {
+               if (nongit_ok) {
+                       warning("%s", err.buf);
+                       strbuf_release(&err);
+                       *nongit_ok = -1;
+                       return -1;
+               }
+               die("%s", err.buf);
+       }
 
-               for (i = 0; i < unknown_extensions.nr; i++)
-                       warning("unknown repository extension: %s",
-                               unknown_extensions.items[i].string);
-               *nongit_ok = -1;
-               ret = -1;
+       repository_format_precious_objects = candidate.precious_objects;
+       string_list_clear(&candidate.unknown_extensions, 0);
+       if (!has_common) {
+               if (candidate.is_bare != -1) {
+                       is_bare_repository_cfg = candidate.is_bare;
+                       if (is_bare_repository_cfg == 1)
+                               inside_work_tree = -1;
+               }
+               if (candidate.work_tree) {
+                       free(git_work_tree_cfg);
+                       git_work_tree_cfg = candidate.work_tree;
+                       inside_work_tree = -1;
+               }
+       } else {
+               free(candidate.work_tree);
        }
 
-       strbuf_release(&sb);
-       return ret;
+       return 0;
 }
 
-static void update_linked_gitdir(const char *gitfile, const char *gitdir)
+int read_repository_format(struct repository_format *format, const char *path)
 {
-       struct strbuf path = STRBUF_INIT;
-       struct stat st;
+       memset(format, 0, sizeof(*format));
+       format->version = -1;
+       format->is_bare = -1;
+       string_list_init(&format->unknown_extensions, 1);
+       git_config_from_file(check_repo_format, path, format);
+       return format->version;
+}
 
-       strbuf_addf(&path, "%s/gitdir", gitdir);
-       if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
-               write_file(path.buf, "%s", gitfile);
-       strbuf_release(&path);
+int verify_repository_format(const struct repository_format *format,
+                            struct strbuf *err)
+{
+       if (GIT_REPO_VERSION_READ < format->version) {
+               strbuf_addf(err, _("Expected git repo version <= %d, found %d"),
+                           GIT_REPO_VERSION_READ, format->version);
+               return -1;
+       }
+
+       if (format->version >= 1 && format->unknown_extensions.nr) {
+               int i;
+
+               strbuf_addstr(err, _("unknown repository extensions found:"));
+
+               for (i = 0; i < format->unknown_extensions.nr; i++)
+                       strbuf_addf(err, "\n\t%s",
+                                   format->unknown_extensions.items[i].string);
+               return -1;
+       }
+
+       return 0;
 }
 
 /*
@@ -485,14 +521,13 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
                error_code = READ_GITFILE_ERR_OPEN_FAILED;
                goto cleanup_return;
        }
-       buf = xmalloc(st.st_size + 1);
+       buf = xmallocz(st.st_size);
        len = read_in_full(fd, buf, st.st_size);
        close(fd);
        if (len != st.st_size) {
                error_code = READ_GITFILE_ERR_READ_FAILED;
                goto cleanup_return;
        }
-       buf[len] = '\0';
        if (!starts_with(buf, "gitdir: ")) {
                error_code = READ_GITFILE_ERR_INVALID_FORMAT;
                goto cleanup_return;
@@ -508,11 +543,8 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
 
        if (!is_absolute_path(dir) && (slash = strrchr(path, '/'))) {
                size_t pathlen = slash+1 - path;
-               size_t dirlen = pathlen + len - 8;
-               dir = xmalloc(dirlen + 1);
-               strncpy(dir, path, pathlen);
-               strncpy(dir + pathlen, buf + 8, len - 8);
-               dir[dirlen] = '\0';
+               dir = xstrfmt("%.*s%.*s", (int)pathlen, path,
+                             (int)(len - 8), buf + 8);
                free(buf);
                buf = dir;
        }
@@ -520,7 +552,6 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
                error_code = READ_GITFILE_ERR_NOT_A_REPO;
                goto cleanup_return;
        }
-       update_linked_gitdir(path, dir);
        path = real_path(dir);
 
 cleanup_return:
@@ -728,9 +759,9 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
 static const char *setup_nongit(const char *cwd, int *nongit_ok)
 {
        if (!nongit_ok)
-               die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT);
+               die(_("Not a git repository (or any of the parent directories): %s"), DEFAULT_GIT_DIR_ENVIRONMENT);
        if (chdir(cwd))
-               die_errno("Cannot come back to cwd");
+               die_errno(_("Cannot come back to cwd"));
        *nongit_ok = 1;
        return NULL;
 }
@@ -811,7 +842,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                *nongit_ok = 0;
 
        if (strbuf_getcwd(&cwd))
-               die_errno("Unable to read current working directory");
+               die_errno(_("Unable to read current working directory"));
        offset = cwd.len;
 
        /*
@@ -881,19 +912,19 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
                        if (parent_device != current_device) {
                                if (nongit_ok) {
                                        if (chdir(cwd.buf))
-                                               die_errno("Cannot come back to cwd");
+                                               die_errno(_("Cannot come back to cwd"));
                                        *nongit_ok = 1;
                                        return NULL;
                                }
                                strbuf_setlen(&cwd, offset);
-                               die("Not a git repository (or any parent up to mount point %s)\n"
-                               "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).",
+                               die(_("Not a git repository (or any parent up to mount point %s)\n"
+                               "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
                                    cwd.buf);
                        }
                }
                if (chdir("..")) {
                        strbuf_setlen(&cwd, offset);
-                       die_errno("Cannot change to '%s/..'", cwd.buf);
+                       die_errno(_("Cannot change to '%s/..'"), cwd.buf);
                }
                offset = offset_parent;
        }
@@ -909,10 +940,9 @@ const char *setup_git_directory_gently(int *nongit_ok)
        else
                setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
 
-       if (startup_info) {
-               startup_info->have_repository = !nongit_ok || !*nongit_ok;
-               startup_info->prefix = prefix;
-       }
+       startup_info->have_repository = !nongit_ok || !*nongit_ok;
+       startup_info->prefix = prefix;
+
        return prefix;
 }
 
@@ -956,9 +986,9 @@ int git_config_perm(const char *var, const char *value)
        /* A filemode value was given: 0xxx */
 
        if ((i & 0600) != 0600)
-               die("Problem with core.sharedRepository filemode value "
+               die(_("Problem with core.sharedRepository filemode value "
                    "(0%.3o).\nThe owner of files must always have "
-                   "read and write permissions.", i);
+                   "read and write permissions."), i);
 
        /*
         * Mask filemode value. Others can not get write permission.
@@ -967,28 +997,10 @@ int git_config_perm(const char *var, const char *value)
        return -(i & 0666);
 }
 
-int check_repository_format_version(const char *var, const char *value, void *cb)
-{
-       int ret = check_repo_format(var, value, cb);
-       if (ret)
-               return ret;
-       if (strcmp(var, "core.bare") == 0) {
-               is_bare_repository_cfg = git_config_bool(var, value);
-               if (is_bare_repository_cfg == 1)
-                       inside_work_tree = -1;
-       } else if (strcmp(var, "core.worktree") == 0) {
-               if (!value)
-                       return config_error_nonbool(var);
-               free(git_work_tree_cfg);
-               git_work_tree_cfg = xstrdup(value);
-               inside_work_tree = -1;
-       }
-       return 0;
-}
-
-int check_repository_format(void)
+void check_repository_format(void)
 {
-       return check_repository_format_gently(get_git_dir(), NULL);
+       check_repository_format_gently(get_git_dir(), NULL);
+       startup_info->have_repository = 1;
 }
 
 /*