From bedd2e7ccb1595c23e159eaa952ae1b0b5a3d2ad Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Sat, 15 Mar 2014 01:49:50 +0100 Subject: Lean and mean initial commit Not much functionality yet --- ini.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 ini.c (limited to 'ini.c') diff --git a/ini.c b/ini.c new file mode 100644 index 0000000..df9dbc6 --- /dev/null +++ b/ini.c @@ -0,0 +1,166 @@ +/* inih -- simple .INI file parser + + inih is released under the New BSD license (see LICENSE.txt). Go to the project + home page for more info: + + http://code.google.com/p/inih/ + + */ + +#include +#include +#include + +#include "ini.h" + +#if !INI_USE_STACK +#include +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* 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 c or ';' comment in given string, or pointer to + null at end of string if neither found. ';' must be prefixed by a whitespace + character to register as a comment. */ +static char* find_char_or_comment(const char* s, char c) +{ + int was_whitespace = 0; + while ( *s && *s != c && !(was_whitespace && *s == ';') ) { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } + 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 ); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_file(FILE* file, int (*handler)(void*, const char*, const char*, const char*), void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; +#else + char* line; +#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_MAX_LINE ); + if ( !line ) { + return -2; + } +#endif + + /* Scan through file line by line */ + while ( fgets( line, INI_MAX_LINE, file ) != NULL ) { + 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 ( *start == ';' || *start == '#' ) { + /* Per Python ConfigParser, allow '#' comments at start of line */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-black 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_char_or_comment( start + 1, ']' ); + if ( *end == ']' ) { + *end = '\0'; + strncpy0( section, start + 1, sizeof(section) ); + *prev_name = '\0'; + } else if ( !error ) { + /* No ']' found on section line */ + error = lineno; + } + } else if ( *start && *start != ';' ) { + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment( start, '=' ); + if ( *end != '=' ) { + end = find_char_or_comment( start, ':' ); + } + if ( *end == '=' || *end == ':' ) { + *end = '\0'; + name = rstrip( start ); + value = lskip( end + 1 ); + end = find_char_or_comment( value, '\0' ); + if ( *end == ';' ) *end = '\0'; + 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 */ + error = lineno; + } + } + } + +#if !INI_USE_STACK + free( line ); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, int (*handler)(void*, const char*, const char*, const char*), 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; +} + -- cgit v1.2.3-55-g7522