32x64 3-color message board http://elektorembedded.blogspot.com/

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ini.c Source File

ini.c

00001 /* inih -- simple .INI file parser
00002 
00003 inih is released under the New BSD license (see LICENSE.txt). Go to the project
00004 home page for more info:
00005 
00006 http://code.google.com/p/inih/
00007 
00008 */
00009 
00010 #include <stdio.h>
00011 #include <ctype.h>
00012 #include <string.h>
00013 
00014 #include "ini.h"
00015 
00016 #define MAX_LINE 200
00017 #define MAX_SECTION 50
00018 #define MAX_NAME 50
00019 
00020 /* Strip whitespace chars off end of given string, in place. Return s. */
00021 static char* rstrip(char* s)
00022 {
00023     char* p = s + strlen(s);
00024     while (p > s && isspace(*--p))
00025         *p = '\0';
00026     return s;
00027 }
00028 
00029 /* Return pointer to first non-whitespace char in given string. */
00030 static char* lskip(const char* s)
00031 {
00032     while (*s && isspace(*s))
00033         s++;
00034     return (char*)s;
00035 }
00036 
00037 /* Return pointer to first char c or ';' in given string, or pointer to
00038    null at end of string if neither found. */
00039 static char* find_char_or_comment(const char* s, char c)
00040 {
00041     while (*s && *s != c && *s != ';')
00042         s++;
00043     return (char*)s;
00044 }
00045 
00046 /* Version of strncpy that ensures dest (size bytes) is null-terminated. */
00047 static char* strncpy0(char* dest, const char* src, size_t size)
00048 {
00049     strncpy(dest, src, size);
00050     dest[size - 1] = '\0';
00051     return dest;
00052 }
00053 
00054 /* See documentation in header file. */
00055 int ini_parse(const char* filename,
00056               int (*handler)(void*, const char*, const char*, const char*),
00057               void* user)
00058 {
00059     /* Uses a fair bit of stack (use heap instead if you need to) */
00060     char line[MAX_LINE];
00061     char section[MAX_SECTION] = "";
00062     char prev_name[MAX_NAME] = "";
00063 
00064     FILE* file;
00065     char* start;
00066     char* end;
00067     char* name;
00068     char* value;
00069     int lineno = 0;
00070     int error = 0;
00071 
00072     file = fopen(filename, "r");
00073     if (!file)
00074         return -1;
00075 
00076     /* Scan through file line by line */
00077     while (fgets(line, sizeof(line), file) != NULL) {
00078         lineno++;
00079         start = lskip(rstrip(line));
00080 
00081 #if INI_ALLOW_MULTILINE
00082         if (*prev_name && *start && start > line) {
00083             /* Non-black line with leading whitespace, treat as continuation
00084                of previous name's value (as per Python ConfigParser). */
00085             if (!handler(user, section, prev_name, start) && !error)
00086                 error = lineno;
00087         }
00088         else
00089 #endif
00090         if (*start == '[') {
00091             /* A "[section]" line */
00092             end = find_char_or_comment(start + 1, ']');
00093             if (*end == ']') {
00094                 *end = '\0';
00095                 strncpy0(section, start + 1, sizeof(section));
00096                 *prev_name = '\0';
00097             }
00098             else if (!error) {
00099                 /* No ']' found on section line */
00100                 error = lineno;
00101             }
00102         }
00103         else if (*start && *start != ';') {
00104             /* Not a comment, must be a name=value pair */
00105             end = find_char_or_comment(start, '=');
00106             if (*end == '=') {
00107                 *end = '\0';
00108                 name = rstrip(start);
00109                 value = lskip(end + 1);
00110                 end = find_char_or_comment(value, ';');
00111                 if (*end == ';')
00112                     *end = '\0';
00113                 rstrip(value);
00114 
00115                 /* Valid name=value pair found, call handler */
00116                 strncpy0(prev_name, name, sizeof(prev_name));
00117                 if (!handler(user, section, name, value) && !error)
00118                     error = lineno;
00119             }
00120             else if (!error) {
00121                 /* No '=' found on name=value line */
00122                 error = lineno;
00123             }
00124         }
00125     }
00126 
00127     fclose(file);
00128 
00129     return error;
00130 }