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