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