liblibgb.c 1.2021.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/gb/gb_ini.h ADDED
@@ -0,0 +1,425 @@
1
+ /* gb_ini.h - v0.93 - public domain ini file loader library - no warranty implied; use at your own risk
2
+ A Simple Ini File Loader Library for C and C++
3
+
4
+ Version History:
5
+ 0.93 - C90 support
6
+ 0.92 - ??
7
+ 0.91 - New styling
8
+ 0.91a - Error handling fix
9
+ 0.91 - Add extern "C" if compiling as C++
10
+ 0.90 - Initial Version
11
+
12
+ LICENSE
13
+ This software is in the public domain. Where that dedication is not
14
+ recognized, you are granted a perpetual, irrevocable license to copy,
15
+ distribute, and modify this file as you see fit.
16
+
17
+ How to use:
18
+ Do this:
19
+ #define GB_INI_IMPLEMENTATION
20
+ before you include this file in *one* C++ file to create the implementation
21
+
22
+ i.e. it should look like this:
23
+ #include ...
24
+ #include ...
25
+ #include ...
26
+ #define GB_INI_IMPLEMENTATION
27
+ #include "gb_ini.h"
28
+
29
+ If you prefer to use C++, you can use all the same functions in a
30
+ namespace instead, do this:
31
+ #define GB_INI_CPP
32
+ before you include the header file
33
+
34
+ i.e it should look like this:
35
+ #define GB_INI_CPP
36
+ #include "gb_ini.h"
37
+ */
38
+
39
+ /* Examples: */
40
+ /* test.ini contents*/
41
+ #if 0
42
+ ; This is a Comment
43
+ # This is also
44
+
45
+ name=gb_ini.h
46
+ version = 01337 # Look mum, a comment!
47
+
48
+ [license]
49
+ name = Public Domain
50
+
51
+ [author]
52
+ name = Ginger Bill
53
+ #endif
54
+ /* C example */
55
+ #if 0
56
+ #define GB_INI_IMPLEMENTATION
57
+ #include "gb_ini.h"
58
+
59
+ #include <stdio.h>
60
+ #include <stdlib.h>
61
+ struct Library {
62
+ char const *name;
63
+ int version;
64
+ char const *license;
65
+ char const *author;
66
+ };
67
+
68
+ // The below macro expands to this:
69
+ // static test_ini_handlerchar const *data, char const *section, char const *name, char const *value)
70
+ static GB_INI_HANDLER(test_ini_handler)
71
+ {
72
+ struct Library *lib = (struct Library *)data;
73
+
74
+ #define TEST(s, n) (strcmp(section, s) == 0 && strcmp(name, n) == 0)
75
+
76
+ if (TEST("", "name"))
77
+ lib->name = strdup(value);
78
+ else if (TEST("", "version"))
79
+ lib->version = atoi(value);
80
+ else if (TEST("license", "name"))
81
+ lib->license = strdup(value);
82
+ else if (TEST("author", "name"))
83
+ lib->author = strdup(value);
84
+ else
85
+ return 0;
86
+
87
+ #undef TEST
88
+
89
+ return 1;
90
+ }
91
+
92
+ int main(int argc, char **argv)
93
+ {
94
+ struct Library lib = {0};
95
+ gbIniError err = gb_ini_parse("test.ini", &test_ini_handler, &lib);
96
+ if (err.type != GB_INI_ERROR_NONE) {
97
+ if (err.line_num > 0)
98
+ printf("Line (%d): ", err.line_num);
99
+ printf("%s\n", gb_ini_error_string(err));
100
+
101
+ return 1;
102
+ }
103
+
104
+ printf("Name : %s\n", lib.name); // Name : gb_init.h
105
+ printf("Version : %d\n", lib.version); // Version : 1337
106
+ printf("License : %s\n", lib.license); // License : Public Domain
107
+ printf("Author : %s\n", lib.author); // Author : Ginger Bill
108
+
109
+ return 0;
110
+ }
111
+ #endif
112
+
113
+ /* C++ example */
114
+ #if 0
115
+ #define GB_INI_CPP
116
+ #define GB_INI_IMPLEMENTATION
117
+ #include "gb_ini.h"
118
+
119
+ #include <stdio.h>
120
+ #include <stdlib.h>
121
+
122
+ struct Library {
123
+ char const *name;
124
+ int version;
125
+ char const *license;
126
+ char const *author;
127
+ };
128
+
129
+ // The below macro expands to this:
130
+ // static test_ini_handler(void *data, char const *section, char const *name, char const *value)
131
+ static GB_INI_HANDLER(test_ini_handler)
132
+ {
133
+ Library* lib = (Library*)data;
134
+
135
+ #define TEST(s, n) (strcmp(section, s) == 0 && strcmp(name, n) == 0)
136
+
137
+ if (TEST("", "name"))
138
+ lib->name = strdup(value);
139
+ else if (TEST("", "version"))
140
+ lib->version = atoi(value);
141
+ else if (TEST("license", "name"))
142
+ lib->license = strdup(value);
143
+ else if (TEST("author", "name"))
144
+ lib->author = strdup(value);
145
+ else
146
+ return 0;
147
+
148
+ #undef TEST
149
+
150
+ return 1;
151
+ }
152
+
153
+ int main(int argc, char** argv)
154
+ {
155
+ Library lib = {};
156
+
157
+ using namespace gb;
158
+
159
+ Ini_Error err = ini_parse("test.ini", &test_ini_handler, &lib);
160
+ if (err.type != INI_ERROR_NONE) {
161
+ if (err.line_num > 0)
162
+ printf("Line (%d): ", err.line_num);
163
+ printf("%s\n", ini_error_string(err));
164
+
165
+ return 1;
166
+ }
167
+
168
+ printf("Name : %s\n", lib.name); // Name : gb_init.h
169
+ printf("Version : %d\n", lib.version); // Version : 90
170
+ printf("License : %s\n", lib.license); // License : Public Domain
171
+ printf("Author : %s\n", lib.author); // Author : Ginger Bill
172
+
173
+ return 0;
174
+ }
175
+ #endif
176
+
177
+ #ifndef GB_INI_INCLUDE_GB_INI_H
178
+ #define GB_INI_INCLUDE_GB_INI_H
179
+
180
+ #ifndef GB_INI_MAX_LINE_LENGTH
181
+ #define GB_INI_MAX_LINE_LENGTH 1024
182
+ #endif
183
+
184
+ #ifndef GB_INI_MAX_SECTION_LENGTH
185
+ #define GB_INI_MAX_SECTION_LENGTH 256
186
+ #endif
187
+
188
+ #ifndef GB_INI_MAX_NAME_LENGTH
189
+ #define GB_INI_MAX_NAME_LENGTH 256
190
+ #endif
191
+
192
+ #ifndef GB_INI_CHECK_FOR_UTF8_BOM
193
+ #define GB_INI_CHECK_FOR_UTF8_BOM 1
194
+ #endif
195
+
196
+
197
+ #ifndef _MSC_VER
198
+ #ifdef __cplusplus
199
+ #define gbini_inline inline
200
+ #else
201
+ #define gbini_inline
202
+ #endif
203
+ #else
204
+ #define gbini_inline __forceinline
205
+ #endif
206
+
207
+ #include <stdio.h>
208
+
209
+ #ifdef __cplusplus
210
+ extern "C" {
211
+ #endif
212
+
213
+ enum {
214
+ GB_INI_ERROR_NONE = 0,
215
+
216
+ GB_INI_ERROR_FILE_ERROR,
217
+ GB_INI_ERROR_MISSING_SECTION_BRACKET,
218
+ GB_INI_ERROR_ASSIGNMENT_MISSING,
219
+ GB_INI_ERROR_HANDLER_ERROR,
220
+
221
+ GB_INI_ERROR_COUNT
222
+ };
223
+
224
+ typedef struct gbIniError {
225
+ int type;
226
+ size_t line_num;
227
+ } gbIniError;
228
+
229
+ #ifndef GB_INI_HANDLER_RETURN_TYPE
230
+ #define GB_INI_HANDLER_RETURN_TYPE
231
+ typedef int gbIniHRT;
232
+ #endif
233
+
234
+ /* This macro can be use to declare this type of function without
235
+ * needing to define all the of the parameters
236
+ */
237
+ #define GB_INI_HANDLER(func_name) gbIniHRT func_name(void *data, char const *section, char const *name, char const *value)
238
+ typedef GB_INI_HANDLER(gbIniHandler);
239
+
240
+ extern char const *GB_ERROR_STRINGS[GB_INI_ERROR_COUNT];
241
+
242
+ gbIniError gb_ini_parse(char const *filename, gbIniHandler* handler_func, void *data);
243
+ gbIniError gb_ini_parse_file(FILE *file, gbIniHandler* handler_func, void *data);
244
+
245
+ gbini_inline char const *gb_ini_error_string(gbIniError const err) { return GB_ERROR_STRINGS[err.type]; }
246
+
247
+ #ifdef __cplusplus
248
+ }
249
+ #endif
250
+
251
+ #ifdef GB_INI_CPP
252
+ #if !defined(__cplusplus)
253
+ #error You need to compile as C++ for the C++ version of gb_ini.h to work
254
+ #endif
255
+
256
+ namespace gb
257
+ {
258
+ typedef gbIniError IniError;
259
+ typedef gbIniHandler IniHandler;
260
+
261
+ /* Just a copy but with the GB_ prefix stripped */
262
+ enum {
263
+ INI_ERROR_NONE = 0,
264
+
265
+ INI_ERROR_FILE_ERROR,
266
+ INI_ERROR_MISSING_SECTION_BRACKET,
267
+ INI_ERROR_ASSIGNMENT_MISSING,
268
+ INI_ERROR_HANDLER_ERROR
269
+
270
+ /* No need for enum count */
271
+ };
272
+
273
+ inline Ini_Error ini_parse(char const *filename, Ini_Handler *handler_func, void *data) { return gb_ini_parse(filename, handler_func, data); }
274
+ inline Ini_Error ini_parse(FILE *file, Ini_Handler *handler_func, void *data) { return gb_ini_parse_file(file, handler_func, data); }
275
+ inline char const *ini_error_string(const Ini_Error err) { return GB_ERROR_STRINGS[err.type]; }
276
+
277
+ } /* namespace gb */
278
+ #endif /* GB_INI_CPP */
279
+ #endif /* GB_INI_INCLUDE_GB_INI_H */
280
+
281
+ #ifdef GB_INI_IMPLEMENTATION
282
+ #include <ctype.h>
283
+ #include <string.h>
284
+
285
+ char const *GB_ERROR_STRINGS[GB_INI_ERROR_COUNT] = {
286
+ "",
287
+
288
+ "Error in opening file",
289
+ "Missing closing section bracket ']'",
290
+ "Missing assignment operator '='",
291
+ "Error in handler function",
292
+ };
293
+
294
+ static gbini_inline char*
295
+ gb__left_whitespace_skip(char const *str)
296
+ {
297
+ while (*str && isspace((unsigned char)(*str)))
298
+ str++;
299
+ return (char*)str;
300
+ }
301
+
302
+ static gbini_inline char*
303
+ gb__right_whitespace_strip(char* str)
304
+ {
305
+ char* end = str + strlen(str);
306
+ while (end > str && isspace((unsigned char)(*--end)))
307
+ *end = '\0';
308
+ return str;
309
+ }
310
+
311
+ static gbini_inline char*
312
+ gb__find_char_or_comment_in_string(char const *str, char c)
313
+ {
314
+ int was_whitespace = 0;
315
+ while (*str && *str != c && !(was_whitespace && *str == ';')) {
316
+ was_whitespace = isspace((unsigned char)(*str));
317
+ str++;
318
+ }
319
+
320
+ return (char*)str;
321
+ }
322
+
323
+ static gbini_inline char*
324
+ gb__string_copy(char* dst, char const *src, size_t size)
325
+ {
326
+ strncpy(dst, src, size);
327
+ dst[size - 1] = '\0';
328
+ return dst;
329
+ }
330
+
331
+
332
+ gbIniError
333
+ gb_ini_parse(char const *filename, gbIniHandler *handler_func, void *data)
334
+ {
335
+ gbIniError err = {GB_INI_ERROR_FILE_ERROR, 0};
336
+
337
+ FILE *file = fopen(filename, "r");
338
+ if (!file)
339
+ return err;
340
+
341
+ err = gb_ini_parse_file(file, handler_func, data);
342
+ fclose(file);
343
+ return err;
344
+ }
345
+
346
+ gbIniError
347
+ gb_ini_parse_file(FILE *file, gbIniHandler *handler_func, void *data)
348
+ {
349
+ char line[GB_INI_MAX_LINE_LENGTH] = "";
350
+ size_t line_num = 0;
351
+
352
+ char section[GB_INI_MAX_SECTION_LENGTH] = "";
353
+ char prev_name[GB_INI_MAX_NAME_LENGTH] = "";
354
+
355
+ char *start;
356
+ char *end;
357
+
358
+ struct gbIniError err = {GB_INI_ERROR_NONE, 0};
359
+
360
+ while (fgets(line, GB_INI_MAX_LINE_LENGTH, file) != 0) {
361
+ line_num++;
362
+
363
+ start = line;
364
+
365
+ #if GB_INI_CHECK_FOR_UTF8_BOM
366
+ /* Check for UTF-8 Byte Order Mark */
367
+ if (line_num == 1 &&
368
+ (unsigned char)start[0] == 0xef &&
369
+ (unsigned char)start[1] == 0xbb &&
370
+ (unsigned char)start[2] == 0xbf) {
371
+ start += 3;
372
+ }
373
+ #endif
374
+
375
+ start = gb__left_whitespace_skip(gb__right_whitespace_strip(start));
376
+
377
+ if (start[0] == ';' || start[0] == '#')
378
+ continue; /* Allow '#' and ';' comments at start of line */
379
+
380
+ if (start[0] == '[') { /* [section] */
381
+ end = gb__find_char_or_comment_in_string(start+1, ']');
382
+ if (*end == ']') {
383
+ char *sect = start + 1;
384
+ *end = '\0';
385
+ sect = gb__left_whitespace_skip(gb__right_whitespace_strip(sect));
386
+
387
+ gb__string_copy(section, sect, sizeof(section));
388
+ *prev_name = '\0';
389
+ } else if (!err.type) {
390
+ err.type = GB_INI_ERROR_MISSING_SECTION_BRACKET;
391
+ err.line_num = line_num;
392
+ }
393
+ } else if (start[0] && start[0] != ';') {
394
+ end = gb__find_char_or_comment_in_string(start, '=');
395
+ if (*end == '=') {
396
+ char *name, *value;
397
+ *end = '\0';
398
+ name = gb__right_whitespace_strip(start);
399
+ value = gb__left_whitespace_skip(end + 1);
400
+ end = gb__find_char_or_comment_in_string(value, '\0');
401
+ if (*end == ';')
402
+ *end = '\0';
403
+ gb__right_whitespace_strip(value);
404
+
405
+ gb__string_copy(prev_name, name, sizeof(prev_name));
406
+ if (!handler_func(data, section, name, value) && !err.type) {
407
+ err.type = GB_INI_ERROR_HANDLER_ERROR;
408
+ err.line_num = line_num;
409
+ }
410
+ } else if (!err.type) {
411
+ /* No '=' found on name=value line */
412
+ err.type = GB_INI_ERROR_ASSIGNMENT_MISSING;
413
+ err.line_num = line_num;
414
+ continue;
415
+ }
416
+ }
417
+
418
+ if (err.type)
419
+ break;
420
+ }
421
+
422
+ return err;
423
+ }
424
+
425
+ #endif /* GB_INI_IMPLEMENTATION */