1 /*
2 * config file parser
3 *
4 */
5
6 #include "config.h"
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stddef.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <errno.h>
14
15 #include <sys/stat.h>
16 #include <sys/types.h>
17
18 #include "list.h"
19 #include "misc.h"
20 #include "parseconfig.h"
21
22 struct cfg_entry {
23 struct list_head next;
24 char *name;
25 unsigned int flags;
26 char *value;
27 };
28
29 struct cfg_section {
30 struct list_head next;
31 char *name;
32 unsigned int flags;
33 struct list_head entries;
34 };
35
36 struct cfg_domain {
37 struct list_head next;
38 char *name;
39 struct list_head sections;
40 };
41
42 LIST_HEAD(domains);
43
44 /* ------------------------------------------------------------------------ */
45 /* internal stuff */
46
47 static struct cfg_domain *d_last;
48 static struct cfg_section *s_last;
49 static struct cfg_entry *e_last;
50
51 static struct cfg_domain*
cfg_find_domain(char * dname)52 cfg_find_domain(char *dname)
53 {
54 struct list_head *item;
55 struct cfg_domain *domain;
56
57 if (d_last && 0 == strcmp(d_last->name,dname))
58 return d_last;
59 d_last = NULL;
60 s_last = NULL;
61 e_last = NULL;
62
63 list_for_each(item,&domains) {
64 domain = list_entry(item, struct cfg_domain, next);
65 if (0 == strcasecmp(domain->name,dname)) {
66 d_last = domain;
67 return domain;
68 }
69 }
70 return NULL;
71 }
72
73 static struct cfg_domain*
cfg_get_domain(char * dname)74 cfg_get_domain(char *dname)
75 {
76 struct cfg_domain *domain;
77
78 domain = cfg_find_domain(dname);
79 if (NULL == domain) {
80 domain = malloc(sizeof(*domain));
81 memset(domain,0,sizeof(*domain));
82 domain->name = strdup(dname);
83 INIT_LIST_HEAD(&domain->sections);
84 list_add_tail(&domain->next,&domains);
85 }
86 d_last = domain;
87 return domain;
88 }
89
90 static struct cfg_section*
cfg_find_section(struct cfg_domain * domain,char * sname)91 cfg_find_section(struct cfg_domain *domain, char *sname)
92 {
93 struct list_head *item;
94 struct cfg_section *section;
95
96 if (s_last && 0 == strcmp(s_last->name,sname))
97 return s_last;
98 s_last = NULL;
99 e_last = NULL;
100
101 list_for_each(item,&domain->sections) {
102 section = list_entry(item, struct cfg_section, next);
103 if (0 == strcasecmp(section->name,sname)) {
104 s_last = section;
105 return section;
106 }
107 }
108 return NULL;
109 }
110
111 static struct cfg_section*
cfg_get_section(struct cfg_domain * domain,char * sname)112 cfg_get_section(struct cfg_domain *domain, char *sname)
113 {
114 struct cfg_section *section;
115
116 section = cfg_find_section(domain,sname);
117 if (NULL == section) {
118 section = malloc(sizeof(*section));
119 memset(section,0,sizeof(*section));
120 section->name = strdup(sname);
121 INIT_LIST_HEAD(§ion->entries);
122 list_add_tail(§ion->next,&domain->sections);
123 }
124 s_last = section;
125 return section;
126 }
127
128 static struct cfg_entry*
cfg_find_entry(struct cfg_section * section,char * ename)129 cfg_find_entry(struct cfg_section *section, char *ename)
130 {
131 struct list_head *item;
132 struct cfg_entry *entry;
133
134 if (e_last && 0 == strcmp(e_last->name,ename))
135 return e_last;
136 e_last = NULL;
137
138 list_for_each(item,§ion->entries) {
139 entry = list_entry(item, struct cfg_entry, next);
140 if (0 == strcasecmp(entry->name,ename)) {
141 e_last = entry;
142 return entry;
143 }
144 }
145 return NULL;
146 }
147
148 static struct cfg_entry*
cfg_get_entry(struct cfg_section * section,char * ename)149 cfg_get_entry(struct cfg_section *section, char *ename)
150 {
151 struct cfg_entry *entry;
152
153 entry = cfg_find_entry(section,ename);
154 if (NULL == entry) {
155 entry = malloc(sizeof(*entry));
156 memset(entry,0,sizeof(*entry));
157 entry->name = strdup(ename);
158 list_add_tail(&entry->next,§ion->entries);
159 }
160 e_last = entry;
161 return entry;
162 }
163
164 static void
cfg_set_entry(struct cfg_section * section,char * name,const char * value)165 cfg_set_entry(struct cfg_section *section, char *name, const char *value)
166 {
167 struct cfg_entry *entry;
168
169 entry = cfg_get_entry(section,name);
170 if (entry->value)
171 free(entry->value);
172 entry->value = strdup(value);
173 }
174
175 static struct cfg_section*
cfg_get_sec(char * dname,char * sname)176 cfg_get_sec(char *dname, char *sname)
177 {
178 struct cfg_domain *domain;
179
180 domain = cfg_find_domain(dname);
181 if (NULL == domain)
182 return NULL;
183 return cfg_find_section(domain,sname);
184 }
185
186 static struct cfg_entry*
cfg_get_ent(char * dname,char * sname,char * ename)187 cfg_get_ent(char *dname, char *sname, char *ename)
188 {
189 struct cfg_section *section;
190
191 section = cfg_get_sec(dname,sname);
192 if (NULL == section)
193 return NULL;
194 return cfg_find_entry(section,ename);
195 }
196
197 /* ------------------------------------------------------------------------ */
198 /* import / add / del config data */
199
200 int
cfg_parse_file(char * dname,char * filename)201 cfg_parse_file(char *dname, char *filename)
202 {
203 struct cfg_domain *domain = NULL;
204 struct cfg_section *section = NULL;
205 char line[256],tag[64],value[192];
206 FILE *fp;
207 int nr;
208
209 if (NULL == (fp = fopen(filename,"r")))
210 return -1;
211
212 nr = 0;
213 domain = cfg_get_domain(dname);
214 while (NULL != fgets(line,255,fp)) {
215 nr++;
216 if (1 == sscanf(line,"# include \"%[^\"]\"",value)) {
217 /* includes */
218 char *h,*inc;
219 inc = malloc(strlen(filename)+strlen(value));
220 strcpy(inc,filename);
221 h = strrchr(inc,'/');
222 if (h)
223 h++;
224 else
225 h = inc;
226 strcpy(h,value);
227 cfg_parse_file(dname,inc);
228 free(inc);
229 continue;
230 }
231 if (line[0] == '\n' || line[0] == '#' || line[0] == '%')
232 continue;
233 if (1 == sscanf(line,"[%99[^]]]",value)) {
234 /* [section] */
235 section = cfg_get_section(domain,value);
236 } else if (2 == sscanf(line," %63[^= ] = %191[^\n]",tag,value)) {
237 /* foo = bar */
238 if (NULL == section) {
239 fprintf(stderr,"%s:%d: error: no section\n",filename,nr);
240 } else {
241 char *c = value + strlen(value)-1;
242 while (c > value && (*c == ' ' || *c == '\t'))
243 *(c--) = 0;
244 cfg_set_entry(section,tag,value);
245 }
246 } else {
247 /* Huh ? */
248 fprintf(stderr,"%s:%d: syntax error\n",filename,nr);
249 }
250 }
251 fclose(fp);
252 return 0;
253 }
254
255 void
cfg_set_str(char * dname,char * sname,char * ename,const char * value)256 cfg_set_str(char *dname, char *sname, char *ename, const char *value)
257 {
258 struct cfg_domain *domain = NULL;
259 struct cfg_section *section = NULL;
260
261 if (NULL == value) {
262 cfg_del_entry(dname, sname, ename);
263 } else {
264 domain = cfg_get_domain(dname);
265 section = cfg_get_section(domain,sname);
266 cfg_set_entry(section,ename,value);
267 }
268 }
269
270 void
cfg_set_int(char * dname,char * sname,char * ename,int value)271 cfg_set_int(char *dname, char *sname, char *ename, int value)
272 {
273 char str[32];
274
275 snprintf(str,sizeof(str),"%d",value);
276 cfg_set_str(dname,sname,ename,str);
277 }
278
279 void
cfg_set_bool(char * dname,char * sname,char * ename,int value)280 cfg_set_bool(char *dname, char *sname, char *ename, int value)
281 {
282 cfg_set_str(dname,sname,ename, value ? "true" : "false");
283 }
284
285 void
cfg_del_section(char * dname,char * sname)286 cfg_del_section(char *dname, char *sname)
287 {
288 struct cfg_section *section;
289 struct cfg_entry *entry;
290
291 section= cfg_get_sec(dname,sname);
292 if (!section)
293 return;
294 list_del(§ion->next);
295 while (!list_empty(§ion->entries)) {
296 entry = list_entry(section->entries.next, struct cfg_entry, next);
297 list_del(&entry->next);
298 free(entry->name);
299 free(entry->value);
300 free(entry);
301 }
302 s_last = NULL;
303 e_last = NULL;
304 free(section->name);
305 free(section);
306 }
307
308 void
cfg_del_entry(char * dname,char * sname,char * ename)309 cfg_del_entry(char *dname, char *sname, char *ename)
310 {
311 struct cfg_entry *entry;
312
313 entry = cfg_get_ent(dname,sname,ename);
314 if (!entry)
315 return;
316 e_last = NULL;
317 list_del(&entry->next);
318 free(entry->name);
319 free(entry->value);
320 free(entry);
321 }
322
323 void
cfg_parse_cmdline(int * argc,char ** argv,struct cfg_cmdline * opt)324 cfg_parse_cmdline(int *argc, char **argv, struct cfg_cmdline *opt)
325 {
326 int i,j,o,shift,len;
327 char sopt,*lopt;
328
329 for (i = 1; i < *argc;) {
330 if (argv[i][0] != '-') {
331 i++;
332 continue;
333 }
334 if (argv[i][1] == 0) {
335 i++;
336 continue;
337 }
338
339 sopt = 0;
340 lopt = NULL;
341 if (argv[i][1] != '-' &&
342 argv[i][2] == 0) {
343 /* short option: -f */
344 sopt = argv[i][1];
345 }
346 if (argv[i][1] != '-') {
347 /* long option: -foo */
348 lopt = argv[i]+1;
349 } else {
350 /* also accept gnu-style: --foo */
351 lopt = argv[i]+2;
352 }
353
354 for (shift = 0, o = 0;
355 0 == shift && opt[o].cmdline != NULL;
356 o++) {
357 len = strlen(opt[o].cmdline);
358
359 if (opt[o].yesno && sopt && sopt == opt[o].letter) {
360 /* yesno: -f */
361 cfg_set_bool(opt[o].option.domain,
362 opt[o].option.section,
363 opt[o].option.entry,
364 1);
365 shift = 1;
366
367 } else if (opt[o].needsarg && sopt && sopt == opt[o].letter &&
368 i+1 < *argc) {
369 /* arg: -f bar */
370 cfg_set_str(opt[o].option.domain,
371 opt[o].option.section,
372 opt[o].option.entry,
373 argv[i+1]);
374 shift = 2;
375
376 } else if (opt[o].value && sopt && sopt == opt[o].letter) {
377 /* -f sets fixed value */
378 cfg_set_str(opt[o].option.domain,
379 opt[o].option.section,
380 opt[o].option.entry,
381 opt[o].value);
382 shift = 1;
383
384 } else if (opt[o].yesno && lopt &&
385 0 == strcmp(lopt,opt[o].cmdline)) {
386 /* yesno: -foo */
387 cfg_set_bool(opt[o].option.domain,
388 opt[o].option.section,
389 opt[o].option.entry,
390 1);
391 shift = 1;
392
393 } else if (opt[o].yesno && lopt &&
394 0 == strncmp(lopt,"no",2) &&
395 0 == strcmp(lopt+2,opt[o].cmdline)) {
396 /* yesno: -nofoo */
397 cfg_set_bool(opt[o].option.domain,
398 opt[o].option.section,
399 opt[o].option.entry,
400 0);
401 shift = 1;
402
403 } else if (opt[o].needsarg && lopt &&
404 0 == strcmp(lopt,opt[o].cmdline) &&
405 i+1 < *argc) {
406 /* arg: -foo bar */
407 cfg_set_str(opt[o].option.domain,
408 opt[o].option.section,
409 opt[o].option.entry,
410 argv[i+1]);
411 shift = 2;
412
413 } else if (opt[o].needsarg && lopt &&
414 0 == strncmp(lopt,opt[o].cmdline,len) &&
415 0 == strncmp(lopt+len,"=",1)) {
416 /* arg: -foo=bar */
417 cfg_set_str(opt[o].option.domain,
418 opt[o].option.section,
419 opt[o].option.entry,
420 argv[i]+2+len);
421 shift = 1;
422
423 } else if (opt[o].value && lopt &&
424 0 == strcmp(lopt,opt[o].cmdline)) {
425 /* -foo sets some fixed value */
426 cfg_set_str(opt[o].option.domain,
427 opt[o].option.section,
428 opt[o].option.entry,
429 opt[o].value);
430 shift = 1;
431 }
432 }
433
434 if (shift) {
435 /* remove processed args */
436 for (j = i; j < *argc+1-shift; j++)
437 argv[j] = argv[j+shift];
438 (*argc) -= shift;
439 } else
440 i++;
441 }
442 }
443
444 void
cfg_help_cmdline(FILE * fp,struct cfg_cmdline * opt,int w1,int w2,int w3)445 cfg_help_cmdline(FILE *fp, struct cfg_cmdline *opt, int w1, int w2, int w3)
446 {
447 char *val;
448 int o,len;
449
450 for (o = 0; opt[o].cmdline != NULL; o++) {
451 fprintf(fp,"%*s",w1,"");
452 if (opt[o].letter) {
453 fprintf(fp,"-%c ",opt[o].letter);
454 } else {
455 fprintf(fp," ");
456 }
457
458 if (opt[o].yesno) {
459 len = fprintf(fp,"-(no)%s ",opt[o].cmdline);
460 } else if (opt[o].needsarg) {
461 len = fprintf(fp,"-%s <arg> ",opt[o].cmdline);
462 } else {
463 len = fprintf(fp,"-%s ",opt[o].cmdline);
464 }
465 if (len < w2)
466 fprintf(fp,"%*s",w2-len,"");
467
468 len = fprintf(fp,"%s ",opt[o].desc);
469
470 if (w3) {
471 if (len < w3)
472 fprintf(fp,"%*s",w3-len,"");
473 val = cfg_get_str(opt[o].option.domain,
474 opt[o].option.section,
475 opt[o].option.entry);
476 if (val)
477 fprintf(fp,"[%s]",val);
478 }
479 fprintf(fp,"\n");
480 }
481 }
482
483 /* ------------------------------------------------------------------------ */
484 /* export config data */
485
cfg_mkdir(char * filename)486 static int cfg_mkdir(char *filename)
487 {
488 char *h;
489 int rc;
490
491 h = strrchr(filename,'/');
492 if (!h || h == filename)
493 return -1;
494 *h = '\0';
495 rc = mkdir(filename,0777);
496 if (-1 == rc && ENOENT == errno) {
497 cfg_mkdir(filename);
498 rc = mkdir(filename,0777);
499 }
500 if (-1 == rc)
501 fprintf(stderr,"mkdir(%s): %s\n",filename,strerror(errno));
502 *h = '/';
503 return rc;
504 }
505
506 int
cfg_write_file(char * dname,char * filename)507 cfg_write_file(char *dname, char *filename)
508 {
509 struct list_head *item1,*item2;
510 struct cfg_domain *domain;
511 struct cfg_section *section;
512 struct cfg_entry *entry;
513 char *bfile, *tfile;
514 int len;
515 FILE *fp;
516
517 len = strlen(filename)+10;
518 bfile = malloc(len);
519 tfile = malloc(len);
520 sprintf(bfile,"%s~",filename);
521 sprintf(tfile,"%s.$$$",filename);
522
523 fp = fopen(tfile,"w");
524 if (NULL == fp && ENOENT == errno) {
525 cfg_mkdir(tfile);
526 fp = fopen(tfile,"w");
527 }
528 if (NULL == fp) {
529 fprintf(stderr,"open(%s): %s\n",tfile,strerror(errno));
530 return -1;
531 }
532
533 domain = cfg_find_domain(dname);
534 if (NULL != domain) {
535 list_for_each(item1,&domain->sections) {
536 section = list_entry(item1, struct cfg_section, next);
537 fprintf(fp,"[%s]\n",section->name);
538 list_for_each(item2,§ion->entries) {
539 entry = list_entry(item2, struct cfg_entry, next);
540 fprintf(fp,"%s = %s\n",entry->name,entry->value);
541 }
542 fprintf(fp,"\n");
543 }
544 }
545 fclose(fp);
546
547 if (-1 == unlink(bfile) && ENOENT != errno) {
548 fprintf(stderr,"unlink(%s): %s\n",bfile,strerror(errno));
549 return -1;
550 }
551 if (-1 == rename(filename,bfile) && ENOENT != errno) {
552 fprintf(stderr,"rename(%s,%s): %s\n",filename,bfile,strerror(errno));
553 return -1;
554 }
555 if (-1 == rename(tfile,filename)) {
556 fprintf(stderr,"rename(%s,%s): %s\n",tfile,filename,strerror(errno));
557 return -1;
558 }
559 return 0;
560 }
561
562 /* ------------------------------------------------------------------------ */
563 /* list / search config data */
564
565 char*
cfg_sections_first(char * dname)566 cfg_sections_first(char *dname)
567 {
568 struct list_head *item;
569 struct cfg_domain *domain;
570 struct cfg_section *section;
571
572 domain = cfg_find_domain(dname);
573 if (NULL == domain)
574 return NULL;
575
576 item = &domain->sections;
577 if (item->next == &domain->sections)
578 return NULL;
579 section = list_entry(item->next, struct cfg_section, next);
580 s_last = section;
581 e_last = NULL;
582 return section->name;
583 }
584
585 char*
cfg_sections_next(char * dname,char * current)586 cfg_sections_next(char *dname, char *current)
587 {
588 struct list_head *item;
589 struct cfg_domain *domain;
590 struct cfg_section *section;
591
592 domain = cfg_find_domain(dname);
593 if (NULL == domain)
594 return NULL;
595 section = cfg_find_section(domain,current);
596 if (NULL == section)
597 return NULL;
598 item = §ion->next;
599
600 if (item->next == &domain->sections)
601 return NULL;
602 section = list_entry(item->next, struct cfg_section, next);
603 s_last = section;
604 e_last = NULL;
605 return section->name;
606 }
607
608 char*
cfg_sections_prev(char * dname,char * current)609 cfg_sections_prev(char *dname, char *current)
610 {
611 struct list_head *item;
612 struct cfg_domain *domain;
613 struct cfg_section *section;
614
615 domain = cfg_find_domain(dname);
616 if (NULL == domain)
617 return NULL;
618 section = cfg_find_section(domain,current);
619 if (NULL == section)
620 return NULL;
621 item = §ion->next;
622
623 if (item->prev == &domain->sections)
624 return NULL;
625 section = list_entry(item->prev, struct cfg_section, next);
626 s_last = section;
627 e_last = NULL;
628 return section->name;
629 }
630
cfg_sections_count(char * dname)631 unsigned int cfg_sections_count(char *dname)
632 {
633 struct list_head *item;
634 struct cfg_domain *domain;
635 int count = 0;
636
637 domain = cfg_find_domain(dname);
638 if (NULL != domain)
639 list_for_each(item,&domain->sections)
640 count++;
641 return count;
642 }
643
cfg_sections_index(char * dname,int i)644 char* cfg_sections_index(char *dname, int i)
645 {
646 struct list_head *item;
647 struct cfg_domain *domain;
648 struct cfg_section *section;
649 int count = 0;
650
651 domain = cfg_find_domain(dname);
652 if (NULL == domain)
653 return NULL;
654
655 list_for_each(item,&domain->sections) {
656 if (i == count) {
657 section = list_entry(item, struct cfg_section, next);
658 s_last = section;
659 e_last = NULL;
660 return section->name;
661 }
662 count++;
663 }
664 return NULL;
665 }
666
667 char*
cfg_entries_first(char * dname,char * sname)668 cfg_entries_first(char *dname, char *sname)
669 {
670 struct list_head *item;
671 struct cfg_section *section;
672 struct cfg_entry *entry;
673
674 section = cfg_get_sec(dname,sname);
675 if (NULL == section)
676 return NULL;
677
678 item = §ion->entries;
679 if (item->next == §ion->entries)
680 return NULL;
681 entry = list_entry(item->next, struct cfg_entry, next);
682 e_last = entry;
683 return entry->name;
684 }
685
686 char*
cfg_entries_next(char * dname,char * sname,char * current)687 cfg_entries_next(char *dname, char *sname, char *current)
688 {
689 struct list_head *item;
690 struct cfg_section *section;
691 struct cfg_entry *entry;
692
693 section = cfg_get_sec(dname,sname);
694 if (NULL == section)
695 return NULL;
696 entry = cfg_find_entry(section,current);
697 if (NULL == entry)
698 return NULL;
699 item = &entry->next;
700
701 if (item->next == §ion->entries)
702 return NULL;
703 entry = list_entry(item->next, struct cfg_entry, next);
704 e_last = entry;
705 return entry->name;
706 }
707
708 char*
cfg_entries_prev(char * dname,char * sname,char * current)709 cfg_entries_prev(char *dname, char *sname, char *current)
710 {
711 struct list_head *item;
712 struct cfg_section *section;
713 struct cfg_entry *entry;
714
715 section = cfg_get_sec(dname,sname);
716 if (NULL == section)
717 return NULL;
718 entry = cfg_find_entry(section,current);
719 if (NULL == entry)
720 return NULL;
721 item = &entry->next;
722
723 if (item->prev == §ion->entries)
724 return NULL;
725 entry = list_entry(item->prev, struct cfg_entry, next);
726 e_last = entry;
727 return entry->name;
728 }
729
cfg_entries_count(char * dname,char * sname)730 unsigned int cfg_entries_count(char *dname, char *sname)
731 {
732 struct list_head *item;
733 struct cfg_section *section;
734 int count = 0;
735
736 section = cfg_get_sec(dname,sname);
737 if (NULL != section)
738 list_for_each(item,§ion->entries)
739 count++;
740 return count;
741 }
742
cfg_entries_index(char * dname,char * sname,int i)743 char* cfg_entries_index(char *dname, char *sname, int i)
744 {
745 struct list_head *item;
746 struct cfg_section *section;
747 struct cfg_entry *entry;
748 int count = 0;
749
750 section = cfg_get_sec(dname,sname);
751 if (NULL == section)
752 return NULL;
753
754 list_for_each(item,§ion->entries) {
755 if (i == count) {
756 entry = list_entry(item, struct cfg_entry, next);
757 e_last = entry;
758 return entry->name;
759 }
760 count++;
761 }
762 return NULL;
763 }
764
cfg_search(char * dname,char * sname,char * ename,char * value)765 char* cfg_search(char *dname, char *sname, char *ename, char *value)
766 {
767 struct list_head *item1,*item2;
768 struct cfg_domain *domain;
769 struct cfg_section *section;
770 struct cfg_entry *entry;
771
772 domain = cfg_find_domain(dname);
773 if (NULL == domain)
774 return NULL;
775 list_for_each(item1,&domain->sections) {
776 section = list_entry(item1, struct cfg_section, next);
777 if (sname && 0 != strcasecmp(section->name,sname))
778 continue;
779 if (!ename)
780 return section->name;
781 list_for_each(item2,§ion->entries) {
782 entry = list_entry(item2, struct cfg_entry, next);
783 if (0 != strcasecmp(entry->name,ename))
784 continue;
785 if (0 == strcasecmp(entry->value,value))
786 return section->name;
787 }
788 }
789 return NULL;
790 }
791
792 /* ------------------------------------------------------------------------ */
793 /* get config data */
794
795 char*
cfg_get_str(char * dname,char * sname,char * ename)796 cfg_get_str(char *dname, char *sname, char *ename)
797 {
798 struct cfg_entry *entry;
799
800 entry = cfg_get_ent(dname, sname, ename);
801 if (NULL == entry)
802 return NULL;
803 return entry->value;
804 }
805
806 unsigned int
cfg_get_int(char * dname,char * sname,char * ename,unsigned int def)807 cfg_get_int(char *dname, char *sname, char *ename, unsigned int def)
808 {
809 char *val;
810
811 val = cfg_get_str(dname,sname,ename);
812 if (NULL == val)
813 return def;
814 return atoi(val);
815 }
816
817 signed int
cfg_get_signed_int(char * dname,char * sname,char * ename,signed int def)818 cfg_get_signed_int(char *dname, char *sname, char *ename, signed int def)
819 {
820 char *val;
821
822 val = cfg_get_str(dname,sname,ename);
823 if (NULL == val)
824 return def;
825 return atoi(val);
826 }
827
828 float
cfg_get_float(char * dname,char * sname,char * ename,float def)829 cfg_get_float(char *dname, char *sname, char *ename, float def)
830 {
831 char *val;
832
833 val = cfg_get_str(dname,sname,ename);
834 if (NULL == val)
835 return def;
836 return atof(val);
837 }
838
839 int
cfg_get_bool(char * dname,char * sname,char * ename,int def)840 cfg_get_bool(char *dname, char *sname, char *ename, int def)
841 {
842 static char *yes[] = { "true", "yes", "on", "1" };
843 char *val;
844 int i;
845 int retval = 0;
846
847 val = cfg_get_str(dname,sname,ename);
848 if (NULL == val)
849 return def;
850 for (i = 0; i < sizeof(yes)/sizeof(yes[0]); i++)
851 if (0 == strcasecmp(val,yes[i]))
852 retval = 1;
853 return retval;
854 }
855
856 /* ------------------------------------------------------------------------ */
857 /* get/set flags */
858
cfg_get_sflags(char * dname,char * sname)859 unsigned int cfg_get_sflags(char *dname, char *sname)
860 {
861 struct cfg_section *section;
862
863 section = cfg_get_sec(dname, sname);
864 if (NULL == section)
865 return 0;
866 return section->flags;
867 }
868
cfg_get_eflags(char * dname,char * sname,char * ename)869 unsigned int cfg_get_eflags(char *dname, char *sname, char *ename)
870 {
871 struct cfg_entry *entry;
872
873 entry = cfg_get_ent(dname, sname, ename);
874 if (NULL == entry)
875 return 0;
876 return entry->flags;
877 }
878
cfg_set_sflags(char * dname,char * sname,unsigned int mask,unsigned int bits)879 unsigned int cfg_set_sflags(char *dname, char *sname,
880 unsigned int mask, unsigned int bits)
881 {
882 struct cfg_section *section;
883
884 section = cfg_get_sec(dname, sname);
885 if (NULL == section)
886 return 0;
887 section->flags &= ~mask;
888 section->flags |= bits;
889 return section->flags;
890 }
891
cfg_set_eflags(char * dname,char * sname,char * ename,unsigned int mask,unsigned int bits)892 unsigned int cfg_set_eflags(char *dname, char *sname, char *ename,
893 unsigned int mask, unsigned int bits)
894 {
895 struct cfg_entry *entry;
896
897 entry = cfg_get_ent(dname, sname, ename);
898 if (NULL == entry)
899 return 0;
900 entry->flags &= ~mask;
901 entry->flags |= bits;
902 return entry->flags;
903 }
904