Mercurial > wgsdk
comparison src/ini.c @ 11:e6a594f16403
*: huge refactor
the config file has changed drastically, moving to an ini file from
that custom format; i *would* have used the win32 functions for those,
but they were barely functional, so I decided on using ini.h which is
lightweight enough.
additionally, I've added Deezer support so album art will be displayed!
unfortunately though winhttp is a pain in the ass so if I send a request
with any form of unicode chars in it it just returns a "bad request" error.
I've tried debugging this but I could never really come up with anything:
my hypothesis is that deezer expects their characters in percent-encoded
UTF-8, but winhttp is sending them in some other encoding.
the config dialog was moved out of config.c (overdue) and many more options
are given in the config as well.
main.c has been renamed to plugin.c to better differentiate it from...
everything else.
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Thu, 14 Mar 2024 20:25:37 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
10:42ac054c0231 | 11:e6a594f16403 |
---|---|
1 /* inih -- simple .INI file parser | |
2 | |
3 SPDX-License-Identifier: BSD-3-Clause | |
4 | |
5 Copyright (C) 2009-2020, Ben Hoyt | |
6 | |
7 inih is released under the New BSD license (see LICENSE.txt). Go to the project | |
8 home page for more info: | |
9 | |
10 https://github.com/benhoyt/inih | |
11 | |
12 */ | |
13 | |
14 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) | |
15 #define _CRT_SECURE_NO_WARNINGS | |
16 #endif | |
17 | |
18 #include <stdio.h> | |
19 #include <ctype.h> | |
20 #include <string.h> | |
21 | |
22 #include "ini.h" | |
23 | |
24 #if !INI_USE_STACK | |
25 #if INI_CUSTOM_ALLOCATOR | |
26 #include <stddef.h> | |
27 void* ini_malloc(size_t size); | |
28 void ini_free(void* ptr); | |
29 void* ini_realloc(void* ptr, size_t size); | |
30 #else | |
31 #include <stdlib.h> | |
32 #define ini_malloc malloc | |
33 #define ini_free free | |
34 #define ini_realloc realloc | |
35 #endif | |
36 #endif | |
37 | |
38 #define MAX_SECTION 50 | |
39 #define MAX_NAME 50 | |
40 | |
41 /* Used by ini_parse_string() to keep track of string parsing state. */ | |
42 typedef struct { | |
43 const char* ptr; | |
44 size_t num_left; | |
45 } ini_parse_string_ctx; | |
46 | |
47 /* Strip whitespace chars off end of given string, in place. Return s. */ | |
48 static char* ini_rstrip(char* s) | |
49 { | |
50 char* p = s + strlen(s); | |
51 while (p > s && isspace((unsigned char)(*--p))) | |
52 *p = '\0'; | |
53 return s; | |
54 } | |
55 | |
56 /* Return pointer to first non-whitespace char in given string. */ | |
57 static char* ini_lskip(const char* s) | |
58 { | |
59 while (*s && isspace((unsigned char)(*s))) | |
60 s++; | |
61 return (char*)s; | |
62 } | |
63 | |
64 /* Return pointer to first char (of chars) or inline comment in given string, | |
65 or pointer to NUL at end of string if neither found. Inline comment must | |
66 be prefixed by a whitespace character to register as a comment. */ | |
67 static char* ini_find_chars_or_comment(const char* s, const char* chars) | |
68 { | |
69 #if INI_ALLOW_INLINE_COMMENTS | |
70 int was_space = 0; | |
71 while (*s && (!chars || !strchr(chars, *s)) && | |
72 !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { | |
73 was_space = isspace((unsigned char)(*s)); | |
74 s++; | |
75 } | |
76 #else | |
77 while (*s && (!chars || !strchr(chars, *s))) { | |
78 s++; | |
79 } | |
80 #endif | |
81 return (char*)s; | |
82 } | |
83 | |
84 /* Similar to strncpy, but ensures dest (size bytes) is | |
85 NUL-terminated, and doesn't pad with NULs. */ | |
86 static char* ini_strncpy0(char* dest, const char* src, size_t size) | |
87 { | |
88 /* Could use strncpy internally, but it causes gcc warnings (see issue #91) */ | |
89 size_t i; | |
90 for (i = 0; i < size - 1 && src[i]; i++) | |
91 dest[i] = src[i]; | |
92 dest[i] = '\0'; | |
93 return dest; | |
94 } | |
95 | |
96 /* See documentation in header file. */ | |
97 int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, | |
98 void* user) | |
99 { | |
100 /* Uses a fair bit of stack (use heap instead if you need to) */ | |
101 #if INI_USE_STACK | |
102 char line[INI_MAX_LINE]; | |
103 size_t max_line = INI_MAX_LINE; | |
104 #else | |
105 char* line; | |
106 size_t max_line = INI_INITIAL_ALLOC; | |
107 #endif | |
108 #if INI_ALLOW_REALLOC && !INI_USE_STACK | |
109 char* new_line; | |
110 size_t offset; | |
111 #endif | |
112 char section[MAX_SECTION] = ""; | |
113 char prev_name[MAX_NAME] = ""; | |
114 | |
115 char* start; | |
116 char* end; | |
117 char* name; | |
118 char* value; | |
119 int lineno = 0; | |
120 int error = 0; | |
121 | |
122 #if !INI_USE_STACK | |
123 line = (char*)ini_malloc(INI_INITIAL_ALLOC); | |
124 if (!line) { | |
125 return -2; | |
126 } | |
127 #endif | |
128 | |
129 #if INI_HANDLER_LINENO | |
130 #define HANDLER(u, s, n, v) handler(u, s, n, v, lineno) | |
131 #else | |
132 #define HANDLER(u, s, n, v) handler(u, s, n, v) | |
133 #endif | |
134 | |
135 /* Scan through stream line by line */ | |
136 while (reader(line, (int)max_line, stream) != NULL) { | |
137 #if INI_ALLOW_REALLOC && !INI_USE_STACK | |
138 offset = strlen(line); | |
139 while (offset == max_line - 1 && line[offset - 1] != '\n') { | |
140 max_line *= 2; | |
141 if (max_line > INI_MAX_LINE) | |
142 max_line = INI_MAX_LINE; | |
143 new_line = ini_realloc(line, max_line); | |
144 if (!new_line) { | |
145 ini_free(line); | |
146 return -2; | |
147 } | |
148 line = new_line; | |
149 if (reader(line + offset, (int)(max_line - offset), stream) == NULL) | |
150 break; | |
151 if (max_line >= INI_MAX_LINE) | |
152 break; | |
153 offset += strlen(line + offset); | |
154 } | |
155 #endif | |
156 | |
157 lineno++; | |
158 | |
159 start = line; | |
160 #if INI_ALLOW_BOM | |
161 if (lineno == 1 && (unsigned char)start[0] == 0xEF && | |
162 (unsigned char)start[1] == 0xBB && | |
163 (unsigned char)start[2] == 0xBF) { | |
164 start += 3; | |
165 } | |
166 #endif | |
167 start = ini_lskip(ini_rstrip(start)); | |
168 | |
169 if (strchr(INI_START_COMMENT_PREFIXES, *start)) { | |
170 /* Start-of-line comment */ | |
171 } | |
172 #if INI_ALLOW_MULTILINE | |
173 else if (*prev_name && *start && start > line) { | |
174 #if INI_ALLOW_INLINE_COMMENTS | |
175 end = ini_find_chars_or_comment(start, NULL); | |
176 if (*end) | |
177 *end = '\0'; | |
178 ini_rstrip(start); | |
179 #endif | |
180 /* Non-blank line with leading whitespace, treat as continuation | |
181 of previous name's value (as per Python configparser). */ | |
182 if (!HANDLER(user, section, prev_name, start) && !error) | |
183 error = lineno; | |
184 } | |
185 #endif | |
186 else if (*start == '[') { | |
187 /* A "[section]" line */ | |
188 end = ini_find_chars_or_comment(start + 1, "]"); | |
189 if (*end == ']') { | |
190 *end = '\0'; | |
191 ini_strncpy0(section, start + 1, sizeof(section)); | |
192 *prev_name = '\0'; | |
193 #if INI_CALL_HANDLER_ON_NEW_SECTION | |
194 if (!HANDLER(user, section, NULL, NULL) && !error) | |
195 error = lineno; | |
196 #endif | |
197 } | |
198 else if (!error) { | |
199 /* No ']' found on section line */ | |
200 error = lineno; | |
201 } | |
202 } | |
203 else if (*start) { | |
204 /* Not a comment, must be a name[=:]value pair */ | |
205 end = ini_find_chars_or_comment(start, "=:"); | |
206 if (*end == '=' || *end == ':') { | |
207 *end = '\0'; | |
208 name = ini_rstrip(start); | |
209 value = end + 1; | |
210 #if INI_ALLOW_INLINE_COMMENTS | |
211 end = ini_find_chars_or_comment(value, NULL); | |
212 if (*end) | |
213 *end = '\0'; | |
214 #endif | |
215 value = ini_lskip(value); | |
216 ini_rstrip(value); | |
217 | |
218 /* Valid name[=:]value pair found, call handler */ | |
219 ini_strncpy0(prev_name, name, sizeof(prev_name)); | |
220 if (!HANDLER(user, section, name, value) && !error) | |
221 error = lineno; | |
222 } | |
223 else if (!error) { | |
224 /* No '=' or ':' found on name[=:]value line */ | |
225 #if INI_ALLOW_NO_VALUE | |
226 *end = '\0'; | |
227 name = ini_rstrip(start); | |
228 if (!HANDLER(user, section, name, NULL) && !error) | |
229 error = lineno; | |
230 #else | |
231 error = lineno; | |
232 #endif | |
233 } | |
234 } | |
235 | |
236 #if INI_STOP_ON_FIRST_ERROR | |
237 if (error) | |
238 break; | |
239 #endif | |
240 } | |
241 | |
242 #if !INI_USE_STACK | |
243 ini_free(line); | |
244 #endif | |
245 | |
246 return error; | |
247 } | |
248 | |
249 /* See documentation in header file. */ | |
250 int ini_parse_file(FILE* file, ini_handler handler, void* user) | |
251 { | |
252 return ini_parse_stream((ini_reader)fgets, file, handler, user); | |
253 } | |
254 | |
255 /* See documentation in header file. */ | |
256 int ini_parse(const char* filename, ini_handler handler, void* user) | |
257 { | |
258 FILE* file; | |
259 int error; | |
260 | |
261 file = fopen(filename, "r"); | |
262 if (!file) | |
263 return -1; | |
264 error = ini_parse_file(file, handler, user); | |
265 fclose(file); | |
266 return error; | |
267 } | |
268 | |
269 /* An ini_reader function to read the next line from a string buffer. This | |
270 is the fgets() equivalent used by ini_parse_string(). */ | |
271 static char* ini_reader_string(char* str, int num, void* stream) { | |
272 ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream; | |
273 const char* ctx_ptr = ctx->ptr; | |
274 size_t ctx_num_left = ctx->num_left; | |
275 char* strp = str; | |
276 char c; | |
277 | |
278 if (ctx_num_left == 0 || num < 2) | |
279 return NULL; | |
280 | |
281 while (num > 1 && ctx_num_left != 0) { | |
282 c = *ctx_ptr++; | |
283 ctx_num_left--; | |
284 *strp++ = c; | |
285 if (c == '\n') | |
286 break; | |
287 num--; | |
288 } | |
289 | |
290 *strp = '\0'; | |
291 ctx->ptr = ctx_ptr; | |
292 ctx->num_left = ctx_num_left; | |
293 return str; | |
294 } | |
295 | |
296 /* See documentation in header file. */ | |
297 int ini_parse_string(const char* string, ini_handler handler, void* user) { | |
298 ini_parse_string_ctx ctx; | |
299 | |
300 ctx.ptr = string; | |
301 ctx.num_left = strlen(string); | |
302 return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler, | |
303 user); | |
304 } |