[PATCH 3/5] gitopt: convert setup_revisions() and friends

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



	diff_opt_parse => diff_opt_handle

I've added --raw to diff_opt_handle() for consistency's sake

Lightly tested, some bugs in the original series of submitted
patches were fixed wrt argument parsing for -C,-M,-B).

Passes all tests so that's a good sign.

Signed-off-by: Eric Wong <normalperson@xxxxxxxx>

---

 builtin-diff.c      |  152 +++++++-------
 builtin-log.c       |    7 -
 commit.c            |   14 +
 diff-files.c        |   25 +-
 diff-index.c        |   18 +-
 diff-stages.c       |   56 +++--
 diff-tree.c         |   15 +
 diff.c              |  183 ++++++++++++-----
 diff.h              |    7 -
 gitopt/diff-files.h |   45 ++++
 gitopt/diff-index.h |   22 ++
 gitopt/diff-tree.h  |   22 ++
 gitopt/diff.h       |   19 ++
 http-push.c         |    2 
 rev-list.c          |   51 +++--
 revision.c          |  542 +++++++++++++++++++++++++++------------------------
 revision.h          |    4 
 17 files changed, 704 insertions(+), 480 deletions(-)
 create mode 100644 gitopt/diff-files.h
 create mode 100644 gitopt/diff-index.h
 create mode 100644 gitopt/diff-tree.h
 create mode 100644 gitopt/diff.h

946397f743f363198d154efaa74d5cc5bd9d6aae
diff --git a/builtin-diff.c b/builtin-diff.c
index d3ac581..3aefd3c 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -12,6 +12,9 @@ #include "diffcore.h"
 #include "revision.h"
 #include "log-tree.h"
 #include "builtin.h"
+#include "gitopt/diff-index.h"
+#include "gitopt/diff-files.h"
+#include "gitopt/diff-tree.h"
 
 /* NEEDSWORK: struct object has place for name but we _do_
  * know mode when we extracted the blob out of a tree, which
@@ -25,26 +28,25 @@ struct blobinfo {
 static const char builtin_diff_usage[] =
 "diff <options> <rev>{0,2} -- <path>*";
 
+static int extra_diff_flags[LAST_DIFF_EXTRA_ID] = { 0 };
+
 static int builtin_diff_files(struct rev_info *revs,
 			      int argc, const char **argv)
 {
-	int silent = 0;
-	while (1 < argc) {
-		const char *arg = argv[1];
-		if (!strcmp(arg, "--base"))
-			revs->max_count = 1;
-		else if (!strcmp(arg, "--ours"))
-			revs->max_count = 2;
-		else if (!strcmp(arg, "--theirs"))
-			revs->max_count = 3;
-		else if (!strcmp(arg, "-q"))
-			silent = 1;
-		else if (!strcmp(arg, "--raw"))
-			revs->diffopt.output_format = DIFF_FORMAT_RAW;
-		else
+	int i;
+	struct df_extra_opts dfeo = { revs, 0 };
+
+	if (argc)
+		usage(builtin_diff_usage);
+
+	for (i = 1; i < ARRAY_SIZE(extra_diff_flags); i++) {
+		if (extra_diff_flags[i]) {
+			if (diff_files_opt_handler(NULL, i, &dfeo) > 0)
+				continue;
 			usage(builtin_diff_usage);
-		argv++; argc--;
+		}
 	}
+
 	/*
 	 * Make sure there are NO revision (i.e. pending object) parameter,
 	 * specified rev.max_count is reasonable (0 <= n <= 3), and
@@ -65,7 +67,7 @@ static int builtin_diff_files(struct rev
 	 */
 	if (revs->diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
 		revs->diffopt.output_format = DIFF_FORMAT_RAW;
-	return run_diff_files(revs, silent);
+	return run_diff_files(revs, dfeo.silent);
 }
 
 static void stuff_change(struct diff_options *opt,
@@ -107,14 +109,9 @@ static int builtin_diff_b_f(struct rev_i
 	/* Blob vs file in the working tree*/
 	struct stat st;
 
-	while (1 < argc) {
-		const char *arg = argv[1];
-		if (!strcmp(arg, "--raw"))
-			revs->diffopt.output_format = DIFF_FORMAT_RAW;
-		else
-			usage(builtin_diff_usage);
-		argv++; argc--;
-	}
+	if (argc)
+		usage(builtin_diff_usage);
+
 	if (lstat(path, &st))
 		die("'%s': %s", path, strerror(errno));
 	if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
@@ -135,14 +132,9 @@ static int builtin_diff_blobs(struct rev
 	/* Blobs */
 	unsigned mode = canon_mode(S_IFREG | 0644);
 
-	while (1 < argc) {
-		const char *arg = argv[1];
-		if (!strcmp(arg, "--raw"))
-			revs->diffopt.output_format = DIFF_FORMAT_RAW;
-		else
-			usage(builtin_diff_usage);
-		argv++; argc--;
-	}
+	if (argc)
+		usage(builtin_diff_usage);
+
 	stuff_change(&revs->diffopt,
 		     mode, mode,
 		     blob[0].sha1, blob[1].sha1,
@@ -155,17 +147,19 @@ static int builtin_diff_blobs(struct rev
 static int builtin_diff_index(struct rev_info *revs,
 			      int argc, const char **argv)
 {
-	int cached = 0;
-	while (1 < argc) {
-		const char *arg = argv[1];
-		if (!strcmp(arg, "--cached"))
-			cached = 1;
-		else if (!strcmp(arg, "--raw"))
-			revs->diffopt.output_format = DIFF_FORMAT_RAW;
-		else
+	int i, cached = 0;
+
+	if (argc)
+		usage(builtin_diff_usage);
+
+	for (i = 1; i < ARRAY_SIZE(extra_diff_flags); i++) {
+		if (extra_diff_flags[i]) {
+			if (diff_index_opt_handler(NULL, i, &cached) > 0)
+				continue;
 			usage(builtin_diff_usage);
-		argv++; argc--;
+		}
 	}
+
 	/*
 	 * Make sure there is one revision (i.e. pending object),
 	 * and there is no revision filtering parameters.
@@ -183,14 +177,9 @@ static int builtin_diff_tree(struct rev_
 {
 	const unsigned char *(sha1[2]);
 	int swap = 1;
-	while (1 < argc) {
-		const char *arg = argv[1];
-		if (!strcmp(arg, "--raw"))
-			revs->diffopt.output_format = DIFF_FORMAT_RAW;
-		else
-			usage(builtin_diff_usage);
-		argv++; argc--;
-	}
+
+	if (argc)
+		usage(builtin_diff_usage);
 
 	/* We saw two trees, ent[0] and ent[1].
 	 * unless ent[0] is unintesting, they are swapped
@@ -212,14 +201,9 @@ static int builtin_diff_combined(struct 
 	const unsigned char (*parent)[20];
 	int i;
 
-	while (1 < argc) {
-		const char *arg = argv[1];
-		if (!strcmp(arg, "--raw"))
-			revs->diffopt.output_format = DIFF_FORMAT_RAW;
-		else
-			usage(builtin_diff_usage);
-		argv++; argc--;
-	}
+	if (argc)
+		usage(builtin_diff_usage);
+
 	if (!revs->dense_combined_merges && !revs->combine_merges)
 		revs->dense_combined_merges = revs->combine_merges = 1;
 	parent = xmalloc(ents * sizeof(*parent));
@@ -243,6 +227,27 @@ static void add_head(struct rev_info *re
 	add_object(obj, &revs->pending_objects, NULL, "HEAD");
 }
 
+static struct opt_spec * diff_combined_ost()
+{
+	struct opt_spec *rv, *tmp;
+
+	tmp = combine_opt_spec(diff_files_ost, diff_tree_ost);
+	rv = combine_opt_spec(tmp, diff_index_ost);
+	free(tmp);
+	return rv;
+}
+
+/* just set flags in here for use by the builtin_diff_* functions  */
+static int diff_combined_handler(struct gitopt_iterator *gi,
+				const int id, void *args)
+{
+	if (id > 0 && id < LAST_DIFF_EXTRA_ID) {
+		extra_diff_flags[id] = 1;
+		return 1;
+	}
+	return 0;
+}
+
 int cmd_diff(int argc, const char **argv, char **envp)
 {
 	struct rev_info rev;
@@ -250,6 +255,9 @@ int cmd_diff(int argc, const char **argv
 	int ents = 0, blobs = 0, paths = 0;
 	const char *path = NULL;
 	struct blobinfo blob[2];
+	struct exec_args *b;
+	struct opt_spec *ost = diff_combined_ost();
+	struct gitopt_extra ge = { ost, diff_combined_handler, NULL };
 
 	/*
 	 * We could get N tree-ish in the rev.pending_objects list.
@@ -275,22 +283,14 @@ int cmd_diff(int argc, const char **argv
 	init_revisions(&rev);
 	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
 
-	argc = setup_revisions(argc, argv, &rev, NULL);
+	b = setup_revisions(argc, argv, &rev, NULL, &ge);
+	free(ost);
+
 	/* Do we have --cached and not have a pending object, then
 	 * default to HEAD by hand.  Eek.
 	 */
-	if (!rev.pending_objects) {
-		int i;
-		for (i = 1; i < argc; i++) {
-			const char *arg = argv[i];
-			if (!strcmp(arg, "--"))
-				break;
-			else if (!strcmp(arg, "--cached")) {
-				add_head(&rev);
-				break;
-			}
-		}
-	}
+	if (!rev.pending_objects && extra_diff_flags[opt_cached])
+		add_head(&rev);
 
 	for (list = rev.pending_objects; list; list = list->next) {
 		struct object *obj = list->item;
@@ -340,17 +340,17 @@ int cmd_diff(int argc, const char **argv
 	if (!ents) {
 		switch (blobs) {
 		case 0:
-			return builtin_diff_files(&rev, argc, argv);
+			return builtin_diff_files(&rev, b->argc, b->argv);
 			break;
 		case 1:
 			if (paths != 1)
 				usage(builtin_diff_usage);
-			return builtin_diff_b_f(&rev, argc, argv, blob, path);
+			return builtin_diff_b_f(&rev, b->argc, b->argv, blob, path);
 			break;
 		case 2:
 			if (paths)
 				usage(builtin_diff_usage);
-			return builtin_diff_blobs(&rev, argc, argv, blob);
+			return builtin_diff_blobs(&rev, b->argc, b->argv, blob);
 			break;
 		default:
 			usage(builtin_diff_usage);
@@ -359,10 +359,10 @@ int cmd_diff(int argc, const char **argv
 	else if (blobs)
 		usage(builtin_diff_usage);
 	else if (ents == 1)
-		return builtin_diff_index(&rev, argc, argv);
+		return builtin_diff_index(&rev, b->argc, b->argv);
 	else if (ents == 2)
-		return builtin_diff_tree(&rev, argc, argv, ent);
+		return builtin_diff_tree(&rev, b->argc, b->argv, ent);
 	else
-		return builtin_diff_combined(&rev, argc, argv, ent, ents);
+		return builtin_diff_combined(&rev, b->argc, b->argv, ent, ents);
 	usage(builtin_diff_usage);
 }
diff --git a/builtin-log.c b/builtin-log.c
index 69f2911..3cfc8ac 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -14,14 +14,15 @@ static int cmd_log_wc(int argc, const ch
 		      struct rev_info *rev)
 {
 	struct commit *commit;
+	struct exec_args *b;
 
 	rev->abbrev = DEFAULT_ABBREV;
 	rev->commit_format = CMIT_FMT_DEFAULT;
 	rev->verbose_header = 1;
-	argc = setup_revisions(argc, argv, rev, "HEAD");
+	b = setup_revisions(argc, argv, rev, "HEAD", NULL);
 
-	if (argc > 1)
-		die("unrecognized argument: %s", argv[1]);
+	if (b->argc > 1)
+		die("unrecognized argument: %s", b->argv[0]);
 
 	prepare_revision_walk(rev);
 	setup_pager();
diff --git a/commit.c b/commit.c
index 2717dd8..2343729 100644
--- a/commit.c
+++ b/commit.c
@@ -24,19 +24,19 @@ const char *commit_type = "commit";
 
 enum cmit_fmt get_commit_format(const char *arg)
 {
-	if (!*arg)
+	if (!arg)
 		return CMIT_FMT_DEFAULT;
-	if (!strcmp(arg, "=raw"))
+	if (!strcmp(arg, "raw"))
 		return CMIT_FMT_RAW;
-	if (!strcmp(arg, "=medium"))
+	if (!strcmp(arg, "medium"))
 		return CMIT_FMT_MEDIUM;
-	if (!strcmp(arg, "=short"))
+	if (!strcmp(arg, "short"))
 		return CMIT_FMT_SHORT;
-	if (!strcmp(arg, "=full"))
+	if (!strcmp(arg, "full"))
 		return CMIT_FMT_FULL;
-	if (!strcmp(arg, "=fuller"))
+	if (!strcmp(arg, "fuller"))
 		return CMIT_FMT_FULLER;
-	if (!strcmp(arg, "=oneline"))
+	if (!strcmp(arg, "oneline"))
 		return CMIT_FMT_ONELINE;
 	die("invalid --pretty format");
 }
diff --git a/diff-files.c b/diff-files.c
index b9d193d..431487b 100644
--- a/diff-files.c
+++ b/diff-files.c
@@ -7,6 +7,7 @@ #include "cache.h"
 #include "diff.h"
 #include "commit.h"
 #include "revision.h"
+#include "gitopt/diff-files.h"
 
 static const char diff_files_usage[] =
 "git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
@@ -15,26 +16,18 @@ COMMON_DIFF_OPTIONS_HELP;
 int main(int argc, const char **argv)
 {
 	struct rev_info rev;
-	int silent = 0;
+	struct exec_args *b;
+	struct df_extra_opts dfeo = { &rev, 0 };
+	struct gitopt_extra ge = { diff_files_ost, diff_files_opt_handler,
+				   &dfeo };
 
 	git_config(git_diff_config);
 	init_revisions(&rev);
 	rev.abbrev = 0;
 
-	argc = setup_revisions(argc, argv, &rev, NULL);
-	while (1 < argc && argv[1][0] == '-') {
-		if (!strcmp(argv[1], "--base"))
-			rev.max_count = 1;
-		else if (!strcmp(argv[1], "--ours"))
-			rev.max_count = 2;
-		else if (!strcmp(argv[1], "--theirs"))
-			rev.max_count = 3;
-		else if (!strcmp(argv[1], "-q"))
-			silent = 1;
-		else
-			usage(diff_files_usage);
-		argv++; argc--;
-	}
+	b = setup_revisions(argc, argv, &rev, NULL, &ge);
+	if (b->argc)
+		usage(diff_files_usage);
 	/*
 	 * Make sure there are NO revision (i.e. pending object) parameter,
 	 * rev.max_count is reasonable (0 <= n <= 3),
@@ -50,5 +43,5 @@ int main(int argc, const char **argv)
 	 */
 	if (rev.diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
 		rev.diffopt.output_format = DIFF_FORMAT_RAW;
-	return run_diff_files(&rev, silent);
+	return run_diff_files(&rev, dfeo.silent);
 }
diff --git a/diff-index.c b/diff-index.c
index 8c9f601..987a00a 100644
--- a/diff-index.c
+++ b/diff-index.c
@@ -2,6 +2,7 @@ #include "cache.h"
 #include "diff.h"
 #include "commit.h"
 #include "revision.h"
+#include "gitopt/diff-index.h"
 
 static const char diff_cache_usage[] =
 "git-diff-index [-m] [--cached] "
@@ -12,21 +13,18 @@ int main(int argc, const char **argv)
 {
 	struct rev_info rev;
 	int cached = 0;
-	int i;
+	struct exec_args *b;
+	struct gitopt_extra ge = { diff_index_ost,
+				diff_index_opt_handler, &cached };
 
 	git_config(git_diff_config);
 	init_revisions(&rev);
 	rev.abbrev = 0;
 
-	argc = setup_revisions(argc, argv, &rev, NULL);
-	for (i = 1; i < argc; i++) {
-		const char *arg = argv[i];
-			
-		if (!strcmp(arg, "--cached"))
-			cached = 1;
-		else
-			usage(diff_cache_usage);
-	}
+	b = setup_revisions(argc, argv, &rev, NULL, &ge);
+	if (b->argc)
+		usage(diff_cache_usage);
+
 	/*
 	 * Make sure there is one revision (i.e. pending object),
 	 * and there is no revision filtering parameters.
diff --git a/diff-stages.c b/diff-stages.c
index dcd20e7..05129c5 100644
--- a/diff-stages.c
+++ b/diff-stages.c
@@ -4,6 +4,13 @@
 
 #include "cache.h"
 #include "diff.h"
+#include "gitopt.h"
+
+enum diff_stages_ost { opt_r = 1 };
+static const struct opt_spec diff_stages_ost[] = {
+	{ 0,	'r',	0,	0,	opt_r },
+	{ 0, 0 }
+};
 
 static struct diff_options diff_options;
 
@@ -59,40 +66,47 @@ int main(int ac, const char **av)
 	int stage1, stage2;
 	const char *prefix = setup_git_directory();
 	const char **pathspec = NULL;
+	struct exec_args *b;
+	struct opt_spec *ost;
+	struct gitopt_iterator gi;
+	int i;
 
 	git_config(git_diff_config);
 	read_cache();
 	diff_setup(&diff_options);
-	while (1 < ac && av[1][0] == '-') {
-		const char *arg = av[1];
-		if (!strcmp(arg, "-r"))
-			; /* as usual */
-		else {
-			int diff_opt_cnt;
-			diff_opt_cnt = diff_opt_parse(&diff_options,
-						      av+1, ac-1);
-			if (diff_opt_cnt < 0)
-				usage(diff_stages_usage);
-			else if (diff_opt_cnt) {
-				av += diff_opt_cnt;
-				ac -= diff_opt_cnt;
-				continue;
-			}
+
+	ost = combine_opt_spec(diff_ost, diff_stages_ost);
+	gitopt_iter_setup(&gi, ac, av);
+
+	for (b=gi.b; (i=gitopt_iter_parse(&gi, ost)); gitopt_iter_next(&gi)) {
+		switch (i) {
+		case GITOPT_NON_OPTION:
+			b->argv[b->argc++] = gi.argv[gi.pos];
+		case GITOPT_DD:
+		case opt_r: /* as usual */
+			break;
+		case GITOPT_ERROR:
+			usage(diff_stages_usage);
+		default:
+			i = diff_opt_handler(&gi, i, &diff_options);
+			if (i > 0)
+				gi.pos += i - 1;
 			else
 				usage(diff_stages_usage);
 		}
-		ac--; av++;
 	}
+	gitopt_iter_done(&gi);
+	free(ost);
 
-	if (ac < 3 ||
-	    sscanf(av[1], "%d", &stage1) != 1 ||
+	if (b->argc < 2 ||
+	    sscanf(b->argv[0], "%d", &stage1) != 1 ||
 	    ! (0 <= stage1 && stage1 <= 3) ||
-	    sscanf(av[2], "%d", &stage2) != 1 ||
+	    sscanf(b->argv[1], "%d", &stage2) != 1 ||
 	    ! (0 <= stage2 && stage2 <= 3))
 		usage(diff_stages_usage);
 
-	av += 3; /* The rest from av[0] are for paths restriction. */
-	pathspec = get_pathspec(prefix, av);
+	b->argv += 2; /* The rest from b->argv[0] are for paths restriction. */
+	pathspec = get_pathspec(prefix, b->argv);
 
 	if (diff_setup_done(&diff_options) < 0)
 		usage(diff_stages_usage);
diff --git a/diff-tree.c b/diff-tree.c
index 7207867..b5c6072 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -2,6 +2,7 @@ #include "cache.h"
 #include "diff.h"
 #include "commit.h"
 #include "log-tree.h"
+#include "gitopt/diff-tree.h"
 
 static struct rev_info log_tree_opt;
 
@@ -66,23 +67,19 @@ int main(int argc, const char **argv)
 	static struct rev_info *opt = &log_tree_opt;
 	struct object_list *list;
 	int read_stdin = 0;
+	struct exec_args *b;
+	struct gitopt_extra ge = { diff_tree_ost, diff_tree_opt_handler,
+				&read_stdin };
 
 	git_config(git_diff_config);
 	nr_sha1 = 0;
 	init_revisions(opt);
 	opt->abbrev = 0;
 	opt->diff = 1;
-	argc = setup_revisions(argc, argv, opt, NULL);
+	b = setup_revisions(argc, argv, opt, NULL, &ge);
 
-	while (--argc > 0) {
-		const char *arg = *++argv;
-
-		if (!strcmp(arg, "--stdin")) {
-			read_stdin = 1;
-			continue;
-		}
+	if (b->argc)
 		usage(diff_tree_usage);
-	}
 
 	/*
 	 * NOTE! "setup_revisions()" will have inserted the revisions
diff --git a/diff.c b/diff.c
index 7a7b839..7d88dc5 100644
--- a/diff.c
+++ b/diff.c
@@ -10,6 +10,48 @@ #include "diff.h"
 #include "diffcore.h"
 #include "delta.h"
 #include "xdiff-interface.h"
+#include "gitopt.h"
+
+static int diff_scoreopt_parse(const int id, const char *opt);
+
+enum diff_ost_ids {
+	opt_p = GITOPT_DIFF_BASE, opt_raw, opt_patch_with_raw,
+	opt_stat, opt_patch_with_stat,
+	opt_z, opt_l, opt_full_index, opt_name_only, opt_name_status,
+	opt_R, opt_S, opt_s, opt_O, opt_diff_filter,
+	opt_pickaxe_all, opt_pickaxe_regex,
+	opt_B, opt_M, opt_C, opt_find_copies_harder, opt_abbrev,
+	opt_binary
+};
+
+const struct opt_spec diff_ost[] = {
+	{ 0,			'p',	0,	0,	opt_p },
+	{ "unified",		'u',	0,	0,	opt_p },
+	{ "raw",		0,	0,	0,	opt_raw },
+	{ "patch-with-raw",	0,	0,	0,	opt_patch_with_raw },
+	{ "stat",		0,	0,	0,	opt_stat },
+	{ "patch-with-stat",	0,	0,	0,	opt_patch_with_stat },
+	{ 0,			'z',	0,	0,	opt_z },
+	{ 0,			'l',	0,	ARG_INT,	opt_l },
+	{ "full-index",		0,	0,	0,	opt_full_index },
+	{ "name-only",		0,	0,	0,	opt_name_only },
+	{ "name-status",	0,	0,	0,	opt_name_status },
+	{ 0,			'R',	0,	0,	opt_R },
+	{ 0,			'S',	0,	ARG_ONE,	opt_S },
+	{ 0,			's',	0,	0,	opt_s },
+	{ 0,			'O',	0,	ARG_ONE, opt_O },
+	{ "diff-filter",	0,	0,	ARG_ONE, opt_diff_filter },
+	{ "pickaxe-all",	0,	0,	0,	opt_pickaxe_all },
+	{ "pickaxe-regex",	0,	0,	0,	opt_pickaxe_regex },
+	{ 0,			'B',	0,	ARG_OPT,	opt_B },
+	{ 0,			'M',	0,	ARG_OPT,	opt_M },
+	{ 0,			'C',	0,	ARG_OPT,	opt_C },
+	{ "find-copies-harder",	0,	0,	0,	opt_find_copies_harder},
+	{ "abbrev",		0,	0,	ARG_OPTINT, opt_abbrev },
+	{ "binary",		0,	0,	0,	opt_binary },
+	{ 0, 0 }
+};
+
 
 static int use_size_cache;
 
@@ -1222,79 +1264,102 @@ int diff_setup_done(struct diff_options 
 	return 0;
 }
 
-int diff_opt_parse(struct diff_options *options, const char **av, int ac)
+int diff_opt_handler(struct gitopt_iterator *gi, const int id, void *args)
 {
-	const char *arg = av[0];
-	if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
+	struct diff_options *options = (struct diff_options *)args;
+
+	switch (id) {
+	case opt_p:
 		options->output_format = DIFF_FORMAT_PATCH;
-	else if (!strcmp(arg, "--patch-with-raw")) {
+		break;
+	case opt_raw:
+		options->output_format = DIFF_FORMAT_RAW;
+		break;
+	case opt_patch_with_raw:
 		options->output_format = DIFF_FORMAT_PATCH;
 		options->with_raw = 1;
-	}
-	else if (!strcmp(arg, "--stat"))
+		break;
+	case opt_stat:
 		options->output_format = DIFF_FORMAT_DIFFSTAT;
-	else if (!strcmp(arg, "--patch-with-stat")) {
+		break;
+	case opt_patch_with_stat:
 		options->output_format = DIFF_FORMAT_PATCH;
 		options->with_stat = 1;
-	}
-	else if (!strcmp(arg, "-z"))
+		break;
+	case opt_z:
 		options->line_termination = 0;
-	else if (!strncmp(arg, "-l", 2))
-		options->rename_limit = strtoul(arg+2, NULL, 10);
-	else if (!strcmp(arg, "--full-index"))
+		break;
+	case opt_l:
+		options->rename_limit = strtoul(gi->ea->argv[0], NULL, 10);
+		break;
+	case opt_full_index:
 		options->full_index = 1;
-	else if (!strcmp(arg, "--binary")) {
+		break;
+	case opt_binary:
 		options->output_format = DIFF_FORMAT_PATCH;
 		options->full_index = options->binary = 1;
-	}
-	else if (!strcmp(arg, "--name-only"))
+		break;
+	case opt_name_only:
 		options->output_format = DIFF_FORMAT_NAME;
-	else if (!strcmp(arg, "--name-status"))
+		break;
+	case opt_name_status:
 		options->output_format = DIFF_FORMAT_NAME_STATUS;
-	else if (!strcmp(arg, "-R"))
+		break;
+	case opt_R:
 		options->reverse_diff = 1;
-	else if (!strncmp(arg, "-S", 2))
-		options->pickaxe = arg + 2;
-	else if (!strcmp(arg, "-s"))
+		break;
+	case opt_S:
+		options->pickaxe = gi->ea->argv[0];
+		break;
+	case opt_s:
 		options->output_format = DIFF_FORMAT_NO_OUTPUT;
-	else if (!strncmp(arg, "-O", 2))
-		options->orderfile = arg + 2;
-	else if (!strncmp(arg, "--diff-filter=", 14))
-		options->filter = arg + 14;
-	else if (!strcmp(arg, "--pickaxe-all"))
+		break;
+	case opt_O:
+		options->orderfile = gi->ea->argv[0];
+		break;
+	case opt_diff_filter:
+		options->filter = gi->ea->argv[0];
+		break;
+	case opt_pickaxe_all:
 		options->pickaxe_opts = DIFF_PICKAXE_ALL;
-	else if (!strcmp(arg, "--pickaxe-regex"))
+		break;
+	case opt_pickaxe_regex:
 		options->pickaxe_opts = DIFF_PICKAXE_REGEX;
-	else if (!strncmp(arg, "-B", 2)) {
-		if ((options->break_opt =
-		     diff_scoreopt_parse(arg)) == -1)
+		break;
+	case opt_B:
+		if (gi->ea->argc && (options->break_opt =
+		     diff_scoreopt_parse(id, gi->ea->argv[1])) == -1)
 			return -1;
-	}
-	else if (!strncmp(arg, "-M", 2)) {
-		if ((options->rename_score =
-		     diff_scoreopt_parse(arg)) == -1)
+		break;
+	case opt_M:
+		if (gi->ea->argc && (options->rename_score =
+		     diff_scoreopt_parse(id, gi->ea->argv[1])) == -1)
 			return -1;
 		options->detect_rename = DIFF_DETECT_RENAME;
-	}
-	else if (!strncmp(arg, "-C", 2)) {
-		if ((options->rename_score =
-		     diff_scoreopt_parse(arg)) == -1)
+		break;
+	case opt_C:
+		if (gi->ea->argc && (options->rename_score =
+		     diff_scoreopt_parse(id, gi->ea->argv[1])) == -1)
 			return -1;
 		options->detect_rename = DIFF_DETECT_COPY;
-	}
-	else if (!strcmp(arg, "--find-copies-harder"))
+		break;
+	case opt_find_copies_harder:
 		options->find_copies_harder = 1;
-	else if (!strcmp(arg, "--abbrev"))
-		options->abbrev = DEFAULT_ABBREV;
-	else if (!strncmp(arg, "--abbrev=", 9)) {
-		options->abbrev = strtoul(arg + 9, NULL, 10);
-		if (options->abbrev < MINIMUM_ABBREV)
-			options->abbrev = MINIMUM_ABBREV;
-		else if (40 < options->abbrev)
-			options->abbrev = 40;
-	}
-	else
+		break;
+	case opt_abbrev:
+		if (gi->ea->argc == 1)
+			options->abbrev = DEFAULT_ABBREV;
+		else {
+			options->abbrev = strtoul(gi->ea->argv[1], NULL, 10);
+			if (options->abbrev < MINIMUM_ABBREV)
+				options->abbrev = MINIMUM_ABBREV;
+			else if (40 < options->abbrev)
+				options->abbrev = 40;
+		}
+		break;
+	default:
 		return 0;
+	}
 	return 1;
 }
 
@@ -1304,9 +1369,13 @@ static int parse_num(const char **cp_p)
 	int ch, dot;
 	const char *cp = *cp_p;
 
+	if (!cp)
+		return 0;
+
 	num = 0;
 	scale = 1;
 	dot = 0;
+
 	for(;;) {
 		ch = *cp;
 		if ( !dot && ch == '.' ) {
@@ -1334,21 +1403,15 @@ static int parse_num(const char **cp_p)
 	return (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);
 }
 
-int diff_scoreopt_parse(const char *opt)
+static int diff_scoreopt_parse(const int id, const char *opt)
 {
-	int opt1, opt2, cmd;
-
-	if (*opt++ != '-')
-		return -1;
-	cmd = *opt++;
-	if (cmd != 'M' && cmd != 'C' && cmd != 'B')
-		return -1; /* that is not a -M, -C nor -B option */
+	int opt1, opt2;
 
 	opt1 = parse_num(&opt);
-	if (cmd != 'B')
+	if (id != opt_B)
 		opt2 = 0;
 	else {
-		if (*opt == 0)
+		if (!opt || *opt == 0)
 			opt2 = 0;
 		else if (*opt != '/')
 			return -1; /* we expect -B80/99 or -B80 */
@@ -1357,7 +1420,7 @@ int diff_scoreopt_parse(const char *opt)
 			opt2 = parse_num(&opt);
 		}
 	}
-	if (*opt != 0)
+	if (opt && *opt != 0)
 		return -1;
 	return opt1 | (opt2 << 16);
 }
diff --git a/diff.h b/diff.h
index d052608..fa44d1b 100644
--- a/diff.h
+++ b/diff.h
@@ -5,6 +5,7 @@ #ifndef DIFF_H
 #define DIFF_H
 
 #include "tree-walk.h"
+#include "gitopt.h"
 
 struct rev_info;
 struct diff_options;
@@ -96,15 +97,13 @@ extern void diff_change(struct diff_opti
 extern void diff_unmerge(struct diff_options *,
 			 const char *path);
 
-extern int diff_scoreopt_parse(const char *opt);
-
 #define DIFF_SETUP_REVERSE      	1
 #define DIFF_SETUP_USE_CACHE		2
 #define DIFF_SETUP_USE_SIZE_CACHE	4
 
 extern int git_diff_config(const char *var, const char *value);
 extern void diff_setup(struct diff_options *);
-extern int diff_opt_parse(struct diff_options *, const char **, int);
+extern int diff_opt_handler(struct gitopt_iterator *, const int, void *);
 extern int diff_setup_done(struct diff_options *);
 
 #define DIFF_DETECT_RENAME	1
@@ -117,6 +116,8 @@ extern void diffcore_std(struct diff_opt
 
 extern void diffcore_std_no_resolve(struct diff_options *);
 
+extern const struct opt_spec diff_ost[];
+
 #define COMMON_DIFF_OPTIONS_HELP \
 "\ncommon diff options:\n" \
 "  -z            output diff-raw with lines terminated with NUL.\n" \
diff --git a/gitopt/diff-files.h b/gitopt/diff-files.h
new file mode 100644
index 0000000..85c84ba
--- /dev/null
+++ b/gitopt/diff-files.h
@@ -0,0 +1,45 @@
+#ifndef GITOPT_DIFF_FILES_H
+#define GITOPT_DIFF_FILES_H
+
+#include "../gitopt/diff.h"
+#include "../revision.h"
+
+struct df_extra_opts {
+	struct rev_info *rev;
+	int silent;
+};
+
+static const struct opt_spec diff_files_ost[] = {
+	{ "base",	0,	0,	0,	opt_base },
+	{ "ours",	0,	0,	0,	opt_ours },
+	{ "theirs",	0,	0,	0,	opt_theirs },
+	{ 0,		'q',	0,	0,	opt_q },
+	{ 0, 0 }
+};
+
+static int diff_files_opt_handler(struct gitopt_iterator *gi,
+				const int id, void *args)
+{
+	int rv = 1;
+	struct df_extra_opts *dfeo = (struct df_extra_opts *)args;
+
+	switch (id) {
+	case opt_base:
+		dfeo->rev->max_count = 1;
+		break;
+	case opt_ours:
+		dfeo->rev->max_count = 2;
+		break;
+	case opt_theirs:
+		dfeo->rev->max_count = 3;
+		break;
+	case opt_q:
+		dfeo->silent = 1;
+		break;
+	default:
+		rv = 0;
+	}
+	return rv;
+}
+
+#endif
diff --git a/gitopt/diff-index.h b/gitopt/diff-index.h
new file mode 100644
index 0000000..aff0944
--- /dev/null
+++ b/gitopt/diff-index.h
@@ -0,0 +1,22 @@
+#ifndef GITOPT_DIFF_INDEX_H
+#define GITOPT_DIFF_INDEX_H
+
+#include "../gitopt/diff.h"
+
+static const struct opt_spec diff_index_ost[] = {
+	{ "cached",	0,	0,	0,	opt_cached },
+	{ 0, 0 }
+};
+
+static int diff_index_opt_handler(struct gitopt_iterator *gi,
+				const int id, void *args)
+{
+	if (id == opt_cached) {
+		*(int *)args = 1;
+		return 1;
+	}
+	return 0;
+}
+
+#endif
+
diff --git a/gitopt/diff-tree.h b/gitopt/diff-tree.h
new file mode 100644
index 0000000..cfee9b5
--- /dev/null
+++ b/gitopt/diff-tree.h
@@ -0,0 +1,22 @@
+#ifndef GITOPT_DIFF_TREE_H
+#define GITOPT_DIFF_TREE_H
+
+#include "../gitopt/diff.h"
+
+static const struct opt_spec diff_tree_ost[] = {
+	{ "stdin",	0,	0,	0,	opt_stdin },
+	{ 0, 0 }
+};
+
+/* inline to suppress a warning as it's not used in builtin_diff_tree */
+static inline int diff_tree_opt_handler(struct gitopt_iterator *gi,
+				const int id, void *args)
+{
+	if (id == opt_stdin) {
+		*(int *)args = 1;
+		return 1;
+	}
+	return 0;
+}
+
+#endif
diff --git a/gitopt/diff.h b/gitopt/diff.h
new file mode 100644
index 0000000..abc2c7a
--- /dev/null
+++ b/gitopt/diff.h
@@ -0,0 +1,19 @@
+#ifndef GITOPT_DIFF_H
+#define GITOPT_DIFF_H
+
+#include "../gitopt.h"
+
+enum diff_extra_ids {
+	/* diff-files */
+	opt_base = 1, opt_ours, opt_theirs, opt_q,
+
+	/* diff-tree */
+	opt_stdin,
+
+	/* diff-index */
+	opt_cached,
+
+	LAST_DIFF_EXTRA_ID,
+};
+
+#endif /* GITOPT_DIFF_H */
diff --git a/http-push.c b/http-push.c
index b4327d9..9c16f3b 100644
--- a/http-push.c
+++ b/http-push.c
@@ -2499,7 +2499,7 @@ int main(int argc, char **argv)
 			commit_argc++;
 		}
 		init_revisions(&revs);
-		setup_revisions(commit_argc, commit_argv, &revs, NULL);
+		setup_revisions(commit_argc, commit_argv, &revs, NULL, NULL);
 		free(new_sha1_hex);
 		if (old_sha1_hex) {
 			free(old_sha1_hex);
diff --git a/rev-list.c b/rev-list.c
index 8b0ec38..7baeb52 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -291,34 +291,49 @@ static void mark_edges_uninteresting(str
 	}
 }
 
+enum rev_list_ids { opt_header = 1, opt_timestamp, opt_bisect };
+
+static const struct opt_spec rev_list_ost[] = {
+	{ "header",	0,	0,	0,	opt_header },
+	{ "timestamp",	0,	0,	0,	opt_timestamp },
+	{ "bisect",	0,	0,	0,	opt_bisect },
+	{ 0, 0 }
+};
+
+static int rev_list_opt_handler(struct gitopt_iterator *gi,
+				const int id, void *args)
+{
+	int rv = 1;
+	switch (id) {
+	case opt_header:
+		revs.verbose_header = 1;
+		break;
+	case opt_timestamp:
+		show_timestamp = 1;
+		break;
+	case opt_bisect:
+		bisect_list = 1;
+		break;
+	default:
+		rv = 0;
+	}
+	return rv;
+}
+
 int main(int argc, const char **argv)
 {
 	struct commit_list *list;
-	int i;
+	struct exec_args *b;
+	struct gitopt_extra ge = { rev_list_ost, rev_list_opt_handler, NULL };
 
 	init_revisions(&revs);
 	revs.abbrev = 0;
 	revs.commit_format = CMIT_FMT_UNSPECIFIED;
-	argc = setup_revisions(argc, argv, &revs, NULL);
-
-	for (i = 1 ; i < argc; i++) {
-		const char *arg = argv[i];
+	b = setup_revisions(argc, argv, &revs, NULL, &ge);
 
-		if (!strcmp(arg, "--header")) {
-			revs.verbose_header = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--timestamp")) {
-			show_timestamp = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--bisect")) {
-			bisect_list = 1;
-			continue;
-		}
+	if (b->argc)
 		usage(rev_list_usage);
 
-	}
 	if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
 		/* The command line has a --pretty  */
 		hdr_termination = '\n';
diff --git a/revision.c b/revision.c
index 2294b16..aeaf52c 100644
--- a/revision.c
+++ b/revision.c
@@ -6,6 +6,7 @@ #include "commit.h"
 #include "diff.h"
 #include "refs.h"
 #include "revision.h"
+#include "gitopt.h"
 
 static char *path_name(struct name_path *path, const char *name)
 {
@@ -534,6 +535,136 @@ void init_revisions(struct rev_info *rev
 	diff_setup(&revs->diffopt);
 }
 
+enum setup_revision_ost_ids {
+	opt_max_count = GITOPT_SR_BASE, opt_max_age, opt_min_age,
+	opt_since, opt_until, opt_all, opt_not, opt_default,
+	opt_topo_order, opt_date_order, opt_parents, opt_dense,
+	opt_sparse, opt_remove_empty, opt_no_merges, opt_boundary,
+	opt_objects, opt_objects_edge, opt_unpacked,
+	opt_r, opt_t, opt_m, opt_c, opt_cc, opt_v,
+	opt_pretty, opt_root, opt_no_commit_id, opt_always,
+	opt_abbrev, opt_no_abbrev, opt_abbrev_commit, opt_full_diff
+};
+
+static const struct opt_spec setup_revisions_ost[] = {
+	{ "max-count",		'n',	0,	ARG_INT,	opt_max_count },
+	{ 0,			' ',	0,	ARG_INT,	opt_max_count },
+	{ "max-age",		0,	0,	ARG_INT,	opt_max_age },
+	{ "min-age",		0,	0,	ARG_INT,	opt_min_age },
+	{ "since",		0,	0,	ARG_ONE,	opt_since },
+	{ "after",		0,	0,	ARG_ONE,	opt_since },
+	{ "before",		0,	0,	ARG_ONE,	opt_until },
+	{ "until",		0,	0,	ARG_ONE,	opt_until },
+	{ "all",		0,	0,	0,		opt_all },
+	{ "not",		0,	0,	0,		opt_not },
+	{ "default",		0,	0,	ARG_ONE,	opt_default },
+	{ "topo-order",		0,	0,	0,	opt_topo_order },
+	{ "date-order",		0,	0,	0,	opt_date_order },
+	{ "parents",		0,	0,	0,	opt_parents },
+	{ "dense",		0,	0,	0,	opt_dense },
+	{ "sparse",		0,	0,	0,	opt_sparse },
+	{ "remove-empty",	0,	0,	0,	opt_remove_empty },
+	{ "no-merges",		0,	0,	0,	opt_no_merges },
+	{ "boundary",		0,	0,	0,	opt_boundary },
+	{ "objects",		0,	0,	0,	opt_objects },
+	{ "objects-edge",	0,	0,	0,	opt_objects_edge },
+	{ "unpacked",		0,	0,	0,	opt_unpacked },
+	{ 0,			'r',	0,	0,	opt_r },
+	{ 0,			't',	0,	0,	opt_t },
+	{ 0,			'm',	0,	0,	opt_m },
+	{ 0,			'c',	0,	0,	opt_c },
+	{ "cc",			0,	0,	0,	opt_cc },
+	{ 0,			'v',	0,	0,	opt_v },
+	{ "pretty",		0,	0,	ARG_OPT,	opt_pretty },
+	{ "root",		0,	0,	0,	opt_root },
+	{ "no-commit-id",	0,	0,	0,	opt_no_commit_id },
+	{ "always",		0,	0,	0,	opt_always },
+	{ "no-abbrev",		0,	0,	0,	opt_no_abbrev },
+	{ "abbrev",		0,	0,	0,	opt_abbrev },
+	{ "abbrev-commit",	0,	0,	0,	opt_abbrev_commit },
+	{ "full-diff",		0,	0,	0,	opt_full_diff },
+	{ 0, 0 }
+};
+
+static int setup_revision(struct gitopt_iterator *gi, struct rev_info *revs,
+			int flags, int seen_dashdash)
+{
+	const char *arg = gi->argv[gi->pos];
+	unsigned char sha1[20];
+	struct object *object;
+	char *dotdot;
+	int local_flags;
+
+	dotdot = strstr(arg, "..");
+	if (dotdot) {
+		unsigned char from_sha1[20];
+		const char *next = dotdot + 2;
+		const char *this = arg;
+		*dotdot = 0;
+		if (!*next)
+			next = "HEAD";
+		if (dotdot == arg)
+			this = "HEAD";
+		if (!get_sha1(this, from_sha1) &&
+		    !get_sha1(next, sha1)) {
+			struct object *exclude;
+			struct object *include;
+
+			exclude = get_reference(revs, this, from_sha1,
+						flags ^ UNINTERESTING);
+			include = get_reference(revs, next, sha1, flags);
+			if (!exclude || !include)
+				die("Invalid revision range %s..%s", arg, next);
+
+			if (!seen_dashdash) {
+				*dotdot = '.';
+				verify_non_filename(revs->prefix, arg);
+			}
+			add_pending_object(revs, exclude, this);
+			add_pending_object(revs, include, next);
+			return 1;
+		}
+		*dotdot = '.';
+	}
+
+	dotdot = strstr(arg, "^@");
+	if (dotdot && !dotdot[2]) {
+		*dotdot = 0;
+		if (add_parents_only(revs, arg, flags))
+			return 1;
+		*dotdot = '^';
+	}
+	local_flags = 0;
+	if (*arg == '^') {
+		local_flags = UNINTERESTING;
+		arg++;
+	}
+	if (get_sha1(arg, sha1) < 0) {
+		int j;
+
+		if (seen_dashdash || local_flags)
+			die("bad revision '%s'", arg);
+
+		/* If we didn't have a "--":
+		 * (1) all filenames must exist;
+		 * (2) all rev-args must not be interpretable
+		 *     as a valid filename.
+		 * but the latter we have checked in the main loop.
+		 */
+		for (j = gi->pos; j < gi->argc; j++)
+			verify_filename(revs->prefix, gi->argv[j]);
+
+		revs->prune_data = get_pathspec(revs->prefix,
+						gi->argv + gi->pos);
+		return 1;
+	}
+	if (!seen_dashdash)
+		verify_non_filename(revs->prefix, arg);
+	object = get_reference(revs, arg, sha1, flags ^ local_flags);
+	add_pending_object(revs, object, arg);
+	return 1;
+}
+
 /*
  * Parse revision information, filling in the "rev_info" structure,
  * and removing the used arguments from the argument list.
@@ -541,11 +672,14 @@ void init_revisions(struct rev_info *rev
  * Returns the number of arguments left that weren't recognized
  * (which are also moved to the head of the argument list)
  */
-int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def)
+struct exec_args *setup_revisions(int argc, const char **argv,
+					struct rev_info *revs, const char *def,
+					const struct gitopt_extra *ge)
 {
-	int i, flags, seen_dashdash;
-	const char **unrecognized = argv + 1;
-	int left = 1;
+	int i, id, flags, seen_dashdash;
+	struct gitopt_iterator gi;
+	struct exec_args *ea, *b;
+	struct opt_spec *ost;
 
 	/* First, search for "--" */
 	seen_dashdash = 0;
@@ -561,261 +695,158 @@ int setup_revisions(int argc, const char
 	}
 
 	flags = 0;
-	for (i = 1; i < argc; i++) {
-		struct object *object;
-		const char *arg = argv[i];
-		unsigned char sha1[20];
-		char *dotdot;
-		int local_flags;
+	ost = combine_opt_spec(setup_revisions_ost, diff_ost);
+	if (ge) {
+		struct opt_spec *tmp = ost;
+		ost = combine_opt_spec(tmp, ge->ost);
+		free(tmp);
+	}
 
-		if (*arg == '-') {
-			int opts;
-			if (!strncmp(arg, "--max-count=", 12)) {
-				revs->max_count = atoi(arg + 12);
-				continue;
-			}
-			/* accept -<digit>, like traditional "head" */
-			if ((*arg == '-') && isdigit(arg[1])) {
-				revs->max_count = atoi(arg + 1);
-				continue;
-			}
-			if (!strcmp(arg, "-n")) {
-				if (argc <= i + 1)
-					die("-n requires an argument");
-				revs->max_count = atoi(argv[++i]);
-				continue;
-			}
-			if (!strncmp(arg,"-n",2)) {
-				revs->max_count = atoi(arg + 2);
-				continue;
-			}
-			if (!strncmp(arg, "--max-age=", 10)) {
-				revs->max_age = atoi(arg + 10);
-				continue;
-			}
-			if (!strncmp(arg, "--since=", 8)) {
-				revs->max_age = approxidate(arg + 8);
-				continue;
-			}
-			if (!strncmp(arg, "--after=", 8)) {
-				revs->max_age = approxidate(arg + 8);
-				continue;
-			}
-			if (!strncmp(arg, "--min-age=", 10)) {
-				revs->min_age = atoi(arg + 10);
-				continue;
-			}
-			if (!strncmp(arg, "--before=", 9)) {
-				revs->min_age = approxidate(arg + 9);
-				continue;
-			}
-			if (!strncmp(arg, "--until=", 8)) {
-				revs->min_age = approxidate(arg + 8);
-				continue;
-			}
-			if (!strcmp(arg, "--all")) {
-				handle_all(revs, flags);
-				continue;
-			}
-			if (!strcmp(arg, "--not")) {
-				flags ^= UNINTERESTING;
-				continue;
-			}
-			if (!strcmp(arg, "--default")) {
-				if (++i >= argc)
-					die("bad --default argument");
-				def = argv[i];
-				continue;
-			}
-			if (!strcmp(arg, "--topo-order")) {
-				revs->topo_order = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--date-order")) {
-				revs->lifo = 0;
-				revs->topo_order = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--parents")) {
-				revs->parents = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--dense")) {
-				revs->dense = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--sparse")) {
-				revs->dense = 0;
-				continue;
-			}
-			if (!strcmp(arg, "--remove-empty")) {
-				revs->remove_empty_trees = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--no-merges")) {
-				revs->no_merges = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--boundary")) {
-				revs->boundary = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--objects")) {
-				revs->tag_objects = 1;
-				revs->tree_objects = 1;
-				revs->blob_objects = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--objects-edge")) {
-				revs->tag_objects = 1;
-				revs->tree_objects = 1;
-				revs->blob_objects = 1;
-				revs->edge_hint = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--unpacked")) {
-				revs->unpacked = 1;
-				continue;
-			}
-			if (!strcmp(arg, "-r")) {
-				revs->diff = 1;
-				revs->diffopt.recursive = 1;
-				continue;
-			}
-			if (!strcmp(arg, "-t")) {
-				revs->diff = 1;
-				revs->diffopt.recursive = 1;
-				revs->diffopt.tree_in_recursive = 1;
-				continue;
-			}
-			if (!strcmp(arg, "-m")) {
-				revs->ignore_merges = 0;
-				continue;
-			}
-			if (!strcmp(arg, "-c")) {
-				revs->diff = 1;
-				revs->dense_combined_merges = 0;
-				revs->combine_merges = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--cc")) {
-				revs->diff = 1;
-				revs->dense_combined_merges = 1;
-				revs->combine_merges = 1;
-				continue;
-			}
-			if (!strcmp(arg, "-v")) {
-				revs->verbose_header = 1;
-				continue;
-			}
-			if (!strncmp(arg, "--pretty", 8)) {
-				revs->verbose_header = 1;
-				revs->commit_format = get_commit_format(arg+8);
-				continue;
-			}
-			if (!strcmp(arg, "--root")) {
-				revs->show_root_diff = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--no-commit-id")) {
-				revs->no_commit_id = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--always")) {
-				revs->always_show_header = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--no-abbrev")) {
-				revs->abbrev = 0;
-				continue;
-			}
-			if (!strcmp(arg, "--abbrev")) {
+	gitopt_iter_setup(&gi, argc, argv);
+	ea = gi.ea;
+	b = gi.b;
+	for (; (id = gitopt_iter_parse(&gi, ost)); gitopt_iter_next(&gi)) {
+		switch (id) {
+		case opt_max_count:
+			revs->max_count = atoi(ea->argv[0]);
+			break;
+		case opt_max_age:
+			revs->max_age = atoi(ea->argv[0]);
+			break;
+		case opt_min_age:
+			revs->min_age = atoi(ea->argv[0]);
+			break;
+		case opt_since:
+			revs->max_age = approxidate(ea->argv[0]);
+			break;
+		case opt_until:
+			revs->min_age = approxidate(ea->argv[0]);
+			break;
+		case opt_all:
+			handle_all(revs, flags);
+			break;
+		case opt_not:
+			flags ^= UNINTERESTING;
+			break;
+		case opt_default:
+			if (!ea->argc)
+				die("bad --default argument");
+			def = ea->argv[0];
+			break;
+		case opt_topo_order:
+			revs->topo_order = 1;
+			break;
+		case opt_date_order:
+			revs->lifo = 0;
+			revs->topo_order = 1;
+			break;
+		case opt_parents:
+			revs->parents = 1;
+			break;
+		case opt_dense:
+			revs->dense = 1;
+			break;
+		case opt_sparse:
+			revs->dense = 0;
+			break;
+		case opt_remove_empty:
+			revs->remove_empty_trees = 1;
+			break;
+		case opt_no_merges:
+			revs->no_merges = 1;
+			break;
+		case opt_boundary:
+			revs->boundary = 1;
+			break;
+		case opt_objects_edge:
+			revs->edge_hint = 1; /* fall through */
+		case opt_objects:
+			revs->tag_objects = 1;
+			revs->tree_objects = 1;
+			revs->blob_objects = 1;
+			break;
+		case opt_unpacked:
+			revs->unpacked = 1;
+			break;
+		case opt_r:
+			revs->diff = 1;
+			revs->diffopt.recursive = 1;
+			break;
+		case opt_t:
+			revs->diff = 1;
+			revs->diffopt.recursive = 1;
+			revs->diffopt.tree_in_recursive = 1;
+			break;
+		case opt_m:
+			revs->ignore_merges = 0;
+			break;
+		case opt_c:
+			revs->diff = 1;
+			revs->dense_combined_merges = 0;
+			revs->combine_merges = 1;
+			break;
+		case opt_cc:
+			revs->diff = 1;
+			revs->dense_combined_merges = 1;
+			revs->combine_merges = 1;
+			break;
+		case opt_v:
+			revs->verbose_header = 1;
+			break;
+		case opt_pretty:
+			revs->verbose_header = 1;
+			revs->commit_format = get_commit_format(ea->argv[1]);
+			break;
+		case opt_root:
+			revs->show_root_diff = 1;
+			break;
+		case opt_no_commit_id:
+			revs->no_commit_id = 1;
+			break;
+		case opt_always:
+			revs->always_show_header = 1;
+			break;
+		case opt_no_abbrev:
+			revs->abbrev = 0;
+			break;
+		case opt_abbrev_commit:
+			revs->abbrev_commit = 1;
+			break;
+		case opt_full_diff:
+			revs->diff = 1;
+			revs->full_diff = 1;
+			break;
+		case opt_abbrev:
+			if (ea->argc == 1)
 				revs->abbrev = DEFAULT_ABBREV;
-				continue;
+			else {
+				revs->abbrev = strtoul(ea->argv[1], NULL, 10);
+				if (revs->abbrev < MINIMUM_ABBREV)
+					revs->abbrev = MINIMUM_ABBREV;
+				else if (40 < revs->abbrev)
+					revs->abbrev = 40;
 			}
-			if (!strcmp(arg, "--abbrev-commit")) {
-				revs->abbrev_commit = 1;
-				continue;
-			}
-			if (!strcmp(arg, "--full-diff")) {
-				revs->diff = 1;
-				revs->full_diff = 1;
-				continue;
-			}
-			opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
-			if (opts > 0) {
-				revs->diff = 1;
-				i += opts - 1;
-				continue;
-			}
-			*unrecognized++ = arg;
-			left++;
-			continue;
-		}
-		dotdot = strstr(arg, "..");
-		if (dotdot) {
-			unsigned char from_sha1[20];
-			const char *next = dotdot + 2;
-			const char *this = arg;
-			*dotdot = 0;
-			if (!*next)
-				next = "HEAD";
-			if (dotdot == arg)
-				this = "HEAD";
-			if (!get_sha1(this, from_sha1) &&
-			    !get_sha1(next, sha1)) {
-				struct object *exclude;
-				struct object *include;
-
-				exclude = get_reference(revs, this, from_sha1, flags ^ UNINTERESTING);
-				include = get_reference(revs, next, sha1, flags);
-				if (!exclude || !include)
-					die("Invalid revision range %s..%s", arg, next);
-
-				if (!seen_dashdash) {
-					*dotdot = '.';
-					verify_non_filename(revs->prefix, arg);
-				}
-				add_pending_object(revs, exclude, this);
-				add_pending_object(revs, include, next);
-				continue;
-			}
-			*dotdot = '.';
-		}
-		dotdot = strstr(arg, "^@");
-		if (dotdot && !dotdot[2]) {
-			*dotdot = 0;
-			if (add_parents_only(revs, arg, flags))
-				continue;
-			*dotdot = '^';
-		}
-		local_flags = 0;
-		if (*arg == '^') {
-			local_flags = UNINTERESTING;
-			arg++;
-		}
-		if (get_sha1(arg, sha1)) {
-			int j;
-
-			if (seen_dashdash || local_flags)
-				die("bad revision '%s'", arg);
-
-			/* If we didn't have a "--":
-			 * (1) all filenames must exist;
-			 * (2) all rev-args must not be interpretable
-			 *     as a valid filename.
-			 * but the latter we have checked in the main loop.
-			 */
-			for (j = i; j < argc; j++)
-				verify_filename(revs->prefix, argv[j]);
-
-			revs->prune_data = get_pathspec(revs->prefix, argv + i);
 			break;
+		case GITOPT_NON_OPTION:
+			/* fprintf(stderr,"no: %s\n",gi.argv[gi.pos]); */
+			i = setup_revision(&gi, revs, flags, seen_dashdash);
+			gi.pos += i - 1;
+			break;
+		default:
+			/* fprintf(stderr,"do: %s\n",gi.argv[gi.pos]); */
+			i = diff_opt_handler(&gi, id, &revs->diffopt);
+			if (i > 0)
+				revs->diff = 1;
+			else if (i < 0) /* error */
+				b->argv[b->argc++] = gi.argv[gi.pos++];
+			else if (ge) {
+				/* i = 0: not a diff_opt, try other handler */
+				i = ge->opt_handler(&gi, id, ge->args);
+				if (i <= 0) /* error */
+					b->argv[b->argc++] = gi.argv[gi.pos++];
+			}
+			gi.pos += i - 1;
 		}
-		if (!seen_dashdash)
-			verify_non_filename(revs->prefix, arg);
-		object = get_reference(revs, arg, sha1, flags ^ local_flags);
-		add_pending_object(revs, object, arg);
 	}
 	if (def && !revs->pending_objects) {
 		unsigned char sha1[20];
@@ -844,7 +875,8 @@ int setup_revisions(int argc, const char
 	revs->diffopt.abbrev = revs->abbrev;
 	diff_setup_done(&revs->diffopt);
 
-	return left;
+	free(ost);
+	return b;
 }
 
 void prepare_revision_walk(struct rev_info *revs)
diff --git a/revision.h b/revision.h
index 48d7b4c..28211b6 100644
--- a/revision.h
+++ b/revision.h
@@ -81,7 +81,9 @@ extern int rev_same_tree_as_empty(struct
 extern int rev_compare_tree(struct rev_info *, struct tree *t1, struct tree *t2);
 
 extern void init_revisions(struct rev_info *revs);
-extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
+extern struct exec_args *setup_revisions(int, const char **argv,
+					struct rev_info *revs, const char *def,
+					const struct gitopt_extra *);
 extern void prepare_revision_walk(struct rev_info *revs);
 extern struct commit *get_revision(struct rev_info *revs);
 
-- 
1.3.2.g102e322

-
: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]