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