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@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@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@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@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