1 /* Licensed under GPLv2+ - see LICENSE file for details */
2 /* Actual code to parse commandline. */
3 #include <ccan/opt/opt.h>
10 /tmp/opt-example: invalid option -- 'x'
11 /tmp/opt-example: unrecognized option '--long'
12 /tmp/opt-example: option '--someflag' doesn't allow an argument
13 /tmp/opt-example: option '--s' is ambiguous
14 /tmp/opt-example: option requires an argument -- 's'
16 static int parse_err(void (*errlog)(const char *fmt, ...),
17 const char *argv0, const char *arg, unsigned len,
20 errlog("%s: %.*s: %s", argv0, len, arg, problem);
24 static void consume_option(int *argc, char *argv[], unsigned optnum)
26 memmove(&argv[optnum], &argv[optnum+1],
27 sizeof(argv[optnum]) * (*argc-optnum));
31 /* Returns 1 if argument consumed, 0 if all done, -1 on error. */
32 int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
33 void (*errlog)(const char *fmt, ...), bool unknown_ok)
36 const char *o, *optarg = NULL;
39 if (getenv("POSIXLY_CORRECT")) {
40 /* Don't find options after non-options. */
43 for (arg = 1; argv[arg]; arg++) {
44 if (argv[arg][0] == '-')
49 if (!argv[arg] || argv[arg][0] != '-')
52 /* Special arg terminator option. */
53 if (strcmp(argv[arg], "--") == 0) {
54 consume_option(argc, argv, arg);
58 /* Long options start with -- */
59 if (argv[arg][1] == '-') {
61 for (o = first_lopt(&i, &len); o; o = next_lopt(o, &i, &len)) {
62 if (strncmp(argv[arg] + 2, o, len) != 0)
64 if (argv[arg][2 + len] == '=')
65 optarg = argv[arg] + 2 + len + 1;
66 else if (argv[arg][2 + len] != '\0')
73 return parse_err(errlog, argv[0],
74 argv[arg], strlen(argv[arg]),
75 "unrecognized option");
77 /* For error messages, we include the leading '--' */
81 /* offset allows us to handle -abc */
82 for (o = first_sopt(&i); o; o = next_sopt(o, &i)) {
83 if (argv[arg][*offset + 1] != *o)
93 return parse_err(errlog, argv[0],
94 argv[arg], strlen(argv[arg]),
95 "unrecognized option");
97 /* For error messages, we include the leading '-' */
102 if ((opt_table[i].type & ~OPT_EARLY) == OPT_NOARG) {
104 return parse_err(errlog, argv[0], o, len,
105 "doesn't allow an argument");
106 if ((opt_table[i].type & OPT_EARLY) == is_early)
107 problem = opt_table[i].cb(opt_table[i].u.arg);
110 /* Swallow any short options as optarg, eg -afile */
111 if (*offset && argv[arg][*offset + 1]) {
112 optarg = argv[arg] + *offset + 1;
115 optarg = argv[arg+1];
118 return parse_err(errlog, argv[0], o, len,
119 "requires an argument");
120 if ((opt_table[i].type & OPT_EARLY) == is_early)
121 problem = opt_table[i].cb_arg(optarg,
126 parse_err(errlog, argv[0], o, len, problem);
127 opt_alloc.free(problem);
132 /* If no more letters in that short opt, reset offset. */
133 if (*offset && !argv[arg][*offset + 1])
136 /* All finished with that option? */
138 consume_option(argc, argv, arg);
139 if (optarg && optarg == argv[arg])
140 consume_option(argc, argv, arg);