]> git.stg.codes - stg.git/blob - libs/conffiles/conffiles.cpp
Install Boost in GitHub Actions.
[stg.git] / libs / conffiles / 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 <sstream>
39 #include <cstdlib>
40 #include <cstdio>
41
42 #include <fstream>
43
44 #include "stg/conffiles.h"
45
46 namespace
47 {
48 //---------------------------------------------------------------------------
49 std::string TrimL(std::string val)
50 {
51 size_t pos = val.find_first_not_of(" \t");
52 if (pos == std::string::npos)
53     {
54     val.erase(val.begin(), val.end());
55     }
56 else
57     {
58     val.erase(0, pos);
59     }
60 return val;
61 }
62 //---------------------------------------------------------------------------
63 std::string TrimR(std::string val)
64 {
65 size_t pos = val.find_last_not_of(" \t");
66 if (pos != std::string::npos)
67     {
68     val.erase(pos + 1);
69     }
70 return val;
71 }
72 //---------------------------------------------------------------------------
73 std::string Trim(const std::string& val)
74 {
75 return TrimR(TrimL(val));
76 }
77 //---------------------------------------------------------------------------
78 } // namespace anonymous
79
80 //---------------------------------------------------------------------------
81 bool StringCaseCmp(const std::string & str1, const std::string & str2)
82 {
83 return (strcasecmp(str1.c_str(), str2.c_str()) < 0);
84 }
85 //---------------------------------------------------------------------------
86 CONFIGFILE::CONFIGFILE(const std::string & fn, bool nook)
87     : param_val(StringCaseCmp),
88       fileName(fn),
89       error(0),
90       changed(false)
91 {
92 std::ifstream f(fileName.c_str());
93
94 if (!f)
95     {
96     if (!nook)
97         error = -1;
98     return;
99     }
100
101 std::string line;
102 while (getline(f, line))
103     {
104     size_t pos = line.find('#');
105     if (pos != std::string::npos)
106         line.resize(pos);
107
108     if (line.find_first_not_of(" \t\r") == std::string::npos)
109         continue;
110
111     pos = line.find_first_of('=');
112     if (pos == std::string::npos)
113         {
114         error = -1;
115         return;
116         }
117
118     std::string parameter = Trim(line.substr(0, pos));
119     std::string value = Trim(line.substr(pos + 1));
120     param_val[parameter] = value;
121     }
122 }
123 //---------------------------------------------------------------------------
124 CONFIGFILE::~CONFIGFILE()
125 {
126 Flush();
127 }
128 //---------------------------------------------------------------------------
129 const std::string & CONFIGFILE::GetFileName() const
130 {
131 return fileName;
132 }
133 //---------------------------------------------------------------------------
134 int CONFIGFILE::Error() const
135 {
136 int e = error;
137 error = 0;
138 return e;
139 }
140 //---------------------------------------------------------------------------
141 int CONFIGFILE::ReadString(const std::string & param, std::string * val, const std::string & defaultVal) const
142 {
143 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
144
145 if (it != param_val.end())
146     {
147     *val = it->second;
148     return 0;
149     }
150
151 *val = defaultVal;
152 return -1;
153 }
154 //---------------------------------------------------------------------------
155 void CONFIGFILE::WriteString(const std::string & param, const std::string &val)
156 {
157 param_val[param] = val;
158 changed = true;
159 }
160 //---------------------------------------------------------------------------
161 int CONFIGFILE::ReadTime(const std::string & param, time_t * val, time_t defaultVal) const
162 {
163 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
164
165 if (it != param_val.end())
166     {
167     char *res;
168     *val = strtol(it->second.c_str(), &res, 10);
169     if (*res != 0)
170         {
171         *val = defaultVal; //Error!
172         return EINVAL;
173         }
174     return 0;
175     }
176
177 *val = defaultVal;
178 return -1;
179 }
180 //---------------------------------------------------------------------------
181 int CONFIGFILE::ReadInt(const std::string & param, int * val, int defaultVal) const
182 {
183 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
184
185 if (it != param_val.end())
186     {
187     char *res;
188     *val = static_cast<int>(strtol(it->second.c_str(), &res, 10));
189     if (*res != 0)
190         {
191         *val = defaultVal; //Error!
192         return EINVAL;
193         }
194     return 0;
195     }
196
197 *val = defaultVal;
198 return -1;
199 }
200 //---------------------------------------------------------------------------
201 int CONFIGFILE::ReadUInt(const std::string & param, unsigned int * val, unsigned int defaultVal) const
202 {
203 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
204
205 if (it != param_val.end())
206     {
207     char *res;
208     *val = static_cast<unsigned int>(strtoul(it->second.c_str(), &res, 10));
209     if (*res != 0)
210         {
211         *val = defaultVal; //Error!
212         return EINVAL;
213         }
214     return 0;
215     }
216
217 *val = defaultVal;
218 return -1;
219 }
220 //---------------------------------------------------------------------------
221 int CONFIGFILE::ReadLongInt(const std::string & param, long int * val, long int defaultVal) const
222 {
223 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
224
225 if (it != param_val.end())
226     {
227     char *res;
228     *val = strtol(it->second.c_str(), &res, 10);
229     if (*res != 0)
230         {
231         *val = defaultVal; //Error!
232         return EINVAL;
233         }
234     return 0;
235     }
236
237 *val = defaultVal;
238 return -1;
239 }
240 //---------------------------------------------------------------------------
241 int CONFIGFILE::ReadULongInt(const std::string & param, unsigned long int * val, unsigned long int defaultVal) const
242 {
243 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
244
245 if (it != param_val.end())
246     {
247     char *res;
248     *val = strtoul(it->second.c_str(), &res, 10);
249     if (*res != 0)
250         {
251         *val = defaultVal; //Error!
252         return EINVAL;
253         }
254     return 0;
255     }
256
257 *val = defaultVal;
258 return -1;
259 }
260 //---------------------------------------------------------------------------
261 int CONFIGFILE::ReadLongLongInt(const std::string & param, int64_t * val, int64_t defaultVal) const
262 {
263 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
264
265 if (it != param_val.end())
266     {
267     char *res;
268     *val = strtoll(it->second.c_str(), &res, 10);
269     if (*res != 0)
270         {
271         *val = defaultVal; //Error!
272         return EINVAL;
273         }
274     return 0;
275     }
276
277 *val = defaultVal;
278 return -1;
279 }
280 //---------------------------------------------------------------------------
281 int CONFIGFILE::ReadULongLongInt(const std::string & param, uint64_t * val, uint64_t defaultVal) const
282 {
283 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
284
285 if (it != param_val.end())
286     {
287     char *res;
288     *val = strtoull(it->second.c_str(), &res, 10);
289     if (*res != 0)
290         {
291         *val = defaultVal; //Error!
292         return EINVAL;
293         }
294     return 0;
295     }
296
297 *val = defaultVal;
298 return -1;
299 }
300 //---------------------------------------------------------------------------
301 int CONFIGFILE::ReadShortInt(const std::string & param, short int * val, short int defaultVal) const
302 {
303 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
304
305 if (it != param_val.end())
306     {
307     char *res;
308     *val = static_cast<short>(strtol(it->second.c_str(), &res, 10));
309     if (*res != 0)
310         {
311         *val = defaultVal; //Error!
312         return EINVAL;
313         }
314     return 0;
315     }
316
317 *val = defaultVal;
318 return -1;
319 }
320 //---------------------------------------------------------------------------
321 int CONFIGFILE::ReadUShortInt(const std::string & param, unsigned short int * val, unsigned short int defaultVal) const
322 {
323 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
324
325 if (it != param_val.end())
326     {
327     char *res;
328     *val = static_cast<short>(strtoul(it->second.c_str(), &res, 10));
329     if (*res != 0)
330         {
331         *val = defaultVal; //Error!
332         return EINVAL;
333         }
334     return 0;
335     }
336
337 *val = defaultVal;
338 return -1;
339 }
340 //---------------------------------------------------------------------------
341 void CONFIGFILE::WriteInt(const std::string & param, int64_t val)
342 {
343 char buf[32];
344 snprintf(buf, sizeof(buf), "%lld", static_cast<long long int>(val));
345 param_val[param] = buf;
346 changed = true;
347 }
348 //---------------------------------------------------------------------------
349 void CONFIGFILE::WriteTime(const std::string & param, time_t val)
350 {
351 std::stringstream ss;
352 ss<<val;
353 param_val[param] = ss.str();
354 changed = true;
355 }
356 //---------------------------------------------------------------------------
357 int CONFIGFILE::ReadDouble(const std::string & param, double * val, double defaultVal) const
358 {
359 const std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it(param_val.find(param));
360
361 if (it != param_val.end())
362     {
363     char *res;
364     *val = strtod(it->second.c_str(), &res);
365     if (*res != 0)
366         {
367         *val = defaultVal; //Error!
368         return EINVAL;
369         }
370     return 0;
371     }
372
373 *val = defaultVal;
374 return -1;
375 }
376 //---------------------------------------------------------------------------
377 void CONFIGFILE::WriteDouble(const std::string & param, double val)
378 {
379 char s[30];
380 snprintf(s, 30, "%f", val);
381 param_val[param] = s;
382 changed = true;
383 }
384 //---------------------------------------------------------------------------
385 int CONFIGFILE::Flush(const std::string & path) const
386 {
387 std::ofstream f(path.c_str());
388 if (!f.is_open())
389     {
390     error = EIO;
391     return EIO;
392     }
393
394 std::map<std::string, std::string, StringCaseCmp_t>::const_iterator it = param_val.begin();
395 while (it != param_val.end())
396     {
397     f << it->first << "=" << it->second << "\n";
398     ++it;
399     }
400
401 f.close();
402 return 0;
403 }
404 //---------------------------------------------------------------------------
405 int CONFIGFILE::Flush() const
406 {
407 if (!changed)
408     return 0;
409
410 char pid[6];
411 snprintf(pid, sizeof(pid), "%d", getpid());
412
413 if (Flush(fileName + "." + pid))
414     return -1;
415
416 if (rename((fileName + "." + pid).c_str(), fileName.c_str()))
417     return -1;
418
419 changed = false;
420
421 return 0;
422 }
423 //---------------------------------------------------------------------------