diff --git a/src/idnode.c b/src/idnode.c index e8f356d5..7952d0ad 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -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 . + */ + #define _GNU_SOURCE #include #include @@ -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 + *****************************************************************************/ diff --git a/src/idnode.h b/src/idnode.h index 947a0a31..5e6f40f0 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -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 . + */ + +#ifndef __TVH_IDNODE_H__ +#define __TVH_IDNODE_H__ #include "tvheadend.h" #include "prop.h" @@ -6,107 +26,112 @@ #include 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 + *****************************************************************************/ diff --git a/src/prop.c b/src/prop.c index 5d521616..21c200cd 100644 --- a/src/prop.c +++ b/src/prop.c @@ -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 . + */ + #include #include #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 + *****************************************************************************/ diff --git a/src/prop.h b/src/prop.h index 83c2fdca..a9e1ce98 100644 --- a/src/prop.h +++ b/src/prop.h @@ -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 . + */ + +#ifndef __TVH_PROP_H__ +#define __TVH_PROP_H__ + #include #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 + *****************************************************************************/