#include "lmtp2nntp_val.h" #include "lmtp2nntp_lh.h" #include #include #include /* 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 { char *name; int type; union { void *p; char c; short s; int i; long l; float f; double d; } data; } val_object_t; struct val_s { lh_t *lh; }; static void *val_unionptr(val_object_t *obj) { void *storage; switch (obj->type & ~VAL_INLINE) { case VAL_TYPE_PTR: storage = &obj->data.p; break; case VAL_TYPE_CHAR: storage = (void *)&obj->data.c; break; case VAL_TYPE_SHORT: storage = (void *)&obj->data.s; break; case VAL_TYPE_INT: storage = (void *)&obj->data.i; break; case VAL_TYPE_LONG: storage = (void *)&obj->data.l; break; case VAL_TYPE_FLOAT: storage = (void *)&obj->data.f; break; case VAL_TYPE_DOUBLE: storage = (void *)&obj->data.d; break; default: storage = NULL; } return storage; } val_rc_t val_create(val_t **valp) { val_t *val; if ((val = (val_t *)malloc(sizeof(val_t))) == NULL) return VAL_MEMORY; if ((val->lh = lh_create()) == NULL) return VAL_LH; *valp = val; return VAL_OK; } val_rc_t val_destroy(val_t *val) { if (val == NULL) return VAL_MEMORY; lh_destroy(val->lh); free(val); return VAL_OK; } val_rc_t val_reg(val_t *val, const char *name, int type, void *storage) { val_object_t obj; if ((obj.name = strdup(name)) == NULL) return VAL_MEMORY; obj.type = type; if (storage == NULL) { obj.type |= VAL_INLINE; obj.data.l = 0; } else obj.data.p = storage; if (! lh_insert(val->lh, name, strlen(name), &obj, sizeof(obj), 1)) return VAL_LH; 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; if ((cp = strchr(name, '.')) != NULL) { if (! lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL)) return VAL_LH; return val_vset((val_t *)obj->data.p, cp+1, ap); } if (! lh_lookup(val->lh, name, strlen(name), (void **)&obj, NULL)) return VAL_LH; if (obj->type & VAL_INLINE) storage = val_unionptr(obj); else storage = obj->data.p; switch(obj->type & ~VAL_INLINE) { 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; 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; if ((cp = strchr(name, '.')) != NULL) { if (! lh_lookup(val->lh, name, cp-name, (void **)&obj, NULL)) return VAL_LH; return val_vget((val_t *)obj->data.p, cp+1, ap); } if (! lh_lookup(val->lh, name, strlen(name), (void **)&obj, NULL)) return VAL_LH; if (obj->type & VAL_INLINE) storage = val_unionptr(obj); else storage = obj->data.p; switch (obj->type & ~VAL_INLINE) { 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; va_start(ap, name); rc = val_vget(val, name, ap); va_end(ap); return rc; }