URI: 
       ini.c - ltk - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/ltk.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       ini.c (5350B)
       ---
            1 /* inih -- simple .INI file parser
            2 
            3 inih is released under the New BSD license (see LICENSE.txt). Go to the project
            4 home page for more info:
            5 
            6 https://github.com/benhoyt/inih
            7 
            8 */
            9 
           10 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
           11 #define _CRT_SECURE_NO_WARNINGS
           12 #endif
           13 
           14 #include <stdio.h>
           15 #include <ctype.h>
           16 #include <string.h>
           17 
           18 #include "ini.h"
           19 
           20 #if !INI_USE_STACK
           21 #include <stdlib.h>
           22 #endif
           23 
           24 #define MAX_SECTION 50
           25 #define MAX_NAME 50
           26 
           27 /* Strip whitespace chars off end of given string, in place. Return s. */
           28 static char* rstrip(char* s)
           29 {
           30     char* p = s + strlen(s);
           31     while (p > s && isspace((unsigned char)(*--p)))
           32         *p = '\0';
           33     return s;
           34 }
           35 
           36 /* Return pointer to first non-whitespace char in given string. */
           37 static char* lskip(const char* s)
           38 {
           39     while (*s && isspace((unsigned char)(*s)))
           40         s++;
           41     return (char*)s;
           42 }
           43 
           44 /* Return pointer to first char (of chars) or inline comment in given string,
           45    or pointer to null at end of string if neither found. Inline comment must
           46    be prefixed by a whitespace character to register as a comment. */
           47 static char* find_chars_or_comment(const char* s, const char* chars)
           48 {
           49 #if INI_ALLOW_INLINE_COMMENTS
           50     int was_space = 0;
           51     while (*s && (!chars || !strchr(chars, *s)) &&
           52            !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
           53         was_space = isspace((unsigned char)(*s));
           54         s++;
           55     }
           56 #else
           57     while (*s && (!chars || !strchr(chars, *s))) {
           58         s++;
           59     }
           60 #endif
           61     return (char*)s;
           62 }
           63 
           64 /* Version of strncpy that ensures dest (size bytes) is null-terminated. */
           65 static char* strncpy0(char* dest, const char* src, size_t size)
           66 {
           67     strncpy(dest, src, size);
           68     dest[size - 1] = '\0';
           69     return dest;
           70 }
           71 
           72 /* See documentation in header file. */
           73 int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
           74                      void* user)
           75 {
           76     /* Uses a fair bit of stack (use heap instead if you need to) */
           77 #if INI_USE_STACK
           78     char line[INI_MAX_LINE];
           79 #else
           80     char* line;
           81 #endif
           82     char section[MAX_SECTION] = "";
           83     char prev_name[MAX_NAME] = "";
           84 
           85     char* start;
           86     char* end;
           87     char* name;
           88     char* value;
           89     int lineno = 0;
           90     int error = 0;
           91 
           92 #if !INI_USE_STACK
           93     line = (char*)malloc(INI_MAX_LINE);
           94     if (!line) {
           95         return -2;
           96     }
           97 #endif
           98 
           99 #if INI_HANDLER_LINENO
          100 #define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
          101 #else
          102 #define HANDLER(u, s, n, v) handler(u, s, n, v)
          103 #endif
          104 
          105     /* Scan through stream line by line */
          106     while (reader(line, INI_MAX_LINE, stream) != NULL) {
          107         lineno++;
          108 
          109         start = line;
          110 #if INI_ALLOW_BOM
          111         if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
          112                            (unsigned char)start[1] == 0xBB &&
          113                            (unsigned char)start[2] == 0xBF) {
          114             start += 3;
          115         }
          116 #endif
          117         start = lskip(rstrip(start));
          118 
          119         if (*start == ';' || *start == '#') {
          120             /* Per Python configparser, allow both ; and # comments at the
          121                start of a line */
          122         }
          123 #if INI_ALLOW_MULTILINE
          124         else if (*prev_name && *start && start > line) {
          125             /* Non-blank line with leading whitespace, treat as continuation
          126                of previous name's value (as per Python configparser). */
          127             if (!HANDLER(user, section, prev_name, start) && !error)
          128                 error = lineno;
          129         }
          130 #endif
          131         else if (*start == '[') {
          132             /* A "[section]" line */
          133             end = find_chars_or_comment(start + 1, "]");
          134             if (*end == ']') {
          135                 *end = '\0';
          136                 strncpy0(section, start + 1, sizeof(section));
          137                 *prev_name = '\0';
          138             }
          139             else if (!error) {
          140                 /* No ']' found on section line */
          141                 error = lineno;
          142             }
          143         }
          144         else if (*start) {
          145             /* Not a comment, must be a name[=:]value pair */
          146             end = find_chars_or_comment(start, "=:");
          147             if (*end == '=' || *end == ':') {
          148                 *end = '\0';
          149                 name = rstrip(start);
          150                 value = end + 1;
          151 #if INI_ALLOW_INLINE_COMMENTS
          152                 end = find_chars_or_comment(value, NULL);
          153                 if (*end)
          154                     *end = '\0';
          155 #endif
          156                 value = lskip(value);
          157                 rstrip(value);
          158 
          159                 /* Valid name[=:]value pair found, call handler */
          160                 strncpy0(prev_name, name, sizeof(prev_name));
          161                 if (!HANDLER(user, section, name, value) && !error)
          162                     error = lineno;
          163             }
          164             else if (!error) {
          165                 /* No '=' or ':' found on name[=:]value line */
          166                 error = lineno;
          167             }
          168         }
          169 
          170 #if INI_STOP_ON_FIRST_ERROR
          171         if (error)
          172             break;
          173 #endif
          174     }
          175 
          176 #if !INI_USE_STACK
          177     free(line);
          178 #endif
          179 
          180     return error;
          181 }
          182 
          183 /* See documentation in header file. */
          184 int ini_parse_file(FILE* file, ini_handler handler, void* user)
          185 {
          186     return ini_parse_stream((ini_reader)fgets, file, handler, user);
          187 }
          188 
          189 /* See documentation in header file. */
          190 int ini_parse(const char* filename, ini_handler handler, void* user)
          191 {
          192     FILE* file;
          193     int error;
          194 
          195     file = fopen(filename, "r");
          196     if (!file)
          197         return -1;
          198     error = ini_parse_file(file, handler, user);
          199     fclose(file);
          200     return error;
          201 }