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
17 #include "linkerconfig/configwriter.h"
18
19 #include <cstdarg>
20 #include <cstdio>
21 #include <iostream>
22 #include <memory>
23 #include <regex>
24
25 #include "linkerconfig/log.h"
26 #include "linkerconfig/variables.h"
27
28 constexpr const char* kVariableRegex =
29 "@\\{([^@\\{\\}:]+)(:([^@\\{\\}:]*))?\\}";
30
31 namespace android {
32 namespace linkerconfig {
33 namespace modules {
34
SetPrefix(const std::string & prefix)35 void ConfigWriter::SetPrefix(const std::string& prefix) {
36 prefix_ = prefix;
37 }
38
ResetPrefix()39 void ConfigWriter::ResetPrefix() {
40 prefix_ = "";
41 }
42
WriteLine(const char * format,...)43 void ConfigWriter::WriteLine(const char* format, ...) {
44 va_list args_for_length, args;
45
46 va_start(args, format);
47 va_copy(args_for_length, args);
48
49 int length = vsnprintf(nullptr, 0, format, args_for_length);
50 va_end(args_for_length);
51
52 if (length < 0) {
53 LOG(ERROR) << "Failed to get length of the string with format " << format;
54 va_end(args);
55 return;
56 }
57
58 std::unique_ptr<char[]> formatted_string(new char[length + 1]);
59
60 int res = vsnprintf(formatted_string.get(), length + 1, format, args);
61 va_end(args);
62
63 if (res < 0) {
64 LOG(ERROR) << "Failed to write a string with format " << format;
65 return;
66 }
67
68 WriteLine(std::string(formatted_string.get()));
69 }
70
WriteLine(const std::string & line)71 void ConfigWriter::WriteLine(const std::string& line) {
72 auto resolved_line = ResolveVariables(prefix_ + line);
73 content_ << resolved_line << std::endl;
74 }
75
ToString()76 std::string ConfigWriter::ToString() {
77 return content_.str();
78 }
79
ResolveVariables(const std::string & str)80 std::string ConfigWriter::ResolveVariables(const std::string& str) {
81 std::string result = str;
82 std::regex variable_regex(kVariableRegex);
83 std::smatch sm;
84
85 while (std::regex_search(result, sm, variable_regex)) {
86 std::stringstream ss;
87 ss << sm.prefix();
88 auto resolved_value = Variables::GetValue(sm[1]);
89 if (resolved_value.has_value()) {
90 ss << resolved_value.value();
91 } else {
92 LOG(WARNING) << "Unable to find value for " << sm[1];
93 bool contains_default = sm[2].length() > 0;
94 if (contains_default) {
95 ss << sm[3];
96 } else {
97 LOG(FATAL) << "There is no default value defined for " << sm[1];
98 }
99 }
100 ss << ResolveVariables(sm.suffix());
101 result = ss.str();
102 }
103
104 return result;
105 }
106
107 } // namespace modules
108 } // namespace linkerconfig
109 } // namespace android