1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef IORAP_SRC_COMMON_CMD_UTILS_H_
16 #define IORAP_SRC_COMMON_CMD_UTILS_H_
17 
18 #include <android-base/parsebool.h>
19 #include <android-base/properties.h>
20 
21 #include <iostream>
22 #include <sstream>
23 #include <optional>
24 #include <vector>
25 
26 namespace iorap::common {
27 // Create execve-compatible argv.
28 // The lifetime is tied to that of vector.
VecToArgv(const char * program_name,const std::vector<std::string> & vector)29 inline std::unique_ptr<const char*[]> VecToArgv(const char* program_name,
30                                               const std::vector<std::string>& vector) {
31   // include program name in argv[0]
32   // include a NULL sentinel in the end.
33   std::unique_ptr<const char*[]> ptr{new const char*[vector.size() + 2]};
34 
35   // program name
36   ptr[0] = program_name;
37 
38   // all the argv
39   for (size_t i = 0; i < vector.size(); ++i) {
40     ptr[i+1] = vector[i].c_str();
41   }
42 
43   // null sentinel
44   ptr[vector.size() + 1] = nullptr;
45 
46   return ptr;
47 }
48 
49 // Appends an args to the argv.
50 template <class T>
AppendArgs(std::vector<std::string> & argv,const T & value)51 void AppendArgs(std::vector<std::string>& argv,
52                 const T& value) {
53   std::stringstream ss;
54   ss << value;
55   argv.push_back(ss.str());
56 }
57 
58 // Appends an args to the argv.
59 template <class T, class T2>
AppendArgs(std::vector<std::string> & argv,const T & value,const T2 & value2)60 void AppendArgs(std::vector<std::string>& argv,
61                 const T& value,
62                 const T2& value2) {
63   AppendArgs(argv, value);
64   AppendArgs(argv, value2);
65 }
66 
67 // Appends a named argument to the argv.
68 //
69 // For example if <name> is "--property" and <value> is int(200):
70 // the string "--property=200" is appended to the argv.
71 template <class T, class T2>
AppendNamedArg(std::vector<std::string> & argv,const T & name,const T2 & value)72 void AppendNamedArg(std::vector<std::string>& argv,
73                     const T& name,
74                     const T2& value) {
75   std::stringstream ss;
76   ss << name;
77   ss << "=";
78   ss << value;
79 
80   argv.push_back(ss.str());
81 }
82 
83 // Appends args from a vector to the argv repeatedly to argv.
84 //
85 // For example, if <args> is "--timestamp" and <values> is [100, 200].
86 // The "--timestamp 100" and "--timestamp 200" are appended.
87 template <class T>
AppendArgsRepeatedly(std::vector<std::string> & argv,std::string args,const std::vector<T> & values)88 void AppendArgsRepeatedly(std::vector<std::string>& argv,
89                           std::string args,
90                           const std::vector<T>& values) {
91   for (const T& v : values) {
92      AppendArgs(argv, args, v);
93   }
94 }
95 
96 // Appends args from a vector to the argv repeatedly to argv.
97 //
98 // For example, if values is [input1.pb, input2.pb],
99 // then the "input1.pb" and "input2.pb" are appended.
100 template <class T>
AppendArgsRepeatedly(std::vector<std::string> & argv,const std::vector<T> & values)101 void AppendArgsRepeatedly(std::vector<std::string>& argv,
102                           const std::vector<T>& values) {
103   for (const T& v : values) {
104      AppendArgs(argv, v);
105   }
106 }
107 
108 // Appends a named argument to the argv repeatedly with different values.
109 //
110 // For example if <name> is "--property" and <value> is [int(200), int(400)]:
111 // the strings "--property=200" and "--property=400" are both appended to the argv.
112 template <class T, class T2>
AppendNamedArgRepeatedly(std::vector<std::string> & argv,const T & name,const std::vector<T2> & values)113 void AppendNamedArgRepeatedly(std::vector<std::string>& argv,
114                               const T& name,
115                               const std::vector<T2>& values) {
116   for (const T2& v :values) {
117     AppendNamedArg(argv, name, v);
118   }
119 }
120 
121 // Get the value of the property.
122 // Firstly, try to find the environment variable. If it does not exist,
123 // try to get the property. If neither, use the default value..
124 //
125 // For example, for prop foo.bar.baz, it will first check for
126 // FOO_BAR_BAZ environment variable.
GetEnvOrProperty(const std::string & prop,const std::string & default_val)127 inline std::string GetEnvOrProperty(const std::string& prop, const std::string& default_val) {
128   std::string env_str = prop;
129   // a.b.c -> a_b_c
130   std::replace(env_str.begin(), env_str.end(), '.', '_');
131   // a_b_c -> A_B_C
132   std::transform(env_str.begin(), env_str.end(), env_str.begin(), ::toupper);
133   char *env = getenv(env_str.c_str());
134   if (env) {
135     return std::string(env);
136   }
137   return ::android::base::GetProperty(prop, default_val);
138 }
139 
140 // Get the boolean value of the property.
141 // Firstly, try to find the environment variable. If it does not exist,
142 // try to get the property. If neither, use the default value..
143 //
144 // For example, for prop foo.bar.baz, it will first check for
145 // FOO_BAR_BAZ environment variable.
GetBoolEnvOrProperty(const std::string & prop,bool default_val)146 inline bool GetBoolEnvOrProperty(const std::string& prop, bool default_val) {
147   std::string env_str = prop;
148   // a.b.c -> a_b_c
149   std::replace(env_str.begin(), env_str.end(), '.', '_');
150   // a_b_c -> A_B_C
151   std::transform(env_str.begin(), env_str.end(), env_str.begin(), ::toupper);
152   char *env = getenv(env_str.c_str());
153   if (env) {
154     using ::android::base::ParseBoolResult;
155 
156     switch (::android::base::ParseBool(env)) {
157       case ParseBoolResult::kError:
158         break;
159       case ParseBoolResult::kFalse:
160         return false;
161       case ParseBoolResult::kTrue:
162         return true;
163     }
164   }
165   return ::android::base::GetBoolProperty(prop, default_val);
166 }
167 
168 }   // namespace iorap::common
169 
170 #endif  // IORAP_SRC_COMMON_CMD_UTILS_H_
171