{"thread":{"id":"49759","subject":"[PATCH 0/13] parseopt fixes from -Wunused-parameters","startedAt":"2018-11-05T06:37:35Z","lastAt":"2018-11-05T18:52:02Z","messageCount":21,"participants":["Jeff King","Junio C Hamano","Duy Nguyen","Carlo Marcelo Arenas Belón"],"isPatch":true,"patchVersion":1,"patchTotal":13},"messages":[{"id":"362457","messageId":"20181105063718.GA24877@sigill.intra.peff.net","threadId":"49759","inReplyTo":null,"subject":"[PATCH 0/13] parseopt fixes from -Wunused-parameters","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:37:18Z","receivedAt":"2018-11-05T06:37:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Continuing my exploration of what -Wunused-parameters can show us, here\nare some bug-fixes related to parse-options callbacks.\n\nThis is the last of the actual bug-fixes I've found. After this, I have\nabout 60 patches worth of cleanups (i.e., dropping the unused\nparameters), and then I have a series to annotate parameters that must\nbe unused (e.g., for functions that must conform to callback\ninterfaces). After we can start compiling with -Wunused-parameters,\nassuming we don't find the annotations too cumbersome.\n\nBut this series fixes real bugs. These first four fix segfaults:\n\n  [01/13]: apply: mark include/exclude options as NONEG\n  [02/13]: am: handle --no-patch-format option\n  [03/13]: ls-files: mark exclude options as NONEG\n  [04/13]: pack-objects: mark index-version option as NONEG\n\nAnd these four fix cases where we just quietly do the wrong thing:\n\n  [05/13]: cat-file: mark batch options with NONEG\n  [06/13]: status: mark --find-renames option with NONEG\n  [07/13]: format-patch: mark \"--no-numbered\" option with NONEG\n  [08/13]: show-branch: mark --reflog option as NONEG\n\nThese ones are just message improvements:\n\n  [09/13]: tag: mark \"--message\" option with NONEG\n  [10/13]: cat-file: report an error on multiple --batch options\n  [11/13]: apply: return -1 from option callback instead of calling exit(1)\n\nThis one is a segfault, but it has no callers. ;)\n\n  [12/13]: parse-options: drop OPT_DATE()\n\nAnd then this last one is mostly about annotating the callbacks. It\ndoesn't strictly need to happen here, but the alternative is that I'd\neventually have to deal with it in the later series I mentioned.\n\n  [13/13]: assert NOARG/NONEG behavior of parse-options callbacks\n\n apply.c                       | 24 +++++++++++++++++++++---\n builtin/am.c                  |  4 +++-\n builtin/blame.c               |  4 ++++\n builtin/cat-file.c            | 10 +++++++---\n builtin/checkout-index.c      |  2 ++\n builtin/clean.c               |  1 +\n builtin/commit.c              |  5 ++++-\n builtin/fetch.c               |  2 ++\n builtin/grep.c                | 14 +++++++++++++-\n builtin/init-db.c             |  1 +\n builtin/interpret-trailers.c  |  2 ++\n builtin/log.c                 | 12 +++++++++++-\n builtin/ls-files.c            | 14 +++++++++++---\n builtin/merge-file.c          |  2 ++\n builtin/merge.c               |  1 +\n builtin/notes.c               |  7 +++++++\n builtin/pack-objects.c        |  5 ++++-\n builtin/read-tree.c           |  3 +++\n builtin/rebase.c              |  6 ++++++\n builtin/show-branch.c         |  3 ++-\n builtin/show-ref.c            |  1 +\n builtin/tag.c                 |  6 ++++--\n builtin/update-index.c        | 21 +++++++++++++++++++--\n parse-options-cb.c            | 14 +++++++-------\n parse-options.h               | 18 ++++++++++++++----\n ref-filter.c                  |  2 ++\n t/helper/test-parse-options.c |  2 +-\n t/t0040-parse-options.sh      | 22 ----------------------\n 28 files changed, 155 insertions(+), 53 deletions(-)\n\n-Peff\n"},{"id":"362458","messageId":"20181105063819.GA25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 01/13] apply: mark include/exclude options as NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:38:19Z","receivedAt":"2018-11-05T06:38:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The options callback for \"git apply --no-include\" is not ready to handle\nthe \"unset\" parameter, and as a result will segfault when it adds a NULL\nargument to the include list (likewise for \"--no-exclude\").\n\nIn theory this might be used to clear the list, but since both\n\"--include\" and \"--exclude\" add to the same list, it's not immediately\nobvious what the semantics should be. Let's punt on that for now and\njust disallow the broken options.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n apply.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex 073d5f0451..d1ca6addeb 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4939,10 +4939,10 @@ int apply_parse_options(int argc, const char **argv,\n \tstruct option builtin_apply_options[] = {\n \t\t{ OPTION_CALLBACK, 0, \"exclude\", state, N_(\"path\"),\n \t\t\tN_(\"don't apply changes matching the given path\"),\n-\t\t\t0, apply_option_parse_exclude },\n+\t\t\tPARSE_OPT_NONEG, apply_option_parse_exclude },\n \t\t{ OPTION_CALLBACK, 0, \"include\", state, N_(\"path\"),\n \t\t\tN_(\"apply changes matching the given path\"),\n-\t\t\t0, apply_option_parse_include },\n+\t\t\tPARSE_OPT_NONEG, apply_option_parse_include },\n \t\t{ OPTION_CALLBACK, 'p', NULL, state, N_(\"num\"),\n \t\t\tN_(\"remove <num> leading slashes from traditional diff paths\"),\n \t\t\t0, apply_option_parse_p },\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362459","messageId":"20181105063839.GB25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 02/13] am: handle --no-patch-format option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:38:39Z","receivedAt":"2018-11-05T06:38:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Running \"git am --no-patch-format\" will currently segfault, since it\ntries to parse a NULL argument. Instead, let's have it cancel any\nprevious --patch-format option.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/am.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 3ee9a9d2a9..dcb880b699 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -2165,7 +2165,9 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int\n {\n \tint *opt_value = opt->value;\n \n-\tif (!strcmp(arg, \"mbox\"))\n+\tif (unset)\n+\t\t*opt_value = PATCH_FORMAT_UNKNOWN;\n+\telse if (!strcmp(arg, \"mbox\"))\n \t\t*opt_value = PATCH_FORMAT_MBOX;\n \telse if (!strcmp(arg, \"stgit\"))\n \t\t*opt_value = PATCH_FORMAT_STGIT;\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362460","messageId":"20181105063919.GC25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 03/13] ls-files: mark exclude options as NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:39:20Z","receivedAt":"2018-11-05T06:39:23Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Running \"git ls-files --no-exclude\" will currently segfault, as its\noption callback does not handle the \"unset\" parameter.\n\nIn theory this could be used to clear the exclude list, but it is not\nclear how that would interact with the other exclude options, nor is the\ncurrent code capable of clearing the list. Let's just disable the broken\noption.\n\nNote that --no-exclude-from will similarly segfault, but\n--no-exclude-standard will not. It just silently does the wrong thing\n(pretending as if --exclude-standard was specified).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/ls-files.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 7f9919a362..2787453eb1 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -548,15 +548,16 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\t    N_(\"show resolve-undo information\")),\n \t\t{ OPTION_CALLBACK, 'x', \"exclude\", &exclude_list, N_(\"pattern\"),\n \t\t\tN_(\"skip files matching pattern\"),\n-\t\t\t0, option_parse_exclude },\n+\t\t\tPARSE_OPT_NONEG, option_parse_exclude },\n \t\t{ OPTION_CALLBACK, 'X', \"exclude-from\", &dir, N_(\"file\"),\n \t\t\tN_(\"exclude patterns are read from <file>\"),\n-\t\t\t0, option_parse_exclude_from },\n+\t\t\tPARSE_OPT_NONEG, option_parse_exclude_from },\n \t\tOPT_STRING(0, \"exclude-per-directory\", &dir.exclude_per_dir, N_(\"file\"),\n \t\t\tN_(\"read additional per-directory exclude patterns in <file>\")),\n \t\t{ OPTION_CALLBACK, 0, \"exclude-standard\", &dir, NULL,\n \t\t\tN_(\"add the standard git exclusions\"),\n-\t\t\tPARSE_OPT_NOARG, option_parse_exclude_standard },\n+\t\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG,\n+\t\t\toption_parse_exclude_standard },\n \t\tOPT_SET_INT_F(0, \"full-name\", &prefix_len,\n \t\t\t      N_(\"make the output relative to the project top directory\"),\n \t\t\t      0, PARSE_OPT_NONEG),\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362461","messageId":"20181105063938.GD25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 04/13] pack-objects: mark index-version option as NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:39:38Z","receivedAt":"2018-11-05T06:39:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Running \"git pack-objects --no-index-version\" will segfault, since the\ncallback is not prepared to handle the \"unset\" flag.\n\nIn theory this might be used to counteract an earlier \"--index-version\",\nor override a pack.indexversion config setting. But the semantics aren't\nimmediately obvious, and it's unlikely anybody wants this. Let's just\ndisable the broken option for now.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/pack-objects.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex e50c6cd1ff..4eac2f997b 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -3252,7 +3252,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"similar to --all-progress when progress meter is shown\")),\n \t\t{ OPTION_CALLBACK, 0, \"index-version\", NULL, N_(\"<version>[,<offset>]\"),\n \t\t  N_(\"write the pack index file in the specified idx format version\"),\n-\t\t  0, option_parse_index_version },\n+\t\t  PARSE_OPT_NONEG, option_parse_index_version },\n \t\tOPT_MAGNITUDE(0, \"max-pack-size\", &pack_size_limit,\n \t\t\t      N_(\"maximum size of each output pack file\")),\n \t\tOPT_BOOL(0, \"local\", &local,\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362462","messageId":"20181105064010.GE25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 05/13] cat-file: mark batch options with NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:40:10Z","receivedAt":"2018-11-05T06:40:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Running \"cat-file --no-batch\" will behave as if \"--batch\" was given,\nsince the option callback does not handle the \"unset\" flag (likewise for\n\"--no-batch-check\").\n\nIn theory this might be used to cancel an earlier --batch, but it's not\nimmediately obvious how that would interact with --batch-check. Let's\njust disallow the negated form of both options.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/cat-file.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 8d97c84725..4a5289079c 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -631,10 +631,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"buffer\", &batch.buffer_output, N_(\"buffer --batch output\")),\n \t\t{ OPTION_CALLBACK, 0, \"batch\", &batch, \"format\",\n \t\t\tN_(\"show info and content of objects fed from the standard input\"),\n-\t\t\tPARSE_OPT_OPTARG, batch_option_callback },\n+\t\t\tPARSE_OPT_OPTARG | PARSE_OPT_NONEG,\n+\t\t\tbatch_option_callback },\n \t\t{ OPTION_CALLBACK, 0, \"batch-check\", &batch, \"format\",\n \t\t\tN_(\"show info about objects fed from the standard input\"),\n-\t\t\tPARSE_OPT_OPTARG, batch_option_callback },\n+\t\t\tPARSE_OPT_OPTARG | PARSE_OPT_NONEG,\n+\t\t\tbatch_option_callback },\n \t\tOPT_BOOL(0, \"follow-symlinks\", &batch.follow_symlinks,\n \t\t\t N_(\"follow in-tree symlinks (used with --batch or --batch-check)\")),\n \t\tOPT_BOOL(0, \"batch-all-objects\", &batch.all_objects,\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362463","messageId":"20181105064053.GF25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 06/13] status: mark --find-renames option with NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:40:53Z","receivedAt":"2018-11-05T06:40:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"If you run \"git status --no-find-renames\", it will behave the same as\n\"--find-renames\", because we ignore the \"unset\" parameter (we see a NULL\n\"arg\", but since the score argument is optional, we just think that the\nuser did not provide a score).\n\nWe already have a separate \"--no-renames\" to disable renames, so there's\nnot much point in supporting \"--no-find-renames\". Let's just flag it as\nan error.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/commit.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 074bd9a551..4d7754ca43 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1335,7 +1335,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"no-renames\", &no_renames, N_(\"do not detect renames\")),\n \t\t{ OPTION_CALLBACK, 'M', \"find-renames\", &rename_score_arg,\n \t\t  N_(\"n\"), N_(\"detect renames, optionally set similarity index\"),\n-\t\t  PARSE_OPT_OPTARG, opt_parse_rename_score },\n+\t\t  PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score },\n \t\tOPT_END(),\n \t};\n \n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362464","messageId":"20181105064112.GG25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 07/13] format-patch: mark \"--no-numbered\" option with NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:41:12Z","receivedAt":"2018-11-05T06:41:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We have separate parse-options entries for \"numbered\" and \"no-numbered\",\nwhich means that we accept \"--no-no-numbered\". It does not behave\nsensibly, though (it ignores the \"unset\" flag and acts like\n\"--no-numbered\").\n\nWe could fix that, but obviously this is silly and unintentional. Let's\njust disallow it.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/log.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 061d4fd864..41188e723c 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -1508,7 +1508,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t    PARSE_OPT_NOARG, numbered_callback },\n \t\t{ OPTION_CALLBACK, 'N', \"no-numbered\", &numbered, NULL,\n \t\t\t    N_(\"use [PATCH] even with multiple patches\"),\n-\t\t\t    PARSE_OPT_NOARG, no_numbered_callback },\n+\t\t\t    PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback },\n \t\tOPT_BOOL('s', \"signoff\", &do_signoff, N_(\"add Signed-off-by:\")),\n \t\tOPT_BOOL(0, \"stdout\", &use_stdout,\n \t\t\t    N_(\"print patches to standard out\")),\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362465","messageId":"20181105064240.GH25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 08/13] show-branch: mark --reflog option as NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:42:40Z","receivedAt":"2018-11-05T06:42:43Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Running \"git show-branch --no-reflog\" will behave as if \"--reflog\" was\ngiven with no options, which makes no sense.\n\nIn theory this option might be used to cancel an earlier \"--reflog\"\noption, but the semantics are not clear. Let's punt on it and just\ndisallow the broken option.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nOn most of these I tried to decide whether there was a sensible\nbehavior, and actually do the fix. But I have to admit I have no idea\nhow \"show-branch -g\" is supposed to work, which is the main reason I\npunted here. If somebody cares enough to write a patch, they can\nsupersede this (but we should do something, because the current behavior\nis nonsense).\n\n builtin/show-branch.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex 65f4a4c83c..b1b540f7f6 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -674,7 +674,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)\n \t\t{ OPTION_CALLBACK, 'g', \"reflog\", &reflog_base, N_(\"<n>[,<base>]\"),\n \t\t\t    N_(\"show <n> most recent ref-log entries starting at \"\n \t\t\t       \"base\"),\n-\t\t\t    PARSE_OPT_OPTARG,\n+\t\t\t    PARSE_OPT_OPTARG | PARSE_OPT_NONEG,\n \t\t\t    parse_reflog_param },\n \t\tOPT_END()\n \t};\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362466","messageId":"20181105064312.GI25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 09/13] tag: mark \"--message\" option with NONEG","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:43:12Z","receivedAt":"2018-11-05T06:43:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"We do not allow \"--no-message\" to work now, as the option callback\nreturns \"-1\" when it sees a NULL arg. However, that will cause\nparse-options to exit(129) without printing anything further, leaving\nthe user confused about what happened.\n\nInstead, let's explicitly mark it as PARSE_OPT_NONEG, which will give a\nuseful error message (and print the usual -h output).\n\nIn theory this could be used to override an earlier \"-m\", but it's not\nclear how it would interact with other message options (e.g., would it\nalso clear data read for \"-F\"?). Since it's already disabled and nobody\nis asking for it, let's punt on that and just improve the error message.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/tag.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex f623632186..6a396a5090 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -390,8 +390,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tOPT_GROUP(N_(\"Tag creation options\")),\n \t\tOPT_BOOL('a', \"annotate\", &annotate,\n \t\t\t\t\tN_(\"annotated tag, needs a message\")),\n-\t\tOPT_CALLBACK('m', \"message\", &msg, N_(\"message\"),\n-\t\t\t     N_(\"tag message\"), parse_msg_arg),\n+\t\t{ OPTION_CALLBACK, 'm', \"message\", &msg, N_(\"message\"),\n+\t\t  N_(\"tag message\"), PARSE_OPT_NONEG, parse_msg_arg },\n \t\tOPT_FILENAME('F', \"file\", &msgfile, N_(\"read message from file\")),\n \t\tOPT_BOOL('e', \"edit\", &edit_flag, N_(\"force edit of tag message\")),\n \t\tOPT_BOOL('s', \"sign\", &opt.sign, N_(\"annotated and GPG-signed tag\")),\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362467","messageId":"20181105064344.GJ25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 10/13] cat-file: report an error on multiple --batch options","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:43:44Z","receivedAt":"2018-11-05T06:43:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The options callback for --batch and --batch-check detects when the two\nmutually incompatible options are used. But it simply returns an error\ncode to parse-options, meaning the program will quit without any kind of\nmessage to the user.\n\nInstead, let's use error() to print something and return -1. Note that\nthis flips the error return from 1 to -1, but negative values are more\nidiomatic here (and parse-options treats them the same).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/cat-file.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 4a5289079c..0f6b692df6 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -596,7 +596,7 @@ static int batch_option_callback(const struct option *opt,\n \tstruct batch_options *bo = opt->value;\n \n \tif (bo->enabled) {\n-\t\treturn 1;\n+\t\treturn error(_(\"only one batch option may be specified\"));\n \t}\n \n \tbo->enabled = 1;\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362468","messageId":"20181105064358.GK25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 11/13] apply: return -1 from option callback instead of calling exit(1)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:43:59Z","receivedAt":"2018-11-05T06:44:02Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"The option callback for \"apply --whitespace\" exits with status \"1\" on\nerror. It makes more sense for it to just return an error to\nparse-options. That code will exit, too, but it will use status \"129\"\nthat is customary for option errors.\n\nThe exit() dates back to aaf6c447aa (builtin/apply: make\nparse_whitespace_option() return -1 instead of die()ing, 2016-08-08).\nThat commit gives no reason why we'd prefer the current exit status (it\nlooks like it was just bumping the \"die\" up a level in the callstack,\nbut did not go as far as it could have).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex d1ca6addeb..c4c9f849b1 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4812,7 +4812,7 @@ static int apply_option_parse_whitespace(const struct option *opt,\n \tstruct apply_state *state = opt->value;\n \tstate->whitespace_option = arg;\n \tif (parse_whitespace_option(state, arg))\n-\t\texit(1);\n+\t\treturn -1;\n \treturn 0;\n }\n \n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362469","messageId":"20181105064427.GL25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 12/13] parse-options: drop OPT_DATE()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:44:27Z","receivedAt":"2018-11-05T06:44:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"There are no users of OPT_DATE except for test-parse-options; its\nonly caller went away in 27ec394a97 (prune: introduce OPT_EXPIRY_DATE()\nand use it, 2013-04-25).\n\nIt also has a bug: it does not specify PARSE_OPT_NONEG, but its callback\ndoes not respect the \"unset\" flag, and will feed NULL to approxidate()\nand segfault. Probably this should be marked with NONEG, or the callback\nshould set the timestamp to some sentinel value (e.g,. \"0\", or\n\"(time_t)-1\").\n\nBut since there are no callers, deleting it means we don't even have to\nthink about what the right behavior should be.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n parse-options-cb.c            |  7 -------\n parse-options.h               |  4 ----\n t/helper/test-parse-options.c |  1 -\n t/t0040-parse-options.sh      | 22 ----------------------\n 4 files changed, 34 deletions(-)\n\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex e8236534ac..6a61166b26 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -28,13 +28,6 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n-int parse_opt_approxidate_cb(const struct option *opt, const char *arg,\n-\t\t\t     int unset)\n-{\n-\t*(timestamp_t *)(opt->value) = approxidate(arg);\n-\treturn 0;\n-}\n-\n int parse_opt_expiry_date_cb(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\ndiff --git a/parse-options.h b/parse-options.h\nindex dd14911a29..c3f2d2eceb 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -150,9 +150,6 @@ struct option {\n \t\t\t\t      (h), 0, &parse_opt_string_list }\n #define OPT_UYN(s, l, v, h)         { OPTION_CALLBACK, (s), (l), (v), NULL, \\\n \t\t\t\t      (h), PARSE_OPT_NOARG, &parse_opt_tertiary }\n-#define OPT_DATE(s, l, v, h) \\\n-\t{ OPTION_CALLBACK, (s), (l), (v), N_(\"time\"),(h), 0,\t\\\n-\t  parse_opt_approxidate_cb }\n #define OPT_EXPIRY_DATE(s, l, v, h) \\\n \t{ OPTION_CALLBACK, (s), (l), (v), N_(\"expiry-date\"),(h), 0,\t\\\n \t  parse_opt_expiry_date_cb }\n@@ -232,7 +229,6 @@ extern struct option *parse_options_concat(struct option *a, struct option *b);\n \n /*----- some often used options -----*/\n extern int parse_opt_abbrev_cb(const struct option *, const char *, int);\n-extern int parse_opt_approxidate_cb(const struct option *, const char *, int);\n extern int parse_opt_expiry_date_cb(const struct option *, const char *, int);\n extern int parse_opt_color_flag_cb(const struct option *, const char *, int);\n extern int parse_opt_verbosity_cb(const struct option *, const char *, int);\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex 9cb8a0ea0f..f0623bb42b 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -119,7 +119,6 @@ int cmd__parse_options(int argc, const char **argv)\n \t\tOPT_INTEGER('j', NULL, &integer, \"get a integer, too\"),\n \t\tOPT_MAGNITUDE('m', \"magnitude\", &magnitude, \"get a magnitude\"),\n \t\tOPT_SET_INT(0, \"set23\", &integer, \"set integer to 23\", 23),\n-\t\tOPT_DATE('t', NULL, &timestamp, \"get timestamp of <time>\"),\n \t\tOPT_CALLBACK('L', \"length\", &integer, \"str\",\n \t\t\t\"get length of <str>\", length_callback),\n \t\tOPT_FILENAME('F', \"file\", &file, \"set file to <file>\"),\ndiff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh\nindex 17d0c18feb..f5b10861c4 100755\n--- a/t/t0040-parse-options.sh\n+++ b/t/t0040-parse-options.sh\n@@ -23,7 +23,6 @@ usage: test-tool parse-options <options>\n     -j <n>                get a integer, too\n     -m, --magnitude <n>   get a magnitude\n     --set23               set integer to 23\n-    -t <time>             get timestamp of <time>\n     -L, --length <str>    get length of <str>\n     -F, --file <file>     set file to <file>\n \n@@ -245,27 +244,6 @@ test_expect_success 'keep some options as arguments' '\n \ttest-tool parse-options --expect=\"arg 00: --quux\" --quux\n '\n \n-cat >expect <<\\EOF\n-boolean: 0\n-integer: 0\n-magnitude: 0\n-timestamp: 1\n-string: (not set)\n-abbrev: 7\n-verbose: -1\n-quiet: 1\n-dry run: no\n-file: (not set)\n-arg 00: foo\n-EOF\n-\n-test_expect_success 'OPT_DATE() works' '\n-\ttest-tool parse-options -t \"1970-01-01 00:00:01 +0000\" \\\n-\t\tfoo -q >output 2>output.err &&\n-\ttest_must_be_empty output.err &&\n-\ttest_cmp expect output\n-'\n-\n cat >expect <<\\EOF\n Callback: \"four\", 0\n boolean: 5\n-- \n2.19.1.1505.g9cd28186cf\n\n"},{"id":"362470","messageId":"20181105064542.GM25864@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"[PATCH 13/13] assert NOARG/NONEG behavior of parse-options callbacks","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T06:45:42Z","receivedAt":"2018-11-05T06:45:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"When we define a parse-options callback, the flags we put in the option\nstruct must match what the callback expects. For example, a callback\nwhich does not handle the \"unset\" parameter should only be used with\nPARSE_OPT_NONEG. But since the callback and the option struct are not\ndefined next to each other, it's easy to get this wrong (as earlier\npatches in this series show).\n\nFortunately, the compiler can help us here: compiling with\n-Wunused-parameters can show us which callbacks ignore their \"unset\"\nparameters (and likewise, ones that ignore \"arg\" expect to be triggered\nwith PARSE_OPT_NOARG).\n\nBut after we've inspected a callback and determined that all of its\ncallers use the right flags, what do we do next? We'd like to silence\nthe compiler warning, but do so in a way that will catch any wrong calls\nin the future.\n\nWe can do that by actually checking those variables and asserting that\nthey match our expectations. Because this is such a common pattern,\nwe'll introduce some helper macros. The resulting messages aren't\nas descriptive as we could make them, but the file/line information from\nBUG() is enough to identify the problem (and anyway, the point is that\nthese should never be seen).\n\nEach of the annotated callbacks in this patch triggers\n-Wunused-parameters, and was manually inspected to make sure all callers\nuse the correct options (so none of these BUGs should be triggerable).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n apply.c                       | 18 ++++++++++++++++++\n builtin/blame.c               |  4 ++++\n builtin/cat-file.c            |  2 ++\n builtin/checkout-index.c      |  2 ++\n builtin/clean.c               |  1 +\n builtin/commit.c              |  3 +++\n builtin/fetch.c               |  2 ++\n builtin/grep.c                | 14 +++++++++++++-\n builtin/init-db.c             |  1 +\n builtin/interpret-trailers.c  |  2 ++\n builtin/log.c                 | 10 ++++++++++\n builtin/ls-files.c            |  7 +++++++\n builtin/merge-file.c          |  2 ++\n builtin/merge.c               |  1 +\n builtin/notes.c               |  7 +++++++\n builtin/pack-objects.c        |  3 +++\n builtin/read-tree.c           |  3 +++\n builtin/rebase.c              |  6 ++++++\n builtin/show-branch.c         |  1 +\n builtin/show-ref.c            |  1 +\n builtin/tag.c                 |  2 ++\n builtin/update-index.c        | 21 +++++++++++++++++++--\n parse-options-cb.c            |  7 +++++++\n parse-options.h               | 14 ++++++++++++++\n ref-filter.c                  |  2 ++\n t/helper/test-parse-options.c |  1 +\n 26 files changed, 134 insertions(+), 3 deletions(-)\n\ndiff --git a/apply.c b/apply.c\nindex c4c9f849b1..3746310cef 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4772,6 +4772,9 @@ static int apply_option_parse_exclude(const struct option *opt,\n \t\t\t\t      const char *arg, int unset)\n {\n \tstruct apply_state *state = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tadd_name_limit(state, arg, 1);\n \treturn 0;\n }\n@@ -4780,6 +4783,9 @@ static int apply_option_parse_include(const struct option *opt,\n \t\t\t\t      const char *arg, int unset)\n {\n \tstruct apply_state *state = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tadd_name_limit(state, arg, 0);\n \tstate->has_include = 1;\n \treturn 0;\n@@ -4790,6 +4796,9 @@ static int apply_option_parse_p(const struct option *opt,\n \t\t\t\tint unset)\n {\n \tstruct apply_state *state = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tstate->p_value = atoi(arg);\n \tstate->p_value_known = 1;\n \treturn 0;\n@@ -4799,6 +4808,9 @@ static int apply_option_parse_space_change(const struct option *opt,\n \t\t\t\t\t   const char *arg, int unset)\n {\n \tstruct apply_state *state = opt->value;\n+\n+\tBUG_ON_OPT_ARG(arg);\n+\n \tif (unset)\n \t\tstate->ws_ignore_action = ignore_ws_none;\n \telse\n@@ -4810,6 +4822,9 @@ static int apply_option_parse_whitespace(const struct option *opt,\n \t\t\t\t\t const char *arg, int unset)\n {\n \tstruct apply_state *state = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tstate->whitespace_option = arg;\n \tif (parse_whitespace_option(state, arg))\n \t\treturn -1;\n@@ -4820,6 +4835,9 @@ static int apply_option_parse_directory(const struct option *opt,\n \t\t\t\t\tconst char *arg, int unset)\n {\n \tstruct apply_state *state = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tstrbuf_reset(&state->root);\n \tstrbuf_addstr(&state->root, arg);\n \tstrbuf_complete(&state->root, '/');\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex a443af9ee9..06a7163ffe 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -732,6 +732,8 @@ static int blame_copy_callback(const struct option *option, const char *arg, int\n {\n \tint *opt = option->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \t/*\n \t * -C enables copy from removed files;\n \t * -C -C enables copy from existing files, but only\n@@ -754,6 +756,8 @@ static int blame_move_callback(const struct option *option, const char *arg, int\n {\n \tint *opt = option->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \t*opt |= PICKAXE_BLAME_MOVE;\n \n \tif (arg)\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 0f6b692df6..1cdd357d52 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -595,6 +595,8 @@ static int batch_option_callback(const struct option *opt,\n {\n \tstruct batch_options *bo = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (bo->enabled) {\n \t\treturn error(_(\"only one batch option may be specified\"));\n \t}\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 88b86c8d9f..eb74774cbc 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -132,6 +132,8 @@ static const char * const builtin_checkout_index_usage[] = {\n static int option_parse_stage(const struct option *opt,\n \t\t\t      const char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (!strcmp(arg, \"all\")) {\n \t\tto_tempfile = 1;\n \t\tcheckout_stage = CHECKOUT_ALL;\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 8d9a7dc206..bbcdeb2d9e 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -140,6 +140,7 @@ static void clean_print_color(enum color_clean ix)\n static int exclude_cb(const struct option *opt, const char *arg, int unset)\n {\n \tstruct string_list *exclude_list = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n \tstring_list_append(exclude_list, arg);\n \treturn 0;\n }\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 4d7754ca43..500f793fa6 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -161,6 +161,9 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)\n static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)\n {\n \tconst char **value = opt->value;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (arg != NULL && *arg == '=')\n \t\targ = arg + 1;\n \ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8f7249f2b1..354ed8bdef 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -98,6 +98,8 @@ static int git_fetch_config(const char *k, const char *v, void *cb)\n \n static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\n \t/*\n \t * \"git fetch --refmap='' origin foo\"\n \t * can be used to tell the command not to store anywhere\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d8508ddf79..33c8b61595 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -712,11 +712,14 @@ static int context_callback(const struct option *opt, const char *arg,\n static int file_callback(const struct option *opt, const char *arg, int unset)\n {\n \tstruct grep_opt *grep_opt = opt->value;\n-\tint from_stdin = !strcmp(arg, \"-\");\n+\tint from_stdin;\n \tFILE *patterns;\n \tint lno = 0;\n \tstruct strbuf sb = STRBUF_INIT;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n+\tfrom_stdin = !strcmp(arg, \"-\");\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n@@ -737,6 +740,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n static int not_callback(const struct option *opt, const char *arg, int unset)\n {\n \tstruct grep_opt *grep_opt = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \tappend_grep_pattern(grep_opt, \"--not\", \"command line\", 0, GREP_NOT);\n \treturn 0;\n }\n@@ -744,6 +749,8 @@ static int not_callback(const struct option *opt, const char *arg, int unset)\n static int and_callback(const struct option *opt, const char *arg, int unset)\n {\n \tstruct grep_opt *grep_opt = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \tappend_grep_pattern(grep_opt, \"--and\", \"command line\", 0, GREP_AND);\n \treturn 0;\n }\n@@ -751,6 +758,8 @@ static int and_callback(const struct option *opt, const char *arg, int unset)\n static int open_callback(const struct option *opt, const char *arg, int unset)\n {\n \tstruct grep_opt *grep_opt = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \tappend_grep_pattern(grep_opt, \"(\", \"command line\", 0, GREP_OPEN_PAREN);\n \treturn 0;\n }\n@@ -758,6 +767,8 @@ static int open_callback(const struct option *opt, const char *arg, int unset)\n static int close_callback(const struct option *opt, const char *arg, int unset)\n {\n \tstruct grep_opt *grep_opt = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \tappend_grep_pattern(grep_opt, \")\", \"command line\", 0, GREP_CLOSE_PAREN);\n \treturn 0;\n }\n@@ -766,6 +777,7 @@ static int pattern_callback(const struct option *opt, const char *arg,\n \t\t\t    int unset)\n {\n \tstruct grep_opt *grep_opt = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n \tappend_grep_pattern(grep_opt, arg, \"-e option\", 0, GREP_PATTERN);\n \treturn 0;\n }\ndiff --git a/builtin/init-db.c b/builtin/init-db.c\nindex 12ddda7e7b..41faffd28d 100644\n--- a/builtin/init-db.c\n+++ b/builtin/init-db.c\n@@ -451,6 +451,7 @@ static int guess_repository_type(const char *git_dir)\n \n static int shared_callback(const struct option *opt, const char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n \t*((int *) opt->value) = (arg) ? git_config_perm(\"arg\", arg) : PERM_GROUP;\n \treturn 0;\n }\ndiff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c\nindex 4b87e0dd2e..8ae40dec47 100644\n--- a/builtin/interpret-trailers.c\n+++ b/builtin/interpret-trailers.c\n@@ -80,6 +80,8 @@ static int parse_opt_parse(const struct option *opt, const char *arg,\n \tv->only_trailers = 1;\n \tv->only_input = 1;\n \tv->unfold = 1;\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \treturn 0;\n }\n \ndiff --git a/builtin/log.c b/builtin/log.c\nindex 41188e723c..9f2d987294 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -107,6 +107,8 @@ static int log_line_range_callback(const struct option *option, const char *arg,\n {\n \tstruct line_opt_callback_data *data = option->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (!arg)\n \t\treturn -1;\n \n@@ -1151,6 +1153,8 @@ static int keep_subject = 0;\n \n static int keep_callback(const struct option *opt, const char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \t((struct rev_info *)opt->value)->total = -1;\n \tkeep_subject = 1;\n \treturn 0;\n@@ -1161,6 +1165,7 @@ static int subject_prefix = 0;\n static int subject_prefix_callback(const struct option *opt, const char *arg,\n \t\t\t    int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n \tsubject_prefix = 1;\n \t((struct rev_info *)opt->value)->subject_prefix = arg;\n \treturn 0;\n@@ -1168,6 +1173,8 @@ static int subject_prefix_callback(const struct option *opt, const char *arg,\n \n static int rfc_callback(const struct option *opt, const char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \treturn subject_prefix_callback(opt, \"RFC PATCH\", unset);\n }\n \n@@ -1176,6 +1183,7 @@ static int numbered_cmdline_opt = 0;\n static int numbered_callback(const struct option *opt, const char *arg,\n \t\t\t     int unset)\n {\n+\tBUG_ON_OPT_ARG(arg);\n \t*(int *)opt->value = numbered_cmdline_opt = unset ? 0 : 1;\n \tif (unset)\n \t\tauto_number =  0;\n@@ -1185,6 +1193,7 @@ static int numbered_callback(const struct option *opt, const char *arg,\n static int no_numbered_callback(const struct option *opt, const char *arg,\n \t\t\t\tint unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n \treturn numbered_callback(opt, arg, 1);\n }\n \n@@ -1192,6 +1201,7 @@ static int output_directory_callback(const struct option *opt, const char *arg,\n \t\t\t      int unset)\n {\n \tconst char **dir = (const char **)opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n \tif (*dir)\n \t\tdie(_(\"Two output directories?\"));\n \t*dir = arg;\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 2787453eb1..c70a9c7158 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -475,6 +475,8 @@ static int option_parse_exclude(const struct option *opt,\n {\n \tstruct string_list *exclude_list = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \texc_given = 1;\n \tstring_list_append(exclude_list, arg);\n \n@@ -486,6 +488,8 @@ static int option_parse_exclude_from(const struct option *opt,\n {\n \tstruct dir_struct *dir = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \texc_given = 1;\n \tadd_excludes_from_file(dir, arg);\n \n@@ -497,6 +501,9 @@ static int option_parse_exclude_standard(const struct option *opt,\n {\n \tstruct dir_struct *dir = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n+\n \texc_given = 1;\n \tsetup_standard_excludes(dir);\n \ndiff --git a/builtin/merge-file.c b/builtin/merge-file.c\nindex b08803e611..06a2f90c48 100644\n--- a/builtin/merge-file.c\n+++ b/builtin/merge-file.c\n@@ -15,6 +15,8 @@ static int label_cb(const struct option *opt, const char *arg, int unset)\n \tstatic int label_count = 0;\n \tconst char **names = (const char **)opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (label_count >= 3)\n \t\treturn error(\"too many labels on the command line\");\n \tnames[label_count++] = arg;\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 4aa6071598..adb0402e84 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -224,6 +224,7 @@ static int option_parse_x(const struct option *opt,\n static int option_parse_n(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n+\tBUG_ON_OPT_ARG(arg);\n \tshow_diffstat = unset;\n \treturn 0;\n }\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex c05cd004ab..91faa514aa 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -215,6 +215,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n {\n \tstruct note_data *d = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tstrbuf_grow(&d->buf, strlen(arg) + 2);\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n@@ -229,6 +231,8 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n {\n \tstruct note_data *d = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tif (!strcmp(arg, \"-\")) {\n@@ -250,6 +254,8 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n \tenum object_type type;\n \tunsigned long len;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \n@@ -273,6 +279,7 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)\n static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)\n {\n \tstruct note_data *d = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n \td->use_editor = 1;\n \treturn parse_reuse_arg(opt, arg, unset);\n }\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 4eac2f997b..6718e62c15 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -3206,6 +3206,9 @@ static int option_parse_index_version(const struct option *opt,\n {\n \tchar *c;\n \tconst char *val = arg;\n+\n+\tBUG_ON_OPT_NEG(unset);\n+\n \tpack_idx_opts.version = strtoul(val, &c, 10);\n \tif (pack_idx_opts.version > 2)\n \t\tdie(_(\"unsupported index version %s\"), val);\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex fbbc98e516..183ee8c1e5 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -44,6 +44,7 @@ static const char * const read_tree_usage[] = {\n static int index_output_cb(const struct option *opt, const char *arg,\n \t\t\t\t int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n \tset_alternate_index_output(arg);\n \treturn 0;\n }\n@@ -54,6 +55,8 @@ static int exclude_per_directory_cb(const struct option *opt, const char *arg,\n \tstruct dir_struct *dir;\n \tstruct unpack_trees_options *opts;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \topts = (struct unpack_trees_options *)opt->value;\n \n \tif (opts->dir)\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 0ee06aa363..b84568fc4e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -703,6 +703,9 @@ static int parse_opt_merge(const struct option *opt, const char *arg, int unset)\n {\n \tstruct rebase_options *opts = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n+\n \tif (!is_interactive(opts))\n \t\topts->type = REBASE_MERGE;\n \n@@ -715,6 +718,9 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,\n {\n \tstruct rebase_options *opts = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n+\n \topts->type = REBASE_INTERACTIVE;\n \topts->flags |= REBASE_INTERACTIVE_EXPLICIT;\n \ndiff --git a/builtin/show-branch.c b/builtin/show-branch.c\nindex b1b540f7f6..934e514944 100644\n--- a/builtin/show-branch.c\n+++ b/builtin/show-branch.c\n@@ -604,6 +604,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg,\n {\n \tchar *ep;\n \tconst char **base = (const char **)opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n \tif (!arg)\n \t\targ = \"\";\n \treflog = strtoul(arg, &ep, 10);\ndiff --git a/builtin/show-ref.c b/builtin/show-ref.c\nindex 2f13f1316f..ed888ffa48 100644\n--- a/builtin/show-ref.c\n+++ b/builtin/show-ref.c\n@@ -151,6 +151,7 @@ static int hash_callback(const struct option *opt, const char *arg, int unset)\n static int exclude_existing_callback(const struct option *opt, const char *arg,\n \t\t\t\t     int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n \texclude_arg = 1;\n \t*(const char **)opt->value = arg;\n \treturn 0;\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 6a396a5090..02f6bd1279 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -338,6 +338,8 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n {\n \tstruct msg_arg *msg = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (!arg)\n \t\treturn -1;\n \tif (msg->buf.len)\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 07c10bcb7d..faa16c61f1 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -790,12 +790,16 @@ static int refresh(struct refresh_params *o, unsigned int flag)\n static int refresh_callback(const struct option *opt,\n \t\t\t\tconst char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \treturn refresh(opt->value, 0);\n }\n \n static int really_refresh_callback(const struct option *opt,\n \t\t\t\tconst char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \treturn refresh(opt->value, REFRESH_REALLY);\n }\n \n@@ -803,6 +807,7 @@ static int chmod_callback(const struct option *opt,\n \t\t\t\tconst char *arg, int unset)\n {\n \tchar *flip = opt->value;\n+\tBUG_ON_OPT_NEG(unset);\n \tif ((arg[0] != '-' && arg[0] != '+') || arg[1] != 'x' || arg[2])\n \t\treturn error(\"option 'chmod' expects \\\"+x\\\" or \\\"-x\\\"\");\n \t*flip = arg[0];\n@@ -812,6 +817,8 @@ static int chmod_callback(const struct option *opt,\n static int resolve_undo_clear_callback(const struct option *opt,\n \t\t\t\tconst char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n+\tBUG_ON_OPT_ARG(arg);\n \tresolve_undo_clear();\n \treturn 0;\n }\n@@ -847,6 +854,8 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,\n \tunsigned int mode;\n \tconst char *path;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {\n \t\tif (add_cacheinfo(mode, &oid, path, 0))\n \t\t\tdie(\"git update-index: --cacheinfo cannot add %s\", path);\n@@ -869,6 +878,8 @@ static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,\n {\n \tint *nul_term_line = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (ctx->argc != 1)\n \t\treturn error(\"option '%s' must be the last argument\", opt->long_name);\n \tallow_add = allow_replace = allow_remove = 1;\n@@ -881,6 +892,8 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx,\n {\n \tint *read_from_stdin = opt->value;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (ctx->argc != 1)\n \t\treturn error(\"option '%s' must be the last argument\", opt->long_name);\n \t*read_from_stdin = 1;\n@@ -888,11 +901,13 @@ static int stdin_callback(struct parse_opt_ctx_t *ctx,\n }\n \n static int unresolve_callback(struct parse_opt_ctx_t *ctx,\n-\t\t\t\tconst struct option *opt, int flags)\n+\t\t\t\tconst struct option *opt, int unset)\n {\n \tint *has_errors = opt->value;\n \tconst char *prefix = startup_info->prefix;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \t/* consume remaining arguments. */\n \t*has_errors = do_unresolve(ctx->argc, ctx->argv,\n \t\t\t\tprefix, prefix ? strlen(prefix) : 0);\n@@ -905,11 +920,13 @@ static int unresolve_callback(struct parse_opt_ctx_t *ctx,\n }\n \n static int reupdate_callback(struct parse_opt_ctx_t *ctx,\n-\t\t\t\tconst struct option *opt, int flags)\n+\t\t\t\tconst struct option *opt, int unset)\n {\n \tint *has_errors = opt->value;\n \tconst char *prefix = startup_info->prefix;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \t/* consume remaining arguments. */\n \tsetup_work_tree();\n \t*has_errors = do_reupdate(ctx->argc, ctx->argv,\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 6a61166b26..8c9edce52f 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -58,6 +58,8 @@ int parse_opt_verbosity_cb(const struct option *opt, const char *arg,\n {\n \tint *target = opt->value;\n \n+\tBUG_ON_OPT_ARG(arg);\n+\n \tif (unset)\n \t\t/* --no-quiet, --no-verbose */\n \t\t*target = 0;\n@@ -80,6 +82,8 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset)\n \tstruct object_id oid;\n \tstruct commit *commit;\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (!arg)\n \t\treturn -1;\n \tif (get_oid(arg, &oid))\n@@ -110,6 +114,9 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset)\n int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)\n {\n \tint *target = opt->value;\n+\n+\tBUG_ON_OPT_ARG(arg);\n+\n \t*target = unset ? 2 : 1;\n \treturn 0;\n }\ndiff --git a/parse-options.h b/parse-options.h\nindex c3f2d2eceb..6c4fe2016d 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -191,6 +191,20 @@ extern int opterror(const struct option *opt, const char *reason, int flags);\n #define opterror(o,r,f) (opterror((o),(r),(f)), const_error())\n #endif\n \n+/*\n+ * Use these assertions for callbacks that expect to be called with NONEG and\n+ * NOARG respectively, and do not otherwise handle the \"unset\" and \"arg\"\n+ * parameters.\n+ */\n+#define BUG_ON_OPT_NEG(unset) do { \\\n+\tif ((unset)) \\\n+\t\tBUG(\"option callback does not expect negation\"); \\\n+} while (0)\n+#define BUG_ON_OPT_ARG(arg) do { \\\n+\tif ((arg)) \\\n+\t\tBUG(\"option callback does not expect an argument\"); \\\n+} while (0)\n+\n /*----- incremental advanced APIs -----*/\n \n enum {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 0c45ed9d94..7eca436223 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -2316,6 +2316,8 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)\n \tstruct object_id oid;\n \tint no_merged = starts_with(opt->long_name, \"no\");\n \n+\tBUG_ON_OPT_NEG(unset);\n+\n \tif (rf->merge) {\n \t\tif (no_merged) {\n \t\t\treturn opterror(opt, \"is incompatible with --merged\", 0);\ndiff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c\nindex f0623bb42b..47fee660b8 100644\n--- a/t/helper/test-parse-options.c\n+++ b/t/helper/test-parse-options.c\n@@ -36,6 +36,7 @@ static int length_callback(const struct option *opt, const char *arg, int unset)\n \n static int number_callback(const struct option *opt, const char *arg, int unset)\n {\n+\tBUG_ON_OPT_NEG(unset);\n \t*(int *)opt->value = strtol(arg, NULL, 10);\n \treturn 0;\n }\n-- \n2.19.1.1505.g9cd28186cf\n"},{"id":"362473","messageId":"xmqqd0rkhui8.fsf@gitster-ct.c.googlers.com","threadId":"49759","inReplyTo":"20181105063819.GA25864@sigill.intra.peff.net","subject":"Re: [PATCH 01/13] apply: mark include/exclude options as NONEG","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-05T07:07:59Z","receivedAt":"2018-11-05T07:08:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> The options callback for \"git apply --no-include\" is not ready to handle\n> the \"unset\" parameter, and as a result will segfault when it adds a NULL\n> argument to the include list (likewise for \"--no-exclude\").\n>\n> In theory this might be used to clear the list, but since both\n> \"--include\" and \"--exclude\" add to the same list, it's not immediately\n> obvious what the semantics should be. Let's punt on that for now and\n> just disallow the broken options.\n\nThanks.  I agree with the conclusion to leave it to later outside\nthis series to define what --no-(include|exclude) should do.\n\nI suspect something along the lines of\n\n    Each element on the single list is marked as either include or\n    exclude, and \"--no-include\" would remove the accumulated\n    \"include\" entries in the list without touching any \"exclude\"\n    elements.\n\nwould be sufficiently clear and useful, perhaps.\n\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>  apply.c | 4 ++--\n>  1 file changed, 2 insertions(+), 2 deletions(-)\n>\n> diff --git a/apply.c b/apply.c\n> index 073d5f0451..d1ca6addeb 100644\n> --- a/apply.c\n> +++ b/apply.c\n> @@ -4939,10 +4939,10 @@ int apply_parse_options(int argc, const char **argv,\n>  \tstruct option builtin_apply_options[] = {\n>  \t\t{ OPTION_CALLBACK, 0, \"exclude\", state, N_(\"path\"),\n>  \t\t\tN_(\"don't apply changes matching the given path\"),\n> -\t\t\t0, apply_option_parse_exclude },\n> +\t\t\tPARSE_OPT_NONEG, apply_option_parse_exclude },\n>  \t\t{ OPTION_CALLBACK, 0, \"include\", state, N_(\"path\"),\n>  \t\t\tN_(\"apply changes matching the given path\"),\n> -\t\t\t0, apply_option_parse_include },\n> +\t\t\tPARSE_OPT_NONEG, apply_option_parse_include },\n>  \t\t{ OPTION_CALLBACK, 'p', NULL, state, N_(\"num\"),\n>  \t\t\tN_(\"remove <num> leading slashes from traditional diff paths\"),\n>  \t\t\t0, apply_option_parse_p },\n"},{"id":"362474","messageId":"xmqq8t28huhg.fsf@gitster-ct.c.googlers.com","threadId":"49759","inReplyTo":"20181105063839.GB25864@sigill.intra.peff.net","subject":"Re: [PATCH 02/13] am: handle --no-patch-format option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-05T07:08:27Z","receivedAt":"2018-11-05T07:08:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Running \"git am --no-patch-format\" will currently segfault, since it\n> tries to parse a NULL argument. Instead, let's have it cancel any\n> previous --patch-format option.\n\nMakes perfect sense.\n\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>  builtin/am.c | 4 +++-\n>  1 file changed, 3 insertions(+), 1 deletion(-)\n>\n> diff --git a/builtin/am.c b/builtin/am.c\n> index 3ee9a9d2a9..dcb880b699 100644\n> --- a/builtin/am.c\n> +++ b/builtin/am.c\n> @@ -2165,7 +2165,9 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int\n>  {\n>  \tint *opt_value = opt->value;\n>  \n> -\tif (!strcmp(arg, \"mbox\"))\n> +\tif (unset)\n> +\t\t*opt_value = PATCH_FORMAT_UNKNOWN;\n> +\telse if (!strcmp(arg, \"mbox\"))\n>  \t\t*opt_value = PATCH_FORMAT_MBOX;\n>  \telse if (!strcmp(arg, \"stgit\"))\n>  \t\t*opt_value = PATCH_FORMAT_STGIT;\n"},{"id":"362493","messageId":"CACsJy8Dz5Meu2fnNOiFXcw4LTROxBAn05OSZhYBih7ac0jQFzA@mail.gmail.com","threadId":"49759","inReplyTo":"20181105063718.GA24877@sigill.intra.peff.net","subject":"Re: [PATCH 0/13] parseopt fixes from -Wunused-parameters","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-11-05T16:51:07Z","receivedAt":"2018-11-05T16:51:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Nov 5, 2018 at 7:39 AM Jeff King <peff@peff.net> wrote:\n>\n> Continuing my exploration of what -Wunused-parameters can show us, here\n> are some bug-fixes related to parse-options callbacks.\n>\n> This is the last of the actual bug-fixes I've found. After this, I have\n> about 60 patches worth of cleanups (i.e., dropping the unused\n> parameters), and then I have a series to annotate parameters that must\n> be unused (e.g., for functions that must conform to callback\n> interfaces). After we can start compiling with -Wunused-parameters,\n> assuming we don't find the annotations too cumbersome.\n\nAnother good thing from this series is there are fewer --no-options to complete.\n\nAbout the annotating unused parameters related to segfault bug fixes\nin this series. Should we just add something like\n\n if (unset)\n    BUG(\"This code does not support --no-stuff\");\n\nwhich could be done in the same patches that fix the segfault, and it\nextends the diff context a bit to see what these callbacks do without\nopening up the editor, and also serves as a kind of annotation?\n-- \nDuy\n"},{"id":"362499","messageId":"20181105183402.9927-1-carenas@gmail.com","threadId":"49759","inReplyTo":"20181105064427.GL25864@sigill.intra.peff.net","subject":"[PATCH] parse-options: deprecate OPT_DATE","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2018-11-05T18:34:02Z","receivedAt":"2018-11-05T18:34:32Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/technical/api-parse-options.txt | 4 ----\n 1 file changed, 4 deletions(-)\n\ndiff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\nindex 829b558110..2b036d7838 100644\n--- a/Documentation/technical/api-parse-options.txt\n+++ b/Documentation/technical/api-parse-options.txt\n@@ -183,10 +183,6 @@ There are some macros to easily define options:\n \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n \tThe scaled value is put into `unsigned_long_var`.\n \n-`OPT_DATE(short, long, &timestamp_t_var, description)`::\n-\tIntroduce an option with date argument, see `approxidate()`.\n-\tThe timestamp is put into `timestamp_t_var`.\n-\n `OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n \tThe timestamp is put into `timestamp_t_var`.\n-- \n2.19.1.816.gcd69ec8cd\n\n"},{"id":"362500","messageId":"20181105184900.GA30690@sigill.intra.peff.net","threadId":"49759","inReplyTo":"CACsJy8Dz5Meu2fnNOiFXcw4LTROxBAn05OSZhYBih7ac0jQFzA@mail.gmail.com","subject":"Re: [PATCH 0/13] parseopt fixes from -Wunused-parameters","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T18:49:00Z","receivedAt":"2018-11-05T18:49:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 05, 2018 at 05:51:07PM +0100, Duy Nguyen wrote:\n\n> On Mon, Nov 5, 2018 at 7:39 AM Jeff King <peff@peff.net> wrote:\n> >\n> > Continuing my exploration of what -Wunused-parameters can show us, here\n> > are some bug-fixes related to parse-options callbacks.\n> >\n> > This is the last of the actual bug-fixes I've found. After this, I have\n> > about 60 patches worth of cleanups (i.e., dropping the unused\n> > parameters), and then I have a series to annotate parameters that must\n> > be unused (e.g., for functions that must conform to callback\n> > interfaces). After we can start compiling with -Wunused-parameters,\n> > assuming we don't find the annotations too cumbersome.\n> \n> Another good thing from this series is there are fewer --no-options to complete.\n> \n> About the annotating unused parameters related to segfault bug fixes\n> in this series. Should we just add something like\n> \n>  if (unset)\n>     BUG(\"This code does not support --no-stuff\");\n> \n> which could be done in the same patches that fix the segfault, and it\n> extends the diff context a bit to see what these callbacks do without\n> opening up the editor, and also serves as a kind of annotation?\n\nThat's done in the final patch. I did originally do it alongside the\nactual segfault fixes, but since it needs doing in so many other\ncallbacks, too, it made sense to me to do it all together.\n\n-Peff\n"},{"id":"362501","messageId":"20181105184921.GB30690@sigill.intra.peff.net","threadId":"49759","inReplyTo":"20181105183402.9927-1-carenas@gmail.com","subject":"Re: [PATCH] parse-options: deprecate OPT_DATE","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-05T18:49:21Z","receivedAt":"2018-11-05T18:49:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 05, 2018 at 10:34:02AM -0800, Carlo Marcelo Arenas Belón wrote:\n\n> Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n> ---\n>  Documentation/technical/api-parse-options.txt | 4 ----\n>  1 file changed, 4 deletions(-)\n> \n> diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt\n> index 829b558110..2b036d7838 100644\n> --- a/Documentation/technical/api-parse-options.txt\n> +++ b/Documentation/technical/api-parse-options.txt\n> @@ -183,10 +183,6 @@ There are some macros to easily define options:\n>  \tscale the provided value by 1024, 1024^2 or 1024^3 respectively.\n>  \tThe scaled value is put into `unsigned_long_var`.\n>  \n> -`OPT_DATE(short, long, &timestamp_t_var, description)`::\n> -\tIntroduce an option with date argument, see `approxidate()`.\n> -\tThe timestamp is put into `timestamp_t_var`.\n> -\n>  `OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::\n>  \tIntroduce an option with expiry date argument, see `parse_expiry_date()`.\n>  \tThe timestamp is put into `timestamp_t_var`.\n\nThank you! I forgot to check the documentation.\n\n-Peff\n"},{"id":"362502","messageId":"CACsJy8A3JTY8+3s4nWYGU6Y=Gq5QEUk1ZCLpbrmr8oV1c0jO4g@mail.gmail.com","threadId":"49759","inReplyTo":"20181105184900.GA30690@sigill.intra.peff.net","subject":"Re: [PATCH 0/13] parseopt fixes from -Wunused-parameters","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-11-05T18:51:32Z","receivedAt":"2018-11-05T18:52:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Nov 5, 2018 at 7:49 PM Jeff King <peff@peff.net> wrote:\n>\n> On Mon, Nov 05, 2018 at 05:51:07PM +0100, Duy Nguyen wrote:\n>\n> > On Mon, Nov 5, 2018 at 7:39 AM Jeff King <peff@peff.net> wrote:\n> > >\n> > > Continuing my exploration of what -Wunused-parameters can show us, here\n> > > are some bug-fixes related to parse-options callbacks.\n> > >\n> > > This is the last of the actual bug-fixes I've found. After this, I have\n> > > about 60 patches worth of cleanups (i.e., dropping the unused\n> > > parameters), and then I have a series to annotate parameters that must\n> > > be unused (e.g., for functions that must conform to callback\n> > > interfaces). After we can start compiling with -Wunused-parameters,\n> > > assuming we don't find the annotations too cumbersome.\n> >\n> > Another good thing from this series is there are fewer --no-options to complete.\n> >\n> > About the annotating unused parameters related to segfault bug fixes\n> > in this series. Should we just add something like\n> >\n> >  if (unset)\n> >     BUG(\"This code does not support --no-stuff\");\n> >\n> > which could be done in the same patches that fix the segfault, and it\n> > extends the diff context a bit to see what these callbacks do without\n> > opening up the editor, and also serves as a kind of annotation?\n>\n> That's done in the final patch. I did originally do it alongside the\n> actual segfault fixes, but since it needs doing in so many other\n> callbacks, too, it made sense to me to do it all together.\n\nOops. I guess I stopped reading the series too early. Sorry for the noise.\n-- \nDuy\n"}]}