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