2 * functions to read and write config files
4 * Copyright (C) 2007 Gerd Hoffmann <kraxel@redhat.com
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <sys/types.h>
32 #include "parseconfig.h"
35 struct list_head next
;
42 struct list_head next
;
45 struct list_head entries
;
49 struct list_head next
;
51 struct list_head sections
;
56 /* ------------------------------------------------------------------------ */
59 static struct cfg_domain
*d_last
;
60 static struct cfg_section
*s_last
;
61 static struct cfg_entry
*e_last
;
63 static struct cfg_domain
*
64 cfg_find_domain(char *dname
)
66 struct list_head
*item
;
67 struct cfg_domain
*domain
;
69 if (d_last
&& 0 == strcmp(d_last
->name
,dname
))
75 list_for_each(item
,&domains
) {
76 domain
= list_entry(item
, struct cfg_domain
, next
);
77 if (0 == strcasecmp(domain
->name
,dname
)) {
85 static struct cfg_domain
*
86 cfg_get_domain(char *dname
)
88 struct cfg_domain
*domain
;
90 domain
= cfg_find_domain(dname
);
92 domain
= malloc(sizeof(*domain
));
93 memset(domain
,0,sizeof(*domain
));
94 domain
->name
= strdup(dname
);
95 INIT_LIST_HEAD(&domain
->sections
);
96 list_add_tail(&domain
->next
,&domains
);
102 static struct cfg_section
*
103 cfg_find_section(struct cfg_domain
*domain
, char *sname
)
105 struct list_head
*item
;
106 struct cfg_section
*section
;
108 if (s_last
&& 0 == strcmp(s_last
->name
,sname
))
113 list_for_each(item
,&domain
->sections
) {
114 section
= list_entry(item
, struct cfg_section
, next
);
115 if (0 == strcasecmp(section
->name
,sname
)) {
123 static struct cfg_section
*
124 cfg_get_section(struct cfg_domain
*domain
, char *sname
)
126 struct cfg_section
*section
;
128 section
= cfg_find_section(domain
,sname
);
129 if (NULL
== section
) {
130 section
= malloc(sizeof(*section
));
131 memset(section
,0,sizeof(*section
));
132 section
->name
= strdup(sname
);
133 INIT_LIST_HEAD(§ion
->entries
);
134 list_add_tail(§ion
->next
,&domain
->sections
);
140 static struct cfg_entry
*
141 cfg_find_entry(struct cfg_section
*section
, char *ename
)
143 struct list_head
*item
;
144 struct cfg_entry
*entry
;
146 if (e_last
&& 0 == strcmp(e_last
->name
,ename
))
150 list_for_each(item
,§ion
->entries
) {
151 entry
= list_entry(item
, struct cfg_entry
, next
);
152 if (0 == strcasecmp(entry
->name
,ename
)) {
160 static struct cfg_entry
*
161 cfg_get_entry(struct cfg_section
*section
, char *ename
)
163 struct cfg_entry
*entry
;
165 entry
= cfg_find_entry(section
,ename
);
167 entry
= malloc(sizeof(*entry
));
168 memset(entry
,0,sizeof(*entry
));
169 entry
->name
= strdup(ename
);
170 list_add_tail(&entry
->next
,§ion
->entries
);
177 cfg_set_entry(struct cfg_section
*section
, char *name
, const char *value
)
179 struct cfg_entry
*entry
;
181 entry
= cfg_get_entry(section
,name
);
184 entry
->value
= strdup(value
);
187 static struct cfg_section
*
188 cfg_get_sec(char *dname
, char *sname
)
190 struct cfg_domain
*domain
;
192 domain
= cfg_find_domain(dname
);
195 return cfg_find_section(domain
,sname
);
198 static struct cfg_entry
*
199 cfg_get_ent(char *dname
, char *sname
, char *ename
)
201 struct cfg_section
*section
;
203 section
= cfg_get_sec(dname
,sname
);
206 return cfg_find_entry(section
,ename
);
209 /* ------------------------------------------------------------------------ */
210 /* import / add / del config data */
213 cfg_parse_file(char *dname
, char *filename
)
215 struct cfg_domain
*domain
= NULL
;
216 struct cfg_section
*section
= NULL
;
217 char line
[256],tag
[64],value
[192];
221 if (NULL
== (fp
= fopen(filename
,"r")))
225 domain
= cfg_get_domain(dname
);
226 while (NULL
!= fgets(line
,255,fp
)) {
228 if (1 == sscanf(line
,"# include \"%[^\"]\"",value
)) {
231 inc
= malloc(strlen(filename
)+strlen(value
));
232 strcpy(inc
,filename
);
233 h
= strrchr(inc
,'/');
239 cfg_parse_file(dname
,inc
);
243 if (line
[0] == '\n' || line
[0] == '#' || line
[0] == '%')
245 if (1 == sscanf(line
,"[%99[^]]]",value
)) {
247 section
= cfg_get_section(domain
,value
);
248 } else if (2 == sscanf(line
," %63[^= ] = %191[^\n]",tag
,value
)) {
250 if (NULL
== section
) {
251 fprintf(stderr
,"%s:%d: error: no section\n",filename
,nr
);
253 char *c
= value
+ strlen(value
)-1;
254 while (c
> value
&& (*c
== ' ' || *c
== '\t'))
256 cfg_set_entry(section
,tag
,value
);
260 fprintf(stderr
,"%s:%d: syntax error\n",filename
,nr
);
268 cfg_set_str(char *dname
, char *sname
, char *ename
, const char *value
)
270 struct cfg_domain
*domain
= NULL
;
271 struct cfg_section
*section
= NULL
;
274 cfg_del_entry(dname
, sname
, ename
);
276 domain
= cfg_get_domain(dname
);
277 section
= cfg_get_section(domain
,sname
);
278 cfg_set_entry(section
,ename
,value
);
283 cfg_set_int(char *dname
, char *sname
, char *ename
, int value
)
287 snprintf(str
,sizeof(str
),"%d",value
);
288 cfg_set_str(dname
,sname
,ename
,str
);
292 cfg_set_bool(char *dname
, char *sname
, char *ename
, int value
)
294 cfg_set_str(dname
,sname
,ename
, value
? "true" : "false");
298 cfg_del_section(char *dname
, char *sname
)
300 struct cfg_section
*section
;
301 struct cfg_entry
*entry
;
303 section
= cfg_get_sec(dname
,sname
);
306 list_del(§ion
->next
);
307 while (!list_empty(§ion
->entries
)) {
308 entry
= list_entry(section
->entries
.next
, struct cfg_entry
, next
);
309 list_del(&entry
->next
);
321 cfg_del_entry(char *dname
, char *sname
, char *ename
)
323 struct cfg_entry
*entry
;
325 entry
= cfg_get_ent(dname
,sname
,ename
);
329 list_del(&entry
->next
);
336 cfg_parse_cmdline(int *argc
, char **argv
, struct cfg_cmdline
*opt
)
341 for (i
= 1; i
< *argc
;) {
342 if (argv
[i
][0] != '-') {
346 if (argv
[i
][1] == 0) {
353 if (argv
[i
][1] != '-' &&
355 /* short option: -f */
358 if (argv
[i
][1] != '-') {
359 /* long option: -foo */
362 /* also accept gnu-style: --foo */
366 for (shift
= 0, o
= 0;
367 0 == shift
&& opt
[o
].cmdline
!= NULL
;
369 len
= strlen(opt
[o
].cmdline
);
371 if (opt
[o
].yesno
&& sopt
&& sopt
== opt
[o
].letter
) {
373 cfg_set_bool(opt
[o
].option
.domain
,
374 opt
[o
].option
.section
,
379 } else if (opt
[o
].needsarg
&& sopt
&& sopt
== opt
[o
].letter
&&
382 cfg_set_str(opt
[o
].option
.domain
,
383 opt
[o
].option
.section
,
388 } else if (opt
[o
].value
&& sopt
&& sopt
== opt
[o
].letter
) {
389 /* -f sets fixed value */
390 cfg_set_str(opt
[o
].option
.domain
,
391 opt
[o
].option
.section
,
396 } else if (opt
[o
].yesno
&& lopt
&&
397 0 == strcmp(lopt
,opt
[o
].cmdline
)) {
399 cfg_set_bool(opt
[o
].option
.domain
,
400 opt
[o
].option
.section
,
405 } else if (opt
[o
].yesno
&& lopt
&&
406 0 == strncmp(lopt
,"no",2) &&
407 0 == strcmp(lopt
+2,opt
[o
].cmdline
)) {
409 cfg_set_bool(opt
[o
].option
.domain
,
410 opt
[o
].option
.section
,
415 } else if (opt
[o
].needsarg
&& lopt
&&
416 0 == strcmp(lopt
,opt
[o
].cmdline
) &&
419 cfg_set_str(opt
[o
].option
.domain
,
420 opt
[o
].option
.section
,
425 } else if (opt
[o
].needsarg
&& lopt
&&
426 0 == strncmp(lopt
,opt
[o
].cmdline
,len
) &&
427 0 == strncmp(lopt
+len
,"=",1)) {
429 cfg_set_str(opt
[o
].option
.domain
,
430 opt
[o
].option
.section
,
435 } else if (opt
[o
].value
&& lopt
&&
436 0 == strcmp(lopt
,opt
[o
].cmdline
)) {
437 /* -foo sets some fixed value */
438 cfg_set_str(opt
[o
].option
.domain
,
439 opt
[o
].option
.section
,
447 /* remove processed args */
448 for (j
= i
; j
< *argc
+1-shift
; j
++)
449 argv
[j
] = argv
[j
+shift
];
457 cfg_help_cmdline(FILE *fp
, struct cfg_cmdline
*opt
, int w1
, int w2
, int w3
)
462 for (o
= 0; opt
[o
].cmdline
!= NULL
; o
++) {
463 fprintf(fp
,"%*s",w1
,"");
465 fprintf(fp
,"-%c ",opt
[o
].letter
);
471 len
= fprintf(fp
,"-(no)%s ",opt
[o
].cmdline
);
472 } else if (opt
[o
].needsarg
) {
473 len
= fprintf(fp
,"-%s <arg> ",opt
[o
].cmdline
);
475 len
= fprintf(fp
,"-%s ",opt
[o
].cmdline
);
478 fprintf(fp
,"%*s",w2
-len
,"");
480 len
= fprintf(fp
,"%s ",opt
[o
].desc
);
484 fprintf(fp
,"%*s",w3
-len
,"");
485 val
= cfg_get_str(opt
[o
].option
.domain
,
486 opt
[o
].option
.section
,
487 opt
[o
].option
.entry
);
489 fprintf(fp
,"[%s]",val
);
495 /* ------------------------------------------------------------------------ */
496 /* export config data */
498 static int cfg_mkdir(char *filename
)
503 h
= strrchr(filename
,'/');
504 if (!h
|| h
== filename
)
507 rc
= mkdir(filename
,0777);
508 if (-1 == rc
&& ENOENT
== errno
) {
510 rc
= mkdir(filename
,0777);
513 fprintf(stderr
,"mkdir(%s): %s\n",filename
,strerror(errno
));
519 cfg_write_file(char *dname
, char *filename
)
521 struct list_head
*item1
,*item2
;
522 struct cfg_domain
*domain
;
523 struct cfg_section
*section
;
524 struct cfg_entry
*entry
;
529 len
= strlen(filename
)+10;
532 sprintf(bfile
,"%s~",filename
);
533 sprintf(tfile
,"%s.$$$",filename
);
535 fp
= fopen(tfile
,"w");
536 if (NULL
== fp
&& ENOENT
== errno
) {
538 fp
= fopen(tfile
,"w");
541 fprintf(stderr
,"open(%s): %s\n",tfile
,strerror(errno
));
545 domain
= cfg_find_domain(dname
);
546 if (NULL
!= domain
) {
547 list_for_each(item1
,&domain
->sections
) {
548 section
= list_entry(item1
, struct cfg_section
, next
);
549 fprintf(fp
,"[%s]\n",section
->name
);
550 list_for_each(item2
,§ion
->entries
) {
551 entry
= list_entry(item2
, struct cfg_entry
, next
);
552 fprintf(fp
,"%s = %s\n",entry
->name
,entry
->value
);
559 if (-1 == unlink(bfile
) && ENOENT
!= errno
) {
560 fprintf(stderr
,"unlink(%s): %s\n",bfile
,strerror(errno
));
563 if (-1 == rename(filename
,bfile
) && ENOENT
!= errno
) {
564 fprintf(stderr
,"rename(%s,%s): %s\n",filename
,bfile
,strerror(errno
));
567 if (-1 == rename(tfile
,filename
)) {
568 fprintf(stderr
,"rename(%s,%s): %s\n",tfile
,filename
,strerror(errno
));
574 /* ------------------------------------------------------------------------ */
575 /* list / search config data */
578 cfg_sections_first(char *dname
)
580 struct list_head
*item
;
581 struct cfg_domain
*domain
;
582 struct cfg_section
*section
;
584 domain
= cfg_find_domain(dname
);
588 item
= &domain
->sections
;
589 if (item
->next
== &domain
->sections
)
591 section
= list_entry(item
->next
, struct cfg_section
, next
);
594 return section
->name
;
598 cfg_sections_next(char *dname
, char *current
)
600 struct list_head
*item
;
601 struct cfg_domain
*domain
;
602 struct cfg_section
*section
;
604 domain
= cfg_find_domain(dname
);
607 section
= cfg_find_section(domain
,current
);
610 item
= §ion
->next
;
612 if (item
->next
== &domain
->sections
)
614 section
= list_entry(item
->next
, struct cfg_section
, next
);
617 return section
->name
;
621 cfg_sections_prev(char *dname
, char *current
)
623 struct list_head
*item
;
624 struct cfg_domain
*domain
;
625 struct cfg_section
*section
;
627 domain
= cfg_find_domain(dname
);
630 section
= cfg_find_section(domain
,current
);
633 item
= §ion
->next
;
635 if (item
->prev
== &domain
->sections
)
637 section
= list_entry(item
->prev
, struct cfg_section
, next
);
640 return section
->name
;
643 unsigned int cfg_sections_count(char *dname
)
645 struct list_head
*item
;
646 struct cfg_domain
*domain
;
649 domain
= cfg_find_domain(dname
);
651 list_for_each(item
,&domain
->sections
)
656 char* cfg_sections_index(char *dname
, int i
)
658 struct list_head
*item
;
659 struct cfg_domain
*domain
;
660 struct cfg_section
*section
;
663 domain
= cfg_find_domain(dname
);
667 list_for_each(item
,&domain
->sections
) {
669 section
= list_entry(item
, struct cfg_section
, next
);
672 return section
->name
;
680 cfg_entries_first(char *dname
, char *sname
)
682 struct list_head
*item
;
683 struct cfg_section
*section
;
684 struct cfg_entry
*entry
;
686 section
= cfg_get_sec(dname
,sname
);
690 item
= §ion
->entries
;
691 if (item
->next
== §ion
->entries
)
693 entry
= list_entry(item
->next
, struct cfg_entry
, next
);
699 cfg_entries_next(char *dname
, char *sname
, char *current
)
701 struct list_head
*item
;
702 struct cfg_section
*section
;
703 struct cfg_entry
*entry
;
705 section
= cfg_get_sec(dname
,sname
);
708 entry
= cfg_find_entry(section
,current
);
713 if (item
->next
== §ion
->entries
)
715 entry
= list_entry(item
->next
, struct cfg_entry
, next
);
721 cfg_entries_prev(char *dname
, char *sname
, char *current
)
723 struct list_head
*item
;
724 struct cfg_section
*section
;
725 struct cfg_entry
*entry
;
727 section
= cfg_get_sec(dname
,sname
);
730 entry
= cfg_find_entry(section
,current
);
735 if (item
->prev
== §ion
->entries
)
737 entry
= list_entry(item
->prev
, struct cfg_entry
, next
);
742 unsigned int cfg_entries_count(char *dname
, char *sname
)
744 struct list_head
*item
;
745 struct cfg_section
*section
;
748 section
= cfg_get_sec(dname
,sname
);
750 list_for_each(item
,§ion
->entries
)
755 char* cfg_entries_index(char *dname
, char *sname
, int i
)
757 struct list_head
*item
;
758 struct cfg_section
*section
;
759 struct cfg_entry
*entry
;
762 section
= cfg_get_sec(dname
,sname
);
766 list_for_each(item
,§ion
->entries
) {
768 entry
= list_entry(item
, struct cfg_entry
, next
);
777 char* cfg_search(char *dname
, char *sname
, char *ename
, char *value
)
779 struct list_head
*item1
,*item2
;
780 struct cfg_domain
*domain
;
781 struct cfg_section
*section
;
782 struct cfg_entry
*entry
;
784 domain
= cfg_find_domain(dname
);
787 list_for_each(item1
,&domain
->sections
) {
788 section
= list_entry(item1
, struct cfg_section
, next
);
789 if (sname
&& 0 != strcasecmp(section
->name
,sname
))
792 return section
->name
;
793 list_for_each(item2
,§ion
->entries
) {
794 entry
= list_entry(item2
, struct cfg_entry
, next
);
795 if (0 != strcasecmp(entry
->name
,ename
))
797 if (0 == strcasecmp(entry
->value
,value
))
798 return section
->name
;
804 /* ------------------------------------------------------------------------ */
805 /* get config data */
808 cfg_get_str(char *dname
, char *sname
, char *ename
)
810 struct cfg_entry
*entry
;
812 entry
= cfg_get_ent(dname
, sname
, ename
);
819 cfg_get_int(char *dname
, char *sname
, char *ename
, unsigned int def
)
823 val
= cfg_get_str(dname
,sname
,ename
);
830 cfg_get_signed_int(char *dname
, char *sname
, char *ename
, signed int def
)
834 val
= cfg_get_str(dname
,sname
,ename
);
841 cfg_get_float(char *dname
, char *sname
, char *ename
, float def
)
845 val
= cfg_get_str(dname
,sname
,ename
);
852 cfg_get_bool(char *dname
, char *sname
, char *ename
, int def
)
854 static char *yes
[] = { "true", "yes", "on", "1" };
859 val
= cfg_get_str(dname
,sname
,ename
);
862 for (i
= 0; i
< sizeof(yes
)/sizeof(yes
[0]); i
++)
863 if (0 == strcasecmp(val
,yes
[i
]))
868 /* ------------------------------------------------------------------------ */
871 unsigned int cfg_get_sflags(char *dname
, char *sname
)
873 struct cfg_section
*section
;
875 section
= cfg_get_sec(dname
, sname
);
878 return section
->flags
;
881 unsigned int cfg_get_eflags(char *dname
, char *sname
, char *ename
)
883 struct cfg_entry
*entry
;
885 entry
= cfg_get_ent(dname
, sname
, ename
);
891 unsigned int cfg_set_sflags(char *dname
, char *sname
,
892 unsigned int mask
, unsigned int bits
)
894 struct cfg_section
*section
;
896 section
= cfg_get_sec(dname
, sname
);
899 section
->flags
&= ~mask
;
900 section
->flags
|= bits
;
901 return section
->flags
;
904 unsigned int cfg_set_eflags(char *dname
, char *sname
, char *ename
,
905 unsigned int mask
, unsigned int bits
)
907 struct cfg_entry
*entry
;
909 entry
= cfg_get_ent(dname
, sname
, ename
);
912 entry
->flags
&= ~mask
;
913 entry
->flags
|= bits
;