1 #include <ccan/opt/opt.h>
13 struct opt_table *opt_table;
14 unsigned int opt_count;
15 const char *opt_argv0;
17 static void check_opt(const struct opt_table *entry)
19 assert(entry->flags == OPT_HASARG || entry->flags == OPT_NOARG);
20 assert(entry->shortopt || entry->longopt);
21 assert(entry->shortopt != ':');
22 assert(entry->shortopt != '?' || entry->flags == OPT_NOARG);
25 static void add_opt(const struct opt_table *entry)
27 opt_table = realloc(opt_table, sizeof(opt_table[0]) * (opt_count+1));
28 opt_table[opt_count++] = *entry;
31 void _opt_register(const char *longopt, char shortopt, enum opt_flags flags,
32 char *(*cb)(void *arg),
33 char *(*cb_arg)(const char *optarg, void *arg),
34 void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
35 void *arg, const char *desc)
38 opt.longopt = longopt;
39 opt.shortopt = shortopt;
50 void opt_register_table(const struct opt_table entry[], const char *desc)
52 unsigned int i, start = opt_count;
55 struct opt_table heading = OPT_SUBTABLE(NULL, desc);
58 for (i = 0; entry[i].flags != OPT_END; i++) {
59 if (entry[i].flags == OPT_SUBTABLE)
60 opt_register_table(subtable_of(&entry[i]),
67 /* We store the table length in arg ptr. */
69 opt_table[start].arg = (void *)(intptr_t)(opt_count - start);
72 static char *make_optstring(void)
74 /* Worst case, each one is ":x:", plus nul term. */
75 char *str = malloc(1 + opt_count * 2 + 1);
78 /* This tells getopt_long we want a ':' returned for missing arg. */
81 for (i = 0; i < opt_count; i++) {
82 if (!opt_table[i].shortopt)
84 str[num++] = opt_table[i].shortopt;
85 if (opt_table[i].flags == OPT_HASARG)
92 static struct option *make_options(void)
94 struct option *options = malloc(sizeof(*options) * (opt_count + 1));
97 for (num = i = 0; i < opt_count; i++) {
98 if (!opt_table[i].longopt)
100 options[num].name = opt_table[i].longopt;
101 options[num].has_arg = (opt_table[i].flags == OPT_HASARG);
102 options[num].flag = NULL;
103 options[num].val = 0;
106 memset(&options[num], 0, sizeof(options[num]));
110 static struct opt_table *find_short(char shortopt)
113 for (i = 0; i < opt_count; i++) {
114 if (opt_table[i].shortopt == shortopt)
115 return &opt_table[i];
120 /* We want the index'th long entry. */
121 static struct opt_table *find_long(int index)
124 for (i = 0; i < opt_count; i++) {
125 if (!opt_table[i].longopt)
128 return &opt_table[i];
134 /* glibc does this as:
135 /tmp/opt-example: invalid option -- 'x'
136 /tmp/opt-example: unrecognized option '--long'
137 /tmp/opt-example: option '--someflag' doesn't allow an argument
138 /tmp/opt-example: option '--s' is ambiguous
139 /tmp/opt-example: option requires an argument -- 's'
141 static void parse_fail(void (*errlog)(const char *fmt, ...),
142 char shortopt, const char *longopt, const char *problem)
145 errlog("%s: -%c: %s", opt_argv0, shortopt, problem);
147 errlog("%s: --%s: %s", opt_argv0, longopt, problem);
150 void dump_optstate(void);
151 void dump_optstate(void)
153 printf("opterr = %i, optind = %i, optopt = %i, optarg = %s\n",
154 opterr, optind, optopt, optarg);
157 /* Parse your arguments. */
158 bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...))
160 char *optstring = make_optstring();
161 struct option *options = make_options();
162 int ret, longidx = 0;
165 /* We will do our own error reporting. */
169 /* Reset in case we're called more than once. */
172 while ((ret = getopt_long(*argc, argv, optstring, options, &longidx))
175 bool missing = false;
177 /* optopt is 0 if it's an unknown long option, *or* if
178 * -? is a valid short option. */
180 if (optopt || strncmp(argv[optind-1], "--", 2) == 0) {
181 parse_fail(errlog, optopt, argv[optind-1]+2,
182 "unrecognized option");
185 } else if (ret == ':') {
193 e = find_long(longidx);
195 /* Missing argument */
197 parse_fail(errlog, e->shortopt, e->longopt,
198 "option requires an argument");
202 if (e->flags == OPT_HASARG)
203 problem = e->cb_arg(optarg, e->arg);
205 problem = e->cb(e->arg);
208 parse_fail(errlog, e->shortopt, e->longopt,
219 /* We hide everything but remaining arguments. */
220 memmove(&argv[1], &argv[optind], sizeof(argv[1]) * (*argc-optind+1));
223 return ret == -1 ? true : false;
226 void opt_log_stderr(const char *fmt, ...)
231 vfprintf(stderr, fmt, ap);
235 char *opt_invalid_argument(const char *arg)
237 char *str = malloc(sizeof("Invalid argument '%s'") + strlen(arg));
238 sprintf(str, "Invalid argument '%s'", arg);