OSSP CVS Repository

ossp - ossp-pkg/lmtp2nntp/lmtp2nntp_val.c 1.3
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/lmtp2nntp/lmtp2nntp_val.c 1.3

#include "lmtp2nntp_val.h"
#include "lmtp2nntp_lh.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

/* 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
};

typedef struct {
    int type;
    union {
        val_t *v;
        void  *p;
        char   c;
        short  s;
        int    i;
        long   l;
        float  f;
        double d;
    } data;
    char *desc;
} val_object_t;

struct val_s {
    lh_t *lh;
};

static void *val_storage(val_object_t *obj)
{
    void *storage;

    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;
        }
    }
    else 
        storage = obj->data.p;
    return storage;
}

val_rc_t val_create(val_t **valp)
{
    val_t *val;

    if (valp == NULL)
        return VAL_ERR_ARG;
    if ((val = (val_t *)malloc(sizeof(val_t))) == NULL)
        return VAL_ERR_SYS;
    if ((val->lh = lh_create()) == NULL) {
        free(val);
        return VAL_ERR_SYS;
    }
    *valp = val;
    return VAL_OK;
}

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);
    return TRUE;
}

val_rc_t val_destroy(val_t *val)
{
    if (val == NULL)
        return VAL_ERR_ARG;
    lh_apply(val->lh, val_destroy_cb, NULL);
    if (!lh_destroy(val->lh))
        return VAL_ERR_SYS;
    free(val);
    return VAL_OK;
}

val_rc_t val_reg(val_t *val, const char *name, int type, const char *desc, void *storage)
{
    val_object_t *obj;
    val_object_t newobj;
    const char *cp;
    val_t *child;

    if (val == NULL || name == NULL || type == 0)
        return VAL_ERR_ARG;



    if ((cp = strchr(name, '.')) != NULL) {
        if (!lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL))
            return VAL_ERR_ARG;
        if (!(obj->type & VAL_TYPE_VAL))
            return VAL_ERR_USE;
        child = *(val_t **)(val_storage(obj));
        return val_reg(child, cp+1, type, desc, storage);
    }



    if (desc != NULL)
        newobj.desc = strdup(desc);
    else
        newobj.desc = NULL;
    if (storage == NULL) { 
        newobj.type   = (type | VAL_INLINE);
        newobj.data.l = 0;
    }
    else {
        newobj.type   = (type & ~VAL_INLINE);
        newobj.data.p = storage;
    }
    if (!lh_insert(val->lh, name, strlen(name), &newobj, sizeof(newobj), 1))
        return VAL_ERR_SYS;

    return VAL_OK;
}

val_rc_t val_vset(val_t *val, const char *name, va_list ap)
{
    val_object_t *obj;
    void *storage;
    const char *cp;
    val_t *child;

    if (val == NULL || name == NULL || ap == NULL)
        return VAL_ERR_ARG;
    if ((cp = strchr(name, '.')) != NULL) {
        if (!lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL))
            return VAL_ERR_ARG;
        if (!(obj->type & VAL_TYPE_VAL))
            return VAL_ERR_USE;
        child = *(val_t **)(val_storage(obj));
        return val_vset(child, cp+1, ap);
    }
    if (!lh_lookup(val->lh, name, strlen(name), (void **)&obj, NULL))
        return VAL_ERR_ARG;
    storage = val_storage(obj);
    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;
    }
    return VAL_OK;
}

val_rc_t val_set(val_t *val, const char *name, ...)
{
    val_rc_t rc;
    va_list ap;

    if (val == NULL || name == NULL)
        return VAL_ERR_ARG;
    va_start(ap, name);
    rc = val_vset(val, name, ap);
    va_end(ap);
    return rc;
}

val_rc_t val_vget(val_t *val, const char *name, va_list ap)
{
    val_object_t *obj;
    void *storage;
    const char *cp;
    val_t *child;

    if (val == NULL || name == NULL || ap == NULL)
        return VAL_ERR_ARG;
    if ((cp = strchr(name, '.')) != NULL) {
        if (!lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL))
            return VAL_ERR_ARG;
        if (!(obj->type & VAL_TYPE_VAL))
            return VAL_ERR_USE;
        child = *(val_t **)(val_storage(obj));
        return val_vget(child, cp+1, ap);
    }
    if (!lh_lookup(val->lh, name, strlen(name), (void **)&obj, NULL))
        return VAL_ERR_ARG;
    storage = val_storage(obj);
    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;
    }
    return VAL_OK;
}

val_rc_t val_get(val_t *val, const char *name, ...)
{
    val_rc_t rc;
    va_list ap;

    if (val == NULL || name == NULL)
        return VAL_ERR_ARG;
    va_start(ap, name);
    rc = val_vget(val, name, ap);
    va_end(ap);
    return rc;
}

#define VAL_MAXNAME 1024

typedef struct {
    val_t *val;
    char *name;
    int prefixlen;
    int depth;
    val_cb_t cb;
    void *ctx;
    val_rc_t rc;
} val_apply_ctx_t;

static val_rc_t val_apply_internal(val_t *, const char *, int, int, val_cb_t, void *);

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 */
    if ((strlen(ctx->name) + 1 + keylen) > VAL_MAXNAME) {
        ctx->rc = VAL_ERR_MEM;
        return FALSE;
    }
    if (strlen(ctx->name) > 0) {
        strcpy(name, ctx->name);
        strcat(name, ".");
        prefixlen = ctx->prefixlen + 1;
    }
    else {
        *name = '\0';
        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)
        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)
{
    val_object_t *obj;
    val_t *child;
    char *cp;
    val_rc_t rc;
    val_apply_ctx_t val_ctx;

fprintf(stderr, "DEBUG: val_apply_internal name=<%s>, prefixlen=%d, depth=%d\n", name, prefixlen, depth);
    if (name[prefixlen] == '\0') {
        /* prefix="foo.bar.", remainder="" */
        //if (--depth > 0) {
            val_ctx.val       = val;
            val_ctx.name      = (char *)name;
            val_ctx.prefixlen = prefixlen;
            val_ctx.depth     = depth;
            val_ctx.cb        = cb;
            val_ctx.ctx       = ctx;
            val_ctx.rc        = VAL_OK;
            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));
            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;
//fprintf(stderr, "DEBUG: depth=%d obj->type=%.8lx\n", depth, obj->type);
            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);
            }
        }
    }
    return VAL_OK;
}

val_rc_t val_apply(val_t *val, const char *name, int depth, val_cb_t cb, void *ctx)
{
    if (val == NULL || name == NULL || depth < 0 || cb == NULL)
        return VAL_ERR_ARG;

    return val_apply_internal(val, name, 0, depth, cb, ctx);
}

CVSTrac 2.0.1