]> mj.ucw.cz Git - libucw.git/blob - lib/conf.c
rewritten, enhanced, updated, fixed
[libucw.git] / lib / conf.c
1 /*
2  *      Sherlock Library -- Reading configuration files
3  *
4  *      (c) 2001 Robert Spalek <robert@ucw.cz>
5  */
6
7 #include "lib/lib.h"
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <getopt.h>
14
15 #include "lib/chartype.h"
16 #include "lib/fastbuf.h"
17 #include "lib/lfs.h"
18
19 #include "lib/conf.h"
20
21 #define BUFFER          1024
22 #define MAX_LEVEL       8
23
24 static struct cfitem *cfsection;
25
26 void cf_register(struct cfitem *items)
27 {
28         if(items[0].type!=CT_SECTION)
29                 die("Invalid configuration section, first item must be of type CT_SECTION");
30         items[0].var=cfsection;
31         cfsection=items;
32 }
33
34 byte *cf_set_item(byte *sect, byte *name, byte *value)
35 {
36         struct cfitem *item;
37         byte *msg=NULL;
38
39         item=cfsection;
40         while(item && strcasecmp(item->name,sect))
41                 item=item->var;
42         if(!item)       /* ignore unknown section */
43                 return NULL;
44
45         for(item++; item->type && strcasecmp(item->name,name); item++);
46
47         switch(item->type){
48                 case CT_INT:
49                         {
50                                 char *end;
51                                 if(!*value)
52                                         msg="Missing number";
53                                 else{
54                                         *((uns *) item->var) = strtoul(value, &end, 0);
55                                         if (end && *end)
56                                                 msg = "Invalid number";
57                                 }
58                                 break;
59                         }
60                 case CT_STRING:
61                         *((byte **) item->var) = stralloc(value);
62                         break;
63                 case CT_FUNCTION:
64                         msg = ((ci_func) item->var)(item, value);
65                         break;
66                 default:
67                         msg = "Unknown keyword";
68                         break;
69         }
70
71         return msg;
72 }
73
74 static int cf_subread(byte *filename,int level)
75 {
76         int fd;
77         struct fastbuf *b;
78         byte def_section[BUFFER];
79         int line;
80         byte *msg=NULL;
81
82         if(level>=MAX_LEVEL){
83                 log(L_ERROR,"Too many (%d) nested files when reading %s",level,filename);
84                 return 0;
85         }
86                 
87         fd=sh_open(filename,O_RDONLY, 0666);
88         if(fd<0){
89                 log(L_ERROR,"Cannot open configuration file %s: %m",filename);
90                 return 0;
91         }
92         b=bfdopen(fd,4096);
93
94         def_section[0]=0;
95         line=0;
96         while(1){
97                 byte buf[BUFFER];
98                 byte *c;
99
100                 if(!bgets(b,buf,BUFFER))
101                         break;
102                 line++;
103
104                 c=buf+strlen(buf);
105                 while(c>buf && Cspace(c[-1]))
106                         *--c=0;
107                 c=buf;
108                 while(*c && Cspace(*c))
109                         c++;
110                 if(!*c || *c=='#')
111                         continue;
112
113                 if(*c=='['){
114                         strcpy(def_section,c+1);
115                         c=strchr(def_section,']');
116                         if(c){
117                                 *c=0;
118                                 if(c[1]){
119                                         msg="Garbage after ]";
120                                         break;
121                                 }
122                         }else{
123                                 msg="Missing ]";
124                                 break;
125                         }
126
127                 }else{
128                         byte *sect,*name,*value;
129
130                         name=c;
131                         while(*c && !Cspace(*c))
132                                 c++;
133                         while(*c && Cspace(*c))
134                                 *c++=0;
135                         value=c;
136
137                         if(!strcasecmp(name,"include")){
138                                 if(!cf_subread(value,level+1)){
139                                         msg="Included from here";
140                                         break;
141                                 }
142                         }else{
143                                 c=strchr(name,'.');
144                                 if(!c)
145                                         sect=def_section;
146                                 else{
147                                         sect=name;
148                                         *c++=0;
149                                         name=c;
150                                 }
151
152                                 msg=cf_set_item(sect,name,value);
153                         }
154                         if(msg)
155                                 break;
156                 }
157
158         }       /* for every line */
159
160         if(msg)
161                 log(L_ERROR,"%s, line %d: %s",filename,line,msg);
162         bclose(b);
163         return !msg;
164 }
165
166 void cf_read(byte *filename)
167 {
168         if(!cf_subread(filename,0))
169                 die("Reading config file %s failed",filename);
170 }
171
172 int cf_getopt(int argc,char * const argv[],
173                 const char *shortopts,const struct option *longopts,
174                 int *longindex)
175 {
176         int res;
177
178         do{
179                 res=getopt_long(argc,argv,shortopts,longopts,longindex);
180                 if(res=='S'){
181                         byte *sect,*name,*value;
182                         byte *c;
183                         byte *msg=NULL;
184
185                         name=optarg;
186                         c=strchr(name,'=');
187                         if(!c){
188                                 msg="Missing argument";
189                                 sect=value="";
190                         }else{
191                                 *c++=0;
192                                 value=c;
193
194                                 c=strchr(name,'.');
195                                 if(!c)
196                                         sect="";
197                                 else{
198                                         sect=name;
199                                         *c++=0;
200                                         name=c;
201                                 }
202
203                                 msg=cf_set_item(sect,name,value);
204                         }
205                         if(msg)
206                                 die("Invalid command line argument %s.%s=%s: %s",sect,name,value,msg);
207
208                 }else if(res=='C'){
209                         cf_read(optarg);
210                 }else{  /* unhandled option */
211                         return res;
212                 }
213         }while(1);
214 }
215