/**************************************************************************** * This file is part of the project AqHome. * 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 #endif #include "./vars_p.h" #include "./vars_dbwrite.h" #include "aqhome/data/path.h" #include #include #include #include #include #include #include /* ------------------------------------------------------------------------------------------------ * 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_WriteDbFile(const AQH_VARS *vt, const char *filename) { int rv; GWEN_BUFFER *fbuf; GWEN_BUFFER *dbuf; fbuf=GWEN_Buffer_new(0, 256, 0, 1); GWEN_Buffer_AppendString(fbuf, filename); GWEN_Buffer_AppendString(fbuf, ".tmp"); dbuf=GWEN_Buffer_new(0, 256, 0, 1); rv=AQH_Vars_WriteDbFormat(vt, dbuf); if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); GWEN_Buffer_free(dbuf); GWEN_Buffer_free(fbuf); return rv; } rv=GWEN_SyncIo_Helper_WriteFile(GWEN_Buffer_GetStart(fbuf), (const uint8_t*) GWEN_Buffer_GetStart(dbuf), GWEN_Buffer_GetUsedBytes(dbuf)); if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); GWEN_Buffer_free(dbuf); GWEN_Buffer_free(fbuf); return rv; } GWEN_Buffer_free(dbuf); if (rename(GWEN_Buffer_GetStart(fbuf), filename)) { DBG_INFO(AQH_LOGDOMAIN, "here (%d: %s)", errno, strerror(errno)); GWEN_Buffer_free(fbuf); return GWEN_ERROR_IO; } GWEN_Buffer_free(fbuf); return 0; } 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 vtChild */ 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"