/* $Id: rubyext.c 3621 2008-04-19 01:47:38Z matju $ GridFlow Copyright (c) 2001-2008 by Mathieu Bouchard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See file ../COPYING for further informations on licensing terms. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gridflow.h.fcs" #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #ifdef HAVE_GEM #include "Base/GemPixDualObj.h" #endif /* for exception-handling in 0.9.0... Linux-only */ #ifndef MACOSX #include #include #endif #undef check std::map fclasses; std::map fclasses_pd; //using namespace std; BuiltinSymbols bsym; Barf::Barf(const char *s, ...) { char buf[1024]; va_list ap; va_start(ap,s); vsnprintf(buf,1024,s,ap); buf[1023]=0; va_end(ap); text = strdup(buf); } Barf::Barf(const char *file, int line, const char *func, const char *s, ...) { char buf[1024]; va_list ap; va_start(ap,s); int n = vsnprintf(buf,1024,s,ap); if (n<1024) snprintf(buf+n, 1024-n, "\n%s:%d:in `%s'", file, line, func); buf[1023]=0; va_end(ap); text = strdup(buf); } void pd_oprint (std::ostream &o, int argc, t_atom *argv) { for (int i=0; is_name; else if (t==A_POINTER) o << "(pointer)"; else if (t==A_COMMA) o << ","; else if (t==A_SEMI) o << ";"; else if (t==A_LIST) { t_binbuf *b = (t_binbuf *)argv[i].a_gpointer; o << "["; pd_oprint(o,binbuf_getnatom(b),binbuf_getvec(b)); o << "]"; } else o << "(atom of type " << t << ")"; if (i!=argc-1) o << " "; } } void pd_post (const char *s, int argc, t_atom *argv) { std::ostringstream os; if (s) os << s << ": "; pd_oprint(os,argc,argv); post("%s",os.str().data()); } void pd_oprintf (std::ostream &o, const char *s, int argc, t_atom *argv) { int i=0; for (; *s; s++) { if (*s!='%') {o << (char)*s; continue;} s++; // skip the % if (*s=='f') { if (!argc) RAISE("not enough args"); if (argv[i].a_type != A_FLOAT) RAISE("expected float"); o << argv[i].a_float; } if (*s=='s') { if (!argc) RAISE("not enough args"); if (argv[i].a_type != A_SYMBOL) RAISE("expected symbol"); o << argv[i].a_symbol->s_name; } if (*s=='_') { if (!argc) RAISE("not enough args"); char buf[MAXPDSTRING]; atom_string(&argv[i],buf,MAXPDSTRING); o << buf; } if (*s=='%') { o << "%"; continue; } RAISE("sorry, this format string is not supported yet"); } } //---------------------------------------------------------------- // Dim void Dim::check() { if (n>MAX_DIM) RAISE("too many dimensions"); for (int i=0; iindex; } NumberTypeE NumberTypeE_find (const t_atom &x) { if (x.a_type!=A_SYMBOL) RAISE("expected number-type (as symbol)"); return NumberTypeE_find(string(x.a_symbol->s_name)); } // don't touch. static void gfmemcopy32(int32 *as, int32 *bs, long n) { ptrdiff_t ba = bs-as; #define FOO(I) as[I] = (as+ba)[I]; UNROLL_8(FOO,n,as) #undef FOO } void gfmemcopy(uint8 *out, const uint8 *in, long n) { for (; n>16; in+=16, out+=16, n-=16) { ((int32*)out)[0] = ((int32*)in)[0]; ((int32*)out)[1] = ((int32*)in)[1]; ((int32*)out)[2] = ((int32*)in)[2]; ((int32*)out)[3] = ((int32*)in)[3]; } for (; n>4; in+=4, out+=4, n-=4) { *(int32*)out = *(int32*)in; } for (; n; in++, out++, n--) { *out = *in; } } //---------------------------------------------------------------- //#define DEBUG extern "C" { void *gfmalloc(size_t n) { #ifdef DEBUG static long cumul=0; uint64 t = gf_timeofday(); #endif void *p = memalign(16,n); long align = (long)p & 15; if (align) fprintf(stderr,"malloc alignment = %ld mod 16\n",align); #ifdef DEBUG t = gf_timeofday() - t; cumul += t; post("malloc p=%p bytes=%ld time=%ld cumul=%ld",p,(long)n,(long)t,(long)cumul); #endif return p; } void gffree(void *p) { #ifdef DEBUG static long cumul=0; uint64 t = gf_timeofday(); #endif free(p); #ifdef DEBUG t = gf_timeofday() - t; cumul += t; post("free p=%p time=%ld cumul=%ld",p, (long)t,(long)cumul); #endif } }; //---------------------------------------------------------------- uint64 gf_timeofday () { timeval t; gettimeofday(&t,0); return t.tv_sec*1000000+t.tv_usec; } #define CONVERT0(z) ((in[z] >> chop[z]) << slide[z]) #define CONVERT1 t = CONVERT0(0) | CONVERT0(1) | CONVERT0(2) #define CONVERT2 for (t=0,i=0; isize; i++) t |= CONVERT0(i); #define WRITE_LE \ for (int bytes = self->bytes; bytes; bytes--, t>>=8) *out++ = t; #define WRITE_BE {int bytes; \ bytes = self->bytes; \ while (bytes--) {out[bytes] = t; t>>=8;}\ out += self->bytes;} /* this macro would be faster if the _increment_ was done only once every loop. or maybe gcc does it, i dunno */ #define NTIMES(_x_) \ for (; n>=4; n-=4) {_x_ _x_ _x_ _x_} \ for (; n; n--) {_x_} /* this could be faster (use asm) */ void swap64 (long n, uint64 *data) { NTIMES({ uint64 x = *data; x = (x<<32) | (x>>32); x = ((x&0x0000ffff0000ffffLL)<<16) | ((x>>16)&0x0000ffff0000ffffLL); x = ((x&0x00ff00ff00ff00ffLL)<< 8) | ((x>> 8)&0x00ff00ff00ff00ffLL); *data++ = x; }) } /* this could be faster (use asm) */ void swap32 (long n, uint32 *data) { NTIMES({ uint32 x = *data; x = (x<<16) | (x>>16); x = ((x&0xff00ff)<<8) | ((x>>8)&0xff00ff); *data++ = x; }) } /* this could be faster (use asm or do it in int32 chunks) */ void swap16 (long n, uint16 *data) {NTIMES({ uint16 x = *data; *data++ = (x<<8) | (x>>8); })} /* **************************************************************** */ template static void default_pack(BitPacking *self, long n, T *in, uint8 *out) { uint32 t; int i; int sameorder = self->endian==2 || self->endian==::is_le(); int size = self->size; uint32 mask[4]; memcpy(mask,self->mask,size*sizeof(uint32)); uint32 hb[4]; for (i=0; ibytes) { case 2: NTIMES(CONVERT1; *((int16 *)out)=t; out+=2; in+=3;) return; case 4: NTIMES(CONVERT1; *((int32 *)out)=t; out+=4; in+=3;) return; } } if (self->is_le()) { switch (size) { case 3: for (; n--; in+=3) {CONVERT1; WRITE_LE;} break; case 4: for (; n--; in+=4) {CONVERT1; WRITE_LE;} break; default:for (; n--; in+=size) {CONVERT2; WRITE_LE;}} } else { switch (size) { case 3: for (; n--; in+=3) {CONVERT1; WRITE_BE;} break; case 4: for (; n--; in+=4) {CONVERT1; WRITE_BE;} break; default:for (; n--; in+=size) {CONVERT2; WRITE_BE;}} } } #define LOOP_UNPACK(_reader_) \ for (; n; n--) { \ int bytes=0; uint32 temp=0; _reader_; \ for (int i=0; isize; i++, out++) { \ uint32 t=temp&self->mask[i]; \ *out = (t<<(7-hb[i]))|(t>>(hb[i]-7));}} template static void default_unpack(BitPacking *self, long n, uint8 * in, T * out) { int hb[4]; for (int i=0; isize; i++) hb[i] = highest_bit(self->mask[i]); if (is_le()) { // smallest byte first LOOP_UNPACK( for(; self->bytes>bytes; bytes++, in++) temp |= *in<<(8*bytes); ) } else { // biggest byte first LOOP_UNPACK( bytes=self->bytes; for (; bytes; bytes--, in++) temp=(temp<<8)|*in; ) } } /* **************************************************************** */ template static void pack2_565(BitPacking *self, long n, T * in, uint8 * out) { // const int hb[3] = {15,10,4}; // const uint32 mask[3] = {0x0000f800,0x000007e0,0x0000001f}; // uint32 span[3] = {4,5,4}; uint32 chop[3] = {3,2,3}; uint32 slide[3] = {11,5,0}; uint32 t; NTIMES(CONVERT1; *((short *)out)=t; out+=2; in+=3;) } template static void pack3_888(BitPacking *self, long n, T *in, uint8 *out) { int32 * o32 = (int32 *)out; while (n>=4) { o32[0] = (in[5]<<24) | (in[ 0]<<16) | (in[ 1]<<8) | in[2]; o32[1] = (in[7]<<24) | (in[ 8]<<16) | (in[ 3]<<8) | in[4]; o32[2] = (in[9]<<24) | (in[10]<<16) | (in[11]<<8) | in[6]; o32+=3; in+=12; n-=4; } out = (uint8 *)o32; NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=3; in+=3; ) } template static void unpack3_888(BitPacking *self, long n, uint8 *in, T *out) { NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=3; in+=3; ) } /* template <> static void pack3_888(BitPacking *self, long n, uint8 * in, uint8 * out) { uint32 * o32 = uint32 *((uint32 *)out.p,n*3/4); uint32 * i32 = uint32 *((uint32 *)in.p,n*3/4); while (n>=4) { #define Z(w,i) ((word##w>>(i*8))&255) uint32 word0 = i32[0]; uint32 word1 = i32[1]; uint32 word2 = i32[2]; o32[0] = (Z(1,1)<<24) | (Z(0,0)<<16) | (Z(0,1)<<8) | Z(0,2); o32[1] = (Z(1,3)<<24) | (Z(2,0)<<16) | (Z(0,3)<<8) | Z(1,0); o32[2] = (Z(2,1)<<24) | (Z(2,2)<<16) | (Z(2,3)<<8) | Z(1,2); o32+=3; i32+=3; n-=4; } #undef Z out = (uint8 *)o32; in = (uint8 *)i32; NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=3; in+=3; ) } */ template static void pack3_888b(BitPacking *self, long n, T * in, uint8 * out) { int32 * o32 = (int32 *)out; while (n>=4) { o32[0] = (in[0]<<16) | (in[1]<<8) | in[2]; o32[1] = (in[3]<<16) | (in[4]<<8) | in[5]; o32[2] = (in[6]<<16) | (in[7]<<8) | in[8]; o32[3] = (in[9]<<16) | (in[10]<<8) | in[11]; o32+=4; in+=12; n-=4; } NTIMES( o32[0] = (in[0]<<16) | (in[1]<<8) | in[2]; o32++; in+=3; ) } // (R,G,B,?) -> B:8,G:8,R:8,0:8 // fishy template static void pack3_bgrn8888(BitPacking *self, long n, T * in, uint8 * out) { /* NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=4; in+=4; ) */ int32 * i32 = (int32 *)in; int32 * o32 = (int32 *)out; while (n>=4) { o32[0] = ((i32[0]&0xff)<<16) | (i32[0]&0xff00) | ((i32[0]>>16)&0xff); o32[1] = ((i32[1]&0xff)<<16) | (i32[1]&0xff00) | ((i32[1]>>16)&0xff); o32[2] = ((i32[2]&0xff)<<16) | (i32[2]&0xff00) | ((i32[2]>>16)&0xff); o32[3] = ((i32[3]&0xff)<<16) | (i32[3]&0xff00) | ((i32[3]>>16)&0xff); o32+=4; i32+=4; n-=4; } NTIMES( o32[0] = ((i32[0]&0xff)<<16) | (i32[0]&0xff00) | ((i32[0]>>16)&0xff); o32++; i32++; ) } static uint32 bp_masks[][4] = { {0x0000f800,0x000007e0,0x0000001f,0}, {0x00ff0000,0x0000ff00,0x000000ff,0}, }; static Packer bp_packers[] = { {default_pack, default_pack, default_pack}, {pack2_565, pack2_565, pack2_565}, {pack3_888, pack3_888, pack3_888}, {pack3_888b, default_pack, default_pack}, {pack3_bgrn8888, default_pack, default_pack}, }; static Unpacker bp_unpackers[] = { {default_unpack, default_unpack, default_unpack}, {unpack3_888, unpack3_888, unpack3_888}, }; static BitPacking builtin_bitpackers[] = { BitPacking(2, 2, 3, bp_masks[0], &bp_packers[1], &bp_unpackers[0]), BitPacking(1, 3, 3, bp_masks[1], &bp_packers[2], &bp_unpackers[1]), BitPacking(1, 4, 3, bp_masks[1], &bp_packers[3], &bp_unpackers[0]), BitPacking(1, 4, 4, bp_masks[1], &bp_packers[4], &bp_unpackers[0]), }; /* **************************************************************** */ bool BitPacking::eq(BitPacking *o) { if (!(bytes == o->bytes)) return false; if (!(size == o->size)) return false; for (int i=0; imask[i])) return false; } if (endian==o->endian) return true; /* same==little on a little-endian; same==big on a big-endian */ return (endian ^ o->endian ^ ::is_le()) == 2; } BitPacking::BitPacking(int endian, int bytes, int size, uint32 *mask, Packer *packer, Unpacker *unpacker) { this->endian = endian; this->bytes = bytes; this->size = size; for (int i=0; imask[i] = mask[i]; if (packer) { this->packer = packer; this->unpacker = unpacker; return; } int packeri=-1; this->packer = &bp_packers[0]; this->unpacker = &bp_unpackers[0]; for (int i=0; i<(int)(sizeof(builtin_bitpackers)/sizeof(BitPacking)); i++) { BitPacking *bp = &builtin_bitpackers[i]; if (this->eq(bp)) { this->packer = bp->packer; this->unpacker = bp->unpacker; packeri=i; goto end; } } end:; #if 0 ::post("Bitpacking: endian=%d bytes=%d size=%d packeri=%d", endian, bytes, size, packeri); ::post(" packer=0x%08x unpacker=0x%08x",this->packer,this->unpacker); ::post(" mask=[0x%08x,0x%08x,0x%08x,0x%08x]",mask[0],mask[1],mask[2],mask[3]); #endif } bool BitPacking::is_le() { return endian==1 || (endian ^ ::is_le())==3; } template void BitPacking::pack(long n, T * in, uint8 * out) { switch (NumberTypeE_type_of(in)) { case uint8_e: packer->as_uint8(this,n,(uint8 *)in,out); break; case int16_e: packer->as_int16(this,n,(int16 *)in,out); break; case int32_e: packer->as_int32(this,n,(int32 *)in,out); break; default: RAISE("argh"); } } template void BitPacking::unpack(long n, uint8 * in, T * out) { switch (NumberTypeE_type_of(out)) { case uint8_e: unpacker->as_uint8(this,n,in,(uint8 *)out); break; case int16_e: unpacker->as_int16(this,n,in,(int16 *)out); break; case int32_e: unpacker->as_int32(this,n,in,(int32 *)out); break; default: RAISE("argh"); } } // i'm sorry... see the end of grid.c for an explanation... //static void make_hocus_pocus () { // exit(1); #define FOO(S) \ ((BitPacking*)0)->pack(0,(S *)0,(uint8 *)0); \ ((BitPacking*)0)->unpack(0,(uint8 *)0,(S *)0); EACH_NUMBER_TYPE(FOO) #undef FOO } std::vector gf_data_path; string gf_find_file (string x) { if (strchr(x.data(),'/')) return x; int n = gf_data_path.size(); struct stat dummy; for (int i=0; iname.data()) static FMethod funcall_lookup (FClass *fclass, const char *sel) { int n = fclass->methodsn; for (int i=0; imethods[i].selector,sel)==0) return fclass->methods[i].method; if (fclass->super) return funcall_lookup(fclass->super,sel); return 0; } static FMethod funcall_lookup (BFObject *bself, const char *sel) { return funcall_lookup(fclasses_pd[pd_class(bself)],sel); } void call_super(int argc, t_atom *argv) {/* unimplemented */} //**************************************************************** // BFObject struct BFProxy : t_object { BFObject *parent; t_inlet *inlet; int id; }; static t_class *BFProxy_class; static void BFObject_anything (BFObject *bself, int winlet, t_symbol *selector, int ac, t_atom2 *at) { try { t_atom2 argv[ac+1]; for (int i=0; is_name); FMethod m; m = funcall_lookup(bself,buf); if (m) {m(bself->self,argc+1,argv); return;} sprintf(buf,"_%d_%s",winlet,selector->s_name); m = funcall_lookup(bself,buf); if (m) {m(bself->self,argc,argv+1); return;} m = funcall_lookup(bself,"anything"); if (m) {SETSYMBOL(argv+0,gensym(buf)); m(bself->self,argc+1,argv); return;} pd_error((t_pd *)bself, "method '%s' not found for inlet %d in class '%s'",selector->s_name,winlet,pd_classname(bself)); } catch (Barf &oozy) {pd_error(bself,"%s",oozy.text);} } static void BFObject_anything0 (BFObject *self, t_symbol *s, int argc, t_atom2 *argv) { BFObject_anything(self,0,s,argc,argv); } static void BFProxy_anything (BFProxy *self, t_symbol *s, int argc, t_atom2 *argv) { BFObject_anything(self->parent,self->id,s,argc,argv); } static void *BFObject_new (t_symbol *classsym, int ac, t_atom *at) { string name = string(classsym->s_name); if (fclasses.find(name)==fclasses.end()) {post("GF: class not found: '%s'",classsym->s_name); return 0;} t_class *qlass = fclasses[name]->bfclass; BFObject *bself = (BFObject *)pd_new(qlass); try { int argc = ac; t_atom argv[argc]; for (int i=0; is_name,argc,argv); #ifdef HAVE_GEM CPPExtern::m_holder = (t_object *)bself; #ifdef HAVE_HOLDNAME CPPExtern::m_holdname = const_cast("keep_gem_happy"); #endif #endif int j; for (j=0; jself = 0; bself->mom = (t_canvas *)canvas_getcurrent(); bself->ninlets = 1; bself->noutlets = 0; bself->inlets = new BFProxy*[1]; bself->outlets = new t_outlet*[1]; bself->inlets[0] = 0; // inlet 0 of this table is not in use bself->ninlets_set( fclasses[classsym->s_name]->ninlets ,false); bself->noutlets_set(fclasses[classsym->s_name]->noutlets,false); t_allocator alloc = fclasses[string(classsym->s_name)]->allocator; bself->self = alloc(bself,0,j,(t_atom2 *)argv); #ifdef HAVE_GEM CPPExtern::m_holder = 0; #ifdef HAVE_HOLDNAME CPPExtern::m_holdname=0; #endif #endif while (jself;} catch (Barf &oozy) {pd_error(bself,"%s",oozy.text);} bself->ninlets_set(1,false); delete[] bself->inlets; delete[] bself->outlets; } //**************************************************************** // from pd/src/g_canvas.c struct _canvasenvironment { t_symbol *ce_dir; /* directory patch lives in */ int ce_argc; /* number of "$" arguments */ t_atom *ce_argv; /* array of "$" arguments */ int ce_dollarzero; /* value of "$0" */ }; #include "bundled/g_canvas.h" static void BFObject_undrawio (BFObject *bself) { #ifndef HAVE_DESIREDATA if (!bself->mom || !glist_isvisible(bself->mom)) return; t_rtext *rt = glist_findrtext(bself->mom,bself); if (!rt) return; glist_eraseiofor(bself->mom,bself,rtext_gettag(rt)); #endif } static void BFObject_redraw (BFObject *bself) { #ifndef HAVE_DESIREDATA if (!bself->mom || !glist_isvisible(bself->mom)) return; t_rtext *rt = glist_findrtext(bself->mom,bself); if (!rt) return; gobj_vis((t_gobj *)bself,bself->mom,0); gobj_vis((t_gobj *)bself,bself->mom,1); canvas_fixlinesfor(bself->mom,(t_text *)bself); #endif } /* warning: deleting inlets that are connected will cause pd to crash */ void BFObject::ninlets_set (int n, bool draw) { if (!te_binbuf) draw=false; if (n<1) RAISE("ninlets_set: n=%d must be at least 1",n); if (draw) BFObject_undrawio(this); if (ninletsparent = this; p->id = ninlets; p->inlet = inlet_new(this, &p->ob_pd, 0,0); ninlets++; } } else { while (ninlets>n) { ninlets--; inlet_free(inlets[ninlets]->inlet); pd_free((t_pd *)inlets[ninlets]); } } if (draw) BFObject_redraw(this); } /* warning: deleting outlets that are connected will cause pd to crash */ void BFObject::noutlets_set (int n, bool draw) { if (!te_binbuf) draw=false; if (n<0) RAISE("noutlets_set: n=%d must be at least 0",n); if (draw) BFObject_undrawio(this); if (noutlets0?n:1]; memcpy(noo,outlets,noutlets*sizeof(t_outlet*)); delete[] outlets; outlets = noo; while (noutletsn) outlet_free(outlets[--noutlets]); } if (draw) BFObject_redraw(this); } void add_creator2(FClass *fclass, const char *name) { fclasses[string(name)] = fclass; class_addcreator((t_newmethod)BFObject_new,gensym((char *)name),A_GIMME,0); } //**************************************************************** struct t_namelist; extern t_namelist *sys_searchpath, *sys_helppath; extern "C" void namelist_append_files(t_namelist *, char *); static void add_to_path(char *dir) { char bof[1024]; sprintf(bof,"%s/abstractions",dir); namelist_append_files(sys_searchpath,bof); sprintf(bof,"%s/deprecated",dir); namelist_append_files(sys_searchpath,bof); sprintf(bof,"%s/doc/flow_classes",dir); namelist_append_files(sys_helppath, bof); } //---------------------------------------------------------------- void fclass_install(FClass *fclass, FClass *super, size_t bytes) { fclass->super = super; if (fclass->startup) fclass->startup(fclass); fclass->bytes = bytes; } void install2(FClass *fclass, const char *name, int inlets, int outlets) { fclass->ninlets = inlets; fclass->noutlets = outlets; fclass->name = string(name); fclass->bfclass = class_new(gensym((char *)name), (t_newmethod)BFObject_new, (t_method)BFObject_delete, sizeof(BFObject), CLASS_DEFAULT, A_GIMME,0); fclasses[string(name)] = fclass; fclasses_pd[fclass->bfclass] = fclass; class_addanything(fclass->bfclass,(t_method)BFObject_anything0); } /* This code handles nested lists because PureData (all versions including 0.40) doesn't do it */ int handle_braces(int ac, t_atom *av) { int stack[16]; int stackn=0; int j=0; t_binbuf *buf = binbuf_new(); for (int i=0; is_name; while (*s=='(') { if (stackn==16) {binbuf_free(buf); RAISE("too many nested lists (>16)");} stack[stackn++]=j; s++; } const char *se = s+strlen(s); while (se>s && se[-1]==')') {se--; close++;} if (s!=se) { binbuf_text(buf,(char *)s,se-s); if ((binbuf_getnatom(buf)==1 && binbuf_getvec(buf)[0].a_type==A_FLOAT) || binbuf_getvec(buf)[0].a_type==A_COMMA) { av[j++] = binbuf_getvec(buf)[0]; } else { char ss[MAXPDSTRING]; int n = min(se-s,MAXPDSTRING-1); sprintf(ss,"%.*s",n,s); SETSYMBOL(av+j,gensym(ss)); j++; // av[j++] = gensym(s); } } } else av[j++]=av[i]; i++; while (close--) { if (!stackn) {binbuf_free(buf); RAISE("close-paren without open-paren",av[i]);} t_binbuf *a2 = binbuf_new(); /* leak because there is no deallocation mechanism whatsoever */ int j2 = stack[--stackn]; binbuf_add(a2,j-j2,av+j2); j=j2; SETLIST(av+j,a2); j++; } } binbuf_free(buf); if (stackn) RAISE("too many open-paren (%d)",stackn); return j; } // foreach macro from desiredata: #define foreach(ITER,COLL) for(typeof(COLL.begin()) ITER = COLL.begin(); ITER != (COLL).end(); ITER++) \class FObject \def 0 get (t_symbol *s=0) { FClass *fc = fclasses_pd[pd_class(bself)]; if (!s) { t_atom a[1]; foreach(attr,fc->attrs) { SETSYMBOL(a,gensym((char *)attr->second->name.data())); pd_typedmess((t_pd *)bself,gensym("get"),1,a); } } else { //t_atom a[1]; //outlet_anything(bself->outlets[bself->noutlets-1],s,1,a); FMethod m = funcall_lookup(bself,"___get"); t_atom2 a[1]; SETSYMBOL(a,s); if (m) m(this,1,a); } } \def 0 help () { FClass *fc = fclasses_pd[pd_class(bself)]; post("attributes ("); foreach(attr,fc->attrs) post(" %s %s;",attr->second->type.data(),attr->second->name.data()); post(")"); post("methods ("); for (int i=0; imethodsn; i++) post(" %s",fc->methods[i]); post(")"); } \classinfo {} \end class void startup_number(); void startup_flow_objects(); void startup_format(); STARTUP_LIST(void) void blargh () { #ifdef MACOSX fprintf(stderr,"unhandled exception\n"); #else void *array[25]; int nSize = backtrace(array, 25); char **symbols = backtrace_symbols(array, nSize); for (int i=0; isecond; foreach(iter2,fc->attrs) delete iter2->second; fc->FClass::~FClass(); } */ } // note: contrary to what m_pd.h says, pd_getfilename() and pd_getdirname() // don't exist; also, canvas_getcurrentdir() isn't available during setup // (segfaults), in addition to libraries not being canvases ;-) // AND ALSO, CONTRARY TO WHAT m_pd.h SAYS, open_via_path()'s args are reversed!!! extern "C" void gridflow_setup () { post("GridFlow " GF_VERSION ", Copyright (c) 2001-2008 Mathieu Bouchard"); post("GridFlow was compiled on "__DATE__", "__TIME__); //std::set_terminate(__gnu_cxx::__verbose_terminate_handler); std::set_terminate(blargh); try { char *dirname = new char[MAXPDSTRING]; char *dirresult = new char[MAXPDSTRING]; char *nameresult; if (getcwd(dirname,MAXPDSTRING)<0) {post("AAAARRRRGGGGHHHH!"); exit(69);} int fd=open_via_path(dirname,"gridflow/gridflow",PDSUF,dirresult,&nameresult,MAXPDSTRING,1); if (fd<0) fd=open_via_path(dirname, "gridflow",PDSUF,dirresult,&nameresult,MAXPDSTRING,1); if (fd>=0) close(fd); else post("%s was not found via the -path!","gridflow"PDSUF); /* nameresult is only a pointer in dirresult space so don't delete[] it. */ add_to_path(dirresult); BFProxy_class = class_new(gensym("gf.proxy"),0,0,sizeof(BFProxy),CLASS_PD|CLASS_NOINLET, A_NULL); class_addanything(BFProxy_class,BFProxy_anything); gf_data_path.push_back(string(dirresult)+"/images"); srandom(rdtsc()); #define FOO(_sym_,_name_) bsym._sym_ = gensym(_name_); BUILTIN_SYMBOLS(FOO) #undef FOO startup_number(); \startall startup_flow_objects(); startup_format(); STARTUP_LIST() //sys_gui("bind . {puts %W}\n"); sys_vgui(".mbar.help add command -label \"GridFlow index\" -command {pd pd open index.pd %s/doc \\;}\n",dirresult); delete[] dirresult; delete[] dirname; } catch (Barf &oozy) {post("gridflow_setup error: %s",oozy.text);} signal(SIGSEGV,SIG_DFL); signal(SIGABRT,SIG_DFL); signal(SIGBUS, SIG_DFL); atexit(gridflow_unsetup); }