Index: ossp-pkg/val/val.c RCS File: /v/ossp/cvs/ossp-pkg/val/val.c,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/val/val.c,v' 2>/dev/null --- 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); } Index: ossp-pkg/val/val.h RCS File: /v/ossp/cvs/ossp-pkg/val/val.h,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/val/val.h,v' 2>/dev/null --- val.h 2002/01/16 14:17:56 1.2 +++ val.h 2002/01/16 20:24:10 1.3 @@ -33,6 +33,10 @@ #include +/* maximum length of a structured value name */ +#define VAL_MAXNAME 1024 + +/* the set of distinct value types */ enum { VAL_TYPE_VAL = 1<<0, VAL_TYPE_PTR = 1<<1, @@ -44,19 +48,25 @@ VAL_TYPE_DOUBLE = 1<<7 }; +/* the set of return codes */ typedef enum { - VAL_OK, - VAL_ERR_ARG, - VAL_ERR_USE, - VAL_ERR_MEM, - VAL_ERR_SYS + VAL_OK, /* everything ok */ + VAL_ERR_ARG, /* error: invalid argument */ + VAL_ERR_USE, /* error: invalid use */ + VAL_ERR_MEM, /* error: no more memory */ + VAL_ERR_HSH, /* error: hash table problem */ + VAL_ERR_INT, /* error: internal error */ + VAL_ERR_SYS /* error: system error (see errno) */ } val_rc_t; +/* the opaque data structure and type */ struct val_s; typedef struct val_s val_t; +/* function type for use with val_apply() */ typedef val_rc_t (*val_cb_t)(void *, const char *, int, const char *, void *); +/* set of API functions */ val_rc_t val_create (val_t **); val_rc_t val_destroy (val_t *); val_rc_t val_reg (val_t *, const char *, int, const char *, void *);