xref: /aosp_15_r20/external/bcc/libbpf-tools/android/argp.cpp (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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