blob: 9c75eedb13409340f02ffff08060884c60abe551 [file] [log] [blame]
Inseob Kim5f8f32c2018-08-24 11:10:44 +09001/*
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 Kim4584b8f2019-06-17 15:52:48 +090026#include <filesystem>
Inseob Kim5f8f32c2018-08-24 11:10:44 +090027#include <regex>
28#include <string>
29
30#include "CodeWriter.h"
31#include "Common.h"
32#include "sysprop.pb.h"
33
Inseob Kim053b83d2019-06-26 13:41:51 +090034using android::base::Result;
35
Inseob Kim5f8f32c2018-08-24 11:10:44 +090036namespace {
37
38constexpr const char* kIndent = " ";
39
40constexpr const char* kCppHeaderIncludes =
41 R"(#include <cstdint>
42#include <optional>
43#include <string>
44#include <vector>
45
46)";
47
48constexpr const char* kCppSourceIncludes =
Inseob Kim59bd6e32019-03-27 17:26:02 +090049 R"(#include <cctype>
50#include <cerrno>
51#include <cstdio>
52#include <cstring>
53#include <limits>
Inseob Kim5f8f32c2018-08-24 11:10:44 +090054#include <utility>
55
Inseob Kim5f8f32c2018-08-24 11:10:44 +090056#include <strings.h>
Inseob Kim698aba92018-09-18 20:39:46 +090057#include <sys/system_properties.h>
Inseob Kim5f8f32c2018-08-24 11:10:44 +090058
Inseob Kim5f8f32c2018-08-24 11:10:44 +090059#include <android-base/parseint.h>
Inseob Kim59bd6e32019-03-27 17:26:02 +090060#include <log/log.h>
Inseob Kim5f8f32c2018-08-24 11:10:44 +090061
62)";
63
64constexpr const char* kCppParsersAndFormatters =
65 R"(template <typename T> constexpr bool is_vector = false;
66
67template <typename T> constexpr bool is_vector<std::vector<T>> = true;
68
Inseob Kim5f8f32c2018-08-24 11:10:44 +090069template <> [[maybe_unused]] std::optional<bool> DoParse(const char* str) {
Inseob Kim44734d42018-08-30 17:11:05 +090070 static constexpr const char* kYes[] = {"1", "true"};
71 static constexpr const char* kNo[] = {"0", "false"};
Inseob Kim5f8f32c2018-08-24 11:10:44 +090072
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
84template <> [[maybe_unused]] std::optional<std::int32_t> DoParse(const char* str) {
85 std::int32_t ret;
Inseob Kim59bd6e32019-03-27 17:26:02 +090086 return android::base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
Inseob Kim5f8f32c2018-08-24 11:10:44 +090087}
88
89template <> [[maybe_unused]] std::optional<std::int64_t> DoParse(const char* str) {
90 std::int64_t ret;
Inseob Kim59bd6e32019-03-27 17:26:02 +090091 return android::base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
Inseob Kim5f8f32c2018-08-24 11:10:44 +090092}
93
94template <> [[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 Kim59bd6e32019-03-27 17:26:02 +0900103 errno = EINVAL;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900104 return std::nullopt;
105 }
106 errno = old_errno;
107 return std::make_optional(ret);
108}
109
110template <> [[maybe_unused]] std::optional<std::string> DoParse(const char* str) {
Inseob Kim14e51872018-10-25 14:27:33 +0900111 return *str == '\0' ? std::nullopt : std::make_optional(str);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900112}
113
Inseob Kimdb7daa12018-12-12 18:04:40 +0900114template <typename Vec> [[maybe_unused]] Vec DoParseList(const char* str) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900115 Vec ret;
Inseob Kim51313222020-01-15 14:37:49 +0900116 if (*str == '\0') return ret;
Inseob Kim59bd6e32019-03-27 17:26:02 +0900117 const char* p = str;
118 for (;;) {
Inseob Kim51313222020-01-15 14:37:49 +0900119 const char* r = p;
120 std::string value;
121 while (*r != ',') {
122 if (*r == '\\') ++r;
123 if (*r == '\0') break;
124 value += *r++;
Inseob Kim59bd6e32019-03-27 17:26:02 +0900125 }
Inseob Kim59bd6e32019-03-27 17:26:02 +0900126 ret.emplace_back(DoParse<typename Vec::value_type>(value.c_str()));
Inseob Kim51313222020-01-15 14:37:49 +0900127 if (*r == '\0') break;
128 p = r + 1;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900129 }
Inseob Kimdb7daa12018-12-12 18:04:40 +0900130 return ret;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900131}
132
Inseob Kimdb7daa12018-12-12 18:04:40 +0900133template <typename T> inline T TryParse(const char* str) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900134 if constexpr(is_vector<T>) {
135 return DoParseList<T>(str);
136 } else {
137 return DoParse<T>(str);
138 }
139}
140
Inseob Kimdb7daa12018-12-12 18:04:40 +0900141[[maybe_unused]] std::string FormatValue(const std::optional<std::int32_t>& value) {
142 return value ? std::to_string(*value) : "";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900143}
144
Inseob Kimdb7daa12018-12-12 18:04:40 +0900145[[maybe_unused]] std::string FormatValue(const std::optional<std::int64_t>& value) {
146 return value ? std::to_string(*value) : "";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900147}
148
Inseob Kimdb7daa12018-12-12 18:04:40 +0900149[[maybe_unused]] std::string FormatValue(const std::optional<double>& value) {
Inseob Kim59bd6e32019-03-27 17:26:02 +0900150 if (!value) return "";
151 char buf[1024];
152 std::sprintf(buf, "%.*g", std::numeric_limits<double>::max_digits10, *value);
153 return buf;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900154}
155
Inseob Kimdb7daa12018-12-12 18:04:40 +0900156[[maybe_unused]] std::string FormatValue(const std::optional<bool>& value) {
157 return value ? (*value ? "true" : "false") : "";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900158}
159
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900160template <typename T>
161[[maybe_unused]] std::string FormatValue(const std::vector<T>& value) {
162 if (value.empty()) return "";
163
164 std::string ret;
Inseob Kim9c5147d2019-03-06 11:36:36 +0900165 bool first = true;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900166
167 for (auto&& element : value) {
Inseob Kim51313222020-01-15 14:37:49 +0900168 if (!first) ret += ',';
Inseob Kim9c5147d2019-03-06 11:36:36 +0900169 else first = false;
Inseob Kimdb7daa12018-12-12 18:04:40 +0900170 if constexpr(std::is_same_v<T, std::optional<std::string>>) {
Inseob Kim51313222020-01-15 14:37:49 +0900171 if (element) {
172 for (char c : *element) {
173 if (c == '\\' || c == ',') ret += '\\';
174 ret += c;
175 }
176 }
Inseob Kimf18ca832018-08-31 16:07:45 +0900177 } else {
178 ret += FormatValue(element);
179 }
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900180 }
181
182 return ret;
183}
184
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900185template <typename T>
Inseob Kimdb7daa12018-12-12 18:04:40 +0900186T GetProp(const char* key) {
187 T ret;
Inseob Kim698aba92018-09-18 20:39:46 +0900188 auto pi = __system_property_find(key);
Inseob Kimdb7daa12018-12-12 18:04:40 +0900189 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 Kim5f8f32c2018-08-24 11:10:44 +0900194 return ret;
195}
196
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900197)";
198
199const std::regex kRegexDot{"\\."};
200const std::regex kRegexUnderscore{"_"};
201
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900202std::string GetCppEnumName(const sysprop::Property& prop);
203std::string GetCppPropTypeName(const sysprop::Property& prop);
204std::string GetCppNamespace(const sysprop::Properties& props);
205
Inseob Kim803bfb82019-02-15 18:40:45 +0900206std::string GenerateHeader(const sysprop::Properties& props,
207 sysprop::Scope scope);
208std::string GenerateSource(const sysprop::Properties& props,
209 const std::string& include_name);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900210
211std::string GetCppEnumName(const sysprop::Property& prop) {
Inseob Kim14e51872018-10-25 14:27:33 +0900212 return ApiNameToIdentifier(prop.api_name()) + "_values";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900213}
214
215std::string GetCppPropTypeName(const sysprop::Property& prop) {
216 switch (prop.type()) {
217 case sysprop::Boolean:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900218 return "std::optional<bool>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900219 case sysprop::Integer:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900220 return "std::optional<std::int32_t>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900221 case sysprop::Long:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900222 return "std::optional<std::int64_t>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900223 case sysprop::Double:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900224 return "std::optional<double>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900225 case sysprop::String:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900226 return "std::optional<std::string>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900227 case sysprop::Enum:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900228 return "std::optional<" + GetCppEnumName(prop) + ">";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900229 case sysprop::BooleanList:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900230 return "std::vector<std::optional<bool>>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900231 case sysprop::IntegerList:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900232 return "std::vector<std::optional<std::int32_t>>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900233 case sysprop::LongList:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900234 return "std::vector<std::optional<std::int64_t>>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900235 case sysprop::DoubleList:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900236 return "std::vector<std::optional<double>>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900237 case sysprop::StringList:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900238 return "std::vector<std::optional<std::string>>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900239 case sysprop::EnumList:
Inseob Kimdb7daa12018-12-12 18:04:40 +0900240 return "std::vector<std::optional<" + GetCppEnumName(prop) + ">>";
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900241 default:
242 __builtin_unreachable();
243 }
244}
245
246std::string GetCppNamespace(const sysprop::Properties& props) {
247 return std::regex_replace(props.module(), kRegexDot, "::");
248}
249
Inseob Kim803bfb82019-02-15 18:40:45 +0900250std::string GenerateHeader(const sysprop::Properties& props,
251 sysprop::Scope scope) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900252 CodeWriter writer(kIndent);
253
254 writer.Write("%s", kGeneratedFileFooterComments);
255
Inseob Kim803bfb82019-02-15 18:40:45 +0900256 writer.Write("#pragma once\n\n");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900257 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 Kimcb71b082019-02-08 21:04:49 +0900262 bool first = true;
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900263
Inseob Kimcb71b082019-02-08 21:04:49 +0900264 for (int i = 0; i < props.prop_size(); ++i) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900265 const sysprop::Property& prop = props.prop(i);
Inseob Kimcb71b082019-02-08 21:04:49 +0900266
Inseob Kim1ca03f32019-06-08 16:31:59 +0900267 // Scope: Internal > Public
Inseob Kimcb71b082019-02-08 21:04:49 +0900268 if (prop.scope() > scope) continue;
269
270 if (!first) {
271 writer.Write("\n");
272 } else {
273 first = false;
274 }
275
Inseob Kim14e51872018-10-25 14:27:33 +0900276 std::string prop_id = ApiNameToIdentifier(prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900277 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 Kimf346e502019-01-04 10:32:39 +0900284 writer.Write("%s,\n", ToUpper(name).c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900285 }
286 writer.Dedent();
287 writer.Write("};\n\n");
288 }
289
Inseob Kim5e64f892019-06-17 15:09:48 +0900290 if (prop.deprecated()) writer.Write("[[deprecated]] ");
Inseob Kimdb7daa12018-12-12 18:04:40 +0900291 writer.Write("%s %s();\n", prop_type.c_str(), prop_id.c_str());
Inseob Kim4ab20d32019-12-03 13:44:55 +0900292 if (prop.access() != sysprop::Readonly) {
Inseob Kim5e64f892019-06-17 15:09:48 +0900293 if (prop.deprecated()) writer.Write("[[deprecated]] ");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900294 writer.Write("bool %s(const %s& value);\n", prop_id.c_str(),
295 prop_type.c_str());
296 }
297 }
298
Inseob Kim803bfb82019-02-15 18:40:45 +0900299 writer.Write("\n} // namespace %s\n", cpp_namespace.c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900300
Inseob Kim803bfb82019-02-15 18:40:45 +0900301 return writer.Code();
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900302}
303
Inseob Kim803bfb82019-02-15 18:40:45 +0900304std::string GenerateSource(const sysprop::Properties& props,
305 const std::string& include_name) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900306 CodeWriter writer(kIndent);
307 writer.Write("%s", kGeneratedFileFooterComments);
Inseob Kimdbc2c802018-09-13 14:16:48 +0900308 writer.Write("#include <%s>\n\n", include_name.c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900309 writer.Write("%s", kCppSourceIncludes);
310
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900311 std::string cpp_namespace = GetCppNamespace(props);
312
Inseob Kimf18ca832018-08-31 16:07:45 +0900313 writer.Write("namespace {\n\n");
314 writer.Write("using namespace %s;\n\n", cpp_namespace.c_str());
Inseob Kimdb7daa12018-12-12 18:04:40 +0900315 writer.Write("template <typename T> T DoParse(const char* str);\n\n");
Inseob Kimf18ca832018-08-31 16:07:45 +0900316
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900317 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 Kim14e51872018-10-25 14:27:33 +0900323 std::string prop_id = ApiNameToIdentifier(prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900324 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 Kimf346e502019-01-04 10:32:39 +0900332 ToUpper(name).c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900333 }
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 Kim14e51872018-10-25 14:27:33 +0900354 if (prop.access() != sysprop::Readonly) {
Inseob Kimdb7daa12018-12-12 18:04:40 +0900355 writer.Write("std::string FormatValue(std::optional<%s> value) {\n",
356 enum_name.c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900357 writer.Indent();
Inseob Kimdb7daa12018-12-12 18:04:40 +0900358 writer.Write("if (!value) return \"\";\n");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900359 writer.Write("for (auto [name, val] : %s_list) {\n", prop_id.c_str());
360 writer.Indent();
Inseob Kimdb7daa12018-12-12 18:04:40 +0900361 writer.Write("if (val == *value) {\n");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900362 writer.Indent();
363 writer.Write("return name;\n");
364 writer.Dedent();
365 writer.Write("}\n");
366 writer.Dedent();
367 writer.Write("}\n");
Inseob Kimf18ca832018-08-31 16:07:45 +0900368
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900369 writer.Write(
Inseob Kim59bd6e32019-03-27 17:26:02 +0900370 "LOG_ALWAYS_FATAL(\"Invalid value %%d for property %s\", "
371 "static_cast<std::int32_t>(*value));\n",
Inseob Kim14e51872018-10-25 14:27:33 +0900372 prop.prop_name().c_str());
Inseob Kimf18ca832018-08-31 16:07:45 +0900373
374 writer.Write("__builtin_unreachable();\n");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900375 writer.Dedent();
376 writer.Write("}\n\n");
377 }
378 }
Inseob Kimf18ca832018-08-31 16:07:45 +0900379 writer.Write("%s", kCppParsersAndFormatters);
Inseob Kimade45e22018-08-29 19:08:35 +0900380 writer.Write("} // namespace\n\n");
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900381
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 Kim14e51872018-10-25 14:27:33 +0900388 std::string prop_id = ApiNameToIdentifier(prop.api_name());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900389 std::string prop_type = GetCppPropTypeName(prop);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900390
Inseob Kimdb7daa12018-12-12 18:04:40 +0900391 writer.Write("%s %s() {\n", prop_type.c_str(), prop_id.c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900392 writer.Indent();
Inseob Kim14e51872018-10-25 14:27:33 +0900393 writer.Write("return GetProp<%s>(\"%s\");\n", prop_type.c_str(),
394 prop.prop_name().c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900395 writer.Dedent();
396 writer.Write("}\n");
397
Inseob Kim14e51872018-10-25 14:27:33 +0900398 if (prop.access() != sysprop::Readonly) {
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900399 writer.Write("\nbool %s(const %s& value) {\n", prop_id.c_str(),
400 prop_type.c_str());
401 writer.Indent();
Inseob Kim9c5147d2019-03-06 11:36:36 +0900402
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 Kimb04d6192018-12-14 08:33:16 +0900420 writer.Write("return __system_property_set(\"%s\", %s) == 0;\n",
Inseob Kim9c5147d2019-03-06 11:36:36 +0900421 prop.prop_name().c_str(), format_expr);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900422 writer.Dedent();
423 writer.Write("}\n");
424 }
425 }
426
Inseob Kimade45e22018-08-29 19:08:35 +0900427 writer.Write("\n} // namespace %s\n", cpp_namespace.c_str());
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900428
Inseob Kim803bfb82019-02-15 18:40:45 +0900429 return writer.Code();
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900430}
431
432} // namespace
433
Inseob Kim053b83d2019-06-26 13:41:51 +0900434Result<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 Kim5f8f32c2018-08-24 11:10:44 +0900439 sysprop::Properties props;
440
Bernie Innocenti7ac8da42020-02-06 23:30:12 +0900441 if (auto res = ParseProps(input_file_path); res.ok()) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900442 props = std::move(*res);
443 } else {
444 return res.error();
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900445 }
446
Inseob Kimdbc2c802018-09-13 14:16:48 +0900447 std::string output_basename = android::base::Basename(input_file_path);
448
Inseob Kimcb71b082019-02-08 21:04:49 +0900449 for (auto&& [scope, dir] : {
450 std::pair(sysprop::Internal, header_dir),
Inseob Kim1ca03f32019-06-08 16:31:59 +0900451 std::pair(sysprop::Public, public_header_dir),
Inseob Kimcb71b082019-02-08 21:04:49 +0900452 }) {
Inseob Kim4584b8f2019-06-17 15:52:48 +0900453 std::error_code ec;
454 std::filesystem::create_directories(dir, ec);
455 if (ec) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900456 return Errorf("Creating directory to {} failed: {}", dir, ec.message());
Inseob Kimcb71b082019-02-08 21:04:49 +0900457 }
458
459 std::string path = dir + "/" + output_basename + ".h";
Inseob Kim803bfb82019-02-15 18:40:45 +0900460 std::string result = GenerateHeader(props, scope);
Inseob Kimcb71b082019-02-08 21:04:49 +0900461
462 if (!android::base::WriteStringToFile(result, path)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900463 return ErrnoErrorf("Writing generated header to {} failed", path);
Inseob Kimcb71b082019-02-08 21:04:49 +0900464 }
465 }
466
Inseob Kimdbc2c802018-09-13 14:16:48 +0900467 std::string source_path = source_output_dir + "/" + output_basename + ".cpp";
Inseob Kim803bfb82019-02-15 18:40:45 +0900468 std::string source_result = GenerateSource(props, include_name);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900469
470 if (!android::base::WriteStringToFile(source_result, source_path)) {
Inseob Kim053b83d2019-06-26 13:41:51 +0900471 return ErrnoErrorf("Writing generated source to {} failed", source_path);
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900472 }
473
Inseob Kim053b83d2019-06-26 13:41:51 +0900474 return {};
Inseob Kim5f8f32c2018-08-24 11:10:44 +0900475}