@matheusbsbs / matheus-bagliano / commits / df217ed643
Fork 0

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 <bebarino@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stephen Boyd committed May 23, 2009 at 11:53 UTC df217ed6430efe444a09fffdafd39720ae3f9864
9 files changed +59 -33
Documentation/technical/api-parse-options.txt
+5
@@ -167,6 +167,11 @@ There are some macros to easily define options:
167 and the result will be put into `var`.
168 See 'Option Callbacks' below for a more elaborate description.
169
170 +`OPT_FILENAME(short, long, &var, description)`::
171 + Introduce an option with a filename argument.
172 + The filename will be prefixed by passing the filename along with
173 + the prefix argument of `parse_options()` to `prefix_filename()`.
174 +
175 `OPT_ARGUMENT(long, description)`::
176 Introduce a long-option argument that will be kept in `argv[]`.
177
builtin-apply.c
+1 -4
@@ -3278,7 +3278,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
3278 "apply a patch without touching the working tree"),
3279 OPT_BOOLEAN(0, "apply", &force_apply,
3280 "also apply the patch (use with --stat/--summary/--check)"),
3281 - OPT_STRING(0, "build-fake-ancestor", &fake_ancestor, "file",
3281 + OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
3282 "build a temporary index based on embedded index information"),
3283 { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
3284 "paths are separated with NUL character",
@@ -3315,9 +3315,6 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
3315
3316 argc = parse_options(argc, argv, prefix, builtin_apply_options,
3317 apply_usage, 0);
3318 - fake_ancestor = parse_options_fix_filename(prefix, fake_ancestor);
3319 - if (fake_ancestor)
3320 - fake_ancestor = xstrdup(fake_ancestor);
3318
3319 if (apply_with_reject)
3320 apply = apply_verbosely = 1;
builtin-commit.c
+2 -8
@@ -88,13 +88,13 @@ static struct option builtin_commit_options[] = {
88 OPT__VERBOSE(&verbose),
89 OPT_GROUP("Commit message options"),
90
91 - OPT_STRING('F', "file", &logfile, "FILE", "read log from file"),
91 + OPT_FILENAME('F', "file", &logfile, "read log from file"),
92 OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
93 OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
94 OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
95 OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
96 OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
97 - OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"),
97 + OPT_FILENAME('t', "template", &template_file, "use specified template file"),
98 OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
99
100 OPT_GROUP("Commit contents options"),
@@ -699,12 +699,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
699
700 argc = parse_options(argc, argv, prefix, builtin_commit_options, usage,
701 0);
702 - logfile = parse_options_fix_filename(prefix, logfile);
703 - if (logfile)
704 - logfile = xstrdup(logfile);
705 - template_file = parse_options_fix_filename(prefix, template_file);
706 - if (template_file)
707 - template_file = xstrdup(template_file);
702
703 if (force_author && !strchr(force_author, '>'))
704 force_author = find_author_by_nickname(force_author);
builtin-fmt-merge-msg.c
+1 -2
@@ -351,7 +351,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
351 struct option options[] = {
352 OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
353 OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
354 - OPT_STRING('F', "file", &inpath, "file", "file to read from"),
354 + OPT_FILENAME('F', "file", &inpath, "file to read from"),
355 OPT_END()
356 };
357
@@ -364,7 +364,6 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
364 0);
365 if (argc > 0)
366 usage_with_options(fmt_merge_msg_usage, options);
367 - inpath = parse_options_fix_filename(prefix, inpath);
367
368 if (inpath && strcmp(inpath, "-")) {
369 in = fopen(inpath, "r");
builtin-tag.c
+1 -2
@@ -387,7 +387,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
387 "annotated tag, needs a message"),
388 OPT_CALLBACK('m', NULL, &msg, "msg",
389 "message for the tag", parse_msg_arg),
390 - OPT_STRING('F', NULL, &msgfile, "file", "message in a file"),
390 + OPT_FILENAME('F', NULL, &msgfile, "message in a file"),
391 OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"),
392 OPT_STRING('u', NULL, &keyid, "key-id",
393 "use another key to sign the tag"),
@@ -406,7 +406,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
406 git_config(git_tag_config, NULL);
407
408 argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0);
409 - msgfile = parse_options_fix_filename(prefix, msgfile);
409
410 if (keyid) {
411 sign = 1;
parse-options.c
+24 -12
@@ -31,11 +31,20 @@ static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
31 return 0;
32 }
33
34 +static void fix_filename(const char *prefix, const char **file)
35 +{
36 + if (!file || !*file || !prefix || is_absolute_path(*file)
37 + || !strcmp("-", *file))
38 + return;
39 + *file = xstrdup(prefix_filename(prefix, strlen(prefix), *file));
40 +}
41 +
42 static int get_value(struct parse_opt_ctx_t *p,
43 const struct option *opt, int flags)
44 {
45 const char *s, *arg;
46 const int unset = flags & OPT_UNSET;
47 + int err;
48
49 if (unset && p->opt)
50 return opterror(opt, "takes no value", flags);
@@ -95,6 +104,19 @@ static int get_value(struct parse_opt_ctx_t *p,
104 return get_arg(p, opt, flags, (const char **)opt->value);
105 return 0;
106
107 + case OPTION_FILENAME:
108 + err = 0;
109 + if (unset)
110 + *(const char **)opt->value = NULL;
111 + else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
112 + *(const char **)opt->value = (const char *)opt->defval;
113 + else
114 + err = get_arg(p, opt, flags, (const char **)opt->value);
115 +
116 + if (!err)
117 + fix_filename(p->prefix, (const char **)opt->value);
118 + return err;
119 +
120 case OPTION_CALLBACK:
121 if (unset)
122 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
@@ -494,6 +516,8 @@ int usage_with_options_internal(const char * const *usagestr,
516 if (opts->flags & PARSE_OPT_NOARG)
517 break;
518 /* FALLTHROUGH */
519 + case OPTION_FILENAME:
520 + /* FALLTHROUGH */
521 case OPTION_STRING:
522 if (opts->argh)
523 pos += usage_argh(opts);
@@ -604,15 +628,3 @@ int parse_opt_with_commit(const struct option *opt, const char *arg, int unset)
628 commit_list_insert(commit, opt->value);
629 return 0;
630 }
607 -
608 -/*
609 - * This should really be OPTION_FILENAME type as a part of
610 - * parse_options that take prefix to do this while parsing.
611 - */
612 -extern const char *parse_options_fix_filename(const char *prefix, const char *file)
613 -{
614 - if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file))
615 - return file;
616 - return prefix_filename(prefix, strlen(prefix), file);
617 -}
618 -
parse-options.h
+3 -2
@@ -17,6 +17,7 @@ enum parse_opt_type {
17 OPTION_STRING,
18 OPTION_INTEGER,
19 OPTION_CALLBACK,
20 + OPTION_FILENAME
21 };
22
23 enum parse_opt_flags {
@@ -117,6 +118,8 @@ struct option {
118 #define OPT_NUMBER_CALLBACK(v, h, f) \
119 { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
120 PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
121 +#define OPT_FILENAME(s, l, v, h) { OPTION_FILENAME, (s), (l), (v), \
122 + "FILE", (h) }
123
124 /* parse_options() will filter out the processed options and leave the
125 * non-option arguments in argv[].
@@ -184,6 +187,4 @@ extern int parse_opt_with_commit(const struct option *, const char *, int);
187 "use <n> digits to display SHA-1s", \
188 PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
189
187 -extern const char *parse_options_fix_filename(const char *prefix, const char *file);
188 -
190 #endif
t/t0040-parse-options.sh
+17 -2
@@ -19,6 +19,7 @@ usage: test-parse-options <options>
19 --set23 set integer to 23
20 -t <time> get timestamp of <time>
21 -L, --length <str> get length of <str>
22 + -F, --file <FILE> set file to <FILE>
23
24 String options
25 -s, --string <string>
@@ -56,10 +57,12 @@ abbrev: 7
57 verbose: 2
58 quiet: no
59 dry run: yes
60 +file: prefix/my.file
61 EOF
62
63 test_expect_success 'short options' '
62 - test-parse-options -s123 -b -i 1729 -b -vv -n > output 2> output.err &&
64 + test-parse-options -s123 -b -i 1729 -b -vv -n -F my.file \
65 + > output 2> output.err &&
66 test_cmp expect output &&
67 test ! -s output.err
68 '
@@ -73,11 +76,12 @@ abbrev: 10
76 verbose: 2
77 quiet: no
78 dry run: no
79 +file: prefix/fi.le
80 EOF
81
82 test_expect_success 'long options' '
83 test-parse-options --boolean --integer 1729 --boolean --string2=321 \
80 - --verbose --verbose --no-dry-run --abbrev=10 \
84 + --verbose --verbose --no-dry-run --abbrev=10 --file fi.le\
85 > output 2> output.err &&
86 test ! -s output.err &&
87 test_cmp expect output
@@ -87,6 +91,8 @@ test_expect_success 'missing required value' '
91 test-parse-options -s;
92 test $? = 129 &&
93 test-parse-options --string;
94 + test $? = 129 &&
95 + test-parse-options --file;
96 test $? = 129
97 '
98
@@ -99,6 +105,7 @@ abbrev: 7
105 verbose: 0
106 quiet: no
107 dry run: no
108 +file: (not set)
109 arg 00: a1
110 arg 01: b1
111 arg 02: --boolean
@@ -120,6 +127,7 @@ abbrev: 7
127 verbose: 0
128 quiet: no
129 dry run: no
130 +file: (not set)
131 EOF
132
133 test_expect_success 'unambiguously abbreviated option' '
@@ -148,6 +156,7 @@ abbrev: 7
156 verbose: 0
157 quiet: no
158 dry run: no
159 +file: (not set)
160 EOF
161
162 test_expect_success 'non ambiguous option (after two options it abbreviates)' '
@@ -175,6 +184,7 @@ abbrev: 7
184 verbose: 0
185 quiet: no
186 dry run: no
187 +file: (not set)
188 arg 00: --quux
189 EOF
190
@@ -193,6 +203,7 @@ abbrev: 7
203 verbose: 0
204 quiet: yes
205 dry run: no
206 +file: (not set)
207 arg 00: foo
208 EOF
209
@@ -213,6 +224,7 @@ abbrev: 7
224 verbose: 0
225 quiet: no
226 dry run: no
227 +file: (not set)
228 EOF
229
230 test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
@@ -240,6 +252,7 @@ abbrev: 7
252 verbose: 0
253 quiet: no
254 dry run: no
255 +file: (not set)
256 EOF
257
258 test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
@@ -263,6 +276,7 @@ abbrev: 7
276 verbose: 0
277 quiet: no
278 dry run: no
279 +file: (not set)
280 EOF
281
282 test_expect_success 'OPT_BIT() works' '
@@ -292,6 +306,7 @@ abbrev: 7
306 verbose: 0
307 quiet: no
308 dry run: no
309 +file: (not set)
310 EOF
311
312 test_expect_success 'OPT_NUMBER_CALLBACK() works' '
test-parse-options.c
+5 -1
@@ -7,6 +7,7 @@ static unsigned long timestamp;
7 static int abbrev = 7;
8 static int verbose = 0, dry_run = 0, quiet = 0;
9 static char *string = NULL;
10 +static char *file = NULL;
11
12 int length_callback(const struct option *opt, const char *arg, int unset)
13 {
@@ -27,6 +28,7 @@ int number_callback(const struct option *opt, const char *arg, int unset)
28
29 int main(int argc, const char **argv)
30 {
31 + const char *prefix = "prefix/";
32 const char *usage[] = {
33 "test-parse-options <options>",
34 NULL
@@ -43,6 +45,7 @@ int main(int argc, const char **argv)
45 OPT_DATE('t', NULL, &timestamp, "get timestamp of <time>"),
46 OPT_CALLBACK('L', "length", &integer, "str",
47 "get length of <str>", length_callback),
48 + OPT_FILENAME('F', "file", &file, "set file to <FILE>"),
49 OPT_GROUP("String options"),
50 OPT_STRING('s', "string", &string, "string", "get a string"),
51 OPT_STRING(0, "string2", &string, "str", "get another string"),
@@ -65,7 +68,7 @@ int main(int argc, const char **argv)
68 };
69 int i;
70
68 - argc = parse_options(argc, argv, NULL, options, usage, 0);
71 + argc = parse_options(argc, argv, prefix, options, usage, 0);
72
73 printf("boolean: %d\n", boolean);
74 printf("integer: %u\n", integer);
@@ -75,6 +78,7 @@ int main(int argc, const char **argv)
78 printf("verbose: %d\n", verbose);
79 printf("quiet: %s\n", quiet ? "yes" : "no");
80 printf("dry run: %s\n", dry_run ? "yes" : "no");
81 + printf("file: %s\n", file ? file : "(not set)");
82
83 for (i = 0; i < argc; i++)
84 printf("arg %02d: %s\n", i, argv[i]);