516 lines
12 KiB
C
516 lines
12 KiB
C
/****************************************************************************
|
|
* This file is part of the project AqHome.
|
|
* AqHome (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 "aqhome/aqhome.h"
|
|
|
|
#include <gwenhywfar/gwenhywfar.h>
|
|
#include <gwenhywfar/logger.h>
|
|
#include <gwenhywfar/pathmanager.h>
|
|
#include <gwenhywfar/debug.h>
|
|
#include <gwenhywfar/i18n.h>
|
|
#include <gwenhywfar/stringlist.h>
|
|
#include <gwenhywfar/directory.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#define AQHOME_PM_LIBNAME "aqhome"
|
|
#define AQHOME_PM_SYSCONFDIR "sysconfdir"
|
|
#define AQHOME_PM_DATADIR "datadir"
|
|
#define AQHOME_PM_RTDATADIR "rtdatadir"
|
|
#define AQHOME_PM_LOCALEDIR "localedir"
|
|
|
|
#define AQHOME_SYSCONFIG_FILE "aqhome.conf"
|
|
|
|
|
|
|
|
static void _initLogging(void);
|
|
static void _finiLogging(void);
|
|
static void _initPathManager(void);
|
|
static void _finiPathManager(void);
|
|
static void _initI18n(void);
|
|
static void _definePath(const char *pathName, const char *pathValue);
|
|
static GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFolder, const char *mask);
|
|
static GWEN_BUFFER *_getRuntimeFilePath(const char *pathName, const char *sFilename);
|
|
static GWEN_BUFFER *_findFileinPath(const char *pathName, const char *sFilename);
|
|
static int _readUint8DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom);
|
|
static int _readUint16DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom);
|
|
static int _readUint32DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom);
|
|
|
|
|
|
|
|
int AQH_Init(void)
|
|
{
|
|
int rv;
|
|
|
|
rv=GWEN_Init();
|
|
if (rv) {
|
|
DBG_ERROR_ERR(AQH_LOGDOMAIN, rv);
|
|
return rv;
|
|
}
|
|
|
|
_initLogging();
|
|
_initPathManager();
|
|
_initI18n();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void AQH_Fini(void)
|
|
{
|
|
_finiPathManager();
|
|
_finiLogging();
|
|
|
|
GWEN_Fini();
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AQH_GetGlobalDataDirs(void)
|
|
{
|
|
return GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, AQHOME_PM_DATADIR);
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AQH_GetGlobalSysconfDirs(void)
|
|
{
|
|
return GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, AQHOME_PM_SYSCONFDIR);
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AQH_GetListOfMatchingDataFiles(const char *subFolder, const char *mask)
|
|
{
|
|
return _getListOfMatchingFiles(AQHOME_PM_DATADIR, subFolder, mask);
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AQH_GetListOfMatchingRuntimeDataFiles(const char *subFolder, const char *mask)
|
|
{
|
|
return _getListOfMatchingFiles(AQHOME_PM_RTDATADIR, subFolder, mask);
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *AQH_GetListOfMatchingSysconfFiles(const char *subFolder, const char *mask)
|
|
{
|
|
return _getListOfMatchingFiles(AQHOME_PM_SYSCONFDIR, subFolder, mask);
|
|
}
|
|
|
|
|
|
|
|
GWEN_BUFFER *AQH_GetRuntimeFilePath(const char *sFilename)
|
|
{
|
|
return _getRuntimeFilePath(AQHOME_PM_RTDATADIR, sFilename);
|
|
}
|
|
|
|
|
|
|
|
GWEN_BUFFER *AQH_FindPathOfRuntimeFile(const char *sFilename)
|
|
{
|
|
return _findFileinPath(AQHOME_PM_RTDATADIR, sFilename);
|
|
}
|
|
|
|
|
|
|
|
GWEN_BUFFER *AQH_FindPathOfSysconfFile(const char *sFilename)
|
|
{
|
|
return _findFileinPath(AQHOME_PM_SYSCONFDIR, sFilename);
|
|
}
|
|
|
|
|
|
|
|
GWEN_BUFFER *AQH_FindPathOfDataFile(const char *sFilename)
|
|
{
|
|
return _findFileinPath(AQHOME_PM_DATADIR, sFilename);
|
|
}
|
|
|
|
|
|
|
|
|
|
GWEN_DB_NODE *AQH_LoadConfigFile(void)
|
|
{
|
|
GWEN_BUFFER *fbuf;
|
|
int rv;
|
|
|
|
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
rv=GWEN_PathManager_FindFile(AQHOME_PM_LIBNAME, AQHOME_PM_SYSCONFDIR, AQHOME_SYSCONFIG_FILE, fbuf);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "Config file \"%s\" not found (%d)", AQHOME_SYSCONFIG_FILE, rv);
|
|
GWEN_Buffer_free(fbuf);
|
|
return NULL;
|
|
}
|
|
else {
|
|
GWEN_DB_NODE *db;
|
|
|
|
db=GWEN_DB_Group_new("aqhome-config");
|
|
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(fbuf), GWEN_DB_FLAGS_DEFAULT);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "Error reading config file \"%s\" (%d)", AQHOME_SYSCONFIG_FILE, rv);
|
|
GWEN_Buffer_free(fbuf);
|
|
GWEN_DB_Group_free(db);
|
|
return NULL;
|
|
}
|
|
GWEN_Buffer_free(fbuf);
|
|
return db;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void AQH_MergeConfigFileIntoConfig(GWEN_DB_NODE *dbArgs, const char *destDbGroupName)
|
|
{
|
|
GWEN_DB_NODE *dbConfig;
|
|
|
|
dbConfig=AQH_LoadConfigFile();
|
|
if (dbConfig) {
|
|
GWEN_DB_GroupRename(dbConfig, destDbGroupName);
|
|
GWEN_DB_AddGroup(dbArgs, dbConfig);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQH_ValueType_fromString(const char *s)
|
|
{
|
|
if (s) {
|
|
if (strcasecmp(s, "sensor")==0)
|
|
return AQH_ValueType_Sensor;
|
|
else if (strcasecmp(s, "actor")==0)
|
|
return AQH_ValueType_Actor;
|
|
}
|
|
return AQH_ValueType_Unknown;
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_ValueType_toString(int i)
|
|
{
|
|
switch (i) {
|
|
case AQH_ValueType_Sensor: return "sensor";
|
|
case AQH_ValueType_Actor: return "actor";
|
|
case AQH_ValueType_Unknown:
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQH_ValueDataType_fromString(const char *s)
|
|
{
|
|
if (s) {
|
|
if (strcasecmp(s, "int")==0)
|
|
return AQH_ValueDataType_Int;
|
|
else if (strcasecmp(s, "dword")==0)
|
|
return AQH_ValueDataType_Uint32;
|
|
else if (strcasecmp(s, "rational")==0)
|
|
return AQH_ValueDataType_Rational;
|
|
else if (strcasecmp(s, "AQH_ValueDataType_Uint8")==0)
|
|
return AQH_ValueDataType_Uint8;
|
|
else if (strcasecmp(s, "AQH_ValueDataType_Uint16")==0)
|
|
return AQH_ValueDataType_Uint16;
|
|
else if (strcasecmp(s, "AQH_ValueDataType_Uint32")==0)
|
|
return AQH_ValueDataType_Uint32;
|
|
}
|
|
return AQH_ValueDataType_Unknown;
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_ValueDataType_toString(int i)
|
|
{
|
|
switch(i) {
|
|
case AQH_ValueDataType_Int: return "int";
|
|
case AQH_ValueDataType_Rational: return "rational";
|
|
case AQH_ValueDataType_Uint8: return "uint8";
|
|
case AQH_ValueDataType_Uint16: return "uint16";
|
|
case AQH_ValueDataType_Uint32: return "uint32";
|
|
case AQH_ValueDataType_Unknown:
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int AQH_ValueModality_fromString(const char *s)
|
|
{
|
|
if (s) {
|
|
if (strcasecmp(s, "temperature")==0)
|
|
return AQH_ValueModality_Temperature;
|
|
else if (strcasecmp(s, "humidity")==0)
|
|
return AQH_ValueModality_Humidity;
|
|
else if (strcasecmp(s, "door")==0)
|
|
return AQH_ValueModality_Door;
|
|
else if (strcasecmp(s, "rgb")==0)
|
|
return AQH_ValueModality_RGB;
|
|
else if (strcasecmp(s, "rgbw")==0)
|
|
return AQH_ValueModality_RGBW;
|
|
else if (strcasecmp(s, "motion")==0)
|
|
return AQH_ValueModality_Motion;
|
|
}
|
|
return AQH_ValueModality_Unknown;
|
|
}
|
|
|
|
|
|
|
|
const char *AQH_ValueModality_toString(int i)
|
|
{
|
|
switch(i) {
|
|
case AQH_ValueModality_Temperature: return "temperature";
|
|
case AQH_ValueModality_Humidity: return "humidity";
|
|
case AQH_ValueModality_Door: return "door";
|
|
case AQH_ValueModality_RGB: return "rgb";
|
|
case AQH_ValueModality_RGBW: return "rgbw";
|
|
case AQH_ValueModality_Motion: return "motion";
|
|
case AQH_ValueModality_Unknown:
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void _initLogging(void)
|
|
{
|
|
const char *s;
|
|
|
|
if (!GWEN_Logger_IsOpen(AQH_LOGDOMAIN))
|
|
GWEN_Logger_Open(AQH_LOGDOMAIN, "aqhome", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
|
|
|
s=getenv("AQHOME_LOGLEVEL");
|
|
if (s && *s) {
|
|
GWEN_LOGGER_LEVEL ll;
|
|
|
|
ll=GWEN_Logger_Name2Level(s);
|
|
GWEN_Logger_SetLevel(AQH_LOGDOMAIN, ll);
|
|
}
|
|
else
|
|
GWEN_Logger_SetLevel(AQH_LOGDOMAIN, GWEN_LoggerLevel_Notice);
|
|
}
|
|
|
|
|
|
|
|
void _finiLogging(void)
|
|
{
|
|
GWEN_Logger_Close(AQH_LOGDOMAIN);
|
|
}
|
|
|
|
|
|
|
|
void _initPathManager(void)
|
|
{
|
|
_definePath(AQHOME_PM_SYSCONFDIR, AQHOME_SYSCONF_DIR);
|
|
_definePath(AQHOME_PM_LOCALEDIR, AQHOME_SYSCONF_DIR);
|
|
_definePath(AQHOME_PM_DATADIR, AQHOME_DATA_DIR);
|
|
_definePath(AQHOME_PM_RTDATADIR, AQHOME_RTDATA_DIR);
|
|
}
|
|
|
|
|
|
|
|
void _finiPathManager(void)
|
|
{
|
|
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_LOCALEDIR);
|
|
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_RTDATADIR);
|
|
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_DATADIR);
|
|
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_SYSCONFDIR);
|
|
GWEN_PathManager_RemovePaths(AQHOME_PM_LIBNAME);
|
|
}
|
|
|
|
|
|
|
|
void _initI18n(void)
|
|
{
|
|
GWEN_STRINGLIST *sl;
|
|
|
|
sl=GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, AQHOME_PM_LOCALEDIR);
|
|
if (sl) {
|
|
const char *localedir;
|
|
int rv;
|
|
|
|
localedir=GWEN_StringList_FirstString(sl);
|
|
|
|
rv=GWEN_I18N_BindTextDomain_Dir(PACKAGE, localedir);
|
|
if (rv) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "Could not bind textdomain (%d)", rv);
|
|
}
|
|
else {
|
|
rv=GWEN_I18N_BindTextDomain_Codeset(PACKAGE, "UTF-8");
|
|
if (rv) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "Could not set codeset (%d)", rv);
|
|
}
|
|
}
|
|
|
|
GWEN_StringList_free(sl);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void _definePath(const char *pathName, const char *pathValue)
|
|
{
|
|
/* define sysconf paths */
|
|
GWEN_PathManager_DefinePath(AQHOME_PM_LIBNAME, pathName);
|
|
#if defined(OS_WIN32) || defined(ENABLE_LOCAL_INSTALL)
|
|
/* add folder relative to EXE */
|
|
GWEN_PathManager_AddRelPath(AQHOME_PM_LIBNAME, AQHOME_PM_LIBNAME, pathName, pathValue, GWEN_PathManager_RelModeExe);
|
|
#else
|
|
/* add absolute folder */
|
|
GWEN_PathManager_AddPath(AQHOME_PM_LIBNAME, AQHOME_PM_LIBNAME, pathName, pathValue);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFolder, const char *mask)
|
|
{
|
|
int rv;
|
|
GWEN_STRINGLIST *sl;
|
|
|
|
sl=GWEN_StringList_new();
|
|
rv=GWEN_PathManager_GetMatchingFilesRecursively(AQHOME_PM_LIBNAME, pathName, subFolder, sl, mask);
|
|
if (rv<0) {
|
|
DBG_INFO(AQH_LOGDOMAIN,
|
|
"Error listing matching data files (folder=%s, mask=%s)",
|
|
subFolder?subFolder:"<empty>", mask?mask:"<empty>");
|
|
GWEN_StringList_free(sl);
|
|
return NULL;
|
|
}
|
|
return sl;
|
|
}
|
|
|
|
|
|
|
|
GWEN_BUFFER *_getRuntimeFilePath(const char *pathName, const char *sFilename)
|
|
{
|
|
GWEN_STRINGLIST *sl;
|
|
|
|
sl=GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, pathName);
|
|
if (sl) {
|
|
GWEN_STRINGLISTENTRY *se;
|
|
|
|
se=GWEN_StringList_FirstEntry(sl);
|
|
if (se) {
|
|
const char *s;
|
|
|
|
s=GWEN_StringListEntry_Data(se);
|
|
if (s && *s) {
|
|
GWEN_BUFFER *buf;
|
|
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
GWEN_Buffer_AppendString(buf, s);
|
|
if (sFilename && *sFilename) {
|
|
GWEN_Buffer_AppendByte(buf, GWEN_DIR_SEPARATOR);
|
|
GWEN_Buffer_AppendString(buf, sFilename);
|
|
}
|
|
GWEN_StringList_free(sl);
|
|
return buf;
|
|
}
|
|
}
|
|
GWEN_StringList_free(sl);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
GWEN_BUFFER *_findFileinPath(const char *pathName, const char *sFilename)
|
|
{
|
|
GWEN_STRINGLIST *sl;
|
|
|
|
sl=GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, pathName);
|
|
if (sl) {
|
|
int rv;
|
|
GWEN_BUFFER *buf;
|
|
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
rv=GWEN_Directory_FindFileInPaths(sl, sFilename, buf);
|
|
GWEN_StringList_free(sl);
|
|
if (rv==0)
|
|
return buf;
|
|
GWEN_Buffer_free(buf);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
int AQH_ReadDataFromString(int dataType, const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
|
|
{
|
|
if (s && *s) {
|
|
switch(dataType) {
|
|
case AQH_ValueDataType_Int:
|
|
|
|
case AQH_ValueDataType_Uint8: return _readUint8DataFromString(s, pDataVal, pDataDenom);
|
|
case AQH_ValueDataType_Uint16: return _readUint16DataFromString(s, pDataVal, pDataDenom);
|
|
case AQH_ValueDataType_Uint32: return _readUint32DataFromString(s, pDataVal, pDataDenom);
|
|
case AQH_ValueDataType_Rational: break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
|
|
|
|
int _readUint8DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
|
|
{
|
|
unsigned int v=0;
|
|
|
|
if (1==sscanf(s, "%i", &v)) {
|
|
*pDataVal=v & 0xff;
|
|
*pDataDenom=1;
|
|
return 0;
|
|
}
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
|
|
|
|
int _readUint16DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
|
|
{
|
|
unsigned int v=0;
|
|
|
|
if (1==sscanf(s, "%i", &v)) {
|
|
*pDataVal=v & 0xffff;
|
|
*pDataDenom=1;
|
|
return 0;
|
|
}
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
|
|
|
|
int _readUint32DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
|
|
{
|
|
unsigned long int v=0;
|
|
|
|
if (1==sscanf(s, "%li", &v)) {
|
|
*pDataVal=(v>>16) & 0xffff;
|
|
*pDataDenom=v & 0xffff;
|
|
return 0;
|
|
}
|
|
return GWEN_ERROR_INVALID;
|
|
}
|
|
|
|
|
|
|
|
|