JLab VME Pipeline TI Library  3v11.3
JLab VME Pipeline TI library
 All Classes Functions Variables Groups
INIReader.h
1 // Read an INI file into easy-to-access name/value pairs.
2 
3 // inih and INIReader are released under the New BSD license (see INIReader-LICENSE.txt).
4 // Go to the project home page for more info:
5 //
6 // https://github.com/benhoyt/inih
7 /* inih -- simple .INI file parser
8 
9 inih is released under the New BSD license (see LICENSE.txt). Go to the project
10 home page for more info:
11 
12 https://github.com/benhoyt/inih
13 
14 */
15 
16 #ifndef __INI_H__
17 #define __INI_H__
18 
19 /* Make this header file easier to include in C++ code */
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 #include <stdio.h>
25 
26 /* Typedef for prototype of handler function. */
27 typedef int (*ini_handler)(void* user, const char* section,
28  const char* name, const char* value);
29 
30 /* Typedef for prototype of fgets-style reader function. */
31 typedef char* (*ini_reader)(char* str, int num, void* stream);
32 
33 /* Parse given INI-style file. May have [section]s, name=value pairs
34  (whitespace stripped), and comments starting with ';' (semicolon). Section
35  is "" if name=value pair parsed before any section heading. name:value
36  pairs are also supported as a concession to Python's configparser.
37 
38  For each name=value pair parsed, call handler function with given user
39  pointer as well as section, name, and value (data only valid for duration
40  of handler call). Handler should return nonzero on success, zero on error.
41 
42  Returns 0 on success, line number of first error on parse error (doesn't
43  stop on first error), -1 on file open error, or -2 on memory allocation
44  error (only when INI_USE_STACK is zero).
45 */
46 int ini_parse(const char* filename, ini_handler handler, void* user);
47 
48 /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
49  close the file when it's finished -- the caller must do that. */
50 int ini_parse_file(FILE* file, ini_handler handler, void* user);
51 
52 /* Same as ini_parse(), but takes an ini_reader function pointer instead of
53  filename. Used for implementing custom or string-based I/O. */
54 int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
55  void* user);
56 
57 /* Nonzero to allow multi-line value parsing, in the style of Python's
58  configparser. If allowed, ini_parse() will call the handler with the same
59  name for each subsequent line parsed. */
60 #ifndef INI_ALLOW_MULTILINE
61 #define INI_ALLOW_MULTILINE 1
62 #endif
63 
64 /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
65  the file. See http://code.google.com/p/inih/issues/detail?id=21 */
66 #ifndef INI_ALLOW_BOM
67 #define INI_ALLOW_BOM 1
68 #endif
69 
70 /* Nonzero to allow inline comments (with valid inline comment characters
71  specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
72  Python 3.2+ configparser behaviour. */
73 #ifndef INI_ALLOW_INLINE_COMMENTS
74 #define INI_ALLOW_INLINE_COMMENTS 1
75 #endif
76 #ifndef INI_INLINE_COMMENT_PREFIXES
77 #define INI_INLINE_COMMENT_PREFIXES ";"
78 #endif
79 
80 /* Nonzero to use stack, zero to use heap (malloc/free). */
81 #ifndef INI_USE_STACK
82 #define INI_USE_STACK 1
83 #endif
84 
85 /* Stop parsing on first error (default is to keep parsing). */
86 #ifndef INI_STOP_ON_FIRST_ERROR
87 #define INI_STOP_ON_FIRST_ERROR 0
88 #endif
89 
90 /* Maximum line length for any line in INI file. */
91 #ifndef INI_MAX_LINE
92 #define INI_MAX_LINE 200
93 #endif
94 
95 #ifdef __cplusplus
96 }
97 #endif
98 
99 /* inih -- simple .INI file parser
100 
101 inih is released under the New BSD license (see LICENSE.txt). Go to the project
102 home page for more info:
103 
104 https://github.com/benhoyt/inih
105 
106 */
107 
108 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
109 #define _CRT_SECURE_NO_WARNINGS
110 #endif
111 
112 #include <stdio.h>
113 #include <ctype.h>
114 #include <string.h>
115 
116 #if !INI_USE_STACK
117 #include <stdlib.h>
118 #endif
119 
120 #define MAX_SECTION 50
121 #define MAX_NAME 50
122 
123 /* Strip whitespace chars off end of given string, in place. Return s. */
124 inline static char* rstrip(char* s)
125 {
126  char* p = s + strlen(s);
127  while (p > s && isspace((unsigned char)(*--p)))
128  *p = '\0';
129  return s;
130 }
131 
132 /* Return pointer to first non-whitespace char in given string. */
133 inline static char* lskip(const char* s)
134 {
135  while (*s && isspace((unsigned char)(*s)))
136  s++;
137  return (char*)s;
138 }
139 
140 /* Return pointer to first char (of chars) or inline comment in given string,
141  or pointer to null at end of string if neither found. Inline comment must
142  be prefixed by a whitespace character to register as a comment. */
143 inline static char* find_chars_or_comment(const char* s, const char* chars)
144 {
145 #if INI_ALLOW_INLINE_COMMENTS
146  int was_space = 0;
147  while (*s && (!chars || !strchr(chars, *s)) &&
148  !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
149  was_space = isspace((unsigned char)(*s));
150  s++;
151  }
152 #else
153  while (*s && (!chars || !strchr(chars, *s))) {
154  s++;
155  }
156 #endif
157  return (char*)s;
158 }
159 
160 /* Version of strncpy that ensures dest (size bytes) is null-terminated. */
161 inline static char* strncpy0(char* dest, const char* src, size_t size)
162 {
163  strncpy(dest, src, size);
164  dest[size - 1] = '\0';
165  return dest;
166 }
167 
168 /* See documentation in header file. */
169 inline int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
170  void* user)
171 {
172  /* Uses a fair bit of stack (use heap instead if you need to) */
173 #if INI_USE_STACK
174  char line[INI_MAX_LINE];
175 #else
176  char* line;
177 #endif
178  char section[MAX_SECTION] = "";
179  char prev_name[MAX_NAME] = "";
180 
181  char* start;
182  char* end;
183  char* name;
184  char* value;
185  int lineno = 0;
186  int error = 0;
187 
188 #if !INI_USE_STACK
189  line = (char*)malloc(INI_MAX_LINE);
190  if (!line) {
191  return -2;
192  }
193 #endif
194 
195  /* Scan through stream line by line */
196  while (reader(line, INI_MAX_LINE, stream) != NULL) {
197  lineno++;
198 
199  start = line;
200 #if INI_ALLOW_BOM
201  if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
202  (unsigned char)start[1] == 0xBB &&
203  (unsigned char)start[2] == 0xBF) {
204  start += 3;
205  }
206 #endif
207  start = lskip(rstrip(start));
208 
209  if (*start == ';' || *start == '#') {
210  /* Per Python configparser, allow both ; and # comments at the
211  start of a line */
212  }
213 #if INI_ALLOW_MULTILINE
214  else if (*prev_name && *start && start > line) {
215 
216 #if INI_ALLOW_INLINE_COMMENTS
217  end = find_chars_or_comment(start, NULL);
218  if (*end)
219  *end = '\0';
220  rstrip(start);
221 #endif
222 
223  /* Non-blank line with leading whitespace, treat as continuation
224  of previous name's value (as per Python configparser). */
225  if (!handler(user, section, prev_name, start) && !error)
226  error = lineno;
227  }
228 #endif
229  else if (*start == '[') {
230  /* A "[section]" line */
231  end = find_chars_or_comment(start + 1, "]");
232  if (*end == ']') {
233  *end = '\0';
234  strncpy0(section, start + 1, sizeof(section));
235  *prev_name = '\0';
236  }
237  else if (!error) {
238  /* No ']' found on section line */
239  error = lineno;
240  }
241  }
242  else if (*start) {
243  /* Not a comment, must be a name[=:]value pair */
244  end = find_chars_or_comment(start, "=:");
245  if (*end == '=' || *end == ':') {
246  *end = '\0';
247  name = rstrip(start);
248  value = lskip(end + 1);
249 #if INI_ALLOW_INLINE_COMMENTS
250  end = find_chars_or_comment(value, NULL);
251  if (*end)
252  *end = '\0';
253 #endif
254  rstrip(value);
255 
256  /* Valid name[=:]value pair found, call handler */
257  strncpy0(prev_name, name, sizeof(prev_name));
258  if (!handler(user, section, name, value) && !error)
259  error = lineno;
260  }
261  else if (!error) {
262  /* No '=' or ':' found on name[=:]value line */
263  error = lineno;
264  }
265  }
266 
267 #if INI_STOP_ON_FIRST_ERROR
268  if (error)
269  break;
270 #endif
271  }
272 
273 #if !INI_USE_STACK
274  free(line);
275 #endif
276 
277  return error;
278 }
279 
280 /* See documentation in header file. */
281 inline int ini_parse_file(FILE* file, ini_handler handler, void* user)
282 {
283  return ini_parse_stream((ini_reader)fgets, file, handler, user);
284 }
285 
286 /* See documentation in header file. */
287 inline int ini_parse(const char* filename, ini_handler handler, void* user)
288 {
289  FILE* file;
290  int error;
291 
292  file = fopen(filename, "r");
293  if (!file)
294  return -1;
295  error = ini_parse_file(file, handler, user);
296  fclose(file);
297  return error;
298 }
299 
300 #endif /* __INI_H__ */
301 
302 
303 #ifndef __INIREADER_H__
304 #define __INIREADER_H__
305 
306 #include <map>
307 #include <set>
308 #include <string>
309 
310 // Read an INI file into easy-to-access name/value pairs. (Note that I've gone
311 // for simplicity here rather than speed, but it should be pretty decent.)
313 {
314 public:
315  // Empty Constructor
316  INIReader() {};
317 
318  // Construct INIReader and parse given filename. See ini.h for more info
319  // about the parsing.
320  explicit INIReader(const std::string& filename);
321 
322  // Construct INIReader and parse given file. See ini.h for more info
323  // about the parsing.
324  explicit INIReader(FILE *file);
325 
326  // Return the result of ini_parse(), i.e., 0 on success, line number of
327  // first error on parse error, or -1 on file open error.
328  int ParseError() const;
329 
330  // Return the list of sections found in ini file
331  const std::set<std::string>& Sections() const;
332 
333  // Get a string value from INI file, returning default_value if not found.
334  std::string Get(const std::string& section, const std::string& name,
335  const std::string& default_value) const;
336 
337  // Get an integer (long) value from INI file, returning default_value if
338  // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
339  long GetInteger(const std::string& section, const std::string& name, long default_value) const;
340 
341  // Get a real (floating point double) value from INI file, returning
342  // default_value if not found or not a valid floating point value
343  // according to strtod().
344  double GetReal(const std::string& section, const std::string& name, double default_value) const;
345 
346  // Get a single precision floating point number value from INI file, returning
347  // default_value if not found or not a valid floating point value
348  // according to strtof().
349  float GetFloat(const std::string& section, const std::string& name, float default_value) const;
350 
351  // Get a boolean value from INI file, returning default_value if not found or if
352  // not a valid true/false value. Valid true values are "true", "yes", "on", "1",
353  // and valid false values are "false", "no", "off", "0" (not case sensitive).
354  bool GetBoolean(const std::string& section, const std::string& name, bool default_value) const;
355 
356 protected:
357  int _error;
358  std::map<std::string, std::string> _values;
359  std::set<std::string> _sections;
360  static std::string MakeKey(const std::string& section, const std::string& name);
361  static int ValueHandler(void* user, const char* section, const char* name,
362  const char* value);
363 };
364 
365 #endif // __INIREADER_H__
366 
367 
368 #ifndef __INIREADER__
369 #define __INIREADER__
370 
371 #include <algorithm>
372 #include <cctype>
373 #include <cstdlib>
374 
375 inline INIReader::INIReader(const std::string& filename)
376 {
377  _error = ini_parse(filename.c_str(), ValueHandler, this);
378 }
379 
380 inline INIReader::INIReader(FILE *file)
381 {
382  _error = ini_parse_file(file, ValueHandler, this);
383 }
384 
385 inline int INIReader::ParseError() const
386 {
387  return _error;
388 }
389 
390 inline const std::set<std::string>& INIReader::Sections() const
391 {
392  return _sections;
393 }
394 
395 inline std::string INIReader::Get(const std::string& section, const std::string& name, const std::string& default_value) const
396 {
397  std::string key = MakeKey(section, name);
398  return _values.count(key) ? _values.at(key) : default_value;
399 }
400 
401 inline long INIReader::GetInteger(const std::string& section, const std::string& name, long default_value) const
402 {
403  std::string valstr = Get(section, name, "");
404  const char* value = valstr.c_str();
405  char* end;
406  // This parses "1234" (decimal) and also "0x4D2" (hex)
407  long n = strtol(value, &end, 0);
408  return end > value ? n : default_value;
409 }
410 
411 inline double INIReader::GetReal(const std::string& section, const std::string& name, double default_value) const
412 {
413  std::string valstr = Get(section, name, "");
414  const char* value = valstr.c_str();
415  char* end;
416  double n = strtod(value, &end);
417  return end > value ? n : default_value;
418 }
419 
420 inline float INIReader::GetFloat(const std::string& section, const std::string& name, float default_value) const
421 {
422  std::string valstr = Get(section, name, "");
423  const char* value = valstr.c_str();
424  char* end;
425  float n = strtof(value, &end);
426  return end > value ? n : default_value;
427 }
428 
429 inline bool INIReader::GetBoolean(const std::string& section, const std::string& name, bool default_value) const
430 {
431  std::string valstr = Get(section, name, "");
432  // Convert to lower case to make string comparisons case-insensitive
433  std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
434  if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
435  return true;
436  else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
437  return false;
438  else
439  return default_value;
440 }
441 
442 inline std::string INIReader::MakeKey(const std::string& section, const std::string& name)
443 {
444  std::string key = section + "=" + name;
445  // Convert to lower case to make section/name lookups case-insensitive
446  std::transform(key.begin(), key.end(), key.begin(), ::tolower);
447  return key;
448 }
449 
450 inline int INIReader::ValueHandler(void* user, const char* section, const char* name,
451  const char* value)
452 {
453  INIReader* reader = (INIReader*)user;
454  std::string key = MakeKey(section, name);
455  if (reader->_values[key].size() > 0)
456  reader->_values[key] += "\n";
457  reader->_values[key] += value;
458  reader->_sections.insert(section);
459  return 1;
460 }
461 
462 #endif // __INIREADER__
Definition: INIReader.h:312