Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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 | #define LOG_TAG "sysprop_cpp_gen" |
| 18 | |
| 19 | #include "CppGen.h" |
| 20 | |
| 21 | #include <android-base/file.h> |
| 22 | #include <android-base/logging.h> |
| 23 | #include <android-base/stringprintf.h> |
| 24 | #include <android-base/strings.h> |
| 25 | #include <cerrno> |
| 26 | #include <regex> |
| 27 | #include <string> |
| 28 | |
| 29 | #include "CodeWriter.h" |
| 30 | #include "Common.h" |
| 31 | #include "sysprop.pb.h" |
| 32 | |
| 33 | namespace { |
| 34 | |
| 35 | constexpr const char* kIndent = " "; |
| 36 | |
| 37 | constexpr const char* kCppHeaderIncludes = |
| 38 | R"(#include <cstdint> |
| 39 | #include <optional> |
| 40 | #include <string> |
| 41 | #include <vector> |
| 42 | |
| 43 | )"; |
| 44 | |
| 45 | constexpr const char* kCppSourceIncludes = |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 46 | R"(#include <cctype> |
| 47 | #include <cerrno> |
| 48 | #include <cstdio> |
| 49 | #include <cstring> |
| 50 | #include <limits> |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 51 | #include <utility> |
| 52 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 53 | #include <strings.h> |
Inseob Kim | 698aba9 | 2018-09-18 20:39:46 +0900 | [diff] [blame] | 54 | #include <sys/system_properties.h> |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 55 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 56 | #include <android-base/parseint.h> |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 57 | #include <log/log.h> |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 58 | |
| 59 | )"; |
| 60 | |
| 61 | constexpr const char* kCppParsersAndFormatters = |
| 62 | R"(template <typename T> constexpr bool is_vector = false; |
| 63 | |
| 64 | template <typename T> constexpr bool is_vector<std::vector<T>> = true; |
| 65 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 66 | template <> [[maybe_unused]] std::optional<bool> DoParse(const char* str) { |
Inseob Kim | 44734d4 | 2018-08-30 17:11:05 +0900 | [diff] [blame] | 67 | static constexpr const char* kYes[] = {"1", "true"}; |
| 68 | static constexpr const char* kNo[] = {"0", "false"}; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 69 | |
| 70 | for (const char* yes : kYes) { |
| 71 | if (strcasecmp(yes, str) == 0) return std::make_optional(true); |
| 72 | } |
| 73 | |
| 74 | for (const char* no : kNo) { |
| 75 | if (strcasecmp(no, str) == 0) return std::make_optional(false); |
| 76 | } |
| 77 | |
| 78 | return std::nullopt; |
| 79 | } |
| 80 | |
| 81 | template <> [[maybe_unused]] std::optional<std::int32_t> DoParse(const char* str) { |
| 82 | std::int32_t ret; |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 83 | return android::base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | template <> [[maybe_unused]] std::optional<std::int64_t> DoParse(const char* str) { |
| 87 | std::int64_t ret; |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 88 | return android::base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | template <> [[maybe_unused]] std::optional<double> DoParse(const char* str) { |
| 92 | int old_errno = errno; |
| 93 | errno = 0; |
| 94 | char* end; |
| 95 | double ret = std::strtod(str, &end); |
| 96 | if (errno != 0) { |
| 97 | return std::nullopt; |
| 98 | } |
| 99 | if (str == end || *end != '\0') { |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 100 | errno = EINVAL; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 101 | return std::nullopt; |
| 102 | } |
| 103 | errno = old_errno; |
| 104 | return std::make_optional(ret); |
| 105 | } |
| 106 | |
| 107 | template <> [[maybe_unused]] std::optional<std::string> DoParse(const char* str) { |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 108 | return *str == '\0' ? std::nullopt : std::make_optional(str); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 109 | } |
| 110 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 111 | template <typename Vec> [[maybe_unused]] Vec DoParseList(const char* str) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 112 | Vec ret; |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 113 | const char* p = str; |
| 114 | for (;;) { |
| 115 | const char* found = p; |
| 116 | while (*found != '\0' && *found != ',') { |
| 117 | ++found; |
| 118 | } |
| 119 | std::string value(p, found); |
| 120 | ret.emplace_back(DoParse<typename Vec::value_type>(value.c_str())); |
| 121 | if (*found == '\0') break; |
| 122 | p = found + 1; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 123 | } |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 124 | return ret; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 125 | } |
| 126 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 127 | template <typename T> inline T TryParse(const char* str) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 128 | if constexpr(is_vector<T>) { |
| 129 | return DoParseList<T>(str); |
| 130 | } else { |
| 131 | return DoParse<T>(str); |
| 132 | } |
| 133 | } |
| 134 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 135 | [[maybe_unused]] std::string FormatValue(const std::optional<std::int32_t>& value) { |
| 136 | return value ? std::to_string(*value) : ""; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 137 | } |
| 138 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 139 | [[maybe_unused]] std::string FormatValue(const std::optional<std::int64_t>& value) { |
| 140 | return value ? std::to_string(*value) : ""; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 141 | } |
| 142 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 143 | [[maybe_unused]] std::string FormatValue(const std::optional<double>& value) { |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 144 | if (!value) return ""; |
| 145 | char buf[1024]; |
| 146 | std::sprintf(buf, "%.*g", std::numeric_limits<double>::max_digits10, *value); |
| 147 | return buf; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 148 | } |
| 149 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 150 | [[maybe_unused]] std::string FormatValue(const std::optional<bool>& value) { |
| 151 | return value ? (*value ? "true" : "false") : ""; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 152 | } |
| 153 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 154 | template <typename T> |
| 155 | [[maybe_unused]] std::string FormatValue(const std::vector<T>& value) { |
| 156 | if (value.empty()) return ""; |
| 157 | |
| 158 | std::string ret; |
Inseob Kim | 9c5147d | 2019-03-06 11:36:36 +0900 | [diff] [blame] | 159 | bool first = true; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 160 | |
| 161 | for (auto&& element : value) { |
Inseob Kim | 9c5147d | 2019-03-06 11:36:36 +0900 | [diff] [blame] | 162 | if (!first) ret += ","; |
| 163 | else first = false; |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 164 | if constexpr(std::is_same_v<T, std::optional<std::string>>) { |
| 165 | if (element) ret += *element; |
Inseob Kim | f18ca83 | 2018-08-31 16:07:45 +0900 | [diff] [blame] | 166 | } else { |
| 167 | ret += FormatValue(element); |
| 168 | } |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 169 | } |
| 170 | |
| 171 | return ret; |
| 172 | } |
| 173 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 174 | template <typename T> |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 175 | T GetProp(const char* key) { |
| 176 | T ret; |
Inseob Kim | 698aba9 | 2018-09-18 20:39:46 +0900 | [diff] [blame] | 177 | auto pi = __system_property_find(key); |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 178 | if (pi != nullptr) { |
| 179 | __system_property_read_callback(pi, [](void* cookie, const char*, const char* value, std::uint32_t) { |
| 180 | *static_cast<T*>(cookie) = TryParse<T>(value); |
| 181 | }, &ret); |
| 182 | } |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 183 | return ret; |
| 184 | } |
| 185 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 186 | )"; |
| 187 | |
| 188 | const std::regex kRegexDot{"\\."}; |
| 189 | const std::regex kRegexUnderscore{"_"}; |
| 190 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 191 | std::string GetCppEnumName(const sysprop::Property& prop); |
| 192 | std::string GetCppPropTypeName(const sysprop::Property& prop); |
| 193 | std::string GetCppNamespace(const sysprop::Properties& props); |
| 194 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 195 | std::string GenerateHeader(const sysprop::Properties& props, |
| 196 | sysprop::Scope scope); |
| 197 | std::string GenerateSource(const sysprop::Properties& props, |
| 198 | const std::string& include_name); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 199 | |
| 200 | std::string GetCppEnumName(const sysprop::Property& prop) { |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 201 | return ApiNameToIdentifier(prop.api_name()) + "_values"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | std::string GetCppPropTypeName(const sysprop::Property& prop) { |
| 205 | switch (prop.type()) { |
| 206 | case sysprop::Boolean: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 207 | return "std::optional<bool>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 208 | case sysprop::Integer: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 209 | return "std::optional<std::int32_t>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 210 | case sysprop::Long: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 211 | return "std::optional<std::int64_t>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 212 | case sysprop::Double: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 213 | return "std::optional<double>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 214 | case sysprop::String: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 215 | return "std::optional<std::string>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 216 | case sysprop::Enum: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 217 | return "std::optional<" + GetCppEnumName(prop) + ">"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 218 | case sysprop::BooleanList: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 219 | return "std::vector<std::optional<bool>>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 220 | case sysprop::IntegerList: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 221 | return "std::vector<std::optional<std::int32_t>>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 222 | case sysprop::LongList: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 223 | return "std::vector<std::optional<std::int64_t>>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 224 | case sysprop::DoubleList: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 225 | return "std::vector<std::optional<double>>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 226 | case sysprop::StringList: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 227 | return "std::vector<std::optional<std::string>>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 228 | case sysprop::EnumList: |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 229 | return "std::vector<std::optional<" + GetCppEnumName(prop) + ">>"; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 230 | default: |
| 231 | __builtin_unreachable(); |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | std::string GetCppNamespace(const sysprop::Properties& props) { |
| 236 | return std::regex_replace(props.module(), kRegexDot, "::"); |
| 237 | } |
| 238 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 239 | std::string GenerateHeader(const sysprop::Properties& props, |
| 240 | sysprop::Scope scope) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 241 | CodeWriter writer(kIndent); |
| 242 | |
| 243 | writer.Write("%s", kGeneratedFileFooterComments); |
| 244 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 245 | writer.Write("#pragma once\n\n"); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 246 | writer.Write("%s", kCppHeaderIncludes); |
| 247 | |
| 248 | std::string cpp_namespace = GetCppNamespace(props); |
| 249 | writer.Write("namespace %s {\n\n", cpp_namespace.c_str()); |
| 250 | |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 251 | bool first = true; |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 252 | |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 253 | for (int i = 0; i < props.prop_size(); ++i) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 254 | const sysprop::Property& prop = props.prop(i); |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 255 | |
| 256 | // Scope: Internal > System > Public |
| 257 | if (prop.scope() > scope) continue; |
| 258 | |
| 259 | if (!first) { |
| 260 | writer.Write("\n"); |
| 261 | } else { |
| 262 | first = false; |
| 263 | } |
| 264 | |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 265 | std::string prop_id = ApiNameToIdentifier(prop.api_name()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 266 | std::string prop_type = GetCppPropTypeName(prop); |
| 267 | |
| 268 | if (prop.type() == sysprop::Enum || prop.type() == sysprop::EnumList) { |
| 269 | writer.Write("enum class %s {\n", GetCppEnumName(prop).c_str()); |
| 270 | writer.Indent(); |
| 271 | for (const std::string& name : |
| 272 | android::base::Split(prop.enum_values(), "|")) { |
Inseob Kim | f346e50 | 2019-01-04 10:32:39 +0900 | [diff] [blame] | 273 | writer.Write("%s,\n", ToUpper(name).c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 274 | } |
| 275 | writer.Dedent(); |
| 276 | writer.Write("};\n\n"); |
| 277 | } |
| 278 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 279 | writer.Write("%s %s();\n", prop_type.c_str(), prop_id.c_str()); |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 280 | if (prop.access() != sysprop::Readonly && scope == sysprop::Internal) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 281 | writer.Write("bool %s(const %s& value);\n", prop_id.c_str(), |
| 282 | prop_type.c_str()); |
| 283 | } |
| 284 | } |
| 285 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 286 | writer.Write("\n} // namespace %s\n", cpp_namespace.c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 287 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 288 | return writer.Code(); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 289 | } |
| 290 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 291 | std::string GenerateSource(const sysprop::Properties& props, |
| 292 | const std::string& include_name) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 293 | CodeWriter writer(kIndent); |
| 294 | writer.Write("%s", kGeneratedFileFooterComments); |
Inseob Kim | dbc2c80 | 2018-09-13 14:16:48 +0900 | [diff] [blame] | 295 | writer.Write("#include <%s>\n\n", include_name.c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 296 | writer.Write("%s", kCppSourceIncludes); |
| 297 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 298 | std::string cpp_namespace = GetCppNamespace(props); |
| 299 | |
Inseob Kim | f18ca83 | 2018-08-31 16:07:45 +0900 | [diff] [blame] | 300 | writer.Write("namespace {\n\n"); |
| 301 | writer.Write("using namespace %s;\n\n", cpp_namespace.c_str()); |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 302 | writer.Write("template <typename T> T DoParse(const char* str);\n\n"); |
Inseob Kim | f18ca83 | 2018-08-31 16:07:45 +0900 | [diff] [blame] | 303 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 304 | for (int i = 0; i < props.prop_size(); ++i) { |
| 305 | const sysprop::Property& prop = props.prop(i); |
| 306 | if (prop.type() != sysprop::Enum && prop.type() != sysprop::EnumList) { |
| 307 | continue; |
| 308 | } |
| 309 | |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 310 | std::string prop_id = ApiNameToIdentifier(prop.api_name()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 311 | std::string enum_name = GetCppEnumName(prop); |
| 312 | |
| 313 | writer.Write("constexpr const std::pair<const char*, %s> %s_list[] = {\n", |
| 314 | enum_name.c_str(), prop_id.c_str()); |
| 315 | writer.Indent(); |
| 316 | for (const std::string& name : |
| 317 | android::base::Split(prop.enum_values(), "|")) { |
| 318 | writer.Write("{\"%s\", %s::%s},\n", name.c_str(), enum_name.c_str(), |
Inseob Kim | f346e50 | 2019-01-04 10:32:39 +0900 | [diff] [blame] | 319 | ToUpper(name).c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 320 | } |
| 321 | writer.Dedent(); |
| 322 | writer.Write("};\n\n"); |
| 323 | |
| 324 | writer.Write("template <>\n"); |
| 325 | writer.Write("std::optional<%s> DoParse(const char* str) {\n", |
| 326 | enum_name.c_str()); |
| 327 | writer.Indent(); |
| 328 | writer.Write("for (auto [name, val] : %s_list) {\n", prop_id.c_str()); |
| 329 | writer.Indent(); |
| 330 | writer.Write("if (strcmp(str, name) == 0) {\n"); |
| 331 | writer.Indent(); |
| 332 | writer.Write("return val;\n"); |
| 333 | writer.Dedent(); |
| 334 | writer.Write("}\n"); |
| 335 | writer.Dedent(); |
| 336 | writer.Write("}\n"); |
| 337 | writer.Write("return std::nullopt;\n"); |
| 338 | writer.Dedent(); |
| 339 | writer.Write("}\n\n"); |
| 340 | |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 341 | if (prop.access() != sysprop::Readonly) { |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 342 | writer.Write("std::string FormatValue(std::optional<%s> value) {\n", |
| 343 | enum_name.c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 344 | writer.Indent(); |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 345 | writer.Write("if (!value) return \"\";\n"); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 346 | writer.Write("for (auto [name, val] : %s_list) {\n", prop_id.c_str()); |
| 347 | writer.Indent(); |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 348 | writer.Write("if (val == *value) {\n"); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 349 | writer.Indent(); |
| 350 | writer.Write("return name;\n"); |
| 351 | writer.Dedent(); |
| 352 | writer.Write("}\n"); |
| 353 | writer.Dedent(); |
| 354 | writer.Write("}\n"); |
Inseob Kim | f18ca83 | 2018-08-31 16:07:45 +0900 | [diff] [blame] | 355 | |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 356 | writer.Write( |
Inseob Kim | 59bd6e3 | 2019-03-27 17:26:02 +0900 | [diff] [blame] | 357 | "LOG_ALWAYS_FATAL(\"Invalid value %%d for property %s\", " |
| 358 | "static_cast<std::int32_t>(*value));\n", |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 359 | prop.prop_name().c_str()); |
Inseob Kim | f18ca83 | 2018-08-31 16:07:45 +0900 | [diff] [blame] | 360 | |
| 361 | writer.Write("__builtin_unreachable();\n"); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 362 | writer.Dedent(); |
| 363 | writer.Write("}\n\n"); |
| 364 | } |
| 365 | } |
Inseob Kim | f18ca83 | 2018-08-31 16:07:45 +0900 | [diff] [blame] | 366 | writer.Write("%s", kCppParsersAndFormatters); |
Inseob Kim | ade45e2 | 2018-08-29 19:08:35 +0900 | [diff] [blame] | 367 | writer.Write("} // namespace\n\n"); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 368 | |
| 369 | writer.Write("namespace %s {\n\n", cpp_namespace.c_str()); |
| 370 | |
| 371 | for (int i = 0; i < props.prop_size(); ++i) { |
| 372 | if (i > 0) writer.Write("\n"); |
| 373 | |
| 374 | const sysprop::Property& prop = props.prop(i); |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 375 | std::string prop_id = ApiNameToIdentifier(prop.api_name()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 376 | std::string prop_type = GetCppPropTypeName(prop); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 377 | |
Inseob Kim | db7daa1 | 2018-12-12 18:04:40 +0900 | [diff] [blame] | 378 | writer.Write("%s %s() {\n", prop_type.c_str(), prop_id.c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 379 | writer.Indent(); |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 380 | writer.Write("return GetProp<%s>(\"%s\");\n", prop_type.c_str(), |
| 381 | prop.prop_name().c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 382 | writer.Dedent(); |
| 383 | writer.Write("}\n"); |
| 384 | |
Inseob Kim | 14e5187 | 2018-10-25 14:27:33 +0900 | [diff] [blame] | 385 | if (prop.access() != sysprop::Readonly) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 386 | writer.Write("\nbool %s(const %s& value) {\n", prop_id.c_str(), |
| 387 | prop_type.c_str()); |
| 388 | writer.Indent(); |
Inseob Kim | 9c5147d | 2019-03-06 11:36:36 +0900 | [diff] [blame] | 389 | |
| 390 | const char* format_expr = "FormatValue(value).c_str()"; |
| 391 | |
| 392 | // Specialized formatters here |
| 393 | if (prop.type() == sysprop::String) { |
| 394 | format_expr = "value ? value->c_str() : \"\""; |
| 395 | } else if (prop.integer_as_bool()) { |
| 396 | if (prop.type() == sysprop::Boolean) { |
| 397 | // optional<bool> -> optional<int> |
| 398 | format_expr = "FormatValue(std::optional<int>(value)).c_str()"; |
| 399 | } else if (prop.type() == sysprop::BooleanList) { |
| 400 | // vector<optional<bool>> -> vector<optional<int>> |
| 401 | format_expr = |
| 402 | "FormatValue(std::vector<std::optional<int>>(" |
| 403 | "value.begin(), value.end())).c_str()"; |
| 404 | } |
| 405 | } |
| 406 | |
Inseob Kim | b04d619 | 2018-12-14 08:33:16 +0900 | [diff] [blame] | 407 | writer.Write("return __system_property_set(\"%s\", %s) == 0;\n", |
Inseob Kim | 9c5147d | 2019-03-06 11:36:36 +0900 | [diff] [blame] | 408 | prop.prop_name().c_str(), format_expr); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 409 | writer.Dedent(); |
| 410 | writer.Write("}\n"); |
| 411 | } |
| 412 | } |
| 413 | |
Inseob Kim | ade45e2 | 2018-08-29 19:08:35 +0900 | [diff] [blame] | 414 | writer.Write("\n} // namespace %s\n", cpp_namespace.c_str()); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 415 | |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 416 | return writer.Code(); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 417 | } |
| 418 | |
| 419 | } // namespace |
| 420 | |
| 421 | bool GenerateCppFiles(const std::string& input_file_path, |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 422 | const std::string& header_dir, |
| 423 | const std::string& system_header_dir, |
Inseob Kim | dbc2c80 | 2018-09-13 14:16:48 +0900 | [diff] [blame] | 424 | const std::string& source_output_dir, |
| 425 | const std::string& include_name, std::string* err) { |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 426 | sysprop::Properties props; |
| 427 | |
| 428 | if (!ParseProps(input_file_path, &props, err)) { |
| 429 | return false; |
| 430 | } |
| 431 | |
Inseob Kim | dbc2c80 | 2018-09-13 14:16:48 +0900 | [diff] [blame] | 432 | std::string output_basename = android::base::Basename(input_file_path); |
| 433 | |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 434 | for (auto&& [scope, dir] : { |
| 435 | std::pair(sysprop::Internal, header_dir), |
| 436 | std::pair(sysprop::System, system_header_dir), |
| 437 | }) { |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 438 | if (!IsDirectory(dir) && !CreateDirectories(dir)) { |
| 439 | *err = "Creating directory to " + dir + " failed: " + strerror(errno); |
| 440 | return false; |
| 441 | } |
| 442 | |
| 443 | std::string path = dir + "/" + output_basename + ".h"; |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 444 | std::string result = GenerateHeader(props, scope); |
Inseob Kim | cb71b08 | 2019-02-08 21:04:49 +0900 | [diff] [blame] | 445 | |
| 446 | if (!android::base::WriteStringToFile(result, path)) { |
| 447 | *err = |
| 448 | "Writing generated header to " + path + " failed: " + strerror(errno); |
| 449 | return false; |
| 450 | } |
| 451 | } |
| 452 | |
Inseob Kim | dbc2c80 | 2018-09-13 14:16:48 +0900 | [diff] [blame] | 453 | std::string source_path = source_output_dir + "/" + output_basename + ".cpp"; |
Inseob Kim | 803bfb8 | 2019-02-15 18:40:45 +0900 | [diff] [blame] | 454 | std::string source_result = GenerateSource(props, include_name); |
Inseob Kim | 5f8f32c | 2018-08-24 11:10:44 +0900 | [diff] [blame] | 455 | |
| 456 | if (!android::base::WriteStringToFile(source_result, source_path)) { |
| 457 | *err = "Writing generated source to " + source_path + |
| 458 | " failed: " + strerror(errno); |
| 459 | return false; |
| 460 | } |
| 461 | |
| 462 | return true; |
| 463 | } |