OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
inifile.cpp
Go to the documentation of this file.
1#include "inifile.h"
2
3#include <Tempest/Log>
4#include <cstring>
5#include <sstream>
6#include <cctype>
7
8#include "utils/fileutil.h"
9
10using namespace Tempest;
11
12static bool compareNoCase(std::string_view a, std::string_view b) {
13 if(a.size()!=b.size())
14 return false;
15 for(size_t i=0; i<a.size(); ++i) {
16 char ca = a[i];
17 char cb = b[i];
18 if('a'<=ca && ca<='z')
19 ca = char((ca-'a')+'A');
20 if('a'<=cb && cb<='z')
21 cb = char((cb-'a')+'A');
22 if(ca!=cb)
23 return false;
24 }
25 return true;
26 }
27
28IniFile::IniFile(std::u16string_view file) {
29 fileName = std::u16string(file);
30 if(!FileUtil::exists(fileName)) {
31 char name[256] = {};
32 size_t li = fileName.find_last_of('/') + 1;
33 for(size_t i=li; i<255 && i<file.size(); ++i)
34 name[i-li] = char(file.data()[i]);
35 Log::e("no \"", name, "\" file in path - using default settings");
36 return;
37 }
38
39 try {
40 RFile f(fileName);
41 implRead(f);
42 }
43 catch (...) {
44 Log::e("unable to read .ini file");
45 }
46 }
47
48IniFile::IniFile(Tempest::RFile &fin) {
49 implRead(fin);
50 }
51
53 if(!changeFlag)
54 return;
55 changeFlag = false;
56
57 std::stringstream s;
58 for(auto& i:sec){
59 s << "[" << i.name << "]" << std::endl << std::endl;
60 for(auto& r:i.val)
61 s << r.name << "=" << r.val << std::endl << std::endl;
62 s << std::endl;
63 }
64
65 try {
66 auto str=s.str();
67 WFile f(fileName);
68 f.write(&str[0],str.size());
69 f.flush();
70 }
71 catch (...) {
72 Log::e("unable to update .ini file");
73 }
74 }
75
76bool IniFile::has(std::string_view secName) {
77 for(auto& i:sec)
78 if(i.name==secName)
79 return true;
80 return false;
81 }
82
83bool IniFile::has(std::string_view s, std::string_view name) {
84 return (nullptr != find(s,name,false));
85 }
86
87int IniFile::getI(std::string_view s, std::string_view name, int idef) {
88 if(auto* val = find(s,name,false))
89 return getI(*val);
90 return idef;
91 }
92
93void IniFile::set(std::string_view sec, std::string_view name, int ival) {
94 if(sec.empty() || name.empty())
95 return;
96 auto& v = find(sec,name);
97 v.val = std::to_string(ival);
98 changeFlag = true;
99 }
100
101float IniFile::getF(std::string_view s, std::string_view name, float fdef) {
102 if(auto* val = find(s,name,false))
103 return getF(*val);
104 return fdef;
105 }
106
107void IniFile::set(std::string_view sec, std::string_view name, float fval) {
108 if(sec.empty() || name.empty())
109 return;
110 auto& v = find(sec,name);
111 v.val = std::to_string(fval);
112 changeFlag = true;
113 }
114
115std::string_view IniFile::getS(std::string_view s, std::string_view name) {
116 if(auto* val = find(s,name,false))
117 return val->val;
118 return "";
119 }
120
121void IniFile::set(std::string_view sec, std::string_view name, std::string_view sval) {
122 if(sec.empty() || name.empty())
123 return;
124 auto& v = find(sec,name);
125 v.val = sval;
126 changeFlag = true;
127 }
128
129void IniFile::implRead(RFile &fin) {
130 size_t sz = fin.size();
131 std::string str(sz,'\0');
132 fin.read(&str[0],sz);
133
134 std::stringstream s(str);
135 while(!s.eof()) {
136 implLine(s);
137 }
138 }
139
140void IniFile::implLine(std::istream &s) {
141 char ch=implSpace(s);
142
143 if(ch=='['){
144 s.get();
145 std::string name = implName(s);
146 addSection(std::move(name));
147 } else {
148 std::string name = implName(s);
149 s.get(ch);
150 while(ch!='=' && ch!='\n' && ch!='\r' && ch!='\0' && !s.eof())
151 s.get(ch);
152 std::string value = implValue(s);
153 addValue(std::move(name),std::move(value));
154 }
155
156 while(ch!='\n' && ch!='\r' && ch!='\0' && !s.eof())
157 s.get(ch);
158 }
159
160char IniFile::implSpace(std::istream &s) {
161 char ch=char(s.peek());
162 while(std::isspace(ch) && !s.eof()){
163 s.get(ch);
164 ch=char(s.peek());
165 }
166 return ch;
167 }
168
169std::string IniFile::implName(std::istream &s) {
170 std::string name;
171 char ch=char(s.peek());
172 while(ch==' ' && !s.eof()) {
173 s.get(ch);
174 ch=char(s.peek());
175 }
176 while(ch!=']' && ch!='=' && ch!='\n' && ch!='\r' && ch!=';' && ch!=' ' && !s.eof()){
177 name.push_back(ch);
178 s.get(ch);
179 ch=char(s.peek());
180 }
181 return name;
182 }
183
184std::string IniFile::implValue(std::istream &s) {
185 std::string name;
186 char ch=char(s.peek());
187 while((ch==' ' || ch=='\t') && !s.eof()) {
188 s.get(ch);
189 ch=char(s.peek());
190 }
191 while(ch!='\n' && ch!='\r' && ch!=';' && !s.eof()){
192 name.push_back(ch);
193 s.get(ch);
194 ch=char(s.peek());
195 if(ch==' ' || ch=='\t') {
196 name.push_back(' ');
197 do {
198 s.get(ch);
199 ch=char(s.peek());
200 } while((ch==' ' || ch=='\t') && !s.eof());
201 }
202 }
203 if(!name.empty() && name.back()==' ') {
204 name.pop_back();
205 }
206 return name;
207 }
208
209void IniFile::addSection(std::string &&name) {
210 for(auto& i:sec)
211 if(i.name==name)
212 return;
213 sec.emplace_back();
214 sec.back().name = std::move(name);
215 }
216
217void IniFile::addValue(std::string &&name, std::string &&val) {
218 if(sec.size()==0)
219 return;
220 addValue(sec.back(),std::move(name),std::move(val));
221 }
222
223void IniFile::addValue(Section &sec, std::string &&name, std::string &&val) {
224 if(name.size()==0)
225 return;
226 sec.val.emplace_back();
227
228 auto& v = sec.val.back();
229 v.name = std::move(name);
230 v.val = std::move(val);
231 }
232
233IniFile::Value& IniFile::find(std::string_view sec, std::string_view name) {
234 return *find(sec,name,true);
235 }
236
237IniFile::Value* IniFile::find(std::string_view s, std::string_view name, bool autoCreate) {
238 for(auto& i:sec){
239 if(compareNoCase(i.name,s)){
240 for(auto& r:i.val)
241 if(compareNoCase(r.name,name))
242 return &r;
243 if(autoCreate) {
244 addValue(i,std::string(name),"");
245 return &i.val.back();
246 }
247 return nullptr;
248 }
249 }
250 if(!autoCreate)
251 return nullptr;
252 sec.emplace_back();
253 sec.back().name = s;
254 addValue(sec.back(),std::string(name),"");
255 return &sec.back().val[0];
256 }
257
258int IniFile::getI(const IniFile::Value &v) const {
259 try {
260 return std::stoi(v.val);
261 }
262 catch(...) {
263 return 0;
264 }
265 }
266
267float IniFile::getF(const IniFile::Value& v) const {
268 try {
269 return float(std::stod(v.val));
270 }
271 catch(...) {
272 return 0;
273 }
274 }
void set(std::string_view sec, std::string_view name, int ival)
Definition inifile.cpp:93
IniFile()=default
auto getS(std::string_view sec, std::string_view name) -> std::string_view
Definition inifile.cpp:115
float getF(std::string_view sec, std::string_view name, float fdef=0)
Definition inifile.cpp:101
int getI(std::string_view sec, std::string_view name, int idef=0)
Definition inifile.cpp:87
bool has(std::string_view sec)
Definition inifile.cpp:76
void flush()
Definition inifile.cpp:52
static bool compareNoCase(std::string_view a, std::string_view b)
Definition inifile.cpp:12
static bool compareNoCase(std::string_view sa, std::string_view sb)
Definition marvin.cpp:26
bool exists(const std::u16string &path)
Definition fileutil.cpp:15