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 <getopt.h>
20 #include <unistd.h>
21
22 #include <list>
23 #include <sstream>
24 #include <string>
25
26 #include "types/bluetooth/uuid.h"
27 #include "types/raw_address.h"
28
29 namespace {
30 enum OptionType {
31 kOptionDevice = 0,
32 kOptionLoop = 1,
33 kOptionUuid = 2,
34 kOptionMsleep = 3,
35 kOptionStdErr = 4,
36 kOptionFlags = 5,
37 kOptionClear = 6,
38 };
39
40 constexpr struct option long_options[] = {{"device", required_argument, 0, 0}, // kOptionDevice
41 {"loop", required_argument, 0, 0}, // kOptionLoop/
42 {"uuid", required_argument, 0, 0}, // kOptionUuid
43 {"msleep", required_argument, 0, 0}, // kOptionMsleep
44 {"stderr", no_argument, 0, 0}, // kOptionStdErr
45 {"flags", required_argument, 0, 0}, // kOptionFlags
46 {"clear", no_argument, 0, 0}, // kOptionDevice
47 {0, 0, 0, 0}};
48
49 const char* kShortArgs = "cd:l:u:";
50
51 } // namespace
52
Usage() const53 void bluetooth::test::headless::GetOpt::Usage() const {
54 fprintf(stdout, "%s: Usage:\n", name_);
55 fprintf(stdout, "%s -c Clear logcat logs\n", name_);
56 fprintf(stdout, "%s --device=<device,> Comma separated list of remote devices\n", name_);
57 fprintf(stdout, "%s --uuid=<uuid,> Comma separated list of uuids\n", name_);
58 fprintf(stdout, "%s --loop=<loop> Number of loops\n", name_);
59 fprintf(stdout, "%s --msleep=<msecs> Sleep msec between loops\n", name_);
60 fprintf(stdout, "%s --stderr Dump stderr to stdout\n", name_);
61 fflush(nullptr);
62 }
63
ParseValue(char * optarg,std::list<std::string> & string_list)64 void bluetooth::test::headless::GetOpt::ParseValue(char* optarg,
65 std::list<std::string>& string_list) {
66 log::assert_that(optarg != nullptr, "assert failed: optarg != nullptr");
67 char* p = optarg;
68 char* pp = optarg;
69 while (*p != '\0') {
70 if (*p == ',') {
71 *p = 0;
72 string_list.push_back(std::string(pp));
73 pp = p + 1;
74 }
75 p++;
76 }
77 if (pp != p) {
78 string_list.push_back(std::string(pp));
79 }
80 }
81
Split(std::string s)82 std::vector<std::string> bluetooth::test::headless::GetOpt::Split(std::string s) {
83 std::stringstream ss(s);
84 std::vector<std::string> values;
85 std::string item;
86 while (std::getline(ss, item, '=')) {
87 values.push_back(item);
88 }
89 return values;
90 }
91
ProcessOption(int option_index,char * optarg)92 void bluetooth::test::headless::GetOpt::ProcessOption(int option_index, char* optarg) {
93 std::list<std::string> string_list;
94 OptionType option_type = static_cast<OptionType>(option_index);
95
96 switch (option_type) {
97 case kOptionDevice:
98 if (!optarg) {
99 return;
100 }
101 ParseValue(optarg, string_list);
102 for (auto& entry : string_list) {
103 if (RawAddress::IsValidAddress(entry)) {
104 RawAddress address;
105 RawAddress::FromString(entry, address);
106 device_.push_back(address);
107 }
108 }
109 break;
110 case kOptionLoop:
111 loop_ = std::stoul(optarg, nullptr, 0);
112 break;
113 case kOptionUuid:
114 if (!optarg) {
115 return;
116 }
117 ParseValue(optarg, string_list);
118 for (auto& entry : string_list) {
119 uuid_.push_back(bluetooth::Uuid::From16Bit(std::stoul(entry.c_str(), nullptr, 0)));
120 }
121 break;
122 case kOptionMsleep:
123 if (!optarg) {
124 return;
125 }
126 msec_ = std::stoul(optarg, nullptr, 0);
127 break;
128 case kOptionStdErr:
129 close_stderr_ = false;
130 break;
131 case kOptionClear:
132 clear_logcat_ = true;
133 break;
134 default:
135 fflush(nullptr);
136 valid_ = false;
137 return;
138 break;
139 }
140 }
141
GetOpt(int argc,char ** argv)142 bluetooth::test::headless::GetOpt::GetOpt(int argc, char** argv) : name_(argv[0]) {
143 while (1) {
144 int option_index = 0;
145 int c = getopt_long_only(argc, argv, kShortArgs, long_options, &option_index);
146 if (c == -1) {
147 break;
148 }
149
150 switch (c) {
151 case 0:
152 ProcessOption(static_cast<OptionType>(option_index), optarg);
153 break;
154 case '?':
155 Usage();
156 valid_ = false;
157 return;
158 default:
159 printf("?? getopt returned character code 0%o ??\n", c);
160 }
161 }
162
163 while (optind < argc) {
164 non_options_.push_back(argv[optind++]);
165 }
166
167 fflush(nullptr);
168 }
169
~GetOpt()170 bluetooth::test::headless::GetOpt::~GetOpt() {}
171