2011-08-11 13:15:38 +04:00
|
|
|
#include "git-compat-util.h"
|
|
|
|
#include "parse-options.h"
|
|
|
|
#include "cache.h"
|
|
|
|
#include "commit.h"
|
|
|
|
#include "color.h"
|
|
|
|
#include "string-list.h"
|
2015-06-14 11:41:49 +03:00
|
|
|
#include "argv-array.h"
|
2015-07-07 19:06:08 +03:00
|
|
|
#include "sha1-array.h"
|
2011-08-11 13:15:38 +04:00
|
|
|
|
|
|
|
/*----- some often used options -----*/
|
|
|
|
|
|
|
|
int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
int v;
|
|
|
|
|
|
|
|
if (!arg) {
|
|
|
|
v = unset ? 0 : DEFAULT_ABBREV;
|
|
|
|
} else {
|
|
|
|
v = strtol(arg, (char **)&arg, 10);
|
|
|
|
if (*arg)
|
|
|
|
return opterror(opt, "expects a numerical value", 0);
|
|
|
|
if (v && v < MINIMUM_ABBREV)
|
|
|
|
v = MINIMUM_ABBREV;
|
|
|
|
else if (v > 40)
|
|
|
|
v = 40;
|
|
|
|
}
|
|
|
|
*(int *)(opt->value) = v;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
2017-04-26 22:29:31 +03:00
|
|
|
*(timestamp_t *)(opt->value) = approxidate(arg);
|
2011-08-11 13:15:38 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-25 22:13:49 +04:00
|
|
|
int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
2018-04-21 06:13:13 +03:00
|
|
|
if (unset)
|
|
|
|
arg = "never";
|
|
|
|
if (parse_expiry_date(arg, (timestamp_t *)opt->value))
|
|
|
|
die(_("malformed expiration date '%s'"), arg);
|
|
|
|
return 0;
|
2013-04-25 22:13:49 +04:00
|
|
|
}
|
|
|
|
|
2011-08-11 13:15:38 +04:00
|
|
|
int parse_opt_color_flag_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
|
|
|
int value;
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
arg = unset ? "never" : (const char *)opt->defval;
|
2011-08-29 08:19:16 +04:00
|
|
|
value = git_config_colorbool(NULL, arg);
|
2011-08-11 13:15:38 +04:00
|
|
|
if (value < 0)
|
|
|
|
return opterror(opt,
|
|
|
|
"expects \"always\", \"auto\", or \"never\"", 0);
|
|
|
|
*(int *)opt->value = value;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_opt_verbosity_cb(const struct option *opt, const char *arg,
|
|
|
|
int unset)
|
|
|
|
{
|
|
|
|
int *target = opt->value;
|
|
|
|
|
|
|
|
if (unset)
|
|
|
|
/* --no-quiet, --no-verbose */
|
|
|
|
*target = 0;
|
|
|
|
else if (opt->short_name == 'v') {
|
|
|
|
if (*target >= 0)
|
|
|
|
(*target)++;
|
|
|
|
else
|
|
|
|
*target = 1;
|
|
|
|
} else {
|
|
|
|
if (*target <= 0)
|
|
|
|
(*target)--;
|
|
|
|
else
|
|
|
|
*target = -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-07 19:06:14 +03:00
|
|
|
int parse_opt_commits(const struct option *opt, const char *arg, int unset)
|
2011-08-11 13:15:38 +04:00
|
|
|
{
|
2017-05-07 01:09:59 +03:00
|
|
|
struct object_id oid;
|
2011-08-11 13:15:38 +04:00
|
|
|
struct commit *commit;
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
2017-05-07 01:09:59 +03:00
|
|
|
if (get_oid(arg, &oid))
|
2011-08-11 13:15:38 +04:00
|
|
|
return error("malformed object name %s", arg);
|
2018-06-29 04:21:58 +03:00
|
|
|
commit = lookup_commit_reference(the_repository, &oid);
|
2011-08-11 13:15:38 +04:00
|
|
|
if (!commit)
|
|
|
|
return error("no such commit %s", arg);
|
|
|
|
commit_list_insert(commit, opt->value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-07 19:06:08 +03:00
|
|
|
int parse_opt_object_name(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
2017-03-26 19:01:31 +03:00
|
|
|
struct object_id oid;
|
2015-07-07 19:06:08 +03:00
|
|
|
|
|
|
|
if (unset) {
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_clear(opt->value);
|
2015-07-07 19:06:08 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
2017-03-26 19:01:31 +03:00
|
|
|
if (get_oid(arg, &oid))
|
2015-07-07 19:06:08 +03:00
|
|
|
return error(_("malformed object name '%s'"), arg);
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_append(opt->value, &oid);
|
2015-07-07 19:06:08 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-08-11 13:15:38 +04:00
|
|
|
int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
int *target = opt->value;
|
|
|
|
*target = unset ? 2 : 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-05 23:44:47 +03:00
|
|
|
struct option *parse_options_concat(struct option *a, struct option *b)
|
2011-08-11 13:15:38 +04:00
|
|
|
{
|
2016-07-05 23:44:47 +03:00
|
|
|
struct option *ret;
|
|
|
|
size_t i, a_len = 0, b_len = 0;
|
|
|
|
|
|
|
|
for (i = 0; a[i].type != OPTION_END; i++)
|
|
|
|
a_len++;
|
|
|
|
for (i = 0; b[i].type != OPTION_END; i++)
|
|
|
|
b_len++;
|
|
|
|
|
|
|
|
ALLOC_ARRAY(ret, st_add3(a_len, b_len, 1));
|
|
|
|
for (i = 0; i < a_len; i++)
|
|
|
|
ret[i] = a[i];
|
|
|
|
for (i = 0; i < b_len; i++)
|
|
|
|
ret[a_len + i] = b[i];
|
|
|
|
ret[a_len + b_len] = b[b_len]; /* final OPTION_END */
|
|
|
|
|
|
|
|
return ret;
|
2011-08-11 13:15:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int parse_opt_string_list(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct string_list *v = opt->value;
|
|
|
|
|
|
|
|
if (unset) {
|
|
|
|
string_list_clear(v, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!arg)
|
|
|
|
return -1;
|
|
|
|
|
parse_opt_string_list: stop allocating new strings
The parse_opt_string_list callback is basically a thin
wrapper to string_list_append() any string options we get.
However, it calls:
string_list_append(v, xstrdup(arg));
which duplicates the option value. This is wrong for two
reasons:
1. If the string list has strdup_strings set, then we are
making an extra copy, which is simply leaked.
2. If the string list does not have strdup_strings set,
then we pass memory ownership to the string list, but
it does not realize this. If we later call
string_list_clear(), which can happen if "--no-foo" is
passed, then we will leak all of the existing entries.
Instead, we should just pass the argument straight to
string_list_append, and it can decide whether to copy or not
based on its strdup_strings flag.
It's possible that some (buggy) caller could be relying on
this extra copy (e.g., because it parses some options from
an allocated argv array and then frees the array), but it's
not likely. For one, we generally only use parse_options on
the argv given to us in main(). And two, such a caller is
broken anyway, because other option types like OPT_STRING()
do not make such a copy. This patch brings us in line with
them.
Noticed-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-06-13 08:39:12 +03:00
|
|
|
string_list_append(v, arg);
|
2011-08-11 13:15:38 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2011-09-28 21:44:30 +04:00
|
|
|
|
|
|
|
int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-14 11:41:48 +03:00
|
|
|
|
2016-09-05 12:44:52 +03:00
|
|
|
/**
|
|
|
|
* Report that the option is unknown, so that other code can handle
|
|
|
|
* it. This can be used as a callback together with
|
|
|
|
* OPTION_LOWLEVEL_CALLBACK to allow an option to be documented in the
|
|
|
|
* "-h" output even if it's not being handled directly by
|
|
|
|
* parse_options().
|
|
|
|
*/
|
|
|
|
int parse_opt_unknown_cb(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2015-06-14 11:41:48 +03:00
|
|
|
/**
|
|
|
|
* Recreates the command-line option in the strbuf.
|
|
|
|
*/
|
|
|
|
static int recreate_opt(struct strbuf *sb, const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
strbuf_reset(sb);
|
|
|
|
|
|
|
|
if (opt->long_name) {
|
|
|
|
strbuf_addstr(sb, unset ? "--no-" : "--");
|
|
|
|
strbuf_addstr(sb, opt->long_name);
|
|
|
|
if (arg) {
|
|
|
|
strbuf_addch(sb, '=');
|
|
|
|
strbuf_addstr(sb, arg);
|
|
|
|
}
|
|
|
|
} else if (opt->short_name && !unset) {
|
|
|
|
strbuf_addch(sb, '-');
|
|
|
|
strbuf_addch(sb, opt->short_name);
|
|
|
|
if (arg)
|
|
|
|
strbuf_addstr(sb, arg);
|
|
|
|
} else
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For an option opt, recreates the command-line option in opt->value which
|
|
|
|
* must be an char* initialized to NULL. This is useful when we need to pass
|
|
|
|
* the command-line option to another command. Since any previous value will be
|
|
|
|
* overwritten, this callback should only be used for options where the last
|
|
|
|
* one wins.
|
|
|
|
*/
|
|
|
|
int parse_opt_passthru(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
static struct strbuf sb = STRBUF_INIT;
|
|
|
|
char **opt_value = opt->value;
|
|
|
|
|
|
|
|
if (recreate_opt(&sb, opt, arg, unset) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-10-08 17:14:57 +03:00
|
|
|
free(*opt_value);
|
2015-06-14 11:41:48 +03:00
|
|
|
|
|
|
|
*opt_value = strbuf_detach(&sb, NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-14 11:41:49 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* For an option opt, recreate the command-line option, appending it to
|
|
|
|
* opt->value which must be a argv_array. This is useful when we need to pass
|
|
|
|
* the command-line option, which can be specified multiple times, to another
|
|
|
|
* command.
|
|
|
|
*/
|
|
|
|
int parse_opt_passthru_argv(const struct option *opt, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
static struct strbuf sb = STRBUF_INIT;
|
|
|
|
struct argv_array *opt_value = opt->value;
|
|
|
|
|
|
|
|
if (recreate_opt(&sb, opt, arg, unset) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
argv_array_push(opt_value, sb.buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|