vars: added code to read AQH_VARS from GWEN_DB strings.

This commit is contained in:
Martin Preuss
2024-05-17 00:03:51 +02:00
parent ead34f0309
commit f8f4380038
8 changed files with 623 additions and 10 deletions

319
aqhome/data/vars_dbread.c Normal file
View File

@@ -0,0 +1,319 @@
/****************************************************************************
* 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 "./vars_dbread.h"
#include "aqhome/data/path.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
#include <ctype.h>
const uint32_t _textFlags=
GWEN_TEXT_FLAGS_DEL_LEADING_BLANKS |
GWEN_TEXT_FLAGS_DEL_TRAILING_BLANKS |
GWEN_TEXT_FLAGS_DEL_QUOTES;
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static const char *_readLine(AQH_VARS **pVars, const char *src, GWEN_BUFFER *wbuf);
static const char *_readGroupOrVar(AQH_VARS **pVars, const char *src, GWEN_BUFFER *wbuf);
static const char *_contAsTypedVar(AQH_VARS **pVars, const char *src, const char *tname, GWEN_BUFFER *wbuf);
static const char *_contAsVar(AQH_VARS **pVars, AQH_VARS_DATATYPE dataType, const char *src, const char *vname, GWEN_BUFFER *wbuf);
static const char *_readValue(AQH_VARS *vtVar, AQH_VARS_DATATYPE dataType, const char *s, GWEN_BUFFER *wbuf);
static AQH_VARS *_mkStringValue(const char *s);
static AQH_VARS *_mkIntValue(const char *s);
static AQH_VARS *_mkDoubleValue(const char *s);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_VARS *AQH_Vars_ReadDbFormat(const char *src)
{
AQH_VARS *vtRoot;
AQH_VARS *vt;
GWEN_BUFFER *wbuf;
const char *s;
vtRoot=AQH_Vars_CreateGroup("root");
vt=vtRoot;
wbuf=GWEN_Buffer_new(0, 64, 0, 1);
s=src;
while(*s) {
GWEN_Buffer_Reset(wbuf);
s=_readLine(&vt, s, wbuf);
if (s==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here");
GWEN_Buffer_free(wbuf);
AQH_Vars_free(vtRoot);
return NULL;
}
}
GWEN_Buffer_free(wbuf);
if (vt!=vtRoot) {
DBG_ERROR(AQH_LOGDOMAIN, "Incomplete groups read");
AQH_Vars_free(vtRoot);
return NULL;
}
return vtRoot;
}
const char *_readLine(AQH_VARS **pVars, const char *src, GWEN_BUFFER *wbuf)
{
int rv;
const char *s;
s=src;
while(*s && isblank(*s))
s++;
if (*s=='}') {
AQH_VARS *vt;
/* current group ends */
vt=AQH_Vars_Tree2_GetParent(*pVars);
*pVars=vt;
s++;
}
else if (*s=='#') {
/* rest of line is a comment */
s++;
while(*s && !(*s==10 || *s==13))
s++;
}
else if (*s==10 || *s==13) {
/* end of line, so empty line */
}
else {
s=_readGroupOrVar(pVars, s, wbuf);
if (s==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return NULL;
}
}
/* handle end of line */
while(*s && isblank(*s))
s++;
while(*s==10 || *s==13)
s++;
return s;
}
const char *_readGroupOrVar(AQH_VARS **pVars, const char *src, GWEN_BUFFER *wbuf)
{
const char *s;
int rv;
rv=GWEN_Text_GetWordToBuffer(src, " ={#\t\r\n", wbuf, _textFlags, &s);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return NULL;
}
while(*s && isblank(*s))
s++;
if (*s=='{') {
AQH_VARS *vt;
/* read group */
vt=AQH_Vars_CreateGroup(GWEN_Buffer_GetStart(wbuf));
AQH_Vars_Tree2_AddChild(*pVars, vt);
*pVars=vt;
s++;
}
else if (*s=='=') {
/* read untyped var, assume string */
s=_contAsVar(pVars, AQH_Vars_DataType_ValueString, s, GWEN_Buffer_GetStart(wbuf), wbuf);
if (s==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return NULL;
}
}
else if (*s=='#' || *s=='\r' || *s=='\n') {
/* line logically or physically ends after first word, syntax error */
DBG_ERROR(AQH_LOGDOMAIN, "Unexpected end of line");
return NULL;
}
else {
s=_contAsTypedVar(pVars, s, GWEN_Buffer_GetStart(wbuf), wbuf);
if (s==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return NULL;
}
}
return s;
}
const char *_contAsTypedVar(AQH_VARS **pVars, const char *src, const char *tname, GWEN_BUFFER *wbuf)
{
AQH_VARS_DATATYPE dataType;
const char *s;
int rv;
/* got type, convert to type */
dataType=AQH_Vars_DataTypeFromString(tname);
if (dataType<AQH_Vars_DataType_ValueString || dataType>AQH_Vars_DataType_ValueDouble) {
DBG_ERROR(AQH_LOGDOMAIN, "Invalid type \"%s\"", tname);
return NULL;
}
/* read name */
GWEN_Buffer_Reset(wbuf);
rv=GWEN_Text_GetWordToBuffer(src, " \t={#\r\n", wbuf, _textFlags, &s);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return NULL;
}
while(*s && isblank(*s))
s++;
s=_contAsVar(pVars, dataType, s, GWEN_Buffer_GetStart(wbuf), wbuf);
if (s==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here");
return NULL;
}
return s;
}
const char *_contAsVar(AQH_VARS **pVars, AQH_VARS_DATATYPE dataType, const char *src, const char *vname, GWEN_BUFFER *wbuf)
{
const char *s;
AQH_VARS *vtVar;
s=src;
if (*s!='=') {
DBG_ERROR(AQH_LOGDOMAIN, "Expected \"=\"");
return NULL;
}
s++;
vtVar=AQH_Vars_CreateVariable(vname);
AQH_Vars_Tree2_AddChild(*pVars, vtVar);
while(*s) {
GWEN_Buffer_Reset(wbuf);
s=_readValue(vtVar, dataType, s, wbuf);
if (s==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here");
return NULL;
}
while(*s && isblank(*s))
s++;
if (*s==';') {
s++;
break;
}
if (*s!=',')
break;
s++;
}
return s;
}
const char *_readValue(AQH_VARS *vtVar, AQH_VARS_DATATYPE dataType, const char *s, GWEN_BUFFER *wbuf)
{
int rv;
AQH_VARS *vtValue;
rv=GWEN_Text_GetWordToBuffer(s, " \t,;#\r\n", wbuf, _textFlags, &s);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return NULL;
}
switch(dataType) {
case AQH_Vars_DataType_ValueString: vtValue=_mkStringValue(GWEN_Buffer_GetStart(wbuf)); break;
case AQH_Vars_DataType_ValueInt: vtValue=_mkIntValue(GWEN_Buffer_GetStart(wbuf)); break;
case AQH_Vars_DataType_ValueDouble: vtValue=_mkDoubleValue(GWEN_Buffer_GetStart(wbuf)); break;
default: vtValue=NULL; break;
}
if (vtValue==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here");
return NULL;
}
AQH_Vars_Tree2_AddChild(vtVar, vtValue);
return s;
}
AQH_VARS *_mkStringValue(const char *s)
{
return AQH_Vars_CreateStringValue(strdup(s));
}
AQH_VARS *_mkIntValue(const char *s)
{
int v;
if (1!=sscanf(s, "%i", &v)) {
DBG_ERROR(AQH_LOGDOMAIN, "Not an int value [%s]", s);
return NULL;
}
return AQH_Vars_CreateIntValue(v);
}
AQH_VARS *_mkDoubleValue(const char *s)
{
int rv;
double v;
rv=GWEN_Text_StringToDouble(s, &v);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Not a double value [%s] (%d)", s, rv);
return NULL;
}
return AQH_Vars_CreateDoubleValue(v);
}
#include "./vars_dbread-t.c"