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