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:
parent
ddcb8d1ca9
commit
ac41437712
4 changed files with 561 additions and 495 deletions
476
src/idnode.c
476
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 <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
|
||||
*****************************************************************************/
|
||||
|
|
164
src/idnode.h
164
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 <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
|
||||
*****************************************************************************/
|
||||
|
|
307
src/prop.c
307
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 <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
|
||||
*****************************************************************************/
|
||||
|
|
109
src/prop.h
109
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 <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
|
||||
*****************************************************************************/
|
||||
|
|
Loading…
Add table
Reference in a new issue