Line | Count | Source (jump to first uncovered line) |
1 | | #include "git-compat-util.h" |
2 | | #include "parse-options.h" |
3 | | #include "abspath.h" |
4 | | #include "parse.h" |
5 | | #include "gettext.h" |
6 | | #include "strbuf.h" |
7 | | #include "string-list.h" |
8 | | #include "utf8.h" |
9 | | |
10 | | static int disallow_abbreviated_options; |
11 | | |
12 | | enum opt_parsed { |
13 | | OPT_LONG = 0, |
14 | | OPT_SHORT = 1<<0, |
15 | | OPT_UNSET = 1<<1, |
16 | | }; |
17 | | |
18 | | static void optbug(const struct option *opt, const char *reason) |
19 | 0 | { |
20 | 0 | if (opt->long_name && opt->short_name) |
21 | 0 | bug("switch '%c' (--%s) %s", opt->short_name, |
22 | 0 | opt->long_name, reason); |
23 | 0 | else if (opt->long_name) |
24 | 0 | bug("option '%s' %s", opt->long_name, reason); |
25 | 0 | else |
26 | 0 | bug("switch '%c' %s", opt->short_name, reason); |
27 | 0 | } |
28 | | |
29 | | static const char *optname(const struct option *opt, enum opt_parsed flags) |
30 | 0 | { |
31 | 0 | static struct strbuf sb = STRBUF_INIT; |
32 | |
|
33 | 0 | strbuf_reset(&sb); |
34 | 0 | if (flags & OPT_SHORT) |
35 | 0 | strbuf_addf(&sb, "switch `%c'", opt->short_name); |
36 | 0 | else if (flags & OPT_UNSET) |
37 | 0 | strbuf_addf(&sb, "option `no-%s'", opt->long_name); |
38 | 0 | else if (flags == OPT_LONG) |
39 | 0 | strbuf_addf(&sb, "option `%s'", opt->long_name); |
40 | 0 | else |
41 | 0 | BUG("optname() got unknown flags %d", flags); |
42 | | |
43 | 0 | return sb.buf; |
44 | 0 | } |
45 | | |
46 | | static enum parse_opt_result get_arg(struct parse_opt_ctx_t *p, |
47 | | const struct option *opt, |
48 | | enum opt_parsed flags, const char **arg) |
49 | 0 | { |
50 | 0 | if (p->opt) { |
51 | 0 | *arg = p->opt; |
52 | 0 | p->opt = NULL; |
53 | 0 | } else if (p->argc == 1 && (opt->flags & PARSE_OPT_LASTARG_DEFAULT)) { |
54 | 0 | *arg = (const char *)opt->defval; |
55 | 0 | } else if (p->argc > 1) { |
56 | 0 | p->argc--; |
57 | 0 | *arg = *++p->argv; |
58 | 0 | } else |
59 | 0 | return error(_("%s requires a value"), optname(opt, flags)); |
60 | 0 | return 0; |
61 | 0 | } |
62 | | |
63 | | static void fix_filename(const char *prefix, char **file) |
64 | 0 | { |
65 | 0 | if (!file || !*file) |
66 | 0 | ; /* leave as NULL */ |
67 | 0 | else |
68 | 0 | *file = prefix_filename_except_for_dash(prefix, *file); |
69 | 0 | } |
70 | | |
71 | | static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p, |
72 | | const struct option *opt, |
73 | | enum opt_parsed flags, |
74 | | const char **argp) |
75 | 0 | { |
76 | 0 | const char *s, *arg; |
77 | 0 | const int unset = flags & OPT_UNSET; |
78 | 0 | int err; |
79 | |
|
80 | 0 | if (unset && p->opt) |
81 | 0 | return error(_("%s takes no value"), optname(opt, flags)); |
82 | 0 | if (unset && (opt->flags & PARSE_OPT_NONEG)) |
83 | 0 | return error(_("%s isn't available"), optname(opt, flags)); |
84 | 0 | if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG)) |
85 | 0 | return error(_("%s takes no value"), optname(opt, flags)); |
86 | | |
87 | 0 | switch (opt->type) { |
88 | 0 | case OPTION_LOWLEVEL_CALLBACK: |
89 | 0 | return opt->ll_callback(p, opt, NULL, unset); |
90 | | |
91 | 0 | case OPTION_BIT: |
92 | 0 | if (unset) |
93 | 0 | *(int *)opt->value &= ~opt->defval; |
94 | 0 | else |
95 | 0 | *(int *)opt->value |= opt->defval; |
96 | 0 | return 0; |
97 | | |
98 | 0 | case OPTION_NEGBIT: |
99 | 0 | if (unset) |
100 | 0 | *(int *)opt->value |= opt->defval; |
101 | 0 | else |
102 | 0 | *(int *)opt->value &= ~opt->defval; |
103 | 0 | return 0; |
104 | | |
105 | 0 | case OPTION_BITOP: |
106 | 0 | if (unset) |
107 | 0 | BUG("BITOP can't have unset form"); |
108 | 0 | *(int *)opt->value &= ~opt->extra; |
109 | 0 | *(int *)opt->value |= opt->defval; |
110 | 0 | return 0; |
111 | | |
112 | 0 | case OPTION_COUNTUP: |
113 | 0 | if (*(int *)opt->value < 0) |
114 | 0 | *(int *)opt->value = 0; |
115 | 0 | *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; |
116 | 0 | return 0; |
117 | | |
118 | 0 | case OPTION_SET_INT: |
119 | 0 | *(int *)opt->value = unset ? 0 : opt->defval; |
120 | 0 | return 0; |
121 | | |
122 | 0 | case OPTION_STRING: |
123 | 0 | if (unset) |
124 | 0 | *(const char **)opt->value = NULL; |
125 | 0 | else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) |
126 | 0 | *(const char **)opt->value = (const char *)opt->defval; |
127 | 0 | else |
128 | 0 | return get_arg(p, opt, flags, (const char **)opt->value); |
129 | 0 | return 0; |
130 | | |
131 | 0 | case OPTION_FILENAME: |
132 | 0 | err = 0; |
133 | 0 | if (unset) |
134 | 0 | *(const char **)opt->value = NULL; |
135 | 0 | else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) |
136 | 0 | *(const char **)opt->value = (const char *)opt->defval; |
137 | 0 | else |
138 | 0 | err = get_arg(p, opt, flags, (const char **)opt->value); |
139 | |
|
140 | 0 | if (!err) |
141 | 0 | fix_filename(p->prefix, (char **)opt->value); |
142 | 0 | return err; |
143 | | |
144 | 0 | case OPTION_CALLBACK: |
145 | 0 | { |
146 | 0 | const char *p_arg = NULL; |
147 | 0 | int p_unset; |
148 | |
|
149 | 0 | if (unset) |
150 | 0 | p_unset = 1; |
151 | 0 | else if (opt->flags & PARSE_OPT_NOARG) |
152 | 0 | p_unset = 0; |
153 | 0 | else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) |
154 | 0 | p_unset = 0; |
155 | 0 | else if (get_arg(p, opt, flags, &arg)) |
156 | 0 | return -1; |
157 | 0 | else { |
158 | 0 | p_unset = 0; |
159 | 0 | p_arg = arg; |
160 | 0 | } |
161 | 0 | if (opt->flags & PARSE_OPT_CMDMODE) |
162 | 0 | *argp = p_arg; |
163 | 0 | if (opt->callback) |
164 | 0 | return (*opt->callback)(opt, p_arg, p_unset) ? (-1) : 0; |
165 | 0 | else |
166 | 0 | return (*opt->ll_callback)(p, opt, p_arg, p_unset); |
167 | 0 | } |
168 | 0 | case OPTION_INTEGER: |
169 | 0 | if (unset) { |
170 | 0 | *(int *)opt->value = 0; |
171 | 0 | return 0; |
172 | 0 | } |
173 | 0 | if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { |
174 | 0 | *(int *)opt->value = opt->defval; |
175 | 0 | return 0; |
176 | 0 | } |
177 | 0 | if (get_arg(p, opt, flags, &arg)) |
178 | 0 | return -1; |
179 | 0 | if (!*arg) |
180 | 0 | return error(_("%s expects a numerical value"), |
181 | 0 | optname(opt, flags)); |
182 | 0 | *(int *)opt->value = strtol(arg, (char **)&s, 10); |
183 | 0 | if (*s) |
184 | 0 | return error(_("%s expects a numerical value"), |
185 | 0 | optname(opt, flags)); |
186 | 0 | return 0; |
187 | | |
188 | 0 | case OPTION_MAGNITUDE: |
189 | 0 | if (unset) { |
190 | 0 | *(unsigned long *)opt->value = 0; |
191 | 0 | return 0; |
192 | 0 | } |
193 | 0 | if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { |
194 | 0 | *(unsigned long *)opt->value = opt->defval; |
195 | 0 | return 0; |
196 | 0 | } |
197 | 0 | if (get_arg(p, opt, flags, &arg)) |
198 | 0 | return -1; |
199 | 0 | if (!git_parse_ulong(arg, opt->value)) |
200 | 0 | return error(_("%s expects a non-negative integer value" |
201 | 0 | " with an optional k/m/g suffix"), |
202 | 0 | optname(opt, flags)); |
203 | 0 | return 0; |
204 | | |
205 | 0 | default: |
206 | 0 | BUG("opt->type %d should not happen", opt->type); |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | | struct parse_opt_cmdmode_list { |
211 | | int value, *value_ptr; |
212 | | const struct option *opt; |
213 | | const char *arg; |
214 | | enum opt_parsed flags; |
215 | | struct parse_opt_cmdmode_list *next; |
216 | | }; |
217 | | |
218 | | static void build_cmdmode_list(struct parse_opt_ctx_t *ctx, |
219 | | const struct option *opts) |
220 | 0 | { |
221 | 0 | ctx->cmdmode_list = NULL; |
222 | |
|
223 | 0 | for (; opts->type != OPTION_END; opts++) { |
224 | 0 | struct parse_opt_cmdmode_list *elem = ctx->cmdmode_list; |
225 | 0 | int *value_ptr = opts->value; |
226 | |
|
227 | 0 | if (!(opts->flags & PARSE_OPT_CMDMODE) || !value_ptr) |
228 | 0 | continue; |
229 | | |
230 | 0 | while (elem && elem->value_ptr != value_ptr) |
231 | 0 | elem = elem->next; |
232 | 0 | if (elem) |
233 | 0 | continue; |
234 | | |
235 | 0 | CALLOC_ARRAY(elem, 1); |
236 | 0 | elem->value_ptr = value_ptr; |
237 | 0 | elem->value = *value_ptr; |
238 | 0 | elem->next = ctx->cmdmode_list; |
239 | 0 | ctx->cmdmode_list = elem; |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | | static char *optnamearg(const struct option *opt, const char *arg, |
244 | | enum opt_parsed flags) |
245 | 0 | { |
246 | 0 | if (flags & OPT_SHORT) |
247 | 0 | return xstrfmt("-%c%s", opt->short_name, arg ? arg : ""); |
248 | 0 | return xstrfmt("--%s%s%s%s", flags & OPT_UNSET ? "no-" : "", |
249 | 0 | opt->long_name, arg ? "=" : "", arg ? arg : ""); |
250 | 0 | } |
251 | | |
252 | | static enum parse_opt_result get_value(struct parse_opt_ctx_t *p, |
253 | | const struct option *opt, |
254 | | enum opt_parsed flags) |
255 | 0 | { |
256 | 0 | const char *arg = NULL; |
257 | 0 | enum parse_opt_result result = do_get_value(p, opt, flags, &arg); |
258 | 0 | struct parse_opt_cmdmode_list *elem = p->cmdmode_list; |
259 | 0 | char *opt_name, *other_opt_name; |
260 | |
|
261 | 0 | for (; elem; elem = elem->next) { |
262 | 0 | if (*elem->value_ptr == elem->value) |
263 | 0 | continue; |
264 | | |
265 | 0 | if (elem->opt && |
266 | 0 | (elem->opt->flags | opt->flags) & PARSE_OPT_CMDMODE) |
267 | 0 | break; |
268 | | |
269 | 0 | elem->opt = opt; |
270 | 0 | elem->arg = arg; |
271 | 0 | elem->flags = flags; |
272 | 0 | elem->value = *elem->value_ptr; |
273 | 0 | } |
274 | |
|
275 | 0 | if (result || !elem) |
276 | 0 | return result; |
277 | | |
278 | 0 | opt_name = optnamearg(opt, arg, flags); |
279 | 0 | other_opt_name = optnamearg(elem->opt, elem->arg, elem->flags); |
280 | 0 | error(_("options '%s' and '%s' cannot be used together"), |
281 | 0 | opt_name, other_opt_name); |
282 | 0 | free(opt_name); |
283 | 0 | free(other_opt_name); |
284 | 0 | return -1; |
285 | 0 | } |
286 | | |
287 | | static enum parse_opt_result parse_short_opt(struct parse_opt_ctx_t *p, |
288 | | const struct option *options) |
289 | 0 | { |
290 | 0 | const struct option *numopt = NULL; |
291 | |
|
292 | 0 | for (; options->type != OPTION_END; options++) { |
293 | 0 | if (options->short_name == *p->opt) { |
294 | 0 | p->opt = p->opt[1] ? p->opt + 1 : NULL; |
295 | 0 | return get_value(p, options, OPT_SHORT); |
296 | 0 | } |
297 | | |
298 | | /* |
299 | | * Handle the numerical option later, explicit one-digit |
300 | | * options take precedence over it. |
301 | | */ |
302 | 0 | if (options->type == OPTION_NUMBER) |
303 | 0 | numopt = options; |
304 | 0 | } |
305 | 0 | if (numopt && isdigit(*p->opt)) { |
306 | 0 | size_t len = 1; |
307 | 0 | char *arg; |
308 | 0 | int rc; |
309 | |
|
310 | 0 | while (isdigit(p->opt[len])) |
311 | 0 | len++; |
312 | 0 | arg = xmemdupz(p->opt, len); |
313 | 0 | p->opt = p->opt[len] ? p->opt + len : NULL; |
314 | 0 | if (numopt->callback) |
315 | 0 | rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0; |
316 | 0 | else |
317 | 0 | rc = (*numopt->ll_callback)(p, numopt, arg, 0); |
318 | 0 | free(arg); |
319 | 0 | return rc; |
320 | 0 | } |
321 | 0 | return PARSE_OPT_UNKNOWN; |
322 | 0 | } |
323 | | |
324 | | static int has_string(const char *it, const char **array) |
325 | 0 | { |
326 | 0 | while (*array) |
327 | 0 | if (!strcmp(it, *(array++))) |
328 | 0 | return 1; |
329 | 0 | return 0; |
330 | 0 | } |
331 | | |
332 | | static int is_alias(struct parse_opt_ctx_t *ctx, |
333 | | const struct option *one_opt, |
334 | | const struct option *another_opt) |
335 | 0 | { |
336 | 0 | const char **group; |
337 | |
|
338 | 0 | if (!ctx->alias_groups) |
339 | 0 | return 0; |
340 | | |
341 | 0 | if (!one_opt->long_name || !another_opt->long_name) |
342 | 0 | return 0; |
343 | | |
344 | 0 | for (group = ctx->alias_groups; *group; group += 3) { |
345 | | /* it and other are from the same family? */ |
346 | 0 | if (has_string(one_opt->long_name, group) && |
347 | 0 | has_string(another_opt->long_name, group)) |
348 | 0 | return 1; |
349 | 0 | } |
350 | 0 | return 0; |
351 | 0 | } |
352 | | |
353 | | struct parsed_option { |
354 | | const struct option *option; |
355 | | enum opt_parsed flags; |
356 | | }; |
357 | | |
358 | | static void register_abbrev(struct parse_opt_ctx_t *p, |
359 | | const struct option *option, enum opt_parsed flags, |
360 | | struct parsed_option *abbrev, |
361 | | struct parsed_option *ambiguous) |
362 | 0 | { |
363 | 0 | if (p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT) |
364 | 0 | return; |
365 | 0 | if (abbrev->option && |
366 | 0 | !(abbrev->flags == flags && is_alias(p, abbrev->option, option))) { |
367 | | /* |
368 | | * If this is abbreviated, it is |
369 | | * ambiguous. So when there is no |
370 | | * exact match later, we need to |
371 | | * error out. |
372 | | */ |
373 | 0 | ambiguous->option = abbrev->option; |
374 | 0 | ambiguous->flags = abbrev->flags; |
375 | 0 | } |
376 | 0 | abbrev->option = option; |
377 | 0 | abbrev->flags = flags; |
378 | 0 | } |
379 | | |
380 | | static enum parse_opt_result parse_long_opt( |
381 | | struct parse_opt_ctx_t *p, const char *arg, |
382 | | const struct option *options) |
383 | 0 | { |
384 | 0 | const char *arg_end = strchrnul(arg, '='); |
385 | 0 | const char *arg_start = arg; |
386 | 0 | enum opt_parsed flags = OPT_LONG; |
387 | 0 | int arg_starts_with_no_no = 0; |
388 | 0 | struct parsed_option abbrev = { .option = NULL, .flags = OPT_LONG }; |
389 | 0 | struct parsed_option ambiguous = { .option = NULL, .flags = OPT_LONG }; |
390 | |
|
391 | 0 | if (skip_prefix(arg_start, "no-", &arg_start)) { |
392 | 0 | if (skip_prefix(arg_start, "no-", &arg_start)) |
393 | 0 | arg_starts_with_no_no = 1; |
394 | 0 | else |
395 | 0 | flags |= OPT_UNSET; |
396 | 0 | } |
397 | |
|
398 | 0 | for (; options->type != OPTION_END; options++) { |
399 | 0 | const char *rest, *long_name = options->long_name; |
400 | 0 | enum opt_parsed opt_flags = OPT_LONG; |
401 | 0 | int allow_unset = !(options->flags & PARSE_OPT_NONEG); |
402 | |
|
403 | 0 | if (options->type == OPTION_SUBCOMMAND) |
404 | 0 | continue; |
405 | 0 | if (!long_name) |
406 | 0 | continue; |
407 | | |
408 | 0 | if (skip_prefix(long_name, "no-", &long_name)) |
409 | 0 | opt_flags |= OPT_UNSET; |
410 | 0 | else if (arg_starts_with_no_no) |
411 | 0 | continue; |
412 | | |
413 | 0 | if (((flags ^ opt_flags) & OPT_UNSET) && !allow_unset) |
414 | 0 | continue; |
415 | | |
416 | 0 | if (skip_prefix(arg_start, long_name, &rest)) { |
417 | 0 | if (*rest == '=') |
418 | 0 | p->opt = rest + 1; |
419 | 0 | else if (*rest) |
420 | 0 | continue; |
421 | 0 | return get_value(p, options, flags ^ opt_flags); |
422 | 0 | } |
423 | | |
424 | | /* abbreviated? */ |
425 | 0 | if (!strncmp(long_name, arg_start, arg_end - arg_start)) |
426 | 0 | register_abbrev(p, options, flags ^ opt_flags, |
427 | 0 | &abbrev, &ambiguous); |
428 | | |
429 | | /* negated and abbreviated very much? */ |
430 | 0 | if (allow_unset && starts_with("no-", arg)) |
431 | 0 | register_abbrev(p, options, OPT_UNSET ^ opt_flags, |
432 | 0 | &abbrev, &ambiguous); |
433 | 0 | } |
434 | | |
435 | 0 | if (disallow_abbreviated_options && (ambiguous.option || abbrev.option)) |
436 | 0 | die("disallowed abbreviated or ambiguous option '%.*s'", |
437 | 0 | (int)(arg_end - arg), arg); |
438 | | |
439 | 0 | if (ambiguous.option) { |
440 | 0 | error(_("ambiguous option: %s " |
441 | 0 | "(could be --%s%s or --%s%s)"), |
442 | 0 | arg, |
443 | 0 | (ambiguous.flags & OPT_UNSET) ? "no-" : "", |
444 | 0 | ambiguous.option->long_name, |
445 | 0 | (abbrev.flags & OPT_UNSET) ? "no-" : "", |
446 | 0 | abbrev.option->long_name); |
447 | 0 | return PARSE_OPT_HELP; |
448 | 0 | } |
449 | 0 | if (abbrev.option) { |
450 | 0 | if (*arg_end) |
451 | 0 | p->opt = arg_end + 1; |
452 | 0 | return get_value(p, abbrev.option, abbrev.flags); |
453 | 0 | } |
454 | 0 | return PARSE_OPT_UNKNOWN; |
455 | 0 | } |
456 | | |
457 | | static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p, |
458 | | const char *arg, |
459 | | const struct option *options) |
460 | 0 | { |
461 | 0 | for (; options->type != OPTION_END; options++) { |
462 | 0 | if (!(options->flags & PARSE_OPT_NODASH)) |
463 | 0 | continue; |
464 | 0 | if (options->short_name == arg[0] && arg[1] == '\0') |
465 | 0 | return get_value(p, options, OPT_SHORT); |
466 | 0 | } |
467 | 0 | return PARSE_OPT_ERROR; |
468 | 0 | } |
469 | | |
470 | | static enum parse_opt_result parse_subcommand(const char *arg, |
471 | | const struct option *options) |
472 | 0 | { |
473 | 0 | for (; options->type != OPTION_END; options++) |
474 | 0 | if (options->type == OPTION_SUBCOMMAND && |
475 | 0 | !strcmp(options->long_name, arg)) { |
476 | 0 | *(parse_opt_subcommand_fn **)options->value = options->subcommand_fn; |
477 | 0 | return PARSE_OPT_SUBCOMMAND; |
478 | 0 | } |
479 | | |
480 | 0 | return PARSE_OPT_UNKNOWN; |
481 | 0 | } |
482 | | |
483 | | static void check_typos(const char *arg, const struct option *options) |
484 | 0 | { |
485 | 0 | if (strlen(arg) < 3) |
486 | 0 | return; |
487 | | |
488 | 0 | if (starts_with(arg, "no-")) { |
489 | 0 | error(_("did you mean `--%s` (with two dashes)?"), arg); |
490 | 0 | exit(129); |
491 | 0 | } |
492 | | |
493 | 0 | for (; options->type != OPTION_END; options++) { |
494 | 0 | if (!options->long_name) |
495 | 0 | continue; |
496 | 0 | if (starts_with(options->long_name, arg)) { |
497 | 0 | error(_("did you mean `--%s` (with two dashes)?"), arg); |
498 | 0 | exit(129); |
499 | 0 | } |
500 | 0 | } |
501 | 0 | } |
502 | | |
503 | | static void parse_options_check(const struct option *opts) |
504 | 0 | { |
505 | 0 | char short_opts[128]; |
506 | 0 | void *subcommand_value = NULL; |
507 | |
|
508 | 0 | memset(short_opts, '\0', sizeof(short_opts)); |
509 | 0 | for (; opts->type != OPTION_END; opts++) { |
510 | 0 | if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) && |
511 | 0 | (opts->flags & PARSE_OPT_OPTARG)) |
512 | 0 | optbug(opts, "uses incompatible flags " |
513 | 0 | "LASTARG_DEFAULT and OPTARG"); |
514 | 0 | if (opts->short_name) { |
515 | 0 | if (0x7F <= opts->short_name) |
516 | 0 | optbug(opts, "invalid short name"); |
517 | 0 | else if (short_opts[opts->short_name]++) |
518 | 0 | optbug(opts, "short name already used"); |
519 | 0 | } |
520 | 0 | if (opts->flags & PARSE_OPT_NODASH && |
521 | 0 | ((opts->flags & PARSE_OPT_OPTARG) || |
522 | 0 | !(opts->flags & PARSE_OPT_NOARG) || |
523 | 0 | !(opts->flags & PARSE_OPT_NONEG) || |
524 | 0 | opts->long_name)) |
525 | 0 | optbug(opts, "uses feature " |
526 | 0 | "not supported for dashless options"); |
527 | 0 | if (opts->type == OPTION_SET_INT && !opts->defval && |
528 | 0 | opts->long_name && !(opts->flags & PARSE_OPT_NONEG)) |
529 | 0 | optbug(opts, "OPTION_SET_INT 0 should not be negatable"); |
530 | 0 | switch (opts->type) { |
531 | 0 | case OPTION_COUNTUP: |
532 | 0 | case OPTION_BIT: |
533 | 0 | case OPTION_NEGBIT: |
534 | 0 | case OPTION_SET_INT: |
535 | 0 | case OPTION_NUMBER: |
536 | 0 | if ((opts->flags & PARSE_OPT_OPTARG) || |
537 | 0 | !(opts->flags & PARSE_OPT_NOARG)) |
538 | 0 | optbug(opts, "should not accept an argument"); |
539 | 0 | break; |
540 | 0 | case OPTION_CALLBACK: |
541 | 0 | if (!opts->callback && !opts->ll_callback) |
542 | 0 | optbug(opts, "OPTION_CALLBACK needs one callback"); |
543 | 0 | else if (opts->callback && opts->ll_callback) |
544 | 0 | optbug(opts, "OPTION_CALLBACK can't have two callbacks"); |
545 | 0 | break; |
546 | 0 | case OPTION_LOWLEVEL_CALLBACK: |
547 | 0 | if (!opts->ll_callback) |
548 | 0 | optbug(opts, "OPTION_LOWLEVEL_CALLBACK needs a callback"); |
549 | 0 | if (opts->callback) |
550 | 0 | optbug(opts, "OPTION_LOWLEVEL_CALLBACK needs no high level callback"); |
551 | 0 | break; |
552 | 0 | case OPTION_ALIAS: |
553 | 0 | optbug(opts, "OPT_ALIAS() should not remain at this point. " |
554 | 0 | "Are you using parse_options_step() directly?\n" |
555 | 0 | "That case is not supported yet."); |
556 | 0 | break; |
557 | 0 | case OPTION_SUBCOMMAND: |
558 | 0 | if (!opts->value || !opts->subcommand_fn) |
559 | 0 | optbug(opts, "OPTION_SUBCOMMAND needs a value and a subcommand function"); |
560 | 0 | if (!subcommand_value) |
561 | 0 | subcommand_value = opts->value; |
562 | 0 | else if (subcommand_value != opts->value) |
563 | 0 | optbug(opts, "all OPTION_SUBCOMMANDs need the same value"); |
564 | 0 | break; |
565 | 0 | default: |
566 | 0 | ; /* ok. (usually accepts an argument) */ |
567 | 0 | } |
568 | 0 | if (opts->argh && |
569 | 0 | strcspn(opts->argh, " _") != strlen(opts->argh)) |
570 | 0 | optbug(opts, "multi-word argh should use dash to separate words"); |
571 | 0 | } |
572 | 0 | BUG_if_bug("invalid 'struct option'"); |
573 | 0 | } |
574 | | |
575 | | static int has_subcommands(const struct option *options) |
576 | 0 | { |
577 | 0 | for (; options->type != OPTION_END; options++) |
578 | 0 | if (options->type == OPTION_SUBCOMMAND) |
579 | 0 | return 1; |
580 | 0 | return 0; |
581 | 0 | } |
582 | | |
583 | | static void parse_options_start_1(struct parse_opt_ctx_t *ctx, |
584 | | int argc, const char **argv, const char *prefix, |
585 | | const struct option *options, |
586 | | enum parse_opt_flags flags) |
587 | 0 | { |
588 | 0 | ctx->argc = argc; |
589 | 0 | ctx->argv = argv; |
590 | 0 | if (!(flags & PARSE_OPT_ONE_SHOT)) { |
591 | 0 | ctx->argc--; |
592 | 0 | ctx->argv++; |
593 | 0 | } |
594 | 0 | ctx->total = ctx->argc; |
595 | 0 | ctx->out = argv; |
596 | 0 | ctx->prefix = prefix; |
597 | 0 | ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); |
598 | 0 | ctx->flags = flags; |
599 | 0 | ctx->has_subcommands = has_subcommands(options); |
600 | 0 | if (!ctx->has_subcommands && (flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) |
601 | 0 | BUG("Using PARSE_OPT_SUBCOMMAND_OPTIONAL without subcommands"); |
602 | 0 | if (ctx->has_subcommands) { |
603 | 0 | if (flags & PARSE_OPT_STOP_AT_NON_OPTION) |
604 | 0 | BUG("subcommands are incompatible with PARSE_OPT_STOP_AT_NON_OPTION"); |
605 | 0 | if (!(flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) { |
606 | 0 | if (flags & PARSE_OPT_KEEP_UNKNOWN_OPT) |
607 | 0 | BUG("subcommands are incompatible with PARSE_OPT_KEEP_UNKNOWN_OPT unless in combination with PARSE_OPT_SUBCOMMAND_OPTIONAL"); |
608 | 0 | if (flags & PARSE_OPT_KEEP_DASHDASH) |
609 | 0 | BUG("subcommands are incompatible with PARSE_OPT_KEEP_DASHDASH unless in combination with PARSE_OPT_SUBCOMMAND_OPTIONAL"); |
610 | 0 | } |
611 | 0 | } |
612 | 0 | if ((flags & PARSE_OPT_KEEP_UNKNOWN_OPT) && |
613 | 0 | (flags & PARSE_OPT_STOP_AT_NON_OPTION) && |
614 | 0 | !(flags & PARSE_OPT_ONE_SHOT)) |
615 | 0 | BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); |
616 | 0 | if ((flags & PARSE_OPT_ONE_SHOT) && |
617 | 0 | (flags & PARSE_OPT_KEEP_ARGV0)) |
618 | 0 | BUG("Can't keep argv0 if you don't have it"); |
619 | 0 | parse_options_check(options); |
620 | 0 | build_cmdmode_list(ctx, options); |
621 | 0 | } |
622 | | |
623 | | void parse_options_start(struct parse_opt_ctx_t *ctx, |
624 | | int argc, const char **argv, const char *prefix, |
625 | | const struct option *options, |
626 | | enum parse_opt_flags flags) |
627 | 0 | { |
628 | 0 | memset(ctx, 0, sizeof(*ctx)); |
629 | 0 | parse_options_start_1(ctx, argc, argv, prefix, options, flags); |
630 | 0 | } |
631 | | |
632 | | static void show_negated_gitcomp(const struct option *opts, int show_all, |
633 | | int nr_noopts) |
634 | 0 | { |
635 | 0 | int printed_dashdash = 0; |
636 | |
|
637 | 0 | for (; opts->type != OPTION_END; opts++) { |
638 | 0 | int has_unset_form = 0; |
639 | 0 | const char *name; |
640 | |
|
641 | 0 | if (!opts->long_name) |
642 | 0 | continue; |
643 | 0 | if (!show_all && |
644 | 0 | (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))) |
645 | 0 | continue; |
646 | 0 | if (opts->flags & PARSE_OPT_NONEG) |
647 | 0 | continue; |
648 | | |
649 | 0 | switch (opts->type) { |
650 | 0 | case OPTION_STRING: |
651 | 0 | case OPTION_FILENAME: |
652 | 0 | case OPTION_INTEGER: |
653 | 0 | case OPTION_MAGNITUDE: |
654 | 0 | case OPTION_CALLBACK: |
655 | 0 | case OPTION_BIT: |
656 | 0 | case OPTION_NEGBIT: |
657 | 0 | case OPTION_COUNTUP: |
658 | 0 | case OPTION_SET_INT: |
659 | 0 | has_unset_form = 1; |
660 | 0 | break; |
661 | 0 | default: |
662 | 0 | break; |
663 | 0 | } |
664 | 0 | if (!has_unset_form) |
665 | 0 | continue; |
666 | | |
667 | 0 | if (skip_prefix(opts->long_name, "no-", &name)) { |
668 | 0 | if (nr_noopts < 0) |
669 | 0 | printf(" --%s", name); |
670 | 0 | } else if (nr_noopts >= 0) { |
671 | 0 | if (nr_noopts && !printed_dashdash) { |
672 | 0 | printf(" --"); |
673 | 0 | printed_dashdash = 1; |
674 | 0 | } |
675 | 0 | printf(" --no-%s", opts->long_name); |
676 | 0 | nr_noopts++; |
677 | 0 | } |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | | static int show_gitcomp(const struct option *opts, int show_all) |
682 | 0 | { |
683 | 0 | const struct option *original_opts = opts; |
684 | 0 | int nr_noopts = 0; |
685 | |
|
686 | 0 | for (; opts->type != OPTION_END; opts++) { |
687 | 0 | const char *prefix = "--"; |
688 | 0 | const char *suffix = ""; |
689 | |
|
690 | 0 | if (!opts->long_name) |
691 | 0 | continue; |
692 | 0 | if (!show_all && |
693 | 0 | (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE | PARSE_OPT_FROM_ALIAS))) |
694 | 0 | continue; |
695 | | |
696 | 0 | switch (opts->type) { |
697 | 0 | case OPTION_SUBCOMMAND: |
698 | 0 | prefix = ""; |
699 | 0 | break; |
700 | 0 | case OPTION_GROUP: |
701 | 0 | continue; |
702 | 0 | case OPTION_STRING: |
703 | 0 | case OPTION_FILENAME: |
704 | 0 | case OPTION_INTEGER: |
705 | 0 | case OPTION_MAGNITUDE: |
706 | 0 | case OPTION_CALLBACK: |
707 | 0 | if (opts->flags & PARSE_OPT_NOARG) |
708 | 0 | break; |
709 | 0 | if (opts->flags & PARSE_OPT_OPTARG) |
710 | 0 | break; |
711 | 0 | if (opts->flags & PARSE_OPT_LASTARG_DEFAULT) |
712 | 0 | break; |
713 | 0 | suffix = "="; |
714 | 0 | break; |
715 | 0 | default: |
716 | 0 | break; |
717 | 0 | } |
718 | 0 | if (opts->flags & PARSE_OPT_COMP_ARG) |
719 | 0 | suffix = "="; |
720 | 0 | if (starts_with(opts->long_name, "no-")) |
721 | 0 | nr_noopts++; |
722 | 0 | printf("%s%s%s%s", opts == original_opts ? "" : " ", |
723 | 0 | prefix, opts->long_name, suffix); |
724 | 0 | } |
725 | 0 | show_negated_gitcomp(original_opts, show_all, -1); |
726 | 0 | show_negated_gitcomp(original_opts, show_all, nr_noopts); |
727 | 0 | fputc('\n', stdout); |
728 | 0 | return PARSE_OPT_COMPLETE; |
729 | 0 | } |
730 | | |
731 | | /* |
732 | | * Scan and may produce a new option[] array, which should be used |
733 | | * instead of the original 'options'. |
734 | | * |
735 | | * Right now this is only used to preprocess and substitute |
736 | | * OPTION_ALIAS. |
737 | | * |
738 | | * The returned options should be freed using free_preprocessed_options. |
739 | | */ |
740 | | static struct option *preprocess_options(struct parse_opt_ctx_t *ctx, |
741 | | const struct option *options) |
742 | 0 | { |
743 | 0 | struct option *newopt; |
744 | 0 | int i, nr, alias; |
745 | 0 | int nr_aliases = 0; |
746 | |
|
747 | 0 | for (nr = 0; options[nr].type != OPTION_END; nr++) { |
748 | 0 | if (options[nr].type == OPTION_ALIAS) |
749 | 0 | nr_aliases++; |
750 | 0 | } |
751 | |
|
752 | 0 | if (!nr_aliases) |
753 | 0 | return NULL; |
754 | | |
755 | 0 | DUP_ARRAY(newopt, options, nr + 1); |
756 | | |
757 | | /* each alias has two string pointers and NULL */ |
758 | 0 | CALLOC_ARRAY(ctx->alias_groups, 3 * (nr_aliases + 1)); |
759 | |
|
760 | 0 | for (alias = 0, i = 0; i < nr; i++) { |
761 | 0 | int short_name; |
762 | 0 | const char *long_name; |
763 | 0 | const char *source; |
764 | 0 | struct strbuf help = STRBUF_INIT; |
765 | 0 | int j; |
766 | |
|
767 | 0 | if (newopt[i].type != OPTION_ALIAS) |
768 | 0 | continue; |
769 | | |
770 | 0 | short_name = newopt[i].short_name; |
771 | 0 | long_name = newopt[i].long_name; |
772 | 0 | source = newopt[i].value; |
773 | |
|
774 | 0 | if (!long_name) |
775 | 0 | BUG("An alias must have long option name"); |
776 | 0 | strbuf_addf(&help, _("alias of --%s"), source); |
777 | |
|
778 | 0 | for (j = 0; j < nr; j++) { |
779 | 0 | const char *name = options[j].long_name; |
780 | |
|
781 | 0 | if (!name || strcmp(name, source)) |
782 | 0 | continue; |
783 | | |
784 | 0 | if (options[j].type == OPTION_ALIAS) |
785 | 0 | BUG("No please. Nested aliases are not supported."); |
786 | | |
787 | 0 | memcpy(newopt + i, options + j, sizeof(*newopt)); |
788 | 0 | newopt[i].short_name = short_name; |
789 | 0 | newopt[i].long_name = long_name; |
790 | 0 | newopt[i].help = strbuf_detach(&help, NULL); |
791 | 0 | newopt[i].flags |= PARSE_OPT_FROM_ALIAS; |
792 | 0 | break; |
793 | 0 | } |
794 | | |
795 | 0 | if (j == nr) |
796 | 0 | BUG("could not find source option '%s' of alias '%s'", |
797 | 0 | source, newopt[i].long_name); |
798 | 0 | ctx->alias_groups[alias * 3 + 0] = newopt[i].long_name; |
799 | 0 | ctx->alias_groups[alias * 3 + 1] = options[j].long_name; |
800 | 0 | ctx->alias_groups[alias * 3 + 2] = NULL; |
801 | 0 | alias++; |
802 | 0 | } |
803 | | |
804 | 0 | return newopt; |
805 | 0 | } |
806 | | |
807 | | static void free_preprocessed_options(struct option *options) |
808 | 0 | { |
809 | 0 | int i; |
810 | |
|
811 | 0 | if (!options) |
812 | 0 | return; |
813 | | |
814 | 0 | for (i = 0; options[i].type != OPTION_END; i++) { |
815 | 0 | if (options[i].flags & PARSE_OPT_FROM_ALIAS) |
816 | 0 | free((void *)options[i].help); |
817 | 0 | } |
818 | 0 | free(options); |
819 | 0 | } |
820 | | |
821 | | static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *, |
822 | | const char * const *, |
823 | | const struct option *, |
824 | | int, int); |
825 | | |
826 | | enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx, |
827 | | const struct option *options, |
828 | | const char * const usagestr[]) |
829 | 0 | { |
830 | 0 | int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); |
831 | | |
832 | | /* we must reset ->opt, unknown short option leave it dangling */ |
833 | 0 | ctx->opt = NULL; |
834 | |
|
835 | 0 | for (; ctx->argc; ctx->argc--, ctx->argv++) { |
836 | 0 | const char *arg = ctx->argv[0]; |
837 | |
|
838 | 0 | if (ctx->flags & PARSE_OPT_ONE_SHOT && |
839 | 0 | ctx->argc != ctx->total) |
840 | 0 | break; |
841 | | |
842 | 0 | if (*arg != '-' || !arg[1]) { |
843 | 0 | if (parse_nodash_opt(ctx, arg, options) == 0) |
844 | 0 | continue; |
845 | 0 | if (!ctx->has_subcommands) { |
846 | 0 | if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) |
847 | 0 | return PARSE_OPT_NON_OPTION; |
848 | 0 | ctx->out[ctx->cpidx++] = ctx->argv[0]; |
849 | 0 | continue; |
850 | 0 | } |
851 | 0 | switch (parse_subcommand(arg, options)) { |
852 | 0 | case PARSE_OPT_SUBCOMMAND: |
853 | 0 | return PARSE_OPT_SUBCOMMAND; |
854 | 0 | case PARSE_OPT_UNKNOWN: |
855 | 0 | if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL) |
856 | | /* |
857 | | * arg is neither a short or long |
858 | | * option nor a subcommand. Since |
859 | | * this command has a default |
860 | | * operation mode, we have to treat |
861 | | * this arg and all remaining args |
862 | | * as args meant to that default |
863 | | * operation mode. |
864 | | * So we are done parsing. |
865 | | */ |
866 | 0 | return PARSE_OPT_DONE; |
867 | 0 | error(_("unknown subcommand: `%s'"), arg); |
868 | 0 | usage_with_options(usagestr, options); |
869 | 0 | case PARSE_OPT_COMPLETE: |
870 | 0 | case PARSE_OPT_HELP: |
871 | 0 | case PARSE_OPT_ERROR: |
872 | 0 | case PARSE_OPT_DONE: |
873 | 0 | case PARSE_OPT_NON_OPTION: |
874 | | /* Impossible. */ |
875 | 0 | BUG("parse_subcommand() cannot return these"); |
876 | 0 | } |
877 | 0 | } |
878 | | |
879 | | /* lone -h asks for help */ |
880 | 0 | if (internal_help && ctx->total == 1 && !strcmp(arg + 1, "h")) |
881 | 0 | goto show_usage; |
882 | | |
883 | | /* |
884 | | * lone --git-completion-helper and --git-completion-helper-all |
885 | | * are asked by git-completion.bash |
886 | | */ |
887 | 0 | if (ctx->total == 1 && !strcmp(arg, "--git-completion-helper")) |
888 | 0 | return show_gitcomp(options, 0); |
889 | 0 | if (ctx->total == 1 && !strcmp(arg, "--git-completion-helper-all")) |
890 | 0 | return show_gitcomp(options, 1); |
891 | | |
892 | 0 | if (arg[1] != '-') { |
893 | 0 | ctx->opt = arg + 1; |
894 | 0 | switch (parse_short_opt(ctx, options)) { |
895 | 0 | case PARSE_OPT_ERROR: |
896 | 0 | return PARSE_OPT_ERROR; |
897 | 0 | case PARSE_OPT_UNKNOWN: |
898 | 0 | if (ctx->opt) |
899 | 0 | check_typos(arg + 1, options); |
900 | 0 | if (internal_help && *ctx->opt == 'h') |
901 | 0 | goto show_usage; |
902 | 0 | goto unknown; |
903 | 0 | case PARSE_OPT_NON_OPTION: |
904 | 0 | case PARSE_OPT_SUBCOMMAND: |
905 | 0 | case PARSE_OPT_HELP: |
906 | 0 | case PARSE_OPT_COMPLETE: |
907 | 0 | BUG("parse_short_opt() cannot return these"); |
908 | 0 | case PARSE_OPT_DONE: |
909 | 0 | break; |
910 | 0 | } |
911 | 0 | if (ctx->opt) |
912 | 0 | check_typos(arg + 1, options); |
913 | 0 | while (ctx->opt) { |
914 | 0 | switch (parse_short_opt(ctx, options)) { |
915 | 0 | case PARSE_OPT_ERROR: |
916 | 0 | return PARSE_OPT_ERROR; |
917 | 0 | case PARSE_OPT_UNKNOWN: |
918 | 0 | if (internal_help && *ctx->opt == 'h') |
919 | 0 | goto show_usage; |
920 | | |
921 | | /* fake a short option thing to hide the fact that we may have |
922 | | * started to parse aggregated stuff |
923 | | * |
924 | | * This is leaky, too bad. |
925 | | */ |
926 | 0 | ctx->argv[0] = xstrdup(ctx->opt - 1); |
927 | 0 | *(char *)ctx->argv[0] = '-'; |
928 | 0 | goto unknown; |
929 | 0 | case PARSE_OPT_NON_OPTION: |
930 | 0 | case PARSE_OPT_SUBCOMMAND: |
931 | 0 | case PARSE_OPT_COMPLETE: |
932 | 0 | case PARSE_OPT_HELP: |
933 | 0 | BUG("parse_short_opt() cannot return these"); |
934 | 0 | case PARSE_OPT_DONE: |
935 | 0 | break; |
936 | 0 | } |
937 | 0 | } |
938 | 0 | continue; |
939 | 0 | } |
940 | | |
941 | 0 | if (!arg[2] /* "--" */) { |
942 | 0 | if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { |
943 | 0 | ctx->argc--; |
944 | 0 | ctx->argv++; |
945 | 0 | } |
946 | 0 | break; |
947 | 0 | } else if (!strcmp(arg + 2, "end-of-options")) { |
948 | 0 | if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) { |
949 | 0 | ctx->argc--; |
950 | 0 | ctx->argv++; |
951 | 0 | } |
952 | 0 | break; |
953 | 0 | } |
954 | | |
955 | 0 | if (internal_help && !strcmp(arg + 2, "help-all")) |
956 | 0 | return usage_with_options_internal(ctx, usagestr, options, 1, 0); |
957 | 0 | if (internal_help && !strcmp(arg + 2, "help")) |
958 | 0 | goto show_usage; |
959 | 0 | switch (parse_long_opt(ctx, arg + 2, options)) { |
960 | 0 | case PARSE_OPT_ERROR: |
961 | 0 | return PARSE_OPT_ERROR; |
962 | 0 | case PARSE_OPT_UNKNOWN: |
963 | 0 | goto unknown; |
964 | 0 | case PARSE_OPT_HELP: |
965 | 0 | goto show_usage; |
966 | 0 | case PARSE_OPT_NON_OPTION: |
967 | 0 | case PARSE_OPT_SUBCOMMAND: |
968 | 0 | case PARSE_OPT_COMPLETE: |
969 | 0 | BUG("parse_long_opt() cannot return these"); |
970 | 0 | case PARSE_OPT_DONE: |
971 | 0 | break; |
972 | 0 | } |
973 | 0 | continue; |
974 | 0 | unknown: |
975 | 0 | if (ctx->flags & PARSE_OPT_ONE_SHOT) |
976 | 0 | break; |
977 | 0 | if (ctx->has_subcommands && |
978 | 0 | (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL) && |
979 | 0 | (ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) { |
980 | | /* |
981 | | * Found an unknown option given to a command with |
982 | | * subcommands that has a default operation mode: |
983 | | * we treat this option and all remaining args as |
984 | | * arguments meant to that default operation mode. |
985 | | * So we are done parsing. |
986 | | */ |
987 | 0 | return PARSE_OPT_DONE; |
988 | 0 | } |
989 | 0 | if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) |
990 | 0 | return PARSE_OPT_UNKNOWN; |
991 | 0 | ctx->out[ctx->cpidx++] = ctx->argv[0]; |
992 | 0 | ctx->opt = NULL; |
993 | 0 | } |
994 | 0 | return PARSE_OPT_DONE; |
995 | | |
996 | 0 | show_usage: |
997 | 0 | return usage_with_options_internal(ctx, usagestr, options, 0, 0); |
998 | 0 | } |
999 | | |
1000 | | int parse_options_end(struct parse_opt_ctx_t *ctx) |
1001 | 0 | { |
1002 | 0 | if (ctx->flags & PARSE_OPT_ONE_SHOT) |
1003 | 0 | return ctx->total - ctx->argc; |
1004 | | |
1005 | 0 | MOVE_ARRAY(ctx->out + ctx->cpidx, ctx->argv, ctx->argc); |
1006 | 0 | ctx->out[ctx->cpidx + ctx->argc] = NULL; |
1007 | 0 | return ctx->cpidx + ctx->argc; |
1008 | 0 | } |
1009 | | |
1010 | | int parse_options(int argc, const char **argv, |
1011 | | const char *prefix, |
1012 | | const struct option *options, |
1013 | | const char * const usagestr[], |
1014 | | enum parse_opt_flags flags) |
1015 | 0 | { |
1016 | 0 | struct parse_opt_ctx_t ctx; |
1017 | 0 | struct option *real_options; |
1018 | |
|
1019 | 0 | disallow_abbreviated_options = |
1020 | 0 | git_env_bool("GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS", 0); |
1021 | |
|
1022 | 0 | memset(&ctx, 0, sizeof(ctx)); |
1023 | 0 | real_options = preprocess_options(&ctx, options); |
1024 | 0 | if (real_options) |
1025 | 0 | options = real_options; |
1026 | 0 | parse_options_start_1(&ctx, argc, argv, prefix, options, flags); |
1027 | 0 | switch (parse_options_step(&ctx, options, usagestr)) { |
1028 | 0 | case PARSE_OPT_HELP: |
1029 | 0 | case PARSE_OPT_ERROR: |
1030 | 0 | exit(129); |
1031 | 0 | case PARSE_OPT_COMPLETE: |
1032 | 0 | exit(0); |
1033 | 0 | case PARSE_OPT_NON_OPTION: |
1034 | 0 | case PARSE_OPT_SUBCOMMAND: |
1035 | 0 | break; |
1036 | 0 | case PARSE_OPT_DONE: |
1037 | 0 | if (ctx.has_subcommands && |
1038 | 0 | !(flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) { |
1039 | 0 | error(_("need a subcommand")); |
1040 | 0 | usage_with_options(usagestr, options); |
1041 | 0 | } |
1042 | 0 | break; |
1043 | 0 | case PARSE_OPT_UNKNOWN: |
1044 | 0 | if (ctx.argv[0][1] == '-') { |
1045 | 0 | error(_("unknown option `%s'"), ctx.argv[0] + 2); |
1046 | 0 | } else if (isascii(*ctx.opt)) { |
1047 | 0 | error(_("unknown switch `%c'"), *ctx.opt); |
1048 | 0 | } else { |
1049 | 0 | error(_("unknown non-ascii option in string: `%s'"), |
1050 | 0 | ctx.argv[0]); |
1051 | 0 | } |
1052 | 0 | usage_with_options(usagestr, options); |
1053 | 0 | } |
1054 | | |
1055 | 0 | precompose_argv_prefix(argc, argv, NULL); |
1056 | 0 | free_preprocessed_options(real_options); |
1057 | 0 | free(ctx.alias_groups); |
1058 | 0 | for (struct parse_opt_cmdmode_list *elem = ctx.cmdmode_list; elem;) { |
1059 | 0 | struct parse_opt_cmdmode_list *next = elem->next; |
1060 | 0 | free(elem); |
1061 | 0 | elem = next; |
1062 | 0 | } |
1063 | 0 | return parse_options_end(&ctx); |
1064 | 0 | } |
1065 | | |
1066 | | static int usage_argh(const struct option *opts, FILE *outfile) |
1067 | 0 | { |
1068 | 0 | const char *s; |
1069 | 0 | int literal = (opts->flags & PARSE_OPT_LITERAL_ARGHELP) || |
1070 | 0 | !opts->argh || !!strpbrk(opts->argh, "()<>[]|"); |
1071 | 0 | if (opts->flags & PARSE_OPT_OPTARG) |
1072 | 0 | if (opts->long_name) |
1073 | 0 | s = literal ? "[=%s]" : "[=<%s>]"; |
1074 | 0 | else |
1075 | 0 | s = literal ? "[%s]" : "[<%s>]"; |
1076 | 0 | else |
1077 | 0 | s = literal ? " %s" : " <%s>"; |
1078 | 0 | return utf8_fprintf(outfile, s, opts->argh ? _(opts->argh) : _("...")); |
1079 | 0 | } |
1080 | | |
1081 | | static int usage_indent(FILE *outfile) |
1082 | 0 | { |
1083 | 0 | return fprintf(outfile, " "); |
1084 | 0 | } |
1085 | | |
1086 | 0 | #define USAGE_OPTS_WIDTH 26 |
1087 | | |
1088 | | static void usage_padding(FILE *outfile, size_t pos) |
1089 | 0 | { |
1090 | 0 | if (pos < USAGE_OPTS_WIDTH) |
1091 | 0 | fprintf(outfile, "%*s", USAGE_OPTS_WIDTH - (int)pos, ""); |
1092 | 0 | else |
1093 | 0 | fprintf(outfile, "\n%*s", USAGE_OPTS_WIDTH, ""); |
1094 | 0 | } |
1095 | | |
1096 | | static const struct option *find_option_by_long_name(const struct option *opts, |
1097 | | const char *long_name) |
1098 | 0 | { |
1099 | 0 | for (; opts->type != OPTION_END; opts++) { |
1100 | 0 | if (opts->long_name && !strcmp(opts->long_name, long_name)) |
1101 | 0 | return opts; |
1102 | 0 | } |
1103 | 0 | return NULL; |
1104 | 0 | } |
1105 | | |
1106 | | static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t *ctx, |
1107 | | const char * const *usagestr, |
1108 | | const struct option *opts, |
1109 | | int full, int err) |
1110 | 0 | { |
1111 | 0 | const struct option *all_opts = opts; |
1112 | 0 | FILE *outfile = err ? stderr : stdout; |
1113 | 0 | int need_newline; |
1114 | |
|
1115 | 0 | const char *usage_prefix = _("usage: %s"); |
1116 | | /* |
1117 | | * The translation could be anything, but we can count on |
1118 | | * msgfmt(1)'s --check option to have asserted that "%s" is in |
1119 | | * the translation. So compute the length of the "usage: " |
1120 | | * part. We are assuming that the translator wasn't overly |
1121 | | * clever and used e.g. "%1$s" instead of "%s", there's only |
1122 | | * one "%s" in "usage_prefix" above, so there's no reason to |
1123 | | * do so even with a RTL language. |
1124 | | */ |
1125 | 0 | size_t usage_len = strlen(usage_prefix) - strlen("%s"); |
1126 | | /* |
1127 | | * TRANSLATORS: the colon here should align with the |
1128 | | * one in "usage: %s" translation. |
1129 | | */ |
1130 | 0 | const char *or_prefix = _(" or: %s"); |
1131 | | /* |
1132 | | * TRANSLATORS: You should only need to translate this format |
1133 | | * string if your language is a RTL language (e.g. Arabic, |
1134 | | * Hebrew etc.), not if it's a LTR language (e.g. German, |
1135 | | * Russian, Chinese etc.). |
1136 | | * |
1137 | | * When a translated usage string has an embedded "\n" it's |
1138 | | * because options have wrapped to the next line. The line |
1139 | | * after the "\n" will then be padded to align with the |
1140 | | * command name, such as N_("git cmd [opt]\n<8 |
1141 | | * spaces>[opt2]"), where the 8 spaces are the same length as |
1142 | | * "git cmd ". |
1143 | | * |
1144 | | * This format string prints out that already-translated |
1145 | | * line. The "%*s" is whitespace padding to account for the |
1146 | | * padding at the start of the line that we add in this |
1147 | | * function. The "%s" is a line in the (hopefully already |
1148 | | * translated) N_() usage string, which contained embedded |
1149 | | * newlines before we split it up. |
1150 | | */ |
1151 | 0 | const char *usage_continued = _("%*s%s"); |
1152 | 0 | const char *prefix = usage_prefix; |
1153 | 0 | int saw_empty_line = 0; |
1154 | |
|
1155 | 0 | if (!usagestr) |
1156 | 0 | return PARSE_OPT_HELP; |
1157 | | |
1158 | 0 | if (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL) |
1159 | 0 | fprintf(outfile, "cat <<\\EOF\n"); |
1160 | |
|
1161 | 0 | while (*usagestr) { |
1162 | 0 | const char *str = _(*usagestr++); |
1163 | 0 | struct string_list list = STRING_LIST_INIT_DUP; |
1164 | 0 | unsigned int j; |
1165 | |
|
1166 | 0 | if (!saw_empty_line && !*str) |
1167 | 0 | saw_empty_line = 1; |
1168 | |
|
1169 | 0 | string_list_split(&list, str, '\n', -1); |
1170 | 0 | for (j = 0; j < list.nr; j++) { |
1171 | 0 | const char *line = list.items[j].string; |
1172 | |
|
1173 | 0 | if (saw_empty_line && *line) |
1174 | 0 | fprintf_ln(outfile, _(" %s"), line); |
1175 | 0 | else if (saw_empty_line) |
1176 | 0 | fputc('\n', outfile); |
1177 | 0 | else if (!j) |
1178 | 0 | fprintf_ln(outfile, prefix, line); |
1179 | 0 | else |
1180 | 0 | fprintf_ln(outfile, usage_continued, |
1181 | 0 | (int)usage_len, "", line); |
1182 | 0 | } |
1183 | 0 | string_list_clear(&list, 0); |
1184 | |
|
1185 | 0 | prefix = or_prefix; |
1186 | 0 | } |
1187 | |
|
1188 | 0 | need_newline = 1; |
1189 | |
|
1190 | 0 | for (; opts->type != OPTION_END; opts++) { |
1191 | 0 | size_t pos; |
1192 | 0 | const char *cp, *np; |
1193 | 0 | const char *positive_name = NULL; |
1194 | |
|
1195 | 0 | if (opts->type == OPTION_SUBCOMMAND) |
1196 | 0 | continue; |
1197 | 0 | if (opts->type == OPTION_GROUP) { |
1198 | 0 | fputc('\n', outfile); |
1199 | 0 | need_newline = 0; |
1200 | 0 | if (*opts->help) |
1201 | 0 | fprintf(outfile, "%s\n", _(opts->help)); |
1202 | 0 | continue; |
1203 | 0 | } |
1204 | 0 | if (!full && (opts->flags & PARSE_OPT_HIDDEN)) |
1205 | 0 | continue; |
1206 | | |
1207 | 0 | if (need_newline) { |
1208 | 0 | fputc('\n', outfile); |
1209 | 0 | need_newline = 0; |
1210 | 0 | } |
1211 | |
|
1212 | 0 | pos = usage_indent(outfile); |
1213 | 0 | if (opts->short_name) { |
1214 | 0 | if (opts->flags & PARSE_OPT_NODASH) |
1215 | 0 | pos += fprintf(outfile, "%c", opts->short_name); |
1216 | 0 | else |
1217 | 0 | pos += fprintf(outfile, "-%c", opts->short_name); |
1218 | 0 | } |
1219 | 0 | if (opts->long_name && opts->short_name) |
1220 | 0 | pos += fprintf(outfile, ", "); |
1221 | 0 | if (opts->long_name) { |
1222 | 0 | const char *long_name = opts->long_name; |
1223 | 0 | if ((opts->flags & PARSE_OPT_NONEG) || |
1224 | 0 | skip_prefix(long_name, "no-", &positive_name)) |
1225 | 0 | pos += fprintf(outfile, "--%s", long_name); |
1226 | 0 | else |
1227 | 0 | pos += fprintf(outfile, "--[no-]%s", long_name); |
1228 | 0 | } |
1229 | |
|
1230 | 0 | if (opts->type == OPTION_NUMBER) |
1231 | 0 | pos += utf8_fprintf(outfile, _("-NUM")); |
1232 | |
|
1233 | 0 | if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) || |
1234 | 0 | !(opts->flags & PARSE_OPT_NOARG)) |
1235 | 0 | pos += usage_argh(opts, outfile); |
1236 | |
|
1237 | 0 | if (opts->type == OPTION_ALIAS) { |
1238 | 0 | usage_padding(outfile, pos); |
1239 | 0 | fprintf_ln(outfile, _("alias of --%s"), |
1240 | 0 | (const char *)opts->value); |
1241 | 0 | continue; |
1242 | 0 | } |
1243 | | |
1244 | 0 | for (cp = opts->help ? _(opts->help) : ""; *cp; cp = np) { |
1245 | 0 | np = strchrnul(cp, '\n'); |
1246 | 0 | if (*np) |
1247 | 0 | np++; |
1248 | 0 | usage_padding(outfile, pos); |
1249 | 0 | fwrite(cp, 1, np - cp, outfile); |
1250 | 0 | pos = 0; |
1251 | 0 | } |
1252 | 0 | fputc('\n', outfile); |
1253 | |
|
1254 | 0 | if (positive_name) { |
1255 | 0 | if (find_option_by_long_name(all_opts, positive_name)) |
1256 | 0 | continue; |
1257 | 0 | pos = usage_indent(outfile); |
1258 | 0 | pos += fprintf(outfile, "--%s", positive_name); |
1259 | 0 | usage_padding(outfile, pos); |
1260 | 0 | fprintf_ln(outfile, _("opposite of --no-%s"), |
1261 | 0 | positive_name); |
1262 | 0 | } |
1263 | 0 | } |
1264 | 0 | fputc('\n', outfile); |
1265 | |
|
1266 | 0 | if (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL) |
1267 | 0 | fputs("EOF\n", outfile); |
1268 | |
|
1269 | 0 | return PARSE_OPT_HELP; |
1270 | 0 | } |
1271 | | |
1272 | | void NORETURN usage_with_options(const char * const *usagestr, |
1273 | | const struct option *opts) |
1274 | 0 | { |
1275 | 0 | usage_with_options_internal(NULL, usagestr, opts, 0, 1); |
1276 | 0 | exit(129); |
1277 | 0 | } |
1278 | | |
1279 | | void NORETURN usage_msg_opt(const char *msg, |
1280 | | const char * const *usagestr, |
1281 | | const struct option *options) |
1282 | 0 | { |
1283 | 0 | die_message("%s\n", msg); /* The extra \n is intentional */ |
1284 | 0 | usage_with_options(usagestr, options); |
1285 | 0 | } |
1286 | | |
1287 | | void NORETURN usage_msg_optf(const char * const fmt, |
1288 | | const char * const *usagestr, |
1289 | | const struct option *options, ...) |
1290 | 0 | { |
1291 | 0 | struct strbuf msg = STRBUF_INIT; |
1292 | 0 | va_list ap; |
1293 | 0 | va_start(ap, options); |
1294 | 0 | strbuf_vaddf(&msg, fmt, ap); |
1295 | 0 | va_end(ap); |
1296 | |
|
1297 | 0 | usage_msg_opt(msg.buf, usagestr, options); |
1298 | 0 | } |
1299 | | |
1300 | | void die_for_incompatible_opt4(int opt1, const char *opt1_name, |
1301 | | int opt2, const char *opt2_name, |
1302 | | int opt3, const char *opt3_name, |
1303 | | int opt4, const char *opt4_name) |
1304 | 0 | { |
1305 | 0 | int count = 0; |
1306 | 0 | const char *options[4]; |
1307 | |
|
1308 | 0 | if (opt1) |
1309 | 0 | options[count++] = opt1_name; |
1310 | 0 | if (opt2) |
1311 | 0 | options[count++] = opt2_name; |
1312 | 0 | if (opt3) |
1313 | 0 | options[count++] = opt3_name; |
1314 | 0 | if (opt4) |
1315 | 0 | options[count++] = opt4_name; |
1316 | 0 | switch (count) { |
1317 | 0 | case 4: |
1318 | 0 | die(_("options '%s', '%s', '%s', and '%s' cannot be used together"), |
1319 | 0 | opt1_name, opt2_name, opt3_name, opt4_name); |
1320 | 0 | break; |
1321 | 0 | case 3: |
1322 | 0 | die(_("options '%s', '%s', and '%s' cannot be used together"), |
1323 | 0 | options[0], options[1], options[2]); |
1324 | 0 | break; |
1325 | 0 | case 2: |
1326 | 0 | die(_("options '%s' and '%s' cannot be used together"), |
1327 | 0 | options[0], options[1]); |
1328 | 0 | break; |
1329 | 0 | default: |
1330 | 0 | break; |
1331 | 0 | } |
1332 | 0 | } |