--- val.c 2002/01/16 16:10:34 1.3
+++ val.c 2002/01/16 20:24:09 1.4
@@ -67,15 +67,6 @@
typedef int (*lh_cb_t)(void *ctx, const void *keyptr, int keylen, const void *datptr, int datlen);
-#if 0
-lh_t *lh_create (void);
-int lh_insert (lh_t *h, const void *keyptr, int keylen, const void *datptr, int datlen, int override);
-int lh_lookup (lh_t *h, const void *keyptr, int keylen, void **datptr, int *datlen);
-int lh_delete (lh_t *h, const void *keyptr, int keylen);
-int lh_apply (lh_t *h, lh_cb_t cb, void *ctx);
-int lh_destroy(lh_t *h);
-#endif
-
/* fixed size (number of pointers) of the directory and of each segment */
#define INITDIRSIZE 256 /* can be an arbitrary value */
#define SEGMENTSIZE 512 /* has to be a power of 2 for below arithmetic */
@@ -128,7 +119,7 @@
* version doesn't provide the `level' (= previous hash) argument for
* consistency reasons with the other hash functions (i.e. same function
* signature). It can be definetely recommended as a good general
- * purpuse hash function.
+ * purpose hash function.
*/
static long
lh_hash(
@@ -564,15 +555,21 @@
** ____ ____
** ____ VALUE LIBRARY ____
**
+** This part implements the actual Value library. Fortunately this
+** is now easy because it internally is just based on the above
+** full-featured linear hashing library.
*/
-/* usually val_object_t.data is a pointer val_object_t.data.p, but VAL_INLINE
- * signals val_object_t.data is actual data val_object_t.data.[csilfd]
+/*
+ * usually val_object_t.data is a pointer val_object_t.data.p,
+ * but VAL_INLINE signals val_object_t.data is actual data
+ * val_object_t.data.[csilfd].
*/
enum {
- VAL_INLINE = 1<<31
+ VAL_INLINE = 1<<31
};
+/* the internal representation of a value object */
typedef struct {
int type;
union {
@@ -588,86 +585,101 @@
char *desc;
} val_object_t;
+/* the val_t internally is just a hash table */
struct val_s {
lh_t *lh;
};
+/* determine address of an object's storage */
static void *val_storage(val_object_t *obj)
{
void *storage;
+ /* argument consistency check */
+ if (obj == NULL)
+ return NULL;
+
+ /* address determination */
if (obj->type & VAL_INLINE) {
switch (obj->type & ~VAL_INLINE) {
- case VAL_TYPE_VAL:
- storage = &obj->data.v;
- break;
- case VAL_TYPE_PTR:
- storage = &obj->data.p;
- break;
- case VAL_TYPE_CHAR:
- storage = &obj->data.c;
- break;
- case VAL_TYPE_SHORT:
- storage = &obj->data.s;
- break;
- case VAL_TYPE_INT:
- storage = &obj->data.i;
- break;
- case VAL_TYPE_LONG:
- storage = &obj->data.l;
- break;
- case VAL_TYPE_FLOAT:
- storage = &obj->data.f;
- break;
- case VAL_TYPE_DOUBLE:
- storage = &obj->data.d;
- break;
- default:
- storage = NULL;
+ case VAL_TYPE_VAL: storage = &obj->data.v; break;
+ case VAL_TYPE_PTR: storage = &obj->data.p; break;
+ case VAL_TYPE_CHAR: storage = &obj->data.c; break;
+ case VAL_TYPE_SHORT: storage = &obj->data.s; break;
+ case VAL_TYPE_INT: storage = &obj->data.i; break;
+ case VAL_TYPE_LONG: storage = &obj->data.l; break;
+ case VAL_TYPE_FLOAT: storage = &obj->data.f; break;
+ case VAL_TYPE_DOUBLE: storage = &obj->data.d; break;
+ default: storage = NULL; break; /* cannot happen */
}
}
else
storage = obj->data.p;
+
return storage;
}
-val_rc_t val_create(val_t **valp)
+/* create object */
+val_rc_t val_create(val_t **pval)
{
val_t *val;
- if (valp == NULL)
+ /* argument consistency check */
+ if (pval == NULL)
return VAL_ERR_ARG;
+
+ /* create top-level structure */
if ((val = (val_t *)malloc(sizeof(val_t))) == NULL)
return VAL_ERR_SYS;
+
+ /* create hash table */
if ((val->lh = lh_create()) == NULL) {
free(val);
return VAL_ERR_SYS;
}
- *valp = val;
+
+ /* pass result to caller */
+ *pval = val;
+
return VAL_OK;
}
-static int (val_destroy_cb)(void *_ctx, const void *keyptr, int keylen, const void *datptr, int datlen)
+/* internal lh_apply() callback for use with val_destroy() */
+static int val_destroy_cb(void *_ctx,
+ const void *keyptr, int keylen,
+ const void *datptr, int datlen)
{
val_object_t *obj;
- obj = (val_object_t *)datptr;
- if (obj->desc != NULL)
- free(obj->desc);
+ /* free description string */
+ if ((obj = (val_object_t *)datptr) != NULL)
+ if (obj->desc != NULL)
+ free(obj->desc);
+
return TRUE;
}
+/* destroy object */
val_rc_t val_destroy(val_t *val)
{
+ /* argument consistency check */
if (val == NULL)
return VAL_ERR_ARG;
+
+ /* destroy all hash table elements */
lh_apply(val->lh, val_destroy_cb, NULL);
+
+ /* destroy hash table */
if (!lh_destroy(val->lh))
return VAL_ERR_SYS;
+
+ /* destroy top-level structure */
free(val);
+
return VAL_OK;
}
+/* register a value */
val_rc_t val_reg(val_t *val, const char *name, int type, const char *desc, void *storage)
{
val_object_t *obj;
@@ -675,11 +687,11 @@
const char *cp;
val_t *child;
+ /* argument consistency check */
if (val == NULL || name == NULL || type == 0)
return VAL_ERR_ARG;
-
-
+ /* recursive step-down on structured name */
if ((cp = strchr(name, '.')) != NULL) {
if (!lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL))
return VAL_ERR_ARG;
@@ -689,8 +701,7 @@
return val_reg(child, cp+1, type, desc, storage);
}
-
-
+ /* create a new value object */
if (desc != NULL)
newobj.desc = strdup(desc);
else
@@ -703,12 +714,15 @@
newobj.type = (type & ~VAL_INLINE);
newobj.data.p = storage;
}
+
+ /* insert value into hash table */
if (!lh_insert(val->lh, name, strlen(name), &newobj, sizeof(newobj), 1))
- return VAL_ERR_SYS;
+ return VAL_ERR_HSH;
return VAL_OK;
}
+/* set a value (va_list variant) */
val_rc_t val_vset(val_t *val, const char *name, va_list ap)
{
val_object_t *obj;
@@ -716,8 +730,11 @@
const char *cp;
val_t *child;
+ /* argument consistency check */
if (val == NULL || name == NULL || ap == NULL)
return VAL_ERR_ARG;
+
+ /* recursive step-down on structured name */
if ((cp = strchr(name, '.')) != NULL) {
if (!lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL))
return VAL_ERR_ARG;
@@ -726,51 +743,50 @@
child = *(val_t **)(val_storage(obj));
return val_vset(child, cp+1, ap);
}
+
+ /* try to lookup object in hash table */
if (!lh_lookup(val->lh, name, strlen(name), (void **)&obj, NULL))
return VAL_ERR_ARG;
- storage = val_storage(obj);
+
+ /* determine value storage */
+ if ((storage = val_storage(obj)) == NULL)
+ return VAL_ERR_INT;
+
+ /* copy value from variable argument into storage location */
switch (obj->type & ~VAL_INLINE) {
- case VAL_TYPE_VAL:
- *(val_t **)storage = (val_t *)va_arg(ap, void *);
- break;
- case VAL_TYPE_PTR:
- *(char **)storage = (char *)va_arg(ap, void *);
- break;
- case VAL_TYPE_CHAR:
- *(char *)storage = (char)va_arg(ap, int);
- break;
- case VAL_TYPE_SHORT:
- *(short *)storage = (short)va_arg(ap, int);
- break;
- case VAL_TYPE_INT:
- *(int *)storage = (int)va_arg(ap, int);
- break;
- case VAL_TYPE_LONG:
- *(long *)storage = (long)va_arg(ap, long);
- break;
- case VAL_TYPE_FLOAT:
- *(float *)storage = (float)va_arg(ap, double);
- break;
- case VAL_TYPE_DOUBLE:
- *(double *)storage = (double)va_arg(ap, double);
- break;
+ case VAL_TYPE_VAL: *(val_t **)storage = (val_t *)va_arg(ap, void *); break;
+ case VAL_TYPE_PTR: *(char **)storage = (char *)va_arg(ap, void *); break;
+ case VAL_TYPE_CHAR: *(char *)storage = (char )va_arg(ap, int ); break;
+ case VAL_TYPE_SHORT: *(short *)storage = (short )va_arg(ap, int ); break;
+ case VAL_TYPE_INT: *(int *)storage = (int )va_arg(ap, int ); break;
+ case VAL_TYPE_LONG: *(long *)storage = (long )va_arg(ap, long ); break;
+ case VAL_TYPE_FLOAT: *(float *)storage = (float )va_arg(ap, double); break;
+ case VAL_TYPE_DOUBLE: *(double *)storage = (double )va_arg(ap, double); break;
+ default: break; /* cannot happen */
}
+
return VAL_OK;
}
+/* set a value */
val_rc_t val_set(val_t *val, const char *name, ...)
{
val_rc_t rc;
va_list ap;
+ /* argument consistency check */
if (val == NULL || name == NULL)
return VAL_ERR_ARG;
+
+ /* just pass-through to va_list variant */
va_start(ap, name);
rc = val_vset(val, name, ap);
va_end(ap);
+
return rc;
}
+/* get a value (va_list variant) */
val_rc_t val_vget(val_t *val, const char *name, va_list ap)
{
val_object_t *obj;
@@ -778,8 +794,11 @@
const char *cp;
val_t *child;
+ /* argument consistency check */
if (val == NULL || name == NULL || ap == NULL)
return VAL_ERR_ARG;
+
+ /* recursive step-down on structured name */
if ((cp = strchr(name, '.')) != NULL) {
if (!lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL))
return VAL_ERR_ARG;
@@ -788,72 +807,71 @@
child = *(val_t **)(val_storage(obj));
return val_vget(child, cp+1, ap);
}
+
+ /* try to lookup object in hash table */
if (!lh_lookup(val->lh, name, strlen(name), (void **)&obj, NULL))
return VAL_ERR_ARG;
- storage = val_storage(obj);
+
+ /* determine value storage */
+ if ((storage = val_storage(obj)) == NULL)
+ return VAL_ERR_INT;
+
+ /* copy value from storage location into variable argument pointer location */
switch (obj->type & ~VAL_INLINE) {
- case VAL_TYPE_VAL:
- *((val_t **)va_arg(ap, void *)) = *(val_t **)storage;
- break;
- case VAL_TYPE_PTR:
- *((char **)va_arg(ap, void *)) = *(char **)storage;
- break;
- case VAL_TYPE_CHAR:
- *((char *)va_arg(ap, int *)) = *(char *)storage;
- break;
- case VAL_TYPE_SHORT:
- *((short *)va_arg(ap, int *)) = *(short *)storage;
- break;
- case VAL_TYPE_INT:
- *((int *)va_arg(ap, int *)) = *(int *)storage;
- break;
- case VAL_TYPE_LONG:
- *((long *)va_arg(ap, long *)) = *(long *)storage;
- break;
- case VAL_TYPE_FLOAT:
- *((float *)va_arg(ap, double *)) = *(float *)storage;
- break;
- case VAL_TYPE_DOUBLE:
- *((double *)va_arg(ap, double *)) = *(double *)storage;
- break;
+ case VAL_TYPE_VAL: *((val_t **)va_arg(ap, void *)) = *(val_t **)storage; break;
+ case VAL_TYPE_PTR: *((char **)va_arg(ap, void *)) = *(char **)storage; break;
+ case VAL_TYPE_CHAR: *((char *)va_arg(ap, int *)) = *(char *)storage; break;
+ case VAL_TYPE_SHORT: *((short *)va_arg(ap, int *)) = *(short *)storage; break;
+ case VAL_TYPE_INT: *((int *)va_arg(ap, int *)) = *(int *)storage; break;
+ case VAL_TYPE_LONG: *((long *)va_arg(ap, long *)) = *(long *)storage; break;
+ case VAL_TYPE_FLOAT: *((float *)va_arg(ap, double *)) = *(float *)storage; break;
+ case VAL_TYPE_DOUBLE: *((double *)va_arg(ap, double *)) = *(double *)storage; break;
+ default: break; /* cannot happen */
}
+
return VAL_OK;
}
+/* get a value */
val_rc_t val_get(val_t *val, const char *name, ...)
{
val_rc_t rc;
va_list ap;
+ /* argument consistency check */
if (val == NULL || name == NULL)
return VAL_ERR_ARG;
+
+ /* just pass-through to va_list variant */
va_start(ap, name);
rc = val_vget(val, name, ap);
va_end(ap);
+
return rc;
}
-#define VAL_MAXNAME 1024
-
+/* internal lh_apply() recursion callback context structure */
typedef struct {
- val_t *val;
- char *name;
- int prefixlen;
- int depth;
- val_cb_t cb;
- void *ctx;
- val_rc_t rc;
+ val_t *val;
+ char *name;
+ int prefixlen;
+ int depth;
+ val_cb_t cb;
+ void *ctx;
+ val_rc_t rc;
} val_apply_ctx_t;
+/* forward declaration */
static val_rc_t val_apply_internal(val_t *, const char *, int, int, val_cb_t, void *);
+/* internal lh_apply() recursion callback for use with val_apply() */
static int (val_apply_cb)(void *_ctx, const void *keyptr, int keylen, const void *datptr, int datlen)
{
val_apply_ctx_t *ctx = (val_apply_ctx_t *)_ctx;
char name[VAL_MAXNAME+1];
int prefixlen;
- /* on-the-fly create NUL-terminated name string */
+ /* on-the-fly create NUL-terminated concatenated name string */
if ((strlen(ctx->name) + 1 + keylen) > VAL_MAXNAME) {
ctx->rc = VAL_ERR_MEM;
return FALSE;
@@ -868,12 +886,18 @@
prefixlen = ctx->prefixlen;
}
strncat(name, (char *)keyptr, keylen);
- if ((ctx->rc = val_apply_internal(ctx->val, name, prefixlen, ctx->depth, ctx->cb, ctx->ctx)) != VAL_OK)
+
+ /* recursive step-down */
+ if ((ctx->rc = val_apply_internal(ctx->val, name, prefixlen,
+ ctx->depth, ctx->cb, ctx->ctx)) != VAL_OK)
return FALSE;
+
return TRUE;
}
-static val_rc_t val_apply_internal(val_t *val, const char *name, int prefixlen, int depth, val_cb_t cb, void *ctx)
+/* internal API-increased variant of val_apply() */
+static val_rc_t val_apply_internal(val_t *val, const char *name, int prefixlen,
+ int depth, val_cb_t cb, void *ctx)
{
val_object_t *obj;
val_t *child;
@@ -882,7 +906,8 @@
val_apply_ctx_t val_ctx;
if (name[prefixlen] == '\0') {
- /* prefix="foo.bar.", remainder="" */
+ /* CASE 1: apply to all elements
+ prefix="foo.bar.", remainder="" */
val_ctx.val = val;
val_ctx.name = (char *)name;
val_ctx.prefixlen = prefixlen;
@@ -893,41 +918,43 @@
if (!lh_apply(val->lh, val_apply_cb, &val_ctx))
return VAL_ERR_SYS;
}
- else {
- if ((cp = strchr(name+prefixlen, '.')) != NULL) {
- /* prefix="foo.bar.", remainder="quux.baz" */
- if (!lh_lookup(val->lh, name+prefixlen, cp-(name+prefixlen), (void **)&obj, NULL))
- return VAL_ERR_ARG;
- if (!(obj->type & VAL_TYPE_VAL))
- return VAL_ERR_USE;
- child = *(val_t **)(val_storage(obj));
+ else if ((cp = strchr(name+prefixlen, '.')) != NULL) {
+ /* CASE 2: still stepping-down for structured name
+ prefix="foo.bar.", remainder="quux.baz" */
+ if (!lh_lookup(val->lh, name+prefixlen, cp-(name+prefixlen), (void **)&obj, NULL))
+ return VAL_ERR_ARG;
+ if (!(obj->type & VAL_TYPE_VAL))
+ return VAL_ERR_USE;
+ child = *(val_t **)(val_storage(obj));
+ if (depth == 0)
+ return VAL_OK;
+ return val_apply_internal(child, name, cp-name+1, depth-1, cb, ctx);
+ } else {
+ /* CASE 3: reached last component of structured name
+ prefix="foo.bar.quux.", remainder="baz" */
+ if (!lh_lookup(val->lh, name+prefixlen, strlen(name+prefixlen), (void **)&obj, NULL))
+ return VAL_ERR_ARG;
+ if ((rc = cb(ctx, name, (obj->type & ~VAL_INLINE),
+ obj->desc, val_storage(obj))) != VAL_OK)
+ return rc;
+ if (obj->type & VAL_TYPE_VAL) {
if (depth == 0)
return VAL_OK;
- return val_apply_internal(child, name, cp-name+1, --depth, cb, ctx);
- }
- else {
- /* prefix="foo.bar.quux.", remainder="baz" */
- if (!lh_lookup(val->lh, name+prefixlen, strlen(name+prefixlen), (void **)&obj, NULL))
- return VAL_ERR_ARG;
- /* execute VAL callback */
- if ((rc = cb(ctx, name, (obj->type & ~VAL_INLINE), obj->desc, val_storage(obj))) != VAL_OK)
- return rc;
- if (obj->type & VAL_TYPE_VAL) {
- if (depth == 0)
- return VAL_OK;
- child = *(val_t **)(val_storage(obj));
- return val_apply_internal(child, name, strlen(name), --depth, cb, ctx);
- }
+ child = *(val_t **)(val_storage(obj));
+ return val_apply_internal(child, name, strlen(name), depth-1, cb, ctx);
}
}
return VAL_OK;
}
+/* apply a callback to each value */
val_rc_t val_apply(val_t *val, const char *name, int depth, val_cb_t cb, void *ctx)
{
+ /* argument consistency check */
if (val == NULL || name == NULL || depth < 0 || cb == NULL)
return VAL_ERR_ARG;
+ /* just pass-through to internal API-extended variant */
return val_apply_internal(val, name, 0, depth, cb, ctx);
}
|