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(&section->entries);
122 	list_add_tail(&section->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,&section->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,&section->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(&section->next);
295     while (!list_empty(&section->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,&section->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 = &section->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 = &section->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 = &section->entries;
679     if (item->next == &section->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 == &section->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 == &section->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,&section->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,&section->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,&section->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