1 /*
2  * Copyright (C) 2019 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 #pragma once
17 
18 #include <android-base/macros.h>
19 #include <android-base/parsedouble.h>
20 #include <android-base/properties.h>
21 #include <log/log.h>
22 
23 #include <fstream>
24 #include <map>
25 #include <sstream>
26 
27 namespace aidl {
28 namespace android {
29 namespace hardware {
30 namespace vibrator {
31 namespace utils {
32 
33 template <typename T>
34 class Is_Iterable {
35   private:
36     template <typename U>
37     static std::true_type test(typename U::iterator *u);
38 
39     template <typename U>
40     static std::false_type test(U *u);
41 
42   public:
43     static const bool value = decltype(test<T>(0))::value;
44 };
45 
46 template <typename T, bool B>
47 using Enable_If_Iterable = std::enable_if_t<Is_Iterable<T>::value == B>;
48 
49 template <typename T, typename U = void>
50 using Enable_If_Signed = std::enable_if_t<std::is_signed_v<T>, U>;
51 
52 template <typename T, typename U = void>
53 using Enable_If_Unsigned = std::enable_if_t<std::is_unsigned_v<T>, U>;
54 
55 // override for default behavior of printing as a character
56 inline std::ostream &operator<<(std::ostream &stream, const int8_t value) {
57     return stream << +value;
58 }
59 // override for default behavior of printing as a character
60 inline std::ostream &operator<<(std::ostream &stream, const uint8_t value) {
61     return stream << +value;
62 }
63 
64 template <typename T>
toUnderlying(const T value)65 inline auto toUnderlying(const T value) {
66     return static_cast<std::underlying_type_t<T>>(value);
67 }
68 
69 template <typename T>
unpack(std::istream & stream,T * value)70 inline Enable_If_Iterable<T, true> unpack(std::istream &stream, T *value) {
71     for (auto &entry : *value) {
72         stream >> entry;
73     }
74 }
75 
76 template <typename T>
unpack(std::istream & stream,T * value)77 inline Enable_If_Iterable<T, false> unpack(std::istream &stream, T *value) {
78     stream >> *value;
79 }
80 
81 template <>
82 inline void unpack<std::string>(std::istream &stream, std::string *value) {
83     *value = std::string(std::istreambuf_iterator(stream), {});
84     stream.setstate(std::istream::eofbit);
85 }
86 
87 template <typename T>
getProperty(const std::string & key,const T def)88 inline Enable_If_Signed<T, T> getProperty(const std::string &key, const T def) {
89     if (std::is_floating_point_v<T>) {
90         float result;
91         std::string value = ::android::base::GetProperty(key, "");
92         if (!value.empty() && ::android::base::ParseFloat(value, &result)) {
93             return result;
94         }
95         return def;
96     } else {
97         return ::android::base::GetIntProperty(key, def);
98     }
99 }
100 
101 template <typename T>
getProperty(const std::string & key,const T def)102 inline Enable_If_Unsigned<T, T> getProperty(const std::string &key, const T def) {
103     return ::android::base::GetUintProperty(key, def);
104 }
105 
106 template <typename T, size_t N>
getProperty(const std::string & key,const std::array<T,N> & def)107 inline std::array<T, N> getProperty(const std::string &key, const std::array<T, N> &def) {
108     std::string value = ::android::base::GetProperty(key, "");
109     if (!value.empty()) {
110         std::array<T, N> result{0};
111         std::stringstream stream{value};
112         utils::unpack(stream, &result);
113         if (stream && stream.eof())
114             return result;
115     }
116     return def;
117 }
118 
119 template <>
120 inline bool getProperty<bool>(const std::string &key, const bool def) {
121     return ::android::base::GetBoolProperty(key, def);
122 }
123 
124 template <typename T>
openNoCreate(const std::string & file,T * outStream)125 static void openNoCreate(const std::string &file, T *outStream) {
126     auto mode = std::is_base_of_v<std::ostream, T> ? std::ios_base::out : std::ios_base::in;
127 
128     // Force 'in' mode to prevent file creation
129     outStream->open(file, mode | std::ios_base::in);
130     if (!*outStream) {
131         ALOGE("Failed to open %s (%d): %s", file.c_str(), errno, strerror(errno));
132     }
133 }
134 
135 template <typename T>
136 static void fileFromEnv(const char *env, T *outStream, std::string *outName = nullptr) {
137     auto file = std::getenv(env);
138 
139     if (file == nullptr) {
140         ALOGE("Failed get env %s", env);
141         return;
142     }
143 
144     if (outName != nullptr) {
145         *outName = std::string(file);
146     }
147 
148     openNoCreate(file, outStream);
149 }
150 
151 static ATTRIBUTE_UNUSED auto pathsFromEnv(const char *env, const std::string &prefix = "") {
152     std::map<std::string, std::ifstream> ret;
153     auto value = std::getenv(env);
154 
155     if (value == nullptr) {
156         return ret;
157     }
158 
159     std::istringstream paths{value};
160     std::string path;
161 
162     while (paths >> path) {
163         ret[path].open(prefix + path);
164     }
165 
166     return ret;
167 }
168 
169 static ATTRIBUTE_UNUSED std::string trim(const std::string &str,
170                                          const std::string &whitespace = " \t") {
171     const auto str_begin = str.find_first_not_of(whitespace);
172     if (str_begin == std::string::npos) {
173         return "";
174     }
175 
176     const auto str_end = str.find_last_not_of(whitespace);
177     const auto str_range = str_end - str_begin + 1;
178 
179     return str.substr(str_begin, str_range);
180 }
181 
182 }  // namespace utils
183 }  // namespace vibrator
184 }  // namespace hardware
185 }  // namespace android
186 }  // namespace aidl
187