1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "test/headless/get_options.h"
18
19 #include <base/logging.h>
20 #include <getopt.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <list>
24 #include <string>
25
26 namespace {
27 constexpr struct option long_options[] = {
28 {"device", required_argument, 0, 0}, {"loop", required_argument, 0, 0},
29 {"uuid", required_argument, 0, 0}, {"msleep", required_argument, 0, 0},
30 {"stderr", no_argument, 0, 0}, {0, 0, 0, 0}};
31
32 enum OptionType {
33 kOptionDevice = 0,
34 kOptionLoop = 1,
35 kOptionUuid = 2,
36 kOptionMsleep = 3,
37 kOptionStdErr = 4,
38 };
39
40 } // namespace
41
Usage() const42 void bluetooth::test::headless::GetOpt::Usage() const {
43 fprintf(stdout, "%s: Usage:\n", name_);
44 fprintf(stdout,
45 "%s --device=<device,> Comma separated list of remote devices\n",
46 name_);
47 fprintf(stdout, "%s --uuid=<uuid,> Comma separated list of uuids\n",
48 name_);
49 fprintf(stdout, "%s --loop=<loop> Number of loops\n", name_);
50 fprintf(stdout, "%s --msleep=<msecs> Sleep msec between loops\n", name_);
51 fprintf(stdout, "%s --stderr Dump stderr to stdout\n", name_);
52 fflush(nullptr);
53 }
54
ParseValue(char * optarg,std::list<std::string> & string_list)55 void bluetooth::test::headless::GetOpt::ParseValue(
56 char* optarg, std::list<std::string>& string_list) {
57 CHECK(optarg != nullptr);
58 char* p = optarg;
59 char* pp = optarg;
60 while (*p != '\0') {
61 if (*p == ',') {
62 *p = 0;
63 string_list.push_back(std::string(pp));
64 pp = p + 1;
65 }
66 p++;
67 }
68 if (pp != p) string_list.push_back(std::string(pp));
69 }
70
ProcessOption(int option_index,char * optarg)71 void bluetooth::test::headless::GetOpt::ProcessOption(int option_index,
72 char* optarg) {
73 std::list<std::string> string_list;
74 OptionType option_type = static_cast<OptionType>(option_index);
75
76 switch (option_type) {
77 case kOptionDevice:
78 if (!optarg) return;
79 ParseValue(optarg, string_list);
80 for (auto& entry : string_list) {
81 if (RawAddress::IsValidAddress(entry)) {
82 RawAddress address;
83 RawAddress::FromString(entry, address);
84 device_.push_back(address);
85 }
86 }
87 break;
88 case kOptionLoop:
89 loop_ = std::stoul(optarg, nullptr, 0);
90 break;
91 case kOptionUuid:
92 if (!optarg) return;
93 ParseValue(optarg, string_list);
94 for (auto& entry : string_list) {
95 uuid_.push_back(
96 bluetooth::Uuid::From16Bit(std::stoul(entry.c_str(), nullptr, 0)));
97 }
98 break;
99 case kOptionMsleep:
100 if (!optarg) return;
101 msec_ = std::stoul(optarg, nullptr, 0);
102 break;
103 case kOptionStdErr:
104 close_stderr_ = false;
105 break;
106 default:
107 fflush(nullptr);
108 valid_ = false;
109 return;
110 break;
111 }
112 }
113
GetOpt(int argc,char ** argv)114 bluetooth::test::headless::GetOpt::GetOpt(int argc, char** argv)
115 : name_(argv[0]) {
116 while (1) {
117 int option_index = 0;
118 int c = getopt_long_only(argc, argv, "d:l:u:", long_options, &option_index);
119 if (c == -1) break;
120
121 switch (c) {
122 case 0:
123 ProcessOption(static_cast<OptionType>(option_index), optarg);
124 break;
125 case '?':
126 Usage();
127 valid_ = false;
128 return;
129 default:
130 printf("?? getopt returned character code 0%o ??\n", c);
131 }
132 }
133
134 while (optind < argc) {
135 non_options_.push_back(argv[optind++]);
136 }
137 fflush(nullptr);
138 }
139
140