aqhome: add writer for AQH_VARS (including a test).
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "aqhome/data/path-t.h"
|
||||
#include "aqhome/data/vars-t.h"
|
||||
#include "aqhome/data/vars_dbread-t.h"
|
||||
#include "aqhome/data/vars_dbwrite-t.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
@@ -329,6 +330,12 @@ int _testModules(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
|
||||
rv=AQH_Vars_DbWrite_AddTests(TestFramework_GetModulesRoot(tf));
|
||||
if (rv<0) {
|
||||
fprintf(stderr, "Adding module \"vars_dbwrite\" failed.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
rv=TestFramework_Run(tf, argc, argv);
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
vars.h
|
||||
vars_p.h
|
||||
vars_dbread.h
|
||||
vars_dbwrite.h
|
||||
path.h
|
||||
</headers>
|
||||
|
||||
@@ -82,6 +83,7 @@
|
||||
datafile_direct.c
|
||||
vars.c
|
||||
vars_dbread.c
|
||||
vars_dbwrite.c
|
||||
path.c
|
||||
</sources>
|
||||
|
||||
@@ -93,6 +95,8 @@
|
||||
vars-t.c
|
||||
vars_dbread-t.h
|
||||
vars_dbread-t.c
|
||||
vars_dbwrite-t.h
|
||||
vars_dbwrite-t.c
|
||||
</extradist>
|
||||
|
||||
|
||||
|
||||
134
aqhome/data/vars_dbwrite-t.c
Normal file
134
aqhome/data/vars_dbwrite-t.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project Gwenhywfar.
|
||||
* AqHome (c) by 2024 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.
|
||||
****************************************************************************/
|
||||
|
||||
/* This file is included by "vars_dbread.c" */
|
||||
|
||||
|
||||
#include <gwenhywfar/testframework.h>
|
||||
#include "vars_dbwrite-t.h"
|
||||
|
||||
|
||||
#ifdef AQHOME_ENABLE_TESTCODE
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int GWENHYWFAR_CB test1(GWEN_TEST_MODULE *mod);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AQH_Vars_DbWrite_AddTests(GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
GWEN_TEST_MODULE *newMod;
|
||||
|
||||
newMod=GWEN_Test_Module_AddModule(mod, "AQH_Vars_DbWrite", NULL);
|
||||
|
||||
GWEN_Test_Module_AddTest(newMod, "test 1: read, write and read groups and vars", test1, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GWENHYWFAR_CB test1(GWEN_UNUSED GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
AQH_VARS *vtRoot;
|
||||
const char *testData=
|
||||
"testGroup1 {\n"
|
||||
" char testVar1=\"value1\"\n"
|
||||
" secondGroup { # here starts the 2nd group\n"
|
||||
"# this is the second comment\n"
|
||||
" int firstVarOfSecondGroup=\"1234\";\n"
|
||||
" secondVarOfSecondGroup=\"s%65condValue\"\n"
|
||||
" }\n"
|
||||
"}";
|
||||
const char *s;
|
||||
GWEN_BUFFER *obuf;
|
||||
int rv;
|
||||
int i;
|
||||
|
||||
vtRoot=AQH_Vars_ReadDbFormat(testData);
|
||||
if (vtRoot==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading dbformat");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
obuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=AQH_Vars_WriteDbFormat(vtRoot, obuf);
|
||||
if (rv<0) {
|
||||
GWEN_Buffer_free(obuf);
|
||||
AQH_Vars_free(vtRoot);
|
||||
return rv;
|
||||
}
|
||||
|
||||
vtRoot=AQH_Vars_ReadDbFormat(GWEN_Buffer_GetStart(obuf));
|
||||
if (vtRoot==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading dbformat");
|
||||
GWEN_Buffer_free(obuf);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
GWEN_Buffer_free(obuf);
|
||||
|
||||
if (NULL==AQH_Vars_GetGroup(vtRoot, "testGroup1", AQH_PATH_FLAGS_PATHMUSTEXIST)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Freshly read group \"testGroup1\" not found");
|
||||
AQH_Vars_free(vtRoot);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
s=AQH_Vars_GetCharValue(vtRoot, "testGroup1/testVar1", 0, NULL);
|
||||
if (!(s && strcasecmp(s, "value1")==0)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Freshly read var \"testVar1\" with bad value (%s)", s?s:"<empty>");
|
||||
AQH_Vars_free(vtRoot);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
i=AQH_Vars_GetIntValue(vtRoot, "testGroup1/secondGroup/firstVarOfSecondGroup", 0, -1);
|
||||
if (i!=1234) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Freshly read var \"testGroup1/secondGroup/firstVarOfSecondGroup\" with bad value (%i)", i);
|
||||
AQH_Vars_free(vtRoot);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
s=AQH_Vars_GetCharValue(vtRoot, "testGroup1/secondGroup/secondVarOfSecondGroup", 0, NULL);
|
||||
if (!(s && strcasecmp(s, "secondValue")==0)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Freshly read var \"testGroup1/secondGroup/secondVarOfSecondGroup\" with bad value (%s)", s?s:"<empty>");
|
||||
AQH_Vars_free(vtRoot);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
AQH_Vars_free(vtRoot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int AQH_Vars_DbRead_AddTests(GWEN_TEST_MODULE *mod)
|
||||
{
|
||||
DBG_ERROR(GWEN_LOGDOMAIN, "AqHome was compiled without test code enabled.");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
29
aqhome/data/vars_dbwrite-t.h
Normal file
29
aqhome/data/vars_dbwrite-t.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_VARS_DBWRITE_T_H
|
||||
#define AQH_VARS_DBWRITE_T_H
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include <gwenhywfar/gwenhywfarapi.h>
|
||||
#include <gwenhywfar/testframework.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests for "Vars" reading and writing GWEN_DB data.
|
||||
*/
|
||||
AQHOME_API int AQH_Vars_DbWrite_AddTests(GWEN_TEST_MODULE *mod);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
207
aqhome/data/vars_dbwrite.c
Normal file
207
aqhome/data/vars_dbwrite.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project Gwenhywfar.
|
||||
* AqHome (c) by 2024 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 "./vars_dbread.h"
|
||||
#include "aqhome/data/path.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* definitions
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const char *_acceptableChars=",.:;-+/&";
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _groupToBuffer(const AQH_VARS *vt, GWEN_BUFFER *dbuf, int indent);
|
||||
static int _groupChildrenToBuffer(const AQH_VARS *vt, GWEN_BUFFER *dbuf, int indent);
|
||||
static int _varToBuffer(const AQH_VARS *vt, GWEN_BUFFER *dbuf, int indent);
|
||||
static void _appendEscapedString(const char *s, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int AQH_Vars_WriteDbFormat(const AQH_VARS *vt, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
if (vt && dbuf) {
|
||||
int rv;
|
||||
|
||||
rv=_groupChildrenToBuffer(vt, dbuf, 0);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _groupToBuffer(const AQH_VARS *vt, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (indent)
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
|
||||
if (vt->data.dataString && *(vt->data.dataString)) {
|
||||
_appendEscapedString(vt->data.dataString, dbuf);
|
||||
GWEN_Buffer_AppendString(dbuf, " {\n");
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Group has no name");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
rv=_groupChildrenToBuffer(vt, dbuf, indent+2);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
if (indent)
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
GWEN_Buffer_AppendString(dbuf, "}\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _groupChildrenToBuffer(const AQH_VARS *vt, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
const AQH_VARS *vtChild;
|
||||
|
||||
vtChild=AQH_Vars_Tree2_GetFirstChild(vt);
|
||||
while(vtChild) {
|
||||
int rv;
|
||||
|
||||
switch(vtChild->dataType) {
|
||||
case AQH_Vars_DataType_Group: rv=_groupToBuffer(vtChild, dbuf, indent+2); break;
|
||||
case AQH_Vars_DataType_Variable: rv=_varToBuffer(vtChild, dbuf, indent+2); break;
|
||||
default:
|
||||
DBG_ERROR(AQH_LOGDOMAIN,
|
||||
"Unexpected data type \"%d\" (%s)",
|
||||
vtChild->dataType,
|
||||
AQH_Vars_DataTypeToString(vtChild->dataType));
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
vtChild=AQH_Vars_Tree2_GetNext(vtChild);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _varToBuffer(const AQH_VARS *vt, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
const AQH_VARS *vtChild;
|
||||
int isFirst=1;
|
||||
|
||||
vtChild=AQH_Vars_Tree2_GetFirstChild(vt);
|
||||
if (vtChild) {
|
||||
if (vt->data.dataString && *(vt->data.dataString)) {
|
||||
if (indent)
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "%s ", AQH_Vars_DataTypeToString(vtChild->dataType));
|
||||
_appendEscapedString(vt->data.dataString, dbuf);
|
||||
GWEN_Buffer_AppendString(dbuf, "=");
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Variable has no name");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
while(vtChild) {
|
||||
if (!isFirst) {
|
||||
GWEN_Buffer_AppendString(dbuf, ", ");
|
||||
isFirst=0;
|
||||
}
|
||||
|
||||
switch(vtChild->dataType) {
|
||||
case AQH_Vars_DataType_ValueString:
|
||||
GWEN_Buffer_AppendByte(dbuf, '\"');
|
||||
_appendEscapedString(vtChild->data.dataString, dbuf);
|
||||
GWEN_Buffer_AppendByte(dbuf, '\"');
|
||||
break;
|
||||
case AQH_Vars_DataType_ValueInt:
|
||||
GWEN_Buffer_AppendArgs(dbuf, "\"%d\"", vtChild->data.dataInt);
|
||||
break;
|
||||
case AQH_Vars_DataType_ValueDouble:
|
||||
GWEN_Buffer_AppendArgs(dbuf, "\"%f\"", vtChild->data.dataDouble);
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG_ERROR(AQH_LOGDOMAIN,
|
||||
"Unexpected data type \"%d\" (%s)",
|
||||
vtChild->dataType,
|
||||
AQH_Vars_DataTypeToString(vtChild->dataType));
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
vtChild=AQH_Vars_Tree2_GetNext(vtChild);
|
||||
}
|
||||
GWEN_Buffer_AppendString(dbuf, "\n");
|
||||
} /* if vtCild */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _appendEscapedString(const char *s, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
while(*s) {
|
||||
unsigned char x;
|
||||
|
||||
x=*s;
|
||||
if ((x>='A' && x<='Z') || (x>='a' && x<='z') || (x>='0' && x<='9') || strchr(_acceptableChars, x))
|
||||
GWEN_Buffer_AppendByte(dbuf, x);
|
||||
else
|
||||
GWEN_Buffer_AppendArgs(dbuf, "%%%02x", x);
|
||||
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "./vars_dbwrite-t.c"
|
||||
|
||||
23
aqhome/data/vars_dbwrite.h
Normal file
23
aqhome/data/vars_dbwrite.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_VARS_DBWRITE_H
|
||||
#define AQH_VARS_DBWRITE_H
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include <aqhome/data/vars.h>
|
||||
|
||||
|
||||
AQHOME_API int AQH_Vars_WriteDbFormat(const AQH_VARS *vt, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user