]> mj.ucw.cz Git - libucw.git/blob - lib/conf.c
written parsing config files and command line parameters, untested yet
[libucw.git] / lib / conf.c
1 /* Reading conf files
2  * Robert Spalek, (c) 2001, robert@ucw.cz
3  * $Id: conf.c,v 1.1 2001/01/07 21:21:53 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
116                 c=buf;
117                 while(*c && isspace(*c))
118                         c++;
119                 if(!*c || *c=='#')
120                         continue;
121
122                 if(*c=='['){
123                         strcpy(def_section,c+1);
124                         c=strchr(def_section,']');
125                         if(c)
126                                 *c=0;
127                         else{
128                                 msg="Missing ]";
129                                 break;
130                         }
131
132                 }else if(*c='<'){
133                         if(!cf_subread(c+1,level+1)){
134                                 msg="";
135                                 break;
136                         }
137                 
138                 }else{
139                         byte *sect,*name,*value;
140
141                         name=c;
142                         c=strpbrk(c," \t");
143                         while(c && *c && isspace(*c))
144                                 c++;
145                         if(!c || !*c){
146                                 msg="Missing argument";
147                                 break;
148                         }
149                         value=c;
150
151                         c=strchr(name,'.');
152                         if(!c)
153                                 sect=def_section;
154                         else{
155                                 sect=name;
156                                 *c++=0;
157                                 name=c;
158                         }
159
160                         msg=cf_set_item(sect,name,value);
161                         if(msg)
162                                 break;
163                 }
164
165         }       /* for every line */
166
167         if(msg)
168                 log("%s, line %d: %s",msg);
169         bclose(b);
170         return !msg;
171 }
172
173 int cf_read(byte *filename)
174 {
175         return cf_subread(filename,0);
176 }
177
178 void cf_read_err(byte *filename)
179 {
180         if(!cf_read(filename))
181                 die("Reading config file %s failed",filename);
182 }
183
184 void cf_register_opts(byte *so,struct option *lo)
185 {
186         int l;
187
188         l=strlen(so);
189         if(shortlen+l>=MAX_SHORT_OPTS)
190                 die("Too many short options %d",shortlen+l);
191         strcat(shortopts,so);
192
193         l=longlen;
194         while(lo->name){
195                 if(l>=MAX_LONG_OPTS)
196                         die("Too many long options %d",l);
197                 longopts[l++]=*lo++;
198         }
199 }
200
201 int cf_getopt(int argc,char * const argv[], int *longindex)
202 {
203         int res;
204
205         do{
206                 res=getopt_long(argc,argv,shortopts,longopts,longindex);
207                 if(res=='S'){
208                         byte *sect,*name,*value;
209                         byte *c;
210                         byte *msg=NULL;
211
212
213                         name=optarg;
214                         c=strchr(name,'=');
215                         if(!c){
216                                 msg="Missing argument";
217                                 sect=value="";
218                         }else{
219                                 *c++=0;
220                                 value=c;
221
222                                 c=strchr(name,'.');
223                                 if(!c)
224                                         sect="";
225                                 else{
226                                         sect=name;
227                                         *c++=0;
228                                         name=c;
229                                 }
230
231                                 msg=cf_set_item(sect,name,value);
232                         }
233                         if(msg)
234                                 die("Invalid command line argument %s.%s=%s: %s",sect,name,value,msg);
235
236                 }else if(res=='C'){
237                         cf_read_err(optarg);
238
239                 }else{  /* unhandled option */
240                         return res;
241                 }
242
243         }while(1);
244 }
245