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, ...),
18 const char *arg, unsigned len,
21 errlog("%s: %.*s: %s", argv0, len, arg, problem);
25 static void consume_option(int *argc, char *argv[], unsigned optnum)
27 memmove(&argv[optnum], &argv[optnum+1],
28 sizeof(argv[optnum]) * (*argc-optnum));
32 /* This sets the len and o to indicate how far it is into the
33 * opt_table's names field. */
34 static struct opt_table *opt_find_long_extra(const char *arg,
42 for (*o = first_lopt(&i, len);
44 *o = next_lopt(*o, &i, len)) {
45 if (strncmp(arg, *o, *len) != 0)
48 *optarg = arg + *len + 1;
49 else if (arg[*len] != '\0')
57 struct opt_table *opt_find_long(const char *arg, const char **optarg)
62 return opt_find_long_extra(arg, optarg ? optarg : &o, &len, &o);
65 static struct opt_table *opt_find_short_extra(char arg, const char **o)
68 for (*o = first_sopt(&i); *o; *o = next_sopt(*o, &i)) {
75 struct opt_table *opt_find_short(char arg)
78 return opt_find_short_extra(arg, &o);
81 /* Returns 1 if argument consumed, 0 if all done, -1 on error. */
82 int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
83 void (*errlog)(const char *fmt, ...), bool unknown_ok)
86 const char *o, *optarg = NULL;
90 if (getenv("POSIXLY_CORRECT")) {
91 /* Don't find options after non-options. */
94 for (arg = 1; argv[arg]; arg++) {
95 if (argv[arg][0] == '-')
100 if (!argv[arg] || argv[arg][0] != '-')
103 /* Special arg terminator option. */
104 if (strcmp(argv[arg], "--") == 0) {
105 consume_option(argc, argv, arg);
109 /* Long options start with -- */
110 if (argv[arg][1] == '-') {
111 assert(*offset == 0);
113 ot = opt_find_long_extra(argv[arg]+2, &optarg, &len, &o);
117 return parse_err(errlog, argv[0],
118 argv[arg], strlen(argv[arg]),
119 "unrecognized option");
122 /* For error messages, we include the leading '--' */
126 ot = opt_find_short_extra(argv[arg][*offset + 1], &o);
132 return parse_err(errlog, argv[0],
133 argv[arg], strlen(argv[arg]),
134 "unrecognized option");
138 /* For error messages, we include the leading '-' */
143 if (ot->type & OPT_NOARG) {
145 return parse_err(errlog, argv[0], o, len,
146 "doesn't allow an argument");
147 if ((ot->type & OPT_EARLY) == is_early)
148 problem = ot->cb(ot->u.arg);
151 /* Swallow any short options as optarg, eg -afile */
152 if (*offset && argv[arg][*offset + 1]) {
153 optarg = argv[arg] + *offset + 1;
156 optarg = argv[arg+1];
159 return parse_err(errlog, argv[0], o, len,
160 "requires an argument");
161 if ((ot->type & OPT_EARLY) == is_early)
162 problem = ot->cb_arg(optarg, ot->u.arg);
166 parse_err(errlog, argv[0], o, len, problem);
167 opt_alloc.free(problem);
172 /* If no more letters in that short opt, reset offset. */
173 if (*offset && !argv[arg][*offset + 1])
176 /* All finished with that option? */
178 consume_option(argc, argv, arg);
179 if (optarg && optarg == argv[arg])
180 consume_option(argc, argv, arg);