LIRC libraries
LinuxInfraredRemoteControl
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Groups Pages
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 
44 typedef enum _line_status_ {
45  LINE_UNPROCESSED,
46  LINE_ERROR,
47  LINE_EMPTY,
48  LINE_COMMENT,
49  LINE_SECTION,
50  LINE_VALUE
51 } line_status;
52 
53 
64 static 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 
90 static 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 
120 static
121 line_status ciniparser_line(char *input_line, char *section,
122  char *key, char *value)
123 {
124  line_status sta;
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  sscanf(line, "[%[^]]", section);
140  strcpy(section, strstrip(section));
141  strcpy(section, strlwc(section));
142  sta = LINE_SECTION;
143  } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
144  || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
145  || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
146  /* Usual key=value, with or without comments */
147  strcpy(key, strstrip(key));
148  strcpy(key, strlwc(key));
149  strcpy(value, strstrip(value));
150  /*
151  * sscanf cannot handle '' or "" as empty values
152  * this is done here
153  */
154  if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
155  value[0] = 0;
156  }
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 
196  return nsec;
197 }
198 
199 const char *ciniparser_getsecname(dictionary *d, int n)
200 {
201  int i;
202  int foundsec;
203 
204  if (d == NULL || n < 0)
205  return NULL;
206 
207  if (n == 0)
208  n ++;
209 
210  foundsec = 0;
211 
212  for (i = 0; i < d->size; i++) {
213  if (d->key[i] == NULL)
214  continue;
215  if (! strchr(d->key[i], ':')) {
216  foundsec++;
217  if (foundsec >= n)
218  break;
219  }
220  }
221 
222  if (foundsec == n) {
223  return d->key[i];
224  }
225 
226  return (char *) NULL;
227 }
228 
229 void ciniparser_dump(dictionary *d, FILE *f)
230 {
231  int i;
232 
233  if (d == NULL || f == NULL)
234  return;
235 
236  for (i = 0; i < d->size; i++) {
237  if (d->key[i] == NULL)
238  continue;
239  if (d->val[i] != NULL) {
240  fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
241  } else {
242  fprintf(f, "[%s]=UNDEF\n", d->key[i]);
243  }
244  }
245 
246  return;
247 }
248 
250 {
251  int i, j;
252  char keym[ASCIILINESZ+1];
253  int nsec;
254  const char *secname;
255  int seclen;
256 
257  if (d == NULL || f == NULL)
258  return;
259 
260  memset(keym, 0, ASCIILINESZ + 1);
261 
262  nsec = ciniparser_getnsec(d);
263  if (nsec < 1) {
264  /* No section in file: dump all keys as they are */
265  for (i = 0; i < d->size; i++) {
266  if (d->key[i] == NULL)
267  continue;
268  fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
269  }
270  return;
271  }
272 
273  for (i = 0; i < nsec; i++) {
274  secname = ciniparser_getsecname(d, i);
275  seclen = (int)strlen(secname);
276  fprintf(f, "\n[%s]\n", secname);
277  snprintf(keym, ASCIILINESZ + 1, "%s:", secname);
278  for (j = 0; j < d->size; j++) {
279  if (d->key[j] == NULL)
280  continue;
281  if (!strncmp(d->key[j], keym, seclen+1)) {
282  fprintf(f, "%-30s = %s\n",
283  d->key[j]+seclen+1,
284  d->val[j] ? d->val[j] : "");
285  }
286  }
287  }
288  fprintf(f, "\n");
289 
290  return;
291 }
292 
293 const char *ciniparser_getstring(dictionary *d, const char *key, char *def)
294 {
295  char *lc_key;
296  const char *sval;
297 
298  if (d == NULL || key == NULL)
299  return def;
300 
301  lc_key = strlwc(key);
302  sval = dictionary_get(d, lc_key, def);
303 
304  return sval;
305 }
306 
307 int ciniparser_getint(dictionary *d, const char *key, int notfound)
308 {
309  const char *str;
310 
311  str = ciniparser_getstring(d, key, INI_INVALID_KEY);
312 
313  if (str == INI_INVALID_KEY)
314  return notfound;
315 
316  return (int) strtol(str, NULL, 10);
317 }
318 
319 double ciniparser_getdouble(dictionary *d, const char *key, double notfound)
320 {
321  const char *str;
322 
323  str = ciniparser_getstring(d, key, INI_INVALID_KEY);
324 
325  if (str == INI_INVALID_KEY)
326  return notfound;
327 
328  return atof(str);
329 }
330 
331 int ciniparser_getboolean(dictionary *d, const char *key, int notfound)
332 {
333  const char *c;
334  int ret;
335 
336  c = ciniparser_getstring(d, key, INI_INVALID_KEY);
337  if (c == INI_INVALID_KEY)
338  return notfound;
339 
340  switch(c[0]) {
341  case 'y': case 'Y': case '1': case 't': case 'T':
342  ret = 1;
343  break;
344  case 'n': case 'N': case '0': case 'f': case 'F':
345  ret = 0;
346  break;
347  default:
348  ret = notfound;
349  break;
350  }
351 
352  return ret;
353 }
354 
355 int ciniparser_find_entry(dictionary *ini, const char *entry)
356 {
357  int found = 0;
358 
359  if (ciniparser_getstring(ini, entry, INI_INVALID_KEY) != INI_INVALID_KEY) {
360  found = 1;
361  }
362 
363  return found;
364 }
365 
366 int ciniparser_set(dictionary *d, const char *entry, const char *val)
367 {
368  return dictionary_set(d, strlwc(entry), val);
369 }
370 
371 void ciniparser_unset(dictionary *ini, char *entry)
372 {
373  dictionary_unset(ini, strlwc(entry));
374 }
375 
376 dictionary *ciniparser_load(const char *ininame)
377 {
378  FILE *in;
379  char line[ASCIILINESZ+1];
380  char section[ASCIILINESZ+1];
381  char key[ASCIILINESZ+1];
382  char tmp[ASCIILINESZ+1];
383  char val[ASCIILINESZ+1];
384  int last = 0, len, lineno = 0, errs = 0;
385  dictionary *dict;
386 
387  if ((in = fopen(ininame, "r")) == NULL) {
388  fprintf(stderr, "ciniparser: cannot open %s\n (ignored)",
389  ininame);
390  return NULL;
391  }
392 
393  dict = dictionary_new(0);
394  if (!dict) {
395  fclose(in);
396  return NULL;
397  }
398 
399  memset(line, 0, ASCIILINESZ + 1);
400  memset(section, 0, ASCIILINESZ + 1);
401  memset(key, 0, ASCIILINESZ + 1);
402  memset(val, 0, ASCIILINESZ + 1);
403  last = 0;
404 
405  while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
406  lineno++;
407  len = (int) strlen(line)-1;
408  /* Safety check against buffer overflows */
409  if (line[len] != '\n') {
410  fprintf(stderr,
411  "ciniparser: input line too long in %s (%d)\n",
412  ininame,
413  lineno);
414  dictionary_del(dict);
415  fclose(in);
416  return NULL;
417  }
418 
419  /* Get rid of \n and spaces at end of line */
420  while ((len >= 0) &&
421  ((line[len] == '\n') || (isspace(line[len])))) {
422  line[len] = 0;
423  len--;
424  }
425 
426  /* Detect multi-line */
427  if (len >= 0 && line[len] == '\\') {
428  /* Multi-line value */
429  last = len;
430  continue;
431  }
432 
433  switch (ciniparser_line(line, section, key, val)) {
434  case LINE_EMPTY:
435  case LINE_COMMENT:
436  break;
437 
438  case LINE_SECTION:
439  errs = dictionary_set(dict, section, NULL);
440  break;
441 
442  case LINE_VALUE:
443  snprintf(tmp, ASCIILINESZ + 1, "%s:%s", section, key);
444  errs = dictionary_set(dict, tmp, val);
445  break;
446 
447  case LINE_ERROR:
448  fprintf(stderr, "ciniparser: syntax error in %s (%d):\n",
449  ininame, lineno);
450  fprintf(stderr, "-> %s\n", line);
451  errs++;
452  break;
453 
454  default:
455  break;
456  }
457  memset(line, 0, ASCIILINESZ);
458  last = 0;
459  if (errs < 0) {
460  fprintf(stderr, "ciniparser: memory allocation failure\n");
461  break;
462  }
463  }
464 
465  if (errs) {
466  dictionary_del(dict);
467  dict = NULL;
468  }
469 
470  fclose(in);
471 
472  return dict;
473 }
474 
476 {
477  dictionary_del(d);
478 }
479 
const char * ciniparser_getstring(dictionary *d, const char *key, char *def)
Get the string associated to a key.
Definition: ciniparser.c:293
int dictionary_set(dictionary *d, const char *key, const char *val)
Set a value in a dictionary.
Definition: dictionary.c:149
dictionary * ciniparser_load(const char *ininame)
Parse an ini file and return an allocated dictionary object.
Definition: ciniparser.c:376
void ciniparser_dump_ini(dictionary *d, FILE *f)
Save a dictionary to a loadable ini file.
Definition: ciniparser.c:249
int ciniparser_getint(dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to an int.
Definition: ciniparser.c:307
const char * dictionary_get(dictionary *d, const char *key, const char *def)
Get a value from a dictionary.
Definition: dictionary.c:129
dictionary * dictionary_new(int size)
Create a new dictionary object.
Definition: dictionary.c:93
void dictionary_del(dictionary *d)
Delete a dictionary object.
Definition: dictionary.c:110
void ciniparser_freedict(dictionary *d)
Free all memory associated to an ini dictionary.
Definition: ciniparser.c:475
int ciniparser_set(dictionary *d, const char *entry, const char *val)
Set an item in the dictionary.
Definition: ciniparser.c:366
int ciniparser_find_entry(dictionary *ini, const char *entry)
Finds out if a given entry exists in a dictionary.
Definition: ciniparser.c:355
void ciniparser_unset(dictionary *ini, char *entry)
Delete an entry in a dictionary.
Definition: ciniparser.c:371
double ciniparser_getdouble(dictionary *d, const char *key, double notfound)
Get the string associated to a key, convert to a double.
Definition: ciniparser.c:319
enum _line_status_ line_status
void dictionary_unset(dictionary *d, const char *key)
Delete a key in a dictionary.
Definition: dictionary.c:209
const char * ciniparser_getsecname(dictionary *d, int n)
Get name for section n in a dictionary.
Definition: ciniparser.c:199
void ciniparser_dump(dictionary *d, FILE *f)
Dump a dictionary to an opened file pointer.
Definition: ciniparser.c:229
_line_status_
Definition: ciniparser.c:44
Dictionary object.
Definition: dictionary.h:67
int ciniparser_getnsec(dictionary *d)
Get number of sections in a dictionary.
Definition: ciniparser.c:179
Parser for ini files.
int ciniparser_getboolean(dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to a boolean.
Definition: ciniparser.c:331