1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * Copyright 2022 The Android Open Source Project
3*387f9dfdSAndroid Build Coastguard Worker *
4*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Worker * limitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker */
16*387f9dfdSAndroid Build Coastguard Worker
17*387f9dfdSAndroid Build Coastguard Worker #include "argp.h"
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard Worker #include <getopt.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <sysexits.h>
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Worker #include <algorithm>
24*387f9dfdSAndroid Build Coastguard Worker #include <sstream>
25*387f9dfdSAndroid Build Coastguard Worker #include <string>
26*387f9dfdSAndroid Build Coastguard Worker #include <vector>
27*387f9dfdSAndroid Build Coastguard Worker
argp_parse(const struct argp * argp,int argc,char ** argv,int,void *,void * input)28*387f9dfdSAndroid Build Coastguard Worker extern "C" error_t argp_parse(const struct argp *argp, int argc, char **argv, int /*unused*/,
29*387f9dfdSAndroid Build Coastguard Worker void * /* unused */, void *input) {
30*387f9dfdSAndroid Build Coastguard Worker int longindex;
31*387f9dfdSAndroid Build Coastguard Worker std::string optstring;
32*387f9dfdSAndroid Build Coastguard Worker std::vector<struct option> optvec;
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Worker // process argp_option array for use with getopt_long
35*387f9dfdSAndroid Build Coastguard Worker for (const struct argp_option *opt = argp->options; opt->name || opt->docstring; ++opt) {
36*387f9dfdSAndroid Build Coastguard Worker if (opt->key && isprint(opt->key)) {
37*387f9dfdSAndroid Build Coastguard Worker optstring += opt->key;
38*387f9dfdSAndroid Build Coastguard Worker if (opt->argname) optstring += ':';
39*387f9dfdSAndroid Build Coastguard Worker }
40*387f9dfdSAndroid Build Coastguard Worker
41*387f9dfdSAndroid Build Coastguard Worker if (opt->name) {
42*387f9dfdSAndroid Build Coastguard Worker optvec.push_back({ .name = opt->name, .has_arg = opt->argname ? 1 : 0,
43*387f9dfdSAndroid Build Coastguard Worker .flag = opt->key ? nullptr : &longindex, .val = opt->key });
44*387f9dfdSAndroid Build Coastguard Worker }
45*387f9dfdSAndroid Build Coastguard Worker }
46*387f9dfdSAndroid Build Coastguard Worker int longhelp = 0;
47*387f9dfdSAndroid Build Coastguard Worker optvec.push_back({ .name = "help", .has_arg = 0, .flag = &longhelp, .val = 1 });
48*387f9dfdSAndroid Build Coastguard Worker optvec.push_back({});
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Worker int opt;
51*387f9dfdSAndroid Build Coastguard Worker while ((opt = getopt_long(argc, argv, optstring.c_str(), optvec.data(), &longindex)) != -1) {
52*387f9dfdSAndroid Build Coastguard Worker struct argp_state state = { .input = input, .argp = argp };
53*387f9dfdSAndroid Build Coastguard Worker if (!opt) {
54*387f9dfdSAndroid Build Coastguard Worker if (longhelp) argp_state_help(&state, stdout, ARGP_HELP_STD_HELP);
55*387f9dfdSAndroid Build Coastguard Worker return EINVAL;
56*387f9dfdSAndroid Build Coastguard Worker }
57*387f9dfdSAndroid Build Coastguard Worker error_t ret = argp->parser(opt, optarg, &state);
58*387f9dfdSAndroid Build Coastguard Worker if (ret) return ret;
59*387f9dfdSAndroid Build Coastguard Worker }
60*387f9dfdSAndroid Build Coastguard Worker
61*387f9dfdSAndroid Build Coastguard Worker // Handle positional arguments
62*387f9dfdSAndroid Build Coastguard Worker if (optind < argc) {
63*387f9dfdSAndroid Build Coastguard Worker for (int idx = optind; idx < argc; idx++) {
64*387f9dfdSAndroid Build Coastguard Worker struct argp_state state = { .input = input, .argp = argp, .arg_num = idx - optind };
65*387f9dfdSAndroid Build Coastguard Worker const error_t ret = argp->parser(ARGP_KEY_ARG, argv[idx], &state);
66*387f9dfdSAndroid Build Coastguard Worker if (ret) return ret;
67*387f9dfdSAndroid Build Coastguard Worker }
68*387f9dfdSAndroid Build Coastguard Worker }
69*387f9dfdSAndroid Build Coastguard Worker struct argp_state state = {.input = input, .argp = argp};
70*387f9dfdSAndroid Build Coastguard Worker const error_t ret = argp->parser(ARGP_KEY_END, 0, &state);
71*387f9dfdSAndroid Build Coastguard Worker // Not all tools expect ARGP_KEY_END, so ARGP_ERR_UNKNOWN here is benign
72*387f9dfdSAndroid Build Coastguard Worker if (ret && ret != ARGP_ERR_UNKNOWN) return ret;
73*387f9dfdSAndroid Build Coastguard Worker return 0;
74*387f9dfdSAndroid Build Coastguard Worker }
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker
argp_usage(struct argp_state * state)77*387f9dfdSAndroid Build Coastguard Worker extern "C" void argp_usage(struct argp_state* state) {
78*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "%s", state->argp->doc);
79*387f9dfdSAndroid Build Coastguard Worker exit(EX_USAGE);
80*387f9dfdSAndroid Build Coastguard Worker }
81*387f9dfdSAndroid Build Coastguard Worker
argp_state_help(struct argp_state * state,FILE * fd,int)82*387f9dfdSAndroid Build Coastguard Worker extern "C" void argp_state_help(struct argp_state* state, FILE *fd, int /* unused */) {
83*387f9dfdSAndroid Build Coastguard Worker constexpr size_t kFlagOffset = 2, kNameOffset = 6, kDocstringOffset = 29;
84*387f9dfdSAndroid Build Coastguard Worker
85*387f9dfdSAndroid Build Coastguard Worker fprintf(fd, "%s\n", state->argp->doc);
86*387f9dfdSAndroid Build Coastguard Worker for (const struct argp_option *opt = state->argp->options; opt->name || opt->docstring; ++opt) {
87*387f9dfdSAndroid Build Coastguard Worker // Skip hidden arguments and empty entries in the argp_option array
88*387f9dfdSAndroid Build Coastguard Worker if (opt->n == OPTION_HIDDEN || (opt->docstring && opt->docstring[0] == '\0')) continue;
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker std::string s(kFlagOffset, ' ');
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker // Append short argument form (e.g. "-p,") if applicable, then whitespace
93*387f9dfdSAndroid Build Coastguard Worker if (opt->key && isprint(opt->key)) {
94*387f9dfdSAndroid Build Coastguard Worker s.append("-");
95*387f9dfdSAndroid Build Coastguard Worker s.append(1, (char)opt->key);
96*387f9dfdSAndroid Build Coastguard Worker s.append(",");
97*387f9dfdSAndroid Build Coastguard Worker }
98*387f9dfdSAndroid Build Coastguard Worker s.append(kNameOffset - s.length(), ' ');
99*387f9dfdSAndroid Build Coastguard Worker
100*387f9dfdSAndroid Build Coastguard Worker // Append long argument form (e.g. "--pid=PID") or whitespace
101*387f9dfdSAndroid Build Coastguard Worker if (opt->name) {
102*387f9dfdSAndroid Build Coastguard Worker s.append("--");
103*387f9dfdSAndroid Build Coastguard Worker s.append(opt->name);
104*387f9dfdSAndroid Build Coastguard Worker if (opt->argname) {
105*387f9dfdSAndroid Build Coastguard Worker s.append("=");
106*387f9dfdSAndroid Build Coastguard Worker s.append(opt->argname);
107*387f9dfdSAndroid Build Coastguard Worker }
108*387f9dfdSAndroid Build Coastguard Worker }
109*387f9dfdSAndroid Build Coastguard Worker if (s.length() < kDocstringOffset) {
110*387f9dfdSAndroid Build Coastguard Worker s.append(kDocstringOffset - s.length(), ' ');
111*387f9dfdSAndroid Build Coastguard Worker } else {
112*387f9dfdSAndroid Build Coastguard Worker s.append(" ");
113*387f9dfdSAndroid Build Coastguard Worker }
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker // Append docstring
116*387f9dfdSAndroid Build Coastguard Worker s.append(opt->docstring);
117*387f9dfdSAndroid Build Coastguard Worker s.append("\n");
118*387f9dfdSAndroid Build Coastguard Worker fprintf(fd, "%s", s.c_str());
119*387f9dfdSAndroid Build Coastguard Worker }
120*387f9dfdSAndroid Build Coastguard Worker exit(EX_OK);
121*387f9dfdSAndroid Build Coastguard Worker }
122