• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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