aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/pool/source/pool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'externals/grill/pool/source/pool.cpp')
-rw-r--r--externals/grill/pool/source/pool.cpp1216
1 files changed, 0 insertions, 1216 deletions
diff --git a/externals/grill/pool/source/pool.cpp b/externals/grill/pool/source/pool.cpp
deleted file mode 100644
index 23e8517f..00000000
--- a/externals/grill/pool/source/pool.cpp
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
-pool - hierarchical storage object for PD and Max/MSP
-
-Copyright (c) 2002-2008 Thomas Grill (gr@grrrr.org)
-For information on usage and redistribution, and for a DISCLAIMER OF ALL
-WARRANTIES, see the file, "license.txt," in this distribution.
-
-$LastChangedRevision: 26 $
-$LastChangedDate: 2008-01-03 16:14:29 +0100 (Thu, 03 Jan 2008) $
-$LastChangedBy: thomas $
-*/
-
-#include "pool.h"
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <fstream>
-#include <vector>
-
-#if FLEXT_OS == FLEXT_OS_WIN
-#include <windows.h> // for charset conversion functions
-#elif FLEXT_OS == FLEXT_OS_MAC
-#include <Carbon/Carbon.h>
-#else
-static bool WCStoUTF8(char *sdst,const wchar_t *src,int dstlen)
-{
- unsigned char *dst = (unsigned char *)sdst;
- unsigned char *max = dst+dstlen;
- for(;;) {
- wchar_t ud = *(src++);
- if(ud < 128) {
- if(dst+1 >= max) return false;
- *(dst++) = (unsigned char)ud;
- }
- else if(ud < 2048) {
- if(dst+2 >= max) return false;
- *(dst++) = 192+(unsigned char)(ud/64);
- *(dst++) = 128+(unsigned char)(ud%64);
- }
- else if(ud < 65535) {
- if(dst+3 >= max) return false;
- *(dst++) = 224+(unsigned char)(ud/4096);
- *(dst++) = 128+(unsigned char)((ud/64)%64);
- *(dst++) = 128+(unsigned char)(ud%64);
- }
- else if(ud < 2097151) {
- if(dst+4 >= max) return false;
- *(dst++) = 240+(unsigned char)(ud/262144);
- *(dst++) = 128+(unsigned char)((ud/4096)%64);
- *(dst++) = 128+(unsigned char)((ud/64)%64);
- *(dst++) = 128+(unsigned char)(ud%64);
- }
- else if(ud < 67108863) {
- if(dst+5 >= max) return false;
- *(dst++) = 248+(unsigned char)(ud/16777216);
- *(dst++) = 128+(unsigned char)((ud/262144)%64);
- *(dst++) = 128+(unsigned char)((ud/4096)%64);
- *(dst++) = 128+(unsigned char)((ud/64)%64);
- *(dst++) = 128+(unsigned char)(ud%64);
- }
- else {
- if(dst+6 >= max) return false;
- *(dst++) = 252+(unsigned char)(ud/1073741824);
- *(dst++) = 128+(unsigned char)((ud/16777216)%64);
- *(dst++) = 128+(unsigned char)((ud/262144)%64);
- *(dst++) = 128+(unsigned char)((ud/4096)%64);
- *(dst++) = 128+(unsigned char)((ud/64)%64);
- *(dst++) = 128+(unsigned char)(ud%64);
- }
- if(!ud) break;
- }
- return true;
-}
-
-static bool UTF8toWCS(wchar_t *dst,const char *ssrc,int dstlen)
-{
- const unsigned char *src = (const unsigned char *)ssrc;
- wchar_t *max = dst+dstlen;
- for(;;) {
- if(*src < 128) {
- *dst = *(src++);
- if(!*dst) break;
- }
- else if(*src < 224) {
- *dst = wchar_t(src[0]-192)*64+wchar_t(src[1]-128);
- src += 2;
- }
- else if(*src < 240) {
- *dst = wchar_t(src[0]-224)*4096+wchar_t(src[1]-128)*64+wchar_t(src[2]-128);
- src += 3;
- }
- else if(*src < 248) {
- *dst = wchar_t(src[0]-240)*262144+wchar_t(src[1]-128)*4096+wchar_t(src[2]-128)*64+wchar_t(src[3]-128);
- src += 4;
- }
- else if(*src < 252) {
- *dst = wchar_t(src[0]-248)*16777216+wchar_t(src[1]-128)*262144+wchar_t(src[2]-128)*4096+wchar_t(src[3]-128)*64+wchar_t(src[4]-128);
- src += 5;
- }
- else if(*src < 254) {
- *dst = wchar_t(src[0]-252)*1073741824+wchar_t(src[1]-128)*16777216+wchar_t(src[2]-128)*262144+wchar_t(src[3]-128)*4096+wchar_t(src[4]-128)*64+wchar_t(src[5]-128);
- src += 6;
- }
- else
- // invalid string
- return false;
-
- if(++dst >= max) return false;
- }
- return true;
-}
-
-#endif
-
-using namespace std;
-
-
-
-inline int compare(int a,int b) { return a == b?0:(a < b?-1:1); }
-inline int compare(float a,float b) { return a == b?0:(a < b?-1:1); }
-
-static int compare(const t_symbol *a,const t_symbol *b)
-{
- if(a == b)
- return 0;
- else
- return strcmp(flext::GetString(a),flext::GetString(b));
-}
-
-static int compare(const t_atom &a,const t_atom &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 t_atom &k,AtomList *d):
- data(d),nxt(NULL)
-{
- SetAtom(key,k);
-}
-
-poolval::~poolval()
-{
- if(data) delete data;
-
- FLEXT_ASSERT(nxt == NULL);
-}
-
-poolval &poolval::Set(AtomList *d)
-{
- if(data) delete data;
- data = d;
- return *this;
-}
-
-poolval *poolval::Dup() const
-{
- return new poolval(key,data?new Atoms(*data):NULL);
-}
-
-
-pooldir::pooldir(const t_atom &d,pooldir *p,int vcnt,int dcnt):
- parent(p),nxt(NULL),vals(NULL),dirs(NULL),
- vbits(Int2Bits(vcnt)),dbits(Int2Bits(dcnt)),
- vsize(1<<vbits),dsize(1<<dbits)
-{
- Reset();
- CopyAtom(&dir,&d);
-}
-
-pooldir::~pooldir()
-{
- Reset(false);
-
- FLEXT_ASSERT(nxt == NULL);
-}
-
-void pooldir::Clear(bool rec,bool dironly)
-{
- if(rec && dirs) {
- for(int i = 0; i < dsize; ++i) {
- pooldir *d = dirs[i].d,*d1;
- if(d) {
- do {
- d1 = d->nxt;
- d->nxt = NULL;
- delete d;
- } while((d = d1) != NULL);
- dirs[i].d = NULL;
- dirs[i].cnt = 0;
- }
- }
- }
- if(!dironly && vals) {
- for(int i = 0; i < vsize; ++i) {
- poolval *v = vals[i].v,*v1;
- if(v) {
- do {
- v1 = v->nxt;
- v->nxt = NULL;
- delete v;
- } while((v = v1) != NULL);
- vals[i].v = NULL;
- vals[i].cnt = 0;
- }
- }
- }
-}
-
-void pooldir::Reset(bool 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(int argc,const t_atom *argv,int vcnt,int dcnt)
-{
- if(!argc) return this;
-
- int 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(int argc,const t_atom *argv,bool rmv)
-{
- if(!argc) return this;
-
- int 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;
- }
-}
-
-bool pooldir::DelDir(int argc,const t_atom *argv)
-{
- pooldir *pd = GetDir(argc,argv,true);
- if(pd && pd != this) {
- delete pd;
- return true;
- }
- else
- return false;
-}
-
-void pooldir::SetVal(const t_atom &key,AtomList *data,bool over)
-{
- int 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;
- }
- }
-}
-
-bool pooldir::SetVali(int rix,AtomList *data)
-{
- poolval *prv = NULL,*ix = NULL;
- int vix;
- for(vix = 0; vix < vsize; ++vix)
- if(rix > vals[vix].cnt) rix -= vals[vix].cnt;
- else {
- ix = vals[vix].v;
- for(; ix && rix; prv = ix,ix = ix->nxt) --rix;
- if(ix && !rix) break;
- }
-
- if(ix) {
- // data exists... overwrite it
-
- 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;
- }
- return true;
- }
- else
- return false;
-}
-
-poolval *pooldir::RefVal(const t_atom &key)
-{
- int 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(int rix)
-{
- for(int 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 t_atom &key)
-{
- poolval *ix = RefVal(key);
- return ix?ix->data:NULL;
-}
-
-flext::AtomList *pooldir::GetVal(const t_atom &key,bool cut)
-{
- int 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 Atoms(*ix->data);
- return ret;
- }
-}
-
-int pooldir::CntAll() const
-{
- int cnt = 0;
- for(int vix = 0; vix < vsize; ++vix) cnt += vals[vix].cnt;
- return cnt;
-}
-
-int pooldir::PrintAll(char *buf,int len) const
-{
- int offs = strlen(buf);
-
- int cnt = 0;
- for(int vix = 0; vix < vsize; ++vix) {
- poolval *ix = vals[vix].v;
- for(int 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;
-}
-
-int pooldir::GetKeys(AtomList &keys)
-{
- int cnt = CntAll();
- keys(cnt);
-
- for(int vix = 0; vix < vsize; ++vix) {
- poolval *ix = vals[vix].v;
- for(int i = 0; ix; ++i,ix = ix->nxt)
- SetAtom(keys[i],ix->key);
- }
- return cnt;
-}
-
-int pooldir::GetAll(t_atom *&keys,Atoms *&lst,bool cut)
-{
- int cnt = CntAll();
- keys = new t_atom[cnt];
- lst = new Atoms[cnt];
-
- for(int 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;
-}
-
-
-int pooldir::CntSub() const
-{
- int cnt = 0;
- for(int dix = 0; dix < dsize; ++dix) cnt += dirs[dix].cnt;
- return cnt;
-}
-
-
-int pooldir::GetSub(const t_atom **&lst)
-{
- const int cnt = CntSub();
- lst = new const t_atom *[cnt];
- for(int i = 0,dix = 0; i < cnt; ++dix) {
- pooldir *ix = dirs[dix].d;
- for(; ix; ix = ix->nxt) lst[i++] = &ix->dir;
- }
- return cnt;
-}
-
-
-bool pooldir::Paste(const pooldir *p,int depth,bool repl,bool mkdir)
-{
- bool ok = true;
-
- for(int vi = 0; vi < p->vsize; ++vi) {
- for(poolval *ix = p->vals[vi].v; ix; ix = ix->nxt) {
- SetVal(ix->key,new Atoms(*ix->data),repl);
- }
- }
-
- if(ok && depth) {
- for(int 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;
-}
-
-bool pooldir::Copy(pooldir *p,int depth,bool cut)
-{
- bool ok = true;
-
- if(cut) {
- for(int 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(int vi = 0; vi < vsize; ++vi) {
- for(poolval *ix = vals[vi].v; ix; ix = ix->nxt) {
- p->SetVal(ix->key,new Atoms(*ix->data));
- }
- }
- }
-
- if(ok && depth) {
- for(int 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 bool _isspace(char c) { return c > 0 && isspace(c); }
-
-static const char *ReadAtom(const char *c,t_atom &a,bool utf8)
-{
- // skip leading whitespace (NON-ASCII character are < 0)
- while(*c && _isspace(*c)) ++c;
- if(!*c) return NULL;
-
- char tmp[1024];
- char *m = tmp; // write position
-
- bool issymbol;
- if(*c == '"') {
- issymbol = true;
- ++c;
- }
- else
- issymbol = false;
-
- // go to next whitespace
- for(bool escaped = false;; ++c)
- if(*c == '\\') {
- if(escaped) {
- *m++ = *c;
- escaped = false;
- }
- else
- escaped = true;
- }
- else if(*c == '"' && issymbol && !escaped) {
- // end of string
- ++c;
- FLEXT_ASSERT(!*c || _isspace(*c));
- *m = 0;
- break;
- }
- else if(!*c || (_isspace(*c) && !escaped)) {
- *m = 0;
- break;
- }
- else {
- *m++ = *c;
- escaped = false;
- }
-
- // save character and set delimiter
-
- float fres;
- // first try float
-#if 0
- if(!issymbol && sscanf(tmp,"%f",&fres) == 1) {
-#else
- char *endp;
- // see if it's a float - thanks to Frank Barknecht
- fres = (float)strtod(tmp,&endp);
- if(!issymbol && !*endp && endp != tmp) {
-#endif
- int ires = (int)fres; // try a cast
- if(fres == ires)
- flext::SetInt(a,ires);
- else
- flext::SetFloat(a,fres);
- }
- // no, it's a symbol
- else {
- const char *c;
- if(utf8) {
-#if FLEXT_OS == FLEXT_OS_WIN
- wchar_t wtmp[1024];
- int err = MultiByteToWideChar(CP_UTF8,0,tmp,strlen(tmp),wtmp,1024);
- if(!err) return NULL;
- err = WideCharToMultiByte(CP_ACP,0,wtmp,err,tmp,1024,NULL,FALSE);
- if(!err) return NULL;
- tmp[err] = 0;
- c = tmp;
-#elif FLEXT_OS == FLEXT_OS_MAC
- char ctmp[1024];
-
- // is the output always MacRoman?
- TextEncoding inconv = CreateTextEncoding(kTextEncodingUnicodeDefault,kTextEncodingDefaultVariant,kUnicodeUTF8Format);
- TextEncoding outconv = CreateTextEncoding(kTextEncodingMacRoman,kTextEncodingDefaultVariant,kTextEncodingDefaultFormat);
-
- TECObjectRef converter;
- OSStatus status = TECCreateConverter(&converter,inconv,outconv);
- if(status) return NULL;
-
- ByteCount inlen,outlen;
- status = TECConvertText(
- converter,
- (ConstTextPtr)tmp,strlen(tmp),&inlen,
- (TextPtr)ctmp,sizeof(ctmp),&outlen
- );
- ctmp[outlen] = 0;
-
- TECDisposeConverter(converter);
- c = ctmp;
- if(status) return NULL;
-#else
- wchar_t wtmp[1024];
- size_t len = mbstowcs(wtmp,tmp,1024);
- if(len < 0) return false;
- if(!WCStoUTF8(tmp,wtmp,sizeof(tmp))) return NULL;
- c = tmp;
-#endif
- }
- else
- c = tmp;
- flext::SetString(a,c);
- }
-
- return c;
-}
-
-static bool ParseAtoms(const char *tmp,flext::AtomList &l,bool utf8)
-{
- FLEXT_ASSERT(tmp);
- vector<t_atom> atoms;
- while(*tmp) {
- t_atom at;
- tmp = ReadAtom(tmp,at,utf8);
- if(!tmp) break;
- atoms.push_back(at);
- }
- l(atoms.size(),&atoms[0]);
- return true;
-}
-
-static bool ParseAtoms(string &s,flext::AtomList &l,bool utf8)
-{
- return ParseAtoms((char *)s.c_str(),l,utf8);
-}
-
-static bool ReadAtoms(istream &is,flext::AtomList &l,char del,bool utf8)
-{
- vector<char> tmp;
- for(;;) {
- char c = is.get();
- if(is.eof() || c == del) break;
- tmp.push_back(c);
- }
- tmp.push_back(0); // end-of-string marker
-
- return is.good() && ParseAtoms(&tmp[0],l,utf8);
-}
-
-static bool WriteAtom(ostream &os,const t_atom &a,bool utf8)
-{
- if(flext::IsFloat(a))
- os << flext::GetFloat(a);
- else if(flext::IsInt(a))
- os << flext::GetInt(a);
- else if(flext::IsSymbol(a)) {
- const char *c = flext::GetString(a);
- if(utf8) {
-#if FLEXT_OS == FLEXT_OS_WIN
- char tmp[1024];
- wchar_t wtmp[1024];
- int err = MultiByteToWideChar(CP_ACP,0,c,strlen(c),wtmp,1024);
- if(!err) return false;
- err = WideCharToMultiByte(CP_UTF8,0,wtmp,err,tmp,1024,NULL,FALSE);
- if(!err) return false;
- tmp[err] = 0;
- c = tmp;
-#elif FLEXT_OS == FLEXT_OS_MAC
- char tmp[1024];
-
- // is the input always MacRoman?
- TextEncoding inconv = CreateTextEncoding(kTextEncodingMacRoman,kTextEncodingDefaultVariant,kTextEncodingDefaultFormat);
- TextEncoding outconv = CreateTextEncoding(kTextEncodingUnicodeDefault,kTextEncodingDefaultVariant,kUnicodeUTF8Format);
-
- TECObjectRef converter;
- OSStatus status = TECCreateConverter(&converter,inconv,outconv);
- if(status) return false;
-
- ByteCount inlen,outlen;
- status = TECConvertText(
- converter,
- (ConstTextPtr)c,strlen(c),&inlen,
- (TextPtr)tmp,sizeof(tmp),&outlen
- );
- tmp[outlen] = 0;
-
- TECDisposeConverter(converter);
-
- if(status) return false;
- c = tmp;
-#else
- char tmp[1024];
- wchar_t wtmp[1024];
- if(!UTF8toWCS(wtmp,c,1024)) return false;
- size_t len = wcstombs(tmp,wtmp,sizeof(tmp));
- if(len < 0) return false;
- c = tmp;
-#endif
- }
-
- os << '"';
- for(; *c; ++c) {
- // escape some special characters
- if(_isspace(*c) || *c == '\\' || *c == ',' || *c == '"')
- os << '\\';
- os << *c;
- }
- os << '"';
- }
- else
- FLEXT_ASSERT(false);
- return true;
-}
-
-static void WriteAtoms(ostream &os,const flext::AtomList &l,bool utf8)
-{
- for(int i = 0; i < l.Count(); ++i) {
- WriteAtom(os,l[i],utf8);
- if(i < l.Count()-1) os << ' ';
- }
-}
-
-bool pooldir::LdDir(istream &is,int depth,bool mkdir)
-{
- for(int i = 1; !is.eof(); ++i) {
- Atoms d,k,*v = new Atoms;
- bool r =
- ReadAtoms(is,d,',',false) &&
- ReadAtoms(is,k,',',false) &&
- ReadAtoms(is,*v,'\n',false);
-
- if(r) {
- if(depth < 0 || d.Count() <= depth) {
- pooldir *nd = mkdir?AddDir(d):GetDir(d);
- if(nd) {
- if(k.Count() == 1) {
- nd->SetVal(k[0],v); v = NULL;
- }
- else if(k.Count() > 1)
- post("pool - file format invalid: key must be a single word");
- }
- #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;
-}
-
-bool pooldir::SvDir(ostream &os,int depth,const AtomList &dir)
-{
- int cnt = 0;
- for(int vi = 0; vi < vsize; ++vi) {
- for(poolval *ix = vals[vi].v; ix; ix = ix->nxt) {
- WriteAtoms(os,dir,false);
- os << " , ";
- WriteAtom(os,ix->key,false);
- os << " , ";
- WriteAtoms(os,*ix->data,false);
- os << endl;
- ++cnt;
- }
- }
- if(!cnt) {
- // no key/value pairs present -> force empty directory
- WriteAtoms(os,dir,false);
- os << " , ," << endl;
- }
- if(depth) {
- // save sub-directories
- int nd = depth > 0?depth-1:-1;
- for(int di = 0; di < dsize; ++di) {
- for(pooldir *ix = dirs[di].d; ix; ix = ix->nxt) {
- ix->SvDir(os,nd,Atoms(dir).Append(ix->dir));
- }
- }
- }
- return true;
-}
-
-class xmltag {
-public:
- string tag,attr;
- bool Ok() const { return tag.length() > 0; }
- bool operator ==(const char *t) const { return !tag.compare(t); }
-
- void Clear()
- {
-#if defined(_MSC_VER) && (_MSC_VER < 0x1200)
- // incomplete STL implementation
- tag = ""; attr = "";
-#else
- tag.clear(); attr.clear();
-#endif
- }
-
- 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;
-}
-
-bool pooldir::LdDirXMLRec(istream &is,int depth,bool mkdir,AtomList &d)
-{
- Atoms k,v;
- bool inval = false,inkey = false,indata = false;
- int cntval = 0;
-
- while(!is.eof()) {
- xmltag tag;
- gettag(is,tag);
- if(!tag.Ok()) {
- // look for value
- string s;
- getvalue(is,s);
-
- if(s.length() &&
- (
- (!inval && inkey && d.Count()) || /* dir */
- (inval && (inkey || indata)) /* value */
- )
- ) {
- bool ret = true;
- if(indata) {
- if(v.Count())
- post("pool - XML load: value data already given, ignoring new data");
- else
- ret = ParseAtoms(s,v,true);
- }
- else // inkey
- if(inval) {
- if(k.Count())
- post("pool - XML load, value key already given, ignoring new key");
- else
- ret = ParseAtoms(s,k,true);
- }
- else {
- t_atom &dkey = d[d.Count()-1];
- FLEXT_ASSERT(IsSymbol(dkey));
- const char *ds = GetString(dkey);
- FLEXT_ASSERT(ds);
- if(*ds)
- post("pool - XML load: dir key already given, ignoring new key");
- else
- ReadAtom(s.c_str(),dkey,true);
-
- ret = true;
- }
- if(!ret) post("pool - error interpreting XML value (%s)",s.c_str());
- }
- else
- post("pool - error reading XML data");
- }
- else 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]) == sym__)
- post("pool - XML load: dir key must be given prior to subdirs, ignoring items");
-
- Atoms dnext(d.Count()+1);
- // copy existing dir
- dnext.Set(d.Count(),d.Atoms(),0,false);
- // initialize current dir key as empty
- SetSymbol(dnext[d.Count()],sym__);
-
- // read next level
- LdDirXMLRec(is,depth,mkdir,dnext);
- }
- else if(tag.type == xmltag::t_end) {
- if(!cntval && mkdir) {
- // no values have been found in dir -> make empty dir
- AddDir(d);
- }
-
- // break tag loop
- break;
- }
- }
- else if(tag == "value") {
- if(tag.type == xmltag::t_start) {
- inval = true;
- ++cntval;
- k.Clear(); v.Clear();
- }
- else if(tag.type == xmltag::t_end) {
- // set value after tag closing, but only if level <= depth
- if(depth < 0 || d.Count() <= depth) {
- int fnd;
- for(fnd = d.Count()-1; fnd >= 0; --fnd)
- if(GetSymbol(d[fnd]) == sym__) 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 directory 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 Atoms(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;
- }
- }
- else if(!d.Count() && tag == "pool" && tag.type == xmltag::t_end) {
- // break tag loop
- break;
- }
-#ifdef FLEXT_DEBUG
- else {
- post("pool - unknown XML tag '%s'",tag.tag.c_str());
- }
-#endif
- }
- return true;
-}
-
-bool pooldir::LdDirXML(istream &is,int depth,bool mkdir)
-{
- while(!is.eof()) {
- xmltag tag;
- if(!gettag(is,tag)) break;
-
- if(tag == "pool") {
- if(tag.type == xmltag::t_start) {
- Atoms empty; // must be a separate definition for gcc
- LdDirXMLRec(is,depth,mkdir,empty);
- }
- else
- post("pool - pool not initialized yet");
- }
- 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,int cnt)
-{
- for(int i = 0; i < cnt; ++i) s << '\t';
-}
-
-bool pooldir::SvDirXML(ostream &os,int depth,const AtomList &dir,int ind)
-{
- int i,lvls = ind?(dir.Count()?1:0):dir.Count();
-
- for(i = 0; i < lvls; ++i) {
- indent(os,ind+i);
- os << "<dir>" << endl;
- indent(os,ind+i+1);
- os << "<key>";
- WriteAtom(os,dir[ind+i],true);
- os << "</key>" << endl;
- }
-
- for(int vi = 0; vi < vsize; ++vi) {
- for(poolval *ix = vals[vi].v; ix; ix = ix->nxt) {
- indent(os,ind+lvls);
- os << "<value><key>";
- WriteAtom(os,ix->key,true);
- os << "</key><data>";
- WriteAtoms(os,*ix->data,true);
- os << "</data></value>" << endl;
- }
- }
-
- if(depth) {
- int nd = depth > 0?depth-1:-1;
- for(int di = 0; di < dsize; ++di) {
- for(pooldir *ix = dirs[di].d; ix; ix = ix->nxt) {
- ix->SvDirXML(os,nd,Atoms(dir).Append(ix->dir),ind+lvls);
- }
- }
- }
-
- for(i = lvls-1; i >= 0; --i) {
- indent(os,ind+i);
- os << "</dir>" << endl;
- }
- return true;
-}
-
-unsigned int pooldir::FoldBits(unsigned long h,int bits)
-{
- if(!bits) return 0;
- const int hmax = (1<<bits)-1;
- unsigned int ret = 0;
- for(unsigned int i = 0; i < sizeof(h)*8; i += bits)
- ret ^= (h>>i)&hmax;
- return ret;
-}
-
-int pooldir::Int2Bits(unsigned long n)
-{
- int b;
- for(b = 0; n; ++b) n >>= 1;
- return b;
-}