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