liblcf
inireader.cpp
Go to the documentation of this file.
1 // Read an INI file into easy-to-access name/value pairs.
2 
3 // inih and INIReader are released under the New BSD license:
4 //
5 // Copyright (c) 2009, Ben Hoyt
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 // * Neither the name of Ben Hoyt nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 // DISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY
23 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Go to the project home page for more info: https://github.com/benhoyt/inih
31 
32 #include <algorithm>
33 #include <cctype>
34 #include <cstdlib>
35 #include <cstring>
36 #include <istream>
37 #include <ini.h>
38 #include "inireader.h"
39 
40 using std::string;
41 
42 INIReader::INIReader(const string& filename)
43 {
44  _error = ini_parse(filename.c_str(), ValueHandler, this);
45 }
46 
47 INIReader::INIReader(std::istream& filestream)
48 {
49  _error = ini_parse_stream([](char* str, int num, void* stream) {
50  std::istream* is = reinterpret_cast<std::istream*>(stream);
51  if (num > 0) {
52  // via https://stackoverflow.com/questions/6089231/
53  std::string out;
54 
55  std::istream::sentry se(*is, true);
56  std::streambuf* sb = is->rdbuf();
57 
58  bool loop = true;
59 
60  do {
61  int c = sb->sbumpc();
62  switch (c) {
63  case '\n':
64  loop = false;
65  break;
66  case '\r':
67  if (sb->sgetc() == '\n') {
68  sb->sbumpc();
69  }
70  loop = false;
71  break;
72  case EOF:
73  // Also handle the case when the last line has no line ending
74  if (out.empty()) {
75  is->setstate(std::ios::eofbit);
76  }
77  loop = false;
78  break;
79  default:
80  out += (char)c;
81  }
82  } while (loop);
83 
84  if (out.empty() && (is->fail() || is->eof())) {
85  return (char*)nullptr;
86  }
87 
88  strncpy(str, out.c_str(), num);
89  str[num - 1] = '\0';
90 
91  return str;
92  }
93 
94  return (char*)nullptr;
95  }, &filestream, ValueHandler, this);
96 }
97 
99 {
100  return _error;
101 }
102 
103 string INIReader::Get(const string& section, const string& name, const string& default_value) const
104 {
105  string key = MakeKey(section, name);
106  // Use _values.find() here instead of _values.at() to support pre C++11 compilers
107  return _values.count(key) ? _values.find(key)->second : default_value;
108 }
109 
110 string INIReader::GetString(const string& section, const string& name, const string& default_value) const
111 {
112  const string str = Get(section, name, "");
113  return str.empty() ? default_value : str;
114 }
115 
116 long INIReader::GetInteger(const string& section, const string& name, long default_value) const
117 {
118  string valstr = Get(section, name, "");
119  const char* value = valstr.c_str();
120  char* end;
121  // This parses "1234" (decimal) and also "0x4D2" (hex)
122  long n = strtol(value, &end, 0);
123  return end > value ? n : default_value;
124 }
125 
126 double INIReader::GetReal(const string& section, const string& name, double default_value) const
127 {
128  string valstr = Get(section, name, "");
129  const char* value = valstr.c_str();
130  char* end;
131  double n = strtod(value, &end);
132  return end > value ? n : default_value;
133 }
134 
135 bool INIReader::GetBoolean(const string& section, const string& name, bool default_value) const
136 {
137  string valstr = Get(section, name, "");
138  // Convert to lower case to make string comparisons case-insensitive
139  std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
140  if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
141  return true;
142  else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
143  return false;
144  else
145  return default_value;
146 }
147 
148 bool INIReader::HasValue(const std::string& section, const std::string& name) const
149 {
150  string key = MakeKey(section, name);
151  return _values.count(key);
152 }
153 
154 string INIReader::MakeKey(const string& section, const string& name)
155 {
156  string key = section + "=" + name;
157  // Convert to lower case to make section/name lookups case-insensitive
158  std::transform(key.begin(), key.end(), key.begin(), ::tolower);
159  return key;
160 }
161 
162 int INIReader::ValueHandler(void* user, const char* section, const char* name,
163  const char* value)
164 {
165  INIReader* reader = static_cast<INIReader*>(user);
166  string key = MakeKey(section, name);
167  if (reader->_values[key].size() > 0)
168  reader->_values[key] += "\n";
169  reader->_values[key] += value;
170  return 1;
171 }
INIReader::GetBoolean
bool GetBoolean(const std::string &section, const std::string &name, bool default_value) const
Definition: inireader.cpp:135
ini_parse_stream
int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler, void *user)
Definition: ini.cpp:103
INIReader::ParseError
int ParseError() const
Definition: inireader.cpp:98
INIReader
Definition: inireader.h:41
INIReader::INIReader
INIReader(const std::string &filename)
Definition: inireader.cpp:42
INIReader::HasValue
bool HasValue(const std::string &section, const std::string &name) const
Definition: inireader.cpp:148
ini_parse
int ini_parse(const char *filename, ini_handler handler, void *user)
Definition: ini.cpp:245
INIReader::_error
int _error
Definition: inireader.h:83
ini.h
INIReader::ValueHandler
static int ValueHandler(void *user, const char *section, const char *name, const char *value)
Definition: inireader.cpp:162
INIReader::GetInteger
long GetInteger(const std::string &section, const std::string &name, long default_value) const
Definition: inireader.cpp:116
INIReader::MakeKey
static std::string MakeKey(const std::string &section, const std::string &name)
Definition: inireader.cpp:154
INIReader::GetString
std::string GetString(const std::string &section, const std::string &name, const std::string &default_value) const
Definition: inireader.cpp:110
inireader.h
INIReader::GetReal
double GetReal(const std::string &section, const std::string &name, double default_value) const
Definition: inireader.cpp:126
INIReader::_values
std::map< std::string, std::string > _values
Definition: inireader.h:84
INIReader::Get
std::string Get(const std::string &section, const std::string &name, const std::string &default_value) const
Definition: inireader.cpp:103