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