]> mj.ucw.cz Git - libucw.git/blob - lib/conf.c
bugfixes
[libucw.git] / lib / conf.c
1 /* Reading conf files
2  * Robert Spalek, (c) 2001, robert@ucw.cz
3  * $Id: conf.c,v 1.2 2001/01/08 10:26:37 robert Exp $
4  */
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <fcntl.h>
11 #include <getopt.h>
12
13 #include "lib/lib.h"
14 #include "lib/fastbuf.h"
15
16 #include "lib/conf.h"
17
18 #define BUFFER          1024
19 #define MAX_LEVEL       8
20
21 #define MAX_SECTIONS    64
22
23 static struct {
24         byte *section;
25         struct cfitem *items;
26 } cfsection[MAX_SECTIONS];
27 static int cfsections;
28
29 #define MAX_SHORT_OPTS  128
30 #define MAX_LONG_OPTS   64
31
32 static byte shortopts[MAX_SHORT_OPTS] = "S:C:";
33 static int shortlen=4;
34
35 static struct option longopts[MAX_LONG_OPTS] =
36 {
37         {"set",         1, 0, 'S'},
38         {"config",      1, 0, 'C'}
39 };
40 static int longlen=2;
41
42 void cf_register(byte *section,struct cfitem *items)
43 {
44         if(cfsections>=MAX_SECTIONS)
45                 die("too many modules %d",cfsections);
46         cfsection[cfsections].section=section;
47         cfsection[cfsections].items=items;
48         cfsections++;
49 }
50
51 static byte *cf_set_item(byte *sect, byte *name, byte *value)
52 {
53         int idsect;
54         struct cfitem *item;
55         byte *msg=NULL;
56
57         idsect=0;
58         while(idsect<cfsections && strcasecmp(sect,cfsection[idsect].section))
59                 idsect++;
60         if(idsect>=cfsections)  /* ignore unknown section */
61                 return NULL;
62
63         item=cfsection[idsect].items;
64         while(item->type && strcasecmp(name,item->name))
65                 item++;
66         switch(item->type){
67                 case ct_int:
68                         {
69                                 char *end;
70                                 *((uns *) item->var) = strtoul(value, &end, 0);
71                                 if (end && *end)
72                                         msg = "Invalid number";
73                                 break;
74                         }
75                 case ct_string:
76                         *((byte **) item->var) = stralloc(value);
77                         break;
78                 case ct_function:
79                         msg = ((ci_func) item->var)(item, value);
80                         break;
81                 default:
82                         msg = "Unknown keyword";
83                         break;
84         }
85
86         return msg;
87 }
88
89 static int cf_subread(byte *filename,int level)
90 {
91         struct fastbuf *b;
92         byte def_section[BUFFER];
93         int line;
94         byte *msg=NULL;
95
96         if(level>=MAX_LEVEL){
97                 log("Too many nested files %d",level);
98                 return 0;
99         }
100                 
101         b=bopen(filename,O_RDONLY,4096);
102         if(!b){
103                 log("Cannot open file %s",filename);
104                 return 0;
105         }
106
107         def_section[0]=0;
108         line=0;
109         while(1){
110                 byte buf[BUFFER];
111                 byte *c;
112
113                 if(!bgets(b,buf,BUFFER))
114                         break;
115                 line++;
116
117                 c=buf;
118                 while(*c && isspace(*c))
119                         c++;
120                 if(!*c || *c=='#')
121                         continue;
122
123                 if(*c=='['){
124                         strcpy(def_section,c+1);
125                         c=strchr(def_section,']');
126                         if(c)
127                                 *c=0;
128                         else{
129                                 msg="Missing ]";
130                                 break;
131                         }
132
133                 }else if(*c=='<'){
134                         if(!cf_subread(c+1,level+1)){
135                                 msg="";
136                                 break;
137                         }
138                 
139                 }else{
140                         byte *sect,*name,*value;
141
142                         name=c;
143                         c=strpbrk(c," \t");
144                         while(c && *c && isspace(*c))
145                                 *c++=0;
146                         if(!c || !*c){
147                                 msg="Missing argument";
148                                 break;
149                         }
150                         value=c;
151
152                         c=strchr(name,'.');
153                         if(!c)
154                                 sect=def_section;
155                         else{
156                                 sect=name;
157                                 *c++=0;
158                                 name=c;
159                         }
160
161                         msg=cf_set_item(sect,name,value);
162                         if(msg)
163                                 break;
164                 }
165
166         }       /* for every line */
167
168         if(msg)
169                 log("%s, line %d: %s",filename,line,msg);
170         bclose(b);
171         return !msg;
172 }
173
174 int cf_read(byte *filename)
175 {
176         return cf_subread(filename,0);
177 }
178
179 void cf_read_err(byte *filename)
180 {
181         if(!cf_read(filename))
182                 die("Reading config file %s failed",filename);
183 }
184
185 void cf_register_opts(byte *so,struct option *lo)
186 {
187         int l;
188
189         l=strlen(so);
190         if(shortlen+l>=MAX_SHORT_OPTS)
191                 die("Too many short options %d",shortlen+l);
192         strcat(shortopts,so);
193
194         l=longlen;
195         while(lo->name){
196                 if(l>=MAX_LONG_OPTS)
197                         die("Too many long options %d",l);
198                 longopts[l++]=*lo++;
199         }
200 }
201
202 int cf_getopt(int argc,char * const argv[], int *longindex)
203 {
204         int res;
205
206         do{
207                 res=getopt_long(argc,argv,shortopts,longopts,longindex);
208                 if(res=='S'){
209                         byte *sect,*name,*value;
210                         byte *c;
211                         byte *msg=NULL;
212
213
214                         name=optarg;
215                         c=strchr(name,'=');
216                         if(!c){
217                                 msg="Missing argument";
218                                 sect=value="";
219                         }else{
220                                 *c++=0;
221                                 value=c;
222
223                                 c=strchr(name,'.');
224                                 if(!c)
225                                         sect="";
226                                 else{
227                                         sect=name;
228                                         *c++=0;
229                                         name=c;
230                                 }
231
232                                 msg=cf_set_item(sect,name,value);
233                         }
234                         if(msg)
235                                 die("Invalid command line argument %s.%s=%s: %s",sect,name,value,msg);
236
237                 }else if(res=='C'){
238                         cf_read_err(optarg);
239
240                 }else{  /* unhandled option */
241                         return res;
242                 }
243
244         }while(1);
245 }
246