Projekt

Allgemein

Profil

Herunterladen (41,5 KB) Statistiken
| Zweig: | Markierung: | Revision:
/***************************************************************************
$RCSfile$
-------------------
cvs : $Id$
begin : Tue Sep 09 2003
copyright : (C) 2003 by Martin Preuss
email : martin@libchipcard.de

***************************************************************************
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
* MA 02111-1307 USA *
* *
***************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#define DISABLE_DEBUGLOG

#include "db_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/path.h>
#include <gwenhywfar/bufferedio.h>
#include <gwenhywfar/text.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


GWEN_DB_NODE *GWEN_DB_ValueBin_new(const void *data,
unsigned int datasize){
GWEN_DB_VALUE_BIN *v;

GWEN_NEW_OBJECT(GWEN_DB_VALUE_BIN, v);

v->h.h.typ=GWEN_DB_NODETYPE_VALUE;
v->h.typ=GWEN_DB_VALUETYPE_BIN;
if (datasize) {
assert(data);
v->dataSize=datasize;
v->data=(char*)malloc(datasize);
assert(v->data);
memmove(v->data, data, datasize);
}
return (GWEN_DB_NODE*)v;
}



GWEN_DB_NODE *GWEN_DB_ValueInt_new(int data) {
GWEN_DB_VALUE_INT *v;

GWEN_NEW_OBJECT(GWEN_DB_VALUE_INT, v);
v->h.h.typ=GWEN_DB_NODETYPE_VALUE;
v->h.typ=GWEN_DB_VALUETYPE_INT;
v->data=data;
return (GWEN_DB_NODE*)v;
}



GWEN_DB_NODE *GWEN_DB_ValueChar_new(const char *data) {
GWEN_DB_VALUE_CHAR *v;

GWEN_NEW_OBJECT(GWEN_DB_VALUE_CHAR, v);
v->h.h.typ=GWEN_DB_NODETYPE_VALUE;
v->h.typ=GWEN_DB_VALUETYPE_CHAR;
if (data)
v->data=strdup(data);
else
v->data=strdup("");
return (GWEN_DB_NODE*)v;
}



GWEN_DB_NODE *GWEN_DB_Group_new(const char *name){
GWEN_DB_GROUP *node;

assert(name);
GWEN_NEW_OBJECT(GWEN_DB_GROUP, node);
node->h.typ=GWEN_DB_NODETYPE_GROUP;
node->name=strdup(name);
return (GWEN_DB_NODE*)node;
}



GWEN_DB_NODE *GWEN_DB_Var_new(const char *name){
GWEN_DB_VAR *node;

assert(name);
GWEN_NEW_OBJECT(GWEN_DB_VAR, node);
node->h.typ=GWEN_DB_NODETYPE_VAR;
node->name=strdup(name);
return (GWEN_DB_NODE*)node;
}



void GWEN_DB_Node_Append(GWEN_DB_NODE *parent,
GWEN_DB_NODE *n){
GWEN_DB_NODE *curr;

assert(parent);
assert(n);

curr=parent->h.child;
if (!curr) {
parent->h.child=n;
}
else {
while(curr->h.next) {
curr=curr->h.next;
}
curr->h.next=n;
}
n->h.parent=parent;
}



void GWEN_DB_Node_Insert(GWEN_DB_NODE *parent,
GWEN_DB_NODE *n){
GWEN_DB_NODE *curr;

assert(parent);
assert(n);

curr=parent->h.child;
if (!curr) {
parent->h.child=n;
}
else {
n->h.next=parent->h.child;
parent->h.child=n;
}
n->h.parent=parent;
}



void GWEN_DB_Node_Unlink(GWEN_DB_NODE *n) {
GWEN_DB_NODE *curr;
GWEN_DB_NODE *parent;

assert(n);
parent=n->h.parent;
assert(parent);

curr=parent->h.child;
if (curr) {
if (curr==n) {
parent->h.child=curr->h.next;
}
else {
while(curr->h.next!=n) {
curr=curr->h.next;
}
if (curr)
curr->h.next=n->h.next;
}
}
n->h.next=0;
n->h.parent=0;
}



void GWEN_DB_Node_free(GWEN_DB_NODE *n){
if (n) {
GWEN_DB_NODE *cn;

/* free children */
cn=n->h.child;
while(cn) {
GWEN_DB_NODE *ncn;

ncn=cn->h.next;
DBG_VERBOUS(0, "Freeing child node");
GWEN_DB_Node_free(cn);
cn=ncn;
}

/* free dynamic (allocated) data */
switch(n->h.typ) {
case GWEN_DB_NODETYPE_GROUP:
DBG_VERBOUS(0, "Freeing dynamic data of group \"%s\"", n->group.name);
free(n->group.name);
break;

case GWEN_DB_NODETYPE_VAR:
DBG_VERBOUS(0, "Freeing dynamic data of var \"%s\"", n->var.name);
free(n->var.name);
break;

case GWEN_DB_NODETYPE_VALUE:
switch(n->val.h.typ) {
case GWEN_DB_VALUETYPE_CHAR:
DBG_VERBOUS(0, "Freeing dynamic data of char value");
free(n->val.c.data);
break;

case GWEN_DB_VALUETYPE_INT:
/* no dynamic data, nothing to do */
DBG_VERBOUS(0, "Freeing dynamic data of int value");
break;

case GWEN_DB_VALUETYPE_BIN:
DBG_VERBOUS(0, "Freeing dynamic data of bin value");
free(n->val.b.data);
break;

default:
DBG_WARN(0, "Unknown value type (%d)", n->val.h.typ);
}
break;

default:
DBG_WARN(0, "Unknown node type (%d)", n->h.typ);
}
DBG_VERBOUS(0, "Freeing node itself");
free(n);
}

}


GWEN_DB_NODE *GWEN_DB_Node_dup(const GWEN_DB_NODE *n){
GWEN_DB_NODE *nn;

switch(n->h.typ) {
case GWEN_DB_NODETYPE_GROUP:
DBG_VERBOUS(0, "Duplicating group \"%s\"", n->group.name);
nn=GWEN_DB_Group_new(n->group.name);
break;

case GWEN_DB_NODETYPE_VAR:
DBG_VERBOUS(0, "Duplicating variable \"%s\"", n->var.name);
nn=GWEN_DB_Var_new(n->var.name);
break;

case GWEN_DB_NODETYPE_VALUE:
switch(n->val.h.typ) {
case GWEN_DB_VALUETYPE_CHAR:
nn=GWEN_DB_ValueChar_new(n->val.c.data);
break;

case GWEN_DB_VALUETYPE_INT:
nn=GWEN_DB_ValueInt_new(n->val.i.data);
break;

case GWEN_DB_VALUETYPE_BIN:
nn=GWEN_DB_ValueBin_new(n->val.b.data,
n->val.b.dataSize);
break;

default:
DBG_WARN(0, "Unknown value type (%d)", n->val.h.typ);
nn=0;
}
break;

default:
DBG_WARN(0, "Unknown node type (%d)", n->h.typ);
nn=0;
}

/* duplicate all children and add them to the new node */
if (nn) {
const GWEN_DB_NODE *cn;

cn=n->h.child;
while(cn) {
GWEN_DB_NODE *ncn;

/* duplicate child and add it */
ncn=GWEN_DB_Node_dup(cn);
if (!ncn) {
GWEN_DB_Node_free(nn);
return 0;
}
GWEN_DB_Node_Append(nn, ncn);
cn=cn->h.next;
} /* while cn */
}

return nn;
}



void GWEN_DB_Group_free(GWEN_DB_NODE *n){
GWEN_DB_Node_free(n);
}



GWEN_DB_NODE *GWEN_DB_Group_dup(const GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Node is not a group");
return 0;
}
return GWEN_DB_Node_dup(n);
}



GWEN_DB_NODE *GWEN_DB_GetFirstGroup(GWEN_DB_NODE *n){
GWEN_DB_NODE *nn;

assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Node is not a group");
return 0;
}
nn=n->h.child;
while(nn) {
if (nn->h.typ==GWEN_DB_NODETYPE_GROUP)
break;
nn=nn->h.next;
} /* while node */
return nn;
}



GWEN_DB_NODE *GWEN_DB_GetNextGroup(GWEN_DB_NODE *n){
GWEN_DB_NODE *og;

og=n;
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Node is not a group");
return 0;
}
n=n->h.next;
while(n) {
if (n->h.typ==GWEN_DB_NODETYPE_GROUP)
break;
n=n->h.next;
} /* while node */
assert(n!=og);
return n;
}



GWEN_DB_NODE *GWEN_DB_GetFirstVar(GWEN_DB_NODE *n){
GWEN_DB_NODE *nn;

assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Node is not a group");
return 0;
}
nn=n->h.child;
while(nn) {
if (nn->h.typ==GWEN_DB_NODETYPE_VAR)
break;
nn=nn->h.next;
} /* while node */
return nn;
}



GWEN_DB_NODE *GWEN_DB_GetNextVar(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VAR) {
DBG_ERROR(0, "Node is not a variable");
return 0;
}
n=n->h.next;
while(n) {
if (n->h.typ==GWEN_DB_NODETYPE_VAR)
break;
n=n->h.next;
} /* while node */
return n;
}



GWEN_DB_NODE *GWEN_DB_GetFirstValue(GWEN_DB_NODE *n){
GWEN_DB_NODE *nn;

assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VAR) {
DBG_ERROR(0, "Node is not a variable");
return 0;
}
nn=n->h.child;
while(nn) {
if (nn->h.typ==GWEN_DB_NODETYPE_VALUE)
break;
nn=nn->h.next;
} /* while node */
return nn;
}



GWEN_DB_NODE *GWEN_DB_GetNextValue(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VALUE) {
DBG_ERROR(0, "Node is not a value");
return 0;
}
n=n->h.next;
while(n) {
if (n->h.typ==GWEN_DB_NODETYPE_VALUE)
break;
n=n->h.next;
} /* while node */
return n;
}



GWEN_DB_VALUETYPE GWEN_DB_GetValueType(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VALUE) {
DBG_ERROR(0, "Node is not a value");
return GWEN_DB_VALUETYPE_UNKNOWN;
}
return n->val.h.typ;
}



const char *GWEN_DB_GetCharValueFromNode(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VALUE) {
DBG_ERROR(0, "Node is not a value");
return 0;
}
if (n->val.h.typ!=GWEN_DB_VALUETYPE_CHAR) {
DBG_ERROR(0, "Node is not a char value");
return 0;
}
return n->val.c.data;
}



int GWEN_DB_GetIntValueFromNode(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VALUE) {
DBG_ERROR(0, "Node is not a value");
return 0;
}

if (n->val.h.typ==GWEN_DB_VALUETYPE_CHAR) {
/* try to convert the char value into an integer */
const char *p;
int res;

p=GWEN_DB_GetCharValueFromNode(n);
assert(p);
if (sscanf(p, "%d", &res)!=1) {
DBG_ERROR(0, "Node is not an int value");
return 0;
}
return res;
}
else if (n->val.h.typ!=GWEN_DB_VALUETYPE_INT) {
DBG_ERROR(0, "Node is not a char or int value");
return 0;
}
return n->val.i.data;
}



const void *GWEN_DB_GetBinValueFromNode(GWEN_DB_NODE *n,
unsigned int *size){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_VALUE) {
DBG_ERROR(0, "Node is not a value");
return 0;
}

if (n->val.h.typ!=GWEN_DB_VALUETYPE_BIN) {
DBG_ERROR(0, "Node is not a binary value");
return 0;
}

*size=n->val.b.dataSize;
return n->val.b.data;
}



GWEN_DB_NODE *GWEN_DB_FindGroup(GWEN_DB_NODE *n,
const char *name) {
GWEN_DB_NODE *nn;

assert(n);
assert(name);

/* find existing node */
nn=n->h.child;
while(nn) {
if (nn->h.typ==GWEN_DB_NODETYPE_GROUP) {
if (strcasecmp(nn->group.name, name)==0) {
/* ok, group found, return it */
return nn;
} /* if entry found */
}
nn=nn->h.next;
} /* while child */

return nn;
}



GWEN_DB_NODE *GWEN_DB_FindVar(GWEN_DB_NODE *n,
const char *name) {
GWEN_DB_NODE *nn;

assert(n);
assert(name);

/* find existing node */
nn=n->h.child;
while(nn) {
if (nn->h.typ==GWEN_DB_NODETYPE_VAR) {
if (strcasecmp(nn->var.name, name)==0) {
/* ok, group found, return it */
return nn;
} /* if entry found */
}
nn=nn->h.next;
} /* while child */

return nn;
}





void* GWEN_DB_HandlePath(const char *entry,
void *data,
unsigned int flags) {
GWEN_DB_NODE *n;
GWEN_DB_NODE *nn;

n=(GWEN_DB_NODE*)data;

/* check whether we are allowed to simply create the node */
if (
((flags & GWEN_PATH_FLAGS_LAST) &&
(((flags & GWEN_PATH_FLAGS_VARIABLE) &&
(flags & GWEN_PATH_FLAGS_CREATE_VAR)) ||
(!(flags & GWEN_PATH_FLAGS_VARIABLE) &&
(flags & GWEN_PATH_FLAGS_CREATE_GROUP)))
) ||
(
!(flags & GWEN_PATH_FLAGS_LAST) &&
(flags & GWEN_PATH_FLAGS_PATHCREATE))
) {
/* simply create the new variable/group */
if (flags & GWEN_PATH_FLAGS_VARIABLE) {
DBG_VERBOUS(0, "Unconditionally creating variable \"%s\"", entry);
nn=GWEN_DB_Var_new(entry);
GWEN_DB_Node_Append(n, nn);
return nn;
}
else {
DBG_VERBOUS(0, "Unconditionally creating group \"%s\"", entry);
nn=GWEN_DB_Group_new(entry);
GWEN_DB_Node_Append(n, nn);
return nn;
}
}

/* find the node */
if (flags & GWEN_PATH_FLAGS_VARIABLE) {
nn=GWEN_DB_FindVar(n, entry);
}
else {
nn=GWEN_DB_FindGroup(n, entry);
}

if (!nn) {
/* node not found, check, if we are allowed to create it */
if (
(!(flags & GWEN_PATH_FLAGS_LAST) &
(flags & GWEN_PATH_FLAGS_PATHMUSTEXIST)) ||
(flags & GWEN_PATH_FLAGS_NAMEMUSTEXIST)
) {
if (flags & GWEN_PATH_FLAGS_VARIABLE) {
DBG_VERBOUS(0, "Variable \"%s\" does not exist", entry);
}
else {
DBG_VERBOUS(0, "Group \"%s\" does not exist", entry);
}
return 0;
}
/* create the new variable/group */
if (flags & GWEN_PATH_FLAGS_VARIABLE) {
DBG_VERBOUS(0, "Variable \"%s\" not found, creating", entry);
nn=GWEN_DB_Var_new(entry);
GWEN_DB_Node_Append(n, nn);
}
else {
DBG_VERBOUS(0, "Group \"%s\" not found, creating", entry);
nn=GWEN_DB_Group_new(entry);
GWEN_DB_Node_Append(n, nn);
}
} /* if node not found */
else {
/* node does exist, check whether this is ok */
if (
((flags & GWEN_PATH_FLAGS_LAST) &
(flags & GWEN_PATH_FLAGS_NAMEMUSTNOTEXIST)) ||
(!(flags & GWEN_PATH_FLAGS_LAST) &
(flags & GWEN_PATH_FLAGS_PATHMUSTNOTEXIST))
) {
DBG_VERBOUS(0, "Entry \"%s\" already exists", entry);
return 0;
}
}

return nn;
}



GWEN_DB_NODE *GWEN_DB_GetNode(GWEN_DB_NODE *n,
const char *path,
unsigned int flags){
return (GWEN_DB_NODE*)GWEN_Path_Handle(path,
n,
flags,
GWEN_DB_HandlePath);
}



void GWEN_DB_ClearNode(GWEN_DB_NODE *n) {
GWEN_DB_NODE *nn;

assert(n);
while ((nn=n->h.child)) {
GWEN_DB_Node_Unlink(nn);
GWEN_DB_Node_free(nn);
} /* while */
}



GWEN_DB_NODE *GWEN_DB_GetValue(GWEN_DB_NODE *n,
const char *path,
int idx) {
GWEN_DB_NODE *nn;
int i;

/* find corresponding node */
nn=GWEN_DB_GetNode(n,
path,
GWEN_PATH_FLAGS_PATHMUSTEXIST |
GWEN_PATH_FLAGS_NAMEMUSTEXIST |
GWEN_PATH_FLAGS_VARIABLE);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not found",
path);
return 0;
}

/* find value */
nn=nn->h.child;
i=0;
while (nn) {
if (nn->h.typ==GWEN_DB_NODETYPE_VALUE) {
/* value found */
if (i==idx) {
return nn;
}
else
i++;
}
nn=nn->h.next;
} /* while */
DBG_VERBOUS(0, "No value[%d] for path \"%s\"",
idx, path);
return 0;
}



int GWEN_DB_DeleteVar(GWEN_DB_NODE *n,
const char *path) {
GWEN_DB_NODE *nn;

/* find corresponding node */
nn=GWEN_DB_GetNode(n,
path,
GWEN_PATH_FLAGS_PATHMUSTEXIST |
GWEN_PATH_FLAGS_NAMEMUSTEXIST |
GWEN_PATH_FLAGS_VARIABLE);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not found",
path);
return 1;
}
GWEN_DB_Node_Unlink(nn);
GWEN_DB_Node_free(nn);
return 0;
}



int GWEN_DB_DeleteGroup(GWEN_DB_NODE *n,
const char *path) {
GWEN_DB_NODE *nn;

/* find corresponding node */
nn=GWEN_DB_GetNode(n,
path,
GWEN_PATH_FLAGS_PATHMUSTEXIST |
GWEN_PATH_FLAGS_NAMEMUSTEXIST);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not found",
path);
return 1;
}
GWEN_DB_Node_Unlink(nn);
GWEN_DB_Node_free(nn);
return 0;
}



int GWEN_DB_ClearGroup(GWEN_DB_NODE *n,
const char *path){
assert(n);
if (path) {
GWEN_DB_NODE *nn;

/* find corresponding node */
nn=GWEN_DB_GetNode(n,
path,
GWEN_PATH_FLAGS_PATHMUSTEXIST |
GWEN_PATH_FLAGS_NAMEMUSTEXIST);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not found",
path);
return 1;
}
GWEN_DB_ClearNode(nn);
}
else {
GWEN_DB_ClearNode(n);
}
return 0;
}



const char *GWEN_DB_GetCharValue(GWEN_DB_NODE *n,
const char *path,
int idx,
const char *defVal){
GWEN_DB_NODE *nn;

nn=GWEN_DB_GetValue(n, path, idx);
if (!nn){
DBG_VERBOUS(0, "Value for \"%s\" not found, returning default value",
path);
return defVal;
}
if (nn->val.h.typ!=GWEN_DB_VALUETYPE_CHAR) {
/* bad type */
DBG_VERBOUS(0, "Bad type for path \"%s\", returning default value",
path);
return defVal;
}
return nn->val.c.data;
}



int GWEN_DB_SetCharValue(GWEN_DB_NODE *n,
unsigned int flags,
const char *path,
const char *val){
GWEN_DB_NODE *nn;
GWEN_DB_NODE *nv;

/* select/create node */
nn=GWEN_DB_GetNode(n,
path,
flags | GWEN_PATH_FLAGS_VARIABLE);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not available",
path);
return 1;
}

/* delete contents of this variable if wanted */
if (flags & GWEN_DB_FLAGS_OVERWRITE_VARS) {
DBG_VERBOUS(0, "Clearing variable \"%s\"", path);
GWEN_DB_ClearNode(nn);
}

nv=GWEN_DB_ValueChar_new(val);
GWEN_DB_Node_Append(nn, nv);
DBG_VERBOUS(0, "Added char value \"%s\" to variable \"%s\"", val, path);

return 0;
}



int GWEN_DB_GetIntValue(GWEN_DB_NODE *n,
const char *path,
int idx,
int defVal){
GWEN_DB_NODE *nn;

nn=GWEN_DB_GetValue(n, path, idx);
if (!nn){
DBG_VERBOUS(0, "Value[%d] for \"%s\" not found, returning default value",
idx, path);
return defVal;
}
if (nn->val.h.typ==GWEN_DB_VALUETYPE_CHAR) {
/* try to convert the char value into an integer */
const char *p;
int res;

DBG_VERBOUS(0, "Converting char value to int");
p=GWEN_DB_GetCharValueFromNode(nn);
assert(p);
if (sscanf(p, "%d", &res)!=1) {
DBG_ERROR(0, "Value[%d] of \"%s\" is not an int value",
idx, path);
return defVal;
}
return res;
}
else if (nn->val.h.typ!=GWEN_DB_VALUETYPE_INT) {
DBG_VERBOUS(0, "Value[%d] of \"%s\" is not an int or char value",
idx, path);
return defVal;
}
DBG_VERBOUS(0, "Returning value from node (\"%s\":%d)",
path, idx);
return nn->val.i.data;
}



int GWEN_DB_SetIntValue(GWEN_DB_NODE *n,
unsigned int flags,
const char *path,
int val){
GWEN_DB_NODE *nn;
GWEN_DB_NODE *nv;

/* select/create node */
nn=GWEN_DB_GetNode(n,
path,
flags | GWEN_PATH_FLAGS_VARIABLE);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not available",
path);
return 1;
}

/* delete contents of this variable if wanted */
if (flags & GWEN_DB_FLAGS_OVERWRITE_VARS) {
DBG_VERBOUS(0, "Clearing variable \"%s\"", path);
GWEN_DB_ClearNode(nn);
}

nv=GWEN_DB_ValueInt_new(val);
GWEN_DB_Node_Append(nn, nv);
DBG_VERBOUS(0, "Added int value \%d\" to variable \"%s\"", val, path);
return 0;
}



const void *GWEN_DB_GetBinValue(GWEN_DB_NODE *n,
const char *path,
int idx,
const void *defVal,
unsigned int defValSize,
unsigned int *returnValueSize){
GWEN_DB_NODE *nn;

assert(returnValueSize);
nn=GWEN_DB_GetValue(n, path, idx);
if (!nn){
DBG_VERBOUS(0, "Value for \"%s\" not found, returning default value",
path);
*returnValueSize=defValSize;
return defVal;
}
if (nn->val.h.typ!=GWEN_DB_VALUETYPE_BIN) {
/* bad type */
DBG_VERBOUS(0, "Bad type for path \"%s\", returning default value",
path);
*returnValueSize=defValSize;
return defVal;
}
*returnValueSize=nn->val.b.dataSize;
return nn->val.b.data;
}



int GWEN_DB_SetBinValue(GWEN_DB_NODE *n,
unsigned int flags,
const char *path,
const void *val,
unsigned int valSize){
GWEN_DB_NODE *nn;
GWEN_DB_NODE *nv;

assert(val);
/* select/create node */
nn=GWEN_DB_GetNode(n,
path,
flags | GWEN_PATH_FLAGS_VARIABLE);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not available",
path);
return 1;
}

/* delete contents of this variable if wanted */
if (flags & GWEN_DB_FLAGS_OVERWRITE_VARS) {
DBG_VERBOUS(0, "Clearing variable \"%s\"", path);
GWEN_DB_ClearNode(nn);
}

nv=GWEN_DB_ValueBin_new(val, valSize);
GWEN_DB_Node_Append(nn, nv);
DBG_VERBOUS(0, "Added bin value to variable \"%s\"", path);
return 0;
}



GWEN_DB_NODE *GWEN_DB_GetGroup(GWEN_DB_NODE *n,
unsigned int flags,
const char *path) {
GWEN_DB_NODE *nn;

/* select/create node */
nn=GWEN_DB_GetNode(n,
path,
flags & ~GWEN_PATH_FLAGS_VARIABLE);
if (!nn) {
DBG_VERBOUS(0, "Path \"%s\" not available",
path);
return 0;
}

/* delete contents of this variable if wanted */
if (flags & GWEN_DB_FLAGS_OVERWRITE_GROUPS) {
DBG_VERBOUS(0, "Clearing group \"%s\"", path);
GWEN_DB_ClearNode(nn);
}

return nn;
}



const char *GWEN_DB_GroupName(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Node is not a group");
return 0;
}
return n->group.name;
}



void GWEN_DB_Dump(GWEN_DB_NODE *n, FILE *f, int insert){
if (n) {
GWEN_DB_NODE *cn;
int i;

for (i=0; i<insert; i++)
fprintf(f, " ");

/* dump dynamic (allocated) data */
switch(n->h.typ) {
case GWEN_DB_NODETYPE_GROUP:
fprintf(f, "Group : \"%s\"\n", n->group.name);
break;

case GWEN_DB_NODETYPE_VAR:
fprintf(f, "Var : \"%s\"\n", n->var.name);
break;

case GWEN_DB_NODETYPE_VALUE:
switch(n->val.h.typ) {
case GWEN_DB_VALUETYPE_CHAR:
fprintf(f, "Value : \"%s\" (char)\n", n->val.c.data);
break;

case GWEN_DB_VALUETYPE_INT:
/* no dynamic data, nothing to do */
fprintf(f, "Value : %d (int)\n", n->val.i.data);
break;

case GWEN_DB_VALUETYPE_BIN:
fprintf(f, "Value : %d bytes (bin)\n", n->val.b.dataSize);
break;

default:
fprintf(f, "Value : [unknown type]\n");
}
break;

default:
fprintf(f, "[unknown node type %d]\n", n->h.typ);
}

/* dump children */
cn=n->h.child;
while(cn) {
GWEN_DB_Dump(cn, f, insert+4);
cn=cn->h.next;
}
}
else {
fprintf(f, "[no node]\n");
}
}



int GWEN_DB_ReadFromStream(GWEN_DB_NODE *n,
GWEN_BUFFEREDIO *bio,
unsigned int dbflags) {
GWEN_ERRORCODE err;
GWEN_DB_NODE *currGrp;
GWEN_DB_NODE *currVar;
char linebuf[GWEN_DB_LINE_MAXSIZE];
char wbuf[256];
char *p;
const char *pos;
int lineno;
GWEN_DB_VALUETYPE vt;
int depth;

currGrp=n;
currVar=0;
lineno=0;
depth=0;

while(!GWEN_BufferedIO_CheckEOF(bio)) {
int isVar;
int isVal;

isVar=0;
isVal=0;
vt=GWEN_DB_VALUETYPE_CHAR;
pos=linebuf;

/* read next line */
lineno++;
err=GWEN_BufferedIO_ReadLine(bio, linebuf, sizeof(linebuf)-1);
if (!GWEN_Error_IsOk(err)) {
DBG_ERROR(0, "Error in line %d", lineno);
return -1;
}

/* eventually stop if empty line */
if (!*pos && (dbflags&GWEN_DB_FLAGS_STOP_ON_EMPTY_LINE)) {
return 0;
}

/* skip blanks */
while(*pos && isspace(*pos))
pos++;

if (!*pos || *pos=='#') {
DBG_VERBOUS(0, "Line %d is empty", lineno);
}
else {
if (*pos=='}') {
/* end of current group */
if (depth<1) {
DBG_ERROR(0, "Extra \"}\" in line %d, pos %d",
lineno, pos-linebuf+1);
return -1;
}
assert(currGrp->h.parent);
currGrp=currGrp->h.parent;
currVar=0;
depth--;
*pos++;
while(*pos && isspace(*pos))
pos++;
}
else if (*pos=='#') {
/* comment only line */
DBG_VERBOUS(0, "Comment-only line");
}
else {
if (*pos==',') {
/* continuing a variable on the next line */
pos++;
isVal=1;
}

if (!isVal) {
/* get first word */
*wbuf=(char)0;
p=GWEN_Text_GetWord(pos,
(dbflags&GWEN_DB_FLAGS_USE_COLON)?
"}{: #,":"}{= #,",
wbuf,
sizeof(wbuf)-1,
GWEN_TEXT_FLAGS_DEL_LEADING_BLANKS |
GWEN_TEXT_FLAGS_DEL_TRAILING_BLANKS |
GWEN_TEXT_FLAGS_DEL_QUOTES |
GWEN_TEXT_FLAGS_CHECK_BACKSLASH,
&pos);
if (!p || !*wbuf) {
DBG_ERROR(0, "Error in line %d, pos %d",
lineno, pos-linebuf+1);
return -1;
}

/* skip blanks */
while(*pos && isspace(*pos))
pos++;

/* actually did read a word */
if (*pos=='{') {
/* found a group definition */
GWEN_DB_NODE *tmpn;

pos++;
DBG_VERBOUS(0, "Found group \"%s\"", wbuf);
tmpn=GWEN_DB_GetGroup(currGrp, dbflags, wbuf);
if (!tmpn) {
DBG_ERROR(0, "Error in line %d, pos %d (no group)",
lineno, pos-linebuf+1);
return -1;
}
currGrp=tmpn;
currVar=0;
depth++;
}
else if (*pos==((dbflags&GWEN_DB_FLAGS_USE_COLON)?':':'=')) {
/* found a variable */
DBG_VERBOUS(0, "Found a variable \"%s\", handle it later", wbuf);
isVar=1;
}
else {
/* found another word, so the previous word is a type specifier */
isVar=1;
DBG_VERBOUS(0, "Found a type specifier \"%s\"", wbuf);
if (strcasecmp(p, "int")==0)
vt=GWEN_DB_VALUETYPE_INT;
else if (strcasecmp(p, "bin")==0)
vt=GWEN_DB_VALUETYPE_BIN;
else if (strcasecmp(p, "char")==0)
vt=GWEN_DB_VALUETYPE_CHAR;
else {
DBG_WARN(0, "Unknown type \"%s\", assuming \"char\"", p);
vt=GWEN_DB_VALUETYPE_CHAR;
}
/* get the variable name */
wbuf[0]=(char)0;
p=GWEN_Text_GetWord(pos,
(dbflags&GWEN_DB_FLAGS_USE_COLON)?
"}{: #":"}{= #",
wbuf,
sizeof(wbuf)-1,
GWEN_TEXT_FLAGS_DEL_LEADING_BLANKS |
GWEN_TEXT_FLAGS_DEL_TRAILING_BLANKS |
GWEN_TEXT_FLAGS_DEL_QUOTES |
GWEN_TEXT_FLAGS_CHECK_BACKSLASH,
&pos);
if (!p || !*wbuf) {
DBG_ERROR(0, "Error in line %d, pos %d",
lineno, pos-linebuf+1);
return -1;
}
/* skip blanks */
while(*pos && isspace(*pos))
pos++;
if (*pos!=((dbflags&GWEN_DB_FLAGS_USE_COLON)?':':'=')) {
DBG_ERROR(0, "Expected \"=\" in line %d at %d",
lineno, pos-linebuf+1);
return -1;
}
isVar=1;
} /* if two words */
} /* if !isVal */

if (isVar) {
DBG_VERBOUS(0, "Creating variable \"%s\"", wbuf);
pos++;
currVar=GWEN_DB_GetNode(currGrp,
wbuf,
dbflags | GWEN_PATH_FLAGS_VARIABLE);
/* next word is a value */
isVal=1;
} /* isVar */

if (isVal) {
GWEN_DB_NODE *tmpn;
int value;

if (!currVar) {
DBG_ERROR(0, "Error in line %d, pos %d (no var)",
lineno, pos-linebuf+1);
return -1;
}

while (*pos) {
DBG_VERBOUS(0, "Reading value");
/* get next value */
p=GWEN_Text_GetWord(pos,
(dbflags&GWEN_DB_FLAGS_USE_COLON)?
"}{: #":"}{= #,",
wbuf,
sizeof(wbuf)-1,
GWEN_TEXT_FLAGS_DEL_LEADING_BLANKS |
GWEN_TEXT_FLAGS_DEL_TRAILING_BLANKS |
GWEN_TEXT_FLAGS_DEL_QUOTES |
GWEN_TEXT_FLAGS_CHECK_BACKSLASH,
&pos);
/* if (!p || !*wbuf) { */
if (!p) {
DBG_DEBUG(0, "Line %d, pos %d: no word",
lineno, pos-linebuf+1);
break;
}
if (!*wbuf) {
DBG_INFO(0, "Line %d, pos %d: no word",
lineno, pos-linebuf+1);
}
DBG_VERBOUS(0, "Creating value \"%s\"", wbuf);

/* set value */
switch(vt) {
case GWEN_DB_VALUETYPE_CHAR:
tmpn=GWEN_DB_ValueChar_new(wbuf);
break;
case GWEN_DB_VALUETYPE_INT:
if (sscanf(wbuf, "%d", &value)!=1) {
DBG_ERROR(0, "Error in line %d, pos %d (no integer)",
lineno, pos-linebuf+1);
return -1;
}
tmpn=GWEN_DB_ValueInt_new(value);
break;
case GWEN_DB_VALUETYPE_BIN: {
char binbuffer[128];
int binsize;

binsize=GWEN_Text_FromHex(wbuf, binbuffer, sizeof(binbuffer));
if (binsize<1) {
DBG_ERROR(0, "Error in line %d, pos %d (no binary)",
lineno, pos-linebuf+1);
return -1;
}
tmpn=GWEN_DB_ValueBin_new(binbuffer, binsize);
break;
}
default:
DBG_ERROR(0, "Error in line %d, pos %d (bad type)",
lineno, pos-linebuf+1);
return -1;
} /* switch */
GWEN_DB_Node_Append(currVar, tmpn);

/* skip blanks */
while(*pos && isspace(*pos))
pos++;

if (*pos!=',')
break;
pos++;
} /* while *pos */
} /* if isVal */

while(*pos && isspace(*pos))
pos++;
if (*pos) {
if (*pos=='}') {
if (depth<1) {
DBG_ERROR(0, "Extra \"}\" in line %d, pos %d",
lineno, pos-linebuf+1);
}
assert(currGrp->h.parent);
currGrp=currGrp->h.parent;
currVar=0;
depth--;
*pos++;
while(*pos && isspace(*pos))
pos++;
}
if (*pos && *pos!='#') {
DBG_ERROR(0, "Extra character in line %d, pos %d",
lineno, pos-linebuf+1);
return -1;
}
}
}
} /* if line is not empty */
} /* while */

if (depth) {
DBG_ERROR(0, "Unbalanced groups (missing %d \"}\" at end of file)",
depth);
return -1;
}
return 0;
}



int GWEN_DB_ReadFile(GWEN_DB_NODE *n,
const char *fname,
unsigned int dbflags) {
GWEN_BUFFEREDIO *bio;
GWEN_ERRORCODE err;
int fd;
int rv;

fd=open(fname, O_RDONLY);
if (fd==-1) {
DBG_ERROR(0, "Error opening file \"%s\": %s",
fname,
strerror(errno));
return -1;
}

bio=GWEN_BufferedIO_File_new(fd);
GWEN_BufferedIO_SetReadBuffer(bio, 0, 1024);
rv=GWEN_DB_ReadFromStream(n, bio, dbflags);
err=GWEN_BufferedIO_Close(bio);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
GWEN_BufferedIO_free(bio);
return -1;
}
GWEN_BufferedIO_free(bio);
return rv;
}



int GWEN_DB_AddGroup(GWEN_DB_NODE *n, GWEN_DB_NODE *nn){
assert(n);
assert(nn);

if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Target node is not a group");
return 0;
}

if (nn->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Sorce node is not a group");
return 0;
}

GWEN_DB_Node_Append(n, nn);
return 0;
}



int GWEN_DB_AddGroupChildren(GWEN_DB_NODE *n, GWEN_DB_NODE *nn){
GWEN_DB_NODE *cpn;

assert(n);
assert(nn);

if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Target node is not a group");
return -1;
}

if (nn->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Source node is not a group");
GWEN_DB_Dump(nn, stderr, 1);
return -1;
}

nn=nn->h.child;
while (nn) {
DBG_VERBOUS(0, "Duplicating node");
cpn=GWEN_DB_Node_dup(nn);
GWEN_DB_Node_Append(n, cpn);
nn=nn->h.next;
} /* while */
return 0;
}



void GWEN_DB_UnlinkGroup(GWEN_DB_NODE *n){
assert(n);
if (n->h.typ!=GWEN_DB_NODETYPE_GROUP) {
DBG_ERROR(0, "Node is not a group");
return;
}
GWEN_DB_Node_Unlink(n);
}



int GWEN_DB_WriteGroupToStream(GWEN_DB_NODE *node,
GWEN_BUFFEREDIO *bio,
unsigned int dbflags,
int insert) {
GWEN_DB_NODE *n;
GWEN_DB_NODE *cn;
int i;
GWEN_ERRORCODE err;

n=node->h.child;
while(n) {
DBG_VERBOUS(0, "Writing node");
switch(n->h.typ) {
case GWEN_DB_NODETYPE_GROUP:
if (dbflags & GWEN_DB_FLAGS_WRITE_SUBGROUPS) {
/* indend */
if (dbflags & GWEN_DB_FLAGS_INDEND) {
for (i=0; i<insert; i++) {
err=GWEN_BufferedIO_WriteChar(bio, ' ');
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
} /* for */
} /* if indend */
err=GWEN_BufferedIO_Write(bio, n->group.name);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
err=GWEN_BufferedIO_WriteLine(bio, " {");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
if (GWEN_DB_WriteGroupToStream(n, bio, dbflags, insert+2))
return 1;

/* indend */
if (dbflags & GWEN_DB_FLAGS_INDEND) {
for (i=0; i<insert; i++) {
err=GWEN_BufferedIO_WriteChar(bio, ' ');
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
} /* for */
} /* if indend */

if (dbflags & GWEN_DB_FLAGS_DETAILED_GROUPS) {
err=GWEN_BufferedIO_Write(bio, "} # ");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
err=GWEN_BufferedIO_WriteLine(bio, n->group.name);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
} /* if detailed groups */
else {
err=GWEN_BufferedIO_WriteLine(bio, "}");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
}
if (dbflags & GWEN_DB_FLAGS_ADD_GROUP_NEWLINES) {
err=GWEN_BufferedIO_WriteLine(bio, "");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
}
}
break;

case GWEN_DB_NODETYPE_VAR:
cn=n->h.child;
if (cn) {
char *typname;
int namewritten;
int values;

typname=0;
namewritten=0;
values=0;
while(cn) {
char numbuffer[32];
char *binbuffer;
unsigned int bbsize;
const char *pvalue;

pvalue=0;
binbuffer=0;
switch(cn->h.typ) {
case GWEN_DB_NODETYPE_VALUE:
switch(cn->val.h.typ) {
case GWEN_DB_VALUETYPE_CHAR:
typname="char ";
pvalue=cn->val.c.data;
break;

case GWEN_DB_VALUETYPE_INT:
typname="int ";
if (GWEN_Text_NumToString(cn->val.i.data,
numbuffer,
sizeof(numbuffer)-1,
0)<1) {
DBG_ERROR(0, "Error writing numeric value");
return 1;
}
pvalue=numbuffer;
break;

case GWEN_DB_VALUETYPE_BIN:
bbsize=cn->val.b.dataSize*2+1;
binbuffer=(char*)malloc(bbsize);
assert(binbuffer);
typname="bin ";
if (!GWEN_Text_ToHex(cn->val.b.data,
cn->val.b.dataSize,
binbuffer,
bbsize)) {
DBG_ERROR(0, "Error writing binary value");
return 1;
}
pvalue=binbuffer;
break;

default:
DBG_WARN(0, "Unknown value type (%d)\n", n->val.h.typ);
break;
} /* switch value type */

if (!namewritten) {
/* write name */
/* indend */
if (dbflags & GWEN_DB_FLAGS_INDEND) {
for (i=0; i<insert; i++) {
err=GWEN_BufferedIO_WriteChar(bio, ' ');
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
} /* for */
} /* if indend */
if (!(dbflags & GWEN_DB_FLAGS_OMIT_TYPES)) {
err=GWEN_BufferedIO_Write(bio, typname);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
}
if (dbflags & GWEN_DB_FLAGS_QUOTE_VARNAMES) {
err=GWEN_BufferedIO_Write(bio, "\"");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
}
err=GWEN_BufferedIO_Write(bio, n->var.name);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
if (dbflags & GWEN_DB_FLAGS_QUOTE_VARNAMES) {
err=GWEN_BufferedIO_Write(bio, "\"");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
}
err=GWEN_BufferedIO_Write(bio,
((dbflags&GWEN_DB_FLAGS_USE_COLON)?
":":"="));
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
namewritten=1;
} /* if !namewritten */

if (values) {
err=GWEN_BufferedIO_Write(bio, ", ");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
}
values++;
if (dbflags & GWEN_DB_FLAGS_QUOTE_VALUES) {
err=GWEN_BufferedIO_Write(bio, "\"");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
}
err=GWEN_BufferedIO_Write(bio, pvalue);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
if (dbflags & GWEN_DB_FLAGS_QUOTE_VALUES) {
err=GWEN_BufferedIO_Write(bio, "\"");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
free(binbuffer);
return 1;
}
}

break;
default:
break;
} /* switch */

free(binbuffer);
cn=cn->h.next;
} /* while cn */
err=GWEN_BufferedIO_WriteLine(bio, "");
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
return 1;
}
} /* if children */
break;

default:
DBG_WARN(0, "[unhandled node type %d]\n", n->h.typ);
}

n=n->h.next;
} /* while */
return 0;
}



int GWEN_DB_WriteToStream(GWEN_DB_NODE *node,
GWEN_BUFFEREDIO *bio,
unsigned int dbflags) {
return GWEN_DB_WriteGroupToStream(node, bio, dbflags, 0);
}



int GWEN_DB_WriteFile(GWEN_DB_NODE *n,
const char *fname,
unsigned int dbflags){
GWEN_BUFFEREDIO *bio;
GWEN_ERRORCODE err;
int fd;
int rv;

if (dbflags & GWEN_DB_FLAGS_APPEND_FILE)
fd=open(fname, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
else
fd=open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd==-1) {
DBG_ERROR(0, "Error opening file \"%s\": %s",
fname,
strerror(errno));
return -1;
}

bio=GWEN_BufferedIO_File_new(fd);
GWEN_BufferedIO_SetWriteBuffer(bio, 0, 1024);
rv=GWEN_DB_WriteToStream(n, bio, dbflags);
err=GWEN_BufferedIO_Close(bio);
if (!GWEN_Error_IsOk(err)) {
DBG_INFO(0, "called from here");
GWEN_BufferedIO_free(bio);
return -1;
}
GWEN_BufferedIO_free(bio);
return rv;
}



int GWEN_DB_VariableExists(GWEN_DB_NODE *n,
const char *path){
return (GWEN_DB_FindVar(n, path)!=0);
}



GWEN_DB_VALUETYPE GWEN_DB_GetVariableType(GWEN_DB_NODE *n,
const char *p){
GWEN_DB_NODE *nn;

nn=GWEN_DB_FindVar(n, p);
if (!nn)
return GWEN_DB_VALUETYPE_UNKNOWN;
nn=GWEN_DB_GetFirstValue(nn);
if (!nn)
return GWEN_DB_VALUETYPE_UNKNOWN;
return GWEN_DB_GetValueType(nn);
}



void GWEN_DB_GroupRename(GWEN_DB_NODE *n, const char *newname){
assert(n);
assert(newname);
assert(n->h.typ==GWEN_DB_NODETYPE_GROUP);
free(n->group.name);
n->group.name=strdup(newname);
}







(5-5/17)