diff --git a/apps/aqhome-react/main.c b/apps/aqhome-react/main.c index f20b4db..1f8576c 100644 --- a/apps/aqhome-react/main.c +++ b/apps/aqhome-react/main.c @@ -20,6 +20,7 @@ #include "aqhome/aqhome.h" #include "aqhome/data/path-t.h" #include "aqhome/data/vars-t.h" +#include "aqhome/data/vars_dbread-t.h" #include #include @@ -322,6 +323,12 @@ int _testModules(int argc, char **argv) return 2; } + rv=AQH_Vars_DbRead_AddTests(TestFramework_GetModulesRoot(tf)); + if (rv<0) { + fprintf(stderr, "Adding module \"vars_dbread\" failed.\n"); + return 2; + } + argc--; argv++; rv=TestFramework_Run(tf, argc, argv); diff --git a/aqhome/data/0BUILD b/aqhome/data/0BUILD index 61d5297..c59f67a 100644 --- a/aqhome/data/0BUILD +++ b/aqhome/data/0BUILD @@ -68,6 +68,7 @@ datafile_direct_p.h vars.h vars_p.h + vars_dbread.h path.h @@ -80,6 +81,7 @@ storage_writexml.c datafile_direct.c vars.c + vars_dbread.c path.c @@ -89,6 +91,8 @@ path-t.c vars-t.h vars-t.c + vars_dbread-t.h + vars_dbread-t.c diff --git a/aqhome/data/vars.c b/aqhome/data/vars.c index 780e791..9b94b85 100644 --- a/aqhome/data/vars.c +++ b/aqhome/data/vars.c @@ -128,6 +128,25 @@ void AQH_Vars_free(AQH_VARS *vt) +AQH_VARS_DATATYPE AQH_Vars_DataTypeFromString(const char *s) +{ + if (s && *s) { + if (strcasecmp(s, "group")==0) + return AQH_Vars_DataType_Group; + else if (strcasecmp(s, "variable")==0) + return AQH_Vars_DataType_Variable; + else if (strcasecmp(s, "char")==0) + return AQH_Vars_DataType_ValueString; + else if (strcasecmp(s, "int")==0) + return AQH_Vars_DataType_ValueInt; + else if (strcasecmp(s, "double")==0) + return AQH_Vars_DataType_ValueDouble; + } + return AQH_Vars_DataType_Unknown; +} + + + AQH_VARS *AQH_Vars_dup(const AQH_VARS *vt) { AQH_VARS *vtCopy; @@ -215,7 +234,14 @@ const char *AQH_Vars_GetStringData(const AQH_VARS *vt, const char *defValue) case AQH_Vars_DataType_Variable: case AQH_Vars_DataType_ValueString: return vt->data.dataString; + case AQH_Vars_DataType_ValueInt: + DBG_INFO(AQH_LOGDOMAIN, "Unexpected type INT: %d", vt->data.dataInt); + break; + case AQH_Vars_DataType_ValueDouble: + DBG_INFO(AQH_LOGDOMAIN, "Unexpected type DOUBLE: %f", vt->data.dataDouble); + break; default: + DBG_INFO(AQH_LOGDOMAIN, "Unexpected type %d", vt->dataType); break; } } @@ -348,10 +374,8 @@ const char *AQH_Vars_GetCharValue(AQH_VARS *vt, const char *path, int idx, const AQH_VARS *vtValue; 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); + if (vtChild==NULL) return defaultValue; - } vtValue=_getValueNodeByIdx(vtChild, idx); if (vtValue) return AQH_Vars_GetStringData(vtValue, defaultValue); @@ -388,10 +412,9 @@ int AQH_Vars_GetIntValue(AQH_VARS *vt, const char *path, int idx, int defaultVal AQH_VARS *vtValue; 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); + if (vtChild==NULL) return defaultValue; - } + vtValue=_getValueNodeByIdx(vtChild, idx); if (vtValue) return AQH_Vars_GetIntData(vtValue, defaultValue); @@ -428,10 +451,8 @@ double AQH_Vars_GetDoubleValue(AQH_VARS *vt, const char *path, int idx, double d AQH_VARS *vtValue; 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); + if (vtChild==NULL) return defaultValue; - } vtValue=_getValueNodeByIdx(vtChild, idx); if (vtValue) return AQH_Vars_GetDoubleData(vtValue, defaultValue); @@ -528,7 +549,7 @@ AQH_VARS *_getNodeByTypeAndName(const AQH_VARS *vt, AQH_VARS_DATATYPE dt, const /* look it up */ vtChild=AQH_Vars_GetFirstChildByType(vt, dt); while(vtChild) { - if (vtChild->data.dataString && strcasecmp(vtChild->data.dataString, name)!=-1) { + if (vtChild->data.dataString && strcasecmp(vtChild->data.dataString, name)==0) { if (idx==0) break; else diff --git a/aqhome/data/vars.h b/aqhome/data/vars.h index 7ac4d9b..009effa 100644 --- a/aqhome/data/vars.h +++ b/aqhome/data/vars.h @@ -34,6 +34,8 @@ typedef struct AQH_VARS AQH_VARS; GWEN_TREE2_FUNCTION_LIB_DEFS(AQH_VARS, AQH_Vars, AQHOME_API); +AQHOME_API AQH_VARS_DATATYPE AQH_Vars_DataTypeFromString(const char *s); + AQHOME_API AQH_VARS *AQH_Vars_CreateGroup(const char *s); AQHOME_API AQH_VARS *AQH_Vars_CreateVariable(const char *s); AQHOME_API AQH_VARS *AQH_Vars_CreateStringValue(char *s); diff --git a/aqhome/data/vars_dbread-t.c b/aqhome/data/vars_dbread-t.c new file mode 100644 index 0000000..9042bb5 --- /dev/null +++ b/aqhome/data/vars_dbread-t.c @@ -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. + ****************************************************************************/ + +/* This file is included by "vars_dbread.c" */ + + +#include +#include "vars_dbread-t.h" + + +#ifdef AQHOME_ENABLE_TESTCODE + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int GWENHYWFAR_CB test1(GWEN_TEST_MODULE *mod); +static int GWENHYWFAR_CB test2(GWEN_TEST_MODULE *mod); +static int GWENHYWFAR_CB test3(GWEN_TEST_MODULE *mod); +static int GWENHYWFAR_CB test4(GWEN_TEST_MODULE *mod); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +int AQH_Vars_DbRead_AddTests(GWEN_TEST_MODULE *mod) +{ + GWEN_TEST_MODULE *newMod; + + newMod=GWEN_Test_Module_AddModule(mod, "AQH_Vars_DbRead", NULL); + + GWEN_Test_Module_AddTest(newMod, "test 1: read group", test1, NULL); + GWEN_Test_Module_AddTest(newMod, "test 2: read var", test2, NULL); + GWEN_Test_Module_AddTest(newMod, "test 3: read group and var", test3, NULL); + GWEN_Test_Module_AddTest(newMod, "test 4: read multi groups and vars", test4, NULL); + + return 0; +} + + + +int GWENHYWFAR_CB test1(GWEN_UNUSED GWEN_TEST_MODULE *mod) +{ + AQH_VARS *vtRoot; + const char *testData="testGroup1 {\n}\n"; + + vtRoot=AQH_Vars_ReadDbFormat(testData); + if (vtRoot==NULL) { + DBG_ERROR(AQH_LOGDOMAIN, "Error reading dbformat"); + return GWEN_ERROR_GENERIC; + } + + 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; + } + + AQH_Vars_free(vtRoot); + + return 0; +} + + + +int GWENHYWFAR_CB test2(GWEN_UNUSED GWEN_TEST_MODULE *mod) +{ + AQH_VARS *vtRoot; + const char *testData="char testVar1=\"value1\"\n"; + const char *s; + + vtRoot=AQH_Vars_ReadDbFormat(testData); + if (vtRoot==NULL) { + DBG_ERROR(AQH_LOGDOMAIN, "Error reading dbformat"); + return GWEN_ERROR_GENERIC; + } + + s=AQH_Vars_GetCharValue(vtRoot, "testVar1", 0, NULL); + if (!(s && strcasecmp(s, "value1")==0)) { + DBG_ERROR(AQH_LOGDOMAIN, "Freshly read var \"testVar1\" with bad value (%s)", s?s:""); + AQH_Vars_free(vtRoot); + return GWEN_ERROR_GENERIC; + } + + AQH_Vars_free(vtRoot); + + return 0; +} + + + +int GWENHYWFAR_CB test3(GWEN_UNUSED GWEN_TEST_MODULE *mod) +{ + AQH_VARS *vtRoot; + const char *testData= + "testGroup1 {\n" + " char testVar1=\"value1\"\n" + "}"; + const char *s; + + vtRoot=AQH_Vars_ReadDbFormat(testData); + if (vtRoot==NULL) { + DBG_ERROR(AQH_LOGDOMAIN, "Error reading dbformat"); + return GWEN_ERROR_GENERIC; + } + + 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:""); + AQH_Vars_free(vtRoot); + return GWEN_ERROR_GENERIC; + } + + AQH_Vars_free(vtRoot); + + return 0; +} + + + +int GWENHYWFAR_CB test4(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=\"secondValue\"\n" + " }\n" + "}"; + const char *s; + int i; + + vtRoot=AQH_Vars_ReadDbFormat(testData); + if (vtRoot==NULL) { + DBG_ERROR(AQH_LOGDOMAIN, "Error reading dbformat"); + return GWEN_ERROR_GENERIC; + } + + 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:""); + 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:""); + 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 + + + + + + + diff --git a/aqhome/data/vars_dbread-t.h b/aqhome/data/vars_dbread-t.h new file mode 100644 index 0000000..c0c79fd --- /dev/null +++ b/aqhome/data/vars_dbread-t.h @@ -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_DBREAD_T_H +#define AQH_VARS_DBREAD_T_H + +#include + +#include +#include + + + +/** + * Tests for "Vars" reading GWEN_DB data. + */ +AQHOME_API int AQH_Vars_DbRead_AddTests(GWEN_TEST_MODULE *mod); + + + + +#endif + + diff --git a/aqhome/data/vars_dbread.c b/aqhome/data/vars_dbread.c new file mode 100644 index 0000000..a2a510e --- /dev/null +++ b/aqhome/data/vars_dbread.c @@ -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 +#endif + + + +#include "./vars_p.h" +#include "./vars_dbread.h" +#include "aqhome/data/path.h" + +#include +#include +#include + +#include + + + +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 (dataTypeAQH_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" + diff --git a/aqhome/data/vars_dbread.h b/aqhome/data/vars_dbread.h new file mode 100644 index 0000000..39a2e36 --- /dev/null +++ b/aqhome/data/vars_dbread.h @@ -0,0 +1,24 @@ +/**************************************************************************** + * 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_DBREAD_H +#define AQH_VARS_DBREAD_H + +#include + +#include + + +AQHOME_API AQH_VARS *AQH_Vars_ReadDbFormat(const char *src); + + + + +#endif + +