#include "dthdr.h"
typedef struct _dtlist_s
{ Dtdata_t data;
Dtlink_t* link;
Dtlink_t* here;
} Dtlist_t;
#ifdef DEBUG
int dtlistprint(Dt_t* dt, Dtlink_t* here, char* (*objprintf)(Void_t*) )
{
int k;
char *obj, *endb, buf[1024];
Dtdisc_t *disc = dt->disc;
Dtlist_t *list = (Dtlist_t*)dt->data;
if(!here && !(here = list->link) )
return -1;
for(; here; here = here->_rght)
{ endb = buf;
*endb++ = '(';
obj = (*objprintf)(_DTOBJ(disc, here));
k = strlen(obj); memcpy(endb, obj, k); endb += k;
*endb++ = ')';
*endb++ = '\n';
write(2, buf, endb-buf);
}
return 0;
}
#endif
#if __STD_C
Void_t* lfirstlast(Dt_t* dt, int type)
#else
Void_t* lfirstlast(dt, type)
Dt_t* dt;
int type;
#endif
{
Dtlink_t *lnk;
Dtdisc_t *disc = dt->disc;
Dtlist_t *list = (Dtlist_t*)dt->data;
if((lnk = list->link) )
{ if(type&DT_LAST)
lnk = lnk->_left;
list->here = lnk;
}
return lnk ? _DTOBJ(disc,lnk) : NIL(Void_t*);
}
#if __STD_C
Void_t* lclear(Dt_t* dt)
#else
Void_t* lclear(dt)
Dt_t* dt;
#endif
{
Dtlink_t *lnk, *next;
Dtdisc_t *disc = dt->disc;
Dtlist_t *list = (Dtlist_t*)dt->data;
lnk = list->link;
list->link = list->here = NIL(Dtlink_t*);
list->data.size = 0;
if(disc->freef || disc->link < 0)
{ for(; lnk; lnk = next)
{ next = lnk->_rght;
_dtfree(dt, lnk, DT_DELETE);
}
}
return NIL(Void_t*);
}
#if __STD_C
Void_t* llist(Dt_t* dt, Dtlink_t* lnk, int type)
#else
Void_t* llist(dt, lnk, type)
Dt_t* dt;
Dtlink_t* lnk;
int type;
#endif
{
Dtlist_t *list = (Dtlist_t*)dt->data;
if(type&(DT_FLATTEN|DT_EXTRACT) )
{ if(lnk)
return NIL(Void_t*);
lnk = list->link;
if(type&DT_EXTRACT)
{ list->link = NIL(Dtlink_t*);
dt->data->size = 0;
}
}
else
{ if(list->link != NIL(Dtlink_t*))
return NIL(Void_t*);
list->link = lnk;
dt->data->size = 0;
for(; lnk; lnk = lnk->_rght)
dt->data->size += 1;
}
return (Void_t*)lnk;
}
#if __STD_C
static Void_t* liststat(Dt_t* dt, Dtstat_t* st)
#else
static Void_t* liststat(dt, st)
Dt_t* dt;
Dtstat_t* st;
#endif
{
if(st)
{ memset(st, 0, sizeof(Dtstat_t));
st->meth = dt->meth->type;
st->size = dt->data->size;
st->space = sizeof(Dtlist_t) + (dt->disc->link >= 0 ? 0 : dt->data->size*sizeof(Dthold_t));
}
return (Void_t*)dt->data->size;
}
#if __STD_C
static Void_t* dtlist(Dt_t* dt, Void_t* obj, int type)
#else
static Void_t* dtlist(dt, obj, type)
Dt_t* dt;
Void_t* obj;
int type;
#endif
{
Dtlink_t *r, *t, *h;
Void_t *key, *o, *k;
Dtdisc_t *disc = dt->disc;
Dtlist_t *list = (Dtlist_t*)dt->data;
type = DTTYPE(dt,type);
if(!(type&DT_OPERATIONS) )
return NIL(Void_t*);
DTSETLOCK(dt);
if(type&(DT_FIRST|DT_LAST) )
DTRETURN(obj, lfirstlast(dt, type));
else if(type&(DT_EXTRACT|DT_RESTORE|DT_FLATTEN) )
DTRETURN(obj, llist(dt, (Dtlink_t*)obj, type));
else if(type&DT_CLEAR)
DTRETURN(obj, lclear(dt));
else if(type&DT_STAT )
DTRETURN(obj, liststat(dt, (Dtstat_t*)obj));
h = list->here;
list->here = NIL(Dtlink_t*);
if(!obj)
{ if((type&(DT_DELETE|DT_DETACH|DT_REMOVE)) && (dt->meth->type&(DT_STACK|DT_QUEUE)) )
if((r = list->link) )
goto dt_delete;
DTRETURN(obj, NIL(Void_t*));
}
if(type&DT_RELINK)
{ r = (Dtlink_t*)obj;
goto do_insert;
}
else if(type&(DT_INSERT|DT_APPEND|DT_ATTACH))
{ if(!(r = _dtmake(dt, obj, type)) )
DTRETURN(obj, NIL(Void_t*));
dt->data->size += 1;
do_insert:
if(dt->meth->type&DT_DEQUE)
{ if(type&DT_APPEND)
goto dt_queue;
else goto dt_stack;
}
else if(dt->meth->type&DT_LIST)
{ if(type&DT_APPEND)
{ if(!h || !h->_rght)
goto dt_queue;
r->_rght = h->_rght;
r->_rght->_left = r;
r->_left = h;
r->_left->_rght = r;
}
else
{ if(!h || h == list->link )
goto dt_stack;
r->_left = h->_left;
r->_left->_rght = r;
r->_rght = h;
r->_rght->_left = r;
}
}
else if(dt->meth->type&DT_STACK)
{ dt_stack:
r->_rght = t = list->link;
if(t)
{ r->_left = t->_left;
t->_left = r;
}
else r->_left = r;
list->link = r;
}
else
{ dt_queue:
if((t = list->link) )
{ t->_left->_rght = r;
r->_left = t->_left;
t->_left = r;
}
else
{ list->link = r;
r->_left = r;
}
r->_rght = NIL(Dtlink_t*);
}
list->here = r;
DTRETURN(obj, _DTOBJ(disc,r));
}
if(type&DT_MATCH)
{ key = obj;
obj = NIL(Void_t*);
}
else key = _DTKEY(disc, obj);
if(h && _DTOBJ(disc,h) == obj && (type & (DT_SEARCH|DT_NEXT|DT_PREV)) )
r = h;
else
{ h = NIL(Dtlink_t*);
for(r = list->link; r; r = r->_rght)
{ o = _DTOBJ(disc,r); k = _DTKEY(disc,o);
if(_DTCMP(dt, key, k, disc) != 0)
continue;
else if(type & (DT_REMOVE|DT_NEXT|DT_PREV) )
{ if(o == obj)
break;
else if(type&DT_NEXT)
h = r;
else if(type&DT_PREV)
h = h ? h : r;
else continue;
}
else if(type & DT_ATLEAST )
h = r;
else break;
}
r = h ? h : r;
}
if(!r)
DTRETURN(obj, NIL(Void_t*));
if(type&(DT_DELETE|DT_DETACH|DT_REMOVE))
{ dt_delete:
if(r->_rght)
r->_rght->_left = r->_left;
if(r == (t = list->link) )
{ list->link = r->_rght;
if((h = list->link) )
h->_left = t->_left;
}
else
{ r->_left->_rght = r->_rght;
if(r == t->_left)
t->_left = r->_left;
}
list->here = r == list->here ? r->_rght : NIL(Dtlink_t*);
obj = _DTOBJ(disc,r);
_dtfree(dt, r, type);
dt->data->size -= 1;
DTRETURN(obj, obj);
}
if(type&DT_NEXT)
r = r->_rght;
else if(type&DT_PREV)
r = r == list->link ? NIL(Dtlink_t*) : r->_left;
list->here = r;
if(r)
DTRETURN(obj, _DTOBJ(disc,r));
else DTRETURN(obj, NIL(Void_t*));
dt_return:
DTANNOUNCE(dt,obj,type);
DTCLRLOCK(dt);
return obj;
}
#if __STD_C
static int listevent(Dt_t* dt, int event, Void_t* arg)
#else
static int listevent(dt, event, arg)
Dt_t* dt;
int event;
Void_t* arg;
#endif
{
Dtlist_t *list = (Dtlist_t*)dt->data;
if(event == DT_OPEN)
{ if(list)
return 0;
if(!(list = (Dtlist_t*)(*dt->memoryf)(dt, 0, sizeof(Dtlist_t), dt->disc)) )
{ DTERROR(dt, "Error in allocating a list data structure");
return -1;
}
memset(list, 0, sizeof(Dtlist_t));
dt->data = (Dtdata_t*)list;
return 1;
}
else if(event == DT_CLOSE)
{ if(!list)
return 0;
if(list->link)
(void)lclear(dt);
(void)(*dt->memoryf)(dt, (Void_t*)list, 0, dt->disc);
dt->data = NIL(Dtdata_t*);
return 0;
}
else return 0;
}
static Dtmethod_t _Dtlist = { dtlist, DT_LIST, listevent, "Dtlist" };
static Dtmethod_t _Dtdeque = { dtlist, DT_DEQUE, listevent, "Dtdeque" };
static Dtmethod_t _Dtstack = { dtlist, DT_STACK, listevent, "Dtstack" };
static Dtmethod_t _Dtqueue = { dtlist, DT_QUEUE, listevent, "Dtqueue" };
__DEFINE__(Dtmethod_t*,Dtlist,&_Dtlist);
__DEFINE__(Dtmethod_t*,Dtdeque,&_Dtdeque);
__DEFINE__(Dtmethod_t*,Dtstack,&_Dtstack);
__DEFINE__(Dtmethod_t*,Dtqueue,&_Dtqueue);
#ifdef NoF
NoF(dtlist)
#endif