]> git.stg.codes - stg.git/blob - stglibs/conffiles.lib/conffiles.cpp
Ticket 37. 'Allow equal' and 'Allow expensive' comments changed to
[stg.git] / stglibs / conffiles.lib / conffiles.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Date: 27.10.2002
19  */
20
21 /*
22  *    Author : Boris Mikhailenko <stg34@ua.fm>
23  */
24
25  /*
26  $Revision: 1.5 $
27  $Date: 2009/10/22 11:40:22 $
28  */
29
30 //---------------------------------------------------------------------------
31
32 // getpid
33 #include <sys/types.h>
34 #include <unistd.h>
35
36 #include <cerrno> // E*
37 #include <cstring>
38 #include <cstdlib>
39 #include <cstdio>
40
41 #include <fstream>
42
43 #include "stg/conffiles.h"
44
45 namespace
46 {
47 //---------------------------------------------------------------------------
48 std::string TrimL(std::string val)
49 {
50 size_t pos = val.find_first_not_of(" \t");
51 if (pos == std::string::npos)
52     {
53     val.erase(val.begin(), val.end());
54     }
55 else
56     {
57     val.erase(0, pos);
58     }
59 return val;
60 }
61 //---------------------------------------------------------------------------
62 std::string TrimR(std::string val)
63 {
64 size_t pos = val.find_last_not_of(" \t");
65 if (pos != std::string::npos)
66     {
67     val.erase(pos + 1);
68     }
69 return val;
70 }
71 //---------------------------------------------------------------------------
72 std::string Trim(std::string val)
73 {
74 return TrimR(TrimL(val));
75 }
76 //---------------------------------------------------------------------------
77 } // namespace anonymous
78
79 //---------------------------------------------------------------------------
80 bool StringCaseCmp(const std::string & str1, const std::string & str2)
81 {
82 return (strcasecmp(str1.c_str(), str2.c_str()) < 0);
83 }
84 //---------------------------------------------------------------------------
85 CONFIGFILE::CONFIGFILE(const std::string & fn, bool nook)
86     : param_val(StringCaseCmp),
87       fileName(fn),
88       error(0),
89       changed(false)
90 {
91 std::ifstream f(fileName.c_str());
92
93 if (!f)
94     {
95     if (!nook)
96         error = -1;
97     return;
98     }
99
100 std::string line;
101 while (getline(f, line))
102     {
103     size_t pos = line.find('#');
104     if (pos != std::string::npos)
105         line.resize(pos);
106
107     if (line.find_first_not_of(" \t\r") == std::string::npos)
108         continue;
109
110     pos = line.find_first_of('=');
111     if (pos == std::string::npos)
112         {
113         error = -1;
114         return;
115         }
116
117     std::string parameter = Trim(line.substr(0, pos));
118     std::string value = Trim(line.substr(pos + 1));
119     param_val[parameter] = value;
120     }
121 }
122 //---------------------------------------------------------------------------
123 CONFIGFILE::~CONFIGFILE()
124 {
125 Flush();
126 }
127 //---------------------------------------------------------------------------
128 const std::string & CONFIGFILE::GetFileName() const
129 {
130 return fileName;
131 }
132 //---------------------------------------------------------------------------
133 int CONFIGFILE::Error() const
134 {
135 int e = error;
136 error = 0;
137 return e;
138 }
139 //---------------------------------------------------------------------------
140 int CONFIGFILE::ReadString(const std::string & param, std::string * val, const std::string & defaultVal) const
141 {
142 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
143
144 if (it != param_val.end())
145     {
146     *val = it->second;
147     return 0;
148     }
149
150 *val = defaultVal;
151 return -1;
152 }
153 //---------------------------------------------------------------------------
154 void CONFIGFILE::WriteString(const std::string & param, const std::string &val)
155 {
156 param_val[param] = val;
157 changed = true;
158 }
159 //---------------------------------------------------------------------------
160 int CONFIGFILE::ReadTime(const std::string & param, time_t * val, time_t defaultVal) const
161 {
162 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
163
164 if (it != param_val.end())
165     {
166     char *res;
167     *val = strtol(it->second.c_str(), &res, 10);
168     if (*res != 0)
169         {
170         *val = defaultVal; //Error!
171         return EINVAL;
172         }
173     return 0;
174     }
175
176 *val = defaultVal;
177 return -1;
178 }
179 //---------------------------------------------------------------------------
180 int CONFIGFILE::ReadInt(const std::string & param, int * val, int defaultVal) const
181 {
182 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
183
184 if (it != param_val.end())
185     {
186     char *res;
187     *val = static_cast<int>(strtol(it->second.c_str(), &res, 10));
188     if (*res != 0)
189         {
190         *val = defaultVal; //Error!
191         return EINVAL;
192         }
193     return 0;
194     }
195
196 *val = defaultVal;
197 return -1;
198 }
199 //---------------------------------------------------------------------------
200 int CONFIGFILE::ReadUInt(const std::string & param, unsigned int * val, unsigned int defaultVal) const
201 {
202 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
203
204 if (it != param_val.end())
205     {
206     char *res;
207     *val = static_cast<unsigned int>(strtoul(it->second.c_str(), &res, 10));
208     if (*res != 0)
209         {
210         *val = defaultVal; //Error!
211         return EINVAL;
212         }
213     return 0;
214     }
215
216 *val = defaultVal;
217 return -1;
218 }
219 //---------------------------------------------------------------------------
220 int CONFIGFILE::ReadLongInt(const std::string & param, long int * val, long int defaultVal) const
221 {
222 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
223
224 if (it != param_val.end())
225     {
226     char *res;
227     *val = strtol(it->second.c_str(), &res, 10);
228     if (*res != 0)
229         {
230         *val = defaultVal; //Error!
231         return EINVAL;
232         }
233     return 0;
234     }
235
236 *val = defaultVal;
237 return -1;
238 }
239 //---------------------------------------------------------------------------
240 int CONFIGFILE::ReadULongInt(const std::string & param, unsigned long int * val, unsigned long int defaultVal) const
241 {
242 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
243
244 if (it != param_val.end())
245     {
246     char *res;
247     *val = strtoul(it->second.c_str(), &res, 10);
248     if (*res != 0)
249         {
250         *val = defaultVal; //Error!
251         return EINVAL;
252         }
253     return 0;
254     }
255
256 *val = defaultVal;
257 return -1;
258 }
259 //---------------------------------------------------------------------------
260 int CONFIGFILE::ReadLongLongInt(const std::string & param, int64_t * val, int64_t defaultVal) const
261 {
262 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
263
264 if (it != param_val.end())
265     {
266     char *res;
267     *val = strtoll(it->second.c_str(), &res, 10);
268     if (*res != 0)
269         {
270         *val = defaultVal; //Error!
271         return EINVAL;
272         }
273     return 0;
274     }
275
276 *val = defaultVal;
277 return -1;
278 }
279 //---------------------------------------------------------------------------
280 int CONFIGFILE::ReadULongLongInt(const std::string & param, uint64_t * val, uint64_t defaultVal) const
281 {
282 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
283
284 if (it != param_val.end())
285     {
286     char *res;
287     *val = strtoull(it->second.c_str(), &res, 10);
288     if (*res != 0)
289         {
290         *val = defaultVal; //Error!
291         return EINVAL;
292         }
293     return 0;
294     }
295
296 *val = defaultVal;
297 return -1;
298 }
299 //---------------------------------------------------------------------------
300 int CONFIGFILE::ReadShortInt(const std::string & param, short int * val, short int defaultVal) const
301 {
302 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
303
304 if (it != param_val.end())
305     {
306     char *res;
307     *val = (short)strtol(it->second.c_str(), &res, 10);
308     if (*res != 0)
309         {
310         *val = defaultVal; //Error!
311         return EINVAL;
312         }
313     return 0;
314     }
315
316 *val = defaultVal;
317 return -1;
318 }
319 //---------------------------------------------------------------------------
320 int CONFIGFILE::ReadUShortInt(const std::string & param, unsigned short int * val, unsigned short int defaultVal) const
321 {
322 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
323
324 if (it != param_val.end())
325     {
326     char *res;
327     *val = (short)strtoul(it->second.c_str(), &res, 10);
328     if (*res != 0)
329         {
330         *val = defaultVal; //Error!
331         return EINVAL;
332         }
333     return 0;
334     }
335
336 *val = defaultVal;
337 return -1;
338 }
339 //---------------------------------------------------------------------------
340 void CONFIGFILE::WriteInt(const std::string & param, int64_t val)
341 {
342 char buf[32];
343 snprintf(buf, sizeof(buf), "%lld", static_cast<long long int>(val));
344 param_val[param] = buf;
345 changed = true;
346 }
347 //---------------------------------------------------------------------------
348 int CONFIGFILE::ReadDouble(const std::string & param, double * val, double defaultVal) const
349 {
350 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
351
352 if (it != param_val.end())
353     {
354     char *res;
355     *val = strtod(it->second.c_str(), &res);
356     if (*res != 0)
357         {
358         *val = defaultVal; //Error!
359         return EINVAL;
360         }
361     return 0;
362     }
363
364 *val = defaultVal;
365 return -1;
366 }
367 //---------------------------------------------------------------------------
368 void CONFIGFILE::WriteDouble(const std::string & param, double val)
369 {
370 char s[30];
371 snprintf(s, 30, "%f", val);
372 param_val[param] = s;
373 changed = true;
374 }
375 //---------------------------------------------------------------------------
376 int CONFIGFILE::Flush(const std::string & path) const
377 {
378 std::ofstream f(path.c_str());
379 if (!f.is_open())
380     {
381     error = EIO;
382     return EIO;
383     }
384
385 std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it = param_val.begin();
386 while (it != param_val.end())
387     {
388     f << it->first << "=" << it->second << "\n";
389     ++it;
390     }
391
392 f.close();
393 return 0;
394 }
395 //---------------------------------------------------------------------------
396 int CONFIGFILE::Flush() const
397 {
398 if (!changed)
399     return 0;
400
401 char pid[6];
402 snprintf(pid, sizeof(pid), "%d", getpid());
403
404 if (Flush(fileName + "." + pid))
405     return -1;
406
407 if (rename((fileName + "." + pid).c_str(), fileName.c_str()))
408     return -1;
409
410 changed = false;
411
412 return 0;
413 }
414 //---------------------------------------------------------------------------