Merge branch 'ps/parse-options-integers'

Update parse-options API to catch mistakes to pass address of an
integral variable of a wrong type/size.

* ps/parse-options-integers:
  parse-options: detect mismatches in integer signedness
  parse-options: introduce precision handling for `OPTION_UNSIGNED`
  parse-options: introduce precision handling for `OPTION_INTEGER`
  parse-options: rename `OPT_MAGNITUDE()` to `OPT_UNSIGNED()`
  parse-options: support unit factors in `OPT_INTEGER()`
  global: use designated initializers for options
  parse: fix off-by-one for minimum signed values
main
Junio C Hamano 2025-04-24 17:25:33 -07:00
commit 2bc5414c41
37 changed files with 656 additions and 252 deletions

View File

@ -211,11 +211,13 @@ There are some macros to easily define options:
Use of `--no-option` will clear the list of preceding values. Use of `--no-option` will clear the list of preceding values.


`OPT_INTEGER(short, long, &int_var, description)`:: `OPT_INTEGER(short, long, &int_var, description)`::
Introduce an option with integer argument. Introduce an option with integer argument. The argument must be a
The integer is put into `int_var`. integer and may include a suffix of 'k', 'm' or 'g' to
scale the provided value by 1024, 1024^2 or 1024^3 respectively.
The scaled value is put into `int_var`.


`OPT_MAGNITUDE(short, long, &unsigned_long_var, description)`:: `OPT_UNSIGNED(short, long, &unsigned_long_var, description)`::
Introduce an option with a size argument. The argument must be a Introduce an option with an unsigned integer argument. The argument must be a
non-negative integer and may include a suffix of 'k', 'm' or 'g' to non-negative integer and may include a suffix of 'k', 'm' or 'g' to
scale the provided value by 1024, 1024^2 or 1024^3 respectively. scale the provided value by 1024, 1024^2 or 1024^3 respectively.
The scaled value is put into `unsigned_long_var`. The scaled value is put into `unsigned_long_var`.

View File

@ -5123,7 +5123,7 @@ int apply_parse_options(int argc, const char **argv,
/* Think twice before adding "--nul" synonym to this */ /* Think twice before adding "--nul" synonym to this */
OPT_SET_INT('z', NULL, &state->line_termination, OPT_SET_INT('z', NULL, &state->line_termination,
N_("paths are separated with NUL character"), '\0'), N_("paths are separated with NUL character"), '\0'),
OPT_INTEGER('C', NULL, &state->p_context, OPT_UNSIGNED('C', NULL, &state->p_context,
N_("ensure at least <n> lines of context match")), N_("ensure at least <n> lines of context match")),
OPT_CALLBACK(0, "whitespace", state, N_("action"), OPT_CALLBACK(0, "whitespace", state, N_("action"),
N_("detect new or modified lines that have whitespace errors"), N_("detect new or modified lines that have whitespace errors"),

View File

@ -650,20 +650,37 @@ static int parse_archive_args(int argc, const char **argv,
OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")), OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
OPT_STRING(0, "prefix", &base, N_("prefix"), OPT_STRING(0, "prefix", &base, N_("prefix"),
N_("prepend prefix to each pathname in the archive")), N_("prepend prefix to each pathname in the archive")),
{ OPTION_CALLBACK, 0, "add-file", args, N_("file"), {
N_("add untracked file to archive"), 0, add_file_cb, .type = OPTION_CALLBACK,
(intptr_t)&base }, .long_name = "add-file",
{ OPTION_CALLBACK, 0, "add-virtual-file", args, .value = args,
N_("path:content"), N_("add untracked file to archive"), 0, .argh = N_("file"),
add_file_cb, (intptr_t)&base }, .help = N_("add untracked file to archive"),
.callback = add_file_cb,
.defval = (intptr_t) &base,
},
{
.type = OPTION_CALLBACK,
.long_name = "add-virtual-file",
.value = args,
.argh = N_("path:content"),
.help = N_("add untracked file to archive"),
.callback = add_file_cb,
.defval = (intptr_t) &base,
},
OPT_STRING('o', "output", &output, N_("file"), OPT_STRING('o', "output", &output, N_("file"),
N_("write the archive to this file")), N_("write the archive to this file")),
OPT_BOOL(0, "worktree-attributes", &worktree_attributes, OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
N_("read .gitattributes in working directory")), N_("read .gitattributes in working directory")),
OPT__VERBOSE(&verbose, N_("report archived files on stderr")), OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
{ OPTION_STRING, 0, "mtime", &mtime_option, N_("time"), {
N_("set modification time of archive entries"), .type = OPTION_STRING,
PARSE_OPT_NONEG }, .long_name = "mtime",
.value = &mtime_option,
.argh = N_("time"),
.help = N_("set modification time of archive entries"),
.flags = PARSE_OPT_NONEG,
},
OPT_NUMBER_CALLBACK(&compression_level, OPT_NUMBER_CALLBACK(&compression_level,
N_("set compression level"), number_callback), N_("set compression level"), number_callback),
OPT_GROUP(""), OPT_GROUP(""),

View File

@ -2400,11 +2400,16 @@ int cmd_am(int argc,
OPT_CMDMODE(0, "quit", &resume_mode, OPT_CMDMODE(0, "quit", &resume_mode,
N_("abort the patching operation but keep HEAD where it is"), N_("abort the patching operation but keep HEAD where it is"),
RESUME_QUIT), RESUME_QUIT),
{ OPTION_CALLBACK, 0, "show-current-patch", &resume_mode, {
"(diff|raw)", .type = OPTION_CALLBACK,
N_("show the patch being applied"), .long_name = "show-current-patch",
PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, .value = &resume_mode,
parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW }, .argh = "(diff|raw)",
.help = N_("show the patch being applied"),
.flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
.callback = parse_opt_show_current_patch,
.defval = RESUME_SHOW_PATCH_RAW,
},
OPT_CMDMODE(0, "retry", &resume_mode, OPT_CMDMODE(0, "retry", &resume_mode,
N_("try to apply current patch again"), N_("try to apply current patch again"),
RESUME_APPLY), RESUME_APPLY),
@ -2417,9 +2422,16 @@ int cmd_am(int argc,
OPT_BOOL(0, "ignore-date", &state.ignore_date, OPT_BOOL(0, "ignore-date", &state.ignore_date,
N_("use current timestamp for author date")), N_("use current timestamp for author date")),
OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate), OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),
{ OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"), {
N_("GPG-sign commits"), .type = OPTION_STRING,
PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, .short_name = 'S',
.long_name = "gpg-sign",
.value = &state.sign_commit,
.argh = N_("key-id"),
.help = N_("GPG-sign commits"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)", OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)",
N_("how to handle empty patches"), N_("how to handle empty patches"),
PARSE_OPT_NONEG, am_option_parse_empty), PARSE_OPT_NONEG, am_option_parse_empty),

View File

@ -123,7 +123,7 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit
.sparse = 0, .sparse = 0,
}; };
struct option options[] = { struct option options[] = {
OPT_INTEGER(0, "min-batch-size", &ctx.min_batch_size, OPT_UNSIGNED(0, "min-batch-size", &ctx.min_batch_size,
N_("Minimum number of objects to request at a time")), N_("Minimum number of objects to request at a time")),
OPT_BOOL(0, "sparse", &ctx.sparse, OPT_BOOL(0, "sparse", &ctx.sparse,
N_("Restrict the missing objects to the current sparse-checkout")), N_("Restrict the missing objects to the current sparse-checkout")),

View File

@ -932,9 +932,16 @@ int cmd_clone(int argc,
N_("don't use local hardlinks, always copy")), N_("don't use local hardlinks, always copy")),
OPT_BOOL('s', "shared", &option_shared, OPT_BOOL('s', "shared", &option_shared,
N_("setup as shared repository")), N_("setup as shared repository")),
{ OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules, {
N_("pathspec"), N_("initialize submodules in the clone"), .type = OPTION_CALLBACK,
PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." }, .long_name = "recurse-submodules",
.value = &option_recurse_submodules,
.argh = N_("pathspec"),
.help = N_("initialize submodules in the clone"),
.flags = PARSE_OPT_OPTARG,
.callback = recurse_submodules_cb,
.defval = (intptr_t)".",
},
OPT_ALIAS(0, "recursive", "recurse-submodules"), OPT_ALIAS(0, "recursive", "recurse-submodules"),
OPT_INTEGER('j', "jobs", &max_jobs, OPT_INTEGER('j', "jobs", &max_jobs,
N_("number of submodules cloned in parallel")), N_("number of submodules cloned in parallel")),

View File

@ -31,7 +31,7 @@ int cmd_column(int argc,
struct option options[] = { struct option options[] = {
OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")), OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")),
OPT_COLUMN(0, "mode", &colopts, N_("layout to use")), OPT_COLUMN(0, "mode", &colopts, N_("layout to use")),
OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")), OPT_UNSIGNED(0, "raw-mode", &colopts, N_("layout to use")),
OPT_INTEGER(0, "width", &copts.width, N_("maximum width")), OPT_INTEGER(0, "width", &copts.width, N_("maximum width")),
OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("padding space on left border")), OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("padding space on left border")),
OPT_STRING(0, "nl", &copts.nl, N_("string"), N_("padding space on right border")), OPT_STRING(0, "nl", &copts.nl, N_("string"), N_("padding space on right border")),

View File

@ -111,8 +111,16 @@ int cmd_commit_tree(int argc,
OPT_CALLBACK_F('F', NULL, &buffer, N_("file"), OPT_CALLBACK_F('F', NULL, &buffer, N_("file"),
N_("read commit log message from file"), PARSE_OPT_NONEG, N_("read commit log message from file"), PARSE_OPT_NONEG,
parse_file_arg_callback), parse_file_arg_callback),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), {
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, .type = OPTION_STRING,
.short_name = 'S',
.long_name = "gpg-sign",
.value = &sign_commit,
.argh = N_("key-id"),
.help = N_("GPG sign commit"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
OPT_END() OPT_END()
}; };
int ret; int ret;

View File

@ -1542,17 +1542,34 @@ struct repository *repo UNUSED)
STATUS_FORMAT_LONG), STATUS_FORMAT_LONG),
OPT_BOOL('z', "null", &s.null_termination, OPT_BOOL('z', "null", &s.null_termination,
N_("terminate entries with NUL")), N_("terminate entries with NUL")),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, {
N_("mode"), .type = OPTION_STRING,
N_("show untracked files, optional modes: all, normal, no. (Default: all)"), .short_name = 'u',
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, .long_name = "untracked-files",
{ OPTION_STRING, 0, "ignored", &ignored_arg, .value = &untracked_files_arg,
N_("mode"), .argh = N_("mode"),
N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"), .help = N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" }, .flags = PARSE_OPT_OPTARG,
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"), .defval = (intptr_t)"all",
N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"), },
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, {
.type = OPTION_STRING,
.long_name = "ignored",
.value = &ignored_arg,
.argh = N_("mode"),
.help = N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t)"traditional",
},
{
.type = OPTION_STRING,
.long_name = "ignore-submodules",
.value = &ignore_submodule_arg,
.argh = N_("when"),
.help = N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t)"all",
},
OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")), OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")), OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
OPT_CALLBACK_F('M', "find-renames", &rename_score_arg, OPT_CALLBACK_F('M', "find-renames", &rename_score_arg,
@ -1688,8 +1705,16 @@ int cmd_commit(int argc,
OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")), OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
OPT_CLEANUP(&cleanup_arg), OPT_CLEANUP(&cleanup_arg),
OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")), OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), {
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, .type = OPTION_STRING,
.short_name = 'S',
.long_name = "gpg-sign",
.value = &sign_commit,
.argh = N_("key-id"),
.help = N_("GPG sign commit"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
/* end commit message options */ /* end commit message options */


OPT_GROUP(N_("Commit contents options")), OPT_GROUP(N_("Commit contents options")),
@ -1714,7 +1739,16 @@ int cmd_commit(int argc,
N_("terminate entries with NUL")), N_("terminate entries with NUL")),
OPT_BOOL(0, "amend", &amend, N_("amend previous commit")), OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, {
.type = OPTION_STRING,
.short_name = 'u',
.long_name = "untracked-files",
.value = &untracked_files_arg,
.argh = N_("mode"),
.help = N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t)"all",
},
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
/* end commit contents options */ /* end commit contents options */

View File

@ -131,9 +131,16 @@ struct config_display_options {
#define TYPE_COLOR 6 #define TYPE_COLOR 6
#define TYPE_BOOL_OR_STR 7 #define TYPE_BOOL_OR_STR 7


#define OPT_CALLBACK_VALUE(s, l, v, h, i) \ #define OPT_CALLBACK_VALUE(s, l, v, h, i) { \
{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \ .type = OPTION_CALLBACK, \
PARSE_OPT_NONEG, option_parse_type, (i) } .short_name = (s), \
.long_name = (l), \
.value = (v), \
.help = (h), \
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, \
.callback = option_parse_type, \
.defval = (i), \
}


static int option_parse_type(const struct option *opt, const char *arg, static int option_parse_type(const struct option *opt, const char *arg,
int unset) int unset)

View File

@ -601,12 +601,24 @@ int cmd_describe(int argc,
N_("do not consider tags matching <pattern>")), N_("do not consider tags matching <pattern>")),
OPT_BOOL(0, "always", &always, OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")), N_("show abbreviated commit object as fallback")),
{OPTION_STRING, 0, "dirty", &dirty, N_("mark"), {
N_("append <mark> on dirty working tree (default: \"-dirty\")"), .type = OPTION_STRING,
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"}, .long_name = "dirty",
{OPTION_STRING, 0, "broken", &broken, N_("mark"), .value = &dirty,
N_("append <mark> on broken working tree (default: \"-broken\")"), .argh = N_("mark"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"}, .help = N_("append <mark> on dirty working tree (default: \"-dirty\")"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "-dirty",
},
{
.type = OPTION_STRING,
.long_name = "broken",
.value = &broken,
.argh = N_("mark"),
.help = N_("append <mark> on broken working tree (default: \"-broken\")"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "-broken",
},
OPT_END(), OPT_END(),
}; };



View File

@ -2352,8 +2352,14 @@ int cmd_fetch(int argc,
OPT_SET_INT_F(0, "refetch", &refetch, OPT_SET_INT_F(0, "refetch", &refetch,
N_("re-fetch without negotiating common commits"), N_("re-fetch without negotiating common commits"),
1, PARSE_OPT_NONEG), 1, PARSE_OPT_NONEG),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), {
N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, .type = OPTION_STRING,
.long_name = "submodule-prefix",
.value = &submodule_prefix,
.argh = N_("dir"),
.help = N_("prepend this to submodule path output"),
.flags = PARSE_OPT_HIDDEN,
},
OPT_CALLBACK_F(0, "recurse-submodules-default", OPT_CALLBACK_F(0, "recurse-submodules-default",
&recurse_submodules_default, N_("on-demand"), &recurse_submodules_default, N_("on-demand"),
N_("default for recursive fetching of submodules " N_("default for recursive fetching of submodules "

View File

@ -20,13 +20,26 @@ int cmd_fmt_merge_msg(int argc,
char *into_name = NULL; char *into_name = NULL;
int shortlog_len = -1; int shortlog_len = -1;
struct option options[] = { struct option options[] = {
{ OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"), {
N_("populate log with at most <n> entries from shortlog"), .type = OPTION_INTEGER,
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN }, .long_name = "log",
{ OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"), .value = &shortlog_len,
N_("alias for --log (deprecated)"), .precision = sizeof(shortlog_len),
PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL, .argh = N_("n"),
DEFAULT_MERGE_LOG_LEN }, .help = N_("populate log with at most <n> entries from shortlog"),
.flags = PARSE_OPT_OPTARG,
.defval = DEFAULT_MERGE_LOG_LEN,
},
{
.type = OPTION_INTEGER,
.long_name = "summary",
.value = &shortlog_len,
.precision = sizeof(shortlog_len),
.argh = N_("n"),
.help = N_("alias for --log (deprecated)"),
.flags = PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN,
.defval = DEFAULT_MERGE_LOG_LEN,
},
OPT_STRING('m', "message", &message, N_("text"), OPT_STRING('m', "message", &message, N_("text"),
N_("use <text> as start of message")), N_("use <text> as start of message")),
OPT_STRING(0, "into-name", &into_name, N_("name"), OPT_STRING(0, "into-name", &into_name, N_("name"),

View File

@ -743,11 +743,17 @@ struct repository *repo UNUSED)
int ret; int ret;
struct option builtin_gc_options[] = { struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")), OPT__QUIET(&quiet, N_("suppress progress reporting")),
{ OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"), {
N_("prune unreferenced objects"), .type = OPTION_STRING,
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire_arg }, .long_name = "prune",
.value = &prune_expire_arg,
.argh = N_("date"),
.help = N_("prune unreferenced objects"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t)prune_expire_arg,
},
OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")), OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")),
OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size, OPT_UNSIGNED(0, "max-cruft-size", &cfg.max_cruft_size,
N_("with --cruft, limit the size of new cruft packs")), N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"), OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),

View File

@ -983,9 +983,9 @@ int cmd_grep(int argc,
OPT_CALLBACK('C', "context", &opt, N_("n"), OPT_CALLBACK('C', "context", &opt, N_("n"),
N_("show <n> context lines before and after matches"), N_("show <n> context lines before and after matches"),
context_callback), context_callback),
OPT_INTEGER('B', "before-context", &opt.pre_context, OPT_UNSIGNED('B', "before-context", &opt.pre_context,
N_("show <n> context lines before matches")), N_("show <n> context lines before matches")),
OPT_INTEGER('A', "after-context", &opt.post_context, OPT_UNSIGNED('A', "after-context", &opt.post_context,
N_("show <n> context lines after matches")), N_("show <n> context lines after matches")),
OPT_INTEGER(0, "threads", &num_threads, OPT_INTEGER(0, "threads", &num_threads,
N_("use <n> worker threads")), N_("use <n> worker threads")),
@ -1017,10 +1017,16 @@ int cmd_grep(int argc,
OPT_BOOL(0, "all-match", &opt.all_match, OPT_BOOL(0, "all-match", &opt.all_match,
N_("show only matches from files that match all patterns")), N_("show only matches from files that match all patterns")),
OPT_GROUP(""), OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, {
N_("pager"), N_("show matching files in the pager"), .type = OPTION_STRING,
PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE, .short_name = 'O',
NULL, (intptr_t)default_pager }, .long_name = "open-files-in-pager",
.value = &show_in_pager,
.argh = N_("pager"),
.help = N_("show matching files in the pager"),
.flags = PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE,
.defval = (intptr_t)default_pager,
},
OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored, OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored,
N_("allow calling of grep(1) (ignored by this build)"), N_("allow calling of grep(1) (ignored by this build)"),
PARSE_OPT_NOCOMPLETE), PARSE_OPT_NOCOMPLETE),

View File

@ -92,10 +92,15 @@ int cmd_init_db(int argc,
N_("directory from which templates will be used")), N_("directory from which templates will be used")),
OPT_SET_INT(0, "bare", &is_bare_repository_cfg, OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
N_("create a bare repository"), 1), N_("create a bare repository"), 1),
{ OPTION_CALLBACK, 0, "shared", &init_shared_repository, {
N_("permissions"), .type = OPTION_CALLBACK,
N_("specify that the git repository is to be shared amongst several users"), .long_name = "shared",
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0}, .value = &init_shared_repository,
.argh = N_("permissions"),
.help = N_("specify that the git repository is to be shared amongst several users"),
.flags = PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
.callback = shared_callback
},
OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET), OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
N_("separate git dir from working tree")), N_("separate git dir from working tree")),

View File

@ -67,9 +67,14 @@ int cmd_ls_remote(int argc,
OPT__QUIET(&quiet, N_("do not print remote URL")), OPT__QUIET(&quiet, N_("do not print remote URL")),
OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"), OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"),
N_("path of git-upload-pack on the remote host")), N_("path of git-upload-pack on the remote host")),
{ OPTION_STRING, 0, "exec", &uploadpack, N_("exec"), {
N_("path of git-upload-pack on the remote host"), .type = OPTION_STRING,
PARSE_OPT_HIDDEN }, .long_name = "exec",
.value = &uploadpack,
.argh = N_("exec"),
.help = N_("path of git-upload-pack on the remote host"),
.flags = PARSE_OPT_HIDDEN,
},
OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS), OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS),
OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES), OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES),
OPT_BIT_F('h', "heads", &flags, OPT_BIT_F('h', "heads", &flags,

View File

@ -249,9 +249,16 @@ static struct option builtin_merge_options[] = {
OPT_BOOL(0, "stat", &show_diffstat, OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")), N_("show a diffstat at the end of the merge")),
OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")), OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
{ OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"), {
N_("add (at most <n>) entries from shortlog to merge commit message"), .type = OPTION_INTEGER,
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN }, .long_name = "log",
.value = &shortlog_len,
.precision = sizeof(shortlog_len),
.argh = N_("n"),
.help = N_("add (at most <n>) entries from shortlog to merge commit message"),
.flags = PARSE_OPT_OPTARG,
.defval = DEFAULT_MERGE_LOG_LEN,
},
OPT_BOOL(0, "squash", &squash, OPT_BOOL(0, "squash", &squash,
N_("create a single commit instead of doing a merge")), N_("create a single commit instead of doing a merge")),
OPT_BOOL(0, "commit", &option_commit, OPT_BOOL(0, "commit", &option_commit,
@ -273,9 +280,16 @@ static struct option builtin_merge_options[] = {
OPT_CALLBACK('m', "message", &merge_msg, N_("message"), OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
N_("merge commit message (for a non-fast-forward merge)"), N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message), option_parse_message),
{ OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"), {
N_("read message from file"), PARSE_OPT_NONEG, .type = OPTION_LOWLEVEL_CALLBACK,
NULL, 0, option_read_message }, .short_name = 'F',
.long_name = "file",
.value = &merge_msg,
.argh = N_("path"),
.help = N_("read message from file"),
.flags = PARSE_OPT_NONEG,
.ll_callback = option_read_message,
},
OPT_STRING(0, "into-name", &into_name, N_("name"), OPT_STRING(0, "into-name", &into_name, N_("name"),
N_("use <name> instead of the real target")), N_("use <name> instead of the real target")),
OPT__VERBOSITY(&verbosity), OPT__VERBOSITY(&verbosity),
@ -288,8 +302,16 @@ static struct option builtin_merge_options[] = {
OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories, OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories,
N_("allow merging unrelated histories")), N_("allow merging unrelated histories")),
OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1), OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), {
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, .type = OPTION_STRING,
.short_name = 'S',
.long_name = "gpg-sign",
.value = &sign_commit,
.argh = N_("key-id"),
.help = N_("GPG sign commit"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
OPT_AUTOSTASH(&autostash), OPT_AUTOSTASH(&autostash),
OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")), OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")), OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")),

View File

@ -245,7 +245,7 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,
{ {
struct option *options; struct option *options;
static struct option builtin_multi_pack_index_repack_options[] = { static struct option builtin_multi_pack_index_repack_options[] = {
OPT_MAGNITUDE(0, "batch-size", &opts.batch_size, OPT_UNSIGNED(0, "batch-size", &opts.batch_size,
N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")), N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
OPT_BIT(0, "progress", &opts.flags, OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS), N_("force progress reporting"), MIDX_PROGRESS),

View File

@ -4488,7 +4488,7 @@ int cmd_pack_objects(int argc,
OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"), OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"),
N_("write the pack index file in the specified idx format version"), N_("write the pack index file in the specified idx format version"),
PARSE_OPT_NONEG, option_parse_index_version), PARSE_OPT_NONEG, option_parse_index_version),
OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit, OPT_UNSIGNED(0, "max-pack-size", &pack_size_limit,
N_("maximum size of each output pack file")), N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local, OPT_BOOL(0, "local", &local,
N_("ignore borrowed objects from alternate object store")), N_("ignore borrowed objects from alternate object store")),
@ -4496,7 +4496,7 @@ int cmd_pack_objects(int argc,
N_("ignore packed objects")), N_("ignore packed objects")),
OPT_INTEGER(0, "window", &window, OPT_INTEGER(0, "window", &window,
N_("limit pack window by objects")), N_("limit pack window by objects")),
OPT_MAGNITUDE(0, "window-memory", &window_memory_limit, OPT_UNSIGNED(0, "window-memory", &window_memory_limit,
N_("limit pack window by memory in addition to object limit")), N_("limit pack window by memory in addition to object limit")),
OPT_INTEGER(0, "depth", &depth, OPT_INTEGER(0, "depth", &depth,
N_("maximum length of delta chain allowed in the resulting pack")), N_("maximum length of delta chain allowed in the resulting pack")),

View File

@ -135,9 +135,14 @@ int cmd_read_tree(int argc,
N_("3-way merge in presence of adds and removes")), N_("3-way merge in presence of adds and removes")),
OPT_BOOL(0, "reset", &opts.reset, OPT_BOOL(0, "reset", &opts.reset,
N_("same as -m, but discard unmerged entries")), N_("same as -m, but discard unmerged entries")),
{ OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"), {
N_("read the tree into the index under <subdirectory>/"), .type = OPTION_STRING,
PARSE_OPT_NONEG }, .long_name = "prefix",
.value = &opts.prefix,
.argh = N_("<subdirectory>/"),
.help = N_("read the tree into the index under <subdirectory>/"),
.flags = PARSE_OPT_NONEG,
},
OPT_BOOL('u', NULL, &opts.update, OPT_BOOL('u', NULL, &opts.update,
N_("update working tree with merge result")), N_("update working tree with merge result")),
OPT_CALLBACK_F(0, "exclude-per-directory", &opts, OPT_CALLBACK_F(0, "exclude-per-directory", &opts,

View File

@ -1123,9 +1123,15 @@ int cmd_rebase(int argc,
OPT_BIT('v', "verbose", &options.flags, OPT_BIT('v', "verbose", &options.flags,
N_("display a diffstat of what changed upstream"), N_("display a diffstat of what changed upstream"),
REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT), REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL, {
N_("do not show diffstat of what changed upstream"), .type = OPTION_NEGBIT,
PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT }, .short_name = 'n',
.long_name = "no-stat",
.value = &options.flags,
.help = N_("do not show diffstat of what changed upstream"),
.flags = PARSE_OPT_NOARG,
.defval = REBASE_DIFFSTAT,
},
OPT_BOOL(0, "signoff", &options.signoff, OPT_BOOL(0, "signoff", &options.signoff,
N_("add a Signed-off-by trailer to each commit")), N_("add a Signed-off-by trailer to each commit")),
OPT_BOOL(0, "committer-date-is-author-date", OPT_BOOL(0, "committer-date-is-author-date",
@ -1191,9 +1197,16 @@ int cmd_rebase(int argc,
OPT_BOOL(0, "update-refs", &options.update_refs, OPT_BOOL(0, "update-refs", &options.update_refs,
N_("update branches that point to commits " N_("update branches that point to commits "
"that are being rebased")), "that are being rebased")),
{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"), {
N_("GPG-sign commits"), .type = OPTION_STRING,
PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, .short_name = 'S',
.long_name = "gpg-sign",
.value = &gpg_sign,
.argh = N_("key-id"),
.help = N_("GPG-sign commits"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
OPT_AUTOSTASH(&options.autostash), OPT_AUTOSTASH(&options.autostash),
OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"), OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"),
N_("add exec lines after each commit of the " N_("add exec lines after each commit of the "

View File

@ -1171,10 +1171,10 @@ int cmd_repack(int argc,
PACK_CRUFT), PACK_CRUFT),
OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"), OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
N_("with --cruft, expire objects older than this")), N_("with --cruft, expire objects older than this")),
OPT_MAGNITUDE(0, "combine-cruft-below-size", OPT_UNSIGNED(0, "combine-cruft-below-size",
&combine_cruft_below_size, &combine_cruft_below_size,
N_("with --cruft, only repack cruft packs smaller than this")), N_("with --cruft, only repack cruft packs smaller than this")),
OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size, OPT_UNSIGNED(0, "max-cruft-size", &cruft_po_args.max_pack_size,
N_("with --cruft, limit the size of new cruft packs")), N_("with --cruft, limit the size of new cruft packs")),
OPT_BOOL('d', NULL, &delete_redundant, OPT_BOOL('d', NULL, &delete_redundant,
N_("remove redundant packs, and run git-prune-packed")), N_("remove redundant packs, and run git-prune-packed")),
@ -1205,7 +1205,7 @@ int cmd_repack(int argc,
N_("limits the maximum delta depth")), N_("limits the maximum delta depth")),
OPT_STRING(0, "threads", &opt_threads, N_("n"), OPT_STRING(0, "threads", &opt_threads, N_("n"),
N_("limits the maximum number of threads")), N_("limits the maximum number of threads")),
OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size, OPT_UNSIGNED(0, "max-pack-size", &po_args.max_pack_size,
N_("maximum size of each packfile")), N_("maximum size of each packfile")),
OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options), OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects, OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,

View File

@ -132,8 +132,16 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")), OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")),
OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"), OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
N_("option for merge strategy")), N_("option for merge strategy")),
{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"), {
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, .type = OPTION_STRING,
.short_name = 'S',
.long_name = "gpg-sign",
.value = &gpg_sign,
.argh = N_("key-id"),
.help = N_("GPG sign commit"),
.flags = PARSE_OPT_OPTARG,
.defval = (intptr_t) "",
},
OPT_END() OPT_END()
}; };
struct option *options = base_options; struct option *options = base_options;

View File

@ -667,9 +667,16 @@ int cmd_show_branch(int ac,
N_("show remote-tracking branches")), N_("show remote-tracking branches")),
OPT__COLOR(&showbranch_use_color, OPT__COLOR(&showbranch_use_color,
N_("color '*!+-' corresponding to the branch")), N_("color '*!+-' corresponding to the branch")),
{ OPTION_INTEGER, 0, "more", &extra, N_("n"), {
N_("show <n> more commits after the common ancestor"), .type = OPTION_INTEGER,
PARSE_OPT_OPTARG, NULL, (intptr_t)1 }, .long_name = "more",
.value = &extra,
.precision = sizeof(extra),
.argh = N_("n"),
.help = N_("show <n> more commits after the common ancestor"),
.flags = PARSE_OPT_OPTARG,
.defval = 1,
},
OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1), OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1),
OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")), OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")),
OPT_BOOL(0, "current", &with_current_branch, OPT_BOOL(0, "current", &with_current_branch,

View File

@ -480,9 +480,16 @@ int cmd_tag(int argc,
int edit_flag = 0; int edit_flag = 0;
struct option options[] = { struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"), {
N_("print <n> lines of each tag message"), .type = OPTION_INTEGER,
PARSE_OPT_OPTARG, NULL, 1 }, .short_name = 'n',
.value = &filter.lines,
.precision = sizeof(filter.lines),
.argh = N_("n"),
.help = N_("print <n> lines of each tag message"),
.flags = PARSE_OPT_OPTARG,
.defval = 1,
},
OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'), OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'),
OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'), OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'),


@ -514,9 +521,14 @@ int cmd_tag(int argc,
N_("do not output a newline after empty formatted refs")), N_("do not output a newline after empty formatted refs")),
OPT_REF_SORT(&sorting_options), OPT_REF_SORT(&sorting_options),
{ {
OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), .type = OPTION_CALLBACK,
N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT, .long_name = "points-at",
parse_opt_object_name, (intptr_t) "HEAD" .value = &filter.points_at,
.argh = N_("object"),
.help = N_("print only tags of the object"),
.flags = PARSE_OPT_LASTARG_DEFAULT,
.callback = parse_opt_object_name,
.defval = (intptr_t) "HEAD",
}, },
OPT_STRING( 0 , "format", &format.format, N_("format"), OPT_STRING( 0 , "format", &format.format, N_("format"),
N_("format to use for the output")), N_("format to use for the output")),

View File

@ -964,29 +964,51 @@ int cmd_update_index(int argc,
N_("like --refresh, but ignore assume-unchanged setting"), N_("like --refresh, but ignore assume-unchanged setting"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, PARSE_OPT_NOARG | PARSE_OPT_NONEG,
really_refresh_callback), really_refresh_callback),
{OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, {
N_("<mode>,<object>,<path>"), .type = OPTION_LOWLEVEL_CALLBACK,
N_("add the specified entry to the index"), .long_name = "cacheinfo",
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ .argh = N_("<mode>,<object>,<path>"),
.help = N_("add the specified entry to the index"),
.flags = PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
NULL, 0, .ll_callback = cacheinfo_callback,
cacheinfo_callback}, },
OPT_CALLBACK_F(0, "chmod", &set_executable_bit, "(+|-)x", OPT_CALLBACK_F(0, "chmod", &set_executable_bit, "(+|-)x",
N_("override the executable bit of the listed files"), N_("override the executable bit of the listed files"),
PARSE_OPT_NONEG, PARSE_OPT_NONEG,
chmod_callback), chmod_callback),
{OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, {
N_("mark files as \"not changing\""), .type = OPTION_SET_INT,
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, .long_name = "assume-unchanged",
{OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, .value = &mark_valid_only,
N_("clear assumed-unchanged bit"), .help = N_("mark files as \"not changing\""),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
{OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, .defval = MARK_FLAG,
N_("mark files as \"index-only\""), },
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {
{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, .type = OPTION_SET_INT,
N_("clear skip-worktree bit"), .long_name = "no-assume-unchanged",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, .value = &mark_valid_only,
.help = N_("clear assumed-unchanged bit"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = UNMARK_FLAG,
},
{
.type = OPTION_SET_INT,
.long_name = "skip-worktree",
.value = &mark_skip_worktree_only,
.help = N_("mark files as \"index-only\""),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = MARK_FLAG,
},
{
.type = OPTION_SET_INT,
.long_name = "no-skip-worktree",
.value = &mark_skip_worktree_only,
.help = N_("clear skip-worktree bit"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = UNMARK_FLAG,
},
OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries, OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries,
N_("do not touch index-only entries")), N_("do not touch index-only entries")),
OPT_SET_INT(0, "info-only", &info_only, OPT_SET_INT(0, "info-only", &info_only,
@ -995,22 +1017,39 @@ int cmd_update_index(int argc,
N_("remove named paths even if present in worktree"), 1), N_("remove named paths even if present in worktree"), 1),
OPT_BOOL('z', NULL, &nul_term_line, OPT_BOOL('z', NULL, &nul_term_line,
N_("with --stdin: input lines are terminated by null bytes")), N_("with --stdin: input lines are terminated by null bytes")),
{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, {
N_("read list of paths to be updated from standard input"), .type = OPTION_LOWLEVEL_CALLBACK,
PARSE_OPT_NONEG | PARSE_OPT_NOARG, .long_name = "stdin",
NULL, 0, stdin_callback}, .value = &read_from_stdin,
{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL, .help = N_("read list of paths to be updated from standard input"),
N_("add entries from standard input to the index"), .flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG,
PARSE_OPT_NONEG | PARSE_OPT_NOARG, .ll_callback = stdin_callback,
NULL, 0, stdin_cacheinfo_callback}, },
{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, {
N_("repopulate stages #2 and #3 for the listed paths"), .type = OPTION_LOWLEVEL_CALLBACK,
PARSE_OPT_NONEG | PARSE_OPT_NOARG, .long_name = "index-info",
NULL, 0, unresolve_callback}, .value = &nul_term_line,
{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, .help = N_("add entries from standard input to the index"),
N_("only update entries that differ from HEAD"), .flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG,
PARSE_OPT_NONEG | PARSE_OPT_NOARG, .ll_callback = stdin_cacheinfo_callback,
NULL, 0, reupdate_callback}, },
{
.type = OPTION_LOWLEVEL_CALLBACK,
.long_name = "unresolve",
.value = &has_errors,
.help = N_("repopulate stages #2 and #3 for the listed paths"),
.flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG,
.ll_callback = unresolve_callback,
},
{
.type = OPTION_LOWLEVEL_CALLBACK,
.short_name = 'g',
.long_name = "again",
.value = &has_errors,
.help = N_("only update entries that differ from HEAD"),
.flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG,
.ll_callback = reupdate_callback,
},
OPT_BIT(0, "ignore-missing", &refresh_args.flags, OPT_BIT(0, "ignore-missing", &refresh_args.flags,
N_("ignore files missing from worktree"), N_("ignore files missing from worktree"),
REFRESH_IGNORE_MISSING), REFRESH_IGNORE_MISSING),
@ -1036,12 +1075,22 @@ int cmd_update_index(int argc,
N_("write out the index even if is not flagged as changed"), 1), N_("write out the index even if is not flagged as changed"), 1),
OPT_BOOL(0, "fsmonitor", &fsmonitor, OPT_BOOL(0, "fsmonitor", &fsmonitor,
N_("enable or disable file system monitor")), N_("enable or disable file system monitor")),
{OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL, {
N_("mark files as fsmonitor valid"), .type = OPTION_SET_INT,
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, .long_name = "fsmonitor-valid",
{OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL, .value = &mark_fsmonitor_only,
N_("clear fsmonitor valid bit"), .help = N_("mark files as fsmonitor valid"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = MARK_FLAG,
},
{
.type = OPTION_SET_INT,
.long_name = "no-fsmonitor-valid",
.value = &mark_fsmonitor_only,
.help = N_("clear fsmonitor valid bit"),
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = UNMARK_FLAG,
},
OPT_END() OPT_END()
}; };



View File

@ -31,10 +31,14 @@ int cmd_write_tree(int argc,
WRITE_TREE_MISSING_OK), WRITE_TREE_MISSING_OK),
OPT_STRING(0, "prefix", &tree_prefix, N_("<prefix>/"), OPT_STRING(0, "prefix", &tree_prefix, N_("<prefix>/"),
N_("write tree object for a subdirectory <prefix>")), N_("write tree object for a subdirectory <prefix>")),
{ OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL, {
N_("only useful for debugging"), .type = OPTION_BIT,
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL, .long_name = "ignore-cache-tree",
WRITE_TREE_IGNORE_CACHE_TREE }, .value = &flags,
.help = N_("only useful for debugging"),
.flags = PARSE_OPT_HIDDEN | PARSE_OPT_NOARG,
.defval = WRITE_TREE_IGNORE_CACHE_TREE,
},
OPT_END() OPT_END()
}; };



13
diff.c
View File

@ -5894,10 +5894,15 @@ struct option *add_diff_options(const struct option *opts,
OPT_CALLBACK_F(0, "diff-filter", options, N_("[(A|C|D|M|R|T|U|X|B)...[*]]"), OPT_CALLBACK_F(0, "diff-filter", options, N_("[(A|C|D|M|R|T|U|X|B)...[*]]"),
N_("select files by diff type"), N_("select files by diff type"),
PARSE_OPT_NONEG, diff_opt_diff_filter), PARSE_OPT_NONEG, diff_opt_diff_filter),
{ OPTION_CALLBACK, 0, "output", options, N_("<file>"), {
N_("output to a specific file"), .type = OPTION_CALLBACK,
PARSE_OPT_NONEG, NULL, 0, diff_opt_output }, .long_name = "output",

.value = options,
.argh = N_("<file>"),
.help = N_("output to a specific file"),
.flags = PARSE_OPT_NONEG,
.ll_callback = diff_opt_output,
},
OPT_END() OPT_END()
}; };



View File

@ -93,12 +93,19 @@ DISABLE_WARNING(-Wsign-compare)
# define BARF_UNLESS_COPYABLE(dst, src) \ # define BARF_UNLESS_COPYABLE(dst, src) \
BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(__typeof__(*(dst)), \ BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(__typeof__(*(dst)), \
__typeof__(*(src)))) __typeof__(*(src))))

# define BARF_UNLESS_SIGNED(var) BUILD_ASSERT_OR_ZERO(((__typeof__(var)) -1) < 0)
# define BARF_UNLESS_UNSIGNED(var) BUILD_ASSERT_OR_ZERO(((__typeof__(var)) -1) > 0)
#else #else
# define BARF_UNLESS_AN_ARRAY(arr) 0 # define BARF_UNLESS_AN_ARRAY(arr) 0
# define BARF_UNLESS_COPYABLE(dst, src) \ # define BARF_UNLESS_COPYABLE(dst, src) \
BUILD_ASSERT_OR_ZERO(0 ? ((*(dst) = *(src)), 0) : \ BUILD_ASSERT_OR_ZERO(0 ? ((*(dst) = *(src)), 0) : \
sizeof(*(dst)) == sizeof(*(src))) sizeof(*(dst)) == sizeof(*(src)))

# define BARF_UNLESS_SIGNED(var) 0
# define BARF_UNLESS_UNSIGNED(var) 0
#endif #endif

/* /*
* ARRAY_SIZE - get the number of elements in a visible array * ARRAY_SIZE - get the number of elements in a visible array
* @x: the array whose size you want. * @x: the array whose size you want.

View File

@ -73,7 +73,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
enum opt_parsed flags, enum opt_parsed flags,
const char **argp) const char **argp)
{ {
const char *s, *arg; const char *arg;
const int unset = flags & OPT_UNSET; const int unset = flags & OPT_UNSET;
int err; int err;


@ -172,41 +172,93 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
return (*opt->ll_callback)(p, opt, p_arg, p_unset); return (*opt->ll_callback)(p, opt, p_arg, p_unset);
} }
case OPTION_INTEGER: case OPTION_INTEGER:
if (unset) { {
*(int *)opt->value = 0; intmax_t upper_bound = INTMAX_MAX >> (bitsizeof(intmax_t) - CHAR_BIT * opt->precision);
return 0; intmax_t lower_bound = -upper_bound - 1;
} intmax_t value;
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
*(int *)opt->value = opt->defval;
return 0;
}
if (get_arg(p, opt, flags, &arg))
return -1;
if (!*arg)
return error(_("%s expects a numerical value"),
optname(opt, flags));
*(int *)opt->value = strtol(arg, (char **)&s, 10);
if (*s)
return error(_("%s expects a numerical value"),
optname(opt, flags));
return 0;


case OPTION_MAGNITUDE:
if (unset) { if (unset) {
*(unsigned long *)opt->value = 0; value = 0;
return 0; } else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
} value = opt->defval;
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { } else if (get_arg(p, opt, flags, &arg)) {
*(unsigned long *)opt->value = opt->defval;
return 0;
}
if (get_arg(p, opt, flags, &arg))
return -1; return -1;
if (!git_parse_ulong(arg, opt->value)) } else if (!*arg) {
return error(_("%s expects a numerical value"),
optname(opt, flags));
} else if (!git_parse_signed(arg, &value, upper_bound)) {
if (errno == ERANGE)
return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"),
arg, optname(opt, flags), lower_bound, upper_bound);

return error(_("%s expects an integer value with an optional k/m/g suffix"),
optname(opt, flags));
}

if (value < lower_bound)
return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"),
arg, optname(opt, flags), (intmax_t)lower_bound, (intmax_t)upper_bound);

switch (opt->precision) {
case 1:
*(int8_t *)opt->value = value;
return 0;
case 2:
*(int16_t *)opt->value = value;
return 0;
case 4:
*(int32_t *)opt->value = value;
return 0;
case 8:
*(int64_t *)opt->value = value;
return 0;
default:
BUG("invalid precision for option %s",
optname(opt, flags));
}
}
case OPTION_UNSIGNED:
{
uintmax_t upper_bound = UINTMAX_MAX >> (bitsizeof(uintmax_t) - CHAR_BIT * opt->precision);
uintmax_t value;

if (unset) {
value = 0;
} else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
value = opt->defval;
} else if (get_arg(p, opt, flags, &arg)) {
return -1;
} else if (!*arg) {
return error(_("%s expects a numerical value"),
optname(opt, flags));
} else if (!git_parse_unsigned(arg, &value, upper_bound)) {
if (errno == ERANGE)
return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"),
arg, optname(opt, flags), (uintmax_t) 0, upper_bound);

return error(_("%s expects a non-negative integer value" return error(_("%s expects a non-negative integer value"
" with an optional k/m/g suffix"), " with an optional k/m/g suffix"),
optname(opt, flags)); optname(opt, flags));
}

switch (opt->precision) {
case 1:
*(uint8_t *)opt->value = value;
return 0; return 0;
case 2:
*(uint16_t *)opt->value = value;
return 0;
case 4:
*(uint32_t *)opt->value = value;
return 0;
case 8:
*(uint64_t *)opt->value = value;
return 0;
default:
BUG("invalid precision for option %s",
optname(opt, flags));
}
}


default: default:
BUG("opt->type %d should not happen", opt->type); BUG("opt->type %d should not happen", opt->type);
@ -656,7 +708,7 @@ static void show_negated_gitcomp(const struct option *opts, int show_all,
case OPTION_STRING: case OPTION_STRING:
case OPTION_FILENAME: case OPTION_FILENAME:
case OPTION_INTEGER: case OPTION_INTEGER:
case OPTION_MAGNITUDE: case OPTION_UNSIGNED:
case OPTION_CALLBACK: case OPTION_CALLBACK:
case OPTION_BIT: case OPTION_BIT:
case OPTION_NEGBIT: case OPTION_NEGBIT:
@ -708,7 +760,7 @@ static int show_gitcomp(const struct option *opts, int show_all)
case OPTION_STRING: case OPTION_STRING:
case OPTION_FILENAME: case OPTION_FILENAME:
case OPTION_INTEGER: case OPTION_INTEGER:
case OPTION_MAGNITUDE: case OPTION_UNSIGNED:
case OPTION_CALLBACK: case OPTION_CALLBACK:
if (opts->flags & PARSE_OPT_NOARG) if (opts->flags & PARSE_OPT_NOARG)
break; break;

View File

@ -25,7 +25,7 @@ enum parse_opt_type {
/* options with arguments (usually) */ /* options with arguments (usually) */
OPTION_STRING, OPTION_STRING,
OPTION_INTEGER, OPTION_INTEGER,
OPTION_MAGNITUDE, OPTION_UNSIGNED,
OPTION_CALLBACK, OPTION_CALLBACK,
OPTION_LOWLEVEL_CALLBACK, OPTION_LOWLEVEL_CALLBACK,
OPTION_FILENAME OPTION_FILENAME
@ -92,6 +92,10 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv,
* `value`:: * `value`::
* stores pointers to the values to be filled. * stores pointers to the values to be filled.
* *
* `precision`::
* precision of the integer pointed to by `value` in number of bytes. Should
* typically be its `sizeof()`.
*
* `argh`:: * `argh`::
* token to explain the kind of argument this option wants. Does not * token to explain the kind of argument this option wants. Does not
* begin in capital letter, and does not end with a full stop. * begin in capital letter, and does not end with a full stop.
@ -151,6 +155,7 @@ struct option {
int short_name; int short_name;
const char *long_name; const char *long_name;
void *value; void *value;
size_t precision;
const char *argh; const char *argh;
const char *help; const char *help;


@ -213,7 +218,8 @@ struct option {
.type = OPTION_INTEGER, \ .type = OPTION_INTEGER, \
.short_name = (s), \ .short_name = (s), \
.long_name = (l), \ .long_name = (l), \
.value = (v), \ .value = (v) + BARF_UNLESS_SIGNED(*(v)), \
.precision = sizeof(*v), \
.argh = N_("n"), \ .argh = N_("n"), \
.help = (h), \ .help = (h), \
.flags = (f), \ .flags = (f), \
@ -270,11 +276,12 @@ struct option {
#define OPT_CMDMODE(s, l, v, h, i) OPT_CMDMODE_F(s, l, v, h, i, 0) #define OPT_CMDMODE(s, l, v, h, i) OPT_CMDMODE_F(s, l, v, h, i, 0)


#define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0) #define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0)
#define OPT_MAGNITUDE(s, l, v, h) { \ #define OPT_UNSIGNED(s, l, v, h) { \
.type = OPTION_MAGNITUDE, \ .type = OPTION_UNSIGNED, \
.short_name = (s), \ .short_name = (s), \
.long_name = (l), \ .long_name = (l), \
.value = (v), \ .value = (v) + BARF_UNLESS_UNSIGNED(*(v)), \
.precision = sizeof(*v), \
.argh = N_("n"), \ .argh = N_("n"), \
.help = (h), \ .help = (h), \
.flags = PARSE_OPT_NONEG, \ .flags = PARSE_OPT_NONEG, \

View File

@ -38,7 +38,7 @@ int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
errno = EINVAL; errno = EINVAL;
return 0; return 0;
} }
if ((val < 0 && -max / factor > val) || if ((val < 0 && (-max - 1) / factor > val) ||
(val > 0 && max / factor < val)) { (val > 0 && max / factor < val)) {
errno = ERANGE; errno = ERANGE;
return 0; return 0;
@ -51,7 +51,7 @@ int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
return 0; return 0;
} }


static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
{ {
if (value && *value) { if (value && *value) {
char *end; char *end;

View File

@ -2,6 +2,7 @@
#define PARSE_H #define PARSE_H


int git_parse_signed(const char *value, intmax_t *ret, intmax_t max); int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);
int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max);
int git_parse_ssize_t(const char *, ssize_t *); int git_parse_ssize_t(const char *, ssize_t *);
int git_parse_ulong(const char *, unsigned long *); int git_parse_ulong(const char *, unsigned long *);
int git_parse_int(const char *value, int *ret); int git_parse_int(const char *value, int *ret);

View File

@ -114,10 +114,15 @@ struct ref_format {
} }


/* Macros for checking --merged and --no-merged options */ /* Macros for checking --merged and --no-merged options */
#define _OPT_MERGED_NO_MERGED(option, filter, h) \ #define _OPT_MERGED_NO_MERGED(option, filter, h) { \
{ OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \ .type = OPTION_CALLBACK, \
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, \ .long_name = option, \
parse_opt_merge_filter, (intptr_t) "HEAD" \ .value = (filter), \
.argh = N_("commit"), \
.help = (h), \
.flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, \
.callback = parse_opt_merge_filter, \
.defval = (intptr_t) "HEAD", \
} }
#define OPT_MERGED(f, h) _OPT_MERGED_NO_MERGED("merged", f, h) #define OPT_MERGED(f, h) _OPT_MERGED_NO_MERGED("merged", f, h)
#define OPT_NO_MERGED(f, h) _OPT_MERGED_NO_MERGED("no-merged", f, h) #define OPT_NO_MERGED(f, h) _OPT_MERGED_NO_MERGED("no-merged", f, h)

View File

@ -6,7 +6,7 @@


static int boolean = 0; static int boolean = 0;
static int integer = 0; static int integer = 0;
static unsigned long magnitude = 0; static unsigned long unsigned_integer = 0;
static timestamp_t timestamp; static timestamp_t timestamp;
static int abbrev = 7; static int abbrev = 7;
static int verbose = -1; /* unspecified */ static int verbose = -1; /* unspecified */
@ -120,20 +120,31 @@ int cmd__parse_options(int argc, const char **argv)
}; };
struct string_list expect = STRING_LIST_INIT_NODUP; struct string_list expect = STRING_LIST_INIT_NODUP;
struct string_list list = STRING_LIST_INIT_NODUP; struct string_list list = STRING_LIST_INIT_NODUP;
uint16_t u16 = 0;
int16_t i16 = 0;


struct option options[] = { struct option options[] = {
OPT_BOOL(0, "yes", &boolean, "get a boolean"), OPT_BOOL(0, "yes", &boolean, "get a boolean"),
OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"), OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"),
{ OPTION_SET_INT, 'B', "no-fear", &boolean, NULL, {
"be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, .type = OPTION_SET_INT,
.short_name = 'B',
.long_name = "no-fear",
.value = &boolean,
.help = "be brave",
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
.defval = 1,
},
OPT_COUNTUP('b', "boolean", &boolean, "increment by one"), OPT_COUNTUP('b', "boolean", &boolean, "increment by one"),
OPT_BIT('4', "or4", &boolean, OPT_BIT('4', "or4", &boolean,
"bitwise-or boolean with ...0100", 4), "bitwise-or boolean with ...0100", 4),
OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4),
OPT_GROUP(""), OPT_GROUP(""),
OPT_INTEGER('i', "integer", &integer, "get a integer"), OPT_INTEGER('i', "integer", &integer, "get a integer"),
OPT_INTEGER(0, "i16", &i16, "get a 16 bit integer"),
OPT_INTEGER('j', NULL, &integer, "get a integer, too"), OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"), OPT_UNSIGNED('u', "unsigned", &unsigned_integer, "get an unsigned integer"),
OPT_UNSIGNED(0, "u16", &u16, "get a 16 bit unsigned integer"),
OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1), OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2), OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
@ -155,12 +166,27 @@ int cmd__parse_options(int argc, const char **argv)
OPT_GROUP("Magic arguments"), OPT_GROUP("Magic arguments"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback), number_callback),
{ OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", {
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, .type = OPTION_COUNTUP,
{ OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL, .short_name = '+',
"positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, .value = &boolean,
{ OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL, .help = "same as -b",
"negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
},
{
.type = OPTION_COUNTUP,
.long_name = "ambiguous",
.value = &ambiguous,
.help = "positive ambiguity",
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
},
{
.type = OPTION_COUNTUP,
.long_name = "no-ambiguous",
.value = &ambiguous,
.help = "negative ambiguity",
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
},
OPT_GROUP("Standard options"), OPT_GROUP("Standard options"),
OPT__ABBREV(&abbrev), OPT__ABBREV(&abbrev),
OPT__VERBOSE(&verbose, "be verbose"), OPT__VERBOSE(&verbose, "be verbose"),
@ -188,7 +214,9 @@ int cmd__parse_options(int argc, const char **argv)
} }
show(&expect, &ret, "boolean: %d", boolean); show(&expect, &ret, "boolean: %d", boolean);
show(&expect, &ret, "integer: %d", integer); show(&expect, &ret, "integer: %d", integer);
show(&expect, &ret, "magnitude: %lu", magnitude); show(&expect, &ret, "i16: %"PRIdMAX, (intmax_t) i16);
show(&expect, &ret, "unsigned: %lu", unsigned_integer);
show(&expect, &ret, "u16: %"PRIuMAX, (uintmax_t) u16);
show(&expect, &ret, "timestamp: %"PRItime, timestamp); show(&expect, &ret, "timestamp: %"PRItime, timestamp);
show(&expect, &ret, "string: %s", string ? string : "(not set)"); show(&expect, &ret, "string: %s", string ? string : "(not set)");
show(&expect, &ret, "abbrev: %d", abbrev); show(&expect, &ret, "abbrev: %d", abbrev);

View File

@ -22,8 +22,10 @@ usage: test-tool parse-options <options>


-i, --[no-]integer <n> -i, --[no-]integer <n>
get a integer get a integer
--[no-]i16 <n> get a 16 bit integer
-j <n> get a integer, too -j <n> get a integer, too
-m, --magnitude <n> get a magnitude -u, --unsigned <n> get an unsigned integer
--u16 <n> get a 16 bit unsigned integer
--[no-]set23 set integer to 23 --[no-]set23 set integer to 23
--mode1 set integer to 1 (cmdmode option) --mode1 set integer to 1 (cmdmode option)
--mode2 set integer to 2 (cmdmode option) --mode2 set integer to 2 (cmdmode option)
@ -111,32 +113,36 @@ test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear


test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'


test_expect_success 'OPT_INT() negative' 'check integer: -2345 -i -2345' test_expect_success 'OPT_INTEGER() negative' 'check integer: -2345 -i -2345'
test_expect_success 'OPT_INTEGER() kilo' 'check integer: 239616 -i 234k'
test_expect_success 'OPT_INTEGER() negative kilo' 'check integer: -239616 -i -234k'


test_expect_success 'OPT_MAGNITUDE() simple' ' test_expect_success 'OPT_UNSIGNED() simple' '
check magnitude: 2345678 -m 2345678 check unsigned: 2345678 -u 2345678
' '


test_expect_success 'OPT_MAGNITUDE() kilo' ' test_expect_success 'OPT_UNSIGNED() kilo' '
check magnitude: 239616 -m 234k check unsigned: 239616 -u 234k
' '


test_expect_success 'OPT_MAGNITUDE() mega' ' test_expect_success 'OPT_UNSIGNED() mega' '
check magnitude: 104857600 -m 100m check unsigned: 104857600 -u 100m
' '


test_expect_success 'OPT_MAGNITUDE() giga' ' test_expect_success 'OPT_UNSIGNED() giga' '
check magnitude: 1073741824 -m 1g check unsigned: 1073741824 -u 1g
' '


test_expect_success 'OPT_MAGNITUDE() 3giga' ' test_expect_success 'OPT_UNSIGNED() 3giga' '
check magnitude: 3221225472 -m 3g check unsigned: 3221225472 -u 3g
' '


cat >expect <<\EOF cat >expect <<\EOF
boolean: 2 boolean: 2
integer: 1729 integer: 1729
magnitude: 16384 i16: 0
unsigned: 16384
u16: 0
timestamp: 0 timestamp: 0
string: 123 string: 123
abbrev: 7 abbrev: 7
@ -147,7 +153,7 @@ file: prefix/my.file
EOF EOF


test_expect_success 'short options' ' test_expect_success 'short options' '
test-tool parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \ test-tool parse-options -s123 -b -i 1729 -u 16k -b -vv -n -F my.file \
>output 2>output.err && >output 2>output.err &&
test_cmp expect output && test_cmp expect output &&
test_must_be_empty output.err test_must_be_empty output.err
@ -156,7 +162,9 @@ test_expect_success 'short options' '
cat >expect <<\EOF cat >expect <<\EOF
boolean: 2 boolean: 2
integer: 1729 integer: 1729
magnitude: 16384 i16: 9000
unsigned: 16384
u16: 32768
timestamp: 0 timestamp: 0
string: 321 string: 321
abbrev: 10 abbrev: 10
@ -167,8 +175,8 @@ file: prefix/fi.le
EOF EOF


test_expect_success 'long options' ' test_expect_success 'long options' '
test-tool parse-options --boolean --integer 1729 --magnitude 16k \ test-tool parse-options --boolean --integer 1729 --i16 9000 --unsigned 16k \
--boolean --string2=321 --verbose --verbose --no-dry-run \ --u16 32k --boolean --string2=321 --verbose --verbose --no-dry-run \
--abbrev=10 --file fi.le --obsolete \ --abbrev=10 --file fi.le --obsolete \
>output 2>output.err && >output 2>output.err &&
test_must_be_empty output.err && test_must_be_empty output.err &&
@ -179,7 +187,9 @@ test_expect_success 'abbreviate to something longer than SHA1 length' '
cat >expect <<-EOF && cat >expect <<-EOF &&
boolean: 0 boolean: 0
integer: 0 integer: 0
magnitude: 0 i16: 0
unsigned: 0
u16: 0
timestamp: 0 timestamp: 0
string: (not set) string: (not set)
abbrev: 100 abbrev: 100
@ -253,7 +263,9 @@ test_expect_success 'superfluous value provided: cmdmode' '
cat >expect <<\EOF cat >expect <<\EOF
boolean: 1 boolean: 1
integer: 13 integer: 13
magnitude: 0 i16: 0
unsigned: 0
u16: 0
timestamp: 0 timestamp: 0
string: 123 string: 123
abbrev: 7 abbrev: 7
@ -276,7 +288,9 @@ test_expect_success 'intermingled arguments' '
cat >expect <<\EOF cat >expect <<\EOF
boolean: 0 boolean: 0
integer: 2 integer: 2
magnitude: 0 i16: 0
unsigned: 0
u16: 0
timestamp: 0 timestamp: 0
string: (not set) string: (not set)
abbrev: 7 abbrev: 7
@ -343,7 +357,9 @@ cat >expect <<\EOF
Callback: "four", 0 Callback: "four", 0
boolean: 5 boolean: 5
integer: 4 integer: 4
magnitude: 0 i16: 0
unsigned: 0
u16: 0
timestamp: 0 timestamp: 0
string: (not set) string: (not set)
abbrev: 7 abbrev: 7
@ -368,7 +384,9 @@ test_expect_success 'OPT_CALLBACK() and callback errors work' '
cat >expect <<\EOF cat >expect <<\EOF
boolean: 1 boolean: 1
integer: 23 integer: 23
magnitude: 0 i16: 0
unsigned: 0
u16: 0
timestamp: 0 timestamp: 0
string: (not set) string: (not set)
abbrev: 7 abbrev: 7
@ -447,7 +465,9 @@ test_expect_success 'OPT_NUMBER_CALLBACK() works' '
cat >expect <<\EOF cat >expect <<\EOF
boolean: 0 boolean: 0
integer: 0 integer: 0
magnitude: 0 i16: 0
unsigned: 0
u16: 0
timestamp: 0 timestamp: 0
string: (not set) string: (not set)
abbrev: 7 abbrev: 7
@ -771,16 +791,35 @@ test_expect_success 'subcommands are incompatible with KEEP_DASHDASH unless in c
grep ^BUG err grep ^BUG err
' '


test_expect_success 'negative magnitude' ' test_expect_success 'negative unsigned' '
test_must_fail test-tool parse-options --magnitude -1 >out 2>err && test_must_fail test-tool parse-options --unsigned -1 >out 2>err &&
grep "non-negative integer" err && grep "non-negative integer" err &&
test_must_be_empty out test_must_be_empty out
' '


test_expect_success 'magnitude with units but no numbers' ' test_expect_success 'unsigned with units but no numbers' '
test_must_fail test-tool parse-options --magnitude m >out 2>err && test_must_fail test-tool parse-options --unsigned m >out 2>err &&
grep "non-negative integer" err && grep "non-negative integer" err &&
test_must_be_empty out test_must_be_empty out
' '


test_expect_success 'i16 limits range' '
test-tool parse-options --i16 32767 >out &&
test_grep "i16: 32767" out &&
test_must_fail test-tool parse-options --i16 32768 2>err &&
test_grep "value 32768 for option .i16. not in range \[-32768,32767\]" err &&

test-tool parse-options --i16 -32768 >out &&
test_grep "i16: -32768" out &&
test_must_fail test-tool parse-options --i16 -32769 2>err &&
test_grep "value -32769 for option .i16. not in range \[-32768,32767\]" err
'

test_expect_success 'u16 limits range' '
test-tool parse-options --u16 65535 >out &&
test_grep "u16: 65535" out &&
test_must_fail test-tool parse-options --u16 65536 2>err &&
test_grep "value 65536 for option .u16. not in range \[0,65535\]" err
'

test_done test_done