Robot Agent  1.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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_ {
30 } line_status ;
31 
32 /*-------------------------------------------------------------------------*/
43 /*--------------------------------------------------------------------------*/
44 static char * strlwc(const char * s)
45 {
46  static char l[ASCIILINESZ+1];
47  int i ;
48 
49  if (s==NULL) return NULL ;
50  memset(l, 0, ASCIILINESZ+1);
51  i=0 ;
52  while (s[i] && i<ASCIILINESZ) {
53  l[i] = (char)tolower((int)s[i]);
54  i++ ;
55  }
56  l[ASCIILINESZ]=(char)0;
57  return l ;
58 }
59 
60 /*-------------------------------------------------------------------------*/
73 /*--------------------------------------------------------------------------*/
74 static char * strstrip(const char * s)
75 {
76  static char l[ASCIILINESZ+1];
77  char * last ;
78 
79  if (s==NULL) return NULL ;
80 
81  while (isspace((int)*s) && *s) s++;
82  memset(l, 0, ASCIILINESZ+1);
83  strcpy(l, s);
84  last = l + strlen(l);
85  while (last > l) {
86  if (!isspace((int)*(last-1)))
87  break ;
88  last -- ;
89  }
90  *last = (char)0;
91  return (char*)l ;
92 }
93 
94 /*-------------------------------------------------------------------------*/
111 /*--------------------------------------------------------------------------*/
113 {
114  int i ;
115  int nsec ;
116 
117  if (d==NULL) return -1 ;
118  nsec=0 ;
119  for (i=0 ; i<d->size ; i++) {
120  if (d->key[i]==NULL)
121  continue ;
122  if (strchr(d->key[i], ':')==NULL) {
123  nsec ++ ;
124  }
125  }
126  return nsec ;
127 }
128 
129 /*-------------------------------------------------------------------------*/
142 /*--------------------------------------------------------------------------*/
144 {
145  int i ;
146  int foundsec ;
147 
148  if (d==NULL || n<0) return NULL ;
149  foundsec=0 ;
150  for (i=0 ; i<d->size ; i++) {
151  if (d->key[i]==NULL)
152  continue ;
153  if (strchr(d->key[i], ':')==NULL) {
154  foundsec++ ;
155  if (foundsec>n)
156  break ;
157  }
158  }
159  if (foundsec<=n) {
160  return NULL ;
161  }
162  return d->key[i] ;
163 }
164 
165 /*-------------------------------------------------------------------------*/
177 /*--------------------------------------------------------------------------*/
178 void iniparser_dump(dictionary * d, FILE * f)
179 {
180  int i ;
181 
182  if (d==NULL || f==NULL) return ;
183  for (i=0 ; i<d->size ; i++) {
184  if (d->key[i]==NULL)
185  continue ;
186  if (d->val[i]!=NULL) {
187  fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
188  } else {
189  fprintf(f, "[%s]=UNDEF\n", d->key[i]);
190  }
191  }
192  return ;
193 }
194 
195 /*-------------------------------------------------------------------------*/
205 /*--------------------------------------------------------------------------*/
206 void iniparser_dump_ini(dictionary * d, FILE * f)
207 {
208  int i ;
209  int nsec ;
210  char * secname ;
211 
212  if (d==NULL || f==NULL) return ;
213 
214  nsec = iniparser_getnsec(d);
215  if (nsec<1) {
216  /* No section in file: dump all keys as they are */
217  for (i=0 ; i<d->size ; i++) {
218  if (d->key[i]==NULL)
219  continue ;
220  fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
221  }
222  return ;
223  }
224  for (i=0 ; i<nsec ; i++) {
225  secname = iniparser_getsecname(d, i) ;
226  iniparser_dumpsection_ini(d, secname, f) ;
227  }
228  fprintf(f, "\n");
229  return ;
230 }
231 
232 /*-------------------------------------------------------------------------*/
243 /*--------------------------------------------------------------------------*/
244 void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
245 {
246  int j ;
247  char keym[ASCIILINESZ+1];
248  int seclen ;
249 
250  if (d==NULL || f==NULL) return ;
251  if (! iniparser_find_entry(d, s)) return ;
252 
253  seclen = (int)strlen(s);
254  fprintf(f, "\n[%s]\n", s);
255  sprintf(keym, "%s:", s);
256  for (j=0 ; j<d->size ; j++) {
257  if (d->key[j]==NULL)
258  continue ;
259  if (!strncmp(d->key[j], keym, seclen+1)) {
260  fprintf(f,
261  "%-30s = %s\n",
262  d->key[j]+seclen+1,
263  d->val[j] ? d->val[j] : "");
264  }
265  }
266  fprintf(f, "\n");
267  return ;
268 }
269 
270 /*-------------------------------------------------------------------------*/
277 /*--------------------------------------------------------------------------*/
279 {
280  int seclen, nkeys ;
281  char keym[ASCIILINESZ+1];
282  int j ;
283 
284  nkeys = 0;
285 
286  if (d==NULL) return nkeys;
287  if (! iniparser_find_entry(d, s)) return nkeys;
288 
289  seclen = (int)strlen(s);
290  sprintf(keym, "%s:", s);
291 
292  for (j=0 ; j<d->size ; j++) {
293  if (d->key[j]==NULL)
294  continue ;
295  if (!strncmp(d->key[j], keym, seclen+1))
296  nkeys++;
297  }
298 
299  return nkeys;
300 
301 }
302 
303 /*-------------------------------------------------------------------------*/
316 /*--------------------------------------------------------------------------*/
317 char ** iniparser_getseckeys(dictionary * d, char * s)
318 {
319 
320  char **keys;
321 
322  int i, j ;
323  char keym[ASCIILINESZ+1];
324  int seclen, nkeys ;
325 
326  keys = NULL;
327 
328  if (d==NULL) return keys;
329  if (! iniparser_find_entry(d, s)) return keys;
330 
331  nkeys = iniparser_getsecnkeys(d, s);
332 
333  keys = (char**) malloc(nkeys*sizeof(char*));
334 
335  seclen = (int)strlen(s);
336  sprintf(keym, "%s:", s);
337 
338  i = 0;
339 
340  for (j=0 ; j<d->size ; j++) {
341  if (d->key[j]==NULL)
342  continue ;
343  if (!strncmp(d->key[j], keym, seclen+1)) {
344  keys[i] = d->key[j];
345  i++;
346  }
347  }
348 
349  return keys;
350 
351 }
352 
353 /*-------------------------------------------------------------------------*/
367 /*--------------------------------------------------------------------------*/
368 char * iniparser_getstring(dictionary * d, const char * key, char * def)
369 {
370  char * lc_key ;
371  char * sval ;
372 
373  if (d==NULL || key==NULL)
374  return def ;
375 
376  lc_key = strlwc(key);
377  sval = dictionary_get(d, lc_key, def);
378  return sval ;
379 }
380 
381 /*-------------------------------------------------------------------------*/
407 /*--------------------------------------------------------------------------*/
408 int iniparser_getint(dictionary * d, const char * key, int notfound)
409 {
410  char * str ;
411 
412  str = iniparser_getstring(d, key, INI_INVALID_KEY);
413  if (str==INI_INVALID_KEY) return notfound ;
414  return (int)strtol(str, NULL, 0);
415 }
416 
417 /*-------------------------------------------------------------------------*/
429 /*--------------------------------------------------------------------------*/
430 double iniparser_getdouble(dictionary * d, const char * key, double notfound)
431 {
432  char * str ;
433 
434  str = iniparser_getstring(d, key, INI_INVALID_KEY);
435  if (str==INI_INVALID_KEY) return notfound ;
436  return atof(str);
437 }
438 
439 /*-------------------------------------------------------------------------*/
470 /*--------------------------------------------------------------------------*/
471 int iniparser_getboolean(dictionary * d, const char * key, int notfound)
472 {
473  char * c ;
474  int ret ;
475 
477  if (c==INI_INVALID_KEY) return notfound ;
478  if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
479  ret = 1 ;
480  } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
481  ret = 0 ;
482  } else {
483  ret = notfound ;
484  }
485  return ret;
486 }
487 
488 /*-------------------------------------------------------------------------*/
499 /*--------------------------------------------------------------------------*/
501  dictionary * ini,
502  const char * entry
503 )
504 {
505  int found=0 ;
507  found = 1 ;
508  }
509  return found ;
510 }
511 
512 /*-------------------------------------------------------------------------*/
524 /*--------------------------------------------------------------------------*/
525 int iniparser_set(dictionary * ini, const char * entry, const char * val)
526 {
527  return dictionary_set(ini, strlwc(entry), val) ;
528 }
529 
530 /*-------------------------------------------------------------------------*/
539 /*--------------------------------------------------------------------------*/
540 void iniparser_unset(dictionary * ini, const char * entry)
541 {
542  dictionary_unset(ini, strlwc(entry));
543 }
544 
545 /*-------------------------------------------------------------------------*/
554 /*--------------------------------------------------------------------------*/
555 static line_status iniparser_line(
556  const char * input_line,
557  char * section,
558  char * key,
559  char * value)
560 {
561  line_status sta ;
562  char line[ASCIILINESZ+1];
563  int len ;
564 
565  strcpy(line, strstrip(input_line));
566  len = (int)strlen(line);
567 
568  sta = LINE_UNPROCESSED ;
569  if (len<1) {
570  /* Empty line */
571  sta = LINE_EMPTY ;
572  } else if (line[0]=='#' || line[0]==';') {
573  /* Comment line */
574  sta = LINE_COMMENT ;
575  } else if (line[0]=='[' && line[len-1]==']') {
576  /* Section name */
577  sscanf(line, "[%[^]]", section);
578  strcpy(section, strstrip(section));
579  strcpy(section, strlwc(section));
580  sta = LINE_SECTION ;
581  } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
582  || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
583  || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
584  /* Usual key=value, with or without comments */
585  strcpy(key, strstrip(key));
586  strcpy(key, strlwc(key));
587  strcpy(value, strstrip(value));
588  /*
589  * sscanf cannot handle '' or "" as empty values
590  * this is done here
591  */
592  if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
593  value[0]=0 ;
594  }
595  sta = LINE_VALUE ;
596  } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
597  || sscanf(line, "%[^=] %[=]", key, value) == 2) {
598  /*
599  * Special cases:
600  * key=
601  * key=;
602  * key=#
603  */
604  strcpy(key, strstrip(key));
605  strcpy(key, strlwc(key));
606  value[0]=0 ;
607  sta = LINE_VALUE ;
608  } else {
609  /* Generate syntax error */
610  sta = LINE_ERROR ;
611  }
612  return sta ;
613 }
614 
615 /*-------------------------------------------------------------------------*/
628 /*--------------------------------------------------------------------------*/
629 dictionary * iniparser_load(const char * ininame)
630 {
631  FILE * in ;
632 
633  char line [ASCIILINESZ+1] ;
634  char section [ASCIILINESZ+1] ;
635  char key [ASCIILINESZ+1] ;
636  char tmp [ASCIILINESZ+1] ;
637  char val [ASCIILINESZ+1] ;
638 
639  int last=0 ;
640  int len ;
641  int lineno=0 ;
642  int errs=0;
643 
644  dictionary * dict ;
645 
646  if ((in=fopen(ininame, "r"))==NULL) {
647  fprintf(stderr, "iniparser: cannot open %s\n", ininame);
648  return NULL ;
649  }
650 
651  dict = dictionary_new(0) ;
652  if (!dict) {
653  fclose(in);
654  return NULL ;
655  }
656 
657  memset(line, 0, ASCIILINESZ);
658  memset(section, 0, ASCIILINESZ);
659  memset(key, 0, ASCIILINESZ);
660  memset(val, 0, ASCIILINESZ);
661  last=0 ;
662 
663  while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
664  lineno++ ;
665  len = (int)strlen(line)-1;
666  if (len==0)
667  continue;
668  /* Safety check against buffer overflows */
669  if (line[len]!='\n') {
670  fprintf(stderr,
671  "iniparser: input line too long in %s (%d)\n",
672  ininame,
673  lineno);
674  dictionary_del(dict);
675  fclose(in);
676  return NULL ;
677  }
678  /* Get rid of \n and spaces at end of line */
679  while ((len>=0) &&
680  ((line[len]=='\n') || (isspace(line[len])))) {
681  line[len]=0 ;
682  len-- ;
683  }
684  /* Detect multi-line */
685  if (line[len]=='\\') {
686  /* Multi-line value */
687  last=len ;
688  continue ;
689  } else {
690  last=0 ;
691  }
692  switch (iniparser_line(line, section, key, val)) {
693  case LINE_EMPTY:
694  case LINE_COMMENT:
695  break ;
696 
697  case LINE_SECTION:
698  errs = dictionary_set(dict, section, NULL);
699  break ;
700 
701  case LINE_VALUE:
702  sprintf(tmp, "%s:%s", section, key);
703  errs = dictionary_set(dict, tmp, val) ;
704  break ;
705 
706  case LINE_ERROR:
707  fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
708  ininame,
709  lineno);
710  fprintf(stderr, "-> %s\n", line);
711  errs++ ;
712  break;
713 
714  default:
715  break ;
716  }
717  memset(line, 0, ASCIILINESZ);
718  last=0;
719  if (errs<0) {
720  fprintf(stderr, "iniparser: memory allocation failure\n");
721  break ;
722  }
723  }
724  if (errs) {
725  dictionary_del(dict);
726  dict = NULL ;
727  }
728  fclose(in);
729  return dict ;
730 }
731 
732 /*-------------------------------------------------------------------------*/
742 /*--------------------------------------------------------------------------*/
744 {
745  dictionary_del(d);
746 }
747 
748 /* vim: set ts=4 et sw=4 tw=75 */
char ** val
Definition: dictionary.h:44
int iniparser_set(dictionary *ini, const char *entry, const char *val)
Set an entry in a dictionary.
Definition: iniparser.c:525
char * iniparser_getstring(dictionary *d, const char *key, char *def)
Get the string associated to a key.
Definition: iniparser.c:368
void iniparser_unset(dictionary *ini, const char *entry)
Delete an entry in a dictionary.
Definition: iniparser.c:540
char * dictionary_get(dictionary *d, const char *key, char *def)
Get a value from a dictionary.
Definition: dictionary.c:175
void dictionary_unset(dictionary *d, const char *key)
Delete a key in a dictionary.
Definition: dictionary.c:288
#define ASCIILINESZ
Definition: iniparser.c:14
#define INI_INVALID_KEY
Definition: iniparser.c:15
dictionary * iniparser_load(const char *ininame)
Parse an ini file and return an allocated dictionary object.
Definition: iniparser.c:629
double iniparser_getdouble(dictionary *d, const char *key, double notfound)
Get the string associated to a key, convert to a double.
Definition: iniparser.c:430
int iniparser_getboolean(dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to a boolean.
Definition: iniparser.c:471
_line_status_
Definition: iniparser.c:23
void iniparser_dump(dictionary *d, FILE *f)
Dump a dictionary to an opened file pointer.
Definition: iniparser.c:178
char ** key
Definition: dictionary.h:45
enum _line_status_ line_status
char * iniparser_getsecname(dictionary *d, int n)
Get name for section n in a dictionary.
Definition: iniparser.c:143
Parser for ini files.
dictionary * dictionary_new(int size)
Create a new dictionary object.
Definition: dictionary.c:117
void dictionary_del(dictionary *d)
Delete a dictionary object.
Definition: dictionary.c:143
void iniparser_dumpsection_ini(dictionary *d, char *s, FILE *f)
Save a dictionary section to a loadable ini file.
Definition: iniparser.c:244
int iniparser_find_entry(dictionary *ini, const char *entry)
Finds out if a given entry exists in a dictionary.
Definition: iniparser.c:500
int iniparser_getsecnkeys(dictionary *d, char *s)
Get the number of keys in a section of a dictionary.
Definition: iniparser.c:278
int iniparser_getnsec(dictionary *d)
Get number of sections in a dictionary.
Definition: iniparser.c:112
int dictionary_set(dictionary *d, const char *key, const char *val)
Set a value in a dictionary.
Definition: dictionary.c:221
char ** iniparser_getseckeys(dictionary *d, char *s)
Get the number of keys in a section of a dictionary.
Definition: iniparser.c:317
Dictionary object.
Definition: dictionary.h:41
void iniparser_dump_ini(dictionary *d, FILE *f)
Save a dictionary to a loadable ini file.
Definition: iniparser.c:206
void iniparser_freedict(dictionary *d)
Free all memory associated to an ini dictionary.
Definition: iniparser.c:743
int iniparser_getint(dictionary *d, const char *key, int notfound)
Get the string associated to a key, convert to an int.
Definition: iniparser.c:408