LIRC libraries
Linux Infrared Remote Control
Loading...
Searching...
No Matches
ciniparser.c
Go to the documentation of this file.
1/* Copyright (c) 2000-2007 by Nicolas Devillard.
2 * Copyright (x) 2009 by Tim Post <tinkertim@gmail.com>
3 * MIT License
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
35#include <ctype.h>
36#include <ciniparser.h>
37
38#define ASCIILINESZ (1024)
39#define INI_INVALID_KEY ((char*)NULL)
40
44typedef enum _line_status_ {
45 LINE_UNPROCESSED,
46 LINE_ERROR,
47 LINE_EMPTY,
48 LINE_COMMENT,
49 LINE_SECTION,
50 LINE_VALUE
52
53
64static char* strlwc(const char* s)
65{
66 static char l[ASCIILINESZ + 1];
67 int i;
68
69 if (s == NULL)
70 return NULL;
71
72 for (i = 0; s[i] && i < ASCIILINESZ; i++)
73 l[i] = tolower(s[i]);
74 l[i] = '\0';
75 return l;
76}
77
90static char* strstrip(const char* s)
91{
92 static char l[ASCIILINESZ + 1];
93 unsigned int i, numspc;
94
95 if (s == NULL)
96 return NULL;
97
98 while (isspace(*s))
99 s++;
100
101 for (i = numspc = 0; s[i] && i < ASCIILINESZ; i++) {
102 l[i] = s[i];
103 if (isspace(l[i]))
104 numspc++;
105 else
106 numspc = 0;
107 }
108 l[i - numspc] = '\0';
109 return l;
110}
111
120static
121line_status ciniparser_line(char* input_line, char* section,
122 char* key, char* value)
123{
124 line_status sta = LINE_ERROR;
125 char line[ASCIILINESZ + 1];
126 int len;
127
128 strcpy(line, strstrip(input_line));
129 len = (int)strlen(line);
130
131 if (len < 1) {
132 /* Empty line */
133 sta = LINE_EMPTY;
134 } else if (line[0] == '#') {
135 /* Comment line */
136 sta = LINE_COMMENT;
137 } else if (line[0] == '[' && line[len - 1] == ']') {
138 /* Section name */
139 if (sscanf(line, "[%[^]]", section) == 1) {
140 strcpy(section, strstrip(section));
141 strcpy(section, strlwc(section));
142 sta = LINE_SECTION;
143 }
144 } else if (sscanf(line, "%[^=] = \"%[^\"]\"", key, value) == 2
145 || sscanf(line, "%[^=] = '%[^\']'", key, value) == 2
146 || sscanf(line, "%[^=] = %[^;#]", key, value) == 2) {
147 /* Usual key=value, with or without comments */
148 strcpy(key, strstrip(key));
149 strcpy(key, strlwc(key));
150 strcpy(value, strstrip(value));
151 /*
152 * sscanf cannot handle '' or "" as empty values
153 * this is done here
154 */
155 if (!strcmp(value, "\"\"") || (!strcmp(value, "''")))
156 value[0] = 0;
157 sta = LINE_VALUE;
158 } else if (sscanf(line, "%[^=] = %[;#]", key, value) == 2
159 || sscanf(line, "%[^=] %[=]", key, value) == 2) {
160 /*
161 * Special cases:
162 * key=
163 * key=;
164 * key=#
165 */
166 strcpy(key, strstrip(key));
167 strcpy(key, strlwc(key));
168 value[0] = 0;
169 sta = LINE_VALUE;
170 } else {
171 /* Generate syntax error */
172 sta = LINE_ERROR;
173 }
174 return sta;
175}
176
177/* The remaining public functions are documented in ciniparser.h */
178
180{
181 int i;
182 int nsec;
183
184 if (d == NULL)
185 return -1;
186
187 nsec = 0;
188 for (i = 0; i < d->size; i++) {
189 if (d->key[i] == NULL)
190 continue;
191 if (strchr(d->key[i], ':') == NULL)
192 nsec++;
193 }
194
195 return nsec;
196}
197
198const char* ciniparser_getsecname(dictionary* d, int n)
199{
200 int i;
201 int foundsec;
202
203 if (d == NULL || n < 0)
204 return NULL;
205
206 if (n == 0)
207 n++;
208
209 foundsec = 0;
210
211 for (i = 0; i < d->size; i++) {
212 if (d->key[i] == NULL)
213 continue;
214 if (!strchr(d->key[i], ':')) {
215 foundsec++;
216 if (foundsec >= n)
217 break;
218 }
219 }
220
221 if (foundsec == n)
222 return d->key[i];
223
224 return (char*)NULL;
225}
226
228{
229 int i;
230
231 if (d == NULL || f == NULL)
232 return;
233
234 for (i = 0; i < d->size; i++) {
235 if (d->key[i] == NULL)
236 continue;
237 if (d->val[i] != NULL)
238 fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
239 else
240 fprintf(f, "[%s]=UNDEF\n", d->key[i]);
241 }
242}
243
245{
246 int i, j;
247 char keym[ASCIILINESZ + 1];
248 int nsec;
249 const char* secname;
250 int seclen;
251
252 if (d == NULL || f == NULL)
253 return;
254
255 memset(keym, 0, ASCIILINESZ + 1);
256
257 nsec = ciniparser_getnsec(d);
258 if (nsec < 1) {
259 /* No section in file: dump all keys as they are */
260 for (i = 0; i < d->size; i++) {
261 if (d->key[i] == NULL)
262 continue;
263 fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
264 }
265 return;
266 }
267
268 for (i = 0; i < nsec; i++) {
269 secname = ciniparser_getsecname(d, i);
270 seclen = (int)strlen(secname);
271 fprintf(f, "\n[%s]\n", secname);
272 snprintf(keym, ASCIILINESZ + 1, "%s:", secname);
273 for (j = 0; j < d->size; j++) {
274 if (d->key[j] == NULL)
275 continue;
276 if (!strncmp(d->key[j], keym, seclen + 1)) {
277 fprintf(f, "%-30s = %s\n",
278 d->key[j] + seclen + 1,
279 d->val[j] ? d->val[j] : "");
280 }
281 }
282 }
283 fprintf(f, "\n");
284}
285
286const char* ciniparser_getstring(dictionary* d, const char* key, char* def)
287{
288 char* lc_key;
289 const char* sval;
290
291 if (d == NULL || key == NULL)
292 return def;
293
294 lc_key = strlwc(key);
295 sval = dictionary_get(d, lc_key, def);
296
297 return sval;
298}
299
300int ciniparser_getint(dictionary* d, const char* key, int notfound)
301{
302 const char* str;
303
304 str = ciniparser_getstring(d, key, INI_INVALID_KEY);
305
306 if (str == INI_INVALID_KEY)
307 return notfound;
308
309 return (int)strtol(str, NULL, 10);
310}
311
312double ciniparser_getdouble(dictionary* d, const char* key, double notfound)
313{
314 const char* str;
315
316 str = ciniparser_getstring(d, key, INI_INVALID_KEY);
317
318 if (str == INI_INVALID_KEY)
319 return notfound;
320
321 return atof(str);
322}
323
324int ciniparser_getboolean(dictionary* d, const char* key, int notfound)
325{
326 const char* c;
327 int ret;
328
329 c = ciniparser_getstring(d, key, INI_INVALID_KEY);
330 if (c == INI_INVALID_KEY)
331 return notfound;
332
333 switch (c[0]) {
334 case 'y': case 'Y': case '1': case 't': case 'T':
335 ret = 1;
336 break;
337 case 'n': case 'N': case '0': case 'f': case 'F':
338 ret = 0;
339 break;
340 default:
341 ret = notfound;
342 break;
343 }
344
345 return ret;
346}
347
348int ciniparser_find_entry(dictionary* ini, const char* entry)
349{
350 int found = 0;
351
352 if (ciniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY)
353 found = 1;
354
355 return found;
356}
357
358int ciniparser_set(dictionary* d, const char* entry, const char* val)
359{
360 return dictionary_set(d, strlwc(entry), val);
361}
362
363void ciniparser_unset(dictionary* ini, char* entry)
364{
365 dictionary_unset(ini, strlwc(entry));
366}
367
368dictionary* ciniparser_load(const char* ininame)
369{
370 FILE* in;
371 char line[ASCIILINESZ + 1];
372 char section[ASCIILINESZ + 1];
373 char key[ASCIILINESZ + 1];
374 char tmp[ASCIILINESZ + 1];
375 char val[ASCIILINESZ + 1];
376 int last = 0, len, lineno = 0, errs = 0;
377 dictionary* dict;
378
379 in = fopen(ininame, "r");
380 if (in == NULL) {
381 fprintf(stderr, "ciniparser: cannot open %s\n (ignored)",
382 ininame);
383 return NULL;
384 }
385
386 dict = dictionary_new(0);
387 if (!dict) {
388 fclose(in);
389 return NULL;
390 }
391
392 memset(line, 0, ASCIILINESZ + 1);
393 memset(section, 0, ASCIILINESZ + 1);
394 memset(key, 0, ASCIILINESZ + 1);
395 memset(val, 0, ASCIILINESZ + 1);
396 last = 0;
397
398 while (fgets(line + last, ASCIILINESZ - last, in) != NULL) {
399 lineno++;
400 len = (int)strlen(line) - 1;
401 /* Safety check against buffer overflows */
402 if (line[len] != '\n') {
403 fprintf(stderr,
404 "ciniparser: input line too long in %s (%d)\n",
405 ininame,
406 lineno);
407 dictionary_del(dict);
408 fclose(in);
409 return NULL;
410 }
411
412 /* Get rid of \n and spaces at end of line */
413 while ((len >= 0) &&
414 ((line[len] == '\n') || (isspace(line[len])))) {
415 line[len] = 0;
416 len--;
417 }
418
419 /* Detect multi-line */
420 if (len >= 0 && line[len] == '\\') {
421 /* Multi-line value */
422 last = len;
423 continue;
424 }
425
426 switch (ciniparser_line(line, section, key, val)) {
427 case LINE_EMPTY:
428 case LINE_COMMENT:
429 break;
430
431 case LINE_SECTION:
432 errs = dictionary_set(dict, section, NULL);
433 break;
434
435 case LINE_VALUE:
436 snprintf(tmp, ASCIILINESZ + 1, "%s:%s", section, key);
437 errs = dictionary_set(dict, tmp, val);
438 break;
439
440 case LINE_ERROR:
441 fprintf(stderr, "ciniparser: syntax error in %s (%d):\n",
442 ininame, lineno);
443 fprintf(stderr, "-> %s\n", line);
444 errs++;
445 break;
446
447 default:
448 break;
449 }
450 memset(line, 0, ASCIILINESZ);
451 last = 0;
452 if (errs < 0) {
453 fprintf(stderr, "ciniparser: memory allocation failure\n");
454 break;
455 }
456 }
457
458 if (errs) {
459 dictionary_del(dict);
460 dict = NULL;
461 }
462
463 fclose(in);
464
465 return dict;
466}
467
472
Parser for ini files.
enum _line_status_ line_status
This enum stores the status for each parsed line (internal use only).
int ciniparser_set(dictionary *d, const char *entry, const char *val)
Set an item in the dictionary.
Definition ciniparser.c:358
dictionary * ciniparser_load(const char *ininame)
Parse an ini file and return an allocated dictionary object.
Definition ciniparser.c:368
int ciniparser_getboolean(dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to a boolean.
Definition ciniparser.c:324
void dictionary_unset(dictionary *d, const char *key)
Delete a key in a dictionary.
Definition dictionary.c:206
_line_status_
This enum stores the status for each parsed line (internal use only).
Definition ciniparser.c:44
int ciniparser_getnsec(dictionary *d)
Get number of sections in a dictionary.
Definition ciniparser.c:179
int ciniparser_getint(dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to an int.
Definition ciniparser.c:300
const char * ciniparser_getsecname(dictionary *d, int n)
Get name for section n in a dictionary.
Definition ciniparser.c:198
dictionary * dictionary_new(int size)
Create a new dictionary object.
Definition dictionary.c:92
const char * dictionary_get(dictionary *d, const char *key, const char *def)
Get a value from a dictionary.
Definition dictionary.c:128
void dictionary_del(dictionary *d)
Delete a dictionary object.
Definition dictionary.c:109
int dictionary_set(dictionary *d, const char *key, const char *val)
Set a value in a dictionary.
Definition dictionary.c:147
double ciniparser_getdouble(dictionary *d, const char *key, double notfound)
Get the string associated to a key, convert to a double.
Definition ciniparser.c:312
void ciniparser_dump(dictionary *d, FILE *f)
Dump a dictionary to an opened file pointer.
Definition ciniparser.c:227
void ciniparser_unset(dictionary *ini, char *entry)
Delete an entry in a dictionary.
Definition ciniparser.c:363
void ciniparser_freedict(dictionary *d)
Free all memory associated to an ini dictionary.
Definition ciniparser.c:468
const char * ciniparser_getstring(dictionary *d, const char *key, char *def)
Get the string associated to a key.
Definition ciniparser.c:286
void ciniparser_dump_ini(dictionary *d, FILE *f)
Save a dictionary to a loadable ini file.
Definition ciniparser.c:244
int ciniparser_find_entry(dictionary *ini, const char *entry)
Finds out if a given entry exists in a dictionary.
Definition ciniparser.c:348
Dictionary object.
Definition dictionary.h:67