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
17#include <iostream>
18#include <fstream>
19
20using namespace std;
21
22#include <stdio.h>
23#include <stdarg.h>
24#include <ctype.h>
25
26#if defined(__unix__)
27#include <unistd.h>
28#endif
29
30namespace sw
31{
32 Configurator::Configurator(string iniPath)
33 {
34 path = iniPath;
35
36 readFile();
37 }
38
39 Configurator::~Configurator()
40 {
41 }
42
43 bool Configurator::readFile()
44 {
45 #if defined(__unix__)
46 if(access(path.c_str(), R_OK) != 0)
47 {
48 return false;
49 }
50 #endif
51
52 fstream file(path.c_str(), ios::in);
53 if(file.fail()) return false;
54
55 string line;
56 string keyName;
57
58 while(getline(file, line))
59 {
60 if(line.length())
61 {
62 if(line[line.length() - 1] == '\r')
63 {
64 line = line.substr(0, line.length() - 1);
65 }
66
67 if(!isprint(line[0]))
68 {
69 // printf("Failing on char %d\n", line[0]);
70 file.close();
71 return false;
72 }
73
74 string::size_type pLeft = line.find_first_of(";#[=");
75
76 if(pLeft != string::npos)
77 {
78 switch(line[pLeft])
79 {
80 case '[':
81 {
82 string::size_type pRight = line.find_last_of("]");
83
84 if(pRight != string::npos && pRight > pLeft)
85 {
86 keyName = line.substr(pLeft + 1, pRight - pLeft - 1);
87 addKeyName(keyName);
88 }
89 }
90 break;
91 case '=':
92 {
93 string valueName = line.substr(0, pLeft);
94 string value = line.substr(pLeft + 1);
95 addValue(keyName, valueName, value);
96 }
97 break;
98 case ';':
99 case '#':
100 // Ignore comments
101 break;
102 }
103 }
104 }
105 }
106
107 file.close();
108
109 if(names.size())
110 {
111 return true;
112 }
113
114 return false;
115 }
116
117 void Configurator::writeFile(std::string title)
118 {
119 #if defined(__unix__)
120 if(access(path.c_str(), W_OK) != 0)
121 {
122 return;
123 }
124 #endif
125
126 fstream file(path.c_str(), ios::out);
127 if(file.fail()) return;
128
129 file << "; " << title << endl << endl;
130
131 for(unsigned int keyID = 0; keyID < sections.size(); keyID++)
132 {
133 file << "[" << names[keyID] << "]" << endl;
134
135 for(unsigned int valueID = 0; valueID < sections[keyID].names.size(); valueID++)
136 {
137 file << sections[keyID].names[valueID] << "=" << sections[keyID].values[valueID] << endl;
138 }
139
140 file << endl;
141 }
142
143 file.close();
144 }
145
146 int Configurator::findKey(string keyName) const
147 {
148 for(unsigned int keyID = 0; keyID < names.size(); keyID++)
149 {
150 if(names[keyID] == keyName)
151 {
152 return keyID;
153 }
154 }
155
156 return -1;
157 }
158
159 int Configurator::findValue(unsigned int keyID, string valueName) const
160 {
161 if(!sections.size() || keyID >= sections.size())
162 {
163 return -1;
164 }
165
166 for(unsigned int valueID = 0; valueID < sections[keyID].names.size(); ++valueID)
167 {
168 if(sections[keyID].names[valueID] == valueName)
169 {
170 return valueID;
171 }
172 }
173
174 return -1;
175 }
176
177 unsigned int Configurator::addKeyName(string keyName)
178 {
179 names.resize(names.size() + 1, keyName);
180 sections.resize(sections.size() + 1);
181 return (unsigned int)names.size() - 1;
182 }
183
184 void Configurator::addValue(string const keyName, string const valueName, string const value)
185 {
186 int keyID = findKey(keyName);
187
188 if(keyID == -1)
189 {
190 keyID = addKeyName(keyName);
191 }
192
193 int valueID = findValue(keyID, valueName);
194
195 if(valueID == -1)
196 {
197 sections[keyID].names.resize(sections[keyID].names.size() + 1, valueName);
198 sections[keyID].values.resize(sections[keyID].values.size() + 1, value);
199 }
200 else
201 {
202 sections[keyID].values[valueID] = value;
203 }
204 }
205
206 string Configurator::getValue(string keyName, string valueName, string defaultValue) const
207 {
208 int keyID = findKey(keyName);
209 if(keyID == -1) return defaultValue;
210 int valueID = findValue((unsigned int)keyID, valueName);
211 if(valueID == -1) return defaultValue;
212
213 return sections[keyID].values[valueID];
214 }
215
216 int Configurator::getInteger(string keyName, string valueName, int defaultValue) const
217 {
218 char svalue[256];
219
220 sprintf(svalue, "%d", defaultValue);
221
222 return atoi(getValue(keyName, valueName, svalue).c_str());
223 }
224
225 bool Configurator::getBoolean(string keyName, string valueName, bool defaultValue) const
226 {
227 return getInteger(keyName, valueName, (int)defaultValue) != 0;
228 }
229
230 double Configurator::getFloat(string keyName, string valueName, double defaultValue) const
231 {
232 char svalue[256];
233
234 sprintf(svalue, "%f", defaultValue);
235
236 return atof(getValue(keyName, valueName, svalue).c_str());
237 }
238
239 unsigned int Configurator::getFormatted(string keyName, string valueName, char *format,
240 void *v1, void *v2, void *v3, void *v4,
241 void *v5, void *v6, void *v7, void *v8,
242 void *v9, void *v10, void *v11, void *v12,
243 void *v13, void *v14, void *v15, void *v16)
244 {
245 string value = getValue(keyName, valueName);
246
247 if(!value.length()) return false;
248
249 unsigned int nVals = sscanf(value.c_str(), format,
250 v1, v2, v3, v4, v5, v6, v7, v8,
251 v9, v10, v11, v12, v13, v14, v15, v16);
252
253 return nVals;
254 }
255}
256