Merge branch 'ph/parseopt'

* ph/parseopt: (24 commits)
  gc: use parse_options
  Fixed a command line option type for builtin-fsck.c
  Make builtin-pack-refs.c use parse_options.
  Make builtin-name-rev.c use parse_options.
  Make builtin-count-objects.c use parse_options.
  Make builtin-fsck.c use parse_options.
  Update manpages to reflect new short and long option aliases
  Make builtin-for-each-ref.c use parse-opts.
  Make builtin-symbolic-ref.c use parse_options.
  Make builtin-update-ref.c use parse_options
  Make builtin-revert.c use parse_options.
  Make builtin-describe.c use parse_options
  Make builtin-branch.c use parse_options.
  Make builtin-mv.c use parse-options
  Make builtin-rm.c use parse_options.
  Port builtin-add.c to use the new option parser.
  parse-options: allow callbacks to take no arguments at all.
  parse-options: Allow abbreviated options when unambiguous
  Add shortcuts for very often used options.
  parse-options: make some arguments optional, add callbacks.
  ...

Conflicts:

	Makefile
	builtin-add.c
This commit is contained in:
Junio C Hamano 2007-11-02 16:42:23 -07:00
commit 3d66dc9657
26 changed files with 932 additions and 613 deletions

1
.gitignore vendored
View File

@ -153,6 +153,7 @@ test-delta
test-dump-cache-tree test-dump-cache-tree
test-genrandom test-genrandom
test-match-trees test-match-trees
test-parse-options
test-sha1 test-sha1
common-cmds.h common-cmds.h
*.tar.gz *.tar.gz

View File

@ -50,10 +50,10 @@ OPTIONS
and `dir/file2`) can be given to add all files in the and `dir/file2`) can be given to add all files in the
directory, recursively. directory, recursively.
-n:: -n, \--dry-run::
Don't actually add the file(s), just show if they exist. Don't actually add the file(s), just show if they exist.
-v:: -v, \--verbose::
Be verbose. Be verbose.
-f:: -f::

View File

@ -85,7 +85,7 @@ OPTIONS
-a:: -a::
List both remote-tracking branches and local branches. List both remote-tracking branches and local branches.
-v:: -v, --verbose::
Show sha1 and commit subject line for each head. Show sha1 and commit subject line for each head.
--abbrev=<length>:: --abbrev=<length>::

View File

@ -34,7 +34,7 @@ OPTIONS
condition. An error happens when a source is neither existing nor condition. An error happens when a source is neither existing nor
controlled by GIT, or when it would overwrite an existing controlled by GIT, or when it would overwrite an existing
file unless '-f' is given. file unless '-f' is given.
-n:: -n, \--dry-run::
Do nothing; only show what would happen Do nothing; only show what would happen

View File

@ -30,7 +30,7 @@ OPTIONS
-f:: -f::
Override the up-to-date check. Override the up-to-date check.
-n:: -n, \--dry-run::
Don't actually remove the file(s), just show if they exist in Don't actually remove the file(s), just show if they exist in
the index. the index.
@ -51,7 +51,7 @@ OPTIONS
\--ignore-unmatch:: \--ignore-unmatch::
Exit with a zero status even if no files matched. Exit with a zero status even if no files matched.
\--quiet:: -q, \--quiet::
git-rm normally outputs one line (in the form of an "rm" command) git-rm normally outputs one line (in the form of an "rm" command)
for each file removed. This option suppresses that output. for each file removed. This option suppresses that output.

View File

@ -26,7 +26,7 @@ a regular file whose contents is `ref: refs/heads/master`.
OPTIONS OPTIONS
------- -------
-q:: -q, --quiet::
Do not issue an error message if the <name> is not a Do not issue an error message if the <name> is not a
symbolic ref but a detached HEAD; instead exit with symbolic ref but a detached HEAD; instead exit with
non-zero status silently. non-zero status silently.

View File

@ -289,7 +289,7 @@ LIB_H = \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
mailmap.h remote.h transport.h diffcore.h hash.h mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h
DIFF_OBJS = \ DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@ -312,7 +312,7 @@ LIB_OBJS = \
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \ color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \ convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
transport.o bundle.o walker.o transport.o bundle.o walker.o parse-options.o
BUILTIN_OBJS = \ BUILTIN_OBJS = \
builtin-add.o \ builtin-add.o \
@ -974,7 +974,7 @@ endif
### Testing rules ### Testing rules
TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X
all:: $(TEST_PROGRAMS) all:: $(TEST_PROGRAMS)

View File

@ -13,9 +13,12 @@
#include "commit.h" #include "commit.h"
#include "revision.h" #include "revision.h"
#include "run-command.h" #include "run-command.h"
#include "parse-options.h"
static const char builtin_add_usage[] = static const char * const builtin_add_usage[] = {
"git-add [-n] [-v] [-f] [--interactive | -i] [-u] [--refresh] [--] <filepattern>..."; "git-add [options] [--] <filepattern>...",
NULL
};
static int take_worktree_changes; static int take_worktree_changes;
static const char *excludes_file; static const char *excludes_file;
@ -162,21 +165,30 @@ static struct lock_file lock_file;
static const char ignore_error[] = static const char ignore_error[] =
"The following paths are ignored by one of your .gitignore files:\n"; "The following paths are ignored by one of your .gitignore files:\n";
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
static int add_interactive = 0;
static struct option builtin_add_options[] = {
OPT__DRY_RUN(&show_only),
OPT__VERBOSE(&verbose),
OPT_GROUP(""),
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
OPT_END(),
};
int cmd_add(int argc, const char **argv, const char *prefix) int cmd_add(int argc, const char **argv, const char *prefix)
{ {
int i, newfd; int i, newfd, orig_argc = argc;
int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
const char **pathspec; const char **pathspec;
struct dir_struct dir; struct dir_struct dir;
int add_interactive = 0;
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, builtin_add_options,
if (!strcmp("--interactive", argv[i]) || builtin_add_usage, 0);
!strcmp("-i", argv[i]))
add_interactive++;
}
if (add_interactive) { if (add_interactive) {
if (argc != 2) if (add_interactive != 1 || orig_argc != 2)
die("add --interactive does not take any parameters"); die("add --interactive does not take any parameters");
exit(interactive_add()); exit(interactive_add());
} }
@ -185,51 +197,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
newfd = hold_locked_index(&lock_file, 1); newfd = hold_locked_index(&lock_file, 1);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (arg[0] != '-')
break;
if (!strcmp(arg, "--")) {
i++;
break;
}
if (!strcmp(arg, "-n")) {
show_only = 1;
continue;
}
if (!strcmp(arg, "-f")) {
ignored_too = 1;
continue;
}
if (!strcmp(arg, "-v")) {
verbose = 1;
continue;
}
if (!strcmp(arg, "-u")) {
take_worktree_changes = 1;
continue;
}
if (!strcmp(arg, "--refresh")) {
refresh_only = 1;
continue;
}
usage(builtin_add_usage);
}
if (take_worktree_changes) { if (take_worktree_changes) {
if (read_cache() < 0) if (read_cache() < 0)
die("index file corrupt"); die("index file corrupt");
add_files_to_cache(verbose, prefix, argv + i); add_files_to_cache(verbose, prefix, argv);
goto finish; goto finish;
} }
if (argc <= i) { if (argc == 0) {
fprintf(stderr, "Nothing specified, nothing added.\n"); fprintf(stderr, "Nothing specified, nothing added.\n");
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n"); fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
return 0; return 0;
} }
pathspec = get_pathspec(prefix, argv + i); pathspec = get_pathspec(prefix, argv);
if (refresh_only) { if (refresh_only) {
refresh(verbose, pathspec); refresh(verbose, pathspec);

View File

@ -11,9 +11,15 @@
#include "commit.h" #include "commit.h"
#include "builtin.h" #include "builtin.h"
#include "remote.h" #include "remote.h"
#include "parse-options.h"
static const char builtin_branch_usage[] = static const char * const builtin_branch_usage[] = {
"git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]"; "git-branch [options] [-r | -a]",
"git-branch [options] [-l] [-f] <branchname> [<start-point>]",
"git-branch [options] [-r] (-d | -D) <branchname>",
"git-branch [options] (-m | -M) [<oldbranch>] <newbranch>",
NULL
};
#define REF_UNKNOWN_TYPE 0x00 #define REF_UNKNOWN_TYPE 0x00
#define REF_LOCAL_BRANCH 0x01 #define REF_LOCAL_BRANCH 0x01
@ -505,93 +511,45 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int rename = 0, force_rename = 0; int rename = 0, force_rename = 0;
int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0; int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
int reflog = 0, track; int reflog = 0, track;
int kinds = REF_LOCAL_BRANCH; int kinds = REF_LOCAL_BRANCH, kind_remote = 0, kind_any = 0;
int i;
struct option options[] = {
OPT_GROUP("Generic options"),
OPT__VERBOSE(&verbose),
OPT_BOOLEAN( 0 , "track", &track, "set up tracking mode (see git-pull(1))"),
OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
OPT_BOOLEAN('r', NULL, &kind_remote, "act on remote-tracking branches"),
OPT__ABBREV(&abbrev),
OPT_GROUP("Specific git-branch actions:"),
OPT_BOOLEAN('a', NULL, &kind_any, "list both remote-tracking and local branches"),
OPT_BOOLEAN('d', NULL, &delete, "delete fully merged branch"),
OPT_BOOLEAN('D', NULL, &force_delete, "delete branch (even if not merged)"),
OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"),
OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
OPT_BOOLEAN('m', NULL, &rename, "move/rename a branch and its reflog"),
OPT_BOOLEAN('M', NULL, &force_rename, "move/rename a branch, even if target exists"),
OPT_END(),
};
git_config(git_branch_config); git_config(git_branch_config);
track = branch_track; track = branch_track;
argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
for (i = 1; i < argc; i++) { delete |= force_delete;
const char *arg = argv[i]; rename |= force_rename;
if (kind_remote)
if (arg[0] != '-') kinds = REF_REMOTE_BRANCH;
break; if (kind_any)
if (!strcmp(arg, "--")) { kinds = REF_REMOTE_BRANCH | REF_LOCAL_BRANCH;
i++; if (abbrev && abbrev < MINIMUM_ABBREV)
break; abbrev = MINIMUM_ABBREV;
} else if (abbrev > 40)
if (!strcmp(arg, "--track")) { abbrev = 40;
track = 1;
continue;
}
if (!strcmp(arg, "--no-track")) {
track = 0;
continue;
}
if (!strcmp(arg, "-d")) {
delete = 1;
continue;
}
if (!strcmp(arg, "-D")) {
delete = 1;
force_delete = 1;
continue;
}
if (!strcmp(arg, "-f")) {
force_create = 1;
continue;
}
if (!strcmp(arg, "-m")) {
rename = 1;
continue;
}
if (!strcmp(arg, "-M")) {
rename = 1;
force_rename = 1;
continue;
}
if (!strcmp(arg, "-r")) {
kinds = REF_REMOTE_BRANCH;
continue;
}
if (!strcmp(arg, "-a")) {
kinds = REF_REMOTE_BRANCH | REF_LOCAL_BRANCH;
continue;
}
if (!strcmp(arg, "-l")) {
reflog = 1;
continue;
}
if (!prefixcmp(arg, "--no-abbrev")) {
abbrev = 0;
continue;
}
if (!prefixcmp(arg, "--abbrev=")) {
abbrev = strtoul(arg + 9, NULL, 10);
if (abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
else if (abbrev > 40)
abbrev = 40;
continue;
}
if (!strcmp(arg, "-v")) {
verbose = 1;
continue;
}
if (!strcmp(arg, "--color")) {
branch_use_color = 1;
continue;
}
if (!strcmp(arg, "--no-color")) {
branch_use_color = 0;
continue;
}
usage(builtin_branch_usage);
}
if ((delete && rename) || (delete && force_create) || if ((delete && rename) || (delete && force_create) ||
(rename && force_create)) (rename && force_create))
usage(builtin_branch_usage); usage_with_options(builtin_branch_usage, options);
head = resolve_ref("HEAD", head_sha1, 0, NULL); head = resolve_ref("HEAD", head_sha1, 0, NULL);
if (!head) if (!head)
@ -599,26 +557,25 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
head = xstrdup(head); head = xstrdup(head);
if (!strcmp(head, "HEAD")) { if (!strcmp(head, "HEAD")) {
detached = 1; detached = 1;
} } else {
else {
if (prefixcmp(head, "refs/heads/")) if (prefixcmp(head, "refs/heads/"))
die("HEAD not found below refs/heads!"); die("HEAD not found below refs/heads!");
head += 11; head += 11;
} }
if (delete) if (delete)
return delete_branches(argc - i, argv + i, force_delete, kinds); return delete_branches(argc, argv, force_delete, kinds);
else if (i == argc) else if (argc == 0)
print_ref_list(kinds, detached, verbose, abbrev); print_ref_list(kinds, detached, verbose, abbrev);
else if (rename && (i == argc - 1)) else if (rename && (argc == 1))
rename_branch(head, argv[i], force_rename); rename_branch(head, argv[0], force_rename);
else if (rename && (i == argc - 2)) else if (rename && (argc == 2))
rename_branch(argv[i], argv[i + 1], force_rename); rename_branch(argv[0], argv[1], force_rename);
else if (i == argc - 1 || i == argc - 2) else if (argc <= 2)
create_branch(argv[i], (i == argc - 2) ? argv[i+1] : head, create_branch(argv[0], (argc == 2) ? argv[1] : head,
force_create, reflog, track); force_create, reflog, track);
else else
usage(builtin_branch_usage); usage_with_options(builtin_branch_usage, options);
return 0; return 0;
} }

View File

@ -6,8 +6,7 @@
#include "cache.h" #include "cache.h"
#include "builtin.h" #include "builtin.h"
#include "parse-options.h"
static const char count_objects_usage[] = "git-count-objects [-v]";
static void count_objects(DIR *d, char *path, int len, int verbose, static void count_objects(DIR *d, char *path, int len, int verbose,
unsigned long *loose, unsigned long *loose,
@ -67,29 +66,28 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
} }
} }
int cmd_count_objects(int ac, const char **av, const char *prefix) static char const * const count_objects_usage[] = {
"git-count-objects [-v]",
NULL
};
int cmd_count_objects(int argc, const char **argv, const char *prefix)
{ {
int i; int i, verbose = 0;
int verbose = 0;
const char *objdir = get_object_directory(); const char *objdir = get_object_directory();
int len = strlen(objdir); int len = strlen(objdir);
char *path = xmalloc(len + 50); char *path = xmalloc(len + 50);
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0; unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
unsigned long loose_size = 0; unsigned long loose_size = 0;
struct option opts[] = {
OPT__VERBOSE(&verbose),
OPT_END(),
};
for (i = 1; i < ac; i++) { argc = parse_options(argc, argv, opts, count_objects_usage, 0);
const char *arg = av[i];
if (*arg != '-')
break;
else if (!strcmp(arg, "-v"))
verbose = 1;
else
usage(count_objects_usage);
}
/* we do not take arguments other than flags for now */ /* we do not take arguments other than flags for now */
if (i < ac) if (argc)
usage(count_objects_usage); usage_with_options(count_objects_usage, opts);
memcpy(path, objdir, len); memcpy(path, objdir, len);
if (len && objdir[len-1] != '/') if (len && objdir[len-1] != '/')
path[len++] = '/'; path[len++] = '/';

View File

@ -4,12 +4,15 @@
#include "refs.h" #include "refs.h"
#include "builtin.h" #include "builtin.h"
#include "exec_cmd.h" #include "exec_cmd.h"
#include "parse-options.h"
#define SEEN (1u<<0) #define SEEN (1u<<0)
#define MAX_TAGS (FLAG_BITS - 1) #define MAX_TAGS (FLAG_BITS - 1)
static const char describe_usage[] = static const char * const describe_usage[] = {
"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*"; "git-describe [options] <committish>*",
NULL
};
static int debug; /* Display lots of verbose info */ static int debug; /* Display lots of verbose info */
static int all; /* Default to annotated tags only */ static int all; /* Default to annotated tags only */
@ -242,57 +245,42 @@ static void describe(const char *arg, int last_one)
int cmd_describe(int argc, const char **argv, const char *prefix) int cmd_describe(int argc, const char **argv, const char *prefix)
{ {
int i;
int contains = 0; int contains = 0;
struct option options[] = {
OPT_BOOLEAN(0, "contains", &contains, "find the tag that comes after the commit"),
OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"),
OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"),
OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
OPT__ABBREV(&abbrev),
OPT_INTEGER(0, "candidates", &max_candidates,
"consider <n> most recent tags (default: 10)"),
OPT_END(),
};
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, options, describe_usage, 0);
const char *arg = argv[i]; if (max_candidates < 1)
max_candidates = 1;
if (*arg != '-') else if (max_candidates > MAX_TAGS)
break; max_candidates = MAX_TAGS;
else if (!strcmp(arg, "--contains"))
contains = 1;
else if (!strcmp(arg, "--debug"))
debug = 1;
else if (!strcmp(arg, "--all"))
all = 1;
else if (!strcmp(arg, "--tags"))
tags = 1;
else if (!prefixcmp(arg, "--abbrev=")) {
abbrev = strtoul(arg + 9, NULL, 10);
if (abbrev != 0 && (abbrev < MINIMUM_ABBREV || 40 < abbrev))
abbrev = DEFAULT_ABBREV;
}
else if (!prefixcmp(arg, "--candidates=")) {
max_candidates = strtoul(arg + 13, NULL, 10);
if (max_candidates < 1)
max_candidates = 1;
else if (max_candidates > MAX_TAGS)
max_candidates = MAX_TAGS;
}
else
usage(describe_usage);
}
save_commit_buffer = 0; save_commit_buffer = 0;
if (contains) { if (contains) {
const char **args = xmalloc((4 + argc - i) * sizeof(char*)); const char **args = xmalloc((4 + argc) * sizeof(char*));
args[0] = "name-rev"; args[0] = "name-rev";
args[1] = "--name-only"; args[1] = "--name-only";
args[2] = "--tags"; args[2] = "--tags";
memcpy(args + 3, argv + i, (argc - i) * sizeof(char*)); memcpy(args + 3, argv, argc * sizeof(char*));
args[3 + argc - i] = NULL; args[3 + argc] = NULL;
return cmd_name_rev(3 + argc - i, args, prefix); return cmd_name_rev(3 + argc, args, prefix);
} }
if (argc <= i) if (argc == 0) {
describe("HEAD", 1); describe("HEAD", 1);
else } else {
while (i < argc) { while (argc-- > 0) {
describe(argv[i], (i == argc - 1)); describe(*argv++, argc == 0);
i++;
} }
}
return 0; return 0;
} }

View File

@ -7,6 +7,7 @@
#include "tree.h" #include "tree.h"
#include "blob.h" #include "blob.h"
#include "quote.h" #include "quote.h"
#include "parse-options.h"
/* Quoting styles */ /* Quoting styles */
#define QUOTE_NONE 0 #define QUOTE_NONE 0
@ -158,17 +159,18 @@ static const char *find_next(const char *cp)
* Make sure the format string is well formed, and parse out * Make sure the format string is well formed, and parse out
* the used atoms. * the used atoms.
*/ */
static void verify_format(const char *format) static int verify_format(const char *format)
{ {
const char *cp, *sp; const char *cp, *sp;
for (cp = format; *cp && (sp = find_next(cp)); ) { for (cp = format; *cp && (sp = find_next(cp)); ) {
const char *ep = strchr(sp, ')'); const char *ep = strchr(sp, ')');
if (!ep) if (!ep)
die("malformatted format string %s", sp); return error("malformatted format string %s", sp);
/* sp points at "%(" and ep points at the closing ")" */ /* sp points at "%(" and ep points at the closing ")" */
parse_atom(sp + 2, ep); parse_atom(sp + 2, ep);
cp = ep + 1; cp = ep + 1;
} }
return 0;
} }
/* /*
@ -800,94 +802,76 @@ static struct ref_sort *default_sort(void)
return sort; return sort;
} }
int cmd_for_each_ref(int ac, const char **av, const char *prefix) int opt_parse_sort(const struct option *opt, const char *arg, int unset)
{
struct ref_sort **sort_tail = opt->value;
struct ref_sort *s;
int len;
if (!arg) /* should --no-sort void the list ? */
return -1;
*sort_tail = s = xcalloc(1, sizeof(*s));
sort_tail = &s->next;
if (*arg == '-') {
s->reverse = 1;
arg++;
}
len = strlen(arg);
s->atom = parse_atom(arg, arg+len);
return 0;
}
static char const * const for_each_ref_usage[] = {
"git-for-each-ref [options] [<pattern>]",
NULL
};
int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
{ {
int i, num_refs; int i, num_refs;
const char *format = NULL; const char *format = "%(objectname) %(objecttype)\t%(refname)";
struct ref_sort *sort = NULL, **sort_tail = &sort; struct ref_sort *sort = NULL, **sort_tail = &sort;
int maxcount = 0; int maxcount = 0, quote_style;
int quote_style = -1; /* unspecified yet */ int quote_shell = 0, quote_perl = 0, quote_python = 0, quote_tcl = 0;
struct refinfo **refs; struct refinfo **refs;
struct grab_ref_cbdata cbdata; struct grab_ref_cbdata cbdata;
for (i = 1; i < ac; i++) { struct option opts[] = {
const char *arg = av[i]; OPT_BOOLEAN('s', "shell", &quote_shell, "quote placeholders suitably for shells"),
if (arg[0] != '-') OPT_BOOLEAN('p', "perl", &quote_perl, "quote placeholders suitably for perl"),
break; OPT_BOOLEAN( 0 , "python", &quote_python, "quote placeholders suitably for python"),
if (!strcmp(arg, "--")) { OPT_BOOLEAN( 0 , "tcl", &quote_tcl, "quote placeholders suitably for tcl"),
i++;
break;
}
if (!prefixcmp(arg, "--format=")) {
if (format)
die("more than one --format?");
format = arg + 9;
continue;
}
if (!strcmp(arg, "-s") || !strcmp(arg, "--shell") ) {
if (0 <= quote_style)
die("more than one quoting style?");
quote_style = QUOTE_SHELL;
continue;
}
if (!strcmp(arg, "-p") || !strcmp(arg, "--perl") ) {
if (0 <= quote_style)
die("more than one quoting style?");
quote_style = QUOTE_PERL;
continue;
}
if (!strcmp(arg, "--python") ) {
if (0 <= quote_style)
die("more than one quoting style?");
quote_style = QUOTE_PYTHON;
continue;
}
if (!strcmp(arg, "--tcl") ) {
if (0 <= quote_style)
die("more than one quoting style?");
quote_style = QUOTE_TCL;
continue;
}
if (!prefixcmp(arg, "--count=")) {
if (maxcount)
die("more than one --count?");
maxcount = atoi(arg + 8);
if (maxcount <= 0)
die("The number %s did not parse", arg);
continue;
}
if (!prefixcmp(arg, "--sort=")) {
struct ref_sort *s = xcalloc(1, sizeof(*s));
int len;
s->next = NULL; OPT_GROUP(""),
*sort_tail = s; OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
sort_tail = &s->next; OPT_STRING( 0 , "format", &format, "format", "format to use for the output"),
OPT_CALLBACK(0 , "sort", &sort_tail, "key",
"field name to sort on", &opt_parse_sort),
OPT_END(),
};
arg += 7; parse_options(argc, argv, opts, for_each_ref_usage, 0);
if (*arg == '-') { if (maxcount < 0) {
s->reverse = 1; error("invalid --count argument: `%d'", maxcount);
arg++; usage_with_options(for_each_ref_usage, opts);
}
len = strlen(arg);
sort->atom = parse_atom(arg, arg+len);
continue;
}
break;
} }
if (quote_style < 0) if (quote_shell + quote_perl + quote_python + quote_tcl > 1) {
quote_style = QUOTE_NONE; error("more than one quoting style ?");
usage_with_options(for_each_ref_usage, opts);
}
if (verify_format(format))
usage_with_options(for_each_ref_usage, opts);
quote_style = QUOTE_SHELL * quote_shell + QUOTE_PERL * quote_perl +
QUOTE_PYTHON * quote_python + QUOTE_TCL * quote_tcl;
if (!sort) if (!sort)
sort = default_sort(); sort = default_sort();
sort_atom_limit = used_atom_cnt; sort_atom_limit = used_atom_cnt;
if (!format)
format = "%(objectname) %(objecttype)\t%(refname)";
verify_format(format);
memset(&cbdata, 0, sizeof(cbdata)); memset(&cbdata, 0, sizeof(cbdata));
cbdata.grab_pattern = av + i; cbdata.grab_pattern = argv;
for_each_ref(grab_single_ref, &cbdata); for_each_ref(grab_single_ref, &cbdata);
refs = cbdata.grab_array; refs = cbdata.grab_array;
num_refs = cbdata.grab_cnt; num_refs = cbdata.grab_cnt;

View File

@ -8,6 +8,7 @@
#include "pack.h" #include "pack.h"
#include "cache-tree.h" #include "cache-tree.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "parse-options.h"
#define REACHABLE 0x0001 #define REACHABLE 0x0001
#define SEEN 0x0002 #define SEEN 0x0002
@ -666,9 +667,24 @@ static int fsck_cache_tree(struct cache_tree *it)
return err; return err;
} }
static const char fsck_usage[] = static char const * const fsck_usage[] = {
"git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] " "git-fsck [options] [<object>...]",
"[--strict] [--verbose] <head-sha1>*]"; NULL
};
static struct option fsck_opts[] = {
OPT__VERBOSE(&verbose),
OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"),
OPT_BOOLEAN(0, "tags", &show_tags, "report tags"),
OPT_BOOLEAN(0, "root", &show_root, "report root nodes"),
OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"),
OPT_BOOLEAN(0, "reflogs", &include_reflogs, "make reflogs head nodes (default)"),
OPT_BOOLEAN(0, "full", &check_full, "also consider alternate objects"),
OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
"write dangling objects in .git/lost-found"),
OPT_END(),
};
int cmd_fsck(int argc, const char **argv, const char *prefix) int cmd_fsck(int argc, const char **argv, const char *prefix)
{ {
@ -677,49 +693,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
track_object_refs = 1; track_object_refs = 1;
errors_found = 0; errors_found = 0;
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0);
const char *arg = argv[i]; if (write_lost_and_found) {
check_full = 1;
if (!strcmp(arg, "--unreachable")) { include_reflogs = 0;
show_unreachable = 1;
continue;
}
if (!strcmp(arg, "--tags")) {
show_tags = 1;
continue;
}
if (!strcmp(arg, "--root")) {
show_root = 1;
continue;
}
if (!strcmp(arg, "--cache")) {
keep_cache_objects = 1;
continue;
}
if (!strcmp(arg, "--no-reflogs")) {
include_reflogs = 0;
continue;
}
if (!strcmp(arg, "--full")) {
check_full = 1;
continue;
}
if (!strcmp(arg, "--strict")) {
check_strict = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
verbose = 1;
continue;
}
if (!strcmp(arg, "--lost-found")) {
check_full = 1;
include_reflogs = 0;
write_lost_and_found = 1;
continue;
}
if (*arg == '-')
usage(fsck_usage);
} }
fsck_head_link(); fsck_head_link();
@ -741,22 +718,18 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
verify_pack(p, 0); verify_pack(p, 0);
for (p = packed_git; p; p = p->next) { for (p = packed_git; p; p = p->next) {
uint32_t i, num; uint32_t j, num;
if (open_pack_index(p)) if (open_pack_index(p))
continue; continue;
num = p->num_objects; num = p->num_objects;
for (i = 0; i < num; i++) for (j = 0; j < num; j++)
fsck_sha1(nth_packed_object_sha1(p, i)); fsck_sha1(nth_packed_object_sha1(p, j));
} }
} }
heads = 0; heads = 0;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];
if (*arg == '-')
continue;
if (!get_sha1(arg, head_sha1)) { if (!get_sha1(arg, head_sha1)) {
struct object *obj = lookup_object(head_sha1); struct object *obj = lookup_object(head_sha1);
@ -783,7 +756,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
} }
if (keep_cache_objects) { if (keep_cache_objects) {
int i;
read_cache(); read_cache();
for (i = 0; i < active_nr; i++) { for (i = 0; i < active_nr; i++) {
unsigned int mode; unsigned int mode;

View File

@ -12,11 +12,15 @@
#include "builtin.h" #include "builtin.h"
#include "cache.h" #include "cache.h"
#include "parse-options.h"
#include "run-command.h" #include "run-command.h"
#define FAILED_RUN "failed to run %s" #define FAILED_RUN "failed to run %s"
static const char builtin_gc_usage[] = "git-gc [--prune] [--aggressive]"; static const char * const builtin_gc_usage[] = {
"git-gc [options]",
NULL
};
static int pack_refs = 1; static int pack_refs = 1;
static int aggressive_window = -1; static int aggressive_window = -1;
@ -165,38 +169,34 @@ static int need_to_gc(void)
int cmd_gc(int argc, const char **argv, const char *prefix) int cmd_gc(int argc, const char **argv, const char *prefix)
{ {
int i;
int prune = 0; int prune = 0;
int aggressive = 0;
int auto_gc = 0; int auto_gc = 0;
char buf[80]; char buf[80];
struct option builtin_gc_options[] = {
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced loose objects"),
OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
OPT_END()
};
git_config(gc_config); git_config(gc_config);
if (pack_refs < 0) if (pack_refs < 0)
pack_refs = !is_bare_repository(); pack_refs = !is_bare_repository();
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, builtin_gc_options, builtin_gc_usage, 0);
const char *arg = argv[i]; if (argc > 0)
if (!strcmp(arg, "--prune")) { usage_with_options(builtin_gc_usage, builtin_gc_options);
prune = 1;
continue; if (aggressive) {
append_option(argv_repack, "-f", MAX_ADD);
if (aggressive_window > 0) {
sprintf(buf, "--window=%d", aggressive_window);
append_option(argv_repack, buf, MAX_ADD);
} }
if (!strcmp(arg, "--aggressive")) {
append_option(argv_repack, "-f", MAX_ADD);
if (aggressive_window > 0) {
sprintf(buf, "--window=%d", aggressive_window);
append_option(argv_repack, buf, MAX_ADD);
}
continue;
}
if (!strcmp(arg, "--auto")) {
auto_gc = 1;
continue;
}
break;
} }
if (i != argc)
usage(builtin_gc_usage);
if (auto_gc) { if (auto_gc) {
/* /*

View File

@ -8,9 +8,12 @@
#include "dir.h" #include "dir.h"
#include "cache-tree.h" #include "cache-tree.h"
#include "path-list.h" #include "path-list.h"
#include "parse-options.h"
static const char builtin_mv_usage[] = static const char * const builtin_mv_usage[] = {
"git-mv [-n] [-f] (<source> <destination> | [-k] <source>... <destination>)"; "git-mv [options] <source>... <destination>",
NULL
};
static const char **copy_pathspec(const char *prefix, const char **pathspec, static const char **copy_pathspec(const char *prefix, const char **pathspec,
int count, int base_name) int count, int base_name)
@ -61,8 +64,14 @@ static struct lock_file lock_file;
int cmd_mv(int argc, const char **argv, const char *prefix) int cmd_mv(int argc, const char **argv, const char *prefix)
{ {
int i, newfd, count; int i, newfd;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
OPT__DRY_RUN(&show_only),
OPT_BOOLEAN('f', NULL, &force, "force move/rename even if target exists"),
OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
OPT_END(),
};
const char **source, **destination, **dest_path; const char **source, **destination, **dest_path;
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes; enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
struct stat st; struct stat st;
@ -78,52 +87,29 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (read_cache() < 0) if (read_cache() < 0)
die("index file corrupt"); die("index file corrupt");
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, builtin_mv_options, builtin_mv_usage, 0);
const char *arg = argv[i]; if (--argc < 1)
usage_with_options(builtin_mv_usage, builtin_mv_options);
if (arg[0] != '-') source = copy_pathspec(prefix, argv, argc, 0);
break; modes = xcalloc(argc, sizeof(enum update_mode));
if (!strcmp(arg, "--")) { dest_path = copy_pathspec(prefix, argv + argc, 1, 0);
i++;
break;
}
if (!strcmp(arg, "-n")) {
show_only = 1;
continue;
}
if (!strcmp(arg, "-f")) {
force = 1;
continue;
}
if (!strcmp(arg, "-k")) {
ignore_errors = 1;
continue;
}
usage(builtin_mv_usage);
}
count = argc - i - 1;
if (count < 1)
usage(builtin_mv_usage);
source = copy_pathspec(prefix, argv + i, count, 0);
modes = xcalloc(count, sizeof(enum update_mode));
dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0);
if (dest_path[0][0] == '\0') if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */ /* special case: "." was normalized to "" */
destination = copy_pathspec(dest_path[0], argv + i, count, 1); destination = copy_pathspec(dest_path[0], argv, argc, 1);
else if (!lstat(dest_path[0], &st) && else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) { S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]); dest_path[0] = add_slash(dest_path[0]);
destination = copy_pathspec(dest_path[0], argv + i, count, 1); destination = copy_pathspec(dest_path[0], argv, argc, 1);
} else { } else {
if (count != 1) if (argc != 1)
usage(builtin_mv_usage); usage_with_options(builtin_mv_usage, builtin_mv_options);
destination = dest_path; destination = dest_path;
} }
/* Checking */ /* Checking */
for (i = 0; i < count; i++) { for (i = 0; i < argc; i++) {
const char *src = source[i], *dst = destination[i]; const char *src = source[i], *dst = destination[i];
int length, src_is_dir; int length, src_is_dir;
const char *bad = NULL; const char *bad = NULL;
@ -167,13 +153,13 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (last - first > 0) { if (last - first > 0) {
source = xrealloc(source, source = xrealloc(source,
(count + last - first) (argc + last - first)
* sizeof(char *)); * sizeof(char *));
destination = xrealloc(destination, destination = xrealloc(destination,
(count + last - first) (argc + last - first)
* sizeof(char *)); * sizeof(char *));
modes = xrealloc(modes, modes = xrealloc(modes,
(count + last - first) (argc + last - first)
* sizeof(enum update_mode)); * sizeof(enum update_mode));
} }
@ -183,13 +169,13 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
for (j = 0; j < last - first; j++) { for (j = 0; j < last - first; j++) {
const char *path = const char *path =
active_cache[first + j]->name; active_cache[first + j]->name;
source[count + j] = path; source[argc + j] = path;
destination[count + j] = destination[argc + j] =
prefix_path(dst, dst_len, prefix_path(dst, dst_len,
path + length); path + length);
modes[count + j] = INDEX; modes[argc + j] = INDEX;
} }
count += last - first; argc += last - first;
} }
} else if (lstat(dst, &st) == 0) { } else if (lstat(dst, &st) == 0) {
bad = "destination exists"; bad = "destination exists";
@ -216,12 +202,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (bad) { if (bad) {
if (ignore_errors) { if (ignore_errors) {
if (--count > 0) { if (--argc > 0) {
memmove(source + i, source + i + 1, memmove(source + i, source + i + 1,
(count - i) * sizeof(char *)); (argc - i) * sizeof(char *));
memmove(destination + i, memmove(destination + i,
destination + i + 1, destination + i + 1,
(count - i) * sizeof(char *)); (argc - i) * sizeof(char *));
} }
} else } else
die ("%s, source=%s, destination=%s", die ("%s, source=%s, destination=%s",
@ -229,7 +215,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
} }
} }
for (i = 0; i < count; i++) { for (i = 0; i < argc; i++) {
const char *src = source[i], *dst = destination[i]; const char *src = source[i], *dst = destination[i];
enum update_mode mode = modes[i]; enum update_mode mode = modes[i];
if (show_only || verbose) if (show_only || verbose)
@ -253,7 +239,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
path_list_insert(dst, &added); path_list_insert(dst, &added);
} }
if (show_only) { if (show_only) {
show_list("Changed : ", &changed); show_list("Changed : ", &changed);
show_list("Adding : ", &added); show_list("Adding : ", &added);
show_list("Deleting : ", &deleted); show_list("Deleting : ", &deleted);

View File

@ -3,12 +3,10 @@
#include "commit.h" #include "commit.h"
#include "tag.h" #include "tag.h"
#include "refs.h" #include "refs.h"
#include "parse-options.h"
#define CUTOFF_DATE_SLOP 86400 /* one day */ #define CUTOFF_DATE_SLOP 86400 /* one day */
static const char name_rev_usage[] =
"git-name-rev [--tags | --refs=<pattern>] ( --all | --stdin | committish [committish...] )\n";
typedef struct rev_name { typedef struct rev_name {
const char *tip_name; const char *tip_name;
int generation; int generation;
@ -153,51 +151,41 @@ static const char* get_rev_name(struct object *o)
} }
} }
static char const * const name_rev_usage[] = {
"git-name-rev [options] ( --all | --stdin | <commit>... )",
NULL
};
int cmd_name_rev(int argc, const char **argv, const char *prefix) int cmd_name_rev(int argc, const char **argv, const char *prefix)
{ {
struct object_array revs = { 0, 0, NULL }; struct object_array revs = { 0, 0, NULL };
int as_is = 0, all = 0, transform_stdin = 0; int all = 0, transform_stdin = 0;
struct name_ref_data data = { 0, 0, NULL }; struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"),
OPT_BOOLEAN(0, "tags", &data.tags_only, "only use tags to name the commits"),
OPT_STRING(0, "refs", &data.ref_filter, "pattern",
"only use refs matching <pattern>"),
OPT_GROUP(""),
OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"),
OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"),
OPT_END(),
};
git_config(git_default_config); git_config(git_default_config);
argc = parse_options(argc, argv, opts, name_rev_usage, 0);
if (!!all + !!transform_stdin + !!argc > 1) {
error("Specify either a list, or --all, not both!");
usage_with_options(name_rev_usage, opts);
}
if (all || transform_stdin)
cutoff = 0;
if (argc < 2) for (; argc; argc--, argv++) {
usage(name_rev_usage);
for (--argc, ++argv; argc; --argc, ++argv) {
unsigned char sha1[20]; unsigned char sha1[20];
struct object *o; struct object *o;
struct commit *commit; struct commit *commit;
if (!as_is && (*argv)[0] == '-') {
if (!strcmp(*argv, "--")) {
as_is = 1;
continue;
} else if (!strcmp(*argv, "--name-only")) {
data.name_only = 1;
continue;
} else if (!strcmp(*argv, "--tags")) {
data.tags_only = 1;
continue;
} else if (!prefixcmp(*argv, "--refs=")) {
data.ref_filter = *argv + 7;
continue;
} else if (!strcmp(*argv, "--all")) {
if (argc > 1)
die("Specify either a list, or --all, not both!");
all = 1;
cutoff = 0;
continue;
} else if (!strcmp(*argv, "--stdin")) {
if (argc > 1)
die("Specify either a list, or --stdin, not both!");
transform_stdin = 1;
cutoff = 0;
continue;
}
usage(name_rev_usage);
}
if (get_sha1(*argv, sha1)) { if (get_sha1(*argv, sha1)) {
fprintf(stderr, "Could not get sha1 for %s. Skipping.\n", fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
*argv); *argv);
@ -212,10 +200,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
} }
commit = (struct commit *)o; commit = (struct commit *)o;
if (cutoff > commit->date) if (cutoff > commit->date)
cutoff = commit->date; cutoff = commit->date;
add_object_array((struct object *)commit, *argv, &revs); add_object_array((struct object *)commit, *argv, &revs);
} }

View File

@ -3,9 +3,7 @@
#include "refs.h" #include "refs.h"
#include "object.h" #include "object.h"
#include "tag.h" #include "tag.h"
#include "parse-options.h"
static const char builtin_pack_refs_usage[] =
"git-pack-refs [--all] [--prune | --no-prune]";
struct ref_to_prune { struct ref_to_prune {
struct ref_to_prune *next; struct ref_to_prune *next;
@ -117,31 +115,26 @@ static int pack_refs(unsigned int flags)
return 0; return 0;
} }
static char const * const pack_refs_usage[] = {
"git-pack-refs [options]",
NULL
};
int cmd_pack_refs(int argc, const char **argv, const char *prefix) int cmd_pack_refs(int argc, const char **argv, const char *prefix)
{ {
int i; int all = 0, prune = 1;
unsigned int flags; unsigned int flags = 0;
struct option opts[] = {
flags = PACK_REFS_PRUNE; OPT_BOOLEAN(0, "all", &all, "pack everything"),
for (i = 1; i < argc; i++) { OPT_BOOLEAN(0, "prune", &prune, "prune loose refs (default)"),
const char *arg = argv[i]; OPT_END(),
if (!strcmp(arg, "--prune")) { };
flags |= PACK_REFS_PRUNE; /* now the default */
continue;
}
if (!strcmp(arg, "--no-prune")) {
flags &= ~PACK_REFS_PRUNE;
continue;
}
if (!strcmp(arg, "--all")) {
flags |= PACK_REFS_ALL;
continue;
}
/* perhaps other parameters later... */
break;
}
if (i != argc)
usage(builtin_pack_refs_usage);
if (parse_options(argc, argv, opts, pack_refs_usage, 0))
usage_with_options(pack_refs_usage, opts);
if (prune)
flags |= PACK_REFS_PRUNE;
if (all)
flags |= PACK_REFS_ALL;
return pack_refs(flags); return pack_refs(flags);
} }

View File

@ -7,6 +7,7 @@
#include "run-command.h" #include "run-command.h"
#include "exec_cmd.h" #include "exec_cmd.h"
#include "utf8.h" #include "utf8.h"
#include "parse-options.h"
/* /*
* This implements the builtins revert and cherry-pick. * This implements the builtins revert and cherry-pick.
@ -19,51 +20,42 @@
* Copyright (c) 2005 Junio C Hamano * Copyright (c) 2005 Junio C Hamano
*/ */
static const char *revert_usage = "git-revert [--edit | --no-edit] [-n] <commit-ish>"; static const char * const revert_usage[] = {
"git-revert [options] <commit-ish>",
NULL
};
static const char *cherry_pick_usage = "git-cherry-pick [--edit] [-n] [-r] [-x] <commit-ish>"; static const char * const cherry_pick_usage[] = {
"git-cherry-pick [options] <commit-ish>",
NULL
};
static int edit; static int edit, no_replay, no_commit, needed_deref;
static int replay;
static enum { REVERT, CHERRY_PICK } action; static enum { REVERT, CHERRY_PICK } action;
static int no_commit;
static struct commit *commit; static struct commit *commit;
static int needed_deref;
static const char *me; static const char *me;
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
static void parse_options(int argc, const char **argv) static void parse_args(int argc, const char **argv)
{ {
const char *usage_str = action == REVERT ? const char * const * usage_str =
revert_usage : cherry_pick_usage; action == REVERT ? revert_usage : cherry_pick_usage;
unsigned char sha1[20]; unsigned char sha1[20];
const char *arg; const char *arg;
int i; int noop;
struct option options[] = {
OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"),
OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"),
OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"),
OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"),
OPT_END(),
};
if (argc < 2) if (parse_options(argc, argv, options, usage_str, 0) != 1)
usage(usage_str); usage_with_options(usage_str, options);
arg = argv[0];
for (i = 1; i < argc; i++) {
arg = argv[i];
if (arg[0] != '-')
break;
if (!strcmp(arg, "-n") || !strcmp(arg, "--no-commit"))
no_commit = 1;
else if (!strcmp(arg, "-e") || !strcmp(arg, "--edit"))
edit = 1;
else if (!strcmp(arg, "--no-edit"))
edit = 0;
else if (!strcmp(arg, "-x") || !strcmp(arg, "--i-really-want-"
"to-expose-my-private-commit-object-name"))
replay = 0;
else if (strcmp(arg, "-r"))
usage(usage_str);
}
if (i != argc - 1)
usage(usage_str);
arg = argv[argc - 1];
if (get_sha1(arg, sha1)) if (get_sha1(arg, sha1))
die ("Cannot find '%s'", arg); die ("Cannot find '%s'", arg);
commit = (struct commit *)parse_object(sha1); commit = (struct commit *)parse_object(sha1);
@ -243,10 +235,10 @@ static int revert_or_cherry_pick(int argc, const char **argv)
git_config(git_default_config); git_config(git_default_config);
me = action == REVERT ? "revert" : "cherry-pick"; me = action == REVERT ? "revert" : "cherry-pick";
setenv(GIT_REFLOG_ACTION, me, 0); setenv(GIT_REFLOG_ACTION, me, 0);
parse_options(argc, argv); parse_args(argc, argv);
/* this is copied from the shell script, but it's never triggered... */ /* this is copied from the shell script, but it's never triggered... */
if (action == REVERT && replay) if (action == REVERT && !no_replay)
die("revert is incompatible with replay"); die("revert is incompatible with replay");
if (no_commit) { if (no_commit) {
@ -310,7 +302,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
next = commit; next = commit;
set_author_ident_env(message); set_author_ident_env(message);
add_message_to_msg(message); add_message_to_msg(message);
if (!replay) { if (no_replay) {
add_to_msg("(cherry picked from commit "); add_to_msg("(cherry picked from commit ");
add_to_msg(sha1_to_hex(commit->object.sha1)); add_to_msg(sha1_to_hex(commit->object.sha1));
add_to_msg(")\n"); add_to_msg(")\n");
@ -388,13 +380,14 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
{ {
if (isatty(0)) if (isatty(0))
edit = 1; edit = 1;
no_replay = 1;
action = REVERT; action = REVERT;
return revert_or_cherry_pick(argc, argv); return revert_or_cherry_pick(argc, argv);
} }
int cmd_cherry_pick(int argc, const char **argv, const char *prefix) int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
{ {
replay = 1; no_replay = 0;
action = CHERRY_PICK; action = CHERRY_PICK;
return revert_or_cherry_pick(argc, argv); return revert_or_cherry_pick(argc, argv);
} }

View File

@ -8,9 +8,12 @@
#include "dir.h" #include "dir.h"
#include "cache-tree.h" #include "cache-tree.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "parse-options.h"
static const char builtin_rm_usage[] = static const char * const builtin_rm_usage[] = {
"git-rm [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>..."; "git-rm [options] [--] <file>...",
NULL
};
static struct { static struct {
int nr, alloc; int nr, alloc;
@ -121,11 +124,23 @@ static int check_local_mod(unsigned char *head, int index_only)
static struct lock_file lock_file; static struct lock_file lock_file;
static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
static int ignore_unmatch = 0;
static struct option builtin_rm_options[] = {
OPT__DRY_RUN(&show_only),
OPT__QUIET(&quiet),
OPT_BOOLEAN( 0 , "cached", &index_only, "only remove from the index"),
OPT_BOOLEAN('f', NULL, &force, "override the up-to-date check"),
OPT_BOOLEAN('r', NULL, &recursive, "allow recursive removal"),
OPT_BOOLEAN( 0 , "ignore-unmatch", &ignore_unmatch,
"exit with a zero status even if nothing matched"),
OPT_END(),
};
int cmd_rm(int argc, const char **argv, const char *prefix) int cmd_rm(int argc, const char **argv, const char *prefix)
{ {
int i, newfd; int i, newfd;
int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
int ignore_unmatch = 0;
const char **pathspec; const char **pathspec;
char *seen; char *seen;
@ -136,34 +151,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (read_cache() < 0) if (read_cache() < 0)
die("index file corrupt"); die("index file corrupt");
for (i = 1 ; i < argc ; i++) { argc = parse_options(argc, argv, builtin_rm_options, builtin_rm_usage, 0);
const char *arg = argv[i]; if (!argc)
usage_with_options(builtin_rm_usage, builtin_rm_options);
if (*arg != '-') pathspec = get_pathspec(prefix, argv);
break;
else if (!strcmp(arg, "--")) {
i++;
break;
}
else if (!strcmp(arg, "-n"))
show_only = 1;
else if (!strcmp(arg, "--cached"))
index_only = 1;
else if (!strcmp(arg, "-f"))
force = 1;
else if (!strcmp(arg, "-r"))
recursive = 1;
else if (!strcmp(arg, "--quiet"))
quiet = 1;
else if (!strcmp(arg, "--ignore-unmatch"))
ignore_unmatch = 1;
else
usage(builtin_rm_usage);
}
if (argc <= i)
usage(builtin_rm_usage);
pathspec = get_pathspec(prefix, argv + i);
seen = NULL; seen = NULL;
for (i = 0; pathspec[i] ; i++) for (i = 0; pathspec[i] ; i++)
/* nothing */; /* nothing */;

View File

@ -1,9 +1,12 @@
#include "builtin.h" #include "builtin.h"
#include "cache.h" #include "cache.h"
#include "refs.h" #include "refs.h"
#include "parse-options.h"
static const char git_symbolic_ref_usage[] = static const char * const git_symbolic_ref_usage[] = {
"git-symbolic-ref [-q] [-m <reason>] name [ref]"; "git-symbolic-ref [options] name [ref]",
NULL
};
static void check_symref(const char *HEAD, int quiet) static void check_symref(const char *HEAD, int quiet)
{ {
@ -26,44 +29,25 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
{ {
int quiet = 0; int quiet = 0;
const char *msg = NULL; const char *msg = NULL;
struct option options[] = {
OPT__QUIET(&quiet),
OPT_STRING('m', NULL, &msg, "reason", "reason of the update"),
OPT_END(),
};
git_config(git_default_config); git_config(git_default_config);
argc = parse_options(argc, argv, options, git_symbolic_ref_usage, 0);
while (1 < argc) { if (msg &&!*msg)
const char *arg = argv[1]; die("Refusing to perform update with empty message");
if (arg[0] != '-')
break;
else if (!strcmp("-q", arg))
quiet = 1;
else if (!strcmp("-m", arg)) {
argc--;
argv++;
if (argc <= 1)
break;
msg = argv[1];
if (!*msg)
die("Refusing to perform update with empty message");
}
else if (!strcmp("--", arg)) {
argc--;
argv++;
break;
}
else
die("unknown option %s", arg);
argc--;
argv++;
}
switch (argc) { switch (argc) {
case 2: case 1:
check_symref(argv[1], quiet); check_symref(argv[0], quiet);
break; break;
case 3: case 2:
create_symref(argv[1], argv[2], msg); create_symref(argv[0], argv[1], msg);
break; break;
default: default:
usage(git_symbolic_ref_usage); usage_with_options(git_symbolic_ref_usage, options);
} }
return 0; return 0;
} }

View File

@ -1,59 +1,44 @@
#include "cache.h" #include "cache.h"
#include "refs.h" #include "refs.h"
#include "builtin.h" #include "builtin.h"
#include "parse-options.h"
static const char git_update_ref_usage[] = static const char * const git_update_ref_usage[] = {
"git-update-ref [-m <reason>] (-d <refname> <value> | [--no-deref] <refname> <value> [<oldval>])"; "git-update-ref [options] -d <refname> <oldval>",
"git-update-ref [options] <refname> <newval> [<oldval>]",
NULL
};
int cmd_update_ref(int argc, const char **argv, const char *prefix) int cmd_update_ref(int argc, const char **argv, const char *prefix)
{ {
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL; const char *refname, *value, *oldval, *msg=NULL;
unsigned char sha1[20], oldsha1[20]; unsigned char sha1[20], oldsha1[20];
int i, delete, ref_flags; int delete = 0, no_deref = 0;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
OPT_BOOLEAN( 0 , "no-deref", &no_deref,
"update <refname> not the one it points to"),
OPT_END(),
};
delete = 0;
ref_flags = 0;
git_config(git_default_config); git_config(git_default_config);
argc = parse_options(argc, argv, options, git_update_ref_usage, 0);
if (msg && !*msg)
die("Refusing to perform update with empty message.");
for (i = 1; i < argc; i++) { if (argc < 2 || argc > 3)
if (!strcmp("-m", argv[i])) { usage_with_options(git_update_ref_usage, options);
if (i+1 >= argc) refname = argv[0];
usage(git_update_ref_usage); value = argv[1];
msg = argv[++i]; oldval = argv[2];
if (!*msg)
die("Refusing to perform update with empty message.");
continue;
}
if (!strcmp("-d", argv[i])) {
delete = 1;
continue;
}
if (!strcmp("--no-deref", argv[i])) {
ref_flags |= REF_NODEREF;
continue;
}
if (!refname) {
refname = argv[i];
continue;
}
if (!value) {
value = argv[i];
continue;
}
if (!oldval) {
oldval = argv[i];
continue;
}
}
if (!refname || !value)
usage(git_update_ref_usage);
if (get_sha1(value, sha1)) if (get_sha1(value, sha1))
die("%s: not a valid SHA1", value); die("%s: not a valid SHA1", value);
if (delete) { if (delete) {
if (oldval) if (oldval)
usage(git_update_ref_usage); usage_with_options(git_update_ref_usage, options);
return delete_ref(refname, sha1); return delete_ref(refname, sha1);
} }
@ -62,5 +47,5 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
die("%s: not a valid old SHA1", oldval); die("%s: not a valid old SHA1", oldval);
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL, return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
ref_flags, DIE_ON_ERR); no_deref ? REF_NODEREF : 0, DIE_ON_ERR);
} }

322
parse-options.c Normal file
View File

@ -0,0 +1,322 @@
#include "git-compat-util.h"
#include "parse-options.h"
#define OPT_SHORT 1
#define OPT_UNSET 2
struct optparse_t {
const char **argv;
int argc;
const char *opt;
};
static inline const char *get_arg(struct optparse_t *p)
{
if (p->opt) {
const char *res = p->opt;
p->opt = NULL;
return res;
}
p->argc--;
return *++p->argv;
}
static inline const char *skip_prefix(const char *str, const char *prefix)
{
size_t len = strlen(prefix);
return strncmp(str, prefix, len) ? NULL : str + len;
}
static int opterror(const struct option *opt, const char *reason, int flags)
{
if (flags & OPT_SHORT)
return error("switch `%c' %s", opt->short_name, reason);
if (flags & OPT_UNSET)
return error("option `no-%s' %s", opt->long_name, reason);
return error("option `%s' %s", opt->long_name, reason);
}
static int get_value(struct optparse_t *p,
const struct option *opt, int flags)
{
const char *s, *arg;
arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
if (p->opt && (flags & OPT_UNSET))
return opterror(opt, "takes no value", flags);
switch (opt->type) {
case OPTION_BOOLEAN:
if (!(flags & OPT_SHORT) && p->opt)
return opterror(opt, "takes no value", flags);
if (flags & OPT_UNSET)
*(int *)opt->value = 0;
else
(*(int *)opt->value)++;
return 0;
case OPTION_STRING:
if (flags & OPT_UNSET) {
*(const char **)opt->value = (const char *)NULL;
return 0;
}
if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
*(const char **)opt->value = (const char *)opt->defval;
return 0;
}
if (!arg)
return opterror(opt, "requires a value", flags);
*(const char **)opt->value = get_arg(p);
return 0;
case OPTION_CALLBACK:
if (flags & OPT_UNSET)
return (*opt->callback)(opt, NULL, 1);
if (opt->flags & PARSE_OPT_NOARG) {
if (p->opt && !(flags & OPT_SHORT))
return opterror(opt, "takes no value", flags);
return (*opt->callback)(opt, NULL, 0);
}
if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
return (*opt->callback)(opt, NULL, 0);
if (!arg)
return opterror(opt, "requires a value", flags);
return (*opt->callback)(opt, get_arg(p), 0);
case OPTION_INTEGER:
if (flags & OPT_UNSET) {
*(int *)opt->value = 0;
return 0;
}
if (opt->flags & PARSE_OPT_OPTARG && (!arg || !isdigit(*arg))) {
*(int *)opt->value = opt->defval;
return 0;
}
if (!arg)
return opterror(opt, "requires a value", flags);
*(int *)opt->value = strtol(get_arg(p), (char **)&s, 10);
if (*s)
return opterror(opt, "expects a numerical value", flags);
return 0;
default:
die("should not happen, someone must be hit on the forehead");
}
}
static int parse_short_opt(struct optparse_t *p, const struct option *options)
{
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
return get_value(p, options, OPT_SHORT);
}
}
return error("unknown switch `%c'", *p->opt);
}
static int parse_long_opt(struct optparse_t *p, const char *arg,
const struct option *options)
{
const char *arg_end = strchr(arg, '=');
const struct option *abbrev_option = NULL;
int abbrev_flags = 0;
if (!arg_end)
arg_end = arg + strlen(arg);
for (; options->type != OPTION_END; options++) {
const char *rest;
int flags = 0;
if (!options->long_name)
continue;
rest = skip_prefix(arg, options->long_name);
if (!rest) {
/* abbreviated? */
if (!strncmp(options->long_name, arg, arg_end - arg)) {
is_abbreviated:
if (abbrev_option)
return error("Ambiguous option: %s "
"(could be --%s%s or --%s%s)",
arg,
(flags & OPT_UNSET) ?
"no-" : "",
options->long_name,
(abbrev_flags & OPT_UNSET) ?
"no-" : "",
abbrev_option->long_name);
if (!(flags & OPT_UNSET) && *arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
abbrev_flags = flags;
continue;
}
/* negated and abbreviated very much? */
if (!prefixcmp("no-", arg)) {
flags |= OPT_UNSET;
goto is_abbreviated;
}
/* negated? */
if (strncmp(arg, "no-", 3))
continue;
flags |= OPT_UNSET;
rest = skip_prefix(arg + 3, options->long_name);
/* abbreviated and negated? */
if (!rest && !prefixcmp(options->long_name, arg + 3))
goto is_abbreviated;
if (!rest)
continue;
}
if (*rest) {
if (*rest != '=')
continue;
p->opt = rest + 1;
}
return get_value(p, options, flags);
}
if (abbrev_option)
return get_value(p, abbrev_option, abbrev_flags);
return error("unknown option `%s'", arg);
}
int parse_options(int argc, const char **argv, const struct option *options,
const char * const usagestr[], int flags)
{
struct optparse_t args = { argv + 1, argc - 1, NULL };
int j = 0;
for (; args.argc; args.argc--, args.argv++) {
const char *arg = args.argv[0];
if (*arg != '-' || !arg[1]) {
argv[j++] = args.argv[0];
continue;
}
if (arg[1] != '-') {
args.opt = arg + 1;
do {
if (*args.opt == 'h')
usage_with_options(usagestr, options);
if (parse_short_opt(&args, options) < 0)
usage_with_options(usagestr, options);
} while (args.opt);
continue;
}
if (!arg[2]) { /* "--" */
if (!(flags & PARSE_OPT_KEEP_DASHDASH)) {
args.argc--;
args.argv++;
}
break;
}
if (!strcmp(arg + 2, "help"))
usage_with_options(usagestr, options);
if (parse_long_opt(&args, arg + 2, options))
usage_with_options(usagestr, options);
}
memmove(argv + j, args.argv, args.argc * sizeof(*argv));
argv[j + args.argc] = NULL;
return j + args.argc;
}
#define USAGE_OPTS_WIDTH 24
#define USAGE_GAP 2
void usage_with_options(const char * const *usagestr,
const struct option *opts)
{
fprintf(stderr, "usage: %s\n", *usagestr++);
while (*usagestr && **usagestr)
fprintf(stderr, " or: %s\n", *usagestr++);
while (*usagestr)
fprintf(stderr, " %s\n", *usagestr++);
if (opts->type != OPTION_GROUP)
fputc('\n', stderr);
for (; opts->type != OPTION_END; opts++) {
size_t pos;
int pad;
if (opts->type == OPTION_GROUP) {
fputc('\n', stderr);
if (*opts->help)
fprintf(stderr, "%s\n", opts->help);
continue;
}
pos = fprintf(stderr, " ");
if (opts->short_name)
pos += fprintf(stderr, "-%c", opts->short_name);
if (opts->long_name && opts->short_name)
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
switch (opts->type) {
case OPTION_INTEGER:
if (opts->flags & PARSE_OPT_OPTARG)
pos += fprintf(stderr, " [<n>]");
else
pos += fprintf(stderr, " <n>");
break;
case OPTION_CALLBACK:
if (opts->flags & PARSE_OPT_NOARG)
break;
/* FALLTHROUGH */
case OPTION_STRING:
if (opts->argh) {
if (opts->flags & PARSE_OPT_OPTARG)
pos += fprintf(stderr, " [<%s>]", opts->argh);
else
pos += fprintf(stderr, " <%s>", opts->argh);
} else {
if (opts->flags & PARSE_OPT_OPTARG)
pos += fprintf(stderr, " [...]");
else
pos += fprintf(stderr, " ...");
}
break;
default:
break;
}
if (pos <= USAGE_OPTS_WIDTH)
pad = USAGE_OPTS_WIDTH - pos;
else {
fputc('\n', stderr);
pad = USAGE_OPTS_WIDTH;
}
fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
}
fputc('\n', stderr);
exit(129);
}
/*----- some often used options -----*/
#include "cache.h"
int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
{
int v;
if (!arg) {
v = unset ? 0 : DEFAULT_ABBREV;
} else {
v = strtol(arg, (char **)&arg, 10);
if (*arg)
return opterror(opt, "expects a numerical value", 0);
if (v && v < MINIMUM_ABBREV)
v = MINIMUM_ABBREV;
else if (v > 40)
v = 40;
}
*(int *)(opt->value) = v;
return 0;
}

70
parse-options.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef PARSE_OPTIONS_H
#define PARSE_OPTIONS_H
enum parse_opt_type {
OPTION_END,
OPTION_GROUP,
OPTION_BOOLEAN,
OPTION_STRING,
OPTION_INTEGER,
OPTION_CALLBACK,
};
enum parse_opt_flags {
PARSE_OPT_KEEP_DASHDASH = 1,
};
enum parse_opt_option_flags {
PARSE_OPT_OPTARG = 1,
PARSE_OPT_NOARG = 2,
};
struct option;
typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
struct option {
enum parse_opt_type type;
int short_name;
const char *long_name;
void *value;
const char *argh;
const char *help;
int flags;
parse_opt_cb *callback;
/* holds default value for PARSE_OPT_OPTARG,
though callbacks can use it like they want */
intptr_t defval;
};
#define OPT_END() { OPTION_END }
#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
#define OPT_CALLBACK(s, l, v, a, h, f) \
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
/* parse_options() will filter out the processed options and leave the
* non-option argments in argv[].
* Returns the number of arguments left in argv[].
*/
extern int parse_options(int argc, const char **argv,
const struct option *options,
const char * const usagestr[], int flags);
extern NORETURN void usage_with_options(const char * const *usagestr,
const struct option *options);
/*----- some often used options -----*/
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose")
#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet")
#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run")
#define OPT__ABBREV(var) \
{ OPTION_CALLBACK, 0, "abbrev", (var), "n", \
"use <n> digits to display SHA-1s", \
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
#endif

93
t/t0040-parse-options.sh Executable file
View File

@ -0,0 +1,93 @@
#!/bin/sh
#
# Copyright (c) 2007 Johannes Schindelin
#
test_description='our own option parser'
. ./test-lib.sh
cat > expect.err << EOF
usage: test-parse-options <options>
-b, --boolean get a boolean
-i, --integer <n> get a integer
-j <n> get a integer, too
string options
-s, --string <string>
get a string
--string2 <str> get another string
EOF
test_expect_success 'test help' '
! test-parse-options -h > output 2> output.err &&
test ! -s output &&
git diff expect.err output.err
'
cat > expect << EOF
boolean: 2
integer: 1729
string: 123
EOF
test_expect_success 'short options' '
test-parse-options -s123 -b -i 1729 -b > output 2> output.err &&
git diff expect output &&
test ! -s output.err
'
cat > expect << EOF
boolean: 2
integer: 1729
string: 321
EOF
test_expect_success 'long options' '
test-parse-options --boolean --integer 1729 --boolean --string2=321 \
> output 2> output.err &&
test ! -s output.err &&
git diff expect output
'
cat > expect << EOF
boolean: 1
integer: 13
string: 123
arg 00: a1
arg 01: b1
arg 02: --boolean
EOF
test_expect_success 'intermingled arguments' '
test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \
> output 2> output.err &&
test ! -s output.err &&
git diff expect output
'
cat > expect << EOF
boolean: 0
integer: 2
string: (not set)
EOF
test_expect_success 'unambiguously abbreviated option' '
test-parse-options --int 2 --boolean --no-bo > output 2> output.err &&
test ! -s output.err &&
git diff expect output
'
test_expect_success 'unambiguously abbreviated option with "="' '
test-parse-options --int=2 > output 2> output.err &&
test ! -s output.err &&
git diff expect output
'
test_expect_failure 'ambiguously abbreviated option' '
test-parse-options --strin 123;
test $? != 129
'
test_done

0
t/t6300-for-each-ref.sh Normal file → Executable file
View File

35
test-parse-options.c Normal file
View File

@ -0,0 +1,35 @@
#include "cache.h"
#include "parse-options.h"
static int boolean = 0;
static int integer = 0;
static char *string = NULL;
int main(int argc, const char **argv)
{
const char *usage[] = {
"test-parse-options <options>",
NULL
};
struct option options[] = {
OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
OPT_INTEGER('i', "integer", &integer, "get a integer"),
OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
OPT_GROUP("string options"),
OPT_STRING('s', "string", &string, "string", "get a string"),
OPT_STRING(0, "string2", &string, "str", "get another string"),
OPT_END(),
};
int i;
argc = parse_options(argc, argv, options, usage, 0);
printf("boolean: %d\n", boolean);
printf("integer: %d\n", integer);
printf("string: %s\n", string ? string : "(not set)");
for (i = 0; i < argc; i++)
printf("arg %02d: %s\n", i, argv[i]);
return 0;
}