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