xref: /aosp_15_r20/external/swiftshader/src/System/Configurator.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "Configurator.hpp"
16 #include "Debug.hpp"
17 
18 #include <algorithm>
19 #include <fstream>
20 #include <istream>
21 
22 namespace {
trimSpaces(const std::string & str)23 inline std::string trimSpaces(const std::string &str)
24 {
25 	std::string trimmed = str;
26 	trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), [](unsigned char c) {
27 		              return !std::isspace(c);
28 	              }));
29 	trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), [](unsigned char c) {
30 		              return !std::isspace(c);
31 	              }).base(),
32 	              trimmed.end());
33 	return trimmed;
34 }
35 }  // namespace
36 
37 namespace sw {
38 
Configurator(const std::string & filePath)39 Configurator::Configurator(const std::string &filePath)
40 {
41 	std::fstream file(filePath, std::ios::in);
42 	if(file.fail())
43 	{
44 		return;
45 	}
46 	readConfiguration(file);
47 	file.close();
48 }
49 
Configurator(std::istream & str)50 Configurator::Configurator(std::istream &str)
51 {
52 	readConfiguration(str);
53 }
54 
readConfiguration(std::istream & str)55 bool Configurator::readConfiguration(std::istream &str)
56 {
57 	std::string line;
58 	std::string sectionName;
59 
60 	int lineNumber = 0;
61 	while(getline(str, line))
62 	{
63 		++lineNumber;
64 		if(line.length())
65 		{
66 			if(line[line.length() - 1] == '\r')
67 			{
68 				line = line.substr(0, line.length() - 1);
69 			}
70 
71 			if(!isprint(line[0]))
72 			{
73 				sw::warn("Cannot parse line %d of configuration, skipping line\n", lineNumber);
74 				return false;
75 			}
76 
77 			std::string::size_type pLeft = line.find_first_of(";#[=");
78 
79 			if(pLeft != std::string::npos)
80 			{
81 				switch(line[pLeft])
82 				{
83 				case '[':
84 					{
85 						std::string::size_type pRight = line.find_last_of("]");
86 
87 						if(pRight != std::string::npos && pRight > pLeft)
88 						{
89 							sectionName = trimSpaces(line.substr(pLeft + 1, pRight - pLeft - 1));
90 							if(!sectionName.length())
91 							{
92 								sw::warn("Found empty section name at line %d of configuration\n", lineNumber);
93 							}
94 						}
95 					}
96 					break;
97 				case '=':
98 					{
99 						std::string key = trimSpaces(line.substr(0, pLeft));
100 						std::string value = trimSpaces(line.substr(pLeft + 1));
101 						if(!key.length() || !value.length())
102 						{
103 							sw::warn("Cannot parse key-value pair at line %d of configuration (key or value is empty), skipping key-value pair\n", lineNumber);
104 						}
105 						else
106 						{
107 							sections[sectionName].keyValuePairs[key] = value;
108 						}
109 					}
110 					break;
111 				case ';':
112 				case '#':
113 					// Ignore comments
114 					break;
115 				}
116 			}
117 		}
118 	}
119 
120 	return sections.size() > 0;
121 }
122 
writeFile(const std::string & filePath,const std::string & title)123 void Configurator::writeFile(const std::string &filePath, const std::string &title)
124 {
125 	std::fstream file(filePath, std::ios::out);
126 	if(file.fail())
127 	{
128 		return;
129 	}
130 
131 	file << "; " << title << std::endl
132 	     << std::endl;
133 
134 	for(const auto &[sectionName, section] : sections)
135 	{
136 		file << "[" << sectionName << "]" << std::endl;
137 		for(const auto &[key, value] : section.keyValuePairs)
138 		{
139 			file << key << "=" << value << std::endl;
140 		}
141 		file << std::endl;
142 	}
143 
144 	file.close();
145 }
146 
getValueIfExists(const std::string & sectionName,const std::string & keyName) const147 std::optional<std::string> Configurator::getValueIfExists(const std::string &sectionName, const std::string &keyName) const
148 {
149 	const auto section = sections.find(sectionName);
150 	if(section == sections.end())
151 	{
152 		return std::nullopt;
153 	}
154 
155 	const auto keyValue = section->second.keyValuePairs.find(keyName);
156 	if(keyValue == section->second.keyValuePairs.end())
157 	{
158 		return std::nullopt;
159 	}
160 
161 	return keyValue->second;
162 }
163 
getValue(const std::string & sectionName,const std::string & keyName,const std::string & defaultValue) const164 std::string Configurator::getValue(const std::string &sectionName, const std::string &keyName, const std::string &defaultValue) const
165 {
166 	const auto value = getValueIfExists(sectionName, keyName);
167 	if(value)
168 	{
169 		return *value;
170 	}
171 	return defaultValue;
172 }
173 
addValue(const std::string & sectionName,const std::string & keyName,const std::string & value)174 void Configurator::addValue(const std::string &sectionName, const std::string &keyName, const std::string &value)
175 {
176 	sections[sectionName].keyValuePairs[keyName] = value;
177 }
178 
getBoolean(const std::string & sectionName,const std::string & keyName,bool defaultValue) const179 bool Configurator::getBoolean(const std::string &sectionName, const std::string &keyName, bool defaultValue) const
180 {
181 	auto strValue = getValueIfExists(sectionName, keyName);
182 	if(!strValue)
183 	{
184 		return defaultValue;
185 	}
186 
187 	std::stringstream ss{ *strValue };
188 
189 	bool val;
190 	ss >> val;
191 	if(ss.fail())
192 	{
193 		// Accept "true" and "false" as well.
194 		ss.clear();
195 		ss >> std::boolalpha >> val;
196 	}
197 	return val;
198 }
199 
getFloat(const std::string & sectionName,const std::string & keyName,double defaultValue) const200 double Configurator::getFloat(const std::string &sectionName, const std::string &keyName, double defaultValue) const
201 {
202 	auto strValue = getValueIfExists(sectionName, keyName);
203 	if(!strValue)
204 	{
205 		return defaultValue;
206 	}
207 
208 	std::stringstream ss{ *strValue };
209 
210 	double val = 0;
211 	ss >> val;
212 	return val;
213 }
214 }  // namespace sw
215