+ if (**val)
+ return 1;
+
+ debug(DBG_ERR, "configuration error, option %s needs a non-empty value", *opt);
+ goto errexit;
+
+errmalloc:
+ debug(DBG_ERR, "malloc failed");
+errexit:
+ free(*opt);
+ *opt = NULL;
+ free(*val);
+ *val = NULL;
+ 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((int)t[1]) && isxdigit((int)t[2])) {
+ *s = 16 * hexdigit2int(t[1]) + hexdigit2int(t[2]);
+ t += 3;
+ } else
+ *s = *t++;
+ }
+ *s = '\0';
+}
+
+typedef int (*t_fptr)(struct gconffile **, void *, char *, char *, char *);
+
+/* 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, *endptr;
+ uint8_t *bln = NULL;
+ long int *lint = NULL;
+ int type = 0, conftype = 0, n;
+ t_fptr cbk = NULL;
+ void *cbkarg = NULL;
+
+ for (;;) {
+ free(opt);
+ if (!getconfigline(cf, block, &opt, &val, &conftype))
+ return 0;
+ if (!opt)
+ return 1;