From df217ed6430efe444a09fffdafd39720ae3f9864 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 23 May 2009 11:53:13 -0700 Subject: parse-opts: add OPT_FILENAME and transition builtins Commit dbd0f5c (Files given on the command line are relative to $cwd, 2008-08-06) introduced parse_options_fix_filename() as a minimal fix. OPT_FILENAME is intended to be a more robust fix for the same issue. OPT_FILENAME and its associated enum OPTION_FILENAME are used to represent filename options within the parse options API. This option is similar to OPTION_STRING. If --no is prefixed to the option the filename is unset. If no argument is given and the default value is set, the filename is set to the default value. The difference is that the filename is prefixed with the prefix passed to parse_options() (or parse_options_start()). Update git-apply, git-commit, git-fmt-merge-msg, and git-tag to use OPT_FILENAME with their filename options. Also, rename parse_options_fix_filename() to fix_filename() as it is no longer extern. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- Documentation/technical/api-parse-options.txt | 5 ++++ builtin-apply.c | 5 +--- builtin-commit.c | 10 ++------ builtin-fmt-merge-msg.c | 3 +-- builtin-tag.c | 3 +-- parse-options.c | 36 ++++++++++++++++++--------- parse-options.h | 5 ++-- t/t0040-parse-options.sh | 19 ++++++++++++-- test-parse-options.c | 6 ++++- 9 files changed, 59 insertions(+), 33 deletions(-) diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index aace5801ca..50f9e9ac17 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -167,6 +167,11 @@ There are some macros to easily define options: and the result will be put into `var`. See 'Option Callbacks' below for a more elaborate description. +`OPT_FILENAME(short, long, &var, description)`:: + Introduce an option with a filename argument. + The filename will be prefixed by passing the filename along with + the prefix argument of `parse_options()` to `prefix_filename()`. + `OPT_ARGUMENT(long, description)`:: Introduce a long-option argument that will be kept in `argv[]`. diff --git a/builtin-apply.c b/builtin-apply.c index bac03d7902..5329186266 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -3278,7 +3278,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) "apply a patch without touching the working tree"), OPT_BOOLEAN(0, "apply", &force_apply, "also apply the patch (use with --stat/--summary/--check)"), - OPT_STRING(0, "build-fake-ancestor", &fake_ancestor, "file", + OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor, "build a temporary index based on embedded index information"), { OPTION_CALLBACK, 'z', NULL, NULL, NULL, "paths are separated with NUL character", @@ -3315,9 +3315,6 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, prefix, builtin_apply_options, apply_usage, 0); - fake_ancestor = parse_options_fix_filename(prefix, fake_ancestor); - if (fake_ancestor) - fake_ancestor = xstrdup(fake_ancestor); if (apply_with_reject) apply = apply_verbosely = 1; diff --git a/builtin-commit.c b/builtin-commit.c index b9a1528c9d..41e222d267 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -88,13 +88,13 @@ static struct option builtin_commit_options[] = { OPT__VERBOSE(&verbose), OPT_GROUP("Commit message options"), - OPT_STRING('F', "file", &logfile, "FILE", "read log from file"), + OPT_FILENAME('F', "file", &logfile, "read log from file"), OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"), OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m), OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "), OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), - OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"), + OPT_FILENAME('t', "template", &template_file, "use specified template file"), OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"), OPT_GROUP("Commit contents options"), @@ -699,12 +699,6 @@ static int parse_and_validate_options(int argc, const char *argv[], argc = parse_options(argc, argv, prefix, builtin_commit_options, usage, 0); - logfile = parse_options_fix_filename(prefix, logfile); - if (logfile) - logfile = xstrdup(logfile); - template_file = parse_options_fix_filename(prefix, template_file); - if (template_file) - template_file = xstrdup(template_file); if (force_author && !strchr(force_author, '>')) force_author = find_author_by_nickname(force_author); diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index d4c7206142..fbf9582e66 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -351,7 +351,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"), OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"), - OPT_STRING('F', "file", &inpath, "file", "file to read from"), + OPT_FILENAME('F', "file", &inpath, "file to read from"), OPT_END() }; @@ -364,7 +364,6 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) 0); if (argc > 0) usage_with_options(fmt_merge_msg_usage, options); - inpath = parse_options_fix_filename(prefix, inpath); if (inpath && strcmp(inpath, "-")) { in = fopen(inpath, "r"); diff --git a/builtin-tag.c b/builtin-tag.c index 6e8b464109..dc3db62811 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -387,7 +387,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) "annotated tag, needs a message"), OPT_CALLBACK('m', NULL, &msg, "msg", "message for the tag", parse_msg_arg), - OPT_STRING('F', NULL, &msgfile, "file", "message in a file"), + OPT_FILENAME('F', NULL, &msgfile, "message in a file"), OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"), OPT_STRING('u', NULL, &keyid, "key-id", "use another key to sign the tag"), @@ -406,7 +406,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix) git_config(git_tag_config, NULL); argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0); - msgfile = parse_options_fix_filename(prefix, msgfile); if (keyid) { sign = 1; diff --git a/parse-options.c b/parse-options.c index be1800d7b4..b85cab2466 100644 --- a/parse-options.c +++ b/parse-options.c @@ -31,11 +31,20 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, return 0; } +static void fix_filename(const char *prefix, const char **file) +{ + if (!file || !*file || !prefix || is_absolute_path(*file) + || !strcmp("-", *file)) + return; + *file = xstrdup(prefix_filename(prefix, strlen(prefix), *file)); +} + static int get_value(struct parse_opt_ctx_t *p, const struct option *opt, int flags) { const char *s, *arg; const int unset = flags & OPT_UNSET; + int err; if (unset && p->opt) return opterror(opt, "takes no value", flags); @@ -95,6 +104,19 @@ static int get_value(struct parse_opt_ctx_t *p, return get_arg(p, opt, flags, (const char **)opt->value); return 0; + case OPTION_FILENAME: + err = 0; + if (unset) + *(const char **)opt->value = NULL; + else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) + *(const char **)opt->value = (const char *)opt->defval; + else + err = get_arg(p, opt, flags, (const char **)opt->value); + + if (!err) + fix_filename(p->prefix, (const char **)opt->value); + return err; + case OPTION_CALLBACK: if (unset) return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; @@ -494,6 +516,8 @@ int usage_with_options_internal(const char * const *usagestr, if (opts->flags & PARSE_OPT_NOARG) break; /* FALLTHROUGH */ + case OPTION_FILENAME: + /* FALLTHROUGH */ case OPTION_STRING: if (opts->argh) pos += usage_argh(opts); @@ -604,15 +628,3 @@ int parse_opt_with_commit(const struct option *opt, const char *arg, int unset) commit_list_insert(commit, opt->value); return 0; } - -/* - * This should really be OPTION_FILENAME type as a part of - * parse_options that take prefix to do this while parsing. - */ -extern const char *parse_options_fix_filename(const char *prefix, const char *file) -{ - if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file)) - return file; - return prefix_filename(prefix, strlen(prefix), file); -} - diff --git a/parse-options.h b/parse-options.h index f652c0f3c7..b374ade95c 100644 --- a/parse-options.h +++ b/parse-options.h @@ -17,6 +17,7 @@ enum parse_opt_type { OPTION_STRING, OPTION_INTEGER, OPTION_CALLBACK, + OPTION_FILENAME }; enum parse_opt_flags { @@ -117,6 +118,8 @@ struct option { #define OPT_NUMBER_CALLBACK(v, h, f) \ { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \ PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) } +#define OPT_FILENAME(s, l, v, h) { OPTION_FILENAME, (s), (l), (v), \ + "FILE", (h) } /* parse_options() will filter out the processed options and leave the * non-option arguments in argv[]. @@ -184,6 +187,4 @@ extern int parse_opt_with_commit(const struct option *, const char *, int); "use digits to display SHA-1s", \ PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 } -extern const char *parse_options_fix_filename(const char *prefix, const char *file); - #endif diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index a40c1236c0..bbc821ef97 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -19,6 +19,7 @@ usage: test-parse-options --set23 set integer to 23 -t