Clemens Valens
/
LED_panel
32x64 3-color message board http://elektorembedded.blogspot.com/
ini.c@0:7a63bd42cf24, 2010-05-05 (annotated)
- Committer:
- Clemo
- Date:
- Wed May 05 12:04:34 2010 +0000
- Revision:
- 0:7a63bd42cf24
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Clemo | 0:7a63bd42cf24 | 1 | /* inih -- simple .INI file parser |
Clemo | 0:7a63bd42cf24 | 2 | |
Clemo | 0:7a63bd42cf24 | 3 | inih is released under the New BSD license (see LICENSE.txt). Go to the project |
Clemo | 0:7a63bd42cf24 | 4 | home page for more info: |
Clemo | 0:7a63bd42cf24 | 5 | |
Clemo | 0:7a63bd42cf24 | 6 | http://code.google.com/p/inih/ |
Clemo | 0:7a63bd42cf24 | 7 | |
Clemo | 0:7a63bd42cf24 | 8 | */ |
Clemo | 0:7a63bd42cf24 | 9 | |
Clemo | 0:7a63bd42cf24 | 10 | #include <stdio.h> |
Clemo | 0:7a63bd42cf24 | 11 | #include <ctype.h> |
Clemo | 0:7a63bd42cf24 | 12 | #include <string.h> |
Clemo | 0:7a63bd42cf24 | 13 | |
Clemo | 0:7a63bd42cf24 | 14 | #include "ini.h" |
Clemo | 0:7a63bd42cf24 | 15 | |
Clemo | 0:7a63bd42cf24 | 16 | #define MAX_LINE 200 |
Clemo | 0:7a63bd42cf24 | 17 | #define MAX_SECTION 50 |
Clemo | 0:7a63bd42cf24 | 18 | #define MAX_NAME 50 |
Clemo | 0:7a63bd42cf24 | 19 | |
Clemo | 0:7a63bd42cf24 | 20 | /* Strip whitespace chars off end of given string, in place. Return s. */ |
Clemo | 0:7a63bd42cf24 | 21 | static char* rstrip(char* s) |
Clemo | 0:7a63bd42cf24 | 22 | { |
Clemo | 0:7a63bd42cf24 | 23 | char* p = s + strlen(s); |
Clemo | 0:7a63bd42cf24 | 24 | while (p > s && isspace(*--p)) |
Clemo | 0:7a63bd42cf24 | 25 | *p = '\0'; |
Clemo | 0:7a63bd42cf24 | 26 | return s; |
Clemo | 0:7a63bd42cf24 | 27 | } |
Clemo | 0:7a63bd42cf24 | 28 | |
Clemo | 0:7a63bd42cf24 | 29 | /* Return pointer to first non-whitespace char in given string. */ |
Clemo | 0:7a63bd42cf24 | 30 | static char* lskip(const char* s) |
Clemo | 0:7a63bd42cf24 | 31 | { |
Clemo | 0:7a63bd42cf24 | 32 | while (*s && isspace(*s)) |
Clemo | 0:7a63bd42cf24 | 33 | s++; |
Clemo | 0:7a63bd42cf24 | 34 | return (char*)s; |
Clemo | 0:7a63bd42cf24 | 35 | } |
Clemo | 0:7a63bd42cf24 | 36 | |
Clemo | 0:7a63bd42cf24 | 37 | /* Return pointer to first char c or ';' in given string, or pointer to |
Clemo | 0:7a63bd42cf24 | 38 | null at end of string if neither found. */ |
Clemo | 0:7a63bd42cf24 | 39 | static char* find_char_or_comment(const char* s, char c) |
Clemo | 0:7a63bd42cf24 | 40 | { |
Clemo | 0:7a63bd42cf24 | 41 | while (*s && *s != c && *s != ';') |
Clemo | 0:7a63bd42cf24 | 42 | s++; |
Clemo | 0:7a63bd42cf24 | 43 | return (char*)s; |
Clemo | 0:7a63bd42cf24 | 44 | } |
Clemo | 0:7a63bd42cf24 | 45 | |
Clemo | 0:7a63bd42cf24 | 46 | /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ |
Clemo | 0:7a63bd42cf24 | 47 | static char* strncpy0(char* dest, const char* src, size_t size) |
Clemo | 0:7a63bd42cf24 | 48 | { |
Clemo | 0:7a63bd42cf24 | 49 | strncpy(dest, src, size); |
Clemo | 0:7a63bd42cf24 | 50 | dest[size - 1] = '\0'; |
Clemo | 0:7a63bd42cf24 | 51 | return dest; |
Clemo | 0:7a63bd42cf24 | 52 | } |
Clemo | 0:7a63bd42cf24 | 53 | |
Clemo | 0:7a63bd42cf24 | 54 | /* See documentation in header file. */ |
Clemo | 0:7a63bd42cf24 | 55 | int ini_parse(const char* filename, |
Clemo | 0:7a63bd42cf24 | 56 | int (*handler)(void*, const char*, const char*, const char*), |
Clemo | 0:7a63bd42cf24 | 57 | void* user) |
Clemo | 0:7a63bd42cf24 | 58 | { |
Clemo | 0:7a63bd42cf24 | 59 | /* Uses a fair bit of stack (use heap instead if you need to) */ |
Clemo | 0:7a63bd42cf24 | 60 | char line[MAX_LINE]; |
Clemo | 0:7a63bd42cf24 | 61 | char section[MAX_SECTION] = ""; |
Clemo | 0:7a63bd42cf24 | 62 | char prev_name[MAX_NAME] = ""; |
Clemo | 0:7a63bd42cf24 | 63 | |
Clemo | 0:7a63bd42cf24 | 64 | FILE* file; |
Clemo | 0:7a63bd42cf24 | 65 | char* start; |
Clemo | 0:7a63bd42cf24 | 66 | char* end; |
Clemo | 0:7a63bd42cf24 | 67 | char* name; |
Clemo | 0:7a63bd42cf24 | 68 | char* value; |
Clemo | 0:7a63bd42cf24 | 69 | int lineno = 0; |
Clemo | 0:7a63bd42cf24 | 70 | int error = 0; |
Clemo | 0:7a63bd42cf24 | 71 | |
Clemo | 0:7a63bd42cf24 | 72 | file = fopen(filename, "r"); |
Clemo | 0:7a63bd42cf24 | 73 | if (!file) |
Clemo | 0:7a63bd42cf24 | 74 | return -1; |
Clemo | 0:7a63bd42cf24 | 75 | |
Clemo | 0:7a63bd42cf24 | 76 | /* Scan through file line by line */ |
Clemo | 0:7a63bd42cf24 | 77 | while (fgets(line, sizeof(line), file) != NULL) { |
Clemo | 0:7a63bd42cf24 | 78 | lineno++; |
Clemo | 0:7a63bd42cf24 | 79 | start = lskip(rstrip(line)); |
Clemo | 0:7a63bd42cf24 | 80 | |
Clemo | 0:7a63bd42cf24 | 81 | #if INI_ALLOW_MULTILINE |
Clemo | 0:7a63bd42cf24 | 82 | if (*prev_name && *start && start > line) { |
Clemo | 0:7a63bd42cf24 | 83 | /* Non-black line with leading whitespace, treat as continuation |
Clemo | 0:7a63bd42cf24 | 84 | of previous name's value (as per Python ConfigParser). */ |
Clemo | 0:7a63bd42cf24 | 85 | if (!handler(user, section, prev_name, start) && !error) |
Clemo | 0:7a63bd42cf24 | 86 | error = lineno; |
Clemo | 0:7a63bd42cf24 | 87 | } |
Clemo | 0:7a63bd42cf24 | 88 | else |
Clemo | 0:7a63bd42cf24 | 89 | #endif |
Clemo | 0:7a63bd42cf24 | 90 | if (*start == '[') { |
Clemo | 0:7a63bd42cf24 | 91 | /* A "[section]" line */ |
Clemo | 0:7a63bd42cf24 | 92 | end = find_char_or_comment(start + 1, ']'); |
Clemo | 0:7a63bd42cf24 | 93 | if (*end == ']') { |
Clemo | 0:7a63bd42cf24 | 94 | *end = '\0'; |
Clemo | 0:7a63bd42cf24 | 95 | strncpy0(section, start + 1, sizeof(section)); |
Clemo | 0:7a63bd42cf24 | 96 | *prev_name = '\0'; |
Clemo | 0:7a63bd42cf24 | 97 | } |
Clemo | 0:7a63bd42cf24 | 98 | else if (!error) { |
Clemo | 0:7a63bd42cf24 | 99 | /* No ']' found on section line */ |
Clemo | 0:7a63bd42cf24 | 100 | error = lineno; |
Clemo | 0:7a63bd42cf24 | 101 | } |
Clemo | 0:7a63bd42cf24 | 102 | } |
Clemo | 0:7a63bd42cf24 | 103 | else if (*start && *start != ';') { |
Clemo | 0:7a63bd42cf24 | 104 | /* Not a comment, must be a name=value pair */ |
Clemo | 0:7a63bd42cf24 | 105 | end = find_char_or_comment(start, '='); |
Clemo | 0:7a63bd42cf24 | 106 | if (*end == '=') { |
Clemo | 0:7a63bd42cf24 | 107 | *end = '\0'; |
Clemo | 0:7a63bd42cf24 | 108 | name = rstrip(start); |
Clemo | 0:7a63bd42cf24 | 109 | value = lskip(end + 1); |
Clemo | 0:7a63bd42cf24 | 110 | end = find_char_or_comment(value, ';'); |
Clemo | 0:7a63bd42cf24 | 111 | if (*end == ';') |
Clemo | 0:7a63bd42cf24 | 112 | *end = '\0'; |
Clemo | 0:7a63bd42cf24 | 113 | rstrip(value); |
Clemo | 0:7a63bd42cf24 | 114 | |
Clemo | 0:7a63bd42cf24 | 115 | /* Valid name=value pair found, call handler */ |
Clemo | 0:7a63bd42cf24 | 116 | strncpy0(prev_name, name, sizeof(prev_name)); |
Clemo | 0:7a63bd42cf24 | 117 | if (!handler(user, section, name, value) && !error) |
Clemo | 0:7a63bd42cf24 | 118 | error = lineno; |
Clemo | 0:7a63bd42cf24 | 119 | } |
Clemo | 0:7a63bd42cf24 | 120 | else if (!error) { |
Clemo | 0:7a63bd42cf24 | 121 | /* No '=' found on name=value line */ |
Clemo | 0:7a63bd42cf24 | 122 | error = lineno; |
Clemo | 0:7a63bd42cf24 | 123 | } |
Clemo | 0:7a63bd42cf24 | 124 | } |
Clemo | 0:7a63bd42cf24 | 125 | } |
Clemo | 0:7a63bd42cf24 | 126 | |
Clemo | 0:7a63bd42cf24 | 127 | fclose(file); |
Clemo | 0:7a63bd42cf24 | 128 | |
Clemo | 0:7a63bd42cf24 | 129 | return error; |
Clemo | 0:7a63bd42cf24 | 130 | } |