in watchman/Options.cpp [281:432]
bool w_getopt(
const OptDesc* opts,
int* argcp,
char*** argvp,
char*** daemon_argvp) {
int num_opts, i;
char* nextshort;
int argc = *argcp;
char** argv = *argvp;
int long_pos = -1;
int res;
int num_daemon = 0;
/* first build up the getopt_long bits that we need */
for (num_opts = 0; opts[num_opts].optname; num_opts++) {
;
}
/* to hold the args we pass to the daemon */
auto daemon_argv = (char**)calloc(num_opts + 1, sizeof(char*));
if (!daemon_argv) {
log(FATAL, "calloc daemon opts\n");
}
*daemon_argvp = daemon_argv;
/* something to hold the long options */
auto long_opts = (option*)calloc(num_opts + 1, sizeof(struct option));
if (!long_opts) {
log(FATAL, "calloc struct option\n");
}
/* and the short options */
auto shortopts = (char*)malloc((1 + num_opts) * 2);
if (!shortopts) {
log(FATAL, "malloc shortopts\n");
}
nextshort = shortopts;
nextshort[0] = ':';
nextshort++;
/* now transfer information into the space we made */
for (i = 0; i < num_opts; i++) {
long_opts[i].name = (char*)opts[i].optname;
long_opts[i].val = opts[i].shortopt;
switch (opts[i].argtype) {
case OPT_NONE:
long_opts[i].has_arg = no_argument;
break;
case REQ_STRING:
case REQ_INT:
long_opts[i].has_arg = required_argument;
break;
}
if (opts[i].shortopt) {
nextshort[0] = (char)opts[i].shortopt;
nextshort++;
if (long_opts[i].has_arg != no_argument) {
nextshort[0] = ':';
nextshort++;
}
}
}
nextshort[0] = 0;
while ((res = getopt_long(argc, argv, shortopts, long_opts, &long_pos)) !=
-1) {
const OptDesc* o;
switch (res) {
case ':':
/* missing option argument.
* Check to see if it was actually optional */
for (long_pos = 0; long_pos < num_opts; long_pos++) {
if (opts[long_pos].shortopt == optopt) {
if (IS_REQUIRED(opts[long_pos].argtype)) {
fprintf(
stderr,
"--%s (-%c) requires an argument",
opts[long_pos].optname,
opts[long_pos].shortopt);
return false;
}
}
}
break;
case '?':
/* unknown option */
fprintf(stderr, "Unknown or invalid option! %s\n", argv[optind - 1]);
usage(opts, stderr);
return false;
default:
if (res == 0) {
/* we got a long option */
o = &opts[long_pos];
} else {
/* map short option to the real thing */
o = NULL;
for (long_pos = 0; long_pos < num_opts; long_pos++) {
if (opts[long_pos].shortopt == res) {
o = &opts[long_pos];
break;
}
}
}
if (o->is_daemon) {
auto value = folly::to<std::string>(
"--", o->optname, "=", optarg ? optarg : "");
// we deliberately leak this value to the caller
daemon_argv[num_daemon++] = strdup(value.c_str());
}
/* store the argument if we found one */
if (o->argtype != OPT_NONE && o->val && optarg) {
switch (o->argtype) {
case REQ_INT: {
auto ival = atoi(optarg);
*(int*)o->val = ival;
cfg_set_arg(o->optname, json_integer(ival));
break;
}
case REQ_STRING: {
auto sval = typed_string_to_json(optarg, W_STRING_UNICODE);
*(std::string*)o->val = optarg;
cfg_set_arg(o->optname, sval);
break;
}
case OPT_NONE:;
}
}
if (o->argtype == OPT_NONE && o->val) {
auto bval = json_true();
*(int*)o->val = 1;
cfg_set_arg(o->optname, bval);
}
}
long_pos = -1;
}
free(long_opts);
free(shortopts);
*argcp = argc - optind;
*argvp = argv + optind;
return true;
}