Files
aqhomecontrol/aqhome/data/path.c
2024-05-18 13:10:41 +02:00

216 lines
5.1 KiB
C

/****************************************************************************
* 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 <config.h>
#endif
#include "./path.h"
#include <gwenhywfar/stringlist.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void *_handleElement(const char *element, void *data, uint32_t flags, AQH_PATH_HANDLERFN fn);
static void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void *AQH_Path_Handle(const char *path, void *data, uint32_t flags, const char *delimiters, AQH_PATH_HANDLERFN fn)
{
if (path && *path) {
GWEN_STRINGLIST *elementList;
/* clear internal flags */
flags&=~AQH_PATH_FLAGS_LAST;
elementList=GWEN_StringList_fromString2(path, delimiters, 0, GWEN_TEXT_FLAGS_CHECK_BACKSLASH | GWEN_TEXT_FLAGS_DEL_QUOTES);
if (elementList) {
GWEN_STRINGLISTENTRY *se;
se=GWEN_StringList_FirstEntry(elementList);
while(se) {
const char *s;
GWEN_STRINGLISTENTRY *seNext;
seNext=GWEN_StringListEntry_Next(se);
if (seNext)
flags&=~AQH_PATH_FLAGS_LAST;
else
flags|=AQH_PATH_FLAGS_LAST;
s=GWEN_StringListEntry_Data(se);
if (s && *s) {
void *result;
result=_handleElement(s, data, flags, fn);
if (result==NULL) {
DBG_INFO(NULL, "Error handling element \"%s\" (%08x)", s, flags);
GWEN_StringList_free(elementList);
return NULL;
}
data=result;
}
se=GWEN_StringListEntry_Next(se);
}
GWEN_StringList_free(elementList);
return data;
}
else {
DBG_INFO(NULL, "Error reading path \"%s\" into stringlist", path);
}
}
else {
DBG_ERROR(NULL, "Empty path given");
}
return NULL;
}
void *_handleElement(const char *element, void *data, uint32_t flags, AQH_PATH_HANDLERFN fn)
{
if (flags & AQH_PATH_FLAGS_PARSEIDX) {
const char *ptrOpenBracket;
ptrOpenBracket=strchr(element, '[');
if (ptrOpenBracket) {
if (ptrOpenBracket!=element) {
const char *s;
int idx=0;
s=ptrOpenBracket+1;
while(*s && isdigit(*s)) {
idx*=10;
idx+=*s-'0';
s++;
}
if (*s!=']') {
DBG_ERROR(NULL, "Closed bracket expected (got \"%c\")", *s);
return NULL;
}
else {
char *rawElement;
void *result;
s++;
rawElement=GWEN_Text_strndup(element, ptrOpenBracket-element);
result=fn?fn(rawElement, data, idx, flags):data;
free(rawElement);
return result;
}
}
else {
DBG_ERROR(NULL, "Empty element with index");
return NULL;
}
}
}
return fn(element, data, 0, flags);
}
int AQH_Path_GetPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
{
if (!(path1 && *path1)) {
if (path2 && *path2) {
GWEN_Buffer_AppendString(diffBuf, path2);
return 0;
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Both paths are NULL.");
return 0;
}
}
if (!(path2 && *path2)) {
GWEN_STRINGLIST *sl1;
sl1=GWEN_StringList_fromString2(path1, "/", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
if (sl1) {
int cnt;
int i;
cnt=GWEN_StringList_Count(sl1);
for (i=0; i<cnt; i++) {
if (i>0)
GWEN_Buffer_AppendString(diffBuf, "/");
GWEN_Buffer_AppendString(diffBuf, "..");
}
GWEN_StringList_free(sl1);
return 0;
}
}
_getPathBetween(path1, path2, diffBuf);
return 0;
}
void _getPathBetween(const char *path1, const char *path2, GWEN_BUFFER *diffBuf)
{
GWEN_STRINGLIST *sl1;
GWEN_STRINGLIST *sl2;
GWEN_STRINGLISTENTRY *se;
int count;
int i;
sl2=GWEN_StringList_fromString2(path2, "/", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
sl1=GWEN_StringList_fromString2(path1, "/", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
GWEN_StringList_RemoveCommonFirstEntries(sl1, sl2);
count=GWEN_StringList_Count(sl1);
for (i=0; i<count; i++) {
if (GWEN_Buffer_GetUsedBytes(diffBuf))
GWEN_Buffer_AppendString(diffBuf, "/");
GWEN_Buffer_AppendString(diffBuf, "..");
}
GWEN_StringList_free(sl1);
se=GWEN_StringList_FirstEntry(sl2);
while(se) {
const char *s;
s=GWEN_StringListEntry_Data(se);
if (s && *s) {
if (GWEN_Buffer_GetUsedBytes(diffBuf))
GWEN_Buffer_AppendString(diffBuf, "/");
GWEN_Buffer_AppendString(diffBuf, s);
}
se=GWEN_StringListEntry_Next(se);
}
GWEN_StringList_free(sl2);
}
#include "./path-t.c"