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