/* flext - C++ layer for Max/MSP and pd (pure data) externals Copyright (c) 2001-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. */ /*! \file flattr.cpp \brief Attribute handling for the flext base class */ #include "flext.h" #include #ifdef __MWERKS__ #define STD std #else #define STD #endif flext_base::attritem::attritem(const t_symbol *t,metharg tp,methfun f,int fl): item(t,0,NULL),argtp(tp), fun(f),flags(fl) {} flext_base::attritem::~attritem() { // if(nxt) delete nxt; } /* void flext_base::AddAttrItem(attritem *m) { int ix = m->Hash(); post("attr index %x",ix); attritem *&aix = attrhead[ix]; if(aix) { attritem *mi; for(mi = aix; mi->nxt; mi = mi->nxt) {} mi->nxt = m; } else aix = m; // m->th->attrcnt++; } */ //! Add get and set attributes void flext_base::AddAttrib(itemarr *aa,itemarr *ma,const char *attr,metharg tp,methfun gfun,methfun sfun) { const t_symbol *asym = MakeSymbol(attr); // if(sfun) // if commented out, there will be a warning at run-time (more user-friendly) { attritem *a = new attritem(asym,tp,sfun,attritem::afl_bothexist|attritem::afl_set); aa->Add(a); // bind attribute to a method methitem *mi = new methitem(0,asym,a); mi->SetArgs(sfun,1,&tp); ma->Add(mi); } // if(gfun) // if commented out, there will be a warning at run-time (more user-friendly) { attritem *a = new attritem(asym,tp,gfun,attritem::afl_bothexist|attritem::afl_get); aa->Add(a); static char tmp[256] = "get"; strcpy(tmp+3,attr); // bind attribute to a method methitem *mi = new methitem(0,MakeSymbol(tmp),a); mi->SetArgs(gfun,0,NULL); ma->Add(mi); } } void flext_base::AddAttrib(const char *attr,metharg tp,methfun gfun,methfun sfun) { if(procattr) AddAttrib(ThAttrs(),ThMeths(),attr,tp,gfun,sfun); else error("%s - attribute procession is not enabled!",thisName()); } void flext_base::AddAttrib(t_class *c,const char *attr,metharg tp,methfun gfun,methfun sfun) { AddAttrib(ClAttrs(c),ClMeths(c),attr,tp,gfun,sfun); } int flext_base::ListAttr(AtomList &la) const { int cnt = attrhead?attrhead->Count():0; int ccnt = clattrhead?clattrhead->Count():0; la(ccnt+cnt); int ix = 0; for(int i = 0; i <= 1; ++i) { itemarr *a = i?attrhead:clattrhead; if(a) { for(int ai = 0; ai < a->Size(); ++ai) { for(item *l = a->Item(ai); l; l = l->nxt) { attritem *a = (attritem *)l; if(!a->BothExist() || a->IsGet()) SetSymbol(la[ix++],a->tag); } } } } return ix; } int flext_base::CheckAttrib(int argc,const t_atom *argv) { int offs = 0; for(; offs < argc; ++offs) if(IsString(argv[offs]) && *GetString(argv[offs]) == '@') break; return offs; } bool flext_base::InitAttrib(int argc,const t_atom *argv) { int cur,nxt; for(cur = 0; cur < argc; cur = nxt) { // find next @symbol for(nxt = cur+1; nxt < argc; ++nxt) if(IsString(argv[nxt]) && *GetString(argv[nxt]) == '@') break; const t_symbol *tag = MakeSymbol(GetString(argv[cur])+1); SetAttrib(tag,nxt-cur-1,argv+cur+1); } return true; } bool flext_base::ListAttrib() { if(outattr) { AtomList la; int c = ListAttr(la); ToOutAnything(outattr,MakeSymbol("attributes"),c,la.Atoms()); return true; } else return false; } flext_base::attritem *flext_base::FindAttr(const t_symbol *tag,bool get) const { attritem *a = (attritem *)attrhead->Find(tag); while(a && (a->tag != tag || a->inlet != 0 || (get?a->IsSet():a->IsGet()))) a = (attritem *)a->nxt; if(!a) { a = (attritem *)clattrhead->Find(tag); while(a && (a->tag != tag || a->inlet != 0 || (get?a->IsSet():a->IsGet()))) a = (attritem *)a->nxt; } return a; } bool flext_base::SetAttrib(const t_symbol *tag,int argc,const t_atom *argv) { // search for matching attribute attritem *a = FindAttr(tag,false); if(a) return SetAttrib(a,argc,argv); else { error("%s - %s: attribute not found",thisName(),GetString(tag)); return true; } } bool flext_base::SetAttrib(attritem *a,int argc,const t_atom *argv) { if(a->fun) { bool ok = true; AtomList la; t_any any; switch(a->argtp) { case a_float: if(argc == 1 && CanbeFloat(argv[0])) { any.ft = GetAFloat(argv[0]); ((methfun_1)a->fun)(this,any); } else ok = false; break; case a_int: if(argc == 1 && CanbeInt(argv[0])) { any.it = GetAInt(argv[0]); ((methfun_1)a->fun)(this,any); } else ok = false; break; case a_symbol: if(argc == 1 && IsSymbol(argv[0])) { any.st = GetSymbol(argv[0]); ((methfun_1)a->fun)(this,any); } else ok = false; break; case a_LIST: any.vt = &(la(argc,argv)); ((methfun_1)a->fun)(this,any); break; default: ERRINTERNAL(); } if(!ok) post("%s - wrong arguments for attribute %s",thisName(),GetString(a->tag)); } else post("%s - attribute %s has no get method",thisName(),GetString(a->tag)); return true; } /* bool flext_base::GetAttrib(const t_symbol *tag) { if(argc) post("%s - %s: arguments ignored",thisName(),GetString(tag)); #ifdef FLEXT_DEBUG if(strncmp(GetString(tag),"get",3)) { post("%s - %s: tag has no 'get' prefix",thisName(),GetString(tag)); return false; } #endif const t_symbol *mtag = MakeSymbol(GetString(a->tag)+3); // search for attribute attritem *a = (attritem *)attrhead->Find(mtag); if(!a) a = (attritem *)clattrhead->Find(mtag); } */ bool flext_base::GetAttrib(attritem *a) { // main attribute tag if(a) { if(a->fun) { AtomList la; t_any any; switch(a->argtp) { case a_float: { ((methfun_1)a->fun)(this,any); la(1); SetFloat(la[0],any.ft); break; } case a_int: { ((methfun_1)a->fun)(this,any); la(1); SetInt(la[0],any.it); break; } case a_symbol: { ((methfun_1)a->fun)(this,any); la(1); SetSymbol(la[0],any.st); break; } case a_LIST: { any.vt = &la; ((methfun_1)a->fun)(this,any); break; } default: ERRINTERNAL(); } ToOutAnything(outattr,a->tag,la.Count(),la.Atoms()); } else post("%s - attribute %s has no set method",thisName(),GetString(a->tag)); } else error("%s - %s: attribute not found",thisName(),GetString(a->tag)); return true; }