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