Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/dependencies/all/iniparser/iniparser.cpp
774 views
1
/*-------------------------------------------------------------------------*/
2
/**
3
@file iniparser.c
4
@author N. Devillard
5
@brief Parser for ini files.
6
*/
7
/*--------------------------------------------------------------------------*/
8
/*---------------------------- Includes ------------------------------------*/
9
#include <ctype.h>
10
#include <stdarg.h>
11
#include "iniparser.h"
12
#include "RSDK/Core/RetroEngine.hpp"
13
14
/*---------------------------- Defines -------------------------------------*/
15
#define ASCIILINESZ (1024)
16
#define INI_INVALID_KEY ((char*)-1)
17
18
/*---------------------------------------------------------------------------
19
Private to this module
20
---------------------------------------------------------------------------*/
21
/**
22
* This enum stores the status for each parsed line (internal use only).
23
*/
24
typedef enum _line_status_ {
25
LINE_UNPROCESSED,
26
LINE_ERROR,
27
LINE_EMPTY,
28
LINE_COMMENT,
29
LINE_SECTION,
30
LINE_VALUE
31
} line_status ;
32
33
/*-------------------------------------------------------------------------*/
34
/**
35
@brief Convert a string to lowercase.
36
@param in String to convert.
37
@param out Output buffer.
38
@param len Size of the out buffer.
39
@return ptr to the out buffer or NULL if an error occured.
40
41
This function convert a string into lowercase.
42
At most len - 1 elements of the input string will be converted.
43
*/
44
/*--------------------------------------------------------------------------*/
45
static const char * strlwc(const char * in, char *out, unsigned len)
46
{
47
unsigned i ;
48
//modified to NOT tolower
49
50
if (in==NULL || out == NULL || len==0) return NULL ;
51
i=0 ;
52
while (in[i] != '\0' && i < len-1) {
53
//out[i] = (char)tolower((int)in[i]);
54
out[i] = in[i];
55
i++ ;
56
}
57
out[i] = '\0';
58
return out ;
59
}
60
61
/*-------------------------------------------------------------------------*/
62
/**
63
@brief Duplicate a string
64
@param s String to duplicate
65
@return Pointer to a newly allocated string, to be freed with free()
66
67
This is a replacement for strdup(). This implementation is provided
68
for systems that do not have it.
69
*/
70
/*--------------------------------------------------------------------------*/
71
static char * xstrdup(const char * s)
72
{
73
char * t ;
74
size_t len ;
75
if (!s)
76
return NULL ;
77
78
len = strlen(s) + 1 ;
79
t = (char*) malloc(len) ;
80
if (t) {
81
memcpy(t, s, len) ;
82
}
83
return t ;
84
}
85
86
static unsigned strstrip(char * s)
87
{
88
char *last = NULL ;
89
char *dest = s;
90
91
if (s==NULL) return 0;
92
93
last = s + strlen(s);
94
while (isspace((int)*s) && *s) s++;
95
while (last > s) {
96
if (!isspace((int)*(last-1)))
97
break ;
98
last -- ;
99
}
100
*last = (char)0;
101
102
memmove(dest,s,last - s + 1);
103
return (unsigned)(last - s);
104
}
105
106
static int default_error_callback(const char *format, ...)
107
{
108
int ret;
109
va_list argptr;
110
va_start(argptr, format);
111
ret = vfprintf(stderr, format, argptr);
112
va_end(argptr);
113
return ret;
114
}
115
116
static int (*iniparser_error_callback)(const char*, ...) = default_error_callback;
117
118
void iniparser_set_error_callback(int (*errback)(const char *, ...))
119
{
120
if (errback) {
121
iniparser_error_callback = errback;
122
} else {
123
iniparser_error_callback = default_error_callback;
124
}
125
}
126
127
/*-------------------------------------------------------------------------*/
128
/**
129
@brief Get number of sections in a dictionary
130
@param d Dictionary to examine
131
@return int Number of sections found in dictionary
132
133
This function returns the number of sections found in a dictionary.
134
The test to recognize sections is done on the string stored in the
135
dictionary: a section name is given as "section" whereas a key is
136
stored as "section:key", thus the test looks for entries that do not
137
contain a colon.
138
139
This clearly fails in the case a section name contains a colon, but
140
this should simply be avoided.
141
142
This function returns -1 in case of error.
143
*/
144
/*--------------------------------------------------------------------------*/
145
int iniparser_getnsec(const dictionary * d)
146
{
147
int i ;
148
int nsec ;
149
150
if (d==NULL) return -1 ;
151
nsec=0 ;
152
for (i=0 ; i<d->size ; i++) {
153
if (d->key[i]==NULL)
154
continue ;
155
if (strchr(d->key[i], ':')==NULL) {
156
nsec ++ ;
157
}
158
}
159
return nsec ;
160
}
161
162
/*-------------------------------------------------------------------------*/
163
/**
164
@brief Get name for section n in a dictionary.
165
@param d Dictionary to examine
166
@param n Section number (from 0 to nsec-1).
167
@return Pointer to char string
168
169
This function locates the n-th section in a dictionary and returns
170
its name as a pointer to a string statically allocated inside the
171
dictionary. Do not free or modify the returned string!
172
173
This function returns NULL in case of error.
174
*/
175
/*--------------------------------------------------------------------------*/
176
const char * iniparser_getsecname(const dictionary * d, int n)
177
{
178
int i ;
179
int foundsec ;
180
181
if (d==NULL || n<0) return NULL ;
182
foundsec=0 ;
183
for (i=0 ; i<d->size ; i++) {
184
if (d->key[i]==NULL)
185
continue ;
186
if (strchr(d->key[i], ':')==NULL) {
187
foundsec++ ;
188
if (foundsec>n)
189
break ;
190
}
191
}
192
if (foundsec<=n) {
193
return NULL ;
194
}
195
return d->key[i] ;
196
}
197
198
void iniparser_dump(const dictionary * d, FILE * f)
199
{
200
int i ;
201
202
if (d==NULL || f==NULL) return ;
203
for (i=0 ; i<d->size ; i++) {
204
if (d->key[i]==NULL)
205
continue ;
206
if (d->val[i]!=NULL) {
207
fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
208
} else {
209
fprintf(f, "[%s]=UNDEF\n", d->key[i]);
210
}
211
}
212
return ;
213
}
214
215
void iniparser_dump_ini(const dictionary * d, FILE * f)
216
{
217
int i ;
218
int nsec ;
219
const char * secname ;
220
221
if (d==NULL || f==NULL) return ;
222
223
nsec = iniparser_getnsec(d);
224
if (nsec<1) {
225
/* No section in file: dump all keys as they are */
226
for (i=0 ; i<d->size ; i++) {
227
if (d->key[i]==NULL)
228
continue ;
229
fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
230
}
231
return ;
232
}
233
for (i=0 ; i<nsec ; i++) {
234
secname = iniparser_getsecname(d, i) ;
235
iniparser_dumpsection_ini(d, secname, f);
236
}
237
fprintf(f, "\n");
238
return ;
239
}
240
241
void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
242
{
243
int j ;
244
char keym[ASCIILINESZ+1];
245
int seclen ;
246
247
if (d==NULL || f==NULL) return ;
248
if (! iniparser_find_entry(d, s)) return ;
249
250
seclen = (int)strlen(s);
251
fprintf(f, "\n[%s]\n", s);
252
sprintf(keym, "%s:", s);
253
for (j=0 ; j<d->size ; j++) {
254
if (d->key[j]==NULL)
255
continue ;
256
if (!strncmp(d->key[j], keym, seclen+1)) {
257
fprintf(f,
258
"%-30s = %s\n",
259
d->key[j]+seclen+1,
260
d->val[j] ? d->val[j] : "");
261
}
262
}
263
fprintf(f, "\n");
264
return ;
265
}
266
267
/*-------------------------------------------------------------------------*/
268
/**
269
@brief Get the number of keys in a section of a dictionary.
270
@param d Dictionary to examine
271
@param s Section name of dictionary to examine
272
@return Number of keys in section
273
*/
274
/*--------------------------------------------------------------------------*/
275
int iniparser_getsecnkeys(const dictionary * d, const char * s)
276
{
277
int seclen, nkeys ;
278
char keym[ASCIILINESZ+1];
279
int j ;
280
281
nkeys = 0;
282
283
if (d==NULL) return nkeys;
284
if (! iniparser_find_entry(d, s)) return nkeys;
285
286
seclen = (int)strlen(s);
287
strlwc(s, keym, sizeof(keym));
288
keym[seclen] = ':';
289
290
for (j=0 ; j<d->size ; j++) {
291
if (d->key[j]==NULL)
292
continue ;
293
if (!strncmp(d->key[j], keym, seclen+1))
294
nkeys++;
295
}
296
297
return nkeys;
298
299
}
300
301
/*-------------------------------------------------------------------------*/
302
/**
303
@brief Get the number of keys in a section of a dictionary.
304
@param d Dictionary to examine
305
@param s Section name of dictionary to examine
306
@param keys Already allocated array to store the keys in
307
@return The pointer passed as `keys` argument or NULL in case of error
308
309
This function queries a dictionary and finds all keys in a given section.
310
The keys argument should be an array of pointers which size has been
311
determined by calling `iniparser_getsecnkeys` function prior to this one.
312
313
Each pointer in the returned char pointer-to-pointer is pointing to
314
a string allocated in the dictionary; do not free or modify them.
315
*/
316
/*--------------------------------------------------------------------------*/
317
const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
318
{
319
int i, j, seclen ;
320
char keym[ASCIILINESZ+1];
321
322
if (d==NULL || keys==NULL) return NULL;
323
if (! iniparser_find_entry(d, s)) return NULL;
324
325
seclen = (int)strlen(s);
326
strlwc(s, keym, sizeof(keym));
327
keym[seclen] = ':';
328
329
i = 0;
330
331
for (j=0 ; j<d->size ; j++) {
332
if (d->key[j]==NULL)
333
continue ;
334
if (!strncmp(d->key[j], keym, seclen+1)) {
335
keys[i] = d->key[j];
336
i++;
337
}
338
}
339
340
return keys;
341
}
342
343
/*-------------------------------------------------------------------------*/
344
/**
345
@brief Get the string associated to a key
346
@param d Dictionary to search
347
@param key Key string to look for
348
@param def Default value to return if key not found.
349
@return pointer to statically allocated character string
350
351
This function queries a dictionary for a key. A key as read from an
352
ini file is given as "section:key". If the key cannot be found,
353
the pointer passed as 'def' is returned.
354
The returned char pointer is pointing to a string allocated in
355
the dictionary, do not free or modify it.
356
*/
357
/*--------------------------------------------------------------------------*/
358
const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
359
{
360
const char * lc_key ;
361
const char * sval ;
362
char tmp_str[ASCIILINESZ+1];
363
364
if (d==NULL || key==NULL)
365
return def ;
366
367
lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
368
sval = dictionary_get(d, lc_key, def);
369
return sval ;
370
}
371
372
/*-------------------------------------------------------------------------*/
373
/**
374
@brief Get the string associated to a key, convert to an long int
375
@param d Dictionary to search
376
@param key Key string to look for
377
@param notfound Value to return in case of error
378
@return long integer
379
380
This function queries a dictionary for a key. A key as read from an
381
ini file is given as "section:key". If the key cannot be found,
382
the notfound value is returned.
383
384
Supported values for integers include the usual C notation
385
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
386
are supported. Examples:
387
388
"42" -> 42
389
"042" -> 34 (octal -> decimal)
390
"0x42" -> 66 (hexa -> decimal)
391
392
Warning: the conversion may overflow in various ways. Conversion is
393
totally outsourced to strtol(), see the associated man page for overflow
394
handling.
395
396
Credits: Thanks to A. Becker for suggesting strtol()
397
*/
398
/*--------------------------------------------------------------------------*/
399
long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound)
400
{
401
const char * str ;
402
403
str = iniparser_getstring(d, key, INI_INVALID_KEY);
404
if (str==INI_INVALID_KEY) return notfound ;
405
return strtol(str, NULL, 0);
406
}
407
408
409
/*-------------------------------------------------------------------------*/
410
/**
411
@brief Get the string associated to a key, convert to an int
412
@param d Dictionary to search
413
@param key Key string to look for
414
@param notfound Value to return in case of error
415
@return integer
416
417
This function queries a dictionary for a key. A key as read from an
418
ini file is given as "section:key". If the key cannot be found,
419
the notfound value is returned.
420
421
Supported values for integers include the usual C notation
422
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
423
are supported. Examples:
424
425
"42" -> 42
426
"042" -> 34 (octal -> decimal)
427
"0x42" -> 66 (hexa -> decimal)
428
429
Warning: the conversion may overflow in various ways. Conversion is
430
totally outsourced to strtol(), see the associated man page for overflow
431
handling.
432
433
Credits: Thanks to A. Becker for suggesting strtol()
434
*/
435
/*--------------------------------------------------------------------------*/
436
int iniparser_getint(const dictionary * d, const char * key, int notfound)
437
{
438
return (int)iniparser_getlongint(d, key, notfound);
439
}
440
441
/*-------------------------------------------------------------------------*/
442
/**
443
@brief Get the string associated to a key, convert to a double
444
@param d Dictionary to search
445
@param key Key string to look for
446
@param notfound Value to return in case of error
447
@return double
448
449
This function queries a dictionary for a key. A key as read from an
450
ini file is given as "section:key". If the key cannot be found,
451
the notfound value is returned.
452
*/
453
/*--------------------------------------------------------------------------*/
454
double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
455
{
456
const char * str ;
457
458
str = iniparser_getstring(d, key, INI_INVALID_KEY);
459
if (str==INI_INVALID_KEY) return notfound ;
460
return atof(str);
461
}
462
463
/*-------------------------------------------------------------------------*/
464
/**
465
@brief Get the string associated to a key, convert to a boolean
466
@param d Dictionary to search
467
@param key Key string to look for
468
@param notfound Value to return in case of error
469
@return integer
470
471
This function queries a dictionary for a key. A key as read from an
472
ini file is given as "section:key". If the key cannot be found,
473
the notfound value is returned.
474
475
A true boolean is found if one of the following is matched:
476
477
- A string starting with 'y'
478
- A string starting with 'Y'
479
- A string starting with 't'
480
- A string starting with 'T'
481
- A string starting with '1'
482
483
A false boolean is found if one of the following is matched:
484
485
- A string starting with 'n'
486
- A string starting with 'N'
487
- A string starting with 'f'
488
- A string starting with 'F'
489
- A string starting with '0'
490
491
The notfound value returned if no boolean is identified, does not
492
necessarily have to be 0 or 1.
493
*/
494
/*--------------------------------------------------------------------------*/
495
int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
496
{
497
int ret ;
498
const char * c ;
499
500
c = iniparser_getstring(d, key, INI_INVALID_KEY);
501
if (c==INI_INVALID_KEY) return notfound ;
502
if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
503
ret = 1 ;
504
} else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
505
ret = 0 ;
506
} else {
507
ret = notfound ;
508
}
509
return ret;
510
}
511
512
int iniparser_find_entry(const dictionary * ini, const char * entry)
513
{
514
int found=0 ;
515
if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
516
found = 1 ;
517
}
518
return found ;
519
}
520
521
int iniparser_set(dictionary * ini, const char * entry, const char * val)
522
{
523
char tmp_str[ASCIILINESZ+1];
524
return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ;
525
}
526
527
void iniparser_unset(dictionary * ini, const char * entry)
528
{
529
char tmp_str[ASCIILINESZ+1];
530
dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
531
}
532
533
static line_status iniparser_line(
534
const char * input_line,
535
char * section,
536
char * key,
537
char * value)
538
{
539
line_status sta ;
540
char * line = NULL;
541
size_t len ;
542
543
line = xstrdup(input_line);
544
len = strstrip(line);
545
546
sta = LINE_UNPROCESSED ;
547
if (len<1) {
548
/* Empty line */
549
sta = LINE_EMPTY ;
550
} else if (line[0]=='#' || line[0]==';') {
551
/* Comment line */
552
sta = LINE_COMMENT ;
553
} else if (line[0]=='[' && line[len-1]==']') {
554
/* Section name */
555
sscanf(line, "[%[^]]", section);
556
strstrip(section);
557
strlwc(section, section, (unsigned)len);
558
sta = LINE_SECTION ;
559
} else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
560
|| sscanf (line, "%[^=] = '%[^\']'", key, value) == 2) {
561
/* Usual key=value with quotes, with or without comments */
562
strstrip(key);
563
strlwc(key, key, (unsigned)len);
564
/* Don't strip spaces from values surrounded with quotes */
565
sta = LINE_VALUE ;
566
} else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
567
/* Usual key=value without quotes, with or without comments */
568
strstrip(key);
569
strlwc(key, key, (unsigned)len);
570
strstrip(value);
571
/*
572
* sscanf cannot handle '' or "" as empty values
573
* this is done here
574
*/
575
if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
576
value[0]=0 ;
577
}
578
sta = LINE_VALUE ;
579
} else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
580
|| sscanf(line, "%[^=] %[=]", key, value) == 2) {
581
/*
582
* Special cases:
583
* key=
584
* key=;
585
* key=#
586
*/
587
strstrip(key);
588
strlwc(key, key, (unsigned)len);
589
value[0]=0 ;
590
sta = LINE_VALUE ;
591
} else {
592
/* Generate syntax error */
593
sta = LINE_ERROR ;
594
}
595
596
free(line);
597
return sta ;
598
}
599
600
/*-------------------------------------------------------------------------*/
601
/**
602
@brief Parse an ini file and return an allocated dictionary object
603
@param ininame Name of the ini file to read.
604
@return Pointer to newly allocated dictionary
605
606
This is the parser for ini files. This function is called, providing
607
the name of the file to be read. It returns a dictionary object that
608
should not be accessed directly, but through accessor functions
609
instead.
610
611
The returned dictionary must be freed using iniparser_freedict().
612
*/
613
/*--------------------------------------------------------------------------*/
614
615
#ifndef __ANDROID__
616
#undef fOpen
617
#define fOpen fopen
618
#endif
619
620
dictionary * iniparser_load(const char * ininame)
621
{
622
FILE * in ;
623
624
char line [ASCIILINESZ+1] ;
625
char section [ASCIILINESZ+1] ;
626
char key [ASCIILINESZ+1] ;
627
char tmp [(ASCIILINESZ * 2) + 2] ;
628
char val [ASCIILINESZ+1] ;
629
630
int last=0 ;
631
int len ;
632
int lineno=0 ;
633
int errs=0;
634
int mem_err=0;
635
636
dictionary * dict ;
637
638
if ((in=fOpen(ininame, "r"))==NULL) {
639
iniparser_error_callback("iniparser: cannot open %s\n", ininame);
640
return NULL ;
641
}
642
643
dict = dictionary_new(0) ;
644
if (!dict) {
645
fclose(in);
646
return NULL ;
647
}
648
649
memset(line, 0, ASCIILINESZ);
650
memset(section, 0, ASCIILINESZ);
651
memset(key, 0, ASCIILINESZ);
652
memset(val, 0, ASCIILINESZ);
653
last=0 ;
654
655
while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
656
lineno++ ;
657
len = (int)strlen(line)-1;
658
if (len<=0)
659
continue;
660
/* Safety check against buffer overflows */
661
if (line[len]!='\n' && !feof(in)) {
662
iniparser_error_callback(
663
"iniparser: input line too long in %s (%d)\n",
664
ininame,
665
lineno);
666
dictionary_del(dict);
667
fclose(in);
668
return NULL ;
669
}
670
/* Get rid of \n and spaces at end of line */
671
while ((len>=0) &&
672
((line[len]=='\n') || (isspace(line[len])))) {
673
line[len]=0 ;
674
len-- ;
675
}
676
if (len < 0) { /* Line was entirely \n and/or spaces */
677
len = 0;
678
}
679
/* Detect multi-line */
680
if (line[len]=='\\') {
681
/* Multi-line value */
682
last=len ;
683
continue ;
684
} else {
685
last=0 ;
686
}
687
switch (iniparser_line(line, section, key, val)) {
688
case LINE_EMPTY:
689
case LINE_COMMENT:
690
break ;
691
692
case LINE_SECTION:
693
mem_err = dictionary_set(dict, section, NULL);
694
break ;
695
696
case LINE_VALUE:
697
sprintf(tmp, "%s:%s", section, key);
698
mem_err = dictionary_set(dict, tmp, val);
699
break ;
700
701
case LINE_ERROR:
702
iniparser_error_callback(
703
"iniparser: syntax error in %s (%d):\n-> %s\n",
704
ininame,
705
lineno,
706
line);
707
errs++ ;
708
break;
709
710
default:
711
break ;
712
}
713
memset(line, 0, ASCIILINESZ);
714
last=0;
715
if (mem_err<0) {
716
iniparser_error_callback("iniparser: memory allocation failure\n");
717
break ;
718
}
719
}
720
if (errs) {
721
dictionary_del(dict);
722
dict = NULL ;
723
}
724
fclose(in);
725
return dict ;
726
}
727
728
void iniparser_freedict(dictionary * d)
729
{
730
dictionary_del(d);
731
}
732
733