idnode: massive cleanup

I've cleaned up all the methods to make things a bit more consistent and
removed stuff that wasn't being used.
This commit is contained in:
Adam Sutton 2013-06-11 20:18:04 +01:00
parent ddcb8d1ca9
commit ac41437712
4 changed files with 561 additions and 495 deletions

View file

@ -1,3 +1,22 @@
/*
* Tvheadend - idnode (class) system
*
* Copyright (C) 2013 Andreas Öman
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
@ -10,11 +29,14 @@
#include "notify.h"
#include "settings.h"
static int randfd = 0;
static int randfd = 0;
static RB_HEAD(,idnode) idnodes;
RB_HEAD(idnode_tree, idnode);
static void idnode_updated(idnode_t *in, int optmask);
static struct idnode_tree idnodes;
/* **************************************************************************
* Utilities
* *************************************************************************/
/**
*
@ -71,6 +93,18 @@ bin2hex(char *dst, size_t dstlen, const uint8_t *src, size_t srclen)
*dst = 0;
}
/**
*
*/
static int
in_cmp(const idnode_t *a, const idnode_t *b)
{
return memcmp(a->in_uuid, b->in_uuid, 16);
}
/* **************************************************************************
* Registration
* *************************************************************************/
/**
*
@ -83,17 +117,6 @@ idnode_init(void)
exit(1);
}
/**
*
*/
static int
in_cmp(const idnode_t *a, const idnode_t *b)
{
return memcmp(a->in_uuid, b->in_uuid, 16);
}
/**
*
*/
@ -121,6 +144,18 @@ idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class)
return 0;
}
/**
*
*/
void
idnode_unlink(idnode_t *in)
{
RB_REMOVE(&idnodes, in, in_link);
}
/* **************************************************************************
* Info
* *************************************************************************/
/**
*
@ -136,61 +171,6 @@ idnode_uuid_as_str(const idnode_t *in)
return b;
}
/**
*
*/
void *
idnode_find(const char *uuid, const idclass_t *idc)
{
idnode_t skel, *r;
if(hex2bin(skel.in_uuid, 16, uuid))
return NULL;
r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
if(r != NULL && idc != NULL) {
const idclass_t *c = r->in_class;
for(;c != NULL; c = c->ic_super) {
if(idc == c)
return r;
}
return NULL;
}
return r;
}
/**
*
*/
void
idnode_unlink(idnode_t *in)
{
RB_REMOVE(&idnodes, in, in_link);
}
/**
* Recursive to get superclass nodes first
*/
static void
add_params(struct idnode *self, const idclass_t *ic, htsmsg_t *p)
{
if(ic->ic_super != NULL)
add_params(self, ic->ic_super, p);
if(TAILQ_FIRST(&p->hm_fields) != NULL) {
// Only add separator if not empty
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "caption", ic->ic_caption ?: ic->ic_class);
htsmsg_add_str(m, "type", "separator");
htsmsg_add_msg(p, NULL, m);
}
prop_add_params_to_msg(self, ic->ic_properties, p);
}
/**
*
*/
@ -209,7 +189,7 @@ idnode_get_title(idnode_t *in)
/**
*
*/
idnode_t **
idnode_set_t *
idnode_get_childs(idnode_t *in)
{
if(in == NULL)
@ -223,7 +203,6 @@ idnode_get_childs(idnode_t *in)
return NULL;
}
/**
*
*/
@ -231,8 +210,6 @@ int
idnode_is_leaf(idnode_t *in)
{
const idclass_t *ic = in->in_class;
if(ic->ic_leaf)
return 1;
for(; ic != NULL; ic = ic->ic_super) {
if(ic->ic_get_childs != NULL)
return 0;
@ -240,137 +217,9 @@ idnode_is_leaf(idnode_t *in)
return 1;
}
/**
*
*/
htsmsg_t *
idnode_serialize(struct idnode *self)
{
const idclass_t *c = self->in_class;
htsmsg_t *m;
if(c->ic_serialize != NULL) {
m = c->ic_serialize(self);
} else {
m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(self));
htsmsg_add_str(m, "text", idnode_get_title(self));
htsmsg_t *p = htsmsg_create_list();
add_params(self, c, p);
htsmsg_add_msg(m, "params", p);
}
return m;
}
/**
*
*/
static void
idnode_updated(idnode_t *in)
{
const idclass_t *ic = in->in_class;
for(; ic != NULL; ic = ic->ic_super) {
if(ic->ic_save != NULL) {
ic->ic_save(in);
break;
}
}
// Tell about updated parameters
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(in));
htsmsg_t *p = htsmsg_create_list();
add_params(in, in->in_class, p);
htsmsg_add_msg(m, "params", p);
notify_by_msg("idnodeParamsChanged", m);
}
/**
*
*/
void
idnode_set_prop(idnode_t *in, const char *key, const char *value)
{
const idclass_t *ic = in->in_class;
int do_save = 0;
for(;ic != NULL; ic = ic->ic_super) {
int x = prop_set(in, ic->ic_properties, key, value);
if(x == -1)
continue;
do_save |= x;
break;
}
if(do_save)
idnode_updated(in);
}
/**
*
*/
void
idnode_update_all_props(idnode_t *in,
const char *(*getvalue)(void *opaque, const char *key),
void *opaque)
{
const idclass_t *ic = in->in_class;
int do_save = 0;
for(;ic != NULL; ic = ic->ic_super)
do_save |= prop_update_all(in, ic->ic_properties, getvalue, opaque);
if(do_save)
idnode_updated(in);
}
/**
*
*/
void
idnode_notify_title_changed(void *obj)
{
idnode_t *in = obj;
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(in));
htsmsg_add_str(m, "text", idnode_get_title(in));
notify_by_msg("idnodeNameChanged", m);
}
/*
* Save
*/
void
idnode_save ( idnode_t *self, htsmsg_t *c )
{
const idclass_t *idc = self->in_class;
while (idc) {
prop_read_values(self, idc->ic_properties, c);
idc = idc->ic_super;
}
}
/*
* Load
*/
void
idnode_load ( idnode_t *self, htsmsg_t *c, int dosave )
{
const idclass_t *idc = self->in_class;
while (idc) {
prop_write_values(self, idc->ic_properties, c);
idc = idc->ic_super;
}
if (dosave)
idnode_updated(self);
}
/* **************************************************************************
* Properties
* *************************************************************************/
static const property_t *
idnode_find_prop
@ -408,6 +257,9 @@ idnode_get_str
return NULL;
}
/*
* Get field as unsigned int
*/
int
idnode_get_u32
( idnode_t *self, const char *key, uint32_t *u32 )
@ -433,8 +285,75 @@ idnode_get_u32
return 1;
}
/*
* Get field as BOOL
*/
int
idnode_get_bool
( idnode_t *self, const char *key, int *b )
{
const property_t *p = idnode_find_prop(self, key);
if (p) {
void *ptr = self;
ptr += p->off;
switch (p->type) {
case PT_BOOL:
*b = *(int*)ptr;
return 0;
default:
break;
}
}
return 1;
}
/* **************************************************************************
* Set procsesing
* Lookup
* *************************************************************************/
/**
*
*/
void *
idnode_find(const char *uuid, const idclass_t *idc)
{
idnode_t skel, *r;
if(hex2bin(skel.in_uuid, 16, uuid))
return NULL;
r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
if(r != NULL && idc != NULL) {
const idclass_t *c = r->in_class;
for(;c != NULL; c = c->ic_super) {
if(idc == c)
return r;
}
return NULL;
}
return r;
}
idnode_set_t *
idnode_find_all ( const idclass_t *idc )
{
idnode_t *in;
const idclass_t *ic;
idnode_set_t *is = calloc(1, sizeof(idnode_set_t));
RB_FOREACH(in, &idnodes, in_link) {
ic = in->in_class;
while (ic) {
if (ic == idc) {
idnode_set_add(is, in, NULL);
break;
}
ic = ic->ic_super;
}
}
return is;
}
/* **************************************************************************
* Set processing
* *************************************************************************/
static int
@ -626,21 +545,140 @@ idnode_set_free ( idnode_set_t *is )
free(is);
}
idnode_set_t *
idnode_find_all ( const idclass_t *idc )
/* **************************************************************************
* Write
* *************************************************************************/
int
idnode_write0 ( idnode_t *self, htsmsg_t *c, int optmask, int dosave )
{
idnode_t *in;
const idclass_t *ic;
idnode_set_t *is = calloc(1, sizeof(idnode_set_t));
RB_FOREACH(in, &idnodes, in_link) {
ic = in->in_class;
while (ic) {
if (ic == idc) {
idnode_set_add(is, in, NULL);
break;
}
ic = ic->ic_super;
int save = 0;
const idclass_t *idc = self->in_class;
for (; idc; idc = idc->ic_super)
save |= prop_write_values(self, idc->ic_properties, c, optmask);
if (save && dosave)
idnode_updated(self, optmask);
return save;
}
/* **************************************************************************
* Read
* *************************************************************************/
/*
* Save
*/
void
idnode_read0 ( idnode_t *self, htsmsg_t *c, int optmask )
{
const idclass_t *idc = self->in_class;
for (; idc; idc = idc->ic_super)
prop_read_values(self, idc->ic_properties, c, optmask);
}
/**
* Recursive to get superclass nodes first
*/
static void
add_params(struct idnode *self, const idclass_t *ic, htsmsg_t *p, int optmask)
{
/* Parent first */
if(ic->ic_super != NULL)
add_params(self, ic->ic_super, p, optmask);
/* Seperator (if not empty) */
if(TAILQ_FIRST(&p->hm_fields) != NULL) {
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "caption", ic->ic_caption ?: ic->ic_class);
htsmsg_add_str(m, "type", "separator");
htsmsg_add_msg(p, NULL, m);
}
/* Properties */
prop_serialize(self, ic->ic_properties, p, optmask);
}
static htsmsg_t *
idnode_params (const idclass_t *idc, idnode_t *self, int optmask)
{
htsmsg_t *p = htsmsg_create_list();
add_params(self, idc, p, optmask);
return p;
}
/*
* Just get the class definition
*/
htsmsg_t *
idclass_serialize0(const idclass_t *idc, int optmask)
{
return idnode_params(idc, NULL, optmask);
}
/**
*
*/
htsmsg_t *
idnode_serialize0(idnode_t *self, int optmask)
{
const idclass_t *idc = self->in_class;
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "uuid", idnode_uuid_as_str(self));
htsmsg_add_str(m, "text", idnode_get_title(self));
htsmsg_add_msg(m, "params", idnode_params(idc, self, optmask));
return m;
}
/* **************************************************************************
* Notifcation
* *************************************************************************/
/**
*
*/
static void
idnode_updated(idnode_t *in, int optmask)
{
const idclass_t *ic = in->in_class;
/* Save */
for(; ic != NULL; ic = ic->ic_super) {
if(ic->ic_save != NULL) {
ic->ic_save(in);
break;
}
}
return is;
/* Notification */
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(in));
htsmsg_t *p = htsmsg_create_list();
add_params(in, in->in_class, p, optmask);
htsmsg_add_msg(m, "params", p);
notify_by_msg("idnodeParamsChanged", m);
}
/**
*
*/
void
idnode_notify_title_changed(void *obj)
{
idnode_t *in = obj;
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(in));
htsmsg_add_str(m, "text", idnode_get_title(in));
notify_by_msg("idnodeNameChanged", m);
}
/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/

View file

@ -1,4 +1,24 @@
#pragma once
/*
* Tvheadend - idnode (class) system
*
* Copyright (C) 2013 Andreas Öman
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TVH_IDNODE_H__
#define __TVH_IDNODE_H__
#include "tvheadend.h"
#include "prop.h"
@ -6,107 +26,112 @@
#include <regex.h>
struct htsmsg;
struct idnode;
typedef struct idnode idnode_t;
/*
* Node set
*/
typedef struct idnode_set
{
idnode_t **is_array; ///< Array of nodes
size_t is_alloc; ///< Size of is_array
size_t is_count; ///< Current usage of is_array
} idnode_set_t;
/*
* Class definition
*/
typedef struct idclass {
const struct idclass *ic_super;
const char *ic_class;
const char *ic_caption;
int ic_leaf;
struct htsmsg *(*ic_serialize)(struct idnode *self);
struct idnode **(*ic_get_childs)(struct idnode *self);
const char *(*ic_get_title)(struct idnode *self);
void (*ic_save)(struct idnode *self);
const property_t *ic_properties;
const struct idclass *ic_super; /// Parent class
const char *ic_class; /// Class name
const char *ic_caption; /// Class description
const property_t *ic_properties; /// Property list
/* Callbacks */
idnode_set_t *(*ic_get_childs)(idnode_t *self);
const char *(*ic_get_title) (idnode_t *self);
void (*ic_save) (idnode_t *self);
} idclass_t;
/*
* Node definition
*/
struct idnode {
uint8_t in_uuid[16]; ///< Unique ID
RB_ENTRY(idnode) in_link; ///< Global hash
const idclass_t *in_class; ///< Class definition
};
typedef struct idnode {
uint8_t in_uuid[16];
RB_ENTRY(idnode) in_link;
const idclass_t *in_class;
} idnode_t;
/*
* Sorting definition
*/
typedef struct idnode_sort {
const char *key;
const char *key; ///< Sort key
enum {
IS_ASC,
IS_DSC
} dir;
} dir; ///< Sort direction
} idnode_sort_t;
/*
* Filter definition
*/
typedef struct idnode_filter_ele
{
LIST_ENTRY(idnode_filter_ele) link;
char *key;
LIST_ENTRY(idnode_filter_ele) link; ///< List link
char *key; ///< Filter key
enum {
IF_STR,
IF_NUM,
IF_BOOL
} type;
} type; ///< Filter type
union {
int b;
char *s;
int64_t n;
regex_t re;
} u;
} u; ///< Filter data
enum {
IC_EQ, // Equals
IC_LT, // LT
IC_GT, // GT
IC_IN, // contains (STR only)
IC_RE, // regexp (STR only)
} comp;
IC_EQ, ///< Equals
IC_LT, ///< LT
IC_GT, ///< GT
IC_IN, ///< contains (STR only)
IC_RE, ///< regexp (STR only)
} comp; ///< Filter comparison
} idnode_filter_ele_t;
typedef LIST_HEAD(,idnode_filter_ele) idnode_filter_t;
typedef struct idnode_set
{
idnode_t **is_array;
size_t is_alloc;
size_t is_count;
} idnode_set_t;
void idnode_init(void);
int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class);
const char *idnode_uuid_as_str(const idnode_t *in);
void *idnode_find(const char *uuid, const idclass_t *class);
idnode_set_t *idnode_find_all(const idclass_t *class);
idnode_t **idnode_get_childs(idnode_t *in);
int idnode_is_leaf(idnode_t *in);
int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class);
void idnode_unlink(idnode_t *in);
htsmsg_t *idnode_serialize(struct idnode *self);
const char *idnode_uuid_as_str (const idnode_t *in);
idnode_set_t *idnode_get_childs (idnode_t *in);
int idnode_is_leaf (idnode_t *in);
void idnode_set_prop(idnode_t *in, const char *key, const char *value);
const property_t* idnode_get_prop(idnode_t *in, const char *key);
void idnode_update_all_props(idnode_t *in,
const char *(*getvalue)(void *opaque,
const char *key),
void *opaque);
void *idnode_find (const char *uuid, const idclass_t *class);
idnode_set_t *idnode_find_all(const idclass_t *class);
void idnode_notify_title_changed(void *obj);
void idnode_save ( idnode_t *self, htsmsg_t *m );
void idnode_load ( idnode_t *self, htsmsg_t *m, int dosave );
htsmsg_t *idclass_serialize0 (const idclass_t *idc, int optmask);
htsmsg_t *idnode_serialize0 (idnode_t *self, int optmask);
void idnode_read0 (idnode_t *self, htsmsg_t *m, int optmask);
int idnode_write0 (idnode_t *self, htsmsg_t *m, int optmask, int dosave);
const char *idnode_get_str ( idnode_t *self, const char *key );
int idnode_get_u32(idnode_t *self, const char *key, uint32_t *u32);
int idnode_get_bool(idnode_t *self, const char *key, int *b);
#define idclass_serialize(idc) idclass_serialize0(idc, 0)
#define idnode_serialize(in) idnode_serialize0(in, 0)
#define idnode_load(in, m) idnode_write0(in, m, PO_NOSAVE, 0)
#define idnode_save(in, m) idnode_read0(in, m, PO_NOSAVE)
#define idnode_update(in, m) idnode_write0(in, m, PO_RDONLY | PO_WRONCE, 1)
const char *idnode_get_str (idnode_t *self, const char *key );
int idnode_get_u32 (idnode_t *self, const char *key, uint32_t *u32);
int idnode_get_bool(idnode_t *self, const char *key, int *b);
/*
* Set processing
*/
void idnode_filter_add_str
(idnode_filter_t *f, const char *k, const char *v, int t);
void idnode_filter_add_num
@ -117,7 +142,16 @@ void idnode_filter_clear
(idnode_filter_t *f);
int idnode_filter
( idnode_t *in, idnode_filter_t *filt );
#define idnode_set_create() calloc(1, sizeof(idnode_set_t))
void idnode_set_add
( idnode_set_t *is, idnode_t *in, idnode_filter_t *filt );
void idnode_set_sort ( idnode_set_t *is, idnode_sort_t *s );
void idnode_set_free ( idnode_set_t *is );
#endif /* __TVH_IDNODE_H__ */
/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/

View file

@ -1,16 +1,38 @@
/*
* Tvheadend - property system (part of idnode)
*
* Copyright (C) 2013 Andreas Öman
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include "tvheadend.h"
#include "prop.h"
/* **************************************************************************
* Utilities
* *************************************************************************/
#define TO_FROM(x, y) ((x) << 16 | (y))
/**
*
/*
* Bool conversion
*/
#if 0
static int
str_to_bool(const char *s)
{
@ -25,6 +47,18 @@ str_to_bool(const char *s)
return 1;
return 0;
}
#endif
/**
*
*/
const static struct strtab typetab[] = {
{ "bool", PT_BOOL },
{ "int", PT_INT },
{ "str", PT_STR },
{ "u16", PT_U16 },
{ "u32", PT_U32 },
};
const property_t *
@ -37,65 +71,109 @@ prop_find(const property_t *p, const char *id)
return NULL;
}
#define TO_FROM(x, y) ((x) << 16 | (y))
/* **************************************************************************
* Write
* *************************************************************************/
/**
*
*/
void
prop_write_values(void *obj, const property_t *pl, htsmsg_t *m)
int
prop_write_values(void *obj, const property_t *pl, htsmsg_t *m, int optmask)
{
int save = 0;
htsmsg_field_t *f;
HTSMSG_FOREACH(f, m) {
if(f->hmf_name == NULL)
continue;
/* Find Property */
const property_t *p = prop_find(pl, f->hmf_name);
if(p == NULL) {
//fprintf(stderr, "Property %s unmappable\n", f->hmf_name);
tvhwarn("prop", "invalid property %s", f->hmf_name);
continue;
}
if(p->options & PO_NOSAVE) continue;
/* Ignore */
if(p->opts & optmask) continue;
void *val = obj + p->off;
/* Write */
void *v = obj + p->off;
switch(TO_FROM(p->type, f->hmf_type)) {
case TO_FROM(PT_BOOL, HMF_BOOL):
*(int *)val = f->hmf_bool;
break;
case TO_FROM(PT_BOOL, HMF_S64):
*(int *)val = !!f->hmf_s64;
break;
case TO_FROM(PT_INT, HMF_S64):
*(int *)val = f->hmf_s64;
break;
case TO_FROM(PT_U16, HMF_S64):
*(uint16_t *)val = f->hmf_s64;
break;
case TO_FROM(PT_U32, HMF_S64):
*(uint32_t *)val = f->hmf_s64;
break;
case TO_FROM(PT_STR, HMF_STR):
if(p->str_set != NULL)
p->str_set(obj, f->hmf_str);
else
mystrset(val, f->hmf_str);
case TO_FROM(PT_BOOL, HMF_BOOL): {
int *val = v;
if (*val != f->hmf_bool) {
*val = f->hmf_bool;
save = 1;
}
break;
}
case TO_FROM(PT_BOOL, HMF_S64): {
int *val = v;
if (*val != !!f->hmf_s64) {
*val = !!f->hmf_s64;
save = 1;
}
break;
}
case TO_FROM(PT_INT, HMF_S64): {
int *val = v;
if (*val != f->hmf_s64) {
*val = f->hmf_s64;
save = 1;
}
break;
}
case TO_FROM(PT_U16, HMF_S64): {
uint16_t *val = v;
if (*val != f->hmf_s64) {
*val = f->hmf_s64;
save = 1;
}
break;
}
case TO_FROM(PT_U32, HMF_S64): {
uint32_t *val = v;
if (*val != f->hmf_s64) {
*val = f->hmf_s64;
save = 1;
}
break;
}
case TO_FROM(PT_STR, HMF_STR): {
char **val = v;
if(p->str_set != NULL)
save |= p->str_set(obj, f->hmf_str);
else if (!strcmp(*val ?: "", f->hmf_str)) {
free(*val);
*val = strdup(f->hmf_str);
save = 1;
}
break;
}
}
}
return save;
}
/* **************************************************************************
* Read
* *************************************************************************/
/**
*
*/
static void
prop_read_value(void *obj, const property_t *p, htsmsg_t *m, const char *name)
prop_read_value
(void *obj, const property_t *p, htsmsg_t *m, const char *name, int optmask)
{
const char *s;
const void *val = obj + p->off;
/* Ignore */
if (p->opts & optmask) return;
/* Read */
switch(p->type) {
case PT_BOOL:
htsmsg_add_bool(m, name, *(int *)val);
@ -125,147 +203,52 @@ prop_read_value(void *obj, const property_t *p, htsmsg_t *m, const char *name)
*
*/
void
prop_read_values(void *obj, const property_t *p, htsmsg_t *m)
prop_read_values(void *obj, const property_t *pl, htsmsg_t *m, int optmask)
{
if(p == NULL)
if(pl == NULL)
return;
int i = 0;
for(;p[i].id; i++)
prop_read_value(obj, p+i, m, p[i].id);
for (; pl->id; pl++)
prop_read_value(obj, pl, m, pl->id, optmask);
}
/**
*
*/
const static struct strtab typetab[] = {
{ "bool", PT_BOOL },
{ "int", PT_INT },
{ "str", PT_STR },
{ "u16", PT_U16 },
{ "u32", PT_U32 },
};
/**
*
*/
void
prop_add_params_to_msg(void *obj, const property_t *p, htsmsg_t *msg)
prop_serialize(void *obj, const property_t *pl, htsmsg_t *msg, int optmask)
{
if(p == NULL)
if(pl == NULL)
return;
int i = 0;
for(;p[i].id; i++) {
for(; pl->id; pl++) {
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", p[i].id);
htsmsg_add_str(m, "caption", p[i].name);
htsmsg_add_str(m, "type", val2str(p[i].type, typetab) ?: "unknown");
if (p->options & PO_RDONLY)
htsmsg_add_u32(m, "rdonly", 1);
if (p->options & PO_NOSAVE)
htsmsg_add_u32(m, "nosave", 1);
if (p[i].type == PT_STR && p[i].str_enum) {
htsmsg_t *l = htsmsg_create_list();
const char **e = p[i].str_enum(obj);
while (*e) {
htsmsg_add_str(l, NULL, *e);
e++;
}
htsmsg_add_msg(m, "enum", l);
} else if (p[i].type == PT_STR && p[i].str_enum2) {
htsmsg_add_msg(m, "enum", p[i].str_enum2(obj));
}
if (obj)
prop_read_value(obj, p+i, m, "value");
htsmsg_add_msg(msg, NULL, m);
/* Metadata */
htsmsg_add_str(m, "id", pl->id);
htsmsg_add_str(m, "caption", pl->name);
htsmsg_add_str(m, "type", val2str(pl->type, typetab) ?: "unknown");
/* Options */
if (pl->opts & PO_RDONLY)
htsmsg_add_u32(m, "rdonly", 1);
if (pl->opts & PO_NOSAVE)
htsmsg_add_u32(m, "nosave", 1);
if (pl->opts & PO_WRONCE)
htsmsg_add_u32(m, "wronce", 1);
/* Enum list */
if (pl->str_enum)
htsmsg_add_msg(m, "enum", pl->str_enum(obj));
/* Data */
if (obj)
prop_read_value(obj, pl, m, "value", optmask);
}
}
/**
* value can be NULL
/******************************************************************************
* Editor Configuration
*
* Return 1 if we actually changed something
*/
static int
prop_seti(void *obj, const property_t *p, const char *value)
{
int i;
uint32_t u32;
uint16_t u16;
const char *s;
if (p->options & PO_NOSAVE) return 0;
void *val = obj + p->off;
switch(p->type) {
case PT_BOOL:
i = str_to_bool(value);
if(0)
case PT_INT:
i = value ? atoi(value) : 0;
if(*(int *)val == i)
return 0; // Already set
*(int *)val = i;
break;
case PT_U16:
u16 = value ? atoi(value) : 0;
if(*(uint16_t *)val == u16)
return 0;
*(uint16_t *)val = u16;
break;
case PT_U32:
u32 = value ? atoi(value) : 0;
if(*(uint32_t *)val == u32)
return 0;
*(uint32_t *)val = u32;
break;
case PT_STR:
if(p->str_get != NULL)
s = p->str_get(obj);
else
s = *(const char **)val;
if(!strcmp(s ?: "", value ?: ""))
return 0;
if(p->str_set != NULL)
p->str_set(obj, value);
else
mystrset(val, value);
break;
}
if(p->notify)
p->notify(obj);
return 1;
}
/**
* Return 1 if something changed
*/
int
prop_set(void *obj, const property_t *p, const char *key, const char *value)
{
if((p = prop_find(p, key)) == NULL)
return -1;
return prop_seti(obj, p, value);
}
/**
*
*/
int
prop_update_all(void *obj, const property_t *p,
const char *(*getvalue)(void *opaque, const char *key),
void *opaque)
{
int i = 0;
int r = 0;
for(; p[i].id; i++)
r |= prop_seti(obj, p+i, getvalue(opaque, p[i].id));
return r;
}
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/

View file

@ -1,8 +1,32 @@
#pragma once
/*
* Tvheadend - property system (part of idnode)
*
* Copyright (C) 2013 Andreas Öman
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TVH_PROP_H__
#define __TVH_PROP_H__
#include <stddef.h>
#include "htsmsg.h"
/*
* Property types
*/
typedef enum {
PT_BOOL,
PT_STR,
@ -11,64 +35,51 @@ typedef enum {
PT_U32,
} prop_type_t;
#define PO_NONE 0x0
#define PO_RDONLY 0x1 // Note: if this is changed, change PROPDEF2
#define PO_NOSAVE 0x2
#define PO_WRONCE 0x4
/*
* Property options
*/
#define PO_NONE 0x00
#define PO_RDONLY 0x01 // Property is read-only
#define PO_NOSAVE 0x02 // Property is transient (not saved)
#define PO_WRONCE 0x04 // Property is write-once (i.e. on creation)
/*
* Property definition
*/
typedef struct property {
const char *id;
const char *name;
prop_type_t type;
size_t off;
int options;
const char *id; ///< Property Key
const char *name; ///< Textual description
prop_type_t type; ///< Type
size_t off; ///< Offset into object
int opts; ///< Options
const char *(*str_get)(void *ptr);
void (*str_set)(void *ptr, const char *str);
const char **(*str_enum)(void *ptr);
htsmsg_t *(*str_enum2)(void *ptr);
/* String based processing */
const char *(*str_get) (void *ptr);
int (*str_set) (void *ptr, const char *str);
htsmsg_t *(*str_enum) (void *ptr);
// Note: htsmsg_t can either be a string list or object list
// where the object has "key" and "val" fields
void (*notify)(void *ptr);
/* Notification callback */
void (*notify) (void *ptr);
} property_t;
const property_t *prop_find(const property_t *p, const char *name);
void prop_add_params_to_msg(void *obj, const property_t *p, htsmsg_t *msg);
int prop_write_values
(void *obj, const property_t *pl, htsmsg_t *m, int optmask);
void prop_write_values(void *ptr, const property_t *pl, htsmsg_t *m);
void prop_read_values
(void *obj, const property_t *pl, htsmsg_t *m, int optmask);
void prop_read_values(void *obj, const property_t *p, htsmsg_t *m);
void prop_serialize
(void *obj, const property_t *pl, htsmsg_t *m, int optmask);
int prop_set(void *obj, const property_t *p, const char *key, const char *val);
int prop_update_all(void *obj, const property_t *p,
const char *(*getvalue)(void *opaque, const char *key),
void *opaque);
#define PROPDEF0(_i, _n, _t, _o)\
.id = _i,\
.name = _n,\
.type = _t,\
.options = _o
#define PROPDEF1(_i, _n, _t, _o, _v)\
.id = _i,\
.name = _n,\
.type = _t,\
.off = offsetof(_o, _v)
#define PROPDEF2(_i, _n, _t, _o, _v, _r)\
.id = _i,\
.name = _n,\
.type = _t,\
.off = offsetof(_o, _v),\
.options = _r
#define PROPDEF3(_i, _n, _t, _o, _v, _c)\
.id = _i,\
.name = _n,\
.type = _t,\
.off = offsetof(_o, _v),\
.options = _c
#endif /* __TVH_PROP_H__ */
/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/