Update inih from
(Resolves a -Wstringop-truncation warning)
MODIFY
src/ini.cpp
src/ini.cpp
@@ -48,6 +48,12 @@ Go to the project home page for more info: https://github.com/benhoyt/inih
#define MAX_SECTION 50
#define MAX_NAME 50
+/* Used by ini_parse_string() to keep track of string parsing state. */
+typedef struct {
+ const char* ptr;
+ size_t num_left;
+} ini_parse_string_ctx;
+
/* Strip whitespace chars off end of given string, in place. Return s. */
static char* rstrip(char* s)
{
@@ -88,7 +94,7 @@ static char* find_chars_or_comment(const char* s, const char* chars)
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
- strncpy(dest, src, size);
+ strncpy(dest, src, size - 1);
dest[size - 1] = '\0';
return dest;
}
@@ -100,8 +106,14 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
+ int max_line = INI_MAX_LINE;
#else
char* line;
+ int max_line = INI_INITIAL_ALLOC;
+#endif
+#if INI_ALLOW_REALLOC && !INI_USE_STACK
+ char* new_line;
+ int offset;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
@@ -114,7 +126,7 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
int error = 0;
#if !INI_USE_STACK
- line = (char*)malloc(INI_MAX_LINE);
+ line = (char*)malloc(INI_INITIAL_ALLOC);
if (!line) {
return -2;
}
@@ -127,7 +139,27 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
#endif
/* Scan through stream line by line */
- while (reader(line, INI_MAX_LINE, stream) != NULL) {
+ while (reader(line, max_line, stream) != NULL) {
+#if INI_ALLOW_REALLOC && !INI_USE_STACK
+ offset = strlen(line);
+ while (offset == max_line - 1 && line[offset - 1] != '\n') {
+ max_line *= 2;
+ if (max_line > INI_MAX_LINE)
+ max_line = INI_MAX_LINE;
+ new_line = realloc(line, max_line);
+ if (!new_line) {
+ free(line);
+ return -2;
+ }
+ line = new_line;
+ if (reader(line + offset, max_line - offset, stream) == NULL)
+ break;
+ if (max_line >= INI_MAX_LINE)
+ break;
+ offset += strlen(line + offset);
+ }
+#endif
+
lineno++;
start = line;
@@ -140,9 +172,8 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
#endif
start = lskip(rstrip(start));
- if (*start == ';' || *start == '#') {
- /* Per Python configparser, allow both ; and # comments at the
- start of a line */
+ if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
+ /* Start-of-line comment */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
@@ -223,3 +254,40 @@ int ini_parse(const char* filename, ini_handler handler, void* user)
fclose(file);
return error;
}
+
+/* An ini_reader function to read the next line from a string buffer. This
+ is the fgets() equivalent used by ini_parse_string(). */
+static char* ini_reader_string(char* str, int num, void* stream) {
+ ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
+ const char* ctx_ptr = ctx->ptr;
+ size_t ctx_num_left = ctx->num_left;
+ char* strp = str;
+ char c;
+
+ if (ctx_num_left == 0 || num < 2)
+ return NULL;
+
+ while (num > 1 && ctx_num_left != 0) {
+ c = *ctx_ptr++;
+ ctx_num_left--;
+ *strp++ = c;
+ if (c == '\n')
+ break;
+ num--;
+ }
+
+ *strp = '\0';
+ ctx->ptr = ctx_ptr;
+ ctx->num_left = ctx_num_left;
+ return str;
+}
+
+/* See documentation in header file. */
+int ini_parse_string(const char* string, ini_handler handler, void* user) {
+ ini_parse_string_ctx ctx;
+
+ ctx.ptr = string;
+ ctx.num_left = strlen(string);
+ return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
+ user);
+}

MODIFY
src/ini.h
src/ini.h
@@ -49,7 +49,8 @@ extern "C" {
/* Typedef for prototype of handler function. */
#if INI_HANDLER_LINENO
typedef int (*ini_handler)(void* user, const char* section,
- const char* name, const char* value, int lineno);
+ const char* name, const char* value,
+ int lineno);
#else
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value);
@@ -78,10 +79,16 @@ int ini_parse(const char* filename, ini_handler handler, void* user);
int ini_parse_file(FILE* file, ini_handler handler, void* user);
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
- filename. Used for implementing custom or string-based I/O. */
+ filename. Used for implementing custom or string-based I/O (see also
+ ini_parse_string). */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user);
+/* Same as ini_parse(), but takes a zero-terminated string with the INI data
+ instead of a file. Useful for parsing INI data from a network socket or
+ already in memory. */
+int ini_parse_string(const char* string, ini_handler handler, void* user);
+
/* Nonzero to allow multi-line value parsing, in the style of Python's
configparser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
@@ -90,11 +97,17 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
#endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
- the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+ the file. See https://github.com/benhoyt/inih/issues/21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
+/* Chars that begin a start-of-line comment. Per Python configparser, allow
+ both ; and # comments at the start of a line by default. */
+#ifndef INI_START_COMMENT_PREFIXES
+#define INI_START_COMMENT_PREFIXES ";#"
+#endif
+
/* Nonzero to allow inline comments (with valid inline comment characters
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
Python 3.2+ configparser behaviour. */
@@ -105,21 +118,35 @@ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
#define INI_INLINE_COMMENT_PREFIXES ";"
#endif
-/* Nonzero to use stack, zero to use heap (malloc/free). */
+/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
+/* Maximum line length for any line in INI file (stack or heap). Note that
+ this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 200
+#endif
+
+/* Nonzero to allow heap line buffer to grow via realloc(), zero for a
+ fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is
+ zero. */
+#ifndef INI_ALLOW_REALLOC
+#define INI_ALLOW_REALLOC 0
+#endif
+
+/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK
+ is zero. */
+#ifndef INI_INITIAL_ALLOC
+#define INI_INITIAL_ALLOC 200
+#endif
+
/* Stop parsing on first error (default is to keep parsing). */
#ifndef INI_STOP_ON_FIRST_ERROR
#define INI_STOP_ON_FIRST_ERROR 0
#endif
-/* Maximum line length for any line in INI file. */
-#ifndef INI_MAX_LINE
-#define INI_MAX_LINE 200
-#endif
-
#ifdef __cplusplus
}
#endif

MODIFY
src/inireader.cpp
src/inireader.cpp
@@ -107,6 +107,12 @@ string INIReader::Get(const string& section, const string& name, const string& d
return _values.count(key) ? _values.find(key)->second : default_value;
}
+string INIReader::GetString(const string& section, const string& name, const string& default_value) const
+{
+ const string str = Get(section, name, "");
+ return str.empty() ? default_value : str;
+}
+
long INIReader::GetInteger(const string& section, const string& name, long default_value) const
{
string valstr = Get(section, name, "");
@@ -139,6 +145,12 @@ bool INIReader::GetBoolean(const string& section, const string& name, bool defau
return default_value;
}
+bool INIReader::HasValue(const std::string& section, const std::string& name) const
+{
+ string key = MakeKey(section, name);
+ return _values.count(key);
+}
+
string INIReader::MakeKey(const string& section, const string& name)
{
string key = section + "=" + name;
@@ -150,7 +162,7 @@ string INIReader::MakeKey(const string& section, const string& name)
int INIReader::ValueHandler(void* user, const char* section, const char* name,
const char* value)
{
- INIReader* reader = (INIReader*)user;
+ INIReader* reader = static_cast<INIReader*>(user);
string key = MakeKey(section, name);
if (reader->_values[key].size() > 0)
reader->_values[key] += "\n";

MODIFY
src/inireader.h
src/inireader.h
@@ -42,7 +42,7 @@ class INIReader
public:
// Construct INIReader and parse given filename. See ini.h for more info
// about the parsing.
- INIReader(const std::string& filename);
+ explicit INIReader(const std::string& filename);
// Construct INIReader and parse given stream. See ini.h for more info
// about the parsing.
@@ -57,6 +57,11 @@ public:
std::string Get(const std::string& section, const std::string& name,
const std::string& default_value) const;
+ // Get a string value from INI file, returning default_value if not found,
+ // empty, or contains only whitespace.
+ std::string GetString(const std::string& section, const std::string& name,
+ const std::string& default_value) const;
+
// Get an integer (long) value from INI file, returning default_value if
// not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
long GetInteger(const std::string& section, const std::string& name, long default_value) const;
@@ -71,6 +76,9 @@ public:
// and valid false values are "false", "no", "off", "0" (not case sensitive).
bool GetBoolean(const std::string& section, const std::string& name, bool default_value) const;
+ // Return true if a value exists with the given section and field names.
+ bool HasValue(const std::string& section, const std::string& name) const;
+
private:
int _error;
std::map<std::string, std::string> _values;

Update inih from https://github.com/benhoyt/inih
(Resolves a -Wstringop-truncation warning)