Clemens Valens
/
LED_panel
32x64 3-color message board http://elektorembedded.blogspot.com/
Diff: ini.c
- Revision:
- 0:7a63bd42cf24
diff -r 000000000000 -r 7a63bd42cf24 ini.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ini.c Wed May 05 12:04:34 2010 +0000 @@ -0,0 +1,130 @@ +/* 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 <stdio.h> +#include <ctype.h> +#include <string.h> + +#include "ini.h" + +#define MAX_LINE 200 +#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(*--p)) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && isspace(*s)) + s++; + return (char*)s; +} + +/* Return pointer to first char c or ';' in given string, or pointer to + null at end of string if neither found. */ +static char* find_char_or_comment(const char* s, char c) +{ + while (*s && *s != c && *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(const char* filename, + int (*handler)(void*, const char*, const char*, const char*), + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ + char line[MAX_LINE]; + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + FILE* file; + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + + file = fopen(filename, "r"); + if (!file) + return -1; + + /* Scan through file line by line */ + while (fgets(line, sizeof(line), file) != NULL) { + lineno++; + start = lskip(rstrip(line)); + +#if INI_ALLOW_MULTILINE + 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; + } + else +#endif + 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 = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, ';'); + 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 '=' found on name=value line */ + error = lineno; + } + } + } + + fclose(file); + + return error; +}