Files
aqhomecontrol/aqhome/data/vars.c
Martin Preuss 2c584bbff9 vars: use const in most api functions
The idea of not using const was to reduce copy operations.
However, it is not very intuitive to know when and which arguments are const
so to simplify working with this new module and make it as close as possible
to GWEN_DB we use const now as in GWEN_DB.
At least AQH_Vars_SetStringData() still doesn't use const so if the need
arises to avoid copying we can.
2024-05-09 14:56:46 +02:00

402 lines
8.3 KiB
C

/****************************************************************************
* This file is part of the project Gwenhywfar.
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./vars_p.h"
#include "aqhome/data/path.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
GWEN_TREE2_FUNCTIONS(AQH_VARS, AQH_Vars);
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static AQH_VARS *_newData(void);
static void _releaseData(AQH_VARS *vt);
static AQH_VARS *_newStringElement(char *s, AQH_VARS_DATATYPE dt);
static AQH_VARS *_getPath(AQH_VARS *vt, const char *s, uint32_t flags);
static void *_pathHandlerFn(const char *entry, void *data, int idx, uint32_t flags);
static AQH_VARS *_getNodeByTypeAndName(const AQH_VARS *vt, AQH_VARS_DATATYPE dt, const char *name, int idx);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_VARS *_newData(void)
{
AQH_VARS *vt;
GWEN_NEW_OBJECT(AQH_VARS, vt);
GWEN_TREE2_INIT(AQH_VARS, vt, AQH_Vars);
return vt;
}
AQH_VARS *_newStringElement(char *s, AQH_VARS_DATATYPE dt)
{
AQH_VARS *vt;
vt=_newData();
vt->data.dataString=s;
vt->dataType=dt;
return vt;
}
void _releaseData(AQH_VARS *vt)
{
if (vt) {
switch(vt->dataType) {
case AQH_Vars_DataType_Group:
case AQH_Vars_DataType_Variable:
case AQH_Vars_DataType_ValueString:
free(vt->data.dataString);
vt->data.dataString=NULL;
break;
default:
break;
}
vt->dataType=AQH_Vars_DataType_Unknown;
}
}
void AQH_Vars_free(AQH_VARS *vt)
{
if (vt) {
GWEN_TREE2_FINI(AQH_VARS, vt, AQH_Vars);
_releaseData(vt);
GWEN_FREE_OBJECT(vt);
}
}
AQH_VARS *AQH_Vars_CreateGroup(const char *s)
{
return _newStringElement(s?strdup(s):NULL, AQH_Vars_DataType_Group);
}
AQH_VARS *AQH_Vars_CreateVariable(const char *s)
{
return _newStringElement(s?strdup(s):NULL, AQH_Vars_DataType_Variable);
}
AQH_VARS *AQH_Vars_CreateStringValue(char *s)
{
return _newStringElement(s, AQH_Vars_DataType_ValueString);
}
AQH_VARS *AQH_Vars_CreateIntValue(int d)
{
AQH_VARS *vt;
vt=_newData();
vt->data.dataInt=d;
vt->dataType=AQH_Vars_DataType_ValueInt;
return vt;
}
AQH_VARS *AQH_Vars_CreateDoubleValue(double d)
{
AQH_VARS *vt;
vt=_newData();
vt->data.dataDouble=d;
vt->dataType=AQH_Vars_DataType_ValueDouble;
return vt;
}
AQH_VARS_DATATYPE AQH_Vars_GetDataType(const AQH_VARS *vt)
{
return vt?vt->dataType:AQH_Vars_DataType_Unknown;
}
uint32_t AQH_Vars_GetFlags(const AQH_VARS *vt)
{
return vt?vt->flags:0;
}
const char *AQH_Vars_GetStringData(const AQH_VARS *vt, const char *defValue)
{
if (vt) {
switch(vt->dataType) {
case AQH_Vars_DataType_Group:
case AQH_Vars_DataType_Variable:
case AQH_Vars_DataType_ValueString:
return vt->data.dataString;
default:
break;
}
}
return defValue;
}
void AQH_Vars_SetStringData(AQH_VARS *vt, char *s)
{
if (vt) {
_releaseData(vt);
vt->data.dataString=s;
vt->dataType=AQH_Vars_DataType_ValueString;
}
}
int AQH_Vars_GetIntData(const AQH_VARS *vt, int defValue)
{
if (vt && vt->dataType==AQH_Vars_DataType_ValueInt)
return vt->data.dataInt;
return defValue;
}
void AQH_Vars_SetIntData(AQH_VARS *vt, int d)
{
if (vt) {
_releaseData(vt);
vt->data.dataInt=d;
vt->dataType=AQH_Vars_DataType_ValueInt;
}
}
double AQH_Vars_GetDoubleData(const AQH_VARS *vt, double defValue)
{
if (vt && vt->dataType==AQH_Vars_DataType_ValueDouble)
return vt->data.dataDouble;
return defValue;
}
void AQH_Vars_SetDoubleData(AQH_VARS *vt, double d)
{
if (vt) {
_releaseData(vt);
vt->data.dataDouble=d;
vt->dataType=AQH_Vars_DataType_ValueDouble;
}
}
AQH_VARS *AQH_Vars_GetFirstChildByType(const AQH_VARS *vt, AQH_VARS_DATATYPE dt)
{
if (vt) {
AQH_VARS *vtChild;
vtChild=AQH_Vars_Tree2_GetFirstChild(vt);
while(vtChild) {
if (vtChild->dataType==dt)
return vtChild;
vtChild=AQH_Vars_Tree2_GetNext(vtChild);
}
}
return NULL;
}
AQH_VARS *AQH_Vars_GetNextByType(const AQH_VARS *vt, AQH_VARS_DATATYPE dt)
{
if (vt) {
AQH_VARS *vtNext;
vtNext=AQH_Vars_Tree2_GetNext(vt);
while(vtNext) {
if (vtNext->dataType==dt)
return vtNext;
vtNext=AQH_Vars_Tree2_GetNext(vtNext);
}
}
return NULL;
}
int AQH_Vars_SetCharValue(AQH_VARS *vt, uint32_t flags, const char *path, const char *value)
{
if (vt) {
AQH_VARS *vtChild;
AQH_VARS *vtValue;
vtChild=_getPath(vt, path, flags | AQH_PATH_FLAGS_VARIABLE);
if (vtChild==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Error getting path for var \"%s\"", path);
return GWEN_ERROR_GENERIC;
}
vtValue=AQH_Vars_CreateStringValue(value?strdup(value):NULL);
AQH_Vars_Tree2_AddChild(vtChild, vtValue);
return 0;
}
return GWEN_ERROR_INVALID;
}
const char *AQH_Vars_GetCharValue(AQH_VARS *vt, const char *path, int idx, const char *defaultValue)
{
if (vt && idx>=0) {
AQH_VARS *vtChild;
AQH_VARS *vtValue;
int i;
vtChild=_getPath(vt, path, AQH_PATH_FLAGS_PATHMUSTEXIST | AQH_PATH_FLAGS_VARIABLE);
if (vtChild==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Path for var \"%s\" not found", path);
return defaultValue;
}
vtValue=AQH_Vars_Tree2_GetFirstChild(vtChild);
i=idx;
while(vtValue && i) {
i--;
vtValue=AQH_Vars_Tree2_GetNext(vtValue);
}
if (vtValue)
return AQH_Vars_GetStringData(vtValue, defaultValue);
}
return defaultValue;
}
AQH_VARS *_getPath(AQH_VARS *vt, const char *s, uint32_t flags)
{
return (AQH_VARS *)AQH_Path_Handle(s, (void*) vt, flags, "/", _pathHandlerFn);
}
void *_pathHandlerFn(const char *entry, void *data, int idx, uint32_t flags)
{
AQH_VARS *vt;
AQH_VARS *vtChild;
AQH_VARS_DATATYPE dt;
vt=(AQH_VARS*) data;
dt=((flags & AQH_PATH_FLAGS_LAST) && (flags & AQH_PATH_FLAGS_VARIABLE))?AQH_Vars_DataType_Variable:AQH_Vars_DataType_Group;
if (
!(
(flags & AQH_PATH_FLAGS_PATHCREATE) ||
((flags & AQH_PATH_FLAGS_LAST) && (flags & AQH_PATH_FLAGS_LASTCREATE))
)
) {
/* look it up */
vtChild=_getNodeByTypeAndName(vt, dt, entry, idx);
if (vtChild) {
/* already exists, should it? */
if (
(flags & AQH_PATH_FLAGS_PATHMUSTNOTEXIST) ||
((flags & AQH_PATH_FLAGS_LAST) && (flags & AQH_PATH_FLAGS_LASTMUSTNOTEXIST))
) {
DBG_INFO(AQH_LOGDOMAIN, "Element \"%s[%d]\" exists when it should not", entry, idx);
return NULL;
}
/* already exists, should we overwrite it (i.e. remove children)? */
if (
(flags & AQH_PATH_FLAGS_LAST) &&
(
((dt==AQH_Vars_DataType_Group) && (flags & AQH_VARS_PATHFLAGS_OVERWRITE_GROUPS)) ||
((dt==AQH_Vars_DataType_Variable) && (flags & AQH_VARS_PATHFLAGS_OVERWRITE_VARS))
)
)
AQH_Vars_Tree2_ClearChildren(vtChild);
return vtChild;
}
else {
/* does not exist, should it? */
if (flags & AQH_PATH_FLAGS_PATHMUSTEXIST) {
DBG_INFO(AQH_LOGDOMAIN, "Element \"%s[%d]\" does not exist when it should", entry, idx);
return NULL;
}
}
}
/* create new string element (either group or var) */
vtChild=_newStringElement(strdup(entry), dt);
AQH_Vars_Tree2_AddChild(vt, vtChild);
return vtChild;
}
AQH_VARS *_getNodeByTypeAndName(const AQH_VARS *vt, AQH_VARS_DATATYPE dt, const char *name, int idx)
{
AQH_VARS *vtChild=NULL;
if (idx>=0) {
/* look it up */
vtChild=AQH_Vars_GetFirstChildByType(vt, dt);
while(vtChild) {
if (vtChild->data.dataString && strcasecmp(vtChild->data.dataString, name)!=-1) {
if (idx==0)
break;
else
idx--;
}
vtChild=AQH_Vars_GetNextByType(vtChild, dt);
}
}
return vtChild;
}
#include "./vars-t.c"