2 * UCW Library -- Reading of configuration files
4 * (c) 2001 Robert Spalek <robert@ucw.cz>
5 * (c) 2003--2005 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
12 #include "lib/chartype.h"
13 #include "lib/fastbuf.h"
14 #include "lib/mempool.h"
28 static struct cfitem *cfsection;
29 struct mempool *cfpool;
31 #ifndef DEFAULT_CONFIG
32 #define DEFAULT_CONFIG NULL
35 byte *cfdeffile = DEFAULT_CONFIG;
37 static void CONSTRUCTOR
40 cfpool = mp_new(4096);
46 return mp_alloc(cfpool, size);
50 cfg_malloc_zero(uns size)
52 return mp_alloc_zero(cfpool, size);
58 return mp_strdup(cfpool, s);
62 cfg_printf(char *fmt, ...)
66 byte *res = mp_vprintf(cfpool, fmt, args);
71 void cf_register(struct cfitem *items)
73 if(items[0].type!=CT_SECTION && items[0].type!=CT_INCOMPLETE_SECTION)
74 die("cf_register: Invalid section type");
75 items[0].var=cfsection;
79 int cf_item_count(void)
81 struct cfitem *sect, *item;
83 for (sect = cfsection; sect; sect = sect->var)
84 for (item = sect+1; item->type; item++)
89 struct cfitem *cf_get_item(byte *sect, byte *name)
91 struct cfitem *item, *section;
94 while(item && strcasecmp(item->name,sect))
96 if(!item) /* unknown section */
100 for(item++; item->type && strcasecmp(item->name,name); item++);
101 if (!item->type && section->type == CT_INCOMPLETE_SECTION)
104 return item; /* item->type == 0 if not found */
108 uns name; /* One-letter name of the unit */
109 uns num, den; /* Fraction */
112 static const struct unit units[] = {
117 { 'g', 1000000000, 1 },
120 { 'G', 1073741824, 1 },
126 static const struct unit *cf_lookup_unit(byte *value, byte *end, char **msg)
129 if (end == value || end[1] || *end >= '0' && *end <= '9')
130 *msg = "Invalid number";
132 for (const struct unit *u=units; u->name; u++)
135 *msg = "Invalid unit";
141 static char cf_rngerr[] = "Number out of range";
143 byte *cf_parse_int(byte *value, uns *varp)
146 const struct unit *u;
149 msg = "Missing number";
153 uns x = strtoul(value, &end, 0);
156 else if (u = cf_lookup_unit(value, end, &msg)) {
157 u64 y = (u64)x * u->num;
159 msg = "Number is not an integer";
172 byte *cf_parse_u64(byte *value, u64 *varp)
175 const struct unit *u;
178 msg = "Missing number";
182 u64 x = strtoull(value, &end, 0);
185 else if (u = cf_lookup_unit(value, end, &msg)) {
186 if (x > ~(u64)0 / u->num)
187 msg = "Number out of range";
191 msg = "Number is not an integer";
201 byte *cf_parse_double(byte *value, double *varp)
204 const struct unit *u;
207 msg = "Missing number";
211 double x = strtoul(value, &end, 0);
214 else if (u = cf_lookup_unit(value, end, &msg))
215 *varp = x * u->num / u->den;
223 cf_parse_ip(byte **p, u32 *varp)
228 return "Missing IP address";
230 if (**p == '0' && *(*p + 1) | 32 == 'X')
233 x = strtoul(*p + 2, (char **)p, 16);
234 if (errno == ERANGE || x > 0xffffffff)
238 for (uns i = 0; i < 4; i++)
250 uns y = strtoul(*p, (char **)p, 10);
251 if (errno == ERANGE || y > 255)
258 return "Invalid IP address";
262 byte *cf_set_item(byte *sect, byte *name, byte *value)
268 return "Empty section name";
269 item=cf_get_item(sect,name);
270 if(!item) /* ignore unknown section */
275 msg = cf_parse_int(value, (uns *) item->var);
278 *((byte **) item->var) = cfg_strdup(value);
281 msg = ((ci_func) item->var)(item, cfg_strdup(value));
284 msg = cf_parse_double(value, (double *) item->var);
287 msg = cf_parse_u64(value, (u64 *) item->var);
290 msg = "Unknown keyword";
296 static int cf_subread(byte *filename,int level)
300 byte def_section[BUFFER];
304 if(level>=MAX_LEVEL){
305 log(L_ERROR,"Too many (%d) nested files when reading %s",level,filename);
309 fd=open(filename,O_RDONLY, 0666);
311 log(L_ERROR,"Cannot open configuration file %s: %m",filename);
322 if(!bgets(b,buf,BUFFER))
327 while(c>buf && Cspace(c[-1]))
330 while(*c && Cspace(*c))
336 strcpy(def_section,c+1);
337 c=strchr(def_section,']');
341 msg="Garbage after ]";
350 byte *sect,*name,*value;
353 while(*c && !Cspace(*c))
355 while(*c && Cspace(*c))
359 if(!strcasecmp(name,"include")){
360 if(!cf_subread(value,level+1)){
361 msg="Included from here";
374 msg=cf_set_item(sect,name,value);
380 } /* for every line */
383 log(L_ERROR,"%s, line %d: %s",filename,line,msg);
388 void cf_read(byte *filename)
390 if(!cf_subread(filename,0))
391 die("Reading config file %s failed",filename);
395 static void cf_opt_S(void)
397 byte *sect,*name,*value;
400 byte arg[strlen(optarg)+1];
406 msg="Missing argument";
423 msg=cf_set_item(sect,name,value);
426 die("Invalid command line argument -S%s.%s=%s: %s",sect,name,value,msg);
430 int cf_getopt(int argc,char * const argv[],
431 const char *shortopts,const struct option *longopts,
435 static int other_options;
438 res=getopt_long(argc,argv,shortopts,longopts,longindex);
439 if(res == 'S' || res == 'C') {
441 die("The -S and -C options must precede all other arguments");
448 /* unhandled option or end of options */