gPass

gPass Git Source Tree

Root/cli/ini.c

1/* inih -- simple .INI file parser
2
3inih is released under the New BSD license (see LICENSE.txt). Go to the project
4home page for more info:
5
6https://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. */
28static 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. */
37static 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. */
47static 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. */
65static 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. */
73int 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 /* Scan through stream line by line */
100 while (reader(line, INI_MAX_LINE, stream) != NULL) {
101 lineno++;
102
103 start = line;
104#if INI_ALLOW_BOM
105 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
106 (unsigned char)start[1] == 0xBB &&
107 (unsigned char)start[2] == 0xBF) {
108 start += 3;
109 }
110#endif
111 start = lskip(rstrip(start));
112
113 if (*start == ';' || *start == '#') {
114 /* Per Python configparser, allow both ; and # comments at the
115 start of a line */
116 }
117#if INI_ALLOW_MULTILINE
118 else if (*prev_name && *start && start > line) {
119 /* Non-blank line with leading whitespace, treat as continuation
120 of previous name's value (as per Python configparser). */
121 if (!handler(user, section, prev_name, start) && !error)
122 error = lineno;
123 }
124#endif
125 else if (*start == '[') {
126 /* A "[section]" line */
127 end = find_chars_or_comment(start + 1, "]");
128 if (*end == ']') {
129 *end = '\0';
130 strncpy0(section, start + 1, sizeof(section));
131 *prev_name = '\0';
132 }
133 else if (!error) {
134 /* No ']' found on section line */
135 error = lineno;
136 }
137 }
138 else if (*start) {
139 /* Not a comment, must be a name[=:]value pair */
140 end = find_chars_or_comment(start, "=:");
141 if (*end == '=' || *end == ':') {
142 *end = '\0';
143 name = rstrip(start);
144 value = lskip(end + 1);
145#if INI_ALLOW_INLINE_COMMENTS
146 end = find_chars_or_comment(value, NULL);
147 if (*end)
148 *end = '\0';
149#endif
150 rstrip(value);
151
152 /* Valid name[=:]value pair found, call handler */
153 strncpy0(prev_name, name, sizeof(prev_name));
154 if (!handler(user, section, name, value) && !error)
155 error = lineno;
156 }
157 else if (!error) {
158 /* No '=' or ':' found on name[=:]value line */
159 error = lineno;
160 }
161 }
162
163#if INI_STOP_ON_FIRST_ERROR
164 if (error)
165 break;
166#endif
167 }
168
169#if !INI_USE_STACK
170 free(line);
171#endif
172
173 return error;
174}
175
176/* See documentation in header file. */
177int ini_parse_file(FILE* file, ini_handler handler, void* user)
178{
179 return ini_parse_stream((ini_reader)fgets, file, handler, user);
180}
181
182/* See documentation in header file. */
183int ini_parse(const char* filename, ini_handler handler, void* user)
184{
185 FILE* file;
186 int error;
187
188 file = fopen(filename, "r");
189 if (!file)
190 return -1;
191 error = ini_parse_file(file, handler, user);
192 fclose(file);
193 return error;
194}

Archive Download this file