[PD-cvs] externals/grill/pool/source data.cpp,NONE,1.1 main.cpp,NONE,1.1 pool.cpp,NONE,1.1 pool.h,NONE,1.1

xovo at users.sourceforge.net xovo at users.sourceforge.net
Thu Jan 8 04:38:38 CET 2004


Update of /cvsroot/pure-data/externals/grill/pool/source
In directory sc8-pr-cvs1:/tmp/cvs-serv31723/source

Added Files:
	data.cpp main.cpp pool.cpp pool.h 
Log Message:
 ""

--- NEW FILE: data.cpp ---
/* 

pool - hierarchical storage object for PD and Max/MSP

Copyright (c) 2002-2003 Thomas Grill (xovo at gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

#include "pool.h"

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <fstream>

using namespace std;

pooldata::pooldata(const S *s,I vcnt,I dcnt):
	sym(s),nxt(NULL),refs(0),
	root(nullatom,NULL,vcnt,dcnt)
{
	FLEXT_LOG1("new pool %s",sym?flext_base::GetString(sym):"<private>");
}

pooldata::~pooldata()
{
	FLEXT_LOG1("free pool %s",sym?flext_base::GetString(sym):"<private>");
}


const A pooldata::nullatom = { A_NULL };


V pooldata::Reset()
{
	root.Reset();
}

BL pooldata::MkDir(const AtomList &d,I vcnt,I dcnt)
{
	root.AddDir(d,vcnt,dcnt);
	return true;
}

BL pooldata::ChkDir(const AtomList &d)
{
	return root.GetDir(d) != NULL;
}

BL pooldata::RmDir(const AtomList &d)
{
	return root.DelDir(d);
}

BL pooldata::Set(const AtomList &d,const A &key,AtomList *data,BL over)
{
	pooldir *pd = root.GetDir(d);
	if(!pd) return false;
	pd->SetVal(key,data,over);
	return true;
}

BL pooldata::Clr(const AtomList &d,const A &key)
{
	pooldir *pd = root.GetDir(d);
	if(!pd) return false;
	pd->ClrVal(key);
	return true;
}

BL pooldata::ClrAll(const AtomList &d,BL rec,BL dironly)
{
	pooldir *pd = root.GetDir(d);
	if(!pd) return false;
	pd->Clear(rec,dironly);
	return true;
}

flext::AtomList *pooldata::Peek(const AtomList &d,const A &key)
{
	pooldir *pd = root.GetDir(d);
	return pd?pd->PeekVal(key):NULL;
}

poolval *pooldata::Ref(const AtomList &d,const A &key)
{
	pooldir *pd = root.GetDir(d);
	return pd?pd->RefVal(key):NULL;
}

poolval *pooldata::Refi(const AtomList &d,I ix)
{
	pooldir *pd = root.GetDir(d);
	return pd?pd->RefVali(ix):NULL;
}

flext::AtomList *pooldata::Get(const AtomList &d,const A &key)
{
	pooldir *pd = root.GetDir(d);
	return pd?pd->GetVal(key):NULL;
}

I pooldata::CntAll(const AtomList &d)
{
	pooldir *pd = root.GetDir(d);
	return pd?pd->CntAll():0;
}

I pooldata::GetAll(const AtomList &d,A *&keys,AtomList *&lst)
{
	pooldir *pd = root.GetDir(d);
	if(pd)
		return pd->GetAll(keys,lst);
	else {
		keys = NULL; lst = NULL;
		return 0;
	}
}

I pooldata::PrintAll(const AtomList &d)
{
    char tmp[1024];
    d.Print(tmp,sizeof tmp);
    pooldir *pd = root.GetDir(d);
    strcat(tmp," , ");
	return pd?pd->PrintAll(tmp,sizeof tmp):0;
}

I pooldata::CntSub(const AtomList &d)
{
	pooldir *pd = root.GetDir(d);
	return pd?pd->CntSub():0;
}

I pooldata::GetSub(const AtomList &d,const t_atom **&dirs)
{
	pooldir *pd = root.GetDir(d);
	if(pd)
		return pd->GetSub(dirs);
	else {
		dirs = NULL;
		return 0;
	}
}


BL pooldata::Paste(const AtomList &d,const pooldir *clip,I depth,BL repl,BL mkdir)
{
	pooldir *pd = root.GetDir(d);
	if(pd)
		return pd->Paste(clip,depth,repl,mkdir);
	else
		return false;
}

pooldir *pooldata::Copy(const AtomList &d,const A &key,BL cut)
{
	pooldir *pd = root.GetDir(d);
	if(pd) {
		AtomList *val = pd->GetVal(key,cut);
		if(val) {
			pooldir *ret = new pooldir(nullatom,NULL,pd->VSize(),pd->DSize());
			ret->SetVal(key,val);
			return ret;
		}
		else
			return NULL;
	}
	else
		return NULL;
}

pooldir *pooldata::CopyAll(const AtomList &d,I depth,BL cut)
{
	pooldir *pd = root.GetDir(d);
	if(pd) {
		// What sizes should we choose here?
		pooldir *ret = new pooldir(nullatom,NULL,pd->VSize(),pd->DSize());
		if(pd->Copy(ret,depth,cut))
			return ret;
		else {
			delete ret;
			return NULL;
		}
	}
	else
		return NULL;
}


static const C *CnvFlnm(C *dst,const C *src,I sz)
{
#if FLEXT_SYS == FLEXT_SYS_PD && FLEXT_OS == FLEXT_OS_WIN
	I i,cnt = strlen(src);
	if(cnt >= sz-1) return NULL;
	for(i = 0; i < cnt; ++i)
		dst[i] = src[i] != '/'?src[i]:'\\';
	dst[i] = 0;
	return dst;
#else
	return src;
#endif
}

BL pooldata::LdDir(const AtomList &d,const C *flnm,I depth,BL mkdir)
{
	pooldir *pd = root.GetDir(d);
	if(pd) {
		C tmp[1024];
		const C *t = CnvFlnm(tmp,flnm,sizeof tmp);
		if(t) {
			ifstream fl(t);
			return fl.good() && pd->LdDir(fl,depth,mkdir);
		}
		else return false;
	}
	else
		return false;
}

BL pooldata::SvDir(const AtomList &d,const C *flnm,I depth,BL absdir)
{
	pooldir *pd = root.GetDir(d);
	if(pd) {
		C tmp[1024];
		const C *t = CnvFlnm(tmp,flnm,sizeof tmp);
		if(t) {
			ofstream fl(t);
			AtomList tmp;
			if(absdir) tmp = d;
			return fl.good() && pd->SvDir(fl,depth,tmp);
		}
		else return false;
	}
	else
		return false;
}

BL pooldata::LdDirXML(const AtomList &d,const C *flnm,I depth,BL mkdir)
{
	pooldir *pd = root.GetDir(d);
	if(pd) {
		C tmp[1024];
		const C *t = CnvFlnm(tmp,flnm,sizeof tmp);
		if(t) {
			ifstream fl(t);
            BL ret = fl.good() != 0;
            if(ret) {
                fl.getline(tmp,sizeof tmp);
                ret = !strncmp(tmp,"<?xml",5);
            }
/*
            if(ret) {
                fl.getline(tmp,sizeof tmp);
                // DOCTYPE need not be present / only external DOCTYPE is allowed!
                ret = !strncmp(tmp,"<!DOCTYPE",9);
            }
*/
            if(ret)
                ret = pd->LdDirXML(fl,depth,mkdir);
            return ret;
		}
	}

    return false;
}

BL pooldata::SvDirXML(const AtomList &d,const C *flnm,I depth,BL absdir)
{
	pooldir *pd = root.GetDir(d);
	if(pd) {
		C tmp[1024];
		const C *t = CnvFlnm(tmp,flnm,sizeof tmp);
		if(t) {
			ofstream fl(t);
			AtomList tmp;
			if(absdir) tmp = d;
            if(fl.good()) {
                fl << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" << endl;
                fl << "<!DOCTYPE pool SYSTEM \"http://www.parasitaere-kapazitaeten.net/ext/pool/pool-0.2.dtd\">" << endl;
                fl << "<pool>" << endl;
                BL ret = pd->SvDirXML(fl,depth,tmp);
                fl << "</pool>" << endl;
                return ret;
            }
		}
	}

    return false;
}



--- NEW FILE: main.cpp ---
/* 

pool - hierarchical storage object for PD and Max/MSP

Copyright (c) 2002-2003 Thomas Grill (xovo at gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

#include "pool.h"
#include <string>

#define POOL_VERSION "0.2.0pre"

#define VCNT 64
#define DCNT 16

class pool:
[...1113 lines suppressed...]
    // / and \ must not be mixed!
    // (char *) type casts for BorlandC++
	C *sl = strchr((C *)fn,'/');
	if(!sl) sl = strchr((C *)fn,'\\');
    if(!sl || (sl != fn 
#if FLEXT_OS == FLEXT_OS_WIN
        && sl[-1] != ':' // look for drive specification with ":/" or ":\\"
#endif
    )) {
        // prepend absolute canvas path if filename has no absolute path
		const C *p = GetString(canvas_getdir(thisCanvas()));
		return string(p)+'/'+fn;
	}
	else
		return fn;
#else
#pragma message("Relative file paths not implemented")
	return fn;
#endif
}

--- NEW FILE: pool.cpp ---
/* 

pool - hierarchical storage object for PD and Max/MSP

Copyright (c) 2002-2003 Thomas Grill (xovo at gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

#include "pool.h"

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <fstream>

using namespace std;

#define VBITS 6
#define DBITS 5

inline I compare(I a,I b) { return a == b?0:(a < b?-1:1); }
inline I compare(F a,F b) { return a == b?0:(a < b?-1:1); }

static I compare(const S *a,const S *b) 
{
	if(a == b)
		return 0;
	else
		return strcmp(flext::GetString(a),flext::GetString(b));
}

static I compare(const A &a,const A &b) 
{
	if(flext::GetType(a) == flext::GetType(b)) {
		switch(flext::GetType(a)) {
		case A_FLOAT:
			return compare(flext::GetFloat(a),flext::GetFloat(b));
#if FLEXT_SYS == FLEXT_SYS_MAX
		case A_LONG:
			return compare(flext::GetInt(a),flext::GetInt(b));
#endif
		case A_SYMBOL:
			return compare(flext::GetSymbol(a),flext::GetSymbol(b));
#if FLEXT_SYS == FLEXT_SYS_PD
		case A_POINTER:
			return flext::GetPointer(a) == flext::GetPointer(b)?0:(flext::GetPointer(a) < flext::GetPointer(b)?-1:1);
#endif
		default:
			FLEXT_LOG("pool - atom comparison: type not handled");
			return -1;
		}
	}
	else
		return flext::GetType(a) < flext::GetType(b)?-1:1;
}


poolval::poolval(const A &k,AtomList *d):
	data(d),nxt(NULL)
{
	SetAtom(key,k);
}

poolval::~poolval()
{
	if(data) delete data;
	if(nxt) delete nxt;
}

poolval &poolval::Set(AtomList *d)
{
	if(data) delete data;
	data = d;
	return *this;
}

poolval *poolval::Dup() const
{
	return new poolval(key,data?new AtomList(*data):NULL); 
}


pooldir::pooldir(const A &d,pooldir *p,I vcnt,I dcnt):
	parent(p),nxt(NULL),vals(NULL),dirs(NULL),
	vbits(vcnt?Int2Bits(vcnt):VBITS),dbits(dcnt?Int2Bits(dcnt):DBITS),
	vsize(1<<vbits),dsize(1<<dbits)
{
	Reset();
	CopyAtom(&dir,&d);
}

pooldir::~pooldir()
{
	Reset(false);
		
	if(nxt) delete nxt;
}

V pooldir::Clear(BL rec,BL dironly)
{
	if(rec && dirs) { 
		for(I i = 0; i < dsize; ++i) if(dirs[i].d) { delete dirs[i].d; dirs[i].d = NULL; }
	}
	if(!dironly && vals) { 
		for(I i = 0; i < vsize; ++i) if(vals[i].v) { delete vals[i].v; vals[i].v = NULL; }
	}
}

V pooldir::Reset(BL realloc)
{
	Clear(true,false);

	if(dirs) delete[] dirs; 
	if(vals) delete[] vals;

	if(realloc) {
		dirs = new direntry[dsize];
		ZeroMem(dirs,dsize*sizeof *dirs);
		vals = new valentry[vsize];
		ZeroMem(vals,vsize*sizeof *vals);
	}
	else 
		dirs = NULL,vals = NULL;
}

pooldir *pooldir::AddDir(I argc,const A *argv,I vcnt,I dcnt)
{
	if(!argc) return this;

	I c = 1,dix = DIdx(argv[0]);
	pooldir *prv = NULL,*ix = dirs[dix].d;
	for(; ix; prv = ix,ix = ix->nxt) {
		c = compare(argv[0],ix->dir);
		if(c <= 0) break;
	}

	if(c || !ix) {
		pooldir *nd = new pooldir(argv[0],this,vcnt,dcnt);
		nd->nxt = ix;

		if(prv) prv->nxt = nd;
		else dirs[dix].d = nd;
		dirs[dix].cnt++;
		ix = nd;
	}

	return ix->AddDir(argc-1,argv+1);
}

pooldir *pooldir::GetDir(I argc,const A *argv,BL rmv)
{
	if(!argc) return this;

	I c = 1,dix = DIdx(argv[0]);
	pooldir *prv = NULL,*ix = dirs[dix].d;
	for(; ix; prv = ix,ix = ix->nxt) {
		c = compare(argv[0],ix->dir);
		if(c <= 0) break;
	}

	if(c || !ix) 
		return NULL;
	else {
		if(argc > 1)
			return ix->GetDir(argc-1,argv+1,rmv);
		else if(rmv) {
			pooldir *nd = ix->nxt;
			if(prv) prv->nxt = nd;
			else dirs[dix].d = nd;
			dirs[dix].cnt--;
			ix->nxt = NULL;
			return ix;
		}
		else 
			return ix;
	}
}

BL pooldir::DelDir(I argc,const A *argv)
{
	pooldir *pd = GetDir(argc,argv,true);
	if(pd && pd != this) {
		delete pd;
		return true;
	}
	else 
		return false;
}

V pooldir::SetVal(const A &key,AtomList *data,BL over)
{
	I c = 1,vix = VIdx(key);
	poolval *prv = NULL,*ix = vals[vix].v;
	for(; ix; prv = ix,ix = ix->nxt) {
		c = compare(key,ix->key);
		if(c <= 0) break;
	}

	if(c || !ix) {
		// no existing data found
	
		if(data) {
			poolval *nv = new poolval(key,data);
			nv->nxt = ix;

			if(prv) prv->nxt = nv;
			else vals[vix].v = nv;
			vals[vix].cnt++;
		}
	}
	else if(over) { 
		// data exists... only set if overwriting enabled
		
		if(data)
			ix->Set(data);
		else {
			// delete key
		
			poolval *nv = ix->nxt;
			if(prv) prv->nxt = nv;
			else vals[vix].v = nv;
			vals[vix].cnt--;
			ix->nxt = NULL;
			delete ix;
		}
	}
}

poolval *pooldir::RefVal(const A &key)
{
	I c = 1,vix = VIdx(key);
	poolval *ix = vals[vix].v;
	for(; ix; ix = ix->nxt) {
		c = compare(key,ix->key);
		if(c <= 0) break;
	}

	return c || !ix?NULL:ix;
}


poolval *pooldir::RefVali(I rix)
{
	for(I vix = 0; vix < vsize; ++vix) 
		if(rix > vals[vix].cnt) rix -= vals[vix].cnt;
		else {
			poolval *ix = vals[vix].v;
			for(; ix && rix; ix = ix->nxt) --rix;
			if(ix && !rix) return ix;
		}
	return NULL;
}

flext::AtomList *pooldir::PeekVal(const A &key)
{
	poolval *ix = RefVal(key);
	return ix?ix->data:NULL;
}

flext::AtomList *pooldir::GetVal(const A &key,BL cut)
{
	I c = 1,vix = VIdx(key);
	poolval *prv = NULL,*ix = vals[vix].v;
	for(; ix; prv = ix,ix = ix->nxt) {
		c = compare(key,ix->key);
		if(c <= 0) break;
	}

	if(c || !ix) 
		return NULL;
	else {
		AtomList *ret;
		if(cut) {
			poolval *nv = ix->nxt;
			if(prv) prv->nxt = nv;
			else vals[vix].v = nv;
			vals[vix].cnt--;
			ix->nxt = NULL;
			ret = ix->data; ix->data = NULL;
			delete ix;
		}
		else
			ret = new AtomList(*ix->data);
		return ret;
	}
}

I pooldir::CntAll() const
{
	I cnt = 0;
	for(I vix = 0; vix < vsize; ++vix) cnt += vals[vix].cnt;
	return cnt;
}

I pooldir::PrintAll(char *buf,int len) const
{
    int offs = strlen(buf);

    I cnt = 0;
    for(I vix = 0; vix < vsize; ++vix) {
		poolval *ix = vals[vix].v;
        for(I i = 0; ix; ++i,ix = ix->nxt) {
			PrintAtom(ix->key,buf+offs,len-offs);
            strcat(buf+offs," , ");
            int l = strlen(buf+offs)+offs;
			ix->data->Print(buf+l,len-l);
            post(buf);
        }
        cnt += vals[vix].cnt;
    }
    
    buf[offs] = 0;

	return cnt;
}

I pooldir::GetKeys(AtomList &keys)
{
	I cnt = CntAll();
	keys(cnt);

	for(I vix = 0; vix < vsize; ++vix) {
		poolval *ix = vals[vix].v;
		for(I i = 0; ix; ++i,ix = ix->nxt) 
			SetAtom(keys[i],ix->key);
	}
	return cnt;
}

I pooldir::GetAll(A *&keys,AtomList *&lst,BL cut)
{
	I cnt = CntAll();
	keys = new A[cnt];
	lst = new AtomList[cnt];

	for(I i = 0,vix = 0; vix < vsize; ++vix) {
		poolval *ix = vals[vix].v;
		for(; ix; ++i) {
			SetAtom(keys[i],ix->key);
			lst[i] = *ix->data;

			if(cut) {
				poolval *t = ix;
				vals[vix].v = ix = ix->nxt;
				vals[vix].cnt--;				
				t->nxt = NULL; delete t;
			}
			else
				ix = ix->nxt;
		}
	}
	return cnt;
}


I pooldir::CntSub() const
{
	I cnt = 0;
	for(I dix = 0; dix < dsize; ++dix) cnt += dirs[dix].cnt;
	return cnt;
}


I pooldir::GetSub(const A **&lst)
{
	const I cnt = CntSub();
	lst = new const A *[cnt];
	for(I i = 0,dix = 0; dix < dsize; ++dix) {
		pooldir *ix = dirs[dix].d;
		for(; ix; ix = ix->nxt) lst[i++] = &ix->dir;
	}
	return cnt;
}


BL pooldir::Paste(const pooldir *p,I depth,BL repl,BL mkdir)
{
	BL ok = true;

	for(I vi = 0; vi < p->vsize; ++vi) {
		for(poolval *ix = p->vals[vi].v; ix; ix = ix->nxt) {
			SetVal(ix->key,new AtomList(*ix->data),repl);
		}
	}

	if(ok && depth) {
		for(I di = 0; di < p->dsize; ++di) {
			for(pooldir *dix = p->dirs[di].d; ok && dix; dix = dix->nxt) {
				pooldir *ndir = mkdir?AddDir(1,&dix->dir):GetDir(1,&dix->dir);
				if(ndir) { 
					ok = ndir->Paste(dix,depth > 0?depth-1:depth,repl,mkdir);
				}
			}
		}
	}

	return ok;
}

BL pooldir::Copy(pooldir *p,I depth,BL cut)
{
	BL ok = true;

	if(cut) {
		for(I vi = 0; vi < vsize; ++vi) {
			for(poolval *ix = vals[vi].v; ix; ix = ix->nxt)
				p->SetVal(ix->key,ix->data);
			vals[vi].cnt = 0;
			vals[vi].v = NULL;
		}
	}
	else {
		for(I vi = 0; vi < vsize; ++vi) {
			for(poolval *ix = vals[vi].v; ix; ix = ix->nxt) {
				p->SetVal(ix->key,new AtomList(*ix->data));
			}
		}
	}

	if(ok && depth) {
		for(I di = 0; di < dsize; ++di) {
			for(pooldir *dix = dirs[di].d; ok && dix; dix = dix->nxt) {
				pooldir *ndir = p->AddDir(1,&dix->dir);
				if(ndir)
					ok = dix->Copy(ndir,depth > 0?depth-1:depth,cut);
				else
					ok = false;
			}
		}
	}

	return ok;
}


static C *ReadAtom(C *c,A *a)
{
	// skip whitespace
	while(*c && isspace(*c)) ++c;
	if(!*c) return NULL;

	const C *m = c; // remember position

	// check for word type (s = 0,1,2 ... int,float,symbol)
	I s = 0;
	for(; *c && !isspace(*c); ++c) {
		if(!isdigit(*c))
            if(!s && (*c == '-' || *c == '+')) {} // minus or plus is ok
            else
			    s = (*c != '.' || s == 1)?2:1;
	}

	if(a) {
		switch(s) {
		case 0: // integer
#if FLEXT_SYS == FLEXT_SYS_MAX
			flext::SetInt(*a,atoi(m));
			break;
#endif
		case 1: // float
			flext::SetFloat(*a,(F)atof(m));
			break;
		default: { // anything else is a symbol
			C t = *c; *c = 0;
			flext::SetString(*a,m);
			*c = t;
			break;
		}
		}
	}

	return c;
}

static BL ParseAtoms(C *tmp,flext::AtomList &l)
{
	I i,cnt;
	C *t = tmp;
	for(cnt = 0; ; ++cnt) {
		t = ReadAtom(t,NULL);
		if(!t) break;
	}

	l(cnt);
	if(cnt) {
		for(i = 0,t = tmp; i < cnt; ++i)
			t = ReadAtom(t,&l[i]);
	}
	return true;
}

static BL ParseAtoms(string &s,flext::AtomList &l) 
{ 
    return ParseAtoms((C *)s.c_str(),l); 
}

static BL ReadAtoms(istream &is,flext::AtomList &l,C del)
{
	C tmp[1024];
	is.getline(tmp,sizeof tmp,del); 
	if(is.eof() || !is.good()) 
        return false;
    else
        return ParseAtoms(tmp,l);
}

static V WriteAtom(ostream &os,const A &a)
{
	switch(a.a_type) {
	case A_FLOAT:
		os << a.a_w.w_float;
		break;
#if FLEXT_SYS == FLEXT_SYS_MAX
	case A_LONG:
		os << a.a_w.w_long;
		break;
#endif
	case A_SYMBOL:
		os << flext::GetString(flext::GetSymbol(a));
		break;
	}
}

static V WriteAtoms(ostream &os,const flext::AtomList &l)
{
	for(I i = 0; i < l.Count(); ++i) {
//        if(IsSymbol(l[i]) os << "\"";
		WriteAtom(os,l[i]);
//        if(IsSymbol(l[i]) os << "\"";
		if(i < l.Count()-1) os << ' ';
	}
}

BL pooldir::LdDir(istream &is,I depth,BL mkdir)
{
	for(I i = 1; !is.eof(); ++i) {
		AtomList d,k,*v = new AtomList;
		BL r = 
            ReadAtoms(is,d,',') && 
            ReadAtoms(is,k,',') && k.Count() == 1 && 
            ReadAtoms(is,*v,'\n');

		if(r) {
			if(depth < 0 || d.Count() <= depth) {
				pooldir *nd = mkdir?AddDir(d):GetDir(d);
				if(nd) {
					nd->SetVal(k[0],v); v = NULL;
				}
	#ifdef FLEXT_DEBUG
				else
					post("pool - directory was not found",i);
	#endif
			}
		}
		else if(!is.eof())
			post("pool - format mismatch encountered, skipped line %i",i);

		if(v) delete v;
	}
	return true;
}

BL pooldir::SvDir(ostream &os,I depth,const AtomList &dir)
{
	for(I vi = 0; vi < vsize; ++vi) {
		for(poolval *ix = vals[vi].v; ix; ix = ix->nxt) {
			WriteAtoms(os,dir);
			os << " , ";
			WriteAtom(os,ix->key);
			os << " , ";
			WriteAtoms(os,*ix->data);
			os << endl;
		}
	}
	if(depth) {
		I nd = depth > 0?depth-1:-1;
		for(I di = 0; di < dsize; ++di) {
			for(pooldir *ix = dirs[di].d; ix; ix = ix->nxt) {
				ix->SvDir(os,nd,AtomList(dir).Append(ix->dir));
			}
		}
	}
	return true;
}

class xmltag {
public:
    string tag,attr;
    bool Ok() const { return tag.length() > 0; }
    bool operator ==(const C *t) const { return !tag.compare(t); }
    void Clear() { tag.clear(); attr.clear(); }
    enum { t_start,t_end,t_empty } type;
};

static bool gettag(istream &is,xmltag &tag)
{
    static const char *commstt = "<!--",*commend = "-->";

    for(;;) {
        // eat whitespace
        while(isspace(is.peek())) is.get();

        // no tag begin -> break
        if(is.peek() != '<') break;
        is.get(); // swallow <

        char tmp[1024],*t = tmp;

        // parse for comment start
        const char *c = commstt;
        while(*++c) {
            if(*c != is.peek()) break;
            *(t++) = is.get();
        }

        if(!*c) { // is comment
            char cmp[2] = {0,0}; // set to some unusual initial value

            for(int ic = 0; ; ic = (++ic)%2) {
                char c = is.get();
                if(c == '>') {
                    // if third character is > then check also the former two
                    int i;
                    for(i = 0; i < 2 && cmp[(ic+i)%2] == commend[i]; ++i);
                    if(i == 2) break; // match: comment end found!
                }
                else
                    cmp[ic] = c;
            }
        }
        else {
            // parse until > with consideration of "s
            bool intx = false;
            for(;;) {
                *t = is.get();
                if(*t == '"') intx = !intx;
                else if(*t == '>' && !intx) {
                    *t = 0;
                    break;
                }
                t++;
            }

            // look for tag slashes

            char *tb = tmp,*te = t-1,*tf;

            for(; isspace(*tb); ++tb);
            if(*tb == '/') { 
                // slash at the beginning -> end tag
                tag.type = xmltag::t_end;
                for(++tb; isspace(*tb); ++tb);
            }
            else {
                for(; isspace(*te); --te);
                if(*te == '/') { 
                    // slash at the end -> empty tag
                    for(--te; isspace(*te); --te);
                    tag.type = xmltag::t_empty;
                }
                else 
                    // no slash -> begin tag
                    tag.type = xmltag::t_start;
            }

            // copy tag text without slashes
            for(tf = tb; tf <= te && *tf && !isspace(*tf); ++tf);
            tag.tag.assign(tb,tf-tb);
            while(isspace(*tf)) ++tf;
            tag.attr.assign(tf,te-tf+1);

            return true;
        }
    }

    tag.Clear();
    return false;
}

static void getvalue(istream &is,string &s)
{
    char tmp[1024],*t = tmp; 
    bool intx = false;
    for(;;) {
        char c = is.peek();
        if(c == '"') intx = !intx;
        else if(c == '<' && !intx) break;
        *(t++) = is.get();
    }
    *t = 0;
    s = tmp;
}

BL pooldir::LdDirXML(istream &is,I depth,BL mkdir)
{
    AtomList d,k,v;
    bool inpool = false,inval = false,inkey = false,indata = false;
    const t_symbol *empty = MakeSymbol("");

	while(!is.eof()) {
        xmltag tag;
        gettag(is,tag);
        if(!tag.Ok()) {
            // look for value
            string s;
            getvalue(is,s);

            if(s.length() && inpool && 
                (
                    (!inval && inkey && d.Count()) ||  /* dir */
                    (inval && (inkey || indata)) /* value */
                )
            ) {
                BL ret = true;
                if(indata) {
                    if(v.Count())
                        post("pool - XML load: value data already given, ignoring new data");
                    else
                        ret = ParseAtoms(s,v);
                }
                else // inkey
                    if(inval) {
                        if(k.Count())
                            post("pool - XML load, value key already given, ignoring new key");
                        else
                            ret = ParseAtoms(s,k);
                    }
                    else {
                        t_atom &dkey = d[d.Count()-1];
                        const char *ds = GetString(dkey);
                        FLEXT_ASSERT(ds);
                        if(*ds) 
                            post("pool - XML load: dir key already given, ignoring new key");
                        else
                            SetString(dkey,s.c_str());
                        ret = true;
                    }
                if(!ret) post("pool - error interpreting XML value (%s)",s.c_str());
            }
            else
                post("pool - error reading XML data");
        }
        else if(tag == "pool") {
            if(tag.type == xmltag::t_end) break;
            else inpool = true;
        }
        else if(inpool) {
            if(tag == "dir") {
                if(tag.type == xmltag::t_start) {
                    // warn if last directory key was not given
                    if(d.Count() && GetSymbol(d[d.Count()-1]) == empty)
                        post("pool - XML load: dir key must be given prior to subdirs, ignoring items");

                    // initialize dir key as empty
                    t_atom at; SetSymbol(at,empty);
                    d.Append(at);
                }
                else if(tag.type == xmltag::t_end) {
                    if(d.Count())
                        d.Part(0,d.Count()-1);
                    else
                        post("pool - XML load: superfluous </dir> in XML data");
                }
            }
            else if(tag == "value") {
                if(tag.type == xmltag::t_start) {
                    inval = true;
                    k.Clear(); v.Clear();
                }
                else if(tag.type == xmltag::t_end) {
        			if(depth < 0 || d.Count() <= depth) {
                        // NOW set value

                        int fnd;
                        for(fnd = d.Count()-1; fnd >= 0; --fnd)
                            if(GetSymbol(d[fnd]) == empty) break;

                        // look if last dir key has been given
                        if(fnd >= 0) {
                            if(fnd == d.Count()-1)
                                post("pool - XML load: dir key must be given prior to values");

                            // else: one directoy level has been left unintialized, ignore items
                        }
                        else {
                            // only use first word of key
                            if(k.Count() == 1) {
		        		        pooldir *nd = mkdir?AddDir(d):GetDir(d);
        				        if(nd) 
                                    nd->SetVal(k[0],new AtomList(v));
                                else
                                    post("pool - XML load: value key must be exactly one word, value not stored");
				            }
                        }
                    }
                    inval = false;
                }
            }
            else if(tag == "key") {
                if(tag.type == xmltag::t_start) {
                    inkey = true;
                }
                else if(tag.type == xmltag::t_end) {
                    inkey = false;
                }
            }
            else if(tag == "data") {
                if(!inval) 
                    post("pool - XML tag <data> not within <value>");

                if(tag.type == xmltag::t_start) {
                    indata = true;
                }
                else if(tag.type == xmltag::t_end) {
                    indata = false;
                }
            }
#ifdef FLEXT_DEBUG
            else {
                post("pool - unknown XML tag '%s'",tag.tag.c_str());
            }
#endif
        }
        else if(tag == "!DOCTYPE") {
            // ignore
        }
#ifdef FLEXT_DEBUG
        else {
            post("pool - unknown XML tag '%s'",tag.tag.c_str());
        }
#endif
    }
    return true;
}

static void indent(ostream &s,I cnt) 
{
    for(I i = 0; i < cnt; ++i) s << '\t';
}

BL pooldir::SvDirXML(ostream &os,I depth,const AtomList &dir,I ind)
{
    if(dir.Count()) {
        indent(os,ind);
        os << "<dir>" << endl;
        indent(os,ind+1);
        os << "<key>";
        WriteAtom(os,dir[dir.Count()-1]);
        os << "</key>" << endl;
    }

	for(I vi = 0; vi < vsize; ++vi) {
		for(poolval *ix = vals[vi].v; ix; ix = ix->nxt) {
            indent(os,ind+1);
            os << "<value><key>";
			WriteAtom(os,ix->key);
            os << "</key><data>";
			WriteAtoms(os,*ix->data);
			os << "</data></value>" << endl;
		}
	}

	if(depth) {
		I nd = depth > 0?depth-1:-1;
		for(I di = 0; di < dsize; ++di) {
			for(pooldir *ix = dirs[di].d; ix; ix = ix->nxt) {
				ix->SvDirXML(os,nd,AtomList(dir).Append(ix->dir),ind+1);
			}
		}
	}

    if(dir.Count()) {
        indent(os,ind);
        os << "</dir>" << endl;
    }
	return true;
}





--- NEW FILE: pool.h ---
/* 

pool - hierarchical storage object for PD and Max/MSP

Copyright (c) 2002-2003 Thomas Grill (xovo at gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

#ifndef __POOL_H
#define __POOL_H

#define FLEXT_ATTRIBUTES 1

#include <flext.h>

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 402)
#error You need at least flext version 0.4.2
#endif

#include <iostream>

using namespace std;

typedef void V;
typedef int I;
typedef unsigned long UL;
typedef float F;
typedef char C;
typedef bool BL;
typedef t_atom A;
typedef t_symbol S;

class poolval:
	public flext
{
public:
	poolval(const A &key,AtomList *data);
	~poolval();

	poolval &Set(AtomList *data);
	poolval *Dup() const;

	A key;
	AtomList *data;
	poolval *nxt;
};

class pooldir:
	public flext
{
public:
	pooldir(const A &dir,pooldir *parent,I vcnt = 0,I dcnt = 0);
	~pooldir();

	V Clear(BL rec,BL dironly = false);
	V Reset(BL realloc = true);

	BL Empty() const { return !dirs && !vals; }
	BL HasDirs() const { return dirs != NULL; }
	BL HasVals() const { return vals != NULL; }

	pooldir *GetDir(I argc,const A *argv,BL cut = false);
	pooldir *GetDir(const AtomList &d,BL cut = false) { return GetDir(d.Count(),d.Atoms(),cut); }
	BL DelDir(I argc,const A *argv);
	BL DelDir(const AtomList &d) { return DelDir(d.Count(),d.Atoms()); }
	pooldir *AddDir(I argc,const A *argv,I vcnt = 0,I dcnt = 0);
	pooldir *AddDir(const AtomList &d,I vcnt = 0,I dcnt = 0) { return AddDir(d.Count(),d.Atoms(),vcnt,dcnt); }

	V SetVal(const A &key,AtomList *data,BL over = true);
	V ClrVal(const A &key) { SetVal(key,NULL); }
	AtomList *PeekVal(const A &key);
	AtomList *GetVal(const A &key,BL cut = false);
	I CntAll() const;
	I GetAll(A *&keys,AtomList *&lst,BL cut = false);
	I PrintAll(char *buf,int len) const;
	I GetKeys(AtomList &keys);
	I CntSub() const;
	I GetSub(const A **&dirs);

	poolval *RefVal(const A &key);
	poolval *RefVali(I ix);
	
	BL Paste(const pooldir *p,I depth,BL repl,BL mkdir);
	BL Copy(pooldir *p,I depth,BL cur);

	BL LdDir(istream &is,I depth,BL mkdir);
	BL LdDirXML(istream &is,I depth,BL mkdir);
	BL SvDir(ostream &os,I depth,const AtomList &dir = AtomList());
	BL SvDirXML(ostream &os,I depth,const AtomList &dir = AtomList(),I ind = 0);

	int VSize() const { return vsize; }
	int DSize() const { return dsize; }

protected:
	int VIdx(const A &v) const { return FoldBits(AtomHash(v),vbits); }
	int DIdx(const A &d) const { return FoldBits(AtomHash(d),dbits); }

	A dir;
	pooldir *nxt;

	pooldir *parent;
	const I vbits,dbits,vsize,dsize;
	
	struct valentry { int cnt; poolval *v; };
	struct direntry { int cnt; pooldir *d; };
	
	valentry *vals;
	direntry *dirs;
};

class pooldata:
	public flext
{
public:
	pooldata(const S *s = NULL,I vcnt = 0,I dcnt = 0);
	~pooldata();

	V Push() { ++refs; }
	BL Pop() { return --refs > 0; }

	V Reset();
	BL MkDir(const AtomList &d,I vcnt = 0,I dcnt = 0); 
	BL ChkDir(const AtomList &d);
	BL RmDir(const AtomList &d);

	BL Set(const AtomList &d,const A &key,AtomList *data,BL over = true);
	BL Clr(const AtomList &d,const A &key);
	BL ClrAll(const AtomList &d,BL rec,BL dironly = false);
	AtomList *Peek(const AtomList &d,const A &key);
	AtomList *Get(const AtomList &d,const A &key);
	poolval *Ref(const AtomList &d,const A &key);
	poolval *Refi(const AtomList &d,I ix);
	I CntAll(const AtomList &d);
	I PrintAll(const AtomList &d);
	I GetAll(const AtomList &d,A *&keys,AtomList *&lst);
	I CntSub(const AtomList &d);
	I GetSub(const AtomList &d,const t_atom **&dirs);

	BL Paste(const AtomList &d,const pooldir *clip,I depth = -1,BL repl = true,BL mkdir = true);
	pooldir *Copy(const AtomList &d,const A &key,BL cut);
	pooldir *CopyAll(const AtomList &d,I depth,BL cut);

	BL LdDir(const AtomList &d,const C *flnm,I depth,BL mkdir = true);
	BL SvDir(const AtomList &d,const C *flnm,I depth,BL absdir);
	BL Load(const C *flnm) { return LdDir(AtomList(),flnm,-1); }
	BL Save(const C *flnm) { return SvDir(AtomList(),flnm,-1,true); }
	BL LdDirXML(const AtomList &d,const C *flnm,I depth,BL mkdir = true);
	BL SvDirXML(const AtomList &d,const C *flnm,I depth,BL absdir);
	BL LoadXML(const C *flnm) { return LdDirXML(AtomList(),flnm,-1); }
	BL SaveXML(const C *flnm) { return SvDirXML(AtomList(),flnm,-1,true); }

	I refs;
	const S *sym;
	pooldata *nxt;

	pooldir root;

private:
	static const A nullatom;
};

#endif






More information about the Pd-cvs mailing list