]> mj.ucw.cz Git - libucw.git/blob - lib/conf.c
bugfix
[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; sect->type; sect++)
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         item=cf_get_item(sect,name);
89         if(!item)       /* ignore unknown section */
90                 return NULL;
91
92         switch(item->type){
93                 case CT_INT:
94                         {
95                                 char *end;
96                                 if(!*value)
97                                         msg="Missing number";
98                                 else{
99                                         *((uns *) item->var) = strtoul(value, &end, 0);
100                                         if (end && *end)
101                                                 msg = "Invalid number";
102                                 }
103                                 break;
104                         }
105                 case CT_STRING:
106                         *((byte **) item->var) = cfg_stralloc(value);
107                         break;
108                 case CT_FUNCTION:
109                         msg = ((ci_func) item->var)(item, cfg_stralloc(value));
110                         break;
111                 default:
112                         msg = "Unknown keyword";
113                         break;
114         }
115
116         return msg;
117 }
118
119 static int cf_subread(byte *filename,int level)
120 {
121         int fd;
122         struct fastbuf *b;
123         byte def_section[BUFFER];
124         int line;
125         byte *msg=NULL;
126
127         if(level>=MAX_LEVEL){
128                 log(L_ERROR,"Too many (%d) nested files when reading %s",level,filename);
129                 return 0;
130         }
131                 
132         fd=open(filename,O_RDONLY, 0666);
133         if(fd<0){
134                 log(L_ERROR,"Cannot open configuration file %s: %m",filename);
135                 return 0;
136         }
137         b=bfdopen(fd,4096);
138
139         def_section[0]=0;
140         line=0;
141         while(1){
142                 byte buf[BUFFER];
143                 byte *c;
144
145                 if(!bgets(b,buf,BUFFER))
146                         break;
147                 line++;
148
149                 c=buf+strlen(buf);
150                 while(c>buf && Cspace(c[-1]))
151                         *--c=0;
152                 c=buf;
153                 while(*c && Cspace(*c))
154                         c++;
155                 if(!*c || *c=='#')
156                         continue;
157
158                 if(*c=='['){
159                         strcpy(def_section,c+1);
160                         c=strchr(def_section,']');
161                         if(c){
162                                 *c=0;
163                                 if(c[1]){
164                                         msg="Garbage after ]";
165                                         break;
166                                 }
167                         }else{
168                                 msg="Missing ]";
169                                 break;
170                         }
171
172                 }else{
173                         byte *sect,*name,*value;
174
175                         name=c;
176                         while(*c && !Cspace(*c))
177                                 c++;
178                         while(*c && Cspace(*c))
179                                 *c++=0;
180                         value=c;
181
182                         if(!strcasecmp(name,"include")){
183                                 if(!cf_subread(value,level+1)){
184                                         msg="Included from here";
185                                         break;
186                                 }
187                         }else{
188                                 c=strchr(name,'.');
189                                 if(!c)
190                                         sect=def_section;
191                                 else{
192                                         sect=name;
193                                         *c++=0;
194                                         name=c;
195                                 }
196
197                                 msg=cf_set_item(sect,name,value);
198                         }
199                         if(msg)
200                                 break;
201                 }
202
203         }       /* for every line */
204
205         if(msg)
206                 log(L_ERROR,"%s, line %d: %s",filename,line,msg);
207         bclose(b);
208         return !msg;
209 }
210
211 void cf_read(byte *filename)
212 {
213         if(!cf_subread(filename,0))
214                 die("Reading config file %s failed",filename);
215         cfdeffile = NULL;
216 }
217
218 int cf_getopt(int argc,char * const argv[],
219                 const char *shortopts,const struct option *longopts,
220                 int *longindex)
221 {
222         int res;
223
224         do{
225                 res=getopt_long(argc,argv,shortopts,longopts,longindex);
226                 if(res=='S'){
227                         byte *sect,*name,*value;
228                         byte *c;
229                         byte *msg=NULL;
230
231                         name=optarg;
232                         c=strchr(name,'=');
233                         if(!c){
234                                 msg="Missing argument";
235                                 sect=value="";
236                         }else{
237                                 *c++=0;
238                                 value=c;
239
240                                 c=strchr(name,'.');
241                                 if(!c)
242                                         sect="";
243                                 else{
244                                         sect=name;
245                                         *c++=0;
246                                         name=c;
247                                 }
248
249                                 if (cfdeffile)
250                                         cf_read(cfdeffile);
251                                 msg=cf_set_item(sect,name,value);
252                         }
253                         if(msg)
254                                 die("Invalid command line argument %s.%s=%s: %s",sect,name,value,msg);
255
256                 }else if(res=='C'){
257                         cf_read(optarg);
258                 }else if(res==-1){
259                         if(cfdeffile)
260                                 cf_read(cfdeffile);
261                         return res;
262                 }else{  /* unhandled option */
263                         return res;
264                 }
265         }while(1);
266 }
267