]> mj.ucw.cz Git - libucw.git/blob - lib/conf.c
empty section of configuration item forbidden
[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/pools.h"
18
19 #include "lib/conf.h"
20
21 #define BUFFER          1024
22 #define MAX_LEVEL       8
23
24 static struct cfitem *cfsection;
25 static struct mempool *cfpool;
26
27 byte *cfdeffile = DEFAULT_CONFIG;
28
29 static void CONSTRUCTOR
30 conf_init(void)
31 {
32         cfpool = mp_new(4096);
33 }
34
35 void *
36 cfg_malloc(uns size)
37 {
38         return mp_alloc(cfpool, size);
39 }
40
41 byte *
42 cfg_stralloc(byte *s)
43 {
44   uns l = strlen(s);
45   byte *k = cfg_malloc(l + 1);
46   strcpy(k, s);
47   return k;
48 }
49
50 void cf_register(struct cfitem *items)
51 {
52         if(items[0].type!=CT_SECTION)
53                 die("Invalid configuration section, first item must be of type CT_SECTION");
54         items[0].var=cfsection;
55         cfsection=items;
56 }
57
58 int cf_item_count(void)
59 {
60         struct cfitem *sect, *item;
61         int count = 0;
62         for (sect = cfsection; sect; sect = sect->var)
63                 for (item = sect+1; item->type; item++)
64                         count++;
65         return count;
66 }
67
68 struct cfitem *cf_get_item(byte *sect, byte *name)
69 {
70         struct cfitem *item;
71
72         item=cfsection;
73         while(item && strcasecmp(item->name,sect))
74                 item=item->var;
75         if(!item)       /* unknown section */
76                 return NULL;
77
78         for(item++; item->type && strcasecmp(item->name,name); item++);
79
80         return item;    /* item->type == 0 if not found */
81 }
82
83 byte *cf_set_item(byte *sect, byte *name, byte *value)
84 {
85         struct cfitem *item;
86         byte *msg=NULL;
87
88         if (!*sect)
89                 return "Empty section name";
90         item=cf_get_item(sect,name);
91         if(!item)       /* ignore unknown section */
92                 return NULL;
93
94         switch(item->type){
95                 case CT_INT:
96                         {
97                                 char *end;
98                                 if(!*value)
99                                         msg="Missing number";
100                                 else{
101                                         *((uns *) item->var) = strtoul(value, &end, 0);
102                                         if (end && *end)
103                                                 msg = "Invalid number";
104                                 }
105                                 break;
106                         }
107                 case CT_STRING:
108                         *((byte **) item->var) = cfg_stralloc(value);
109                         break;
110                 case CT_FUNCTION:
111                         msg = ((ci_func) item->var)(item, cfg_stralloc(value));
112                         break;
113                 default:
114                         msg = "Unknown keyword";
115                         break;
116         }
117
118         return msg;
119 }
120
121 static int cf_subread(byte *filename,int level)
122 {
123         int fd;
124         struct fastbuf *b;
125         byte def_section[BUFFER];
126         int line;
127         byte *msg=NULL;
128
129         if(level>=MAX_LEVEL){
130                 log(L_ERROR,"Too many (%d) nested files when reading %s",level,filename);
131                 return 0;
132         }
133                 
134         fd=open(filename,O_RDONLY, 0666);
135         if(fd<0){
136                 log(L_ERROR,"Cannot open configuration file %s: %m",filename);
137                 return 0;
138         }
139         b=bfdopen(fd,4096);
140
141         def_section[0]=0;
142         line=0;
143         while(1){
144                 byte buf[BUFFER];
145                 byte *c;
146
147                 if(!bgets(b,buf,BUFFER))
148                         break;
149                 line++;
150
151                 c=buf+strlen(buf);
152                 while(c>buf && Cspace(c[-1]))
153                         *--c=0;
154                 c=buf;
155                 while(*c && Cspace(*c))
156                         c++;
157                 if(!*c || *c=='#')
158                         continue;
159
160                 if(*c=='['){
161                         strcpy(def_section,c+1);
162                         c=strchr(def_section,']');
163                         if(c){
164                                 *c=0;
165                                 if(c[1]){
166                                         msg="Garbage after ]";
167                                         break;
168                                 }
169                         }else{
170                                 msg="Missing ]";
171                                 break;
172                         }
173
174                 }else{
175                         byte *sect,*name,*value;
176
177                         name=c;
178                         while(*c && !Cspace(*c))
179                                 c++;
180                         while(*c && Cspace(*c))
181                                 *c++=0;
182                         value=c;
183
184                         if(!strcasecmp(name,"include")){
185                                 if(!cf_subread(value,level+1)){
186                                         msg="Included from here";
187                                         break;
188                                 }
189                         }else{
190                                 c=strchr(name,'.');
191                                 if(!c)
192                                         sect=def_section;
193                                 else{
194                                         sect=name;
195                                         *c++=0;
196                                         name=c;
197                                 }
198
199                                 msg=cf_set_item(sect,name,value);
200                         }
201                         if(msg)
202                                 break;
203                 }
204
205         }       /* for every line */
206
207         if(msg)
208                 log(L_ERROR,"%s, line %d: %s",filename,line,msg);
209         bclose(b);
210         return !msg;
211 }
212
213 void cf_read(byte *filename)
214 {
215         if(!cf_subread(filename,0))
216                 die("Reading config file %s failed",filename);
217         cfdeffile = NULL;
218 }
219
220 int cf_getopt(int argc,char * const argv[],
221                 const char *shortopts,const struct option *longopts,
222                 int *longindex)
223 {
224         int res;
225
226         do{
227                 res=getopt_long(argc,argv,shortopts,longopts,longindex);
228                 if(res=='S'){
229                         byte *sect,*name,*value;
230                         byte *c;
231                         byte *msg=NULL;
232
233                         name=optarg;
234                         c=strchr(name,'=');
235                         if(!c){
236                                 msg="Missing argument";
237                                 sect=value="";
238                         }else{
239                                 *c++=0;
240                                 value=c;
241
242                                 c=strchr(name,'.');
243                                 if(!c)
244                                         sect="";
245                                 else{
246                                         sect=name;
247                                         *c++=0;
248                                         name=c;
249                                 }
250
251                                 if (cfdeffile)
252                                         cf_read(cfdeffile);
253                                 msg=cf_set_item(sect,name,value);
254                         }
255                         if(msg)
256                                 die("Invalid command line argument %s.%s=%s: %s",sect,name,value,msg);
257
258                 }else if(res=='C'){
259                         cf_read(optarg);
260                 }else{
261                         /* unhandled option or end of options */
262                         if(cfdeffile)
263                                 cf_read(cfdeffile);
264                         return res;
265                 }
266         }while(1);
267 }