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:
commit
3d66dc9657
1
.gitignore
vendored
1
.gitignore
vendored
@ -153,6 +153,7 @@ test-delta
|
||||
test-dump-cache-tree
|
||||
test-genrandom
|
||||
test-match-trees
|
||||
test-parse-options
|
||||
test-sha1
|
||||
common-cmds.h
|
||||
*.tar.gz
|
||||
|
@ -50,10 +50,10 @@ OPTIONS
|
||||
and `dir/file2`) can be given to add all files in the
|
||||
directory, recursively.
|
||||
|
||||
-n::
|
||||
-n, \--dry-run::
|
||||
Don't actually add the file(s), just show if they exist.
|
||||
|
||||
-v::
|
||||
-v, \--verbose::
|
||||
Be verbose.
|
||||
|
||||
-f::
|
||||
|
@ -85,7 +85,7 @@ OPTIONS
|
||||
-a::
|
||||
List both remote-tracking branches and local branches.
|
||||
|
||||
-v::
|
||||
-v, --verbose::
|
||||
Show sha1 and commit subject line for each head.
|
||||
|
||||
--abbrev=<length>::
|
||||
|
@ -34,7 +34,7 @@ OPTIONS
|
||||
condition. An error happens when a source is neither existing nor
|
||||
controlled by GIT, or when it would overwrite an existing
|
||||
file unless '-f' is given.
|
||||
-n::
|
||||
-n, \--dry-run::
|
||||
Do nothing; only show what would happen
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ OPTIONS
|
||||
-f::
|
||||
Override the up-to-date check.
|
||||
|
||||
-n::
|
||||
-n, \--dry-run::
|
||||
Don't actually remove the file(s), just show if they exist in
|
||||
the index.
|
||||
|
||||
@ -51,7 +51,7 @@ OPTIONS
|
||||
\--ignore-unmatch::
|
||||
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)
|
||||
for each file removed. This option suppresses that output.
|
||||
|
||||
|
@ -26,7 +26,7 @@ a regular file whose contents is `ref: refs/heads/master`.
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
-q::
|
||||
-q, --quiet::
|
||||
Do not issue an error message if the <name> is not a
|
||||
symbolic ref but a detached HEAD; instead exit with
|
||||
non-zero status silently.
|
||||
|
6
Makefile
6
Makefile
@ -289,7 +289,7 @@ LIB_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 \
|
||||
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.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) \
|
||||
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 \
|
||||
transport.o bundle.o walker.o
|
||||
transport.o bundle.o walker.o parse-options.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
@ -974,7 +974,7 @@ endif
|
||||
|
||||
### 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)
|
||||
|
||||
|
@ -13,9 +13,12 @@
|
||||
#include "commit.h"
|
||||
#include "revision.h"
|
||||
#include "run-command.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char builtin_add_usage[] =
|
||||
"git-add [-n] [-v] [-f] [--interactive | -i] [-u] [--refresh] [--] <filepattern>...";
|
||||
static const char * const builtin_add_usage[] = {
|
||||
"git-add [options] [--] <filepattern>...",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int take_worktree_changes;
|
||||
static const char *excludes_file;
|
||||
@ -162,21 +165,30 @@ static struct lock_file lock_file;
|
||||
static const char ignore_error[] =
|
||||
"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 i, newfd;
|
||||
int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
||||
int i, newfd, orig_argc = argc;
|
||||
const char **pathspec;
|
||||
struct dir_struct dir;
|
||||
int add_interactive = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp("--interactive", argv[i]) ||
|
||||
!strcmp("-i", argv[i]))
|
||||
add_interactive++;
|
||||
}
|
||||
argc = parse_options(argc, argv, builtin_add_options,
|
||||
builtin_add_usage, 0);
|
||||
if (add_interactive) {
|
||||
if (argc != 2)
|
||||
if (add_interactive != 1 || orig_argc != 2)
|
||||
die("add --interactive does not take any parameters");
|
||||
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);
|
||||
|
||||
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 (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
add_files_to_cache(verbose, prefix, argv + i);
|
||||
add_files_to_cache(verbose, prefix, argv);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (argc <= i) {
|
||||
if (argc == 0) {
|
||||
fprintf(stderr, "Nothing specified, nothing added.\n");
|
||||
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
|
||||
return 0;
|
||||
}
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
|
||||
if (refresh_only) {
|
||||
refresh(verbose, pathspec);
|
||||
|
133
builtin-branch.c
133
builtin-branch.c
@ -11,9 +11,15 @@
|
||||
#include "commit.h"
|
||||
#include "builtin.h"
|
||||
#include "remote.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char 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]]";
|
||||
static const char * const builtin_branch_usage[] = {
|
||||
"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_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 verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
|
||||
int reflog = 0, track;
|
||||
int kinds = REF_LOCAL_BRANCH;
|
||||
int i;
|
||||
int kinds = REF_LOCAL_BRANCH, kind_remote = 0, kind_any = 0;
|
||||
|
||||
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);
|
||||
track = branch_track;
|
||||
argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(arg, "--track")) {
|
||||
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")) {
|
||||
delete |= force_delete;
|
||||
rename |= force_rename;
|
||||
if (kind_remote)
|
||||
kinds = REF_REMOTE_BRANCH;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-a")) {
|
||||
if (kind_any)
|
||||
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)
|
||||
if (abbrev && 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) ||
|
||||
(rename && force_create))
|
||||
usage(builtin_branch_usage);
|
||||
usage_with_options(builtin_branch_usage, options);
|
||||
|
||||
head = resolve_ref("HEAD", head_sha1, 0, NULL);
|
||||
if (!head)
|
||||
@ -599,26 +557,25 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
head = xstrdup(head);
|
||||
if (!strcmp(head, "HEAD")) {
|
||||
detached = 1;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (prefixcmp(head, "refs/heads/"))
|
||||
die("HEAD not found below refs/heads!");
|
||||
head += 11;
|
||||
}
|
||||
|
||||
if (delete)
|
||||
return delete_branches(argc - i, argv + i, force_delete, kinds);
|
||||
else if (i == argc)
|
||||
return delete_branches(argc, argv, force_delete, kinds);
|
||||
else if (argc == 0)
|
||||
print_ref_list(kinds, detached, verbose, abbrev);
|
||||
else if (rename && (i == argc - 1))
|
||||
rename_branch(head, argv[i], force_rename);
|
||||
else if (rename && (i == argc - 2))
|
||||
rename_branch(argv[i], argv[i + 1], force_rename);
|
||||
else if (i == argc - 1 || i == argc - 2)
|
||||
create_branch(argv[i], (i == argc - 2) ? argv[i+1] : head,
|
||||
else if (rename && (argc == 1))
|
||||
rename_branch(head, argv[0], force_rename);
|
||||
else if (rename && (argc == 2))
|
||||
rename_branch(argv[0], argv[1], force_rename);
|
||||
else if (argc <= 2)
|
||||
create_branch(argv[0], (argc == 2) ? argv[1] : head,
|
||||
force_create, reflog, track);
|
||||
else
|
||||
usage(builtin_branch_usage);
|
||||
usage_with_options(builtin_branch_usage, options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,8 +6,7 @@
|
||||
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
|
||||
static const char count_objects_usage[] = "git-count-objects [-v]";
|
||||
#include "parse-options.h"
|
||||
|
||||
static void count_objects(DIR *d, char *path, int len, int verbose,
|
||||
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 verbose = 0;
|
||||
int i, verbose = 0;
|
||||
const char *objdir = get_object_directory();
|
||||
int len = strlen(objdir);
|
||||
char *path = xmalloc(len + 50);
|
||||
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
|
||||
unsigned long loose_size = 0;
|
||||
struct option opts[] = {
|
||||
OPT__VERBOSE(&verbose),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
for (i = 1; i < ac; i++) {
|
||||
const char *arg = av[i];
|
||||
if (*arg != '-')
|
||||
break;
|
||||
else if (!strcmp(arg, "-v"))
|
||||
verbose = 1;
|
||||
else
|
||||
usage(count_objects_usage);
|
||||
}
|
||||
|
||||
argc = parse_options(argc, argv, opts, count_objects_usage, 0);
|
||||
/* we do not take arguments other than flags for now */
|
||||
if (i < ac)
|
||||
usage(count_objects_usage);
|
||||
if (argc)
|
||||
usage_with_options(count_objects_usage, opts);
|
||||
memcpy(path, objdir, len);
|
||||
if (len && objdir[len-1] != '/')
|
||||
path[len++] = '/';
|
||||
|
@ -4,12 +4,15 @@
|
||||
#include "refs.h"
|
||||
#include "builtin.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
#define SEEN (1u<<0)
|
||||
#define MAX_TAGS (FLAG_BITS - 1)
|
||||
|
||||
static const char describe_usage[] =
|
||||
"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*";
|
||||
static const char * const describe_usage[] = {
|
||||
"git-describe [options] <committish>*",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int debug; /* Display lots of verbose info */
|
||||
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 i;
|
||||
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++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (*arg != '-')
|
||||
break;
|
||||
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);
|
||||
argc = parse_options(argc, argv, options, describe_usage, 0);
|
||||
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;
|
||||
|
||||
if (contains) {
|
||||
const char **args = xmalloc((4 + argc - i) * sizeof(char*));
|
||||
const char **args = xmalloc((4 + argc) * sizeof(char*));
|
||||
args[0] = "name-rev";
|
||||
args[1] = "--name-only";
|
||||
args[2] = "--tags";
|
||||
memcpy(args + 3, argv + i, (argc - i) * sizeof(char*));
|
||||
args[3 + argc - i] = NULL;
|
||||
return cmd_name_rev(3 + argc - i, args, prefix);
|
||||
memcpy(args + 3, argv, argc * sizeof(char*));
|
||||
args[3 + argc] = NULL;
|
||||
return cmd_name_rev(3 + argc, args, prefix);
|
||||
}
|
||||
|
||||
if (argc <= i)
|
||||
if (argc == 0) {
|
||||
describe("HEAD", 1);
|
||||
else
|
||||
while (i < argc) {
|
||||
describe(argv[i], (i == argc - 1));
|
||||
i++;
|
||||
} else {
|
||||
while (argc-- > 0) {
|
||||
describe(*argv++, argc == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "tree.h"
|
||||
#include "blob.h"
|
||||
#include "quote.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
/* Quoting styles */
|
||||
#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
|
||||
* the used atoms.
|
||||
*/
|
||||
static void verify_format(const char *format)
|
||||
static int verify_format(const char *format)
|
||||
{
|
||||
const char *cp, *sp;
|
||||
for (cp = format; *cp && (sp = find_next(cp)); ) {
|
||||
const char *ep = strchr(sp, ')');
|
||||
if (!ep)
|
||||
die("malformatted format string %s", sp);
|
||||
return error("malformatted format string %s", sp);
|
||||
/* sp points at "%(" and ep points at the closing ")" */
|
||||
parse_atom(sp + 2, ep);
|
||||
cp = ep + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -800,94 +802,76 @@ static struct ref_sort *default_sort(void)
|
||||
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)
|
||||
{
|
||||
int i, num_refs;
|
||||
const char *format = NULL;
|
||||
struct ref_sort *sort = NULL, **sort_tail = &sort;
|
||||
int maxcount = 0;
|
||||
int quote_style = -1; /* unspecified yet */
|
||||
struct refinfo **refs;
|
||||
struct grab_ref_cbdata cbdata;
|
||||
|
||||
for (i = 1; i < ac; i++) {
|
||||
const char *arg = av[i];
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
if (!strcmp(arg, "--")) {
|
||||
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));
|
||||
struct ref_sort **sort_tail = opt->value;
|
||||
struct ref_sort *s;
|
||||
int len;
|
||||
|
||||
s->next = NULL;
|
||||
*sort_tail = s;
|
||||
if (!arg) /* should --no-sort void the list ? */
|
||||
return -1;
|
||||
|
||||
*sort_tail = s = xcalloc(1, sizeof(*s));
|
||||
sort_tail = &s->next;
|
||||
|
||||
arg += 7;
|
||||
if (*arg == '-') {
|
||||
s->reverse = 1;
|
||||
arg++;
|
||||
}
|
||||
len = strlen(arg);
|
||||
sort->atom = parse_atom(arg, arg+len);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (quote_style < 0)
|
||||
quote_style = QUOTE_NONE;
|
||||
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;
|
||||
const char *format = "%(objectname) %(objecttype)\t%(refname)";
|
||||
struct ref_sort *sort = NULL, **sort_tail = &sort;
|
||||
int maxcount = 0, quote_style;
|
||||
int quote_shell = 0, quote_perl = 0, quote_python = 0, quote_tcl = 0;
|
||||
struct refinfo **refs;
|
||||
struct grab_ref_cbdata cbdata;
|
||||
|
||||
struct option opts[] = {
|
||||
OPT_BOOLEAN('s', "shell", "e_shell, "quote placeholders suitably for shells"),
|
||||
OPT_BOOLEAN('p', "perl", "e_perl, "quote placeholders suitably for perl"),
|
||||
OPT_BOOLEAN( 0 , "python", "e_python, "quote placeholders suitably for python"),
|
||||
OPT_BOOLEAN( 0 , "tcl", "e_tcl, "quote placeholders suitably for tcl"),
|
||||
|
||||
OPT_GROUP(""),
|
||||
OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
|
||||
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(),
|
||||
};
|
||||
|
||||
parse_options(argc, argv, opts, for_each_ref_usage, 0);
|
||||
if (maxcount < 0) {
|
||||
error("invalid --count argument: `%d'", maxcount);
|
||||
usage_with_options(for_each_ref_usage, opts);
|
||||
}
|
||||
if (quote_shell + quote_perl + quote_python + quote_tcl > 1) {
|
||||
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)
|
||||
sort = default_sort();
|
||||
sort_atom_limit = used_atom_cnt;
|
||||
if (!format)
|
||||
format = "%(objectname) %(objecttype)\t%(refname)";
|
||||
|
||||
verify_format(format);
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
cbdata.grab_pattern = av + i;
|
||||
cbdata.grab_pattern = argv;
|
||||
for_each_ref(grab_single_ref, &cbdata);
|
||||
refs = cbdata.grab_array;
|
||||
num_refs = cbdata.grab_cnt;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "pack.h"
|
||||
#include "cache-tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
#define REACHABLE 0x0001
|
||||
#define SEEN 0x0002
|
||||
@ -666,9 +667,24 @@ static int fsck_cache_tree(struct cache_tree *it)
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char fsck_usage[] =
|
||||
"git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] "
|
||||
"[--strict] [--verbose] <head-sha1>*]";
|
||||
static char const * const fsck_usage[] = {
|
||||
"git-fsck [options] [<object>...]",
|
||||
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)
|
||||
{
|
||||
@ -677,49 +693,10 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
track_object_refs = 1;
|
||||
errors_found = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (!strcmp(arg, "--unreachable")) {
|
||||
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")) {
|
||||
argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0);
|
||||
if (write_lost_and_found) {
|
||||
check_full = 1;
|
||||
include_reflogs = 0;
|
||||
write_lost_and_found = 1;
|
||||
continue;
|
||||
}
|
||||
if (*arg == '-')
|
||||
usage(fsck_usage);
|
||||
}
|
||||
|
||||
fsck_head_link();
|
||||
@ -741,22 +718,18 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
verify_pack(p, 0);
|
||||
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
uint32_t i, num;
|
||||
uint32_t j, num;
|
||||
if (open_pack_index(p))
|
||||
continue;
|
||||
num = p->num_objects;
|
||||
for (i = 0; i < num; i++)
|
||||
fsck_sha1(nth_packed_object_sha1(p, i));
|
||||
for (j = 0; j < num; j++)
|
||||
fsck_sha1(nth_packed_object_sha1(p, j));
|
||||
}
|
||||
}
|
||||
|
||||
heads = 0;
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (*arg == '-')
|
||||
continue;
|
||||
|
||||
if (!get_sha1(arg, 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) {
|
||||
int i;
|
||||
read_cache();
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
unsigned int mode;
|
||||
|
36
builtin-gc.c
36
builtin-gc.c
@ -12,11 +12,15 @@
|
||||
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "parse-options.h"
|
||||
#include "run-command.h"
|
||||
|
||||
#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 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 i;
|
||||
int prune = 0;
|
||||
int aggressive = 0;
|
||||
int auto_gc = 0;
|
||||
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);
|
||||
|
||||
if (pack_refs < 0)
|
||||
pack_refs = !is_bare_repository();
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--prune")) {
|
||||
prune = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--aggressive")) {
|
||||
argc = parse_options(argc, argv, builtin_gc_options, builtin_gc_usage, 0);
|
||||
if (argc > 0)
|
||||
usage_with_options(builtin_gc_usage, builtin_gc_options);
|
||||
|
||||
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);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--auto")) {
|
||||
auto_gc = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i != argc)
|
||||
usage(builtin_gc_usage);
|
||||
|
||||
if (auto_gc) {
|
||||
/*
|
||||
|
82
builtin-mv.c
82
builtin-mv.c
@ -8,9 +8,12 @@
|
||||
#include "dir.h"
|
||||
#include "cache-tree.h"
|
||||
#include "path-list.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char builtin_mv_usage[] =
|
||||
"git-mv [-n] [-f] (<source> <destination> | [-k] <source>... <destination>)";
|
||||
static const char * const builtin_mv_usage[] = {
|
||||
"git-mv [options] <source>... <destination>",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
||||
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 i, newfd, count;
|
||||
int i, newfd;
|
||||
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;
|
||||
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
|
||||
struct stat st;
|
||||
@ -78,52 +87,29 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
argc = parse_options(argc, argv, builtin_mv_options, builtin_mv_usage, 0);
|
||||
if (--argc < 1)
|
||||
usage_with_options(builtin_mv_usage, builtin_mv_options);
|
||||
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
if (!strcmp(arg, "--")) {
|
||||
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);
|
||||
source = copy_pathspec(prefix, argv, argc, 0);
|
||||
modes = xcalloc(argc, sizeof(enum update_mode));
|
||||
dest_path = copy_pathspec(prefix, argv + argc, 1, 0);
|
||||
|
||||
if (dest_path[0][0] == '\0')
|
||||
/* 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) &&
|
||||
S_ISDIR(st.st_mode)) {
|
||||
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 {
|
||||
if (count != 1)
|
||||
usage(builtin_mv_usage);
|
||||
if (argc != 1)
|
||||
usage_with_options(builtin_mv_usage, builtin_mv_options);
|
||||
destination = dest_path;
|
||||
}
|
||||
|
||||
/* Checking */
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
const char *src = source[i], *dst = destination[i];
|
||||
int length, src_is_dir;
|
||||
const char *bad = NULL;
|
||||
@ -167,13 +153,13 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (last - first > 0) {
|
||||
source = xrealloc(source,
|
||||
(count + last - first)
|
||||
(argc + last - first)
|
||||
* sizeof(char *));
|
||||
destination = xrealloc(destination,
|
||||
(count + last - first)
|
||||
(argc + last - first)
|
||||
* sizeof(char *));
|
||||
modes = xrealloc(modes,
|
||||
(count + last - first)
|
||||
(argc + last - first)
|
||||
* 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++) {
|
||||
const char *path =
|
||||
active_cache[first + j]->name;
|
||||
source[count + j] = path;
|
||||
destination[count + j] =
|
||||
source[argc + j] = path;
|
||||
destination[argc + j] =
|
||||
prefix_path(dst, dst_len,
|
||||
path + length);
|
||||
modes[count + j] = INDEX;
|
||||
modes[argc + j] = INDEX;
|
||||
}
|
||||
count += last - first;
|
||||
argc += last - first;
|
||||
}
|
||||
} else if (lstat(dst, &st) == 0) {
|
||||
bad = "destination exists";
|
||||
@ -216,12 +202,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (bad) {
|
||||
if (ignore_errors) {
|
||||
if (--count > 0) {
|
||||
if (--argc > 0) {
|
||||
memmove(source + i, source + i + 1,
|
||||
(count - i) * sizeof(char *));
|
||||
(argc - i) * sizeof(char *));
|
||||
memmove(destination + i,
|
||||
destination + i + 1,
|
||||
(count - i) * sizeof(char *));
|
||||
(argc - i) * sizeof(char *));
|
||||
}
|
||||
} else
|
||||
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];
|
||||
enum update_mode mode = modes[i];
|
||||
if (show_only || verbose)
|
||||
|
@ -3,12 +3,10 @@
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
#include "refs.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
#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 {
|
||||
const char *tip_name;
|
||||
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)
|
||||
{
|
||||
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 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);
|
||||
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)
|
||||
usage(name_rev_usage);
|
||||
|
||||
for (--argc, ++argv; argc; --argc, ++argv) {
|
||||
for (; argc; argc--, argv++) {
|
||||
unsigned char sha1[20];
|
||||
struct object *o;
|
||||
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)) {
|
||||
fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
|
||||
*argv);
|
||||
@ -212,10 +200,8 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
commit = (struct commit *)o;
|
||||
|
||||
if (cutoff > commit->date)
|
||||
cutoff = commit->date;
|
||||
|
||||
add_object_array((struct object *)commit, *argv, &revs);
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,7 @@
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
|
||||
static const char builtin_pack_refs_usage[] =
|
||||
"git-pack-refs [--all] [--prune | --no-prune]";
|
||||
#include "parse-options.h"
|
||||
|
||||
struct ref_to_prune {
|
||||
struct ref_to_prune *next;
|
||||
@ -117,31 +115,26 @@ static int pack_refs(unsigned int flags)
|
||||
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 i;
|
||||
unsigned int flags;
|
||||
int all = 0, prune = 1;
|
||||
unsigned int flags = 0;
|
||||
struct option opts[] = {
|
||||
OPT_BOOLEAN(0, "all", &all, "pack everything"),
|
||||
OPT_BOOLEAN(0, "prune", &prune, "prune loose refs (default)"),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
flags = PACK_REFS_PRUNE;
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
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")) {
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
/* perhaps other parameters later... */
|
||||
break;
|
||||
}
|
||||
if (i != argc)
|
||||
usage(builtin_pack_refs_usage);
|
||||
|
||||
return pack_refs(flags);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "run-command.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "utf8.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
/*
|
||||
* This implements the builtins revert and cherry-pick.
|
||||
@ -19,51 +20,42 @@
|
||||
* 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 replay;
|
||||
static int edit, no_replay, no_commit, needed_deref;
|
||||
static enum { REVERT, CHERRY_PICK } action;
|
||||
static int no_commit;
|
||||
static struct commit *commit;
|
||||
static int needed_deref;
|
||||
|
||||
static const char *me;
|
||||
|
||||
#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 ?
|
||||
revert_usage : cherry_pick_usage;
|
||||
const char * const * usage_str =
|
||||
action == REVERT ? revert_usage : cherry_pick_usage;
|
||||
unsigned char sha1[20];
|
||||
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)
|
||||
usage(usage_str);
|
||||
|
||||
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 (parse_options(argc, argv, options, usage_str, 0) != 1)
|
||||
usage_with_options(usage_str, options);
|
||||
arg = argv[0];
|
||||
if (get_sha1(arg, sha1))
|
||||
die ("Cannot find '%s'", arg);
|
||||
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);
|
||||
me = action == REVERT ? "revert" : "cherry-pick";
|
||||
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... */
|
||||
if (action == REVERT && replay)
|
||||
if (action == REVERT && !no_replay)
|
||||
die("revert is incompatible with replay");
|
||||
|
||||
if (no_commit) {
|
||||
@ -310,7 +302,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
next = commit;
|
||||
set_author_ident_env(message);
|
||||
add_message_to_msg(message);
|
||||
if (!replay) {
|
||||
if (no_replay) {
|
||||
add_to_msg("(cherry picked from commit ");
|
||||
add_to_msg(sha1_to_hex(commit->object.sha1));
|
||||
add_to_msg(")\n");
|
||||
@ -388,13 +380,14 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
if (isatty(0))
|
||||
edit = 1;
|
||||
no_replay = 1;
|
||||
action = REVERT;
|
||||
return revert_or_cherry_pick(argc, argv);
|
||||
}
|
||||
|
||||
int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
replay = 1;
|
||||
no_replay = 0;
|
||||
action = CHERRY_PICK;
|
||||
return revert_or_cherry_pick(argc, argv);
|
||||
}
|
||||
|
54
builtin-rm.c
54
builtin-rm.c
@ -8,9 +8,12 @@
|
||||
#include "dir.h"
|
||||
#include "cache-tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char builtin_rm_usage[] =
|
||||
"git-rm [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>...";
|
||||
static const char * const builtin_rm_usage[] = {
|
||||
"git-rm [options] [--] <file>...",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct {
|
||||
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 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 i, newfd;
|
||||
int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
|
||||
int ignore_unmatch = 0;
|
||||
const char **pathspec;
|
||||
char *seen;
|
||||
|
||||
@ -136,34 +151,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
for (i = 1 ; i < argc ; i++) {
|
||||
const char *arg = argv[i];
|
||||
argc = parse_options(argc, argv, builtin_rm_options, builtin_rm_usage, 0);
|
||||
if (!argc)
|
||||
usage_with_options(builtin_rm_usage, builtin_rm_options);
|
||||
|
||||
if (*arg != '-')
|
||||
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);
|
||||
pathspec = get_pathspec(prefix, argv);
|
||||
seen = NULL;
|
||||
for (i = 0; pathspec[i] ; i++)
|
||||
/* nothing */;
|
||||
|
@ -1,9 +1,12 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char git_symbolic_ref_usage[] =
|
||||
"git-symbolic-ref [-q] [-m <reason>] name [ref]";
|
||||
static const char * const git_symbolic_ref_usage[] = {
|
||||
"git-symbolic-ref [options] name [ref]",
|
||||
NULL
|
||||
};
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
while (1 < argc) {
|
||||
const char *arg = argv[1];
|
||||
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)
|
||||
argc = parse_options(argc, argv, options, git_symbolic_ref_usage, 0);
|
||||
if (msg &&!*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) {
|
||||
case 2:
|
||||
check_symref(argv[1], quiet);
|
||||
case 1:
|
||||
check_symref(argv[0], quiet);
|
||||
break;
|
||||
case 3:
|
||||
create_symref(argv[1], argv[2], msg);
|
||||
case 2:
|
||||
create_symref(argv[0], argv[1], msg);
|
||||
break;
|
||||
default:
|
||||
usage(git_symbolic_ref_usage);
|
||||
usage_with_options(git_symbolic_ref_usage, options);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,59 +1,44 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "builtin.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
static const char git_update_ref_usage[] =
|
||||
"git-update-ref [-m <reason>] (-d <refname> <value> | [--no-deref] <refname> <value> [<oldval>])";
|
||||
static const char * const git_update_ref_usage[] = {
|
||||
"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)
|
||||
{
|
||||
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
|
||||
const char *refname, *value, *oldval, *msg=NULL;
|
||||
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);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp("-m", argv[i])) {
|
||||
if (i+1 >= argc)
|
||||
usage(git_update_ref_usage);
|
||||
msg = argv[++i];
|
||||
if (!*msg)
|
||||
argc = parse_options(argc, argv, options, git_update_ref_usage, 0);
|
||||
if (msg && !*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 (argc < 2 || argc > 3)
|
||||
usage_with_options(git_update_ref_usage, options);
|
||||
refname = argv[0];
|
||||
value = argv[1];
|
||||
oldval = argv[2];
|
||||
|
||||
if (get_sha1(value, sha1))
|
||||
die("%s: not a valid SHA1", value);
|
||||
|
||||
if (delete) {
|
||||
if (oldval)
|
||||
usage(git_update_ref_usage);
|
||||
usage_with_options(git_update_ref_usage, options);
|
||||
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);
|
||||
|
||||
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
322
parse-options.c
Normal 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
70
parse-options.h
Normal 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
93
t/t0040-parse-options.sh
Executable 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
0
t/t6300-for-each-ref.sh
Normal file → Executable file
35
test-parse-options.c
Normal file
35
test-parse-options.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user