Git fork

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

+649 -245
+6 -4
Documentation/technical/api-parse-options.adoc
··· 211 211 Use of `--no-option` will clear the list of preceding values. 212 212 213 213 `OPT_INTEGER(short, long, &int_var, description)`:: 214 - Introduce an option with integer argument. 215 - The integer is put into `int_var`. 214 + Introduce an option with integer argument. The argument must be a 215 + integer and may include a suffix of 'k', 'm' or 'g' to 216 + scale the provided value by 1024, 1024^2 or 1024^3 respectively. 217 + The scaled value is put into `int_var`. 216 218 217 - `OPT_MAGNITUDE(short, long, &unsigned_long_var, description)`:: 218 - Introduce an option with a size argument. The argument must be a 219 + `OPT_UNSIGNED(short, long, &unsigned_long_var, description)`:: 220 + Introduce an option with an unsigned integer argument. The argument must be a 219 221 non-negative integer and may include a suffix of 'k', 'm' or 'g' to 220 222 scale the provided value by 1024, 1024^2 or 1024^3 respectively. 221 223 The scaled value is put into `unsigned_long_var`.
+2 -2
apply.c
··· 5123 5123 /* Think twice before adding "--nul" synonym to this */ 5124 5124 OPT_SET_INT('z', NULL, &state->line_termination, 5125 5125 N_("paths are separated with NUL character"), '\0'), 5126 - OPT_INTEGER('C', NULL, &state->p_context, 5127 - N_("ensure at least <n> lines of context match")), 5126 + OPT_UNSIGNED('C', NULL, &state->p_context, 5127 + N_("ensure at least <n> lines of context match")), 5128 5128 OPT_CALLBACK(0, "whitespace", state, N_("action"), 5129 5129 N_("detect new or modified lines that have whitespace errors"), 5130 5130 apply_option_parse_whitespace),
+26 -9
archive.c
··· 650 650 OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")), 651 651 OPT_STRING(0, "prefix", &base, N_("prefix"), 652 652 N_("prepend prefix to each pathname in the archive")), 653 - { OPTION_CALLBACK, 0, "add-file", args, N_("file"), 654 - N_("add untracked file to archive"), 0, add_file_cb, 655 - (intptr_t)&base }, 656 - { OPTION_CALLBACK, 0, "add-virtual-file", args, 657 - N_("path:content"), N_("add untracked file to archive"), 0, 658 - add_file_cb, (intptr_t)&base }, 653 + { 654 + .type = OPTION_CALLBACK, 655 + .long_name = "add-file", 656 + .value = args, 657 + .argh = N_("file"), 658 + .help = N_("add untracked file to archive"), 659 + .callback = add_file_cb, 660 + .defval = (intptr_t) &base, 661 + }, 662 + { 663 + .type = OPTION_CALLBACK, 664 + .long_name = "add-virtual-file", 665 + .value = args, 666 + .argh = N_("path:content"), 667 + .help = N_("add untracked file to archive"), 668 + .callback = add_file_cb, 669 + .defval = (intptr_t) &base, 670 + }, 659 671 OPT_STRING('o', "output", &output, N_("file"), 660 672 N_("write the archive to this file")), 661 673 OPT_BOOL(0, "worktree-attributes", &worktree_attributes, 662 674 N_("read .gitattributes in working directory")), 663 675 OPT__VERBOSE(&verbose, N_("report archived files on stderr")), 664 - { OPTION_STRING, 0, "mtime", &mtime_option, N_("time"), 665 - N_("set modification time of archive entries"), 666 - PARSE_OPT_NONEG }, 676 + { 677 + .type = OPTION_STRING, 678 + .long_name = "mtime", 679 + .value = &mtime_option, 680 + .argh = N_("time"), 681 + .help = N_("set modification time of archive entries"), 682 + .flags = PARSE_OPT_NONEG, 683 + }, 667 684 OPT_NUMBER_CALLBACK(&compression_level, 668 685 N_("set compression level"), number_callback), 669 686 OPT_GROUP(""),
+20 -8
builtin/am.c
··· 2400 2400 OPT_CMDMODE(0, "quit", &resume_mode, 2401 2401 N_("abort the patching operation but keep HEAD where it is"), 2402 2402 RESUME_QUIT), 2403 - { OPTION_CALLBACK, 0, "show-current-patch", &resume_mode, 2404 - "(diff|raw)", 2405 - N_("show the patch being applied"), 2406 - PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, 2407 - parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW }, 2403 + { 2404 + .type = OPTION_CALLBACK, 2405 + .long_name = "show-current-patch", 2406 + .value = &resume_mode, 2407 + .argh = "(diff|raw)", 2408 + .help = N_("show the patch being applied"), 2409 + .flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, 2410 + .callback = parse_opt_show_current_patch, 2411 + .defval = RESUME_SHOW_PATCH_RAW, 2412 + }, 2408 2413 OPT_CMDMODE(0, "retry", &resume_mode, 2409 2414 N_("try to apply current patch again"), 2410 2415 RESUME_APPLY), ··· 2417 2422 OPT_BOOL(0, "ignore-date", &state.ignore_date, 2418 2423 N_("use current timestamp for author date")), 2419 2424 OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate), 2420 - { OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"), 2421 - N_("GPG-sign commits"), 2422 - PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, 2425 + { 2426 + .type = OPTION_STRING, 2427 + .short_name = 'S', 2428 + .long_name = "gpg-sign", 2429 + .value = &state.sign_commit, 2430 + .argh = N_("key-id"), 2431 + .help = N_("GPG-sign commits"), 2432 + .flags = PARSE_OPT_OPTARG, 2433 + .defval = (intptr_t) "", 2434 + }, 2423 2435 OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)", 2424 2436 N_("how to handle empty patches"), 2425 2437 PARSE_OPT_NONEG, am_option_parse_empty),
+2 -2
builtin/backfill.c
··· 123 123 .sparse = 0, 124 124 }; 125 125 struct option options[] = { 126 - OPT_INTEGER(0, "min-batch-size", &ctx.min_batch_size, 127 - N_("Minimum number of objects to request at a time")), 126 + OPT_UNSIGNED(0, "min-batch-size", &ctx.min_batch_size, 127 + N_("Minimum number of objects to request at a time")), 128 128 OPT_BOOL(0, "sparse", &ctx.sparse, 129 129 N_("Restrict the missing objects to the current sparse-checkout")), 130 130 OPT_END(),
+10 -3
builtin/clone.c
··· 932 932 N_("don't use local hardlinks, always copy")), 933 933 OPT_BOOL('s', "shared", &option_shared, 934 934 N_("setup as shared repository")), 935 - { OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules, 936 - N_("pathspec"), N_("initialize submodules in the clone"), 937 - PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." }, 935 + { 936 + .type = OPTION_CALLBACK, 937 + .long_name = "recurse-submodules", 938 + .value = &option_recurse_submodules, 939 + .argh = N_("pathspec"), 940 + .help = N_("initialize submodules in the clone"), 941 + .flags = PARSE_OPT_OPTARG, 942 + .callback = recurse_submodules_cb, 943 + .defval = (intptr_t)".", 944 + }, 938 945 OPT_ALIAS(0, "recursive", "recurse-submodules"), 939 946 OPT_INTEGER('j', "jobs", &max_jobs, 940 947 N_("number of submodules cloned in parallel")),
+1 -1
builtin/column.c
··· 31 31 struct option options[] = { 32 32 OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")), 33 33 OPT_COLUMN(0, "mode", &colopts, N_("layout to use")), 34 - OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")), 34 + OPT_UNSIGNED(0, "raw-mode", &colopts, N_("layout to use")), 35 35 OPT_INTEGER(0, "width", &copts.width, N_("maximum width")), 36 36 OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("padding space on left border")), 37 37 OPT_STRING(0, "nl", &copts.nl, N_("string"), N_("padding space on right border")),
+10 -2
builtin/commit-tree.c
··· 111 111 OPT_CALLBACK_F('F', NULL, &buffer, N_("file"), 112 112 N_("read commit log message from file"), PARSE_OPT_NONEG, 113 113 parse_file_arg_callback), 114 - { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), 115 - N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, 114 + { 115 + .type = OPTION_STRING, 116 + .short_name = 'S', 117 + .long_name = "gpg-sign", 118 + .value = &sign_commit, 119 + .argh = N_("key-id"), 120 + .help = N_("GPG sign commit"), 121 + .flags = PARSE_OPT_OPTARG, 122 + .defval = (intptr_t) "", 123 + }, 116 124 OPT_END() 117 125 }; 118 126 int ret;
+48 -14
builtin/commit.c
··· 1542 1542 STATUS_FORMAT_LONG), 1543 1543 OPT_BOOL('z', "null", &s.null_termination, 1544 1544 N_("terminate entries with NUL")), 1545 - { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, 1546 - N_("mode"), 1547 - N_("show untracked files, optional modes: all, normal, no. (Default: all)"), 1548 - PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, 1549 - { OPTION_STRING, 0, "ignored", &ignored_arg, 1550 - N_("mode"), 1551 - N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"), 1552 - PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" }, 1553 - { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"), 1554 - N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"), 1555 - PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, 1545 + { 1546 + .type = OPTION_STRING, 1547 + .short_name = 'u', 1548 + .long_name = "untracked-files", 1549 + .value = &untracked_files_arg, 1550 + .argh = N_("mode"), 1551 + .help = N_("show untracked files, optional modes: all, normal, no. (Default: all)"), 1552 + .flags = PARSE_OPT_OPTARG, 1553 + .defval = (intptr_t)"all", 1554 + }, 1555 + { 1556 + .type = OPTION_STRING, 1557 + .long_name = "ignored", 1558 + .value = &ignored_arg, 1559 + .argh = N_("mode"), 1560 + .help = N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"), 1561 + .flags = PARSE_OPT_OPTARG, 1562 + .defval = (intptr_t)"traditional", 1563 + }, 1564 + { 1565 + .type = OPTION_STRING, 1566 + .long_name = "ignore-submodules", 1567 + .value = &ignore_submodule_arg, 1568 + .argh = N_("when"), 1569 + .help = N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"), 1570 + .flags = PARSE_OPT_OPTARG, 1571 + .defval = (intptr_t)"all", 1572 + }, 1556 1573 OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")), 1557 1574 OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")), 1558 1575 OPT_CALLBACK_F('M', "find-renames", &rename_score_arg, ··· 1688 1705 OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")), 1689 1706 OPT_CLEANUP(&cleanup_arg), 1690 1707 OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")), 1691 - { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), 1692 - N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, 1708 + { 1709 + .type = OPTION_STRING, 1710 + .short_name = 'S', 1711 + .long_name = "gpg-sign", 1712 + .value = &sign_commit, 1713 + .argh = N_("key-id"), 1714 + .help = N_("GPG sign commit"), 1715 + .flags = PARSE_OPT_OPTARG, 1716 + .defval = (intptr_t) "", 1717 + }, 1693 1718 /* end commit message options */ 1694 1719 1695 1720 OPT_GROUP(N_("Commit contents options")), ··· 1714 1739 N_("terminate entries with NUL")), 1715 1740 OPT_BOOL(0, "amend", &amend, N_("amend previous commit")), 1716 1741 OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), 1717 - { 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" }, 1742 + { 1743 + .type = OPTION_STRING, 1744 + .short_name = 'u', 1745 + .long_name = "untracked-files", 1746 + .value = &untracked_files_arg, 1747 + .argh = N_("mode"), 1748 + .help = N_("show untracked files, optional modes: all, normal, no. (Default: all)"), 1749 + .flags = PARSE_OPT_OPTARG, 1750 + .defval = (intptr_t)"all", 1751 + }, 1718 1752 OPT_PATHSPEC_FROM_FILE(&pathspec_from_file), 1719 1753 OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul), 1720 1754 /* end commit contents options */
+10 -3
builtin/config.c
··· 131 131 #define TYPE_COLOR 6 132 132 #define TYPE_BOOL_OR_STR 7 133 133 134 - #define OPT_CALLBACK_VALUE(s, l, v, h, i) \ 135 - { OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \ 136 - PARSE_OPT_NONEG, option_parse_type, (i) } 134 + #define OPT_CALLBACK_VALUE(s, l, v, h, i) { \ 135 + .type = OPTION_CALLBACK, \ 136 + .short_name = (s), \ 137 + .long_name = (l), \ 138 + .value = (v), \ 139 + .help = (h), \ 140 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, \ 141 + .callback = option_parse_type, \ 142 + .defval = (i), \ 143 + } 137 144 138 145 static int option_parse_type(const struct option *opt, const char *arg, 139 146 int unset)
+18 -6
builtin/describe.c
··· 601 601 N_("do not consider tags matching <pattern>")), 602 602 OPT_BOOL(0, "always", &always, 603 603 N_("show abbreviated commit object as fallback")), 604 - {OPTION_STRING, 0, "dirty", &dirty, N_("mark"), 605 - N_("append <mark> on dirty working tree (default: \"-dirty\")"), 606 - PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"}, 607 - {OPTION_STRING, 0, "broken", &broken, N_("mark"), 608 - N_("append <mark> on broken working tree (default: \"-broken\")"), 609 - PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"}, 604 + { 605 + .type = OPTION_STRING, 606 + .long_name = "dirty", 607 + .value = &dirty, 608 + .argh = N_("mark"), 609 + .help = N_("append <mark> on dirty working tree (default: \"-dirty\")"), 610 + .flags = PARSE_OPT_OPTARG, 611 + .defval = (intptr_t) "-dirty", 612 + }, 613 + { 614 + .type = OPTION_STRING, 615 + .long_name = "broken", 616 + .value = &broken, 617 + .argh = N_("mark"), 618 + .help = N_("append <mark> on broken working tree (default: \"-broken\")"), 619 + .flags = PARSE_OPT_OPTARG, 620 + .defval = (intptr_t) "-broken", 621 + }, 610 622 OPT_END(), 611 623 }; 612 624
+8 -2
builtin/fetch.c
··· 2352 2352 OPT_SET_INT_F(0, "refetch", &refetch, 2353 2353 N_("re-fetch without negotiating common commits"), 2354 2354 1, PARSE_OPT_NONEG), 2355 - { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), 2356 - N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, 2355 + { 2356 + .type = OPTION_STRING, 2357 + .long_name = "submodule-prefix", 2358 + .value = &submodule_prefix, 2359 + .argh = N_("dir"), 2360 + .help = N_("prepend this to submodule path output"), 2361 + .flags = PARSE_OPT_HIDDEN, 2362 + }, 2357 2363 OPT_CALLBACK_F(0, "recurse-submodules-default", 2358 2364 &recurse_submodules_default, N_("on-demand"), 2359 2365 N_("default for recursive fetching of submodules "
+20 -7
builtin/fmt-merge-msg.c
··· 20 20 char *into_name = NULL; 21 21 int shortlog_len = -1; 22 22 struct option options[] = { 23 - { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"), 24 - N_("populate log with at most <n> entries from shortlog"), 25 - PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN }, 26 - { OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"), 27 - N_("alias for --log (deprecated)"), 28 - PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL, 29 - DEFAULT_MERGE_LOG_LEN }, 23 + { 24 + .type = OPTION_INTEGER, 25 + .long_name = "log", 26 + .value = &shortlog_len, 27 + .precision = sizeof(shortlog_len), 28 + .argh = N_("n"), 29 + .help = N_("populate log with at most <n> entries from shortlog"), 30 + .flags = PARSE_OPT_OPTARG, 31 + .defval = DEFAULT_MERGE_LOG_LEN, 32 + }, 33 + { 34 + .type = OPTION_INTEGER, 35 + .long_name = "summary", 36 + .value = &shortlog_len, 37 + .precision = sizeof(shortlog_len), 38 + .argh = N_("n"), 39 + .help = N_("alias for --log (deprecated)"), 40 + .flags = PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, 41 + .defval = DEFAULT_MERGE_LOG_LEN, 42 + }, 30 43 OPT_STRING('m', "message", &message, N_("text"), 31 44 N_("use <text> as start of message")), 32 45 OPT_STRING(0, "into-name", &into_name, N_("name"),
+11 -5
builtin/gc.c
··· 743 743 int ret; 744 744 struct option builtin_gc_options[] = { 745 745 OPT__QUIET(&quiet, N_("suppress progress reporting")), 746 - { OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"), 747 - N_("prune unreferenced objects"), 748 - PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire_arg }, 746 + { 747 + .type = OPTION_STRING, 748 + .long_name = "prune", 749 + .value = &prune_expire_arg, 750 + .argh = N_("date"), 751 + .help = N_("prune unreferenced objects"), 752 + .flags = PARSE_OPT_OPTARG, 753 + .defval = (intptr_t)prune_expire_arg, 754 + }, 749 755 OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")), 750 - OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size, 751 - N_("with --cruft, limit the size of new cruft packs")), 756 + OPT_UNSIGNED(0, "max-cruft-size", &cfg.max_cruft_size, 757 + N_("with --cruft, limit the size of new cruft packs")), 752 758 OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), 753 759 OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"), 754 760 PARSE_OPT_NOCOMPLETE),
+12 -6
builtin/grep.c
··· 983 983 OPT_CALLBACK('C', "context", &opt, N_("n"), 984 984 N_("show <n> context lines before and after matches"), 985 985 context_callback), 986 - OPT_INTEGER('B', "before-context", &opt.pre_context, 986 + OPT_UNSIGNED('B', "before-context", &opt.pre_context, 987 987 N_("show <n> context lines before matches")), 988 - OPT_INTEGER('A', "after-context", &opt.post_context, 988 + OPT_UNSIGNED('A', "after-context", &opt.post_context, 989 989 N_("show <n> context lines after matches")), 990 990 OPT_INTEGER(0, "threads", &num_threads, 991 991 N_("use <n> worker threads")), ··· 1017 1017 OPT_BOOL(0, "all-match", &opt.all_match, 1018 1018 N_("show only matches from files that match all patterns")), 1019 1019 OPT_GROUP(""), 1020 - { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, 1021 - N_("pager"), N_("show matching files in the pager"), 1022 - PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE, 1023 - NULL, (intptr_t)default_pager }, 1020 + { 1021 + .type = OPTION_STRING, 1022 + .short_name = 'O', 1023 + .long_name = "open-files-in-pager", 1024 + .value = &show_in_pager, 1025 + .argh = N_("pager"), 1026 + .help = N_("show matching files in the pager"), 1027 + .flags = PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE, 1028 + .defval = (intptr_t)default_pager, 1029 + }, 1024 1030 OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored, 1025 1031 N_("allow calling of grep(1) (ignored by this build)"), 1026 1032 PARSE_OPT_NOCOMPLETE),
+9 -4
builtin/init-db.c
··· 92 92 N_("directory from which templates will be used")), 93 93 OPT_SET_INT(0, "bare", &is_bare_repository_cfg, 94 94 N_("create a bare repository"), 1), 95 - { OPTION_CALLBACK, 0, "shared", &init_shared_repository, 96 - N_("permissions"), 97 - N_("specify that the git repository is to be shared amongst several users"), 98 - PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0}, 95 + { 96 + .type = OPTION_CALLBACK, 97 + .long_name = "shared", 98 + .value = &init_shared_repository, 99 + .argh = N_("permissions"), 100 + .help = N_("specify that the git repository is to be shared amongst several users"), 101 + .flags = PARSE_OPT_OPTARG | PARSE_OPT_NONEG, 102 + .callback = shared_callback 103 + }, 99 104 OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET), 100 105 OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), 101 106 N_("separate git dir from working tree")),
+8 -3
builtin/ls-remote.c
··· 67 67 OPT__QUIET(&quiet, N_("do not print remote URL")), 68 68 OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"), 69 69 N_("path of git-upload-pack on the remote host")), 70 - { OPTION_STRING, 0, "exec", &uploadpack, N_("exec"), 71 - N_("path of git-upload-pack on the remote host"), 72 - PARSE_OPT_HIDDEN }, 70 + { 71 + .type = OPTION_STRING, 72 + .long_name = "exec", 73 + .value = &uploadpack, 74 + .argh = N_("exec"), 75 + .help = N_("path of git-upload-pack on the remote host"), 76 + .flags = PARSE_OPT_HIDDEN, 77 + }, 73 78 OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS), 74 79 OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES), 75 80 OPT_BIT_F('h', "heads", &flags,
+30 -8
builtin/merge.c
··· 249 249 OPT_BOOL(0, "stat", &show_diffstat, 250 250 N_("show a diffstat at the end of the merge")), 251 251 OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")), 252 - { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"), 253 - N_("add (at most <n>) entries from shortlog to merge commit message"), 254 - PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN }, 252 + { 253 + .type = OPTION_INTEGER, 254 + .long_name = "log", 255 + .value = &shortlog_len, 256 + .precision = sizeof(shortlog_len), 257 + .argh = N_("n"), 258 + .help = N_("add (at most <n>) entries from shortlog to merge commit message"), 259 + .flags = PARSE_OPT_OPTARG, 260 + .defval = DEFAULT_MERGE_LOG_LEN, 261 + }, 255 262 OPT_BOOL(0, "squash", &squash, 256 263 N_("create a single commit instead of doing a merge")), 257 264 OPT_BOOL(0, "commit", &option_commit, ··· 273 280 OPT_CALLBACK('m', "message", &merge_msg, N_("message"), 274 281 N_("merge commit message (for a non-fast-forward merge)"), 275 282 option_parse_message), 276 - { OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"), 277 - N_("read message from file"), PARSE_OPT_NONEG, 278 - NULL, 0, option_read_message }, 283 + { 284 + .type = OPTION_LOWLEVEL_CALLBACK, 285 + .short_name = 'F', 286 + .long_name = "file", 287 + .value = &merge_msg, 288 + .argh = N_("path"), 289 + .help = N_("read message from file"), 290 + .flags = PARSE_OPT_NONEG, 291 + .ll_callback = option_read_message, 292 + }, 279 293 OPT_STRING(0, "into-name", &into_name, N_("name"), 280 294 N_("use <name> instead of the real target")), 281 295 OPT__VERBOSITY(&verbosity), ··· 288 302 OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories, 289 303 N_("allow merging unrelated histories")), 290 304 OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1), 291 - { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), 292 - N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, 305 + { 306 + .type = OPTION_STRING, 307 + .short_name = 'S', 308 + .long_name = "gpg-sign", 309 + .value = &sign_commit, 310 + .argh = N_("key-id"), 311 + .help = N_("GPG sign commit"), 312 + .flags = PARSE_OPT_OPTARG, 313 + .defval = (intptr_t) "", 314 + }, 293 315 OPT_AUTOSTASH(&autostash), 294 316 OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")), 295 317 OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")),
+1 -1
builtin/multi-pack-index.c
··· 245 245 { 246 246 struct option *options; 247 247 static struct option builtin_multi_pack_index_repack_options[] = { 248 - OPT_MAGNITUDE(0, "batch-size", &opts.batch_size, 248 + OPT_UNSIGNED(0, "batch-size", &opts.batch_size, 249 249 N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")), 250 250 OPT_BIT(0, "progress", &opts.flags, 251 251 N_("force progress reporting"), MIDX_PROGRESS),
+4 -4
builtin/pack-objects.c
··· 4488 4488 OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"), 4489 4489 N_("write the pack index file in the specified idx format version"), 4490 4490 PARSE_OPT_NONEG, option_parse_index_version), 4491 - OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit, 4492 - N_("maximum size of each output pack file")), 4491 + OPT_UNSIGNED(0, "max-pack-size", &pack_size_limit, 4492 + N_("maximum size of each output pack file")), 4493 4493 OPT_BOOL(0, "local", &local, 4494 4494 N_("ignore borrowed objects from alternate object store")), 4495 4495 OPT_BOOL(0, "incremental", &incremental, 4496 4496 N_("ignore packed objects")), 4497 4497 OPT_INTEGER(0, "window", &window, 4498 4498 N_("limit pack window by objects")), 4499 - OPT_MAGNITUDE(0, "window-memory", &window_memory_limit, 4500 - N_("limit pack window by memory in addition to object limit")), 4499 + OPT_UNSIGNED(0, "window-memory", &window_memory_limit, 4500 + N_("limit pack window by memory in addition to object limit")), 4501 4501 OPT_INTEGER(0, "depth", &depth, 4502 4502 N_("maximum length of delta chain allowed in the resulting pack")), 4503 4503 OPT_BOOL(0, "reuse-delta", &reuse_delta,
+8 -3
builtin/read-tree.c
··· 135 135 N_("3-way merge in presence of adds and removes")), 136 136 OPT_BOOL(0, "reset", &opts.reset, 137 137 N_("same as -m, but discard unmerged entries")), 138 - { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"), 139 - N_("read the tree into the index under <subdirectory>/"), 140 - PARSE_OPT_NONEG }, 138 + { 139 + .type = OPTION_STRING, 140 + .long_name = "prefix", 141 + .value = &opts.prefix, 142 + .argh = N_("<subdirectory>/"), 143 + .help = N_("read the tree into the index under <subdirectory>/"), 144 + .flags = PARSE_OPT_NONEG, 145 + }, 141 146 OPT_BOOL('u', NULL, &opts.update, 142 147 N_("update working tree with merge result")), 143 148 OPT_CALLBACK_F(0, "exclude-per-directory", &opts,
+19 -6
builtin/rebase.c
··· 1123 1123 OPT_BIT('v', "verbose", &options.flags, 1124 1124 N_("display a diffstat of what changed upstream"), 1125 1125 REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT), 1126 - {OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL, 1127 - N_("do not show diffstat of what changed upstream"), 1128 - PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT }, 1126 + { 1127 + .type = OPTION_NEGBIT, 1128 + .short_name = 'n', 1129 + .long_name = "no-stat", 1130 + .value = &options.flags, 1131 + .help = N_("do not show diffstat of what changed upstream"), 1132 + .flags = PARSE_OPT_NOARG, 1133 + .defval = REBASE_DIFFSTAT, 1134 + }, 1129 1135 OPT_BOOL(0, "signoff", &options.signoff, 1130 1136 N_("add a Signed-off-by trailer to each commit")), 1131 1137 OPT_BOOL(0, "committer-date-is-author-date", ··· 1191 1197 OPT_BOOL(0, "update-refs", &options.update_refs, 1192 1198 N_("update branches that point to commits " 1193 1199 "that are being rebased")), 1194 - { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"), 1195 - N_("GPG-sign commits"), 1196 - PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, 1200 + { 1201 + .type = OPTION_STRING, 1202 + .short_name = 'S', 1203 + .long_name = "gpg-sign", 1204 + .value = &gpg_sign, 1205 + .argh = N_("key-id"), 1206 + .help = N_("GPG-sign commits"), 1207 + .flags = PARSE_OPT_OPTARG, 1208 + .defval = (intptr_t) "", 1209 + }, 1197 1210 OPT_AUTOSTASH(&options.autostash), 1198 1211 OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"), 1199 1212 N_("add exec lines after each commit of the "
+7 -7
builtin/repack.c
··· 1171 1171 PACK_CRUFT), 1172 1172 OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"), 1173 1173 N_("with --cruft, expire objects older than this")), 1174 - OPT_MAGNITUDE(0, "combine-cruft-below-size", 1175 - &combine_cruft_below_size, 1176 - N_("with --cruft, only repack cruft packs smaller than this")), 1177 - OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size, 1178 - N_("with --cruft, limit the size of new cruft packs")), 1174 + OPT_UNSIGNED(0, "combine-cruft-below-size", 1175 + &combine_cruft_below_size, 1176 + N_("with --cruft, only repack cruft packs smaller than this")), 1177 + OPT_UNSIGNED(0, "max-cruft-size", &cruft_po_args.max_pack_size, 1178 + N_("with --cruft, limit the size of new cruft packs")), 1179 1179 OPT_BOOL('d', NULL, &delete_redundant, 1180 1180 N_("remove redundant packs, and run git-prune-packed")), 1181 1181 OPT_BOOL('f', NULL, &po_args.no_reuse_delta, ··· 1205 1205 N_("limits the maximum delta depth")), 1206 1206 OPT_STRING(0, "threads", &opt_threads, N_("n"), 1207 1207 N_("limits the maximum number of threads")), 1208 - OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size, 1209 - N_("maximum size of each packfile")), 1208 + OPT_UNSIGNED(0, "max-pack-size", &po_args.max_pack_size, 1209 + N_("maximum size of each packfile")), 1210 1210 OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options), 1211 1211 OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects, 1212 1212 N_("repack objects in packs marked with .keep")),
+10 -2
builtin/revert.c
··· 132 132 OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")), 133 133 OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"), 134 134 N_("option for merge strategy")), 135 - { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"), 136 - N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, 135 + { 136 + .type = OPTION_STRING, 137 + .short_name = 'S', 138 + .long_name = "gpg-sign", 139 + .value = &gpg_sign, 140 + .argh = N_("key-id"), 141 + .help = N_("GPG sign commit"), 142 + .flags = PARSE_OPT_OPTARG, 143 + .defval = (intptr_t) "", 144 + }, 137 145 OPT_END() 138 146 }; 139 147 struct option *options = base_options;
+10 -3
builtin/show-branch.c
··· 667 667 N_("show remote-tracking branches")), 668 668 OPT__COLOR(&showbranch_use_color, 669 669 N_("color '*!+-' corresponding to the branch")), 670 - { OPTION_INTEGER, 0, "more", &extra, N_("n"), 671 - N_("show <n> more commits after the common ancestor"), 672 - PARSE_OPT_OPTARG, NULL, (intptr_t)1 }, 670 + { 671 + .type = OPTION_INTEGER, 672 + .long_name = "more", 673 + .value = &extra, 674 + .precision = sizeof(extra), 675 + .argh = N_("n"), 676 + .help = N_("show <n> more commits after the common ancestor"), 677 + .flags = PARSE_OPT_OPTARG, 678 + .defval = 1, 679 + }, 673 680 OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1), 674 681 OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")), 675 682 OPT_BOOL(0, "current", &with_current_branch,
+18 -6
builtin/tag.c
··· 480 480 int edit_flag = 0; 481 481 struct option options[] = { 482 482 OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), 483 - { OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"), 484 - N_("print <n> lines of each tag message"), 485 - PARSE_OPT_OPTARG, NULL, 1 }, 483 + { 484 + .type = OPTION_INTEGER, 485 + .short_name = 'n', 486 + .value = &filter.lines, 487 + .precision = sizeof(filter.lines), 488 + .argh = N_("n"), 489 + .help = N_("print <n> lines of each tag message"), 490 + .flags = PARSE_OPT_OPTARG, 491 + .defval = 1, 492 + }, 486 493 OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'), 487 494 OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'), 488 495 ··· 514 521 N_("do not output a newline after empty formatted refs")), 515 522 OPT_REF_SORT(&sorting_options), 516 523 { 517 - OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), 518 - N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT, 519 - parse_opt_object_name, (intptr_t) "HEAD" 524 + .type = OPTION_CALLBACK, 525 + .long_name = "points-at", 526 + .value = &filter.points_at, 527 + .argh = N_("object"), 528 + .help = N_("print only tags of the object"), 529 + .flags = PARSE_OPT_LASTARG_DEFAULT, 530 + .callback = parse_opt_object_name, 531 + .defval = (intptr_t) "HEAD", 520 532 }, 521 533 OPT_STRING( 0 , "format", &format.format, N_("format"), 522 534 N_("format to use for the output")),
+90 -41
builtin/update-index.c
··· 964 964 N_("like --refresh, but ignore assume-unchanged setting"), 965 965 PARSE_OPT_NOARG | PARSE_OPT_NONEG, 966 966 really_refresh_callback), 967 - {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, 968 - N_("<mode>,<object>,<path>"), 969 - N_("add the specified entry to the index"), 970 - PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ 971 - PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, 972 - NULL, 0, 973 - cacheinfo_callback}, 967 + { 968 + .type = OPTION_LOWLEVEL_CALLBACK, 969 + .long_name = "cacheinfo", 970 + .argh = N_("<mode>,<object>,<path>"), 971 + .help = N_("add the specified entry to the index"), 972 + .flags = PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ 973 + PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, 974 + .ll_callback = cacheinfo_callback, 975 + }, 974 976 OPT_CALLBACK_F(0, "chmod", &set_executable_bit, "(+|-)x", 975 977 N_("override the executable bit of the listed files"), 976 978 PARSE_OPT_NONEG, 977 979 chmod_callback), 978 - {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, 979 - N_("mark files as \"not changing\""), 980 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, 981 - {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, 982 - N_("clear assumed-unchanged bit"), 983 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, 984 - {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, 985 - N_("mark files as \"index-only\""), 986 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, 987 - {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, 988 - N_("clear skip-worktree bit"), 989 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, 980 + { 981 + .type = OPTION_SET_INT, 982 + .long_name = "assume-unchanged", 983 + .value = &mark_valid_only, 984 + .help = N_("mark files as \"not changing\""), 985 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 986 + .defval = MARK_FLAG, 987 + }, 988 + { 989 + .type = OPTION_SET_INT, 990 + .long_name = "no-assume-unchanged", 991 + .value = &mark_valid_only, 992 + .help = N_("clear assumed-unchanged bit"), 993 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 994 + .defval = UNMARK_FLAG, 995 + }, 996 + { 997 + .type = OPTION_SET_INT, 998 + .long_name = "skip-worktree", 999 + .value = &mark_skip_worktree_only, 1000 + .help = N_("mark files as \"index-only\""), 1001 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 1002 + .defval = MARK_FLAG, 1003 + }, 1004 + { 1005 + .type = OPTION_SET_INT, 1006 + .long_name = "no-skip-worktree", 1007 + .value = &mark_skip_worktree_only, 1008 + .help = N_("clear skip-worktree bit"), 1009 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 1010 + .defval = UNMARK_FLAG, 1011 + }, 990 1012 OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries, 991 1013 N_("do not touch index-only entries")), 992 1014 OPT_SET_INT(0, "info-only", &info_only, ··· 995 1017 N_("remove named paths even if present in worktree"), 1), 996 1018 OPT_BOOL('z', NULL, &nul_term_line, 997 1019 N_("with --stdin: input lines are terminated by null bytes")), 998 - {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, 999 - N_("read list of paths to be updated from standard input"), 1000 - PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1001 - NULL, 0, stdin_callback}, 1002 - {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL, 1003 - N_("add entries from standard input to the index"), 1004 - PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1005 - NULL, 0, stdin_cacheinfo_callback}, 1006 - {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, 1007 - N_("repopulate stages #2 and #3 for the listed paths"), 1008 - PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1009 - NULL, 0, unresolve_callback}, 1010 - {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, 1011 - N_("only update entries that differ from HEAD"), 1012 - PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1013 - NULL, 0, reupdate_callback}, 1020 + { 1021 + .type = OPTION_LOWLEVEL_CALLBACK, 1022 + .long_name = "stdin", 1023 + .value = &read_from_stdin, 1024 + .help = N_("read list of paths to be updated from standard input"), 1025 + .flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1026 + .ll_callback = stdin_callback, 1027 + }, 1028 + { 1029 + .type = OPTION_LOWLEVEL_CALLBACK, 1030 + .long_name = "index-info", 1031 + .value = &nul_term_line, 1032 + .help = N_("add entries from standard input to the index"), 1033 + .flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1034 + .ll_callback = stdin_cacheinfo_callback, 1035 + }, 1036 + { 1037 + .type = OPTION_LOWLEVEL_CALLBACK, 1038 + .long_name = "unresolve", 1039 + .value = &has_errors, 1040 + .help = N_("repopulate stages #2 and #3 for the listed paths"), 1041 + .flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1042 + .ll_callback = unresolve_callback, 1043 + }, 1044 + { 1045 + .type = OPTION_LOWLEVEL_CALLBACK, 1046 + .short_name = 'g', 1047 + .long_name = "again", 1048 + .value = &has_errors, 1049 + .help = N_("only update entries that differ from HEAD"), 1050 + .flags = PARSE_OPT_NONEG | PARSE_OPT_NOARG, 1051 + .ll_callback = reupdate_callback, 1052 + }, 1014 1053 OPT_BIT(0, "ignore-missing", &refresh_args.flags, 1015 1054 N_("ignore files missing from worktree"), 1016 1055 REFRESH_IGNORE_MISSING), ··· 1036 1075 N_("write out the index even if is not flagged as changed"), 1), 1037 1076 OPT_BOOL(0, "fsmonitor", &fsmonitor, 1038 1077 N_("enable or disable file system monitor")), 1039 - {OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL, 1040 - N_("mark files as fsmonitor valid"), 1041 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, 1042 - {OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL, 1043 - N_("clear fsmonitor valid bit"), 1044 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, 1078 + { 1079 + .type = OPTION_SET_INT, 1080 + .long_name = "fsmonitor-valid", 1081 + .value = &mark_fsmonitor_only, 1082 + .help = N_("mark files as fsmonitor valid"), 1083 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 1084 + .defval = MARK_FLAG, 1085 + }, 1086 + { 1087 + .type = OPTION_SET_INT, 1088 + .long_name = "no-fsmonitor-valid", 1089 + .value = &mark_fsmonitor_only, 1090 + .help = N_("clear fsmonitor valid bit"), 1091 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 1092 + .defval = UNMARK_FLAG, 1093 + }, 1045 1094 OPT_END() 1046 1095 }; 1047 1096
+8 -4
builtin/write-tree.c
··· 31 31 WRITE_TREE_MISSING_OK), 32 32 OPT_STRING(0, "prefix", &tree_prefix, N_("<prefix>/"), 33 33 N_("write tree object for a subdirectory <prefix>")), 34 - { OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL, 35 - N_("only useful for debugging"), 36 - PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL, 37 - WRITE_TREE_IGNORE_CACHE_TREE }, 34 + { 35 + .type = OPTION_BIT, 36 + .long_name = "ignore-cache-tree", 37 + .value = &flags, 38 + .help = N_("only useful for debugging"), 39 + .flags = PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, 40 + .defval = WRITE_TREE_IGNORE_CACHE_TREE, 41 + }, 38 42 OPT_END() 39 43 }; 40 44
+9 -4
diff.c
··· 5894 5894 OPT_CALLBACK_F(0, "diff-filter", options, N_("[(A|C|D|M|R|T|U|X|B)...[*]]"), 5895 5895 N_("select files by diff type"), 5896 5896 PARSE_OPT_NONEG, diff_opt_diff_filter), 5897 - { OPTION_CALLBACK, 0, "output", options, N_("<file>"), 5898 - N_("output to a specific file"), 5899 - PARSE_OPT_NONEG, NULL, 0, diff_opt_output }, 5900 - 5897 + { 5898 + .type = OPTION_CALLBACK, 5899 + .long_name = "output", 5900 + .value = options, 5901 + .argh = N_("<file>"), 5902 + .help = N_("output to a specific file"), 5903 + .flags = PARSE_OPT_NONEG, 5904 + .ll_callback = diff_opt_output, 5905 + }, 5901 5906 OPT_END() 5902 5907 }; 5903 5908
+7
git-compat-util.h
··· 93 93 # define BARF_UNLESS_COPYABLE(dst, src) \ 94 94 BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(__typeof__(*(dst)), \ 95 95 __typeof__(*(src)))) 96 + 97 + # define BARF_UNLESS_SIGNED(var) BUILD_ASSERT_OR_ZERO(((__typeof__(var)) -1) < 0) 98 + # define BARF_UNLESS_UNSIGNED(var) BUILD_ASSERT_OR_ZERO(((__typeof__(var)) -1) > 0) 96 99 #else 97 100 # define BARF_UNLESS_AN_ARRAY(arr) 0 98 101 # define BARF_UNLESS_COPYABLE(dst, src) \ 99 102 BUILD_ASSERT_OR_ZERO(0 ? ((*(dst) = *(src)), 0) : \ 100 103 sizeof(*(dst)) == sizeof(*(src))) 104 + 105 + # define BARF_UNLESS_SIGNED(var) 0 106 + # define BARF_UNLESS_UNSIGNED(var) 0 101 107 #endif 108 + 102 109 /* 103 110 * ARRAY_SIZE - get the number of elements in a visible array 104 111 * @x: the array whose size you want.
+77 -25
parse-options.c
··· 73 73 enum opt_parsed flags, 74 74 const char **argp) 75 75 { 76 - const char *s, *arg; 76 + const char *arg; 77 77 const int unset = flags & OPT_UNSET; 78 78 int err; 79 79 ··· 172 172 return (*opt->ll_callback)(p, opt, p_arg, p_unset); 173 173 } 174 174 case OPTION_INTEGER: 175 + { 176 + intmax_t upper_bound = INTMAX_MAX >> (bitsizeof(intmax_t) - CHAR_BIT * opt->precision); 177 + intmax_t lower_bound = -upper_bound - 1; 178 + intmax_t value; 179 + 175 180 if (unset) { 176 - *(int *)opt->value = 0; 177 - return 0; 178 - } 179 - if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 180 - *(int *)opt->value = opt->defval; 181 - return 0; 182 - } 183 - if (get_arg(p, opt, flags, &arg)) 181 + value = 0; 182 + } else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 183 + value = opt->defval; 184 + } else if (get_arg(p, opt, flags, &arg)) { 184 185 return -1; 185 - if (!*arg) 186 + } else if (!*arg) { 186 187 return error(_("%s expects a numerical value"), 187 188 optname(opt, flags)); 188 - *(int *)opt->value = strtol(arg, (char **)&s, 10); 189 - if (*s) 190 - return error(_("%s expects a numerical value"), 189 + } else if (!git_parse_signed(arg, &value, upper_bound)) { 190 + if (errno == ERANGE) 191 + return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"), 192 + arg, optname(opt, flags), lower_bound, upper_bound); 193 + 194 + return error(_("%s expects an integer value with an optional k/m/g suffix"), 191 195 optname(opt, flags)); 192 - return 0; 196 + } 193 197 194 - case OPTION_MAGNITUDE: 195 - if (unset) { 196 - *(unsigned long *)opt->value = 0; 198 + if (value < lower_bound) 199 + return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"), 200 + arg, optname(opt, flags), (intmax_t)lower_bound, (intmax_t)upper_bound); 201 + 202 + switch (opt->precision) { 203 + case 1: 204 + *(int8_t *)opt->value = value; 197 205 return 0; 198 - } 199 - if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 200 - *(unsigned long *)opt->value = opt->defval; 206 + case 2: 207 + *(int16_t *)opt->value = value; 208 + return 0; 209 + case 4: 210 + *(int32_t *)opt->value = value; 201 211 return 0; 212 + case 8: 213 + *(int64_t *)opt->value = value; 214 + return 0; 215 + default: 216 + BUG("invalid precision for option %s", 217 + optname(opt, flags)); 202 218 } 203 - if (get_arg(p, opt, flags, &arg)) 219 + } 220 + case OPTION_UNSIGNED: 221 + { 222 + uintmax_t upper_bound = UINTMAX_MAX >> (bitsizeof(uintmax_t) - CHAR_BIT * opt->precision); 223 + uintmax_t value; 224 + 225 + if (unset) { 226 + value = 0; 227 + } else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 228 + value = opt->defval; 229 + } else if (get_arg(p, opt, flags, &arg)) { 204 230 return -1; 205 - if (!git_parse_ulong(arg, opt->value)) 231 + } else if (!*arg) { 232 + return error(_("%s expects a numerical value"), 233 + optname(opt, flags)); 234 + } else if (!git_parse_unsigned(arg, &value, upper_bound)) { 235 + if (errno == ERANGE) 236 + return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"), 237 + arg, optname(opt, flags), (uintmax_t) 0, upper_bound); 238 + 206 239 return error(_("%s expects a non-negative integer value" 207 240 " with an optional k/m/g suffix"), 208 241 optname(opt, flags)); 209 - return 0; 242 + } 243 + 244 + switch (opt->precision) { 245 + case 1: 246 + *(uint8_t *)opt->value = value; 247 + return 0; 248 + case 2: 249 + *(uint16_t *)opt->value = value; 250 + return 0; 251 + case 4: 252 + *(uint32_t *)opt->value = value; 253 + return 0; 254 + case 8: 255 + *(uint64_t *)opt->value = value; 256 + return 0; 257 + default: 258 + BUG("invalid precision for option %s", 259 + optname(opt, flags)); 260 + } 261 + } 210 262 211 263 default: 212 264 BUG("opt->type %d should not happen", opt->type); ··· 656 708 case OPTION_STRING: 657 709 case OPTION_FILENAME: 658 710 case OPTION_INTEGER: 659 - case OPTION_MAGNITUDE: 711 + case OPTION_UNSIGNED: 660 712 case OPTION_CALLBACK: 661 713 case OPTION_BIT: 662 714 case OPTION_NEGBIT: ··· 708 760 case OPTION_STRING: 709 761 case OPTION_FILENAME: 710 762 case OPTION_INTEGER: 711 - case OPTION_MAGNITUDE: 763 + case OPTION_UNSIGNED: 712 764 case OPTION_CALLBACK: 713 765 if (opts->flags & PARSE_OPT_NOARG) 714 766 break;
+12 -5
parse-options.h
··· 25 25 /* options with arguments (usually) */ 26 26 OPTION_STRING, 27 27 OPTION_INTEGER, 28 - OPTION_MAGNITUDE, 28 + OPTION_UNSIGNED, 29 29 OPTION_CALLBACK, 30 30 OPTION_LOWLEVEL_CALLBACK, 31 31 OPTION_FILENAME ··· 92 92 * `value`:: 93 93 * stores pointers to the values to be filled. 94 94 * 95 + * `precision`:: 96 + * precision of the integer pointed to by `value` in number of bytes. Should 97 + * typically be its `sizeof()`. 98 + * 95 99 * `argh`:: 96 100 * token to explain the kind of argument this option wants. Does not 97 101 * begin in capital letter, and does not end with a full stop. ··· 151 155 int short_name; 152 156 const char *long_name; 153 157 void *value; 158 + size_t precision; 154 159 const char *argh; 155 160 const char *help; 156 161 ··· 213 218 .type = OPTION_INTEGER, \ 214 219 .short_name = (s), \ 215 220 .long_name = (l), \ 216 - .value = (v), \ 221 + .value = (v) + BARF_UNLESS_SIGNED(*(v)), \ 222 + .precision = sizeof(*v), \ 217 223 .argh = N_("n"), \ 218 224 .help = (h), \ 219 225 .flags = (f), \ ··· 270 276 #define OPT_CMDMODE(s, l, v, h, i) OPT_CMDMODE_F(s, l, v, h, i, 0) 271 277 272 278 #define OPT_INTEGER(s, l, v, h) OPT_INTEGER_F(s, l, v, h, 0) 273 - #define OPT_MAGNITUDE(s, l, v, h) { \ 274 - .type = OPTION_MAGNITUDE, \ 279 + #define OPT_UNSIGNED(s, l, v, h) { \ 280 + .type = OPTION_UNSIGNED, \ 275 281 .short_name = (s), \ 276 282 .long_name = (l), \ 277 - .value = (v), \ 283 + .value = (v) + BARF_UNLESS_UNSIGNED(*(v)), \ 284 + .precision = sizeof(*v), \ 278 285 .argh = N_("n"), \ 279 286 .help = (h), \ 280 287 .flags = PARSE_OPT_NONEG, \
+2 -2
parse.c
··· 38 38 errno = EINVAL; 39 39 return 0; 40 40 } 41 - if ((val < 0 && -max / factor > val) || 41 + if ((val < 0 && (-max - 1) / factor > val) || 42 42 (val > 0 && max / factor < val)) { 43 43 errno = ERANGE; 44 44 return 0; ··· 51 51 return 0; 52 52 } 53 53 54 - static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) 54 + int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) 55 55 { 56 56 if (value && *value) { 57 57 char *end;
+1
parse.h
··· 2 2 #define PARSE_H 3 3 4 4 int git_parse_signed(const char *value, intmax_t *ret, intmax_t max); 5 + int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max); 5 6 int git_parse_ssize_t(const char *, ssize_t *); 6 7 int git_parse_ulong(const char *, unsigned long *); 7 8 int git_parse_int(const char *value, int *ret);
+10 -5
ref-filter.h
··· 114 114 } 115 115 116 116 /* Macros for checking --merged and --no-merged options */ 117 - #define _OPT_MERGED_NO_MERGED(option, filter, h) \ 118 - { OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \ 119 - PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, \ 120 - parse_opt_merge_filter, (intptr_t) "HEAD" \ 121 - } 117 + #define _OPT_MERGED_NO_MERGED(option, filter, h) { \ 118 + .type = OPTION_CALLBACK, \ 119 + .long_name = option, \ 120 + .value = (filter), \ 121 + .argh = N_("commit"), \ 122 + .help = (h), \ 123 + .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, \ 124 + .callback = parse_opt_merge_filter, \ 125 + .defval = (intptr_t) "HEAD", \ 126 + } 122 127 #define OPT_MERGED(f, h) _OPT_MERGED_NO_MERGED("merged", f, h) 123 128 #define OPT_NO_MERGED(f, h) _OPT_MERGED_NO_MERGED("no-merged", f, h) 124 129
+39 -11
t/helper/test-parse-options.c
··· 6 6 7 7 static int boolean = 0; 8 8 static int integer = 0; 9 - static unsigned long magnitude = 0; 9 + static unsigned long unsigned_integer = 0; 10 10 static timestamp_t timestamp; 11 11 static int abbrev = 7; 12 12 static int verbose = -1; /* unspecified */ ··· 120 120 }; 121 121 struct string_list expect = STRING_LIST_INIT_NODUP; 122 122 struct string_list list = STRING_LIST_INIT_NODUP; 123 + uint16_t u16 = 0; 124 + int16_t i16 = 0; 123 125 124 126 struct option options[] = { 125 127 OPT_BOOL(0, "yes", &boolean, "get a boolean"), 126 128 OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"), 127 - { OPTION_SET_INT, 'B', "no-fear", &boolean, NULL, 128 - "be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, 129 + { 130 + .type = OPTION_SET_INT, 131 + .short_name = 'B', 132 + .long_name = "no-fear", 133 + .value = &boolean, 134 + .help = "be brave", 135 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 136 + .defval = 1, 137 + }, 129 138 OPT_COUNTUP('b', "boolean", &boolean, "increment by one"), 130 139 OPT_BIT('4', "or4", &boolean, 131 140 "bitwise-or boolean with ...0100", 4), 132 141 OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), 133 142 OPT_GROUP(""), 134 143 OPT_INTEGER('i', "integer", &integer, "get a integer"), 144 + OPT_INTEGER(0, "i16", &i16, "get a 16 bit integer"), 135 145 OPT_INTEGER('j', NULL, &integer, "get a integer, too"), 136 - OPT_MAGNITUDE('m', "magnitude", &magnitude, "get a magnitude"), 146 + OPT_UNSIGNED('u', "unsigned", &unsigned_integer, "get an unsigned integer"), 147 + OPT_UNSIGNED(0, "u16", &u16, "get a 16 bit unsigned integer"), 137 148 OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), 138 149 OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1), 139 150 OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2), ··· 155 166 OPT_GROUP("Magic arguments"), 156 167 OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", 157 168 number_callback), 158 - { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", 159 - PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, 160 - { OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL, 161 - "positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, 162 - { OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL, 163 - "negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, 169 + { 170 + .type = OPTION_COUNTUP, 171 + .short_name = '+', 172 + .value = &boolean, 173 + .help = "same as -b", 174 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, 175 + }, 176 + { 177 + .type = OPTION_COUNTUP, 178 + .long_name = "ambiguous", 179 + .value = &ambiguous, 180 + .help = "positive ambiguity", 181 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 182 + }, 183 + { 184 + .type = OPTION_COUNTUP, 185 + .long_name = "no-ambiguous", 186 + .value = &ambiguous, 187 + .help = "negative ambiguity", 188 + .flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG, 189 + }, 164 190 OPT_GROUP("Standard options"), 165 191 OPT__ABBREV(&abbrev), 166 192 OPT__VERBOSE(&verbose, "be verbose"), ··· 188 214 } 189 215 show(&expect, &ret, "boolean: %d", boolean); 190 216 show(&expect, &ret, "integer: %d", integer); 191 - show(&expect, &ret, "magnitude: %lu", magnitude); 217 + show(&expect, &ret, "i16: %"PRIdMAX, (intmax_t) i16); 218 + show(&expect, &ret, "unsigned: %lu", unsigned_integer); 219 + show(&expect, &ret, "u16: %"PRIuMAX, (uintmax_t) u16); 192 220 show(&expect, &ret, "timestamp: %"PRItime, timestamp); 193 221 show(&expect, &ret, "string: %s", string ? string : "(not set)"); 194 222 show(&expect, &ret, "abbrev: %d", abbrev);
+66 -27
t/t0040-parse-options.sh
··· 22 22 23 23 -i, --[no-]integer <n> 24 24 get a integer 25 + --[no-]i16 <n> get a 16 bit integer 25 26 -j <n> get a integer, too 26 - -m, --magnitude <n> get a magnitude 27 + -u, --unsigned <n> get an unsigned integer 28 + --u16 <n> get a 16 bit unsigned integer 27 29 --[no-]set23 set integer to 23 28 30 --mode1 set integer to 1 (cmdmode option) 29 31 --mode2 set integer to 2 (cmdmode option) ··· 111 113 112 114 test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' 113 115 114 - test_expect_success 'OPT_INT() negative' 'check integer: -2345 -i -2345' 116 + test_expect_success 'OPT_INTEGER() negative' 'check integer: -2345 -i -2345' 117 + test_expect_success 'OPT_INTEGER() kilo' 'check integer: 239616 -i 234k' 118 + test_expect_success 'OPT_INTEGER() negative kilo' 'check integer: -239616 -i -234k' 115 119 116 - test_expect_success 'OPT_MAGNITUDE() simple' ' 117 - check magnitude: 2345678 -m 2345678 120 + test_expect_success 'OPT_UNSIGNED() simple' ' 121 + check unsigned: 2345678 -u 2345678 118 122 ' 119 123 120 - test_expect_success 'OPT_MAGNITUDE() kilo' ' 121 - check magnitude: 239616 -m 234k 124 + test_expect_success 'OPT_UNSIGNED() kilo' ' 125 + check unsigned: 239616 -u 234k 122 126 ' 123 127 124 - test_expect_success 'OPT_MAGNITUDE() mega' ' 125 - check magnitude: 104857600 -m 100m 128 + test_expect_success 'OPT_UNSIGNED() mega' ' 129 + check unsigned: 104857600 -u 100m 126 130 ' 127 131 128 - test_expect_success 'OPT_MAGNITUDE() giga' ' 129 - check magnitude: 1073741824 -m 1g 132 + test_expect_success 'OPT_UNSIGNED() giga' ' 133 + check unsigned: 1073741824 -u 1g 130 134 ' 131 135 132 - test_expect_success 'OPT_MAGNITUDE() 3giga' ' 133 - check magnitude: 3221225472 -m 3g 136 + test_expect_success 'OPT_UNSIGNED() 3giga' ' 137 + check unsigned: 3221225472 -u 3g 134 138 ' 135 139 136 140 cat >expect <<\EOF 137 141 boolean: 2 138 142 integer: 1729 139 - magnitude: 16384 143 + i16: 0 144 + unsigned: 16384 145 + u16: 0 140 146 timestamp: 0 141 147 string: 123 142 148 abbrev: 7 ··· 147 153 EOF 148 154 149 155 test_expect_success 'short options' ' 150 - test-tool parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \ 156 + test-tool parse-options -s123 -b -i 1729 -u 16k -b -vv -n -F my.file \ 151 157 >output 2>output.err && 152 158 test_cmp expect output && 153 159 test_must_be_empty output.err ··· 156 162 cat >expect <<\EOF 157 163 boolean: 2 158 164 integer: 1729 159 - magnitude: 16384 165 + i16: 9000 166 + unsigned: 16384 167 + u16: 32768 160 168 timestamp: 0 161 169 string: 321 162 170 abbrev: 10 ··· 167 175 EOF 168 176 169 177 test_expect_success 'long options' ' 170 - test-tool parse-options --boolean --integer 1729 --magnitude 16k \ 171 - --boolean --string2=321 --verbose --verbose --no-dry-run \ 178 + test-tool parse-options --boolean --integer 1729 --i16 9000 --unsigned 16k \ 179 + --u16 32k --boolean --string2=321 --verbose --verbose --no-dry-run \ 172 180 --abbrev=10 --file fi.le --obsolete \ 173 181 >output 2>output.err && 174 182 test_must_be_empty output.err && ··· 179 187 cat >expect <<-EOF && 180 188 boolean: 0 181 189 integer: 0 182 - magnitude: 0 190 + i16: 0 191 + unsigned: 0 192 + u16: 0 183 193 timestamp: 0 184 194 string: (not set) 185 195 abbrev: 100 ··· 253 263 cat >expect <<\EOF 254 264 boolean: 1 255 265 integer: 13 256 - magnitude: 0 266 + i16: 0 267 + unsigned: 0 268 + u16: 0 257 269 timestamp: 0 258 270 string: 123 259 271 abbrev: 7 ··· 276 288 cat >expect <<\EOF 277 289 boolean: 0 278 290 integer: 2 279 - magnitude: 0 291 + i16: 0 292 + unsigned: 0 293 + u16: 0 280 294 timestamp: 0 281 295 string: (not set) 282 296 abbrev: 7 ··· 343 357 Callback: "four", 0 344 358 boolean: 5 345 359 integer: 4 346 - magnitude: 0 360 + i16: 0 361 + unsigned: 0 362 + u16: 0 347 363 timestamp: 0 348 364 string: (not set) 349 365 abbrev: 7 ··· 368 384 cat >expect <<\EOF 369 385 boolean: 1 370 386 integer: 23 371 - magnitude: 0 387 + i16: 0 388 + unsigned: 0 389 + u16: 0 372 390 timestamp: 0 373 391 string: (not set) 374 392 abbrev: 7 ··· 447 465 cat >expect <<\EOF 448 466 boolean: 0 449 467 integer: 0 450 - magnitude: 0 468 + i16: 0 469 + unsigned: 0 470 + u16: 0 451 471 timestamp: 0 452 472 string: (not set) 453 473 abbrev: 7 ··· 771 791 grep ^BUG err 772 792 ' 773 793 774 - test_expect_success 'negative magnitude' ' 775 - test_must_fail test-tool parse-options --magnitude -1 >out 2>err && 794 + test_expect_success 'negative unsigned' ' 795 + test_must_fail test-tool parse-options --unsigned -1 >out 2>err && 776 796 grep "non-negative integer" err && 777 797 test_must_be_empty out 778 798 ' 779 799 780 - test_expect_success 'magnitude with units but no numbers' ' 781 - test_must_fail test-tool parse-options --magnitude m >out 2>err && 800 + test_expect_success 'unsigned with units but no numbers' ' 801 + test_must_fail test-tool parse-options --unsigned m >out 2>err && 782 802 grep "non-negative integer" err && 783 803 test_must_be_empty out 804 + ' 805 + 806 + test_expect_success 'i16 limits range' ' 807 + test-tool parse-options --i16 32767 >out && 808 + test_grep "i16: 32767" out && 809 + test_must_fail test-tool parse-options --i16 32768 2>err && 810 + test_grep "value 32768 for option .i16. not in range \[-32768,32767\]" err && 811 + 812 + test-tool parse-options --i16 -32768 >out && 813 + test_grep "i16: -32768" out && 814 + test_must_fail test-tool parse-options --i16 -32769 2>err && 815 + test_grep "value -32769 for option .i16. not in range \[-32768,32767\]" err 816 + ' 817 + 818 + test_expect_success 'u16 limits range' ' 819 + test-tool parse-options --u16 65535 >out && 820 + test_grep "u16: 65535" out && 821 + test_must_fail test-tool parse-options --u16 65536 2>err && 822 + test_grep "value 65536 for option .u16. not in range \[0,65535\]" err 784 823 ' 785 824 786 825 test_done