pax_global_header00006660000000000000000000000064136266533000014516gustar00rootroot0000000000000052 comment=351217124ddb3e3fe2b982248a04c672350bb0af inih-r48/000077500000000000000000000000001362665330000124245ustar00rootroot00000000000000inih-r48/.travis.yml000066400000000000000000000004571362665330000145430ustar00rootroot00000000000000language: c # Setting sudo access to false will let Travis CI use containers # rather than VMs to run the tests. For more details see: # https://docs.travis-ci.com/user/reference/overview/ sudo: false script: - cd tests - ./unittest.sh - cd ../examples - ./cpptest.sh - git diff --exit-code inih-r48/LICENSE.txt000066400000000000000000000027461362665330000142600ustar00rootroot00000000000000 The "inih" library is distributed under the New BSD license: Copyright (c) 2009, Ben Hoyt All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Ben Hoyt nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. inih-r48/README.md000066400000000000000000000166141362665330000137130ustar00rootroot00000000000000# inih (INI Not Invented Here) [![TravisCI Build](https://travis-ci.org/benhoyt/inih.svg)](https://travis-ci.org/benhoyt/inih) **inih (INI Not Invented Here)** is a simple [.INI file](http://en.wikipedia.org/wiki/INI_file) parser written in C. It's only a couple of pages of code, and it was designed to be _small and simple_, so it's good for embedded systems. It's also more or less compatible with Python's [ConfigParser](http://docs.python.org/library/configparser.html) style of .INI files, including RFC 822-style multi-line syntax and `name: value` entries. To use it, just give `ini_parse()` an INI file, and it will call a callback for every `name=value` pair parsed, giving you strings for the section, name, and value. It's done this way ("SAX style") because it works well on low-memory embedded systems, but also because it makes for a KISS implementation. You can also call `ini_parse_file()` to parse directly from a `FILE*` object, `ini_parse_string()` to parse data from a string, or `ini_parse_stream()` to parse using a custom fgets-style reader function for custom I/O. Download a release, browse the source, or read about [how to use inih in a DRY style](http://blog.brush.co.nz/2009/08/xmacros/) with X-Macros. ## Compile-time options ## You can control various aspects of inih using preprocessor defines: ### Syntax options ### * **Multi-line entries:** By default, inih supports multi-line entries in the style of Python's ConfigParser. To disable, add `-DINI_ALLOW_MULTILINE=0`. * **UTF-8 BOM:** By default, inih allows a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of INI files. To disable, add `-DINI_ALLOW_BOM=0`. * **Inline comments:** By default, inih allows inline comments with the `;` character. To disable, add `-DINI_ALLOW_INLINE_COMMENTS=0`. You can also specify which character(s) start an inline comment using `INI_INLINE_COMMENT_PREFIXES`. * **Start-of-line comments:** By default, inih allows both `;` and `#` to start a comment at the beginning of a line. You can override this by changing `INI_START_COMMENT_PREFIXES`. * **Allow no value:** By default, inih treats a name with no value (no `=` or `:` on the line) as an error. To allow names with no values, add `-DINI_ALLOW_NO_VALUE=1`, and inih will call your handler function with value set to NULL. ### Parsing options ### * **Stop on first error:** By default, inih keeps parsing the rest of the file after an error. To stop parsing on the first error, add `-DINI_STOP_ON_FIRST_ERROR=1`. * **Report line numbers:** By default, the `ini_handler` callback doesn't receive the line number as a parameter. If you need that, add `-DINI_HANDLER_LINENO=1`. * **Call handler on new section:** By default, inih only calls the handler on each `name=value` pair. To detect new sections (e.g., the INI file has multiple sections with the same name), add `-DINI_CALL_HANDLER_ON_NEW_SECTION=1`. Your handler function will then be called each time a new section is encountered, with `section` set to the new section name but `name` and `value` set to NULL. ### Memory options ### * **Stack vs heap:** By default, inih creates a fixed-sized line buffer on the stack. To allocate on the heap using `malloc` instead, specify `-DINI_USE_STACK=0`. * **Maximum line length:** The default maximum line length (for stack or heap) is 200 bytes. To override this, add something like `-DINI_MAX_LINE=1000`. Note that `INI_MAX_LINE` must be 3 more than the longest line (due to `\r`, `\n`, and the NUL). * **Allow realloc:** By default when using the heap (`-DINI_USE_STACK=0`), inih allocates a fixed-sized buffer of `INI_INITIAL_ALLOC` bytes. To allow this to grow to `INI_MAX_LINE` bytes, doubling if needed, set `-DINI_ALLOW_REALLOC=1`. * **Initial malloc size:** `INI_INITIAL_ALLOC` specifies the initial malloc size when using the heap. It defaults to 200 bytes. ## Simple example in C ## ```c #include #include #include #include "../ini.h" typedef struct { int version; const char* name; const char* email; } configuration; static int handler(void* user, const char* section, const char* name, const char* value) { configuration* pconfig = (configuration*)user; #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 if (MATCH("protocol", "version")) { pconfig->version = atoi(value); } else if (MATCH("user", "name")) { pconfig->name = strdup(value); } else if (MATCH("user", "email")) { pconfig->email = strdup(value); } else { return 0; /* unknown section/name, error */ } return 1; } int main(int argc, char* argv[]) { configuration config; if (ini_parse("test.ini", handler, &config) < 0) { printf("Can't load 'test.ini'\n"); return 1; } printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n", config.version, config.name, config.email); return 0; } ``` ## C++ example ## If you're into C++ and the STL, there is also an easy-to-use [INIReader class](https://github.com/benhoyt/inih/blob/master/cpp/INIReader.h) that stores values in a `map` and lets you `Get()` them: ```cpp #include #include "INIReader.h" int main() { INIReader reader("../examples/test.ini"); if (reader.ParseError() < 0) { std::cout << "Can't load 'test.ini'\n"; return 1; } std::cout << "Config loaded from 'test.ini': version=" << reader.GetInteger("protocol", "version", -1) << ", name=" << reader.Get("user", "name", "UNKNOWN") << ", email=" << reader.Get("user", "email", "UNKNOWN") << ", pi=" << reader.GetReal("user", "pi", -1) << ", active=" << reader.GetBoolean("user", "active", true) << "\n"; return 0; } ``` This simple C++ API works fine, but it's not very fully-fledged. I'm not planning to work more on the C++ API at the moment, so if you want a bit more power (for example `GetSections()` and `GetFields()` functions), see these forks: * https://github.com/Blandinium/inih * https://github.com/OSSystems/inih ## Differences from ConfigParser ## Some differences between inih and Python's [ConfigParser](http://docs.python.org/library/configparser.html) standard library module: * INI name=value pairs given above any section headers are treated as valid items with no section (section name is an empty string). In ConfigParser having no section is an error. * Line continuations are handled with leading whitespace on continued lines (like ConfigParser). However, instead of concatenating continued lines together, they are treated as separate values for the same key (unlike ConfigParser). ## Platform-specific notes ## * Windows/Win32 uses UTF-16 filenames natively, so to handle Unicode paths you need to call `_wfopen()` to open a file and then `ini_parse_file()` to parse it; inih does not include `wchar_t` or Unicode handling. ## Meson notes ## * The `meson.build` file is intended to build libraries which can be installed on a system. This is not required to use or compile inih. * If you want to use inih for programs which may be shipped in a distro, consider linking against the shared library. Meson adds entries for pkg-config (`inih` and `INIReader`). * In case you use inih as a subproject, you can use the `inih_dep` and `INIReader_dep` dependency variables. ## Related links ## * [Conan package for inih](https://github.com/mohamedghita/conan-inih) (Conan is a C/C++ package manager) inih-r48/cpp/000077500000000000000000000000001362665330000132065ustar00rootroot00000000000000inih-r48/cpp/INIReader.cpp000066400000000000000000000071401362665330000154560ustar00rootroot00000000000000// Read an INI file into easy-to-access name/value pairs. // SPDX-License-Identifier: BSD-3-Clause // Copyright (C) 2009-2020, Ben Hoyt // inih and INIReader are released under the New BSD license (see LICENSE.txt). // Go to the project home page for more info: // // https://github.com/benhoyt/inih #include #include #include #include "../ini.h" #include "INIReader.h" using std::string; INIReader::INIReader(const string& filename) { _error = ini_parse(filename.c_str(), ValueHandler, this); } INIReader::INIReader(const char *buffer, size_t buffer_size) { string content(buffer, buffer_size); _error = ini_parse_string(content.c_str(), ValueHandler, this); } int INIReader::ParseError() const { return _error; } string INIReader::Get(const string& section, const string& name, const string& default_value) const { string key = MakeKey(section, name); // Use _values.find() here instead of _values.at() to support pre C++11 compilers 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, ""); const char* value = valstr.c_str(); char* end; // This parses "1234" (decimal) and also "0x4D2" (hex) long n = strtol(value, &end, 0); return end > value ? n : default_value; } double INIReader::GetReal(const string& section, const string& name, double default_value) const { string valstr = Get(section, name, ""); const char* value = valstr.c_str(); char* end; double n = strtod(value, &end); return end > value ? n : default_value; } bool INIReader::GetBoolean(const string& section, const string& name, bool default_value) const { string valstr = Get(section, name, ""); // Convert to lower case to make string comparisons case-insensitive std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") return true; else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") return false; else return default_value; } bool INIReader::HasSection(const string& section) const { const string key = MakeKey(section, ""); std::map::const_iterator pos = _values.lower_bound(key); if (pos == _values.end()) return false; // Does the key at the lower_bound pos start with "section"? return pos->first.compare(0, key.length(), key) == 0; } bool INIReader::HasValue(const string& section, const 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; // Convert to lower case to make section/name lookups case-insensitive std::transform(key.begin(), key.end(), key.begin(), ::tolower); return key; } int INIReader::ValueHandler(void* user, const char* section, const char* name, const char* value) { if (!name) // Happens when INI_CALL_HANDLER_ON_NEW_SECTION enabled return 1; INIReader* reader = static_cast(user); string key = MakeKey(section, name); if (reader->_values[key].size() > 0) reader->_values[key] += "\n"; reader->_values[key] += value ? value : ""; return 1; } inih-r48/cpp/INIReader.h000066400000000000000000000057611362665330000151320ustar00rootroot00000000000000// Read an INI file into easy-to-access name/value pairs. // SPDX-License-Identifier: BSD-3-Clause // Copyright (C) 2009-2020, Ben Hoyt // inih and INIReader are released under the New BSD license (see LICENSE.txt). // Go to the project home page for more info: // // https://github.com/benhoyt/inih #ifndef __INIREADER_H__ #define __INIREADER_H__ #include #include // Read an INI file into easy-to-access name/value pairs. (Note that I've gone // for simplicity here rather than speed, but it should be pretty decent.) class INIReader { public: // Construct INIReader and parse given filename. See ini.h for more info // about the parsing. explicit INIReader(const std::string& filename); // Construct INIReader and parse given buffer. See ini.h for more info // about the parsing. explicit INIReader(const char *buffer, size_t buffer_size); // Return the result of ini_parse(), i.e., 0 on success, line number of // first error on parse error, or -1 on file open error. int ParseError() const; // Get a string value from INI file, returning default_value if not found. 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; // Get a real (floating point double) value from INI file, returning // default_value if not found or not a valid floating point value // according to strtod(). double GetReal(const std::string& section, const std::string& name, double default_value) const; // Get a boolean value from INI file, returning default_value if not found or if // not a valid true/false value. Valid true values are "true", "yes", "on", "1", // 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 the given section exists (section must contain at least // one name=value pair). bool HasSection(const std::string& section) 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 _values; static std::string MakeKey(const std::string& section, const std::string& name); static int ValueHandler(void* user, const char* section, const char* name, const char* value); }; #endif // __INIREADER_H__ inih-r48/examples/000077500000000000000000000000001362665330000142425ustar00rootroot00000000000000inih-r48/examples/INIReaderExample.cpp000066400000000000000000000017261362665330000200320ustar00rootroot00000000000000// Example that shows simple usage of the INIReader class #include #include "../cpp/INIReader.h" int main() { INIReader reader("../examples/test.ini"); if (reader.ParseError() < 0) { std::cout << "Can't load 'test.ini'\n"; return 1; } std::cout << "Config loaded from 'test.ini': version=" << reader.GetInteger("protocol", "version", -1) << ", name=" << reader.Get("user", "name", "UNKNOWN") << ", email=" << reader.Get("user", "email", "UNKNOWN") << ", pi=" << reader.GetReal("user", "pi", -1) << ", active=" << reader.GetBoolean("user", "active", true) << "\n"; std::cout << "Has values: user.name=" << reader.HasValue("user", "name") << ", user.nose=" << reader.HasValue("user", "nose") << "\n"; std::cout << "Has sections: user=" << reader.HasSection("user") << ", fizz=" << reader.HasSection("fizz") << "\n"; return 0; } inih-r48/examples/config.def000066400000000000000000000002201362665330000161610ustar00rootroot00000000000000// CFG(section, name, default) CFG(protocol, version, "0") CFG(user, name, "Fatty Lumpkin") CFG(user, email, "fatty@lumpkin.com") #undef CFG inih-r48/examples/cpptest.sh000077500000000000000000000002251362665330000162620ustar00rootroot00000000000000#!/usr/bin/env bash g++ INIReaderExample.cpp ../cpp/INIReader.cpp ../ini.c -o INIReaderExample ./INIReaderExample > cpptest.txt rm INIReaderExample inih-r48/examples/cpptest.txt000066400000000000000000000002461362665330000164670ustar00rootroot00000000000000Config loaded from 'test.ini': version=6, name=Bob Smith, email=bob@smith.com, pi=3.14159, active=1 Has values: user.name=1, user.nose=0 Has sections: user=1, fizz=0 inih-r48/examples/ini_dump.c000066400000000000000000000017241362665330000162160ustar00rootroot00000000000000/* ini.h example that simply dumps an INI file without comments */ #include #include #include "../ini.h" static int dumper(void* user, const char* section, const char* name, const char* value) { static char prev_section[50] = ""; if (strcmp(section, prev_section)) { printf("%s[%s]\n", (prev_section[0] ? "\n" : ""), section); strncpy(prev_section, section, sizeof(prev_section)); prev_section[sizeof(prev_section) - 1] = '\0'; } printf("%s = %s\n", name, value); return 1; } int main(int argc, char* argv[]) { int error; if (argc <= 1) { printf("Usage: ini_dump filename.ini\n"); return 1; } error = ini_parse(argv[1], dumper, NULL); if (error < 0) { printf("Can't read '%s'!\n", argv[1]); return 2; } else if (error) { printf("Bad config file (first error on line %d)!\n", error); return 3; } return 0; } inih-r48/examples/ini_example.c000066400000000000000000000022361362665330000167030ustar00rootroot00000000000000/* Example: parse a simple configuration file */ #include #include #include #include "../ini.h" typedef struct { int version; const char* name; const char* email; } configuration; static int handler(void* user, const char* section, const char* name, const char* value) { configuration* pconfig = (configuration*)user; #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 if (MATCH("protocol", "version")) { pconfig->version = atoi(value); } else if (MATCH("user", "name")) { pconfig->name = strdup(value); } else if (MATCH("user", "email")) { pconfig->email = strdup(value); } else { return 0; /* unknown section/name, error */ } return 1; } int main(int argc, char* argv[]) { configuration config; if (ini_parse("test.ini", handler, &config) < 0) { printf("Can't load 'test.ini'\n"); return 1; } printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n", config.version, config.name, config.email); free((void*)config.name); free((void*)config.email); return 0; } inih-r48/examples/ini_xmacros.c000066400000000000000000000022251362665330000167220ustar00rootroot00000000000000/* Parse a configuration file into a struct using X-Macros */ #include #include #include "../ini.h" /* define the config struct type */ typedef struct { #define CFG(s, n, default) char *s##_##n; #include "config.def" } config; /* create one and fill in its default values */ config Config = { #define CFG(s, n, default) default, #include "config.def" }; /* process a line of the INI file, storing valid values into config struct */ int handler(void *user, const char *section, const char *name, const char *value) { config *cfg = (config *)user; if (0) ; #define CFG(s, n, default) else if (strcmp(section, #s)==0 && \ strcmp(name, #n)==0) cfg->s##_##n = strdup(value); #include "config.def" return 1; } /* print all the variables in the config, one per line */ void dump_config(config *cfg) { #define CFG(s, n, default) printf("%s_%s = %s\n", #s, #n, cfg->s##_##n); #include "config.def" } int main(int argc, char* argv[]) { if (ini_parse("test.ini", handler, &Config) < 0) printf("Can't load 'test.ini', using defaults\n"); dump_config(&Config); return 0; } inih-r48/examples/test.ini000066400000000000000000000005421362665330000157230ustar00rootroot00000000000000; Test config file for ini_example.c and INIReaderTest.cpp [protocol] ; Protocol configuration version=6 ; IPv6 [user] name = Bob Smith ; Spaces around '=' are stripped email = bob@smith.com ; And comments (like this) ignored active = true ; Test a boolean pi = 3.14159 ; Test a floating point number inih-r48/ini.c000066400000000000000000000170551362665330000133570ustar00rootroot00000000000000/* inih -- simple .INI file parser SPDX-License-Identifier: BSD-3-Clause Copyright (C) 2009-2020, Ben Hoyt inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: https://github.com/benhoyt/inih */ #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include "ini.h" #if !INI_USE_STACK #include #endif #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) { char* p = s + strlen(s); while (p > s && isspace((unsigned char)(*--p))) *p = '\0'; return s; } /* Return pointer to first non-whitespace char in given string. */ static char* lskip(const char* s) { while (*s && isspace((unsigned char)(*s))) s++; return (char*)s; } /* Return pointer to first char (of chars) or inline comment in given string, or pointer to null at end of string if neither found. Inline comment must be prefixed by a whitespace character to register as a comment. */ static char* find_chars_or_comment(const char* s, const char* chars) { #if INI_ALLOW_INLINE_COMMENTS int was_space = 0; while (*s && (!chars || !strchr(chars, *s)) && !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { was_space = isspace((unsigned char)(*s)); s++; } #else while (*s && (!chars || !strchr(chars, *s))) { s++; } #endif return (char*)s; } /* 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 - 1); dest[size - 1] = '\0'; return dest; } /* See documentation in header file. */ int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, void* user) { /* 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; size_t max_line = INI_INITIAL_ALLOC; #endif #if INI_ALLOW_REALLOC && !INI_USE_STACK char* new_line; size_t offset; #endif char section[MAX_SECTION] = ""; char prev_name[MAX_NAME] = ""; char* start; char* end; char* name; char* value; int lineno = 0; int error = 0; #if !INI_USE_STACK line = (char*)malloc(INI_INITIAL_ALLOC); if (!line) { return -2; } #endif #if INI_HANDLER_LINENO #define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) #else #define HANDLER(u, s, n, v) handler(u, s, n, v) #endif /* Scan through stream line by line */ while (reader(line, (int)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, (int)(max_line - offset), stream) == NULL) break; if (max_line >= INI_MAX_LINE) break; offset += strlen(line + offset); } #endif lineno++; start = line; #if INI_ALLOW_BOM if (lineno == 1 && (unsigned char)start[0] == 0xEF && (unsigned char)start[1] == 0xBB && (unsigned char)start[2] == 0xBF) { start += 3; } #endif start = lskip(rstrip(start)); if (strchr(INI_START_COMMENT_PREFIXES, *start)) { /* Start-of-line comment */ } #if INI_ALLOW_MULTILINE else if (*prev_name && *start && start > line) { /* Non-blank line with leading whitespace, treat as continuation of previous name's value (as per Python configparser). */ if (!HANDLER(user, section, prev_name, start) && !error) error = lineno; } #endif else if (*start == '[') { /* A "[section]" line */ end = find_chars_or_comment(start + 1, "]"); if (*end == ']') { *end = '\0'; strncpy0(section, start + 1, sizeof(section)); *prev_name = '\0'; #if INI_CALL_HANDLER_ON_NEW_SECTION if (!HANDLER(user, section, NULL, NULL) && !error) error = lineno; #endif } else if (!error) { /* No ']' found on section line */ error = lineno; } } else if (*start) { /* Not a comment, must be a name[=:]value pair */ end = find_chars_or_comment(start, "=:"); if (*end == '=' || *end == ':') { *end = '\0'; name = rstrip(start); value = end + 1; #if INI_ALLOW_INLINE_COMMENTS end = find_chars_or_comment(value, NULL); if (*end) *end = '\0'; #endif value = lskip(value); rstrip(value); /* Valid name[=:]value pair found, call handler */ strncpy0(prev_name, name, sizeof(prev_name)); if (!HANDLER(user, section, name, value) && !error) error = lineno; } else if (!error) { /* No '=' or ':' found on name[=:]value line */ #if INI_ALLOW_NO_VALUE *end = '\0'; name = rstrip(start); if (!HANDLER(user, section, name, NULL) && !error) error = lineno; #else error = lineno; #endif } } #if INI_STOP_ON_FIRST_ERROR if (error) break; #endif } #if !INI_USE_STACK free(line); #endif return error; } /* See documentation in header file. */ int ini_parse_file(FILE* file, ini_handler handler, void* user) { return ini_parse_stream((ini_reader)fgets, file, handler, user); } /* See documentation in header file. */ int ini_parse(const char* filename, ini_handler handler, void* user) { FILE* file; int error; file = fopen(filename, "r"); if (!file) return -1; error = ini_parse_file(file, handler, 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); } inih-r48/ini.h000066400000000000000000000116051362665330000133570ustar00rootroot00000000000000/* inih -- simple .INI file parser SPDX-License-Identifier: BSD-3-Clause Copyright (C) 2009-2020, Ben Hoyt inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: https://github.com/benhoyt/inih */ #ifndef __INI_H__ #define __INI_H__ /* Make this header file easier to include in C++ code */ #ifdef __cplusplus extern "C" { #endif #include /* Nonzero if ini_handler callback should accept lineno parameter. */ #ifndef INI_HANDLER_LINENO #define INI_HANDLER_LINENO 0 #endif /* 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); #else typedef int (*ini_handler)(void* user, const char* section, const char* name, const char* value); #endif /* Typedef for prototype of fgets-style reader function. */ typedef char* (*ini_reader)(char* str, int num, void* stream); /* Parse given INI-style file. May have [section]s, name=value pairs (whitespace stripped), and comments starting with ';' (semicolon). Section is "" if name=value pair parsed before any section heading. name:value pairs are also supported as a concession to Python's configparser. For each name=value pair parsed, call handler function with given user pointer as well as section, name, and value (data only valid for duration of handler call). Handler should return nonzero on success, zero on error. Returns 0 on success, line number of first error on parse error (doesn't stop on first error), -1 on file open error, or -2 on memory allocation error (only when INI_USE_STACK is zero). */ int ini_parse(const char* filename, ini_handler handler, void* user); /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't close the file when it's finished -- the caller must do that. */ 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 (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. */ #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 1 #endif /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of 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. */ #ifndef INI_ALLOW_INLINE_COMMENTS #define INI_ALLOW_INLINE_COMMENTS 1 #endif #ifndef INI_INLINE_COMMENT_PREFIXES #define INI_INLINE_COMMENT_PREFIXES ";" #endif /* 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 /* Nonzero to call the handler at the start of each new section (with name and value NULL). Default is to only call the handler on each name=value pair. */ #ifndef INI_CALL_HANDLER_ON_NEW_SECTION #define INI_CALL_HANDLER_ON_NEW_SECTION 0 #endif /* Nonzero to allow a name without a value (no '=' or ':' on the line) and call the handler with value NULL in this case. Default is to treat no-value lines as an error. */ #ifndef INI_ALLOW_NO_VALUE #define INI_ALLOW_NO_VALUE 0 #endif #ifdef __cplusplus } #endif #endif /* __INI_H__ */ inih-r48/meson.build000066400000000000000000000023041362665330000145650ustar00rootroot00000000000000project('inih', ['c','cpp'], meson_version : '>= 0.46.0', default_options : ['default_library=both'], license : 'BSD-3-Clause', version : '48' ) pkg = import('pkgconfig') #### inih #### install_headers('ini.h') inc_inih = include_directories('.') lib_inih = library('inih', ['ini.c'], include_directories : inc_inih, install : true, version : meson.project_version(), soversion : '0' ) pkg.generate(lib_inih, name : 'inih', description : 'simple .INI file parser', version : meson.project_version() ) inih_dep = declare_dependency( link_with : lib_inih, include_directories : inc_inih ) #### INIReader #### install_headers('cpp/INIReader.h') inc_INIReader = include_directories('cpp') lib_INIReader = library('INIReader', ['cpp/INIReader.cpp'], include_directories : inc_INIReader, dependencies : inih_dep, install : true, version : meson.project_version(), soversion : '0' ) pkg.generate(lib_INIReader, name : 'INIReader', description : 'simple .INI file parser for C++', version : meson.project_version() ) INIReader_dep = declare_dependency( link_with : lib_inih, include_directories : inc_INIReader ) inih-r48/tests/000077500000000000000000000000001362665330000135665ustar00rootroot00000000000000inih-r48/tests/bad_comment.ini000066400000000000000000000000211362665330000165300ustar00rootroot00000000000000This is an error inih-r48/tests/bad_multi.ini000066400000000000000000000000131362665330000162210ustar00rootroot00000000000000 indented inih-r48/tests/bad_section.ini000066400000000000000000000001071362665330000165370ustar00rootroot00000000000000[section1] name1=value1 [section2 [section3 ; comment ] name2=value2 inih-r48/tests/baseline_allow_no_value.txt000066400000000000000000000025651362665330000212070ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 ... This is an error; bad_comment.ini: e=0 user=103 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; multi_line.ini: e=0 user=105 ... indented; bad_multi.ini: e=0 user=106 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section_list] ... section0; ... section1; ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=0 user=109 inih-r48/tests/baseline_call_handler_on_new_section.txt000066400000000000000000000025201362665330000236710ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [empty] ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... [section1] ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section_list] ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_disallow_inline_comments.txt000066400000000000000000000027731362665330000232630ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test ; name=value comment; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3 ; only this will be a comment; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345 ; key should be "test;3"; ... test4=4#5#6 ; '#' only starts a comment at start of line; ... test7=; blank value, except if inline comments disabled; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... [section3 ; comment ] ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith ; comment line 1; multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_handler_lineno.txt000066400000000000000000000031731362665330000211560ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; line 3 ... two=1234; line 4 ... [ section 2 ] ... happy=4; line 8 ... sad=; line 9 ... [comment_test] ... test1=1;2;3; line 15 ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; line 16 ... test;3=345; line 17 ... test4=4#5#6; line 18 ... test7=; line 21 ... test8=; not a comment, needs whitespace before ';'; line 22 ... [colon_tests] ... Content-Type=text/html; line 25 ... foo=bar; line 26 ... adams=42; line 27 ... funny1=with = equals; line 28 ... funny2=with : colons; line 29 ... funny3=two = equals; line 30 ... funny4=two : colons; line 31 normal.ini: e=0 user=101 ... [section1] ... name1=value1; line 2 ... name2=value2; line 5 bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; line 2 ... user=parse_error; line 3 ... c=d; line 4 user_error.ini: e=3 user=104 ... [section1] ... single1=abc; line 2 ... multi=this is a; line 3 ... multi=multi-line value; line 4 ... single2=xyz; line 5 ... [section2] ... multi=a; line 7 ... multi=b; line 8 ... multi=c; line 9 ... [section3] ... single=ghi; line 11 ... multi=the quick; line 12 ... multi=brown fox; line 13 ... name=bob smith; line 14 multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; line 2 ... key“=value“; line 3 bom.ini: e=0 user=107 ... [section1] ... single1=abc; line 2 ... single2=xyz; line 3 ... single1=def; line 5 ... single2=qrs; line 6 duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; line 6 ... [section1] ... key1=val1; line 9 no_value.ini: e=2 user=109 inih-r48/tests/baseline_heap.txt000066400000000000000000000024421362665330000171100ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_heap_max_line.txt000066400000000000000000000024541362665330000207670ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this; ... test2=needs whitespace b; ... test;3=345; ... test4=4#5#6; ... test4=only starts a comm; ... test7=; ... test8=; not a comm; ... [colon_tests] ... Content-Type=text/; ... foo=bar; ... adams=42; ... funny1=with = equ; ... funny2=with : col; ... funny3=two = equa; ... funny4=two : colo; normal.ini: e=2 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; ... name=comment line 1; ... name=comment line 2; multi_line.ini: e=5 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_heap_realloc.txt000066400000000000000000000024421362665330000206110ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_heap_realloc_max_line.txt000066400000000000000000000024541362665330000224700ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this; ... test2=needs whitespace b; ... test;3=345; ... test4=4#5#6; ... test4=only starts a comm; ... test7=; ... test8=; not a comm; ... [colon_tests] ... Content-Type=text/; ... foo=bar; ... adams=42; ... funny1=with = equ; ... funny2=with : col; ... funny3=two = equa; ... funny4=two : colo; normal.ini: e=2 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; ... name=comment line 1; ... name=comment line 2; multi_line.ini: e=5 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_heap_string.txt000066400000000000000000000005411362665330000204740ustar00rootroot00000000000000empty string: e=0 user=0 ... [section] ... foo=bar; ... bazz=buzz quxx; basic: e=0 user=101 ... [section] ... hello=world; ... forty_two=42; crlf: e=0 user=102 ... [sec] ... foo=0123456789012; ... bar=4321; long line: e=3 user=103 ... [sec] ... foo=0123456789012; ... bix=1234; long continued: e=0 user=104 ... [s] ... a=1; ... c=3; error: e=3 user=105 inih-r48/tests/baseline_multi.txt000066400000000000000000000024421362665330000173250ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_multi_max_line.txt000066400000000000000000000024541362665330000212040ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this; ... test2=needs whitespace b; ... test;3=345; ... test4=4#5#6; ... test4=only starts a comm; ... test7=; ... test8=; not a comm; ... [colon_tests] ... Content-Type=text/; ... foo=bar; ... adams=42; ... funny1=with = equ; ... funny2=with : col; ... funny3=two = equa; ... funny4=two : colo; normal.ini: e=2 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; ... name=comment line 1; ... name=comment line 2; multi_line.ini: e=5 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_single.txt000066400000000000000000000023271362665330000174560ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; ... name2=value2; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; ... c=d; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... single2=xyz; ... [section2] ... multi=a; ... [section3] ... single=ghi; ... multi=the quick; ... name=bob smith; multi_line.ini: e=4 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 ... [section0] ... key0=val0; ... [section1] ... key1=val1; no_value.ini: e=2 user=109 inih-r48/tests/baseline_stop_on_first_error.txt000066400000000000000000000023131362665330000222710ustar00rootroot00000000000000no_file.ini: e=-1 user=0 ... [section1] ... one=This is a test; ... two=1234; ... [ section 2 ] ... happy=4; ... sad=; ... [comment_test] ... test1=1;2;3; ... test2=2;3;4;this won't be a comment, needs whitespace before ';'; ... test;3=345; ... test4=4#5#6; ... test7=; ... test8=; not a comment, needs whitespace before ';'; ... [colon_tests] ... Content-Type=text/html; ... foo=bar; ... adams=42; ... funny1=with = equals; ... funny2=with : colons; ... funny3=two = equals; ... funny4=two : colons; normal.ini: e=0 user=101 ... [section1] ... name1=value1; bad_section.ini: e=3 user=102 bad_comment.ini: e=1 user=102 ... [section] ... a=b; ... user=parse_error; user_error.ini: e=3 user=104 ... [section1] ... single1=abc; ... multi=this is a; ... multi=multi-line value; ... single2=xyz; ... [section2] ... multi=a; ... multi=b; ... multi=c; ... [section3] ... single=ghi; ... multi=the quick; ... multi=brown fox; ... name=bob smith; multi_line.ini: e=0 user=105 bad_multi.ini: e=1 user=105 ... [bom_section] ... bom_name=bom_value; ... key“=value“; bom.ini: e=0 user=107 ... [section1] ... single1=abc; ... single2=xyz; ... single1=def; ... single2=qrs; duplicate_sections.ini: e=0 user=108 no_value.ini: e=2 user=108 inih-r48/tests/baseline_string.txt000066400000000000000000000005411362665330000174770ustar00rootroot00000000000000empty string: e=0 user=0 ... [section] ... foo=bar; ... bazz=buzz quxx; basic: e=0 user=101 ... [section] ... hello=world; ... forty_two=42; crlf: e=0 user=102 ... [sec] ... foo=0123456789012; ... bar=4321; long line: e=3 user=103 ... [sec] ... foo=0123456789012; ... bix=1234; long continued: e=0 user=104 ... [s] ... a=1; ... c=3; error: e=3 user=105 inih-r48/tests/bom.ini000066400000000000000000000000661362665330000150460ustar00rootroot00000000000000[bom_section] bom_name=bom_value key“ = value“ inih-r48/tests/duplicate_sections.ini000066400000000000000000000001151362665330000201450ustar00rootroot00000000000000[section1] single1 = abc single2 = xyz [section1] single1 = def single2 = qrsinih-r48/tests/multi_line.ini000066400000000000000000000003721362665330000164320ustar00rootroot00000000000000[section1] single1 = abc multi = this is a multi-line value single2 = xyz [section2] multi = a b c [section3] single: ghi multi: the quick brown fox name = bob smith ; comment line 1 ; comment line 2 inih-r48/tests/no_value.ini000066400000000000000000000001261362665330000160760ustar00rootroot00000000000000[section_list] section0 section1 [section0] key0=val0 [section1] key1=val1 inih-r48/tests/normal.ini000066400000000000000000000013551362665330000155630ustar00rootroot00000000000000; This is an INI file [section1] ; section comment one=This is a test ; name=value comment two = 1234 ; x=y [ section 2 ] happy = 4 sad = [empty] ; do nothing [comment_test] test1 = 1;2;3 ; only this will be a comment test2 = 2;3;4;this won't be a comment, needs whitespace before ';' test;3 = 345 ; key should be "test;3" test4 = 4#5#6 ; '#' only starts a comment at start of line #test5 = 567 ; entire line commented # test6 = 678 ; entire line commented, except in MULTILINE mode test7 = ; blank value, except if inline comments disabled test8 =; not a comment, needs whitespace before ';' [colon_tests] Content-Type: text/html foo:bar adams : 42 funny1 : with = equals funny2 = with : colons funny3 = two = equals funny4 : two : colons inih-r48/tests/unittest.bat000066400000000000000000000025511362665330000161400ustar00rootroot00000000000000@call tcc ..\ini.c -I..\ -run unittest.c > baseline_multi.txt @call tcc ..\ini.c -I..\ -DINI_MAX_LINE=20 -run unittest.c > baseline_multi_max_line.txt @call tcc ..\ini.c -I..\ -DINI_ALLOW_MULTILINE=0 -run unittest.c > baseline_single.txt @call tcc ..\ini.c -I..\ -DINI_ALLOW_INLINE_COMMENTS=0 -run unittest.c > baseline_disallow_inline_comments.txt @call tcc ..\ini.c -I..\ -DINI_STOP_ON_FIRST_ERROR=1 -run unittest.c > baseline_stop_on_first_error.txt @call tcc ..\ini.c -I..\ -DINI_HANDLER_LINENO=1 -run unittest.c > baseline_handler_lineno.txt @call tcc ..\ini.c -I..\ -DINI_USE_STACK=0 -run unittest.c > baseline_heap.txt @call tcc ..\ini.c -I..\ -DINI_USE_STACK=0 -DINI_MAX_LINE=20 -DINI_INITIAL_ALLOC=20 -run unittest.c > baseline_heap_max_line.txt @call tcc ..\ini.c -I..\ -DINI_USE_STACK=0 -DINI_ALLOW_REALLOC=1 -DINI_INITIAL_ALLOC=5 -run unittest.c > baseline_heap_realloc.txt @call tcc ..\ini.c -I..\ -DINI_USE_STACK=0 -DINI_MAX_LINE=20 -DINI_ALLOW_REALLOC=1 -DINI_INITIAL_ALLOC=5 -run unittest.c > baseline_heap_realloc_max_line.txt @call tcc ..\ini.c -I..\ -DINI_USE_STACK=0 -DINI_MAX_LINE=20 -DINI_INITIAL_ALLOC=20 -run unittest.c > baseline_heap_string.txt @call tcc ..\ini.c -I..\ -DINI_CALL_HANDLER_ON_NEW_SECTION=1 -run unittest.c > baseline_call_handler_on_new_section.txt @call tcc ..\ini.c -I..\ -DINI_ALLOW_NO_VALUE=1 -run unittest.c > baseline_allow_no_value.txt inih-r48/tests/unittest.c000066400000000000000000000034561362665330000156210ustar00rootroot00000000000000/* inih -- unit tests This works simply by dumping a bunch of info to standard output, which is redirected to an output file (baseline_*.txt) and checked into the Subversion repository. This baseline file is the test output, so the idea is to check it once, and if it changes -- look at the diff and see which tests failed. See unittest.bat and unittest.sh for how to run this (with tcc and gcc, respectively). */ #include #include #include #include "../ini.h" int User; char Prev_section[50]; #if INI_HANDLER_LINENO int dumper(void* user, const char* section, const char* name, const char* value, int lineno) #else int dumper(void* user, const char* section, const char* name, const char* value) #endif { User = *((int*)user); if (!name || strcmp(section, Prev_section)) { printf("... [%s]\n", section); strncpy(Prev_section, section, sizeof(Prev_section)); Prev_section[sizeof(Prev_section) - 1] = '\0'; } if (!name) { return 1; } #if INI_HANDLER_LINENO printf("... %s%s%s; line %d\n", name, value ? "=" : "", value ? value : "", lineno); #else printf("... %s%s%s;\n", name, value ? "=" : "", value ? value : ""); #endif return strcmp(name, "user")==0 && strcmp(value, "parse_error")==0 ? 0 : 1; } void parse(const char* fname) { static int u = 100; int e; *Prev_section = '\0'; e = ini_parse(fname, dumper, &u); printf("%s: e=%d user=%d\n", fname, e, User); u++; } int main(void) { parse("no_file.ini"); parse("normal.ini"); parse("bad_section.ini"); parse("bad_comment.ini"); parse("user_error.ini"); parse("multi_line.ini"); parse("bad_multi.ini"); parse("bom.ini"); parse("duplicate_sections.ini"); parse("no_value.ini"); return 0; } inih-r48/tests/unittest.sh000077500000000000000000000045641362665330000160150ustar00rootroot00000000000000#!/usr/bin/env bash gcc ../ini.c unittest.c -o unittest_multi ./unittest_multi > baseline_multi.txt rm -f unittest_multi gcc ../ini.c -DINI_MAX_LINE=20 unittest.c -o unittest_multi_max_line ./unittest_multi_max_line > baseline_multi_max_line.txt rm -f unittest_multi_max_line gcc ../ini.c -DINI_ALLOW_MULTILINE=0 unittest.c -o unittest_single ./unittest_single > baseline_single.txt rm -f unittest_single gcc ../ini.c -DINI_ALLOW_INLINE_COMMENTS=0 unittest.c -o unittest_disallow_inline_comments ./unittest_disallow_inline_comments > baseline_disallow_inline_comments.txt rm -f unittest_disallow_inline_comments gcc ../ini.c -DINI_STOP_ON_FIRST_ERROR=1 unittest.c -o unittest_stop_on_first_error ./unittest_stop_on_first_error > baseline_stop_on_first_error.txt rm -f unittest_stop_on_first_error gcc ../ini.c -DINI_HANDLER_LINENO=1 unittest.c -o unittest_handler_lineno ./unittest_handler_lineno > baseline_handler_lineno.txt rm -f unittest_handler_lineno gcc ../ini.c -DINI_MAX_LINE=20 unittest_string.c -o unittest_string ./unittest_string > baseline_string.txt rm -f unittest_string gcc ../ini.c -DINI_USE_STACK=0 unittest.c -o unittest_heap ./unittest_heap > baseline_heap.txt rm -f unittest_heap gcc ../ini.c -DINI_USE_STACK=0 -DINI_MAX_LINE=20 -DINI_INITIAL_ALLOC=20 unittest.c -o unittest_heap_max_line ./unittest_heap_max_line > baseline_heap_max_line.txt rm -f unittest_heap_max_line gcc ../ini.c -DINI_USE_STACK=0 -DINI_ALLOW_REALLOC=1 -DINI_INITIAL_ALLOC=5 unittest.c -o unittest_heap_realloc ./unittest_heap_realloc > baseline_heap_realloc.txt rm -f unittest_heap_realloc gcc ../ini.c -DINI_USE_STACK=0 -DINI_MAX_LINE=20 -DINI_ALLOW_REALLOC=1 -DINI_INITIAL_ALLOC=5 unittest.c -o unittest_heap_realloc_max_line ./unittest_heap_realloc_max_line > baseline_heap_realloc_max_line.txt rm -f unittest_heap_realloc_max_line gcc ../ini.c -DINI_USE_STACK=0 -DINI_MAX_LINE=20 -DINI_INITIAL_ALLOC=20 unittest_string.c -o unittest_heap_string ./unittest_heap_string > baseline_heap_string.txt rm -f unittest_heap_string gcc ../ini.c -DINI_CALL_HANDLER_ON_NEW_SECTION=1 unittest.c -o unittest_call_handler_on_new_section ./unittest_call_handler_on_new_section > baseline_call_handler_on_new_section.txt rm -f unittest_call_handler_on_new_section gcc ../ini.c -DINI_ALLOW_NO_VALUE=1 unittest.c -o unittest_allow_no_value ./unittest_allow_no_value > baseline_allow_no_value.txt rm -f unittest_allow_no_value inih-r48/tests/unittest_string.c000066400000000000000000000021671362665330000172050ustar00rootroot00000000000000/* inih -- unit tests for ini_parse_string() */ #include #include #include #include "../ini.h" int User; char Prev_section[50]; int dumper(void* user, const char* section, const char* name, const char* value) { User = *((int*)user); if (strcmp(section, Prev_section)) { printf("... [%s]\n", section); strncpy(Prev_section, section, sizeof(Prev_section)); Prev_section[sizeof(Prev_section) - 1] = '\0'; } printf("... %s=%s;\n", name, value); return 1; } void parse(const char* name, const char* string) { static int u = 100; int e; *Prev_section = '\0'; e = ini_parse_string(string, dumper, &u); printf("%s: e=%d user=%d\n", name, e, User); u++; } int main(void) { parse("empty string", ""); parse("basic", "[section]\nfoo = bar\nbazz = buzz quxx"); parse("crlf", "[section]\r\nhello = world\r\nforty_two = 42\r\n"); parse("long line", "[sec]\nfoo = 01234567890123456789\nbar=4321\n"); parse("long continued", "[sec]\nfoo = 0123456789012bix=1234\n"); parse("error", "[s]\na=1\nb\nc=3"); return 0; } inih-r48/tests/user_error.ini000066400000000000000000000000511362665330000164520ustar00rootroot00000000000000[section] a = b user = parse_error c = d