#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include <glob.h>
#include <sys/types.h>
+#include <ctype.h>
#include <libgen.h>
#include <errno.h>
#include "debug.h"
return 1;
}
-FILE *pushgconffile(struct gconffile **cf, const char *path) {
+FILE *pushgconffile(struct gconffile **cf, FILE *file, const char *description) {
int i;
struct gconffile *newcf;
- char *pathcopy;
- FILE *f;
+ char *desc;
- f = fopen(path, "r");
- if (!f) {
- debug(DBG_INFO, "could not read config file %s", path);
+ if (!file) {
+ debug(DBG_INFO, "could not read config from %s", description);
return NULL;
}
- debug(DBG_DBG, "opened config file %s", path);
+ debug(DBG_DBG, "reading config from %s", description);
- pathcopy = stringcopy(path, 0);
- if (!pathcopy)
+ desc = stringcopy(description, 0);
+ if (!desc)
goto errmalloc;
if (!*cf) {
memmove(newcf + 1, newcf, sizeof(struct gconffile) * (i + 1));
memset(newcf, 0, sizeof(struct gconffile));
}
- newcf[0].file = f;
- newcf[0].path = pathcopy;
+ newcf[0].file = file;
+ newcf[0].path = desc;
*cf = newcf;
- return f;
+ return file;
errmalloc:
- free(pathcopy);
- fclose(f);
+ free(desc);
+ fclose(file);
debug(DBG_ERR, "malloc failed");
return NULL;
}
-FILE *pushgconffiles(struct gconffile **cf, const char *cfgpath) {
+FILE *pushgconfpath(struct gconffile **cf, const char *path) {
+ FILE *f;
+
+ f = fopen(path, "r");
+ return pushgconffile(cf, f, path);
+}
+
+FILE *pushgconfpaths(struct gconffile **cf, const char *cfgpath) {
int i;
FILE *f = NULL;
glob_t globbuf;
}
for (i = globbuf.gl_pathc - 1; i >= 0; i--) {
- f = pushgconffile(cf, globbuf.gl_pathv[i]);
+ f = pushgconfpath(cf, globbuf.gl_pathv[i]);
if (!f)
break;
}
return f;
}
-int popgconffile(struct gconffile **cf) {
+int popgconf(struct gconffile **cf) {
int i;
if (!*cf)
struct gconffile *openconfigfile(const char *file) {
struct gconffile *cf = NULL;
- if (!pushgconffile(&cf, file)) {
+ if (!pushgconfpath(&cf, file)) {
debug(DBG_ERR, "could not read config file %s\n%s", file, strerror(errno));
return NULL;
}
for (;;) {
if (!getlinefromcf(*cf, line, 1024)) {
- if (popgconffile(cf))
+ if (popgconf(cf))
continue;
return 1;
}
return 0;
}
+uint8_t hexdigit2int(char d) {
+ if (d >= '0' && d <= '9')
+ return d - '0';
+ if (d >= 'a' && d <= 'f')
+ return 10 + d - 'a';
+ if (d >= 'A' && d <= 'F')
+ return 10 + d - 'A';
+ return 0;
+}
+
+void unhex(char *s) {
+ char *t;
+ for (t = s; *t; s++) {
+ if (*t == '%' && isxdigit(t[1]) && isxdigit(t[2])) {
+ *s = 16 * hexdigit2int(t[1]) + hexdigit2int(t[2]);
+ t += 3;
+ } else
+ *s = *t++;
+ }
+ *s = '\0';
+}
+
/* returns 1 if ok, 0 on error */
/* caller must free returned values also on error */
int getgenericconfig(struct gconffile **cf, char *block, ...) {
va_list ap;
- char *opt = NULL, *val, *word, *optval, **str = NULL, ***mstr = NULL, **newmstr;
- uint8_t *bln;
+ char *opt = NULL, *val, *word, *optval, **str = NULL, ***mstr = NULL, **newmstr, *endptr;
+ uint8_t *bln = NULL;
+ long int *lint = NULL;
int type = 0, conftype = 0, n;
- void (*cbk)(struct gconffile **, void *, char *, char *, char *) = NULL;
+ int (*cbk)(struct gconffile **, void *, char *, char *, char *) = NULL;
void *cbkarg = NULL;
for (;;) {
return 1;
if (conftype == CONF_STR && !strcasecmp(opt, "include")) {
- if (!pushgconffiles(cf, val)) {
+ if (!pushgconfpaths(cf, val)) {
debug(DBG_ERR, "failed to include config file %s", val);
goto errexit;
}
if (!bln)
goto errparam;
break;
+ case CONF_LINT:
+ lint = va_arg(ap, long int *);
+ if (!lint)
+ goto errparam;
+ break;
case CONF_CBK:
- cbk = va_arg(ap, void (*)(struct gconffile **, void *, char *, char *, char *));
+ cbk = va_arg(ap, int (*)(struct gconffile **, void *, char *, char *, char *));
if (!cbk)
goto errparam;
cbkarg = va_arg(ap, void *);
goto errexit;
}
- if (((type == CONF_STR || type == CONF_MSTR || type == CONF_BLN) && conftype != CONF_STR) ||
+ if (((type == CONF_STR || type == CONF_MSTR || type == CONF_BLN || type == CONF_LINT) && conftype != CONF_STR) ||
(type == CONF_CBK && conftype != CONF_CBK)) {
if (block)
debug(DBG_ERR, "configuration error in block %s, wrong syntax for option %s", block, opt);
debug(DBG_ERR, "configuration error, option %s already set to %s", opt, *str);
goto errexit;
}
+ unhex(val);
*str = val;
break;
case CONF_MSTR:
debug(DBG_ERR, "malloc failed");
goto errexit;
}
+ unhex(val);
newmstr[n] = val;
newmstr[n + 1] = NULL;
*mstr = newmstr;
goto errexit;
}
break;
+ case CONF_LINT:
+ endptr = NULL;
+ *lint = strtol(val, &endptr, 0);
+ if (*lint == LONG_MIN || *lint == LONG_MAX || !endptr || endptr == val || *endptr != '\0') {
+ if (block)
+ debug(DBG_ERR, "configuration error in block %s, value for option %s must be an integer, not %s", block, opt, val);
+ else
+ debug(DBG_ERR, "configuration error, value for option %s must be an integer, not %s", opt, val);
+ goto errexit;
+ }
+ break;
case CONF_CBK:
optval = malloc(strlen(opt) + strlen(val) + 2);
if (!optval) {
goto errexit;
}
sprintf(optval, "%s %s", opt, val);
- cbk(cf, cbkarg, optval, opt, val);
+ if (!cbk(cf, cbkarg, optval, opt, val)) {
+ free(optval);
+ goto errexit;
+ }
free(val);
free(optval);
continue;
debug(DBG_DBG, "getgenericconfig: block %s: %s = %s", block, opt, val);
else
debug(DBG_DBG, "getgenericconfig: %s = %s", opt, val);
- if (type == CONF_BLN)
+ if (type == CONF_BLN || type == CONF_LINT)
free(val);
}