KTH framework for Nek5000 toolboxes; testing version  0.0.1
iniparser.c
Go to the documentation of this file.
1 
2 /*-------------------------------------------------------------------------*/
8 /*--------------------------------------------------------------------------*/
9 /*---------------------------- Includes ------------------------------------*/
10 #include <ctype.h>
11 #include "iniparser.h"
12 
13 /*---------------------------- Defines -------------------------------------*/
14 #define ASCIILINESZ (1024)
15 #define INI_INVALID_KEY ((char*)-1)
16 
17 /*---------------------------------------------------------------------------
18  Private to this module
19  ---------------------------------------------------------------------------*/
23 typedef enum _line_status_ {
31 
32 /*-------------------------------------------------------------------------*/
43 /*--------------------------------------------------------------------------*/
44 const char * strlwc(const char * in, char *out, unsigned len)
45 {
46  unsigned i ;
47 
48  if (in==NULL || out == NULL || len==0) return NULL ;
49  i=0 ;
50  while (in[i] != '\0' && i < len-1) {
51  out[i] = (char)tolower((int)in[i]);
52  i++ ;
53  }
54  out[i] = '\0';
55  return out ;
56 }
57 
58 /*-------------------------------------------------------------------------*/
67 /*--------------------------------------------------------------------------*/
68 static char * xstrdup(const char * s)
69 {
70  char * t ;
71  size_t len ;
72  if (!s)
73  return NULL ;
74 
75  len = strlen(s) + 1 ;
76  t = (char*) malloc(len) ;
77  if (t) {
78  memcpy(t, s, len) ;
79  }
80  return t ;
81 }
82 
83 /*-------------------------------------------------------------------------*/
89 /*--------------------------------------------------------------------------*/
90 unsigned strstrip(char * s)
91 {
92  char *last = NULL ;
93  char *dest = s;
94 
95  if (s==NULL) return 0;
96 
97  last = s + strlen(s);
98  while (isspace((int)*s) && *s) s++;
99  while (last > s) {
100  if (!isspace((int)*(last-1)))
101  break ;
102  last -- ;
103  }
104  *last = (char)0;
105 
106  memmove(dest,s,last - s + 1);
107  return last - s;
108 }
109 
110 /*-------------------------------------------------------------------------*/
127 /*--------------------------------------------------------------------------*/
129 {
130  int i ;
131  int nsec ;
132 
133  if (d==NULL) return -1 ;
134  nsec=0 ;
135  for (i=0 ; i<d->size ; i++) {
136  if (d->key[i]==NULL)
137  continue ;
138  if (strchr(d->key[i], ':')==NULL) {
139  nsec ++ ;
140  }
141  }
142  return nsec ;
143 }
144 
145 /*-------------------------------------------------------------------------*/
158 /*--------------------------------------------------------------------------*/
159 const char * iniparser_getsecname(const dictionary * d, int n)
160 {
161  int i ;
162  int foundsec ;
163 
164  if (d==NULL || n<0) return NULL ;
165  foundsec=0 ;
166  for (i=0 ; i<d->size ; i++) {
167  if (d->key[i]==NULL)
168  continue ;
169  if (strchr(d->key[i], ':')==NULL) {
170  foundsec++ ;
171  if (foundsec>n)
172  break ;
173  }
174  }
175  if (foundsec<=n) {
176  return NULL ;
177  }
178  return d->key[i] ;
179 }
180 
181 /*-------------------------------------------------------------------------*/
193 /*--------------------------------------------------------------------------*/
194 void iniparser_dump(const dictionary * d, FILE * f)
195 {
196  int i ;
197 
198  if (d==NULL || f==NULL) return ;
199  for (i=0 ; i<d->size ; i++) {
200  if (d->key[i]==NULL) continue ;
201  fprintf(f, "%s = [%s]\n", d->key[i], d->val[i]);
202  }
203 
204  fflush(stdout);
205  return ;
206 }
207 
208 /*-------------------------------------------------------------------------*/
218 /*--------------------------------------------------------------------------*/
219 void iniparser_dump_ini(const dictionary * d, FILE * f)
220 {
221  int i ;
222  int nsec ;
223  const char * secname ;
224 
225  if (d==NULL || f==NULL) return ;
226 
227  nsec = iniparser_getnsec(d);
228  if (nsec<1) {
229  /* No section in file: dump all keys as they are */
230  for (i=0 ; i<d->size ; i++) {
231  if (d->key[i]==NULL)
232  continue ;
233  fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
234  }
235  return ;
236  }
237  for (i=0 ; i<nsec ; i++) {
238  secname = iniparser_getsecname(d, i) ;
239  iniparser_dumpsection_ini(d, secname, f);
240  }
241  fprintf(f, "\n");
242  return ;
243 }
244 
245 /*-------------------------------------------------------------------------*/
256 /*--------------------------------------------------------------------------*/
257 void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f)
258 {
259  int j ;
260  char keym[ASCIILINESZ+1];
261  int seclen ;
262 
263  if (d==NULL || f==NULL) return ;
264  if (! iniparser_find_entry(d, s)) return ;
265 
266  seclen = (int)strlen(s);
267  fprintf(f, "\n[%s]\n", s);
268  sprintf(keym, "%s:", s);
269  for (j=0 ; j<d->size ; j++) {
270  if (d->key[j]==NULL)
271  continue ;
272  if (!strncmp(d->key[j], keym, seclen+1)) {
273  fprintf(f,
274  "%-30s = %s\n",
275  d->key[j]+seclen+1,
276  d->val[j] ? d->val[j] : "");
277  }
278  }
279  fprintf(f, "\n");
280  return ;
281 }
282 
283 /*-------------------------------------------------------------------------*/
290 /*--------------------------------------------------------------------------*/
291 int iniparser_getsecnkeys(const dictionary * d, const char * s)
292 {
293  int seclen, nkeys ;
294  char keym[ASCIILINESZ+1];
295  int j ;
296 
297  nkeys = 0;
298 
299  if (d==NULL) return nkeys;
300  if (! iniparser_find_entry(d, s)) return nkeys;
301 
302  seclen = (int)strlen(s);
303  sprintf(keym, "%s:", s);
304 
305  for (j=0 ; j<d->size ; j++) {
306  if (d->key[j]==NULL)
307  continue ;
308  if (!strncmp(d->key[j], keym, seclen+1))
309  nkeys++;
310  }
311 
312  return nkeys;
313 
314 }
315 
316 /*-------------------------------------------------------------------------*/
331 /*--------------------------------------------------------------------------*/
332 const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys)
333 {
334  int i, j, seclen ;
335  char keym[ASCIILINESZ+1];
336 
337  if (d==NULL || keys==NULL) return NULL;
338  if (! iniparser_find_entry(d, s)) return NULL;
339 
340  seclen = (int)strlen(s);
341  sprintf(keym, "%s:", s);
342 
343  i = 0;
344 
345  for (j=0 ; j<d->size ; j++) {
346  if (d->key[j]==NULL)
347  continue ;
348  if (!strncmp(d->key[j], keym, seclen+1)) {
349  keys[i] = d->key[j];
350  i++;
351  }
352  }
353 
354  return keys;
355 }
356 
357 /*-------------------------------------------------------------------------*/
371 /*--------------------------------------------------------------------------*/
372 const char * iniparser_getstring(const dictionary * d, const char * key, const char * def)
373 {
374  const char * lc_key ;
375  const char * sval ;
376  char tmp_str[ASCIILINESZ+1];
377 
378  if (d==NULL || key==NULL)
379  return def ;
380 
381  lc_key = strlwc(key, tmp_str, sizeof(tmp_str));
382  sval = dictionary_get(d, lc_key, def);
383  return sval ;
384 }
385 
386 /*-------------------------------------------------------------------------*/
412 /*--------------------------------------------------------------------------*/
413 int iniparser_getint(const dictionary * d, const char * key, int notfound)
414 {
415  const char * str ;
416 
417  str = iniparser_getstring(d, key, INI_INVALID_KEY);
418  if (str==INI_INVALID_KEY) return notfound ;
419  return (int)strtol(str, NULL, 0);
420 }
421 
422 /*-------------------------------------------------------------------------*/
434 /*--------------------------------------------------------------------------*/
435 double iniparser_getdouble(const dictionary * d, const char * key, double notfound)
436 {
437  const char * str ;
438 
439  str = iniparser_getstring(d, key, INI_INVALID_KEY);
440  if (str==INI_INVALID_KEY) return notfound ;
441  return atof(str);
442 }
443 
444 /*-------------------------------------------------------------------------*/
475 /*--------------------------------------------------------------------------*/
476 int iniparser_getboolean(const dictionary * d, const char * key, int notfound)
477 {
478  int ret ;
479  const char * c ;
480 
482  if (c==INI_INVALID_KEY) return notfound ;
483  if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
484  ret = 1 ;
485  } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
486  ret = 0 ;
487  } else {
488  ret = notfound ;
489  }
490  return ret;
491 }
492 
493 /*-------------------------------------------------------------------------*/
504 /*--------------------------------------------------------------------------*/
505 int iniparser_find_entry(const dictionary * ini, const char * entry)
506 {
507  int found=0 ;
509  found = 1 ;
510  }
511  return found ;
512 }
513 
514 /*-------------------------------------------------------------------------*/
526 /*--------------------------------------------------------------------------*/
527 int iniparser_set(dictionary * ini, const char * entry, const char * val)
528 {
529  char tmp_str[ASCIILINESZ+1];
530  return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ;
531 }
532 
533 /*-------------------------------------------------------------------------*/
542 /*--------------------------------------------------------------------------*/
543 void iniparser_unset(dictionary * ini, const char * entry)
544 {
545  char tmp_str[ASCIILINESZ+1];
546  dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str)));
547 }
548 
549 /*-------------------------------------------------------------------------*/
558 /*--------------------------------------------------------------------------*/
559 static line_status iniparser_line(
560  const char * input_line,
561  char * section,
562  char * key,
563  char * value)
564 {
565  line_status sta ;
566  char * line = NULL;
567  size_t len ;
568 
569  line = xstrdup(input_line);
570  len = strstrip(line);
571 
572  sta = LINE_UNPROCESSED ;
573  if (len<1) {
574  /* Empty line */
575  sta = LINE_EMPTY ;
576  } else if (line[0]=='#' || line[0]==';') {
577  /* Comment line */
578  sta = LINE_COMMENT ;
579 /* } else if (line[0]=='[' && line[len-1]==']') { */
580  } else if (line[0]=='[') {
581  /* Section name */
582  sscanf(line, "[%[^]]", section);
583  strstrip(section);
584  strlwc(section, section, len);
585  sta = LINE_SECTION ;
586  } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
587  || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2) {
588  /* Usual key=value with quotes, with or without comments */
589  strstrip(key);
590  strlwc(key, key, len);
591  /* Don't strip spaces from values surrounded with quotes */
592  /*
593  * sscanf cannot handle '' or "" as empty values
594  * this is done here
595  */
596  if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
597  value[0]=0 ;
598  }
599  sta = LINE_VALUE ;
600  } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
601  /* Usual key=value without quotes, with or without comments */
602  strstrip(key);
603  strlwc(key, key, len);
604  strstrip(value);
605 
606  sta = LINE_VALUE ;
607  } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
608  || sscanf(line, "%[^=] %[=]", key, value) == 2) {
609  /*
610  * Special cases:
611  * key=
612  * key=;
613  * key=#
614  */
615  strstrip(key);
616  strlwc(key, key, len);
617  value[0]=0 ;
618  sta = LINE_VALUE ;
619  } else {
620  /* Generate syntax error */
621  sta = LINE_ERROR ;
622  }
623 
624  free(line);
625  return sta ;
626 }
627 
628 /*-------------------------------------------------------------------------*/
641 /*--------------------------------------------------------------------------*/
642 dictionary * iniparser_load(const char * ininame)
643 {
644  FILE * in ;
645 
646  char line [ASCIILINESZ+1] ;
647  char section [ASCIILINESZ+1] ;
648  char key [ASCIILINESZ+1] ;
649  char tmp [(ASCIILINESZ * 2) + 1] ;
650  char val [ASCIILINESZ+1] ;
651 
652  int last=0 ;
653  int len ;
654  int lineno=0 ;
655  int errs=0;
656 
657  dictionary * dict ;
658 
659  if ((in=fopen(ininame, "r"))==NULL) {
660  fprintf(stderr, "iniparser: cannot open %s\n", ininame);
661  return NULL ;
662  }
663 
664  dict = dictionary_new(0) ;
665  if (!dict) {
666  fclose(in);
667  return NULL ;
668  }
669 
670  memset(line, 0, ASCIILINESZ);
671  memset(section, 0, ASCIILINESZ);
672  memset(key, 0, ASCIILINESZ);
673  memset(val, 0, ASCIILINESZ);
674  last=0 ;
675 
676  while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
677  lineno++ ;
678  len = (int)strlen(line)-1;
679  if (len==0)
680  continue;
681  /* Safety check against buffer overflows */
682  if (line[len]!='\n' && !feof(in)) {
683  fprintf(stderr,
684  "iniparser: input line too long in %s (%d)\n",
685  ininame,
686  lineno);
687  dictionary_del(dict);
688  fclose(in);
689  return NULL ;
690  }
691  /* Get rid of \n and spaces at end of line */
692  while ((len>=0) &&
693  ((line[len]=='\n') || (isspace(line[len])))) {
694  line[len]=0 ;
695  len-- ;
696  }
697  if (len < 0) { /* Line was entirely \n and/or spaces */
698  len = 0;
699  }
700  /* Detect multi-line */
701  if (line[len]=='\\') {
702  /* Multi-line value */
703  last=len ;
704  continue ;
705  } else {
706  last=0 ;
707  }
708  switch (iniparser_line(line, section, key, val)) {
709  case LINE_EMPTY:
710  case LINE_COMMENT:
711  break ;
712 
713  case LINE_SECTION:
714  errs = dictionary_set(dict, section, NULL);
715  break ;
716 
717  case LINE_VALUE:
718  sprintf(tmp, "%s:%s", section, key);
719  errs = dictionary_set(dict, tmp, val) ;
720  break ;
721 
722  case LINE_ERROR:
723  fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
724  ininame,
725  lineno);
726  fprintf(stderr, "-> %s\n", line);
727  errs++ ;
728  break;
729 
730  default:
731  break ;
732  }
733  memset(line, 0, ASCIILINESZ);
734  last=0;
735  if (errs<0) {
736  fprintf(stderr, "iniparser: memory allocation failure\n");
737  break ;
738  }
739  }
740  if (errs) {
741  dictionary_del(dict);
742  dict = NULL ;
743  }
744  fclose(in);
745  return dict ;
746 }
747 
748 /*-------------------------------------------------------------------------*/
758 /*--------------------------------------------------------------------------*/
760 {
761  dictionary_del(d);
762 }
void dictionary_del(dictionary *d)
Delete a dictionary object.
Definition: dictionary.c:177
void dictionary_unset(dictionary *d, const char *key)
Delete a key in a dictionary.
Definition: dictionary.c:314
const char * dictionary_get(const dictionary *d, const char *key, const char *def)
Get a value from a dictionary.
Definition: dictionary.c:209
int dictionary_set(dictionary *d, const char *key, const char *val)
Set a value in a dictionary.
Definition: dictionary.c:255
dictionary * dictionary_new(size_t size)
Create a new dictionary object.
Definition: dictionary.c:150
enum _line_status_ line_status
double iniparser_getdouble(const dictionary *d, const char *key, double notfound)
Get the string associated to a key, convert to a double.
Definition: iniparser.c:435
void iniparser_unset(dictionary *ini, const char *entry)
Delete an entry in a dictionary.
Definition: iniparser.c:543
_line_status_
Definition: iniparser.c:23
@ LINE_SECTION
Definition: iniparser.c:28
@ LINE_COMMENT
Definition: iniparser.c:27
@ LINE_ERROR
Definition: iniparser.c:25
@ LINE_VALUE
Definition: iniparser.c:29
@ LINE_UNPROCESSED
Definition: iniparser.c:24
@ LINE_EMPTY
Definition: iniparser.c:26
const char ** iniparser_getseckeys(const dictionary *d, const char *s, const char **keys)
Get the number of keys in a section of a dictionary.
Definition: iniparser.c:332
int iniparser_getsecnkeys(const dictionary *d, const char *s)
Get the number of keys in a section of a dictionary.
Definition: iniparser.c:291
const char * strlwc(const char *in, char *out, unsigned len)
Convert a string to lowercase.
Definition: iniparser.c:44
void iniparser_dumpsection_ini(const dictionary *d, const char *s, FILE *f)
Save a dictionary section to a loadable ini file.
Definition: iniparser.c:257
void iniparser_dump(const dictionary *d, FILE *f)
Dump a dictionary to an opened file pointer.
Definition: iniparser.c:194
unsigned strstrip(char *s)
Remove blanks at the beginning and the end of a string.
Definition: iniparser.c:90
void iniparser_freedict(dictionary *d)
Free all memory associated to an ini dictionary.
Definition: iniparser.c:759
int iniparser_getint(const dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to an int.
Definition: iniparser.c:413
dictionary * iniparser_load(const char *ininame)
Parse an ini file and return an allocated dictionary object.
Definition: iniparser.c:642
const char * iniparser_getsecname(const dictionary *d, int n)
Get name for section n in a dictionary.
Definition: iniparser.c:159
int iniparser_find_entry(const dictionary *ini, const char *entry)
Finds out if a given entry exists in a dictionary.
Definition: iniparser.c:505
int iniparser_getnsec(const dictionary *d)
Get number of sections in a dictionary.
Definition: iniparser.c:128
int iniparser_set(dictionary *ini, const char *entry, const char *val)
Set an entry in a dictionary.
Definition: iniparser.c:527
#define ASCIILINESZ
Definition: iniparser.c:14
void iniparser_dump_ini(const dictionary *d, FILE *f)
Save a dictionary to a loadable ini file.
Definition: iniparser.c:219
const char * iniparser_getstring(const dictionary *d, const char *key, const char *def)
Get the string associated to a key.
Definition: iniparser.c:372
int iniparser_getboolean(const dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to a boolean.
Definition: iniparser.c:476
#define INI_INVALID_KEY
Definition: iniparser.c:15
Parser for ini files.
Dictionary object.
Definition: dictionary.h:45
char ** key
Definition: dictionary.h:49
char ** val
Definition: dictionary.h:48
ssize_t size
Definition: dictionary.h:47