summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2024-06-06 21:49:23 +0200
committerJunio C Hamano <gitster@pobox.com>2024-06-06 21:49:23 +0200
commitcf792653ad407badec34e67612231676057f9532 (patch)
tree9bf1e8c130b89f468e10ec979f07089e622133f1
parentThe tenth batch (diff)
parentbuiltin/mv: fix leaks for submodule gitfile paths (diff)
downloadgit-cf792653ad407badec34e67612231676057f9532.tar.xz
git-cf792653ad407badec34e67612231676057f9532.zip
Merge branch 'ps/leakfixes'
Leakfixes. * ps/leakfixes: builtin/mv: fix leaks for submodule gitfile paths builtin/mv: refactor to use `struct strvec` builtin/mv duplicate string list memory builtin/mv: refactor `add_slash()` to always return allocated strings strvec: add functions to replace and remove strings submodule: fix leaking memory for submodule entries commit-reach: fix memory leak in `ahead_behind()` builtin/credential: clear credential before exit config: plug various memory leaks config: clarify memory ownership in `git_config_string()` builtin/log: stop using globals for format config builtin/log: stop using globals for log config convert: refactor code to clarify ownership of check_roundtrip_encoding diff: refactor code to clarify memory ownership of prefixes config: clarify memory ownership in `git_config_pathname()` http: refactor code to clarify memory ownership checkout: clarify memory ownership in `unique_tracking_name()` strbuf: fix leak when `appendwholeline()` fails with EOF transport-helper: fix leaking helper name
-rw-r--r--Makefile1
-rw-r--r--alias.c6
-rw-r--r--attr.c2
-rw-r--r--attr.h2
-rw-r--r--builtin/blame.c2
-rw-r--r--builtin/checkout.c14
-rw-r--r--builtin/commit.c4
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/credential.c2
-rw-r--r--builtin/log.c708
-rw-r--r--builtin/merge.c4
-rw-r--r--builtin/mv.c222
-rw-r--r--builtin/rebase.c2
-rw-r--r--builtin/receive-pack.c6
-rw-r--r--builtin/repack.c8
-rw-r--r--builtin/worktree.c20
-rw-r--r--checkout.c4
-rw-r--r--checkout.h6
-rw-r--r--commit-reach.c4
-rw-r--r--config.c55
-rw-r--r--config.h10
-rw-r--r--convert.c30
-rw-r--r--convert.h2
-rw-r--r--delta-islands.c2
-rw-r--r--diff.c20
-rw-r--r--environment.c16
-rw-r--r--environment.h14
-rw-r--r--fetch-pack.c4
-rw-r--r--fsck.c4
-rw-r--r--fsmonitor-settings.c5
-rw-r--r--gpg-interface.c6
-rw-r--r--http.c50
-rw-r--r--imap-send.c12
-rw-r--r--mailmap.c4
-rw-r--r--mailmap.h4
-rw-r--r--merge-ll.c6
-rw-r--r--pager.c2
-rw-r--r--pretty.c14
-rw-r--r--promisor-remote.h2
-rw-r--r--remote.c20
-rw-r--r--remote.h8
-rw-r--r--sequencer.c2
-rw-r--r--setup.c6
-rw-r--r--strbuf.c4
-rw-r--r--strvec.c20
-rw-r--r--strvec.h13
-rw-r--r--submodule-config.c2
-rwxr-xr-xt/t0300-credentials.sh2
-rwxr-xr-xt/t0611-reftable-httpd.sh1
-rwxr-xr-xt/t1013-read-tree-submodule.sh1
-rwxr-xr-xt/t1306-xdg-files.sh1
-rwxr-xr-xt/t1350-config-hooks-path.sh1
-rwxr-xr-xt/t1400-update-ref.sh2
-rwxr-xr-xt/t2013-checkout-submodule.sh1
-rwxr-xr-xt/t2024-checkout-dwim.sh1
-rwxr-xr-xt/t2060-switch.sh1
-rwxr-xr-xt/t3007-ls-files-recurse-submodules.sh1
-rwxr-xr-xt/t3203-branch-output.sh2
-rwxr-xr-xt/t3415-rebase-autosquash.sh1
-rwxr-xr-xt/t3426-rebase-submodule.sh1
-rwxr-xr-xt/t3512-cherry-pick-submodule.sh1
-rwxr-xr-xt/t3513-revert-submodule.sh1
-rwxr-xr-xt/t3600-rm.sh1
-rwxr-xr-xt/t3906-stash-submodule.sh1
-rwxr-xr-xt/t4001-diff-rename.sh4
-rwxr-xr-xt/t4041-diff-submodule-option.sh1
-rwxr-xr-xt/t4043-diff-rename-binary.sh1
-rwxr-xr-xt/t4059-diff-submodule-not-initialized.sh1
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh1
-rwxr-xr-xt/t4120-apply-popt.sh1
-rwxr-xr-xt/t4137-apply-submodule.sh1
-rwxr-xr-xt/t4210-log-i18n.sh2
-rwxr-xr-xt/t5563-simple-http-auth.sh1
-rwxr-xr-xt/t5564-http-proxy.sh1
-rwxr-xr-xt/t5581-http-curl-verbose.sh1
-rwxr-xr-xt/t6006-rev-list-format.sh1
-rwxr-xr-xt/t6041-bisect-submodule.sh1
-rwxr-xr-xt/t6400-merge-df.sh1
-rwxr-xr-xt/t6412-merge-large-rename.sh1
-rwxr-xr-xt/t6426-merge-skip-unneeded-updates.sh1
-rwxr-xr-xt/t6429-merge-sequence-rename-caching.sh1
-rwxr-xr-xt/t6438-submodule-directory-file-conflicts.sh1
-rwxr-xr-xt/t7001-mv.sh2
-rwxr-xr-xt/t7005-editor.sh1
-rwxr-xr-xt/t7102-reset.sh1
-rwxr-xr-xt/t7112-reset-submodule.sh1
-rwxr-xr-xt/t7417-submodule-path-url.sh1
-rwxr-xr-xt/t7421-submodule-summary-add.sh1
-rwxr-xr-xt/t9129-git-svn-i18n-commitencoding.sh1
-rwxr-xr-xt/t9139-git-svn-non-utf8-commitencoding.sh1
-rw-r--r--t/unit-tests/t-strvec.c269
-rw-r--r--t/unit-tests/test-lib.c13
-rw-r--r--t/unit-tests/test-lib.h13
-rw-r--r--transport-helper.c6
-rw-r--r--transport.c1
-rw-r--r--upload-pack.c2
-rw-r--r--userdiff.h12
97 files changed, 1138 insertions, 585 deletions
diff --git a/Makefile b/Makefile
index 59d98ba688..2f5f16847a 100644
--- a/Makefile
+++ b/Makefile
@@ -1338,6 +1338,7 @@ UNIT_TEST_PROGRAMS += t-mem-pool
UNIT_TEST_PROGRAMS += t-prio-queue
UNIT_TEST_PROGRAMS += t-strbuf
UNIT_TEST_PROGRAMS += t-strcmp-offset
+UNIT_TEST_PROGRAMS += t-strvec
UNIT_TEST_PROGRAMS += t-trailer
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
diff --git a/alias.c b/alias.c
index 5a238f2e30..4daafd9bda 100644
--- a/alias.c
+++ b/alias.c
@@ -21,9 +21,11 @@ static int config_alias_cb(const char *key, const char *value,
return 0;
if (data->alias) {
- if (!strcasecmp(p, data->alias))
- return git_config_string((const char **)&data->v,
+ if (!strcasecmp(p, data->alias)) {
+ FREE_AND_NULL(data->v);
+ return git_config_string(&data->v,
key, value);
+ }
} else if (data->list) {
string_list_append(data->list, p);
}
diff --git a/attr.c b/attr.c
index 38c586ab63..300f994ba6 100644
--- a/attr.c
+++ b/attr.c
@@ -25,7 +25,7 @@
#include "tree-walk.h"
#include "object-name.h"
-const char *git_attr_tree;
+char *git_attr_tree;
const char git_attr__true[] = "(builtin)true";
const char git_attr__false[] = "\0(builtin)false";
diff --git a/attr.h b/attr.h
index 127998ae01..e7cc318b0c 100644
--- a/attr.h
+++ b/attr.h
@@ -236,6 +236,6 @@ const char *git_attr_global_file(void);
/* Return whether the system gitattributes file is enabled and should be used. */
int git_attr_system_is_enabled(void);
-extern const char *git_attr_tree;
+extern char *git_attr_tree;
#endif /* ATTR_H */
diff --git a/builtin/blame.c b/builtin/blame.c
index fadba1a530..e09ff0155a 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -718,7 +718,7 @@ static int git_blame_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "blame.ignorerevsfile")) {
- const char *str;
+ char *str;
int ret;
ret = git_config_pathname(&str, var, value);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f90a4ca4b7..3cf44b4683 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1275,12 +1275,12 @@ static void setup_new_branch_info_and_source_tree(
}
}
-static const char *parse_remote_branch(const char *arg,
- struct object_id *rev,
- int could_be_checkout_paths)
+static char *parse_remote_branch(const char *arg,
+ struct object_id *rev,
+ int could_be_checkout_paths)
{
int num_matches = 0;
- const char *remote = unique_tracking_name(arg, rev, &num_matches);
+ char *remote = unique_tracking_name(arg, rev, &num_matches);
if (remote && could_be_checkout_paths) {
die(_("'%s' could be both a local file and a tracking branch.\n"
@@ -1316,6 +1316,7 @@ static int parse_branchname_arg(int argc, const char **argv,
const char **new_branch = &opts->new_branch;
int argcount = 0;
const char *arg;
+ char *remote = NULL;
int dash_dash_pos;
int has_dash_dash = 0;
int i;
@@ -1416,8 +1417,8 @@ static int parse_branchname_arg(int argc, const char **argv,
recover_with_dwim = 0;
if (recover_with_dwim) {
- const char *remote = parse_remote_branch(arg, rev,
- could_be_checkout_paths);
+ remote = parse_remote_branch(arg, rev,
+ could_be_checkout_paths);
if (remote) {
*new_branch = arg;
arg = remote;
@@ -1459,6 +1460,7 @@ static int parse_branchname_arg(int argc, const char **argv,
argc--;
}
+ free(remote);
return argcount;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index 78bfae2164..f53e7e86ff 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -107,7 +107,7 @@ static enum {
} commit_style;
static const char *logfile, *force_author;
-static const char *template_file;
+static char *template_file;
/*
* The _message variables are commit names from which to take
* the commit message and/or authorship.
@@ -133,7 +133,7 @@ static struct strvec trailer_args = STRVEC_INIT;
* is specified explicitly.
*/
static enum commit_msg_cleanup_mode cleanup_mode;
-static const char *cleanup_arg;
+static char *cleanup_arg;
static enum commit_whence whence;
static int use_editor = 1, include_status = 1;
diff --git a/builtin/config.c b/builtin/config.c
index c38264c999..20a0b64090 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -289,7 +289,7 @@ static int format_config(const struct config_display_options *opts,
else
strbuf_addstr(buf, v ? "true" : "false");
} else if (opts->type == TYPE_PATH) {
- const char *v;
+ char *v;
if (git_config_pathname(&v, key_, value_) < 0)
return -1;
strbuf_addstr(buf, v);
diff --git a/builtin/credential.c b/builtin/credential.c
index 5100d441f2..b72e76dd9a 100644
--- a/builtin/credential.c
+++ b/builtin/credential.c
@@ -39,5 +39,7 @@ int cmd_credential(int argc, const char **argv, const char *prefix UNUSED)
} else {
usage(usage_msg);
}
+
+ credential_clear(&c);
return 0;
}
diff --git a/builtin/log.c b/builtin/log.c
index c8ce0c0d88..78a247d8a9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -48,22 +48,8 @@
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
#define FORMAT_PATCH_NAME_MAX_DEFAULT 64
-/* Set a default date-time format for git log ("log.date" config variable) */
-static const char *default_date_mode = NULL;
-
-static int default_abbrev_commit;
-static int default_show_root = 1;
-static int default_follow;
-static int default_show_signature;
-static int default_encode_email_headers = 1;
-static int decoration_style;
-static int decoration_given;
-static int use_mailmap_config = 1;
static unsigned int force_in_body_from;
static int stdout_mboxrd;
-static const char *fmt_patch_subject_prefix = "PATCH";
-static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
-static const char *fmt_pretty;
static int format_no_prefix;
static const char * const builtin_log_usage[] = {
@@ -111,6 +97,39 @@ static int parse_decoration_style(const char *value)
return -1;
}
+struct log_config {
+ int default_abbrev_commit;
+ int default_show_root;
+ int default_follow;
+ int default_show_signature;
+ int default_encode_email_headers;
+ int decoration_style;
+ int decoration_given;
+ int use_mailmap_config;
+ char *fmt_patch_subject_prefix;
+ int fmt_patch_name_max;
+ char *fmt_pretty;
+ char *default_date_mode;
+};
+
+static void log_config_init(struct log_config *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->default_show_root = 1;
+ cfg->default_encode_email_headers = 1;
+ cfg->use_mailmap_config = 1;
+ cfg->fmt_patch_subject_prefix = xstrdup("PATCH");
+ cfg->fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
+ cfg->decoration_style = auto_decoration_style();
+}
+
+static void log_config_release(struct log_config *cfg)
+{
+ free(cfg->default_date_mode);
+ free(cfg->fmt_pretty);
+ free(cfg->fmt_patch_subject_prefix);
+}
+
static int use_default_decoration_filter = 1;
static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
@@ -127,20 +146,22 @@ static int clear_decorations_callback(const struct option *opt UNUSED,
return 0;
}
-static int decorate_callback(const struct option *opt UNUSED, const char *arg,
+static int decorate_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct log_config *cfg = opt->value;
+
if (unset)
- decoration_style = 0;
+ cfg->decoration_style = 0;
else if (arg)
- decoration_style = parse_decoration_style(arg);
+ cfg->decoration_style = parse_decoration_style(arg);
else
- decoration_style = DECORATE_SHORT_REFS;
+ cfg->decoration_style = DECORATE_SHORT_REFS;
- if (decoration_style < 0)
+ if (cfg->decoration_style < 0)
die(_("invalid --decorate option: %s"), arg);
- decoration_given = 1;
+ cfg->decoration_given = 1;
return 0;
}
@@ -160,32 +181,26 @@ static int log_line_range_callback(const struct option *option, const char *arg,
return 0;
}
-static void init_log_defaults(void)
+static void cmd_log_init_defaults(struct rev_info *rev,
+ struct log_config *cfg)
{
- init_diff_ui_defaults();
-
- decoration_style = auto_decoration_style();
-}
-
-static void cmd_log_init_defaults(struct rev_info *rev)
-{
- if (fmt_pretty)
- get_commit_format(fmt_pretty, rev);
- if (default_follow)
+ if (cfg->fmt_pretty)
+ get_commit_format(cfg->fmt_pretty, rev);
+ if (cfg->default_follow)
rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
init_diffstat_widths(&rev->diffopt);
rev->diffopt.flags.recursive = 1;
rev->diffopt.flags.allow_textconv = 1;
- rev->abbrev_commit = default_abbrev_commit;
- rev->show_root_diff = default_show_root;
- rev->subject_prefix = fmt_patch_subject_prefix;
- rev->patch_name_max = fmt_patch_name_max;
- rev->show_signature = default_show_signature;
- rev->encode_email_headers = default_encode_email_headers;
+ rev->abbrev_commit = cfg->default_abbrev_commit;
+ rev->show_root_diff = cfg->default_show_root;
+ rev->subject_prefix = cfg->fmt_patch_subject_prefix;
+ rev->patch_name_max = cfg->fmt_patch_name_max;
+ rev->show_signature = cfg->default_show_signature;
+ rev->encode_email_headers = cfg->default_encode_email_headers;
- if (default_date_mode)
- parse_date_format(default_date_mode, &rev->date_mode);
+ if (cfg->default_date_mode)
+ parse_date_format(cfg->default_date_mode, &rev->date_mode);
}
static void set_default_decoration_filter(struct decoration_filter *decoration_filter)
@@ -233,7 +248,8 @@ static void set_default_decoration_filter(struct decoration_filter *decoration_f
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
- struct rev_info *rev, struct setup_revision_opt *opt)
+ struct rev_info *rev, struct setup_revision_opt *opt,
+ struct log_config *cfg)
{
struct userformat_want w;
int quiet = 0, source = 0, mailmap;
@@ -258,7 +274,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
N_("pattern"), N_("only decorate refs that match <pattern>")),
OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
N_("pattern"), N_("do not decorate refs that match <pattern>")),
- OPT_CALLBACK_F(0, "decorate", NULL, NULL, N_("decorate options"),
+ OPT_CALLBACK_F(0, "decorate", cfg, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback),
OPT_CALLBACK('L', NULL, &line_cb, "range:file",
N_("trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
@@ -269,7 +285,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
line_cb.rev = rev;
line_cb.prefix = prefix;
- mailmap = use_mailmap_config;
+ mailmap = cfg->use_mailmap_config;
argc = parse_options(argc, argv, prefix,
builtin_log_options, builtin_log_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
@@ -314,8 +330,8 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
* "log --pretty=raw" is special; ignore UI oriented
* configuration variables such as decoration.
*/
- if (!decoration_given)
- decoration_style = 0;
+ if (!cfg->decoration_given)
+ cfg->decoration_style = 0;
if (!rev->abbrev_commit_given)
rev->abbrev_commit = 0;
}
@@ -326,24 +342,24 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
* Disable decoration loading if the format will not
* show them anyway.
*/
- decoration_style = 0;
- } else if (!decoration_style) {
+ cfg->decoration_style = 0;
+ } else if (!cfg->decoration_style) {
/*
* If we are going to show them, make sure we do load
* them here, but taking care not to override a
* specific style set by config or --decorate.
*/
- decoration_style = DECORATE_SHORT_REFS;
+ cfg->decoration_style = DECORATE_SHORT_REFS;
}
}
- if (decoration_style || rev->simplify_by_decoration) {
+ if (cfg->decoration_style || rev->simplify_by_decoration) {
set_default_decoration_filter(&decoration_filter);
- if (decoration_style)
+ if (cfg->decoration_style)
rev->show_decorations = 1;
- load_ref_decorations(&decoration_filter, decoration_style);
+ load_ref_decorations(&decoration_filter, cfg->decoration_style);
}
if (rev->line_level_traverse)
@@ -353,16 +369,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
}
static void cmd_log_init(int argc, const char **argv, const char *prefix,
- struct rev_info *rev, struct setup_revision_opt *opt)
-{
- cmd_log_init_defaults(rev);
- cmd_log_init_finish(argc, argv, prefix, rev, opt);
-}
-
-static int cmd_log_deinit(int ret, struct rev_info *rev)
+ struct rev_info *rev, struct setup_revision_opt *opt,
+ struct log_config *cfg)
{
- release_revisions(rev);
- return ret;
+ cmd_log_init_defaults(rev, cfg);
+ cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg);
}
/*
@@ -566,30 +577,37 @@ static int cmd_log_walk(struct rev_info *rev)
static int git_log_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ struct log_config *cfg = cb;
const char *slot_name;
- if (!strcmp(var, "format.pretty"))
- return git_config_string(&fmt_pretty, var, value);
- if (!strcmp(var, "format.subjectprefix"))
- return git_config_string(&fmt_patch_subject_prefix, var, value);
+ if (!strcmp(var, "format.pretty")) {
+ FREE_AND_NULL(cfg->fmt_pretty);
+ return git_config_string(&cfg->fmt_pretty, var, value);
+ }
+ if (!strcmp(var, "format.subjectprefix")) {
+ FREE_AND_NULL(cfg->fmt_patch_subject_prefix);
+ return git_config_string(&cfg->fmt_patch_subject_prefix, var, value);
+ }
if (!strcmp(var, "format.filenamemaxlength")) {
- fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
+ cfg->fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "format.encodeemailheaders")) {
- default_encode_email_headers = git_config_bool(var, value);
+ cfg->default_encode_email_headers = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.abbrevcommit")) {
- default_abbrev_commit = git_config_bool(var, value);
+ cfg->default_abbrev_commit = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "log.date"))
- return git_config_string(&default_date_mode, var, value);
+ if (!strcmp(var, "log.date")) {
+ FREE_AND_NULL(cfg->default_date_mode);
+ return git_config_string(&cfg->default_date_mode, var, value);
+ }
if (!strcmp(var, "log.decorate")) {
- decoration_style = parse_decoration_style(value);
- if (decoration_style < 0)
- decoration_style = 0; /* maybe warn? */
+ cfg->decoration_style = parse_decoration_style(value);
+ if (cfg->decoration_style < 0)
+ cfg->decoration_style = 0; /* maybe warn? */
return 0;
}
if (!strcmp(var, "log.diffmerges")) {
@@ -598,21 +616,21 @@ static int git_log_config(const char *var, const char *value,
return diff_merges_config(value);
}
if (!strcmp(var, "log.showroot")) {
- default_show_root = git_config_bool(var, value);
+ cfg->default_show_root = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.follow")) {
- default_follow = git_config_bool(var, value);
+ cfg->default_follow = git_config_bool(var, value);
return 0;
}
if (skip_prefix(var, "color.decorate.", &slot_name))
return parse_decorate_color_config(var, slot_name, value);
if (!strcmp(var, "log.mailmap")) {
- use_mailmap_config = git_config_bool(var, value);
+ cfg->use_mailmap_config = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.showsignature")) {
- default_show_signature = git_config_bool(var, value);
+ cfg->default_show_signature = git_config_bool(var, value);
return 0;
}
@@ -621,11 +639,14 @@ static int git_log_config(const char *var, const char *value,
int cmd_whatchanged(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -635,10 +656,15 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
static void show_tagger(const char *buf, struct rev_info *rev)
@@ -733,14 +759,16 @@ static void show_setup_revisions_tweak(struct rev_info *rev)
int cmd_show(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
unsigned int i;
struct setup_revision_opt opt;
struct pathspec match_all;
int ret = 0;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
if (the_repository->gitdir) {
prepare_repo_settings(the_repository);
@@ -759,10 +787,14 @@ int cmd_show(int argc, const char **argv, const char *prefix)
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
opt.tweak = show_setup_revisions_tweak;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
- if (!rev.no_walk)
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ if (!rev.no_walk) {
+ ret = cmd_log_walk(&rev);
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
+ }
rev.diffopt.no_free = 1;
for (i = 0; i < rev.pending.nr && !ret; i++) {
@@ -832,8 +864,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
rev.diffopt.no_free = 0;
diff_free(&rev.diffopt);
+ release_revisions(&rev);
+ log_config_release(&cfg);
- return cmd_log_deinit(ret, &rev);
+ return ret;
}
/*
@@ -841,11 +875,14 @@ int cmd_show(int argc, const char **argv, const char *prefix)
*/
int cmd_log_reflog(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
init_reflog_walk(&rev.reflog_info);
@@ -854,14 +891,18 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
rev.verbose_header = 1;
memset(&opt, 0, sizeof(opt));
opt.def = "HEAD";
- cmd_log_init_defaults(&rev);
+ cmd_log_init_defaults(&rev, &cfg);
rev.abbrev_commit = 1;
rev.commit_format = CMIT_FMT_ONELINE;
rev.use_terminator = 1;
rev.always_show_header = 1;
- cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
+ cmd_log_init_finish(argc, argv, prefix, &rev, &opt, &cfg);
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
+ ret = cmd_log_walk(&rev);
+
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
static void log_setup_revisions_tweak(struct rev_info *rev)
@@ -876,11 +917,14 @@ static void log_setup_revisions_tweak(struct rev_info *rev)
int cmd_log(int argc, const char **argv, const char *prefix)
{
+ struct log_config cfg;
struct rev_info rev;
struct setup_revision_opt opt;
+ int ret;
- init_log_defaults();
- git_config(git_log_config, NULL);
+ log_config_init(&cfg);
+ init_diff_ui_defaults();
+ git_config(git_log_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
@@ -890,42 +934,17 @@ int cmd_log(int argc, const char **argv, const char *prefix)
opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH;
opt.tweak = log_setup_revisions_tweak;
- cmd_log_init(argc, argv, prefix, &rev, &opt);
- return cmd_log_deinit(cmd_log_walk(&rev), &rev);
-}
-
-/* format-patch */
-
-static const char *fmt_patch_suffix = ".patch";
-static int numbered = 0;
-static int auto_number = 1;
-
-static char *default_attach = NULL;
-
-static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
-static struct string_list extra_to = STRING_LIST_INIT_NODUP;
-static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
+ cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
-static void add_header(const char *value)
-{
- struct string_list_item *item;
- int len = strlen(value);
- while (len && value[len - 1] == '\n')
- len--;
-
- if (!strncasecmp(value, "to: ", 4)) {
- item = string_list_append(&extra_to, value + 4);
- len -= 4;
- } else if (!strncasecmp(value, "cc: ", 4)) {
- item = string_list_append(&extra_cc, value + 4);
- len -= 4;
- } else {
- item = string_list_append(&extra_hdr, value);
- }
+ ret = cmd_log_walk(&rev);
- item->string[len] = '\0';
+ release_revisions(&rev);
+ log_config_release(&cfg);
+ return ret;
}
+/* format-patch */
+
enum cover_setting {
COVER_UNSET,
COVER_OFF,
@@ -952,17 +971,61 @@ enum auto_base_setting {
AUTO_BASE_WHEN_ABLE
};
-static enum thread_level thread;
-static int do_signoff;
-static enum auto_base_setting auto_base;
-static char *from;
-static const char *signature = git_version_string;
-static const char *signature_file;
-static enum cover_setting config_cover_letter;
-static const char *config_output_directory;
-static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
-static int show_notes;
-static struct display_notes_opt notes_opt;
+struct format_config {
+ struct log_config log;
+ enum thread_level thread;
+ int do_signoff;
+ enum auto_base_setting auto_base;
+ char *base_commit;
+ char *from;
+ char *signature;
+ char *signature_file;
+ enum cover_setting config_cover_letter;
+ char *config_output_directory;
+ enum cover_from_description cover_from_description_mode;
+ int show_notes;
+ struct display_notes_opt notes_opt;
+ int numbered_cmdline_opt;
+ int numbered;
+ int auto_number;
+ char *default_attach;
+ struct string_list extra_hdr;
+ struct string_list extra_to;
+ struct string_list extra_cc;
+ int keep_subject;
+ int subject_prefix;
+ struct strbuf sprefix;
+ char *fmt_patch_suffix;
+};
+
+static void format_config_init(struct format_config *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+ log_config_init(&cfg->log);
+ cfg->cover_from_description_mode = COVER_FROM_MESSAGE;
+ cfg->auto_number = 1;
+ string_list_init_dup(&cfg->extra_hdr);
+ string_list_init_dup(&cfg->extra_to);
+ string_list_init_dup(&cfg->extra_cc);
+ strbuf_init(&cfg->sprefix, 0);
+ cfg->fmt_patch_suffix = xstrdup(".patch");
+}
+
+static void format_config_release(struct format_config *cfg)
+{
+ log_config_release(&cfg->log);
+ free(cfg->base_commit);
+ free(cfg->from);
+ free(cfg->signature);
+ free(cfg->signature_file);
+ free(cfg->config_output_directory);
+ free(cfg->default_attach);
+ string_list_clear(&cfg->extra_hdr, 0);
+ string_list_clear(&cfg->extra_to, 0);
+ string_list_clear(&cfg->extra_cc, 0);
+ strbuf_release(&cfg->sprefix);
+ free(cfg->fmt_patch_suffix);
+}
static enum cover_from_description parse_cover_from_description(const char *arg)
{
@@ -980,27 +1043,51 @@ static enum cover_from_description parse_cover_from_description(const char *arg)
die(_("%s: invalid cover from description mode"), arg);
}
+static void add_header(struct format_config *cfg, const char *value)
+{
+ struct string_list_item *item;
+ int len = strlen(value);
+ while (len && value[len - 1] == '\n')
+ len--;
+
+ if (!strncasecmp(value, "to: ", 4)) {
+ item = string_list_append(&cfg->extra_to, value + 4);
+ len -= 4;
+ } else if (!strncasecmp(value, "cc: ", 4)) {
+ item = string_list_append(&cfg->extra_cc, value + 4);
+ len -= 4;
+ } else {
+ item = string_list_append(&cfg->extra_hdr, value);
+ }
+
+ item->string[len] = '\0';
+}
+
static int git_format_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
+ struct format_config *cfg = cb;
+
if (!strcmp(var, "format.headers")) {
if (!value)
die(_("format.headers without value"));
- add_header(value);
+ add_header(cfg, value);
return 0;
}
- if (!strcmp(var, "format.suffix"))
- return git_config_string(&fmt_patch_suffix, var, value);
+ if (!strcmp(var, "format.suffix")) {
+ FREE_AND_NULL(cfg->fmt_patch_suffix);
+ return git_config_string(&cfg->fmt_patch_suffix, var, value);
+ }
if (!strcmp(var, "format.to")) {
if (!value)
return config_error_nonbool(var);
- string_list_append(&extra_to, value);
+ string_list_append(&cfg->extra_to, value);
return 0;
}
if (!strcmp(var, "format.cc")) {
if (!value)
return config_error_nonbool(var);
- string_list_append(&extra_cc, value);
+ string_list_append(&cfg->extra_cc, value);
return 0;
}
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
@@ -1009,69 +1096,76 @@ static int git_format_config(const char *var, const char *value,
}
if (!strcmp(var, "format.numbered")) {
if (value && !strcasecmp(value, "auto")) {
- auto_number = 1;
+ cfg->auto_number = 1;
return 0;
}
- numbered = git_config_bool(var, value);
- auto_number = auto_number && numbered;
+ cfg->numbered = git_config_bool(var, value);
+ cfg->auto_number = cfg->auto_number && cfg->numbered;
return 0;
}
if (!strcmp(var, "format.attach")) {
- if (value && *value)
- default_attach = xstrdup(value);
- else if (value && !*value)
- FREE_AND_NULL(default_attach);
- else
- default_attach = xstrdup(git_version_string);
+ if (value && *value) {
+ FREE_AND_NULL(cfg->default_attach);
+ cfg->default_attach = xstrdup(value);
+ } else if (value && !*value) {
+ FREE_AND_NULL(cfg->default_attach);
+ } else {
+ FREE_AND_NULL(cfg->default_attach);
+ cfg->default_attach = xstrdup(git_version_string);
+ }
return 0;
}
if (!strcmp(var, "format.thread")) {
if (value && !strcasecmp(value, "deep")) {
- thread = THREAD_DEEP;
+ cfg->thread = THREAD_DEEP;
return 0;
}
if (value && !strcasecmp(value, "shallow")) {
- thread = THREAD_SHALLOW;
+ cfg->thread = THREAD_SHALLOW;
return 0;
}
- thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
+ cfg->thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
return 0;
}
if (!strcmp(var, "format.signoff")) {
- do_signoff = git_config_bool(var, value);
+ cfg->do_signoff = git_config_bool(var, value);
return 0;
}
- if (!strcmp(var, "format.signature"))
- return git_config_string(&signature, var, value);
- if (!strcmp(var, "format.signaturefile"))
- return git_config_pathname(&signature_file, var, value);
+ if (!strcmp(var, "format.signature")) {
+ FREE_AND_NULL(cfg->signature);
+ return git_config_string(&cfg->signature, var, value);
+ }
+ if (!strcmp(var, "format.signaturefile")) {
+ FREE_AND_NULL(cfg->signature_file);
+ return git_config_pathname(&cfg->signature_file, var, value);
+ }
if (!strcmp(var, "format.coverletter")) {
if (value && !strcasecmp(value, "auto")) {
- config_cover_letter = COVER_AUTO;
+ cfg->config_cover_letter = COVER_AUTO;
return 0;
}
- config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+ cfg->config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
return 0;
}
- if (!strcmp(var, "format.outputdirectory"))
- return git_config_string(&config_output_directory, var, value);
+ if (!strcmp(var, "format.outputdirectory")) {
+ FREE_AND_NULL(cfg->config_output_directory);
+ return git_config_string(&cfg->config_output_directory, var, value);
+ }
if (!strcmp(var, "format.useautobase")) {
if (value && !strcasecmp(value, "whenAble")) {
- auto_base = AUTO_BASE_WHEN_ABLE;
+ cfg->auto_base = AUTO_BASE_WHEN_ABLE;
return 0;
}
- auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
+ cfg->auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
return 0;
}
if (!strcmp(var, "format.from")) {
int b = git_parse_maybe_bool(value);
- free(from);
+ FREE_AND_NULL(cfg->from);
if (b < 0)
- from = xstrdup(value);
+ cfg->from = xstrdup(value);
else if (b)
- from = xstrdup(git_committer_info(IDENT_NO_DATE));
- else
- from = NULL;
+ cfg->from = xstrdup(git_committer_info(IDENT_NO_DATE));
return 0;
}
if (!strcmp(var, "format.forceinbodyfrom")) {
@@ -1081,15 +1175,15 @@ static int git_format_config(const char *var, const char *value,
if (!strcmp(var, "format.notes")) {
int b = git_parse_maybe_bool(value);
if (b < 0)
- enable_ref_display_notes(&notes_opt, &show_notes, value);
+ enable_ref_display_notes(&cfg->notes_opt, &cfg->show_notes, value);
else if (b)
- enable_default_display_notes(&notes_opt, &show_notes);
+ enable_default_display_notes(&cfg->notes_opt, &cfg->show_notes);
else
- disable_display_notes(&notes_opt, &show_notes);
+ disable_display_notes(&cfg->notes_opt, &cfg->show_notes);
return 0;
}
if (!strcmp(var, "format.coverfromdescription")) {
- cover_from_description_mode = parse_cover_from_description(value);
+ cfg->cover_from_description_mode = parse_cover_from_description(value);
return 0;
}
if (!strcmp(var, "format.mboxrd")) {
@@ -1110,7 +1204,7 @@ static int git_format_config(const char *var, const char *value,
if (!strcmp(var, "diff.noprefix"))
return 0;
- return git_log_config(var, value, ctx, cb);
+ return git_log_config(var, value, ctx, &cfg->log);
}
static const char *output_directory = NULL;
@@ -1198,7 +1292,7 @@ static void gen_message_id(struct rev_info *info, char *base)
info->message_id = strbuf_detach(&buf, NULL);
}
-static void print_signature(FILE *file)
+static void print_signature(const char *signature, FILE *file)
{
if (!signature || !*signature)
return;
@@ -1268,14 +1362,15 @@ static void prepare_cover_text(struct pretty_print_context *pp,
const char *branch_name,
struct strbuf *sb,
const char *encoding,
- int need_8bit_cte)
+ int need_8bit_cte,
+ const struct format_config *cfg)
{
const char *subject = "*** SUBJECT HERE ***";
const char *body = "*** BLURB HERE ***";
struct strbuf description_sb = STRBUF_INIT;
struct strbuf subject_sb = STRBUF_INIT;
- if (cover_from_description_mode == COVER_FROM_NONE)
+ if (cfg->cover_from_description_mode == COVER_FROM_NONE)
goto do_pp;
if (description_file && *description_file)
@@ -1285,13 +1380,13 @@ static void prepare_cover_text(struct pretty_print_context *pp,
if (!description_sb.len)
goto do_pp;
- if (cover_from_description_mode == COVER_FROM_SUBJECT ||
- cover_from_description_mode == COVER_FROM_AUTO)
+ if (cfg->cover_from_description_mode == COVER_FROM_SUBJECT ||
+ cfg->cover_from_description_mode == COVER_FROM_AUTO)
body = format_subject(&subject_sb, description_sb.buf, " ");
- if (cover_from_description_mode == COVER_FROM_MESSAGE ||
- (cover_from_description_mode == COVER_FROM_AUTO &&
- subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+ if (cfg->cover_from_description_mode == COVER_FROM_MESSAGE ||
+ (cfg->cover_from_description_mode == COVER_FROM_AUTO &&
+ subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
body = description_sb.buf;
else
subject = subject_sb.buf;
@@ -1328,7 +1423,8 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
int nr, struct commit **list,
const char *description_file,
const char *branch_name,
- int quiet)
+ int quiet,
+ const struct format_config *cfg)
{
const char *committer;
struct shortlog log;
@@ -1367,7 +1463,7 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
pp.encode_email_headers = rev->encode_email_headers;
pp_user_info(&pp, NULL, &sb, committer, encoding);
prepare_cover_text(&pp, description_file, branch_name, &sb,
- encoding, need_8bit_cte);
+ encoding, need_8bit_cte, cfg);
fprintf(rev->diffopt.file, "%s\n", sb.buf);
free(pp.after_subject);
@@ -1468,29 +1564,30 @@ static const char * const builtin_format_patch_usage[] = {
NULL
};
-static int keep_subject = 0;
+struct keep_callback_data {
+ struct format_config *cfg;
+ struct rev_info *revs;
+};
static int keep_callback(const struct option *opt, const char *arg, int unset)
{
+ struct keep_callback_data *data = opt->value;
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- ((struct rev_info *)opt->value)->total = -1;
- keep_subject = 1;
+ data->revs->total = -1;
+ data->cfg->keep_subject = 1;
return 0;
}
-static int subject_prefix = 0;
-
static int subject_prefix_callback(const struct option *opt, const char *arg,
int unset)
{
- struct strbuf *sprefix;
+ struct format_config *cfg = opt->value;
BUG_ON_OPT_NEG(unset);
- sprefix = opt->value;
- subject_prefix = 1;
- strbuf_reset(sprefix);
- strbuf_addstr(sprefix, arg);
+ cfg->subject_prefix = 1;
+ strbuf_reset(&cfg->sprefix);
+ strbuf_addstr(&cfg->sprefix, arg);
return 0;
}
@@ -1507,15 +1604,14 @@ static int rfc_callback(const struct option *opt, const char *arg,
return 0;
}
-static int numbered_cmdline_opt = 0;
-
static int numbered_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct format_config *cfg = opt->value;
BUG_ON_OPT_ARG(arg);
- *(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;
+ cfg->numbered = cfg->numbered_cmdline_opt = unset ? 0 : 1;
if (unset)
- auto_number = 0;
+ cfg->auto_number = 0;
return 0;
}
@@ -1539,13 +1635,14 @@ static int output_directory_callback(const struct option *opt, const char *arg,
static int thread_callback(const struct option *opt, const char *arg, int unset)
{
- enum thread_level *thread = (enum thread_level *)opt->value;
+ struct format_config *cfg = opt->value;
+
if (unset)
- *thread = THREAD_UNSET;
+ cfg->thread = THREAD_UNSET;
else if (!arg || !strcmp(arg, "shallow"))
- *thread = THREAD_SHALLOW;
+ cfg->thread = THREAD_SHALLOW;
else if (!strcmp(arg, "deep"))
- *thread = THREAD_DEEP;
+ cfg->thread = THREAD_DEEP;
/*
* Please update _git_formatpatch() in git-completion.bash
* when you add new options.
@@ -1581,15 +1678,17 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
-static int header_callback(const struct option *opt UNUSED, const char *arg,
+static int header_callback(const struct option *opt, const char *arg,
int unset)
{
+ struct format_config *cfg = opt->value;
+
if (unset) {
- string_list_clear(&extra_hdr, 0);
- string_list_clear(&extra_to, 0);
- string_list_clear(&extra_cc, 0);
+ string_list_clear(&cfg->extra_hdr, 0);
+ string_list_clear(&cfg->extra_to, 0);
+ string_list_clear(&cfg->extra_cc, 0);
} else {
- add_header(arg);
+ add_header(cfg, arg);
}
return 0;
}
@@ -1611,17 +1710,17 @@ static int from_callback(const struct option *opt, const char *arg, int unset)
static int base_callback(const struct option *opt, const char *arg, int unset)
{
- const char **base_commit = opt->value;
+ struct format_config *cfg = opt->value;
if (unset) {
- auto_base = AUTO_BASE_NEVER;
- *base_commit = NULL;
+ cfg->auto_base = AUTO_BASE_NEVER;
+ FREE_AND_NULL(cfg->base_commit);
} else if (!strcmp(arg, "auto")) {
- auto_base = AUTO_BASE_ALWAYS;
- *base_commit = NULL;
+ cfg->auto_base = AUTO_BASE_ALWAYS;
+ FREE_AND_NULL(cfg->base_commit);
} else {
- auto_base = AUTO_BASE_NEVER;
- *base_commit = arg;
+ cfg->auto_base = AUTO_BASE_NEVER;
+ cfg->base_commit = xstrdup(arg);
}
return 0;
}
@@ -1632,7 +1731,7 @@ struct base_tree_info {
struct object_id *patch_id;
};
-static struct commit *get_base_commit(const char *base_commit,
+static struct commit *get_base_commit(const struct format_config *cfg,
struct commit **list,
int total)
{
@@ -1640,9 +1739,9 @@ static struct commit *get_base_commit(const char *base_commit,
struct commit **rev;
int i = 0, rev_nr = 0, auto_select, die_on_failure, ret;
- switch (auto_base) {
+ switch (cfg->auto_base) {
case AUTO_BASE_NEVER:
- if (base_commit) {
+ if (cfg->base_commit) {
auto_select = 0;
die_on_failure = 1;
} else {
@@ -1652,11 +1751,11 @@ static struct commit *get_base_commit(const char *base_commit,
break;
case AUTO_BASE_ALWAYS:
case AUTO_BASE_WHEN_ABLE:
- if (base_commit) {
+ if (cfg->base_commit) {
BUG("requested automatic base selection but a commit was provided");
} else {
auto_select = 1;
- die_on_failure = auto_base == AUTO_BASE_ALWAYS;
+ die_on_failure = cfg->auto_base == AUTO_BASE_ALWAYS;
}
break;
default:
@@ -1664,9 +1763,9 @@ static struct commit *get_base_commit(const char *base_commit,
}
if (!auto_select) {
- base = lookup_commit_reference_by_name(base_commit);
+ base = lookup_commit_reference_by_name(cfg->base_commit);
if (!base)
- die(_("unknown commit %s"), base_commit);
+ die(_("unknown commit %s"), cfg->base_commit);
} else {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
@@ -1884,6 +1983,7 @@ static void infer_range_diff_ranges(struct strbuf *r1,
int cmd_format_patch(int argc, const char **argv, const char *prefix)
{
+ struct format_config cfg;
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
@@ -1908,7 +2008,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char *cover_from_description_arg = NULL;
char *description_file = NULL;
char *branch_name = NULL;
- char *base_commit = NULL;
struct base_tree_info bases;
struct commit *base;
int show_progress = 0;
@@ -1919,18 +2018,24 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
- struct strbuf sprefix = STRBUF_INIT;
const char *rfc = NULL;
int creation_factor = -1;
+ const char *signature = git_version_string;
+ const char *signature_file_arg = NULL;
+ struct keep_callback_data keep_callback_data = {
+ .cfg = &cfg,
+ .revs = &rev,
+ };
+ const char *fmt_patch_suffix = NULL;
const struct option builtin_format_patch_options[] = {
- OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
+ OPT_CALLBACK_F('n', "numbered", &cfg, NULL,
N_("use [PATCH n/m] even with a single patch"),
PARSE_OPT_NOARG, numbered_callback),
- OPT_CALLBACK_F('N', "no-numbered", &numbered, NULL,
+ OPT_CALLBACK_F('N', "no-numbered", &cfg, NULL,
N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
- OPT_BOOL('s', "signoff", &do_signoff, N_("add a Signed-off-by trailer")),
+ OPT_BOOL('s', "signoff", &cfg.do_signoff, N_("add a Signed-off-by trailer")),
OPT_BOOL(0, "stdout", &use_stdout,
N_("print patches to standard out")),
OPT_BOOL(0, "cover-letter", &cover_letter,
@@ -1943,7 +2048,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("start numbering patches at <n> instead of 1")),
OPT_STRING('v', "reroll-count", &reroll_count, N_("reroll-count"),
N_("mark the series as Nth re-roll")),
- OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
+ OPT_INTEGER(0, "filename-max-length", &cfg.log.fmt_patch_name_max,
N_("max length of output filename")),
OPT_CALLBACK_F(0, "rfc", &rfc, N_("rfc"),
N_("add <rfc> (default 'RFC') before 'PATCH'"),
@@ -1953,13 +2058,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("generate parts of a cover letter based on a branch's description")),
OPT_FILENAME(0, "description-file", &description_file,
N_("use branch description from file")),
- OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
+ OPT_CALLBACK_F(0, "subject-prefix", &cfg, N_("prefix"),
N_("use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback),
OPT_CALLBACK_F('o', "output-directory", &output_directory,
N_("dir"), N_("store resulting files in <dir>"),
PARSE_OPT_NONEG, output_directory_callback),
- OPT_CALLBACK_F('k', "keep-subject", &rev, NULL,
+ OPT_CALLBACK_F('k', "keep-subject", &keep_callback_data, NULL,
N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback),
OPT_BOOL(0, "no-binary", &no_binary_diff,
@@ -1972,11 +2077,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("show patch format instead of default (patch + stat)"),
1, PARSE_OPT_NONEG),
OPT_GROUP(N_("Messaging")),
- OPT_CALLBACK(0, "add-header", NULL, N_("header"),
+ OPT_CALLBACK(0, "add-header", &cfg, N_("header"),
N_("add email header"), header_callback),
- OPT_STRING_LIST(0, "to", &extra_to, N_("email"), N_("add To: header")),
- OPT_STRING_LIST(0, "cc", &extra_cc, N_("email"), N_("add Cc: header")),
- OPT_CALLBACK_F(0, "from", &from, N_("ident"),
+ OPT_STRING_LIST(0, "to", &cfg.extra_to, N_("email"), N_("add To: header")),
+ OPT_STRING_LIST(0, "cc", &cfg.extra_cc, N_("email"), N_("add Cc: header")),
+ OPT_CALLBACK_F(0, "from", &cfg.from, N_("ident"),
N_("set From address to <ident> (or committer ident if absent)"),
PARSE_OPT_OPTARG, from_callback),
OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
@@ -1988,15 +2093,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
N_("inline the patch"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
inline_callback),
- OPT_CALLBACK_F(0, "thread", &thread, N_("style"),
+ OPT_CALLBACK_F(0, "thread", &cfg, N_("style"),
N_("enable message threading, styles: shallow, deep"),
PARSE_OPT_OPTARG, thread_callback),
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_CALLBACK_F(0, "base", &base_commit, N_("base-commit"),
+ OPT_CALLBACK_F(0, "base", &cfg, N_("base-commit"),
N_("add prerequisite tree info to the patch series"),
0, base_callback),
- OPT_FILENAME(0, "signature-file", &signature_file,
+ OPT_FILENAME(0, "signature-file", &signature_file_arg,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_BOOL(0, "progress", &show_progress,
@@ -2013,20 +2118,17 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT_END()
};
- extra_hdr.strdup_strings = 1;
- extra_to.strdup_strings = 1;
- extra_cc.strdup_strings = 1;
-
- init_log_defaults();
- init_display_notes(&notes_opt);
- git_config(git_format_config, NULL);
+ format_config_init(&cfg);
+ init_diff_ui_defaults();
+ init_display_notes(&cfg.notes_opt);
+ git_config(git_format_config, &cfg);
repo_init_revisions(the_repository, &rev, prefix);
git_config(grep_config, &rev.grep_filter);
- rev.show_notes = show_notes;
- memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
+ rev.show_notes = cfg.show_notes;
+ memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
rev.commit_format = CMIT_FMT_EMAIL;
- rev.encode_email_headers = default_encode_email_headers;
+ rev.encode_email_headers = cfg.log.default_encode_email_headers;
rev.expand_tabs_in_log_default = 0;
rev.verbose_header = 1;
rev.diff = 1;
@@ -2037,12 +2139,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
- strbuf_addstr(&sprefix, fmt_patch_subject_prefix);
+ strbuf_addstr(&cfg.sprefix, cfg.log.fmt_patch_subject_prefix);
if (format_no_prefix)
diff_set_noprefix(&rev.diffopt);
- if (default_attach) {
- rev.mime_boundary = default_attach;
+ if (cfg.default_attach) {
+ rev.mime_boundary = cfg.default_attach;
rev.no_inline = 1;
}
@@ -2058,60 +2160,63 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.force_in_body_from = force_in_body_from;
+ if (!fmt_patch_suffix)
+ fmt_patch_suffix = cfg.fmt_patch_suffix;
+
/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
- if (fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
- fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
+ if (cfg.log.fmt_patch_name_max <= strlen("0000-") + strlen(fmt_patch_suffix))
+ cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
if (cover_from_description_arg)
- cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+ cfg.cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
if (rfc && rfc[0]) {
- subject_prefix = 1;
+ cfg.subject_prefix = 1;
if (rfc[0] == '-')
- strbuf_addf(&sprefix, " %s", rfc + 1);
+ strbuf_addf(&cfg.sprefix, " %s", rfc + 1);
else
- strbuf_insertf(&sprefix, 0, "%s ", rfc);
+ strbuf_insertf(&cfg.sprefix, 0, "%s ", rfc);
}
if (reroll_count) {
- strbuf_addf(&sprefix, " v%s", reroll_count);
+ strbuf_addf(&cfg.sprefix, " v%s", reroll_count);
rev.reroll_count = reroll_count;
}
- rev.subject_prefix = sprefix.buf;
+ rev.subject_prefix = cfg.sprefix.buf;
- for (i = 0; i < extra_hdr.nr; i++) {
- strbuf_addstr(&buf, extra_hdr.items[i].string);
+ for (i = 0; i < cfg.extra_hdr.nr; i++) {
+ strbuf_addstr(&buf, cfg.extra_hdr.items[i].string);
strbuf_addch(&buf, '\n');
}
- if (extra_to.nr)
+ if (cfg.extra_to.nr)
strbuf_addstr(&buf, "To: ");
- for (i = 0; i < extra_to.nr; i++) {
+ for (i = 0; i < cfg.extra_to.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
- strbuf_addstr(&buf, extra_to.items[i].string);
- if (i + 1 < extra_to.nr)
+ strbuf_addstr(&buf, cfg.extra_to.items[i].string);
+ if (i + 1 < cfg.extra_to.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
- if (extra_cc.nr)
+ if (cfg.extra_cc.nr)
strbuf_addstr(&buf, "Cc: ");
- for (i = 0; i < extra_cc.nr; i++) {
+ for (i = 0; i < cfg.extra_cc.nr; i++) {
if (i)
strbuf_addstr(&buf, " ");
- strbuf_addstr(&buf, extra_cc.items[i].string);
- if (i + 1 < extra_cc.nr)
+ strbuf_addstr(&buf, cfg.extra_cc.items[i].string);
+ if (i + 1 < cfg.extra_cc.nr)
strbuf_addch(&buf, ',');
strbuf_addch(&buf, '\n');
}
rev.extra_headers = to_free = strbuf_detach(&buf, NULL);
- if (from) {
- if (split_ident_line(&rev.from_ident, from, strlen(from)))
- die(_("invalid ident line: %s"), from);
+ if (cfg.from) {
+ if (split_ident_line(&rev.from_ident, cfg.from, strlen(cfg.from)))
+ die(_("invalid ident line: %s"), cfg.from);
}
if (start_number < 0)
@@ -2122,14 +2227,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
- if (numbered && keep_subject && !numbered_cmdline_opt)
- numbered = 0;
+ if (cfg.numbered && cfg.keep_subject && !cfg.numbered_cmdline_opt)
+ cfg.numbered = 0;
- if (numbered && keep_subject)
+ if (cfg.numbered && cfg.keep_subject)
die(_("options '%s' and '%s' cannot be used together"), "-n", "-k");
- if (keep_subject && subject_prefix)
+ if (cfg.keep_subject && cfg.subject_prefix)
die(_("options '%s' and '%s' cannot be used together"), "--subject-prefix/--rfc", "-k");
- rev.preserve_subject = keep_subject;
+ rev.preserve_subject = cfg.keep_subject;
argc = setup_revisions(argc, argv, &rev, &s_r_opt);
if (argc > 1)
@@ -2156,7 +2261,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.always_show_header = 1;
rev.zero_commit = zero_commit;
- rev.patch_name_max = fmt_patch_name_max;
+ rev.patch_name_max = cfg.log.fmt_patch_name_max;
if (!rev.diffopt.flags.text && !no_binary_diff)
rev.diffopt.flags.binary = 1;
@@ -2177,7 +2282,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int saved;
if (!output_directory)
- output_directory = config_output_directory;
+ output_directory = cfg.config_output_directory;
output_directory = set_outdir(prefix, output_directory);
if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
@@ -2275,14 +2380,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
goto done;
total = nr;
if (cover_letter == -1) {
- if (config_cover_letter == COVER_AUTO)
+ if (cfg.config_cover_letter == COVER_AUTO)
cover_letter = (total > 1);
else
- cover_letter = (config_cover_letter == COVER_ON);
+ cover_letter = (cfg.config_cover_letter == COVER_ON);
}
- if (!keep_subject && auto_number && (total > 1 || cover_letter))
- numbered = 1;
- if (numbered)
+ if (!cfg.keep_subject && cfg.auto_number && (total > 1 || cover_letter))
+ cfg.numbered = 1;
+ if (cfg.numbered)
rev.total = total + start_number - 1;
if (idiff_prev.nr) {
@@ -2314,27 +2419,40 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
_("Range-diff against v%d:"));
}
+ /*
+ * The order of precedence is:
+ *
+ * 1. The `--signature` and `--no-signature` options.
+ * 2. The `--signature-file` option.
+ * 3. The `format.signature` config.
+ * 4. The `format.signatureFile` config.
+ * 5. Default `git_version_string`.
+ */
if (!signature) {
; /* --no-signature inhibits all signatures */
} else if (signature && signature != git_version_string) {
; /* non-default signature already set */
- } else if (signature_file) {
+ } else if (signature_file_arg || (cfg.signature_file && !cfg.signature)) {
struct strbuf buf = STRBUF_INIT;
+ const char *signature_file = signature_file_arg ?
+ signature_file_arg : cfg.signature_file;
if (strbuf_read_file(&buf, signature_file, 128) < 0)
die_errno(_("unable to read signature file '%s'"), signature_file);
signature = strbuf_detach(&buf, NULL);
+ } else if (cfg.signature) {
+ signature = cfg.signature;
}
memset(&bases, 0, sizeof(bases));
- base = get_base_commit(base_commit, list, nr);
+ base = get_base_commit(&cfg, list, nr);
if (base) {
reset_revision_walk();
clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);
}
- if (in_reply_to || thread || cover_letter) {
+ if (in_reply_to || cfg.thread || cover_letter) {
rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
string_list_init_dup(rev.ref_message_ids);
}
@@ -2345,19 +2463,19 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.numbered_files = just_numbers;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
- if (thread)
+ if (cfg.thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, !!output_directory,
- origin, nr, list, description_file, branch_name, quiet);
+ origin, nr, list, description_file, branch_name, quiet, &cfg);
print_bases(&bases, rev.diffopt.file);
- print_signature(rev.diffopt.file);
+ print_signature(signature, rev.diffopt.file);
total++;
start_number--;
/* interdiff/range-diff in cover-letter; omit from patches */
rev.idiff_oid1 = NULL;
rev.rdiff1 = NULL;
}
- rev.add_signoff = do_signoff;
+ rev.add_signoff = cfg.do_signoff;
if (show_progress)
progress = start_delayed_progress(_("Generating patches"), total);
@@ -2367,7 +2485,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
commit = list[nr];
rev.nr = total - nr + (start_number - 1);
/* Make the second and subsequent mails replies to the first */
- if (thread) {
+ if (cfg.thread) {
/* Have we already had a message ID? */
if (rev.message_id) {
/*
@@ -2391,7 +2509,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
* letter is a reply to the
* --in-reply-to, if specified.
*/
- if (thread == THREAD_SHALLOW
+ if (cfg.thread == THREAD_SHALLOW
&& rev.ref_message_ids->nr > 0
&& (!cover_letter || rev.nr > 1))
free(rev.message_id);
@@ -2424,7 +2542,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
mime_boundary_leader,
rev.mime_boundary);
else
- print_signature(rev.diffopt.file);
+ print_signature(signature, rev.diffopt.file);
}
if (output_directory)
fclose(rev.diffopt.file);
@@ -2432,9 +2550,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
stop_progress(&progress);
free(list);
free(branch_name);
- string_list_clear(&extra_to, 0);
- string_list_clear(&extra_cc, 0);
- string_list_clear(&extra_hdr, 0);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
@@ -2444,13 +2559,14 @@ done:
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
- strbuf_release(&sprefix);
free(to_free);
free(rev.message_id);
if (rev.ref_message_ids)
string_list_clear(rev.ref_message_ids, 0);
free(rev.ref_message_ids);
- return cmd_log_deinit(0, &rev);
+ release_revisions(&rev);
+ format_config_release(&cfg);
+ return 0;
}
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
diff --git a/builtin/merge.c b/builtin/merge.c
index e4bd65eeba..daed2d4e1e 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -100,7 +100,7 @@ static struct strategy all_strategy[] = {
{ "subtree", NO_FAST_FORWARD | NO_TRIVIAL },
};
-static const char *pull_twohead, *pull_octopus;
+static char *pull_twohead, *pull_octopus;
enum ff_type {
FF_NO,
@@ -110,7 +110,7 @@ enum ff_type {
static enum ff_type fast_forward = FF_ALLOW;
-static const char *cleanup_arg;
+static char *cleanup_arg;
static enum commit_msg_cleanup_mode cleanup_mode;
static int option_parse_message(const struct option *opt,
diff --git a/builtin/mv.c b/builtin/mv.c
index 74aa9746aa..81ca910de6 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -20,6 +20,7 @@
#include "read-cache-ll.h"
#include "repository.h"
#include "setup.h"
+#include "strvec.h"
#include "submodule.h"
#include "entry.h"
@@ -38,45 +39,35 @@ enum update_mode {
#define DUP_BASENAME 1
#define KEEP_TRAILING_SLASH 2
-static const char **internal_prefix_pathspec(const char *prefix,
- const char **pathspec,
- int count, unsigned flags)
+static void internal_prefix_pathspec(struct strvec *out,
+ const char *prefix,
+ const char **pathspec,
+ int count, unsigned flags)
{
- int i;
- const char **result;
int prefixlen = prefix ? strlen(prefix) : 0;
- ALLOC_ARRAY(result, count + 1);
/* Create an intermediate copy of the pathspec based on the flags */
- for (i = 0; i < count; i++) {
- int length = strlen(pathspec[i]);
- int to_copy = length;
- char *it;
+ for (int i = 0; i < count; i++) {
+ size_t length = strlen(pathspec[i]);
+ size_t to_copy = length;
+ const char *maybe_basename;
+ char *trimmed, *prefixed_path;
+
while (!(flags & KEEP_TRAILING_SLASH) &&
to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
to_copy--;
- it = xmemdupz(pathspec[i], to_copy);
- if (flags & DUP_BASENAME) {
- result[i] = xstrdup(basename(it));
- free(it);
- } else {
- result[i] = it;
- }
- }
- result[count] = NULL;
+ trimmed = xmemdupz(pathspec[i], to_copy);
+ maybe_basename = (flags & DUP_BASENAME) ? basename(trimmed) : trimmed;
+ prefixed_path = prefix_path(prefix, prefixlen, maybe_basename);
+ strvec_push(out, prefixed_path);
- /* Prefix the pathspec and free the old intermediate strings */
- for (i = 0; i < count; i++) {
- const char *match = prefix_path(prefix, prefixlen, result[i]);
- free((char *) result[i]);
- result[i] = match;
+ free(prefixed_path);
+ free(trimmed);
}
-
- return result;
}
-static const char *add_slash(const char *path)
+static char *add_slash(const char *path)
{
size_t len = strlen(path);
if (len && path[len - 1] != '/') {
@@ -86,32 +77,34 @@ static const char *add_slash(const char *path)
with_slash[len] = 0;
return with_slash;
}
- return path;
+ return xstrdup(path);
}
#define SUBMODULE_WITH_GITDIR ((const char *)1)
-static void prepare_move_submodule(const char *src, int first,
- const char **submodule_gitfile)
+static const char *submodule_gitfile_path(const char *src, int first)
{
struct strbuf submodule_dotgit = STRBUF_INIT;
+ const char *path;
+
if (!S_ISGITLINK(the_repository->index->cache[first]->ce_mode))
die(_("Directory %s is in index and no submodule?"), src);
if (!is_staging_gitmodules_ok(the_repository->index))
die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+
strbuf_addf(&submodule_dotgit, "%s/.git", src);
- *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
- if (*submodule_gitfile)
- *submodule_gitfile = xstrdup(*submodule_gitfile);
- else
- *submodule_gitfile = SUBMODULE_WITH_GITDIR;
+
+ path = read_gitfile(submodule_dotgit.buf);
strbuf_release(&submodule_dotgit);
+ if (path)
+ return path;
+ return SUBMODULE_WITH_GITDIR;
}
static int index_range_of_same_dir(const char *src, int length,
int *first_p, int *last_p)
{
- const char *src_w_slash = add_slash(src);
+ char *src_w_slash = add_slash(src);
int first, last, len_w_slash = length + 1;
first = index_name_pos(the_repository->index, src_w_slash, len_w_slash);
@@ -124,8 +117,8 @@ static int index_range_of_same_dir(const char *src, int length,
if (strncmp(path, src_w_slash, len_w_slash))
break;
}
- if (src_w_slash != src)
- free((char *)src_w_slash);
+
+ free(src_w_slash);
*first_p = first;
*last_p = last;
return last - first;
@@ -141,7 +134,7 @@ static int index_range_of_same_dir(const char *src, int length,
static int empty_dir_has_sparse_contents(const char *name)
{
int ret = 0;
- const char *with_slash = add_slash(name);
+ char *with_slash = add_slash(name);
int length = strlen(with_slash);
int pos = index_name_pos(the_repository->index, with_slash, length);
@@ -159,8 +152,7 @@ static int empty_dir_has_sparse_contents(const char *name)
}
free_return:
- if (with_slash != name)
- free((char *)with_slash);
+ free(with_slash);
return ret;
}
@@ -177,18 +169,23 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "sparse", &ignore_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
OPT_END(),
};
- const char **source, **destination, **dest_path, **submodule_gitfile;
- const char *dst_w_slash;
+ struct strvec sources = STRVEC_INIT;
+ struct strvec dest_paths = STRVEC_INIT;
+ struct strvec destinations = STRVEC_INIT;
+ struct strvec submodule_gitfiles_to_free = STRVEC_INIT;
+ const char **submodule_gitfiles;
+ char *dst_w_slash = NULL;
const char **src_dir = NULL;
int src_dir_nr = 0, src_dir_alloc = 0;
struct strbuf a_src_dir = STRBUF_INIT;
enum update_mode *modes, dst_mode = 0;
struct stat st, dest_st;
- struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ struct string_list src_for_dst = STRING_LIST_INIT_DUP;
struct lock_file lock_file = LOCK_INIT;
struct cache_entry *ce;
- struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
- struct string_list dirty_paths = STRING_LIST_INIT_NODUP;
+ struct string_list only_match_skip_worktree = STRING_LIST_INIT_DUP;
+ struct string_list dirty_paths = STRING_LIST_INIT_DUP;
+ int ret;
git_config(git_default_config, NULL);
@@ -201,7 +198,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));
- source = internal_prefix_pathspec(prefix, argv, argc, 0);
+ internal_prefix_pathspec(&sources, prefix, argv, argc, 0);
CALLOC_ARRAY(modes, argc);
/*
@@ -212,45 +209,39 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
flags = KEEP_TRAILING_SLASH;
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
flags = 0;
- dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
- dst_w_slash = add_slash(dest_path[0]);
- submodule_gitfile = xcalloc(argc, sizeof(char *));
+ internal_prefix_pathspec(&dest_paths, prefix, argv + argc, 1, flags);
+ dst_w_slash = add_slash(dest_paths.v[0]);
+ submodule_gitfiles = xcalloc(argc, sizeof(char *));
- if (dest_path[0][0] == '\0')
+ if (dest_paths.v[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
- else if (!lstat(dest_path[0], &st) &&
- S_ISDIR(st.st_mode)) {
- destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
+ internal_prefix_pathspec(&destinations, dest_paths.v[0], argv, argc, DUP_BASENAME);
+ else if (!lstat(dest_paths.v[0], &st) && S_ISDIR(st.st_mode)) {
+ internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+ } else if (!path_in_sparse_checkout(dst_w_slash, the_repository->index) &&
+ empty_dir_has_sparse_contents(dst_w_slash)) {
+ internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+ dst_mode = SKIP_WORKTREE_DIR;
+ } else if (argc != 1) {
+ die(_("destination '%s' is not a directory"), dest_paths.v[0]);
} else {
- if (!path_in_sparse_checkout(dst_w_slash, the_repository->index) &&
- empty_dir_has_sparse_contents(dst_w_slash)) {
- destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
- dst_mode = SKIP_WORKTREE_DIR;
- } else if (argc != 1) {
- die(_("destination '%s' is not a directory"), dest_path[0]);
- } else {
- destination = dest_path;
- /*
- * <destination> is a file outside of sparse-checkout
- * cone. Insist on cone mode here for backward
- * compatibility. We don't want dst_mode to be assigned
- * for a file when the repo is using no-cone mode (which
- * is deprecated at this point) sparse-checkout. As
- * SPARSE here is only considering cone-mode situation.
- */
- if (!path_in_cone_mode_sparse_checkout(destination[0], the_repository->index))
- dst_mode = SPARSE;
- }
- }
- if (dst_w_slash != dest_path[0]) {
- free((char *)dst_w_slash);
- dst_w_slash = NULL;
+ strvec_pushv(&destinations, dest_paths.v);
+
+ /*
+ * <destination> is a file outside of sparse-checkout
+ * cone. Insist on cone mode here for backward
+ * compatibility. We don't want dst_mode to be assigned
+ * for a file when the repo is using no-cone mode (which
+ * is deprecated at this point) sparse-checkout. As
+ * SPARSE here is only considering cone-mode situation.
+ */
+ if (!path_in_cone_mode_sparse_checkout(destinations.v[0], the_repository->index))
+ dst_mode = SPARSE;
}
/* Checking */
for (i = 0; i < argc; i++) {
- const char *src = source[i], *dst = destination[i];
+ const char *src = sources.v[i], *dst = destinations.v[i];
int length;
const char *bad = NULL;
int skip_sparse = 0;
@@ -265,12 +256,14 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
pos = index_name_pos(the_repository->index, src, length);
if (pos < 0) {
- const char *src_w_slash = add_slash(src);
+ char *src_w_slash = add_slash(src);
if (!path_in_sparse_checkout(src_w_slash, the_repository->index) &&
empty_dir_has_sparse_contents(src)) {
+ free(src_w_slash);
modes[i] |= SKIP_WORKTREE_DIR;
goto dir_check;
}
+ free(src_w_slash);
/* only error if existence is expected. */
if (!(modes[i] & SPARSE))
bad = _("bad source");
@@ -310,12 +303,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
dir_check:
if (S_ISDIR(st.st_mode)) {
- int j, dst_len, n;
+ char *dst_with_slash;
+ size_t dst_with_slash_len;
+ int j, n;
int first = index_name_pos(the_repository->index, src, length), last;
if (first >= 0) {
- prepare_move_submodule(src, first,
- submodule_gitfile + i);
+ const char *path = submodule_gitfile_path(src, first);
+ if (path != SUBMODULE_WITH_GITDIR)
+ path = strvec_push(&submodule_gitfiles_to_free, path);
+ submodule_gitfiles[i] = path;
goto act_on_entry;
} else if (index_range_of_same_dir(src, length,
&first, &last) < 1) {
@@ -330,24 +327,28 @@ dir_check:
src_dir[src_dir_nr++] = src;
n = argc + last - first;
- REALLOC_ARRAY(source, n);
- REALLOC_ARRAY(destination, n);
REALLOC_ARRAY(modes, n);
- REALLOC_ARRAY(submodule_gitfile, n);
+ REALLOC_ARRAY(submodule_gitfiles, n);
- dst = add_slash(dst);
- dst_len = strlen(dst);
+ dst_with_slash = add_slash(dst);
+ dst_with_slash_len = strlen(dst_with_slash);
for (j = 0; j < last - first; j++) {
const struct cache_entry *ce = the_repository->index->cache[first + j];
const char *path = ce->name;
- source[argc + j] = path;
- destination[argc + j] =
- prefix_path(dst, dst_len, path + length + 1);
+ char *prefixed_path = prefix_path(dst_with_slash, dst_with_slash_len, path + length + 1);
+
+ strvec_push(&sources, path);
+ strvec_push(&destinations, prefixed_path);
+
memset(modes + argc + j, 0, sizeof(enum update_mode));
modes[argc + j] |= ce_skip_worktree(ce) ? SPARSE : INDEX;
- submodule_gitfile[argc + j] = NULL;
+ submodule_gitfiles[argc + j] = NULL;
+
+ free(prefixed_path);
}
+
+ free(dst_with_slash);
argc += last - first;
goto act_on_entry;
}
@@ -428,23 +429,25 @@ act_on_entry:
remove_entry:
if (--argc > 0) {
int n = argc - i;
- MOVE_ARRAY(source + i, source + i + 1, n);
- MOVE_ARRAY(destination + i, destination + i + 1, n);
+ strvec_remove(&sources, i);
+ strvec_remove(&destinations, i);
MOVE_ARRAY(modes + i, modes + i + 1, n);
- MOVE_ARRAY(submodule_gitfile + i,
- submodule_gitfile + i + 1, n);
+ MOVE_ARRAY(submodule_gitfiles + i,
+ submodule_gitfiles + i + 1, n);
i--;
}
}
if (only_match_skip_worktree.nr) {
advise_on_updating_sparse_paths(&only_match_skip_worktree);
- if (!ignore_errors)
- return 1;
+ if (!ignore_errors) {
+ ret = 1;
+ goto out;
+ }
}
for (i = 0; i < argc; i++) {
- const char *src = source[i], *dst = destination[i];
+ const char *src = sources.v[i], *dst = destinations.v[i];
enum update_mode mode = modes[i];
int pos;
int sparse_and_dirty = 0;
@@ -464,12 +467,12 @@ remove_entry:
continue;
die_errno(_("renaming '%s' failed"), src);
}
- if (submodule_gitfile[i]) {
+ if (submodule_gitfiles[i]) {
if (!update_path_in_gitmodules(src, dst))
gitmodules_modified = 1;
- if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
+ if (submodule_gitfiles[i] != SUBMODULE_WITH_GITDIR)
connect_work_tree_and_git_dir(dst,
- submodule_gitfile[i],
+ submodule_gitfiles[i],
1);
}
@@ -565,11 +568,18 @@ remove_entry:
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("Unable to write new index file"));
+ ret = 0;
+
+out:
+ free(dst_w_slash);
string_list_clear(&src_for_dst, 0);
string_list_clear(&dirty_paths, 0);
- UNLEAK(source);
- UNLEAK(dest_path);
- free(submodule_gitfile);
+ string_list_clear(&only_match_skip_worktree, 0);
+ strvec_clear(&sources);
+ strvec_clear(&dest_paths);
+ strvec_clear(&destinations);
+ strvec_clear(&submodule_gitfiles_to_free);
+ free(submodule_gitfiles);
free(modes);
- return 0;
+ return ret;
}
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 0466d9414a..14d4f0a5e6 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -83,7 +83,7 @@ static const char *action_names[] = {
struct rebase_options {
enum rebase_type type;
enum empty_type empty;
- const char *default_backend;
+ char *default_backend;
const char *state_dir;
struct commit *upstream;
const char *upstream_name;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index be8969a84a..01c1f04ece 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -88,7 +88,7 @@ static struct strbuf push_cert = STRBUF_INIT;
static struct object_id push_cert_oid;
static struct signature_check sigcheck;
static const char *push_cert_nonce;
-static const char *cert_nonce_seed;
+static char *cert_nonce_seed;
static struct strvec hidden_refs = STRVEC_INIT;
static const char *NONCE_UNSOLICITED = "UNSOLICITED";
@@ -168,13 +168,13 @@ static int receive_pack_config(const char *var, const char *value,
}
if (strcmp(var, "receive.fsck.skiplist") == 0) {
- const char *path;
+ char *path;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
fsck_msg_types.len ? ',' : '=', path);
- free((char *)path);
+ free(path);
return 0;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index 58ad82dd97..f0317fa94a 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -48,10 +48,10 @@ static const char incremental_bitmap_conflict_error[] = N_(
);
struct pack_objects_args {
- const char *window;
- const char *window_memory;
- const char *depth;
- const char *threads;
+ char *window;
+ char *window_memory;
+ char *depth;
+ char *threads;
unsigned long max_pack_size;
int no_reuse_delta;
int no_reuse_object;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 893e973871..1d51e54fcd 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -736,16 +736,14 @@ static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
return 1;
}
-static const char *dwim_branch(const char *path, const char **new_branch)
+static char *dwim_branch(const char *path, char **new_branch)
{
int n;
int branch_exists;
const char *s = worktree_basename(path, &n);
- const char *branchname = xstrndup(s, n);
+ char *branchname = xstrndup(s, n);
struct strbuf ref = STRBUF_INIT;
- UNLEAK(branchname);
-
branch_exists = !strbuf_check_branch_ref(&ref, branchname) &&
refs_ref_exists(get_main_ref_store(the_repository),
ref.buf);
@@ -756,8 +754,7 @@ static const char *dwim_branch(const char *path, const char **new_branch)
*new_branch = branchname;
if (guess_remote) {
struct object_id oid;
- const char *remote =
- unique_tracking_name(*new_branch, &oid, NULL);
+ char *remote = unique_tracking_name(*new_branch, &oid, NULL);
return remote;
}
return NULL;
@@ -769,6 +766,8 @@ static int add(int ac, const char **av, const char *prefix)
const char *new_branch_force = NULL;
char *path;
const char *branch;
+ char *branch_to_free = NULL;
+ char *new_branch_to_free = NULL;
const char *new_branch = NULL;
const char *opt_track = NULL;
const char *lock_reason = NULL;
@@ -859,16 +858,17 @@ static int add(int ac, const char **av, const char *prefix)
opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
} else if (ac < 2) {
/* DWIM: Guess branch name from path. */
- const char *s = dwim_branch(path, &new_branch);
+ char *s = dwim_branch(path, &new_branch_to_free);
if (s)
- branch = s;
+ branch = branch_to_free = s;
+ new_branch = new_branch_to_free;
/* DWIM: Infer --orphan when repo has no refs. */
opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
} else if (ac == 2) {
struct object_id oid;
struct commit *commit;
- const char *remote;
+ char *remote;
commit = lookup_commit_reference_by_name(branch);
if (!commit) {
@@ -923,6 +923,8 @@ static int add(int ac, const char **av, const char *prefix)
ret = add_worktree(path, branch, &opts);
free(path);
+ free(branch_to_free);
+ free(new_branch_to_free);
return ret;
}
diff --git a/checkout.c b/checkout.c
index 4256e71a7c..cfaea4bd10 100644
--- a/checkout.c
+++ b/checkout.c
@@ -45,8 +45,8 @@ static int check_tracking_name(struct remote *remote, void *cb_data)
return 0;
}
-const char *unique_tracking_name(const char *name, struct object_id *oid,
- int *dwim_remotes_matched)
+char *unique_tracking_name(const char *name, struct object_id *oid,
+ int *dwim_remotes_matched)
{
struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
const char *default_remote = NULL;
diff --git a/checkout.h b/checkout.h
index 3c514a5ab4..ba15a13fb3 100644
--- a/checkout.h
+++ b/checkout.h
@@ -8,8 +8,8 @@
* tracking branch. Return the name of the remote if such a branch
* exists, NULL otherwise.
*/
-const char *unique_tracking_name(const char *name,
- struct object_id *oid,
- int *dwim_remotes_matched);
+char *unique_tracking_name(const char *name,
+ struct object_id *oid,
+ int *dwim_remotes_matched);
#endif /* CHECKOUT_H */
diff --git a/commit-reach.c b/commit-reach.c
index 8f9b008f87..384aee1ab3 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -1106,6 +1106,10 @@ void ahead_behind(struct repository *r,
/* STALE is used here, PARENT2 is used by insert_no_dup(). */
repo_clear_commit_marks(r, PARENT2 | STALE);
+ while (prio_queue_peek(&queue)) {
+ struct commit *c = prio_queue_get(&queue);
+ free_bit_array(c);
+ }
clear_bit_arrays(&bit_arrays);
clear_prio_queue(&queue);
}
diff --git a/config.c b/config.c
index 14461312b3..abce05b774 100644
--- a/config.c
+++ b/config.c
@@ -1338,7 +1338,7 @@ int git_config_bool(const char *name, const char *value)
return v;
}
-int git_config_string(const char **dest, const char *var, const char *value)
+int git_config_string(char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
@@ -1346,7 +1346,7 @@ int git_config_string(const char **dest, const char *var, const char *value)
return 0;
}
-int git_config_pathname(const char **dest, const char *var, const char *value)
+int git_config_pathname(char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
@@ -1414,11 +1414,15 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.attributesfile"))
+ if (!strcmp(var, "core.attributesfile")) {
+ FREE_AND_NULL(git_attributes_file);
return git_config_pathname(&git_attributes_file, var, value);
+ }
- if (!strcmp(var, "core.hookspath"))
+ if (!strcmp(var, "core.hookspath")) {
+ FREE_AND_NULL(git_hooks_path);
return git_config_pathname(&git_hooks_path, var, value);
+ }
if (!strcmp(var, "core.bare")) {
is_bare_repository_cfg = git_config_bool(var, value);
@@ -1553,8 +1557,10 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.checkroundtripencoding"))
+ if (!strcmp(var, "core.checkroundtripencoding")) {
+ FREE_AND_NULL(check_roundtrip_encoding);
return git_config_string(&check_roundtrip_encoding, var, value);
+ }
if (!strcmp(var, "core.notesref")) {
if (!value)
@@ -1563,8 +1569,10 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.editor"))
+ if (!strcmp(var, "core.editor")) {
+ FREE_AND_NULL(editor_program);
return git_config_string(&editor_program, var, value);
+ }
if (!strcmp(var, "core.commentchar") ||
!strcmp(var, "core.commentstring")) {
@@ -1582,11 +1590,13 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.askpass"))
+ if (!strcmp(var, "core.askpass")) {
+ FREE_AND_NULL(askpass_program);
return git_config_string(&askpass_program, var, value);
+ }
if (!strcmp(var, "core.excludesfile")) {
- free((char *)excludes_file);
+ FREE_AND_NULL(excludes_file);
return git_config_pathname(&excludes_file, var, value);
}
@@ -1689,11 +1699,15 @@ static int git_default_sparse_config(const char *var, const char *value)
static int git_default_i18n_config(const char *var, const char *value)
{
- if (!strcmp(var, "i18n.commitencoding"))
+ if (!strcmp(var, "i18n.commitencoding")) {
+ FREE_AND_NULL(git_commit_encoding);
return git_config_string(&git_commit_encoding, var, value);
+ }
- if (!strcmp(var, "i18n.logoutputencoding"))
+ if (!strcmp(var, "i18n.logoutputencoding")) {
+ FREE_AND_NULL(git_log_output_encoding);
return git_config_string(&git_log_output_encoding, var, value);
+ }
/* Add other config variables here and to Documentation/config.txt. */
return 0;
@@ -1766,10 +1780,15 @@ static int git_default_push_config(const char *var, const char *value)
static int git_default_mailmap_config(const char *var, const char *value)
{
- if (!strcmp(var, "mailmap.file"))
+ if (!strcmp(var, "mailmap.file")) {
+ FREE_AND_NULL(git_mailmap_file);
return git_config_pathname(&git_mailmap_file, var, value);
- if (!strcmp(var, "mailmap.blob"))
+ }
+
+ if (!strcmp(var, "mailmap.blob")) {
+ FREE_AND_NULL(git_mailmap_blob);
return git_config_string(&git_mailmap_blob, var, value);
+ }
/* Add other config variables here and to Documentation/config.txt. */
return 0;
@@ -1777,8 +1796,10 @@ static int git_default_mailmap_config(const char *var, const char *value)
static int git_default_attr_config(const char *var, const char *value)
{
- if (!strcmp(var, "attr.tree"))
+ if (!strcmp(var, "attr.tree")) {
+ FREE_AND_NULL(git_attr_tree);
return git_config_string(&git_attr_tree, var, value);
+ }
/*
* Add other attribute related config variables here and to
@@ -2405,7 +2426,7 @@ int git_configset_get_string(struct config_set *set, const char *key, char **des
{
const char *value;
if (!git_configset_get_value(set, key, &value, NULL))
- return git_config_string((const char **)dest, key, value);
+ return git_config_string(dest, key, value);
else
return 1;
}
@@ -2483,7 +2504,7 @@ int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *d
return 1;
}
-int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
+int git_configset_get_pathname(struct config_set *set, const char *key, char **dest)
{
const char *value;
if (!git_configset_get_value(set, key, &value, NULL))
@@ -2628,7 +2649,7 @@ int repo_config_get_maybe_bool(struct repository *repo,
}
int repo_config_get_pathname(struct repository *repo,
- const char *key, const char **dest)
+ const char *key, char **dest)
{
int ret;
git_config_check_init(repo);
@@ -2727,7 +2748,7 @@ int git_config_get_maybe_bool(const char *key, int *dest)
return repo_config_get_maybe_bool(the_repository, key, dest);
}
-int git_config_get_pathname(const char *key, const char **dest)
+int git_config_get_pathname(const char *key, char **dest)
{
return repo_config_get_pathname(the_repository, key, dest);
}
diff --git a/config.h b/config.h
index e66c84520b..8620aa731b 100644
--- a/config.h
+++ b/config.h
@@ -280,13 +280,13 @@ int git_config_bool(const char *, const char *);
* Allocates and copies the value string into the `dest` parameter; if no
* string is given, prints an error message and returns -1.
*/
-int git_config_string(const char **, const char *, const char *);
+int git_config_string(char **, const char *, const char *);
/**
* Similar to `git_config_string`, but expands `~` or `~user` into the
* user's home directory when found at the beginning of the path.
*/
-int git_config_pathname(const char **, const char *, const char *);
+int git_config_pathname(char **, const char *, const char *);
int git_config_expiry_date(timestamp_t *, const char *, const char *);
int git_config_color(char *, const char *, const char *);
@@ -541,7 +541,7 @@ int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned lon
int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
-int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
+int git_configset_get_pathname(struct config_set *cs, const char *key, char **dest);
/* Functions for reading a repository's config */
struct repository;
@@ -577,7 +577,7 @@ int repo_config_get_bool_or_int(struct repository *repo,
int repo_config_get_maybe_bool(struct repository *repo,
const char *key, int *dest);
int repo_config_get_pathname(struct repository *repo,
- const char *key, const char **dest);
+ const char *key, char **dest);
/*
* Functions for reading protected config. By definition, protected
@@ -687,7 +687,7 @@ int git_config_get_maybe_bool(const char *key, int *dest);
* Similar to `git_config_get_string`, but expands `~` or `~user` into
* the user's home directory when found at the beginning of the path.
*/
-int git_config_get_pathname(const char *key, const char **dest);
+int git_config_get_pathname(const char *key, char **dest);
int git_config_get_index_threads(int *dest);
int git_config_get_split_index(void);
diff --git a/convert.c b/convert.c
index 35b25eb3cb..f2b9f01354 100644
--- a/convert.c
+++ b/convert.c
@@ -345,30 +345,32 @@ static int check_roundtrip(const char *enc_name)
* space separated encodings (eg. "UTF-16, ASCII, CP1125").
* Search for the given encoding in that string.
*/
- const char *found = strcasestr(check_roundtrip_encoding, enc_name);
+ const char *encoding = check_roundtrip_encoding ?
+ check_roundtrip_encoding : "SHIFT-JIS";
+ const char *found = strcasestr(encoding, enc_name);
const char *next;
int len;
if (!found)
return 0;
next = found + strlen(enc_name);
- len = strlen(check_roundtrip_encoding);
+ len = strlen(encoding);
return (found && (
/*
- * check that the found encoding is at the
- * beginning of check_roundtrip_encoding or
- * that it is prefixed with a space or comma
+ * Check that the found encoding is at the beginning of
+ * encoding or that it is prefixed with a space or
+ * comma.
*/
- found == check_roundtrip_encoding || (
+ found == encoding || (
(isspace(found[-1]) || found[-1] == ',')
)
) && (
/*
- * check that the found encoding is at the
- * end of check_roundtrip_encoding or
- * that it is suffixed with a space or comma
+ * Check that the found encoding is at the end of
+ * encoding or that it is suffixed with a space
+ * or comma.
*/
- next == check_roundtrip_encoding + len || (
- next < check_roundtrip_encoding + len &&
+ next == encoding + len || (
+ next < encoding + len &&
(isspace(next[0]) || next[0] == ',')
)
));
@@ -979,9 +981,9 @@ done:
static struct convert_driver {
const char *name;
struct convert_driver *next;
- const char *smudge;
- const char *clean;
- const char *process;
+ char *smudge;
+ char *clean;
+ char *process;
int required;
} *user_convert, **user_convert_tail;
diff --git a/convert.h b/convert.h
index ab8b4fa68d..d925589444 100644
--- a/convert.h
+++ b/convert.h
@@ -92,7 +92,7 @@ void convert_attrs(struct index_state *istate,
struct conv_attrs *ca, const char *path);
extern enum eol core_eol;
-extern const char *check_roundtrip_encoding;
+extern char *check_roundtrip_encoding;
const char *get_cached_convert_stats_ascii(struct index_state *istate,
const char *path);
const char *get_wt_convert_stats_ascii(const char *path);
diff --git a/delta-islands.c b/delta-islands.c
index 4ac3c10551..89d51b72e3 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -313,7 +313,7 @@ struct island_load_data {
size_t nr;
size_t alloc;
};
-static const char *core_island_name;
+static char *core_island_name;
static void free_config_regexes(struct island_load_data *ild)
{
diff --git a/diff.c b/diff.c
index ded9ac70df..e70301df76 100644
--- a/diff.c
+++ b/diff.c
@@ -56,14 +56,14 @@ static int diff_color_moved_default;
static int diff_color_moved_ws_default;
static int diff_context_default = 3;
static int diff_interhunk_context_default;
-static const char *diff_word_regex_cfg;
-static const char *external_diff_cmd_cfg;
-static const char *diff_order_file_cfg;
+static char *diff_word_regex_cfg;
+static char *external_diff_cmd_cfg;
+static char *diff_order_file_cfg;
int diff_auto_refresh_index = 1;
static int diff_mnemonic_prefix;
static int diff_no_prefix;
-static const char *diff_src_prefix = "a/";
-static const char *diff_dst_prefix = "b/";
+static char *diff_src_prefix;
+static char *diff_dst_prefix;
static int diff_relative;
static int diff_stat_name_width;
static int diff_stat_graph_width;
@@ -411,9 +411,11 @@ int git_diff_ui_config(const char *var, const char *value,
return 0;
}
if (!strcmp(var, "diff.srcprefix")) {
+ FREE_AND_NULL(diff_src_prefix);
return git_config_string(&diff_src_prefix, var, value);
}
if (!strcmp(var, "diff.dstprefix")) {
+ FREE_AND_NULL(diff_dst_prefix);
return git_config_string(&diff_dst_prefix, var, value);
}
if (!strcmp(var, "diff.relative")) {
@@ -3433,8 +3435,8 @@ void diff_set_noprefix(struct diff_options *options)
void diff_set_default_prefix(struct diff_options *options)
{
- options->a_prefix = diff_src_prefix;
- options->b_prefix = diff_dst_prefix;
+ options->a_prefix = diff_src_prefix ? diff_src_prefix : "a/";
+ options->b_prefix = diff_dst_prefix ? diff_dst_prefix : "b/";
}
struct userdiff_driver *get_textconv(struct repository *r,
@@ -5371,8 +5373,8 @@ static int diff_opt_default_prefix(const struct option *opt,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(optarg);
- diff_src_prefix = "a/";
- diff_dst_prefix = "b/";
+ FREE_AND_NULL(diff_src_prefix);
+ FREE_AND_NULL(diff_dst_prefix);
diff_set_default_prefix(options);
return 0;
}
diff --git a/environment.c b/environment.c
index a73ba9c12c..701d515135 100644
--- a/environment.c
+++ b/environment.c
@@ -42,12 +42,12 @@ int is_bare_repository_cfg = -1; /* unspecified */
int warn_ambiguous_refs = 1;
int warn_on_object_refname_ambiguity = 1;
int repository_format_precious_objects;
-const char *git_commit_encoding;
-const char *git_log_output_encoding;
+char *git_commit_encoding;
+char *git_log_output_encoding;
char *apply_default_whitespace;
char *apply_default_ignorewhitespace;
-const char *git_attributes_file;
-const char *git_hooks_path;
+char *git_attributes_file;
+char *git_hooks_path;
int zlib_compression_level = Z_BEST_SPEED;
int pack_compression_level = Z_DEFAULT_COMPRESSION;
int fsync_object_files = -1;
@@ -58,13 +58,13 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
size_t delta_base_cache_limit = 96 * 1024 * 1024;
unsigned long big_file_threshold = 512 * 1024 * 1024;
-const char *editor_program;
-const char *askpass_program;
-const char *excludes_file;
+char *editor_program;
+char *askpass_program;
+char *excludes_file;
enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
-const char *check_roundtrip_encoding = "SHIFT-JIS";
+char *check_roundtrip_encoding;
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
diff --git a/environment.h b/environment.h
index 0b2d457f07..e9f01d4d11 100644
--- a/environment.h
+++ b/environment.h
@@ -131,8 +131,8 @@ extern int warn_ambiguous_refs;
extern int warn_on_object_refname_ambiguity;
extern char *apply_default_whitespace;
extern char *apply_default_ignorewhitespace;
-extern const char *git_attributes_file;
-extern const char *git_hooks_path;
+extern char *git_attributes_file;
+extern char *git_hooks_path;
extern int zlib_compression_level;
extern int pack_compression_level;
extern size_t packed_git_window_size;
@@ -224,12 +224,12 @@ int odb_pack_keep(const char *name);
const char *get_log_output_encoding(void);
const char *get_commit_output_encoding(void);
-extern const char *git_commit_encoding;
-extern const char *git_log_output_encoding;
+extern char *git_commit_encoding;
+extern char *git_log_output_encoding;
-extern const char *editor_program;
-extern const char *askpass_program;
-extern const char *excludes_file;
+extern char *editor_program;
+extern char *askpass_program;
+extern char *excludes_file;
/*
* Should we print an ellipsis after an abbreviated SHA-1 value
diff --git a/fetch-pack.c b/fetch-pack.c
index 7d2aef21ad..eba9e420ea 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1860,13 +1860,13 @@ static int fetch_pack_config_cb(const char *var, const char *value,
const char *msg_id;
if (strcmp(var, "fetch.fsck.skiplist") == 0) {
- const char *path;
+ char *path ;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
fsck_msg_types.len ? ',' : '=', path);
- free((char *)path);
+ free(path);
return 0;
}
diff --git a/fsck.c b/fsck.c
index 78af29d264..dd0a33028e 100644
--- a/fsck.c
+++ b/fsck.c
@@ -1274,13 +1274,13 @@ int git_fsck_config(const char *var, const char *value,
const char *msg_id;
if (strcmp(var, "fsck.skiplist") == 0) {
- const char *path;
+ char *path;
struct strbuf sb = STRBUF_INIT;
if (git_config_pathname(&path, var, value))
return 1;
strbuf_addf(&sb, "skiplist=%s", path);
- free((char *)path);
+ free(path);
fsck_set_msg_types(options, sb.buf);
strbuf_release(&sb);
return 0;
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index a6a9e6bc19..e818583420 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -103,6 +103,7 @@ static struct fsmonitor_settings *alloc_settings(void)
static void lookup_fsmonitor_settings(struct repository *r)
{
const char *const_str;
+ char *to_free = NULL;
int bool_value;
if (r->settings.fsmonitor)
@@ -129,8 +130,9 @@ static void lookup_fsmonitor_settings(struct repository *r)
break;
case -1: /* config value set to an arbitrary string */
- if (repo_config_get_pathname(r, "core.fsmonitor", &const_str))
+ if (repo_config_get_pathname(r, "core.fsmonitor", &to_free))
return; /* should not happen */
+ const_str = to_free;
break;
default: /* should not happen */
@@ -141,6 +143,7 @@ static void lookup_fsmonitor_settings(struct repository *r)
fsm_settings__set_hook(r, const_str);
else
fsm_settings__set_disabled(r);
+ free(to_free);
}
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
diff --git a/gpg-interface.c b/gpg-interface.c
index 1ff94266d2..5193223714 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -27,12 +27,14 @@ static void gpg_interface_lazy_init(void)
}
static char *configured_signing_key;
-static const char *ssh_default_key_command, *ssh_allowed_signers, *ssh_revocation_file;
+static char *ssh_default_key_command;
+static char *ssh_allowed_signers;
+static char *ssh_revocation_file;
static enum signature_trust_level configured_min_trust_level = TRUST_UNDEFINED;
struct gpg_format {
const char *name;
- const char *program;
+ char *program;
const char **verify_args;
const char **sigs;
int (*verify_signed_buffer)(struct signature_check *sigc,
diff --git a/http.c b/http.c
index 752c879c1f..67cc47d28f 100644
--- a/http.c
+++ b/http.c
@@ -38,11 +38,11 @@ char curl_errorstr[CURL_ERROR_SIZE];
static int curl_ssl_verify = -1;
static int curl_ssl_try;
-static const char *curl_http_version = NULL;
-static const char *ssl_cert;
-static const char *ssl_cert_type;
-static const char *ssl_cipherlist;
-static const char *ssl_version;
+static char *curl_http_version;
+static char *ssl_cert;
+static char *ssl_cert_type;
+static char *ssl_cipherlist;
+static char *ssl_version;
static struct {
const char *name;
long ssl_version;
@@ -59,23 +59,23 @@ static struct {
{ "tlsv1.3", CURL_SSLVERSION_TLSv1_3 },
#endif
};
-static const char *ssl_key;
-static const char *ssl_key_type;
-static const char *ssl_capath;
-static const char *curl_no_proxy;
+static char *ssl_key;
+static char *ssl_key_type;
+static char *ssl_capath;
+static char *curl_no_proxy;
#ifdef GIT_CURL_HAVE_CURLOPT_PINNEDPUBLICKEY
-static const char *ssl_pinnedkey;
+static char *ssl_pinnedkey;
#endif
-static const char *ssl_cainfo;
+static char *ssl_cainfo;
static long curl_low_speed_limit = -1;
static long curl_low_speed_time = -1;
static int curl_ftp_no_epsv;
-static const char *curl_http_proxy;
-static const char *http_proxy_authmethod;
+static char *curl_http_proxy;
+static char *http_proxy_authmethod;
-static const char *http_proxy_ssl_cert;
-static const char *http_proxy_ssl_key;
-static const char *http_proxy_ssl_ca_info;
+static char *http_proxy_ssl_cert;
+static char *http_proxy_ssl_key;
+static char *http_proxy_ssl_ca_info;
static struct credential proxy_cert_auth = CREDENTIAL_INIT;
static int proxy_ssl_cert_password_required;
@@ -95,7 +95,7 @@ static struct {
*/
};
#ifdef CURLGSSAPI_DELEGATION_FLAG
-static const char *curl_deleg;
+static char *curl_deleg;
static struct {
const char *name;
long curl_deleg_param;
@@ -108,11 +108,11 @@ static struct {
static struct credential proxy_auth = CREDENTIAL_INIT;
static const char *curl_proxyuserpwd;
-static const char *curl_cookie_file;
+static char *curl_cookie_file;
static int curl_save_cookies;
struct credential http_auth = CREDENTIAL_INIT;
static int http_proactive_auth;
-static const char *user_agent;
+static char *user_agent;
static int curl_empty_auth = -1;
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
@@ -592,10 +592,10 @@ static void init_curl_http_auth(CURL *result)
}
/* *var must be free-able */
-static void var_override(const char **var, char *value)
+static void var_override(char **var, char *value)
{
if (value) {
- free((void *)*var);
+ free(*var);
*var = xstrdup(value);
}
}
@@ -1233,11 +1233,13 @@ static CURL *get_curl_handle(void)
return result;
}
-static void set_from_env(const char **var, const char *envname)
+static void set_from_env(char **var, const char *envname)
{
const char *val = getenv(envname);
- if (val)
- *var = val;
+ if (val) {
+ FREE_AND_NULL(*var);
+ *var = xstrdup(val);
+ }
}
void http_init(struct remote *remote, const char *url, int proactive_auth)
diff --git a/imap-send.c b/imap-send.c
index c0130d0e02..a5d1510180 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -70,16 +70,16 @@ static char *next_arg(char **);
struct imap_server_conf {
const char *name;
- const char *tunnel;
- const char *host;
+ char *tunnel;
+ char *host;
int port;
- const char *folder;
- const char *user;
- const char *pass;
+ char *folder;
+ char *user;
+ char *pass;
int use_ssl;
int ssl_verify;
int use_html;
- const char *auth_method;
+ char *auth_method;
};
static struct imap_server_conf server = {
diff --git a/mailmap.c b/mailmap.c
index 3d6a5e9400..b2efe29b3d 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -6,8 +6,8 @@
#include "object-store-ll.h"
#include "setup.h"
-const char *git_mailmap_file;
-const char *git_mailmap_blob;
+char *git_mailmap_file;
+char *git_mailmap_blob;
struct mailmap_info {
char *name;
diff --git a/mailmap.h b/mailmap.h
index 0f8fd2c586..cbda9bc5e0 100644
--- a/mailmap.h
+++ b/mailmap.h
@@ -3,8 +3,8 @@
struct string_list;
-extern const char *git_mailmap_file;
-extern const char *git_mailmap_blob;
+extern char *git_mailmap_file;
+extern char *git_mailmap_blob;
int read_mailmap(struct string_list *map);
void clear_mailmap(struct string_list *map);
diff --git a/merge-ll.c b/merge-ll.c
index bf1077ae09..e29b15fa4a 100644
--- a/merge-ll.c
+++ b/merge-ll.c
@@ -27,9 +27,9 @@ typedef enum ll_merge_result (*ll_merge_fn)(const struct ll_merge_driver *,
struct ll_merge_driver {
const char *name;
- const char *description;
+ char *description;
ll_merge_fn fn;
- const char *recursive;
+ char *recursive;
struct ll_merge_driver *next;
char *cmdline;
};
@@ -268,7 +268,7 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn,
* merge.default and merge.driver configuration items
*/
static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail;
-static const char *default_ll_merge;
+static char *default_ll_merge;
static int read_merge_config(const char *var, const char *value,
const struct config_context *ctx UNUSED,
diff --git a/pager.c b/pager.c
index b8822a9381..e9e121db69 100644
--- a/pager.c
+++ b/pager.c
@@ -13,7 +13,7 @@ int pager_use_color = 1;
#endif
static struct child_process pager_process;
-static const char *pager_program;
+static char *pager_program;
/* Is the value coming back from term_columns() just a guess? */
static int term_columns_guessed;
diff --git a/pretty.c b/pretty.c
index 7ead078998..22a81506b7 100644
--- a/pretty.c
+++ b/pretty.c
@@ -62,7 +62,7 @@ static int git_pretty_formats_config(const char *var, const char *value,
{
struct cmt_fmt_map *commit_format = NULL;
const char *name;
- const char *fmt;
+ char *fmt;
int i;
if (!skip_prefix(var, "pretty.", &name))
@@ -93,13 +93,17 @@ static int git_pretty_formats_config(const char *var, const char *value,
if (git_config_string(&fmt, var, value))
return -1;
- if (skip_prefix(fmt, "format:", &fmt))
+ if (skip_prefix(fmt, "format:", &commit_format->user_format)) {
commit_format->is_tformat = 0;
- else if (skip_prefix(fmt, "tformat:", &fmt) || strchr(fmt, '%'))
+ } else if (skip_prefix(fmt, "tformat:", &commit_format->user_format)) {
commit_format->is_tformat = 1;
- else
+ } else if (strchr(fmt, '%')) {
+ commit_format->is_tformat = 1;
+ commit_format->user_format = fmt;
+ } else {
commit_format->is_alias = 1;
- commit_format->user_format = fmt;
+ commit_format->user_format = fmt;
+ }
return 0;
}
diff --git a/promisor-remote.h b/promisor-remote.h
index 2cb9eda9ea..88cb599c39 100644
--- a/promisor-remote.h
+++ b/promisor-remote.h
@@ -13,7 +13,7 @@ struct object_id;
*/
struct promisor_remote {
struct promisor_remote *next;
- const char *partial_clone_filter;
+ char *partial_clone_filter;
const char name[FLEX_ARRAY];
};
diff --git a/remote.c b/remote.c
index 5898da2bb5..dcb5492c85 100644
--- a/remote.c
+++ b/remote.c
@@ -430,29 +430,29 @@ static int handle_config(const char *key, const char *value,
else if (!strcmp(subkey, "prunetags"))
remote->prune_tags = git_config_bool(key, value);
else if (!strcmp(subkey, "url")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
add_url(remote, v);
} else if (!strcmp(subkey, "pushurl")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
add_pushurl(remote, v);
} else if (!strcmp(subkey, "push")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
refspec_append(&remote->push, v);
- free((char *)v);
+ free(v);
} else if (!strcmp(subkey, "fetch")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
refspec_append(&remote->fetch, v);
- free((char *)v);
+ free(v);
} else if (!strcmp(subkey, "receivepack")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
if (!remote->receivepack)
@@ -460,7 +460,7 @@ static int handle_config(const char *key, const char *value,
else
error(_("more than one receivepack given, using the first"));
} else if (!strcmp(subkey, "uploadpack")) {
- const char *v;
+ char *v;
if (git_config_string(&v, key, value))
return -1;
if (!remote->uploadpack)
@@ -473,10 +473,10 @@ static int handle_config(const char *key, const char *value,
else if (!strcmp(value, "--tags"))
remote->fetch_tags = 2;
} else if (!strcmp(subkey, "proxy")) {
- return git_config_string((const char **)&remote->http_proxy,
+ return git_config_string(&remote->http_proxy,
key, value);
} else if (!strcmp(subkey, "proxyauthmethod")) {
- return git_config_string((const char **)&remote->http_proxy_authmethod,
+ return git_config_string(&remote->http_proxy_authmethod,
key, value);
} else if (!strcmp(subkey, "vcs")) {
return git_config_string(&remote->foreign_vcs, key, value);
diff --git a/remote.h b/remote.h
index dfd4837e60..e8c6655e42 100644
--- a/remote.h
+++ b/remote.h
@@ -46,7 +46,7 @@ struct remote_state {
struct hashmap branches_hash;
struct branch *current_branch;
- const char *pushremote_name;
+ char *pushremote_name;
struct rewrites rewrites;
struct rewrites rewrites_push;
@@ -65,7 +65,7 @@ struct remote {
int origin, configured_in_repo;
- const char *foreign_vcs;
+ char *foreign_vcs;
/* An array of all of the url_nr URLs configured for the remote */
const char **url;
@@ -309,9 +309,9 @@ struct branch {
const char *refname;
/* The name of the remote listed in the configuration. */
- const char *remote_name;
+ char *remote_name;
- const char *pushremote_name;
+ char *pushremote_name;
/* An array of the "merge" lines in the configuration. */
const char **merge_name;
diff --git a/sequencer.c b/sequencer.c
index aa2a239835..30513e87bf 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -306,7 +306,7 @@ static int git_sequencer_config(const char *k, const char *v,
}
if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
- int ret = git_config_string((const char**)&opts->default_strategy, k, v);
+ int ret = git_config_string(&opts->default_strategy, k, v);
if (ret == 0) {
/*
* pull.twohead is allowed to be multi-valued; we only
diff --git a/setup.c b/setup.c
index 3ade79d245..e47946d0e7 100644
--- a/setup.c
+++ b/setup.c
@@ -1230,13 +1230,13 @@ static int safe_directory_cb(const char *key, const char *value,
} else if (!strcmp(value, "*")) {
data->is_safe = 1;
} else {
- const char *interpolated = NULL;
+ char *interpolated = NULL;
if (!git_config_pathname(&interpolated, key, value) &&
!fspathcmp(data->path, interpolated ? interpolated : value))
data->is_safe = 1;
- free((char *)interpolated);
+ free(interpolated);
}
return 0;
@@ -1875,7 +1875,7 @@ static int template_dir_cb(const char *key, const char *value,
char *path = NULL;
FREE_AND_NULL(data->path);
- if (!git_config_pathname((const char **)&path, key, value))
+ if (!git_config_pathname(&path, key, value))
data->path = path ? path : xstrdup(value);
}
diff --git a/strbuf.c b/strbuf.c
index 0d929e4e19..e1076c9891 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -691,8 +691,10 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
int strbuf_appendwholeline(struct strbuf *sb, FILE *fp, int term)
{
struct strbuf line = STRBUF_INIT;
- if (strbuf_getwholeline(&line, fp, term))
+ if (strbuf_getwholeline(&line, fp, term)) {
+ strbuf_release(&line);
return EOF;
+ }
strbuf_addbuf(sb, &line);
strbuf_release(&line);
return 0;
diff --git a/strvec.c b/strvec.c
index 178f4f3748..d4073ec9fa 100644
--- a/strvec.c
+++ b/strvec.c
@@ -56,6 +56,26 @@ void strvec_pushv(struct strvec *array, const char **items)
strvec_push(array, *items);
}
+const char *strvec_replace(struct strvec *array, size_t idx, const char *replacement)
+{
+ char *to_free;
+ if (idx >= array->nr)
+ BUG("index outside of array boundary");
+ to_free = (char *) array->v[idx];
+ array->v[idx] = xstrdup(replacement);
+ free(to_free);
+ return array->v[idx];
+}
+
+void strvec_remove(struct strvec *array, size_t idx)
+{
+ if (idx >= array->nr)
+ BUG("index outside of array boundary");
+ free((char *)array->v[idx]);
+ memmove(array->v + idx, array->v + idx + 1, (array->nr - idx) * sizeof(char *));
+ array->nr--;
+}
+
void strvec_pop(struct strvec *array)
{
if (!array->nr)
diff --git a/strvec.h b/strvec.h
index 4715d3e51f..6c7e8b7d50 100644
--- a/strvec.h
+++ b/strvec.h
@@ -65,6 +65,19 @@ void strvec_pushl(struct strvec *, ...);
void strvec_pushv(struct strvec *, const char **);
/**
+ * Replace the value at the given index with a new value. The index must be
+ * valid. Returns a pointer to the inserted value.
+ */
+const char *strvec_replace(struct strvec *array, size_t idx, const char *replacement);
+
+/*
+ * Remove the value at the given index. The remainder of the array will be
+ * moved to fill the resulting gap. The provided index must point into the
+ * array.
+ */
+void strvec_remove(struct strvec *array, size_t idx);
+
+/**
* Remove the final element from the array. If there are no
* elements in the array, do nothing.
*/
diff --git a/submodule-config.c b/submodule-config.c
index 11428b4ada..ec45ea67b9 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -91,6 +91,8 @@ static void free_one_config(struct submodule_entry *entry)
free((void *) entry->config->path);
free((void *) entry->config->name);
free((void *) entry->config->branch);
+ free((void *) entry->config->url);
+ free((void *) entry->config->ignore);
free((void *) entry->config->update_strategy.command);
free(entry->config);
}
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index 432f029d48..6a76b7fdbd 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='basic credential helper tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-credential.sh
diff --git a/t/t0611-reftable-httpd.sh b/t/t0611-reftable-httpd.sh
index 5e05b9c1f2..2805995cc8 100755
--- a/t/t0611-reftable-httpd.sh
+++ b/t/t0611-reftable-httpd.sh
@@ -2,6 +2,7 @@
test_description='reftable HTTPD tests'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-httpd.sh
diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh
index bfc90d4cf2..cf8b94ebed 100755
--- a/t/t1013-read-tree-submodule.sh
+++ b/t/t1013-read-tree-submodule.sh
@@ -2,6 +2,7 @@
test_description='read-tree can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh
index 40d3c42618..53e5b290b9 100755
--- a/t/t1306-xdg-files.sh
+++ b/t/t1306-xdg-files.sh
@@ -7,6 +7,7 @@
test_description='Compatibility with $XDG_CONFIG_HOME/git/ files'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' '
diff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh
index 45a0492917..ceeb7ac3a4 100755
--- a/t/t1350-config-hooks-path.sh
+++ b/t/t1350-config-hooks-path.sh
@@ -2,6 +2,7 @@
test_description='Test the core.hooksPath configuration variable'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up a pre-commit hook in core.hooksPath' '
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index ec3443cc87..bbee2783ab 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -4,6 +4,8 @@
#
test_description='Test git update-ref and basic ref logging'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
Z=$ZERO_OID
diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh
index b2bdd1fcb4..3c1d663d94 100755
--- a/t/t2013-checkout-submodule.sh
+++ b/t/t2013-checkout-submodule.sh
@@ -2,6 +2,7 @@
test_description='checkout can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
index a3b1449ef1..2caada3d83 100755
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@ -4,6 +4,7 @@ test_description='checkout <branch>
Ensures that checkout on an unborn branch does what the user expects'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Is the current branch "refs/heads/$1"?
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index c91c4db936..77b2346291 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -5,6 +5,7 @@ test_description='switch basic functionality'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3007-ls-files-recurse-submodules.sh b/t/t3007-ls-files-recurse-submodules.sh
index 61771eec83..f04bdc8c78 100755
--- a/t/t3007-ls-files-recurse-submodules.sh
+++ b/t/t3007-ls-files-recurse-submodules.sh
@@ -6,6 +6,7 @@ This test verifies the recurse-submodules feature correctly lists files from
submodules.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup directory structure and submodules' '
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 758963b189..e627f08a17 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='git branch display tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index fcc40d6fe1..22452ff84c 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -5,6 +5,7 @@ test_description='auto squash'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh
index ba069dccbd..94ea88e384 100755
--- a/t/t3426-rebase-submodule.sh
+++ b/t/t3426-rebase-submodule.sh
@@ -2,6 +2,7 @@
test_description='rebase can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh
index f22d1ddead..9387a22a9e 100755
--- a/t/t3512-cherry-pick-submodule.sh
+++ b/t/t3512-cherry-pick-submodule.sh
@@ -5,6 +5,7 @@ test_description='cherry-pick can handle submodules'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh
index 8bfe3ed246..e178968b40 100755
--- a/t/t3513-revert-submodule.sh
+++ b/t/t3513-revert-submodule.sh
@@ -2,6 +2,7 @@
test_description='revert can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 98259e2ada..31ac31d4bc 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -8,6 +8,7 @@ test_description='Test of the various options to git rm.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Setup some files to be removed, some with funny characters
diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh
index 0f7348ec21..0f61f01ef4 100755
--- a/t/t3906-stash-submodule.sh
+++ b/t/t3906-stash-submodule.sh
@@ -2,6 +2,7 @@
test_description='stash can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh
index 49c042a38a..cd1931dd55 100755
--- a/t/t4001-diff-rename.sh
+++ b/t/t4001-diff-rename.sh
@@ -3,9 +3,9 @@
# Copyright (c) 2005 Junio C Hamano
#
-test_description='Test rename detection in diff engine.
+test_description='Test rename detection in diff engine.'
-'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 0c1502d4b0..8fc40e75eb 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -12,6 +12,7 @@ This test tries to verify the sanity of the --submodule option of git diff.
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Tested non-UTF-8 encoding
diff --git a/t/t4043-diff-rename-binary.sh b/t/t4043-diff-rename-binary.sh
index 2a2cf91352..e486493908 100755
--- a/t/t4043-diff-rename-binary.sh
+++ b/t/t4043-diff-rename-binary.sh
@@ -5,6 +5,7 @@
test_description='Move a binary file'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
diff --git a/t/t4059-diff-submodule-not-initialized.sh b/t/t4059-diff-submodule-not-initialized.sh
index d489230df8..668f526303 100755
--- a/t/t4059-diff-submodule-not-initialized.sh
+++ b/t/t4059-diff-submodule-not-initialized.sh
@@ -9,6 +9,7 @@ This test tries to verify that add_submodule_odb works when the submodule was
initialized previously but the checkout has since been removed.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Tested non-UTF-8 encoding
diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh
index 97c6424cd5..8ce67442d9 100755
--- a/t/t4060-diff-submodule-option-diff-format.sh
+++ b/t/t4060-diff-submodule-option-diff-format.sh
@@ -10,6 +10,7 @@ test_description='Support for diff format verbose submodule difference in git di
This test tries to verify the sanity of --submodule=diff option of git diff.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Tested non-UTF-8 encoding
diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh
index 697e86c0ff..f788428540 100755
--- a/t/t4120-apply-popt.sh
+++ b/t/t4120-apply-popt.sh
@@ -5,6 +5,7 @@
test_description='git apply -p handling.'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh
index 07d5262537..ebd0d4ad17 100755
--- a/t/t4137-apply-submodule.sh
+++ b/t/t4137-apply-submodule.sh
@@ -2,6 +2,7 @@
test_description='git apply handling submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh
index 75216f19ce..7120030b5c 100755
--- a/t/t4210-log-i18n.sh
+++ b/t/t4210-log-i18n.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test log with i18n features'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
# two forms of é
diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh
index 5d5caa3f58..4af796de67 100755
--- a/t/t5563-simple-http-auth.sh
+++ b/t/t5563-simple-http-auth.sh
@@ -2,6 +2,7 @@
test_description='test http auth header and credential helper interop'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-httpd.sh
diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh
index 9da5134614..bb35b87071 100755
--- a/t/t5564-http-proxy.sh
+++ b/t/t5564-http-proxy.sh
@@ -2,6 +2,7 @@
test_description="test fetching through http proxy"
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-httpd.sh
diff --git a/t/t5581-http-curl-verbose.sh b/t/t5581-http-curl-verbose.sh
index cded79c16b..724f610054 100755
--- a/t/t5581-http-curl-verbose.sh
+++ b/t/t5581-http-curl-verbose.sh
@@ -4,6 +4,7 @@ test_description='test GIT_CURL_VERBOSE'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 573eb97a0f..f1623b1c06 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -8,6 +8,7 @@ test_description='git rev-list --pretty=format test'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh
index 82013fc903..3946e18089 100755
--- a/t/t6041-bisect-submodule.sh
+++ b/t/t6041-bisect-submodule.sh
@@ -2,6 +2,7 @@
test_description='bisect can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t6400-merge-df.sh b/t/t6400-merge-df.sh
index 3de4ef6bd9..27d6efdc9a 100755
--- a/t/t6400-merge-df.sh
+++ b/t/t6400-merge-df.sh
@@ -7,6 +7,7 @@ test_description='Test merge with directory/file conflicts'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'prepare repository' '
diff --git a/t/t6412-merge-large-rename.sh b/t/t6412-merge-large-rename.sh
index ca018d11f5..d0863a8fb5 100755
--- a/t/t6412-merge-large-rename.sh
+++ b/t/t6412-merge-large-rename.sh
@@ -4,6 +4,7 @@ test_description='merging with large rename matrix'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
count() {
diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh
index b059475ed0..62f0180325 100755
--- a/t/t6426-merge-skip-unneeded-updates.sh
+++ b/t/t6426-merge-skip-unneeded-updates.sh
@@ -22,6 +22,7 @@ test_description="merge cases"
# underscore notation is to differentiate different
# files that might be renamed into each other's paths.)
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-merge.sh
diff --git a/t/t6429-merge-sequence-rename-caching.sh b/t/t6429-merge-sequence-rename-caching.sh
index 0f39ed0d08..cb1c4ceef7 100755
--- a/t/t6429-merge-sequence-rename-caching.sh
+++ b/t/t6429-merge-sequence-rename-caching.sh
@@ -2,6 +2,7 @@
test_description="remember regular & dir renames in sequence of merges"
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
#
diff --git a/t/t6438-submodule-directory-file-conflicts.sh b/t/t6438-submodule-directory-file-conflicts.sh
index 8df67a0ef9..3594190af8 100755
--- a/t/t6438-submodule-directory-file-conflicts.sh
+++ b/t/t6438-submodule-directory-file-conflicts.sh
@@ -2,6 +2,7 @@
test_description='merge can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 879a6dce60..86258f9f43 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='git mv in subdirs'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh
index 5fcf281dfb..b9822294fe 100755
--- a/t/t7005-editor.sh
+++ b/t/t7005-editor.sh
@@ -2,6 +2,7 @@
test_description='GIT_EDITOR, core.editor, and stuff'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
unset EDITOR VISUAL GIT_EDITOR
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index 62d9f846ce..2add26d768 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -10,6 +10,7 @@ Documented tests for git reset'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
commit_msg () {
diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh
index a3e2413bc3..b0d3d93b0b 100755
--- a/t/t7112-reset-submodule.sh
+++ b/t/t7112-reset-submodule.sh
@@ -2,6 +2,7 @@
test_description='reset can handle submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t7417-submodule-path-url.sh b/t/t7417-submodule-path-url.sh
index 5e3051da8b..dbbb3853dc 100755
--- a/t/t7417-submodule-path-url.sh
+++ b/t/t7417-submodule-path-url.sh
@@ -4,6 +4,7 @@ test_description='check handling of .gitmodule path with dash'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7421-submodule-summary-add.sh b/t/t7421-submodule-summary-add.sh
index ce64d8b137..479c8fdde1 100755
--- a/t/t7421-submodule-summary-add.sh
+++ b/t/t7421-submodule-summary-add.sh
@@ -10,6 +10,7 @@ while making sure to add submodules using `git submodule add` instead of
`git add` as done in t7401.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh
index 185248a4cd..01e1e8a8f7 100755
--- a/t/t9129-git-svn-i18n-commitencoding.sh
+++ b/t/t9129-git-svn-i18n-commitencoding.sh
@@ -4,7 +4,6 @@
test_description='git svn honors i18n.commitEncoding in config'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
compare_git_head_with () {
diff --git a/t/t9139-git-svn-non-utf8-commitencoding.sh b/t/t9139-git-svn-non-utf8-commitencoding.sh
index b7f756b2b7..22d80b0be2 100755
--- a/t/t9139-git-svn-non-utf8-commitencoding.sh
+++ b/t/t9139-git-svn-non-utf8-commitencoding.sh
@@ -4,7 +4,6 @@
test_description='git svn refuses to dcommit non-UTF8 messages'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
# ISO-2022-JP can pass for valid UTF-8, so skipping that in this test
diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c
new file mode 100644
index 0000000000..f17fb10d9e
--- /dev/null
+++ b/t/unit-tests/t-strvec.c
@@ -0,0 +1,269 @@
+#include "test-lib.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+#define check_strvec(vec, ...) \
+ check_strvec_loc(TEST_LOCATION(), vec, __VA_ARGS__)
+static void check_strvec_loc(const char *loc, struct strvec *vec, ...)
+{
+ va_list ap;
+ size_t nr = 0;
+
+ va_start(ap, vec);
+ while (1) {
+ const char *str = va_arg(ap, const char *);
+ if (!str)
+ break;
+
+ if (!check_uint(vec->nr, >, nr) ||
+ !check_uint(vec->alloc, >, nr) ||
+ !check_str(vec->v[nr], str)) {
+ struct strbuf msg = STRBUF_INIT;
+ strbuf_addf(&msg, "strvec index %"PRIuMAX, (uintmax_t) nr);
+ test_assert(loc, msg.buf, 0);
+ strbuf_release(&msg);
+ return;
+ }
+
+ nr++;
+ }
+
+ check_uint(vec->nr, ==, nr);
+ check_uint(vec->alloc, >=, nr);
+ check_pointer_eq(vec->v[nr], NULL);
+}
+
+static void t_static_init(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+}
+
+static void t_dynamic_init(void)
+{
+ struct strvec vec;
+ strvec_init(&vec);
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+}
+
+static void t_clear(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_push(&vec, "foo");
+ strvec_clear(&vec);
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+}
+
+static void t_push(void)
+{
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_push(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+
+ strvec_push(&vec, "bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+
+ strvec_clear(&vec);
+}
+
+static void t_pushf(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushf(&vec, "foo: %d", 1);
+ check_strvec(&vec, "foo: 1", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_pushl(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_pushv(void)
+{
+ const char *strings[] = {
+ "foo", "bar", "baz", NULL,
+ };
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushv(&vec, strings);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+
+ strvec_clear(&vec);
+}
+
+static void t_replace_at_head(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 0, "replaced");
+ check_strvec(&vec, "replaced", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_replace_at_tail(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 2, "replaced");
+ check_strvec(&vec, "foo", "bar", "replaced", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_replace_in_between(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 1, "replaced");
+ check_strvec(&vec, "foo", "replaced", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_replace_with_substring(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", NULL);
+ strvec_replace(&vec, 0, vec.v[0] + 1);
+ check_strvec(&vec, "oo", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_remove_at_head(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 0);
+ check_strvec(&vec, "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_remove_at_tail(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 2);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_remove_in_between(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 1);
+ check_strvec(&vec, "foo", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_pop_empty_array(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pop(&vec);
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+}
+
+static void t_pop_non_empty_array(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_pop(&vec);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_split_empty_string(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+}
+
+static void t_split_single_item(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_split_multiple_items(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo bar baz");
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_split_whitespace_only(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, " \t\n");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+}
+
+static void t_split_multiple_consecutive_whitespaces(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo\n\t bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+}
+
+static void t_detach(void)
+{
+ struct strvec vec = STRVEC_INIT;
+ const char **detached;
+
+ strvec_push(&vec, "foo");
+
+ detached = strvec_detach(&vec);
+ check_str(detached[0], "foo");
+ check_pointer_eq(detached[1], NULL);
+
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+
+ free((char *) detached[0]);
+ free(detached);
+}
+
+int cmd_main(int argc, const char **argv)
+{
+ TEST(t_static_init(), "static initialization");
+ TEST(t_dynamic_init(), "dynamic initialization");
+ TEST(t_clear(), "clear");
+ TEST(t_push(), "push");
+ TEST(t_pushf(), "pushf");
+ TEST(t_pushl(), "pushl");
+ TEST(t_pushv(), "pushv");
+ TEST(t_replace_at_head(), "replace at head");
+ TEST(t_replace_in_between(), "replace in between");
+ TEST(t_replace_at_tail(), "replace at tail");
+ TEST(t_replace_with_substring(), "replace with substring");
+ TEST(t_remove_at_head(), "remove at head");
+ TEST(t_remove_in_between(), "remove in between");
+ TEST(t_remove_at_tail(), "remove at tail");
+ TEST(t_pop_empty_array(), "pop with empty array");
+ TEST(t_pop_non_empty_array(), "pop with non-empty array");
+ TEST(t_split_empty_string(), "split empty string");
+ TEST(t_split_single_item(), "split single item");
+ TEST(t_split_multiple_items(), "split multiple items");
+ TEST(t_split_whitespace_only(), "split whitespace only");
+ TEST(t_split_multiple_consecutive_whitespaces(), "split multiple consecutive whitespaces");
+ TEST(t_detach(), "detach");
+ return test_done();
+}
diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c
index 66d6980ffb..3c513ce59a 100644
--- a/t/unit-tests/test-lib.c
+++ b/t/unit-tests/test-lib.c
@@ -318,6 +318,19 @@ int check_bool_loc(const char *loc, const char *check, int ok)
union test__tmp test__tmp[2];
+int check_pointer_eq_loc(const char *loc, const char *check, int ok,
+ const void *a, const void *b)
+{
+ int ret = test_assert(loc, check, ok);
+
+ if (!ret) {
+ test_msg(" left: %p", a);
+ test_msg(" right: %p", b);
+ }
+
+ return ret;
+}
+
int check_int_loc(const char *loc, const char *check, int ok,
intmax_t a, intmax_t b)
{
diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h
index a8f07ae0b7..2de6d715d5 100644
--- a/t/unit-tests/test-lib.h
+++ b/t/unit-tests/test-lib.h
@@ -79,6 +79,18 @@ int check_bool_loc(const char *loc, const char *check, int ok);
* Compare two integers. Prints a message with the two values if the
* comparison fails. NB this is not thread safe.
*/
+#define check_pointer_eq(a, b) \
+ (test__tmp[0].p = (a), test__tmp[1].p = (b), \
+ check_pointer_eq_loc(TEST_LOCATION(), #a" == "#b, \
+ test__tmp[0].p == test__tmp[1].p, \
+ test__tmp[0].p, test__tmp[1].p))
+int check_pointer_eq_loc(const char *loc, const char *check, int ok,
+ const void *a, const void *b);
+
+/*
+ * Compare two integers. Prints a message with the two values if the
+ * comparison fails. NB this is not thread safe.
+ */
#define check_int(a, op, b) \
(test__tmp[0].i = (a), test__tmp[1].i = (b), \
check_int_loc(TEST_LOCATION(), #a" "#op" "#b, \
@@ -136,6 +148,7 @@ union test__tmp {
intmax_t i;
uintmax_t u;
char c;
+ const void *p;
};
extern union test__tmp test__tmp[2];
diff --git a/transport-helper.c b/transport-helper.c
index 780fcaf529..9820947ab2 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -22,7 +22,7 @@
static int debug;
struct helper_data {
- const char *name;
+ char *name;
struct child_process *helper;
FILE *out;
unsigned fetch : 1,
@@ -111,6 +111,7 @@ static void do_take_over(struct transport *transport)
data = (struct helper_data *)transport->data;
transport_take_over(transport, data->helper);
fclose(data->out);
+ free(data->name);
free(data);
}
@@ -253,6 +254,7 @@ static int disconnect_helper(struct transport *transport)
close(data->helper->out);
fclose(data->out);
res = finish_command(data->helper);
+ FREE_AND_NULL(data->name);
FREE_AND_NULL(data->helper);
}
return res;
@@ -1297,7 +1299,7 @@ static struct transport_vtable vtable = {
int transport_helper_init(struct transport *transport, const char *name)
{
struct helper_data *data = xcalloc(1, sizeof(*data));
- data->name = name;
+ data->name = xstrdup(name);
transport_check_allowed(name);
diff --git a/transport.c b/transport.c
index 0ad04b77fd..83ddea8fbc 100644
--- a/transport.c
+++ b/transport.c
@@ -1176,6 +1176,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
int len = external_specification_len(url);
char *handler = xmemdupz(url, len);
transport_helper_init(ret, handler);
+ free(handler);
}
if (ret->smart_options) {
diff --git a/upload-pack.c b/upload-pack.c
index bbfb04c8bd..b726f7a57d 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -94,7 +94,7 @@ struct upload_pack_data {
struct packet_writer writer;
- const char *pack_objects_hook;
+ char *pack_objects_hook;
unsigned stateless_rpc : 1; /* v0 only */
unsigned no_done : 1; /* v0 only */
diff --git a/userdiff.h b/userdiff.h
index d726804c3e..cc8e5abfef 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -7,19 +7,19 @@ struct index_state;
struct repository;
struct userdiff_funcname {
- const char *pattern;
+ char *pattern;
int cflags;
};
struct userdiff_driver {
const char *name;
- const char *external;
- const char *algorithm;
+ char *external;
+ char *algorithm;
int binary;
struct userdiff_funcname funcname;
- const char *word_regex;
- const char *word_regex_multi_byte;
- const char *textconv;
+ char *word_regex;
+ char *word_regex_multi_byte;
+ char *textconv;
struct notes_cache *textconv_cache;
int textconv_want_cache;
};