SOCKET val_sock(value inValue) { if (!val_is_null(inValue)) { if (val_is_kind(inValue,k_socket) ) return ((SOCKET)(socket_int)val_data(inValue)); inValue = val_field(inValue,id___s); if (val_is_kind(inValue,k_socket) ) return ((SOCKET)(socket_int)val_data(inValue)); } val_throw(alloc_string("Invalid socket handle")); return 0; }
/** Destroy an ENetPeer structure. **/ static void destroy_enetpeer( value p ) { #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enetpeer\n"); exit(0); #endif return; ENetPeer *peer; if(!val_is_abstract(p) || !val_is_kind(p, k_udprpeer)) return; peer = (ENetPeer *)val_data(p); if(peer == NULL) return; // force immediate disconnect, if still connected. enet_peer_disconnect_now(peer, 0); // if the peer has an event still, destroy it //free_peer_event(peer); // clear the peer structure enet_peer_reset(peer); // peers never need be deallocated, they are part of an ENetHost #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enetpeer done.\n"); #endif return; }
/** Destroy an allocated ENetHost pointer. Must be used with val_gc() for every ENetHost created. */ static void destroy_enethost( value h ) { #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enethost\n"); //exit(0); #endif //return; if(!val_is_kind(h, k_udprhost)) return; ENetHost *host = (ENetHost *)val_data(h); ENetPeer *peer; //int x, count; if(host == NULL) return; enet_host_flush( host ); for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { if (peer->state == ENET_PEER_STATE_CONNECTED) { enet_peer_disconnect_now(peer, 0); } } #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enethost\n"); #endif enet_host_destroy( host ); //val_kind(v) = NULL; #ifdef ENET_DEBUG fprintf(stderr, "*** destroy_enethost done.\n"); #endif return; }
/** Set the in and out speeds of a host in Bytes per second. **/ static value udpr_setrate(value o, value in, value out) { if( !val_is_abstract(o) || !val_is_kind(o,k_udprhost) ) neko_error(); enet_host_bandwidth_limit((ENetHost *)val_data(o), (enet_uint32)val_int32(in), (enet_uint32)val_int32(out)); return val_true; }
/** Destroy an allocated ENetEvent struct **/ static void destroy_enetevent( value e ) { ENetEvent *event; if( !val_is_abstract(e) || !val_is_kind(e,k_udprevent) ) return; event = (ENetEvent *)val_data(e); if(e == NULL) return; // enet_packet_destroy frees the packet itself. #ifdef ENET_DEBUG printf("*** destroy_enetevent freeing packet\n"); #endif if(event->packet != NULL) enet_packet_destroy (event->packet); //if(event->type == ENET_EVENT_TYPE_DISCONNECT //&& event->peer->data != NULL) //enet_free(event->peer -> data); #ifdef ENET_DEBUG //printf("*** destroy_enetevent freeing event\n"); #endif enet_free(event); #ifdef ENET_DEBUG //printf("*** destroy_enetevent done.\n"); #endif return; }
static void dump_module( value v, field f, void *p ) { value vname; const char *name; if( !val_is_kind(v,neko_kind_module) ) return; vname = val_field_name(f); name = val_is_null(vname)?"???":val_string(vname); ((dump_param*)p)->callb( name, (neko_module*)val_data(v), &((dump_param*)p)->tot ); }
/** Returns an ENetPeer *, or throw if connection fails. **/ static value udpr_connect(value h, value ip, value port, value channels, value timeout) { ENetAddress address; ENetEvent event; ENetHost *host; ENetPeer *peer; int to; if( !val_is_abstract(h) || !val_is_kind(h,k_udprhost) ) neko_error(); // checked in address population //val_check(ip,int); //val_check(port,int); val_check(channels,int); val_check(timeout,int); to = val_int(timeout); if(to < 0) to = 5000; host = (ENetHost *)val_data(h); if(populate_address(&address, ip, port) != val_true) neko_error(); // Initiate the connection with channels 0..channels-1 peer = enet_host_connect (host, &address, (size_t)val_int(channels)); if (peer == NULL) neko_error(); #ifdef ENET_DEBUG fprintf(stderr, "udpr_connect: waiting %d\n", to); #endif /* Wait up to 5 seconds for the connection attempt to succeed. */ if (enet_host_service (host, & event, to) > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { // success #ifdef ENET_DEBUG fprintf(stderr, "udpr_connect: returning peer %x\n", peer); #endif value v = alloc_abstract(k_udprpeer,peer); //val_gc(v, destroy_enetpeer); return v; } // timeout has occurred or disconnect received. #ifdef ENET_DEBUG fprintf(stderr, "udpr_connect: *** enet_peer_reset\n"); #endif enet_peer_reset (peer); neko_error(); }
/** Returns the ENetPeer that generated an event, with the Event allocated pointer in Peer->data. The returned ENetPeer must not be destroyed, since it's a copy of an existing peer pointer. Timeout is float number of seconds (0.001 == 1 ms) **/ static value udpr_poll(value h, value timeout) { //ENetPeerHandle hndPeer = enet_host_peer_to_handle(host, event->peer); ENetEvent *event; int res; if( !val_is_abstract(h) || !val_is_kind(h,k_udprhost) ) neko_error(); val_check(timeout,number); enet_uint32 tout = (enet_uint32)(val_number(timeout)*1000); event = (ENetEvent *) enet_malloc (sizeof (ENetEvent)); // Wait up to timeout milliseconds for an event. res = enet_host_service ((ENetHost *)val_data(h), event, tout); if(res <= 0) { if(res == 0) return val_null; neko_error(); } switch (event->type) { case ENET_EVENT_TYPE_NONE: //if(event->peer != NULL) //free_peer_event(event->peer); enet_free(event); return val_null; break; default: // auto frees any existing unhandled event, add this event. #ifdef ENET_DEBUG_FULL if(event->type == ENET_EVENT_TYPE_RECEIVE) fprintf(stderr, "udpr_poll: event type %s %0.*s\n", event_to_string(event->type), event->packet->dataLength, event->packet->data); else fprintf(stderr, "udpr_poll: event type %s\n", event_to_string(event->type)); #endif break; } value v = alloc_abstract(k_udprevent,event); val_gc(v, destroy_enetevent); return v; #ifdef ENET_DEBUG //fprintf(stderr, "udpr_poll: returning peer %x\n", event->peer); #endif //value v = alloc_abstract(k_udprpeer, event->peer); //return v; }
value ftRenderGlyph( value font, value _index, value _size, value _hint ) { if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); val_check( _size, number ); int size = val_number(_size); FT_Set_Char_Size( *face, size, size, 72, 72 ); val_check( _hint, bool ); int hint = val_bool(_hint); val_check(_index,number); /* int index = FT_Get_Char_Index( *face, (FT_UInt) val_number(_index) ); fprintf( stderr, "char %i is glyph %i\n", (int)val_number(_index), (int)index ); int err = FT_Load_Glyph( *face, index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING ); fprintf( stderr, "Load Glyph idx %i->%i/%i, sz %i, face %p: err 0x%x\n", (int)val_number(_index), index, (int)((*face)->num_glyphs), size>>6, face, err ); */ int err = FT_Load_Char( *face, (FT_ULong)val_number(_index), FT_LOAD_RENDER | (hint?0:FT_LOAD_NO_HINTING) ); if( err ) { fprintf( stderr, "Load_Char failed: %x char index %i\n", err, FT_Get_Char_Index( *face, (FT_UInt) val_number(_index) ) ); val_throw(alloc_string("Could not load requested Glyph")); // return( val_null ); } FT_GlyphSlot glyph = (*face)->glyph; /* err = FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL ); if( err || glyph->format != ft_glyph_format_bitmap ) { val_throw(alloc_string("Could not render requested Glyph")); } */ FT_Bitmap bitmap = glyph->bitmap; value ret = alloc_object(NULL); alloc_field( ret, val_id("width"), alloc_int(bitmap.width) ); alloc_field( ret, val_id("height"), alloc_int(bitmap.rows) ); alloc_field( ret, val_id("bitmap"), copy_string( (char*)bitmap.buffer, bitmap.width*bitmap.rows ) ); alloc_field( ret, val_id("x"), alloc_int( glyph->metrics.horiBearingX ) ); alloc_field( ret, val_id("y"), alloc_int( glyph->metrics.horiBearingY ) ); alloc_field( ret, val_id("advance"), alloc_float( glyph->advance.x )); return ret; }
bool AbstractToObject (value inValue, OBJ *&outObj) { outObj = 0; if (!val_is_kind (inValue, gObjectKind)) { return false; } Object* obj = (Object*)val_to_kind (inValue, gObjectKind); outObj = dynamic_cast<OBJ*> (obj); return outObj; }
/** set_flush_mode : 'stream -> string -> void <doc>Change the flush mode ("NO","SYNC","FULL","FINISH","BLOCK")</doc> **/ static value set_flush_mode( value s, value flush ) { int f; if( !val_is_kind(s,k_stream_inf) ) val_check_kind(s,k_stream_def); val_check(flush,string); if( strcmp(val_string(flush),"NO") == 0 ) f = Z_NO_FLUSH; else if( strcmp(val_string(flush),"SYNC") == 0 ) f = Z_SYNC_FLUSH; else if( strcmp(val_string(flush),"FULL") == 0 ) f = Z_FULL_FLUSH; else if( strcmp(val_string(flush),"FINISH") == 0 ) f = Z_FINISH; else if( strcmp(val_string(flush),"BLOCK") == 0 ) f = Z_BLOCK; else return alloc_null(); val_flush(val_stream(s)) = f; return alloc_null(); }
static fd_set *make_socket_array( value a, int len, fd_set *tmp, SOCKET *n ) { int i; SOCKET sock; if( val_is_null(a) ) return NULL; if( !val_is_array(a) ) return &INVALID; if( len > FD_SETSIZE ) val_throw(alloc_string("Too many sockets in select")); FD_ZERO(tmp); for(i=0;i<len;i++) { value s = val_array_ptr(a)[i]; if( !val_is_kind(s,k_socket) ) return &INVALID; sock = val_sock(s); if( sock > *n ) *n = sock; FD_SET(sock,tmp); } return tmp; }
value hx_zmq_construct_socket (value context_handle,value type) { val_is_kind(context_handle,k_zmq_context_handle); if (!val_is_int(type)) { val_throw(alloc_int(EINVAL)); return alloc_null(); } void *s = zmq_socket (val_data(context_handle),val_int(type)); int err = zmq_errno(); if (s == NULL) { val_throw (alloc_int(err)); return alloc_null(); } // See: http://nekovm.org/doc/ffi#abstracts_and_kinds value v = alloc_abstract(k_zmq_socket_handle,s); val_gc(v,finalize_socket); // finalize_socket is called when the abstract value is garbage collected return v; }
static value loader_loadmodule( value mname, value vthis ) { value o = val_this(); value cache; val_check(o,object); val_check(mname,string); val_check(vthis,object); cache = val_field(o,id_cache); val_check(cache,object); { reader r; readp p; neko_module *m; neko_vm *vm = NEKO_VM(); field mid = val_id(val_string(mname)); value mv = val_field(cache,mid); if( val_is_kind(mv,neko_kind_module) ) { m = (neko_module*)val_data(mv); return m->exports; } open_module(val_field(o,id_path),val_string(mname),&r,&p); if( vm->fstats ) vm->fstats(vm,"neko_read_module",1); m = neko_read_module(r,p,vthis); if( vm->fstats ) vm->fstats(vm,"neko_read_module",0); close_module(p); if( m == NULL ) { buffer b = alloc_buffer("Invalid module : "); val_buffer(b,mname); bfailure(b); } m->name = alloc_string(val_string(mname)); mv = alloc_abstract(neko_kind_module,m); alloc_field(cache,mid,mv); if( vm->fstats ) vm->fstats(vm,val_string(mname),1); neko_vm_execute(neko_vm_current(),m); if( vm->fstats ) vm->fstats(vm,val_string(mname),0); return m->exports; } }
value ftIterateKerningPairs( value font, value callback ) { if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); if( !FT_HAS_KERNING((*face)) ) { return val_null; } FT_UInt left_index, right_index; FT_ULong left, right; FT_Vector vec; left = FT_Get_First_Char( *face, &left_index ); while( left != 0 ) { right = FT_Get_First_Char( *face, &right_index ); while( right != 0 ) { if( !FT_Get_Kerning( *face, left_index, right_index, FT_KERNING_UNFITTED, &vec ) && vec.x ) { // printf("KERNING %c_%c: %f\n", left, right, vec.x ); val_call3( callback, alloc_int( (int)left ), alloc_int( (int)right ), alloc_float( vec.x ) ); } right = FT_Get_Next_Char( *face, right, &right_index ); } left = FT_Get_Next_Char( *face, left, &left_index ); } return val_true; }
/** get_adler32 : 'stream -> 'int32 <doc>Returns the adler32 value of the stream</doc> **/ static value get_adler32( value s ) { if( !val_is_kind(s,k_stream_inf) ) val_check_kind(s,k_stream_def); return alloc_int32(val_stream(s)->adler); }
static value unserialize_rec( sbuffer *b, value loader ) { switch( read_char(b) ) { case 'N': return val_null; case 'T': return val_true; case 'F': return val_false; case 'i': return alloc_int(read_int(b)); case 'I': return alloc_int32(read_int(b)); case 'f': { tfloat d; read_str(b,sizeof(tfloat),&d); return alloc_float(d); } case 's': { int l = read_int(b); value v; if( l < 0 || l > max_string_size ) ERROR(); v = alloc_empty_string(l); add_ref(b,v); read_str(b,l,(char*)val_string(v)); return v; } case 'o': { int f; value o = alloc_object(NULL); add_ref(b,o); while( (f = read_int(b)) != 0 ) { value fval = unserialize_rec(b,loader); alloc_field(o,(field)f,fval); } switch( read_char(b) ) { case 'p': { value v = unserialize_rec(b,loader); if( !val_is_object(v) ) ERROR(); ((vobject*)o)->proto = (vobject*)v; } break; case 'z': break; default: ERROR(); } return o; } case 'r': { int n = read_int(b); if( n < 0 || n >= b->nrefs ) ERROR(); return b->trefs[b->nrefs - n - 1]; } case 'a': { int i; int n = read_int(b); value o; value *t; if( n < 0 || n > max_array_size ) ERROR(); o = alloc_array(n); t = val_array_ptr(o); add_ref(b,o); for(i=0;i<n;i++) t[i] = unserialize_rec(b,loader); return o; } case 'p': { int nargs = read_int(b); vfunction *f = (vfunction*)alloc_function((void*)1,nargs,NULL); vfunction *f2; value name; add_ref(b,(value)f); name = unserialize_rec(b,loader); f2 = (vfunction*)val_ocall2(loader,id_loadprim,name,alloc_int(nargs)); if( !val_is_function(f2) || val_fun_nargs(f2) != nargs ) failure("Loader returned not-a-function"); f->t = f2->t; f->addr = f2->addr; f->module = f2->module; return (value)f; } case 'L': { vfunction *f = (vfunction*)alloc_function((void*)1,0,NULL); value mname; int pos; int nargs; value env; add_ref(b,(value)f); mname = unserialize_rec(b,loader); pos = read_int(b); nargs = read_int(b); env = unserialize_rec(b,loader); if( !val_is_array(env) ) ERROR(); { value exp = val_ocall2(loader,id_loadmodule,mname,loader); value mval; unsigned int i; int_val *mpos; neko_module *m; if( !val_is_object(exp) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } mval = val_field(exp,id_module); if( !val_is_kind(mval,neko_kind_module) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid type"); bfailure(b); } m = (neko_module*)val_data(mval); mpos = m->code + pos; for(i=0;i<m->nglobals;i++) { vfunction *g = (vfunction*)m->globals[i]; if( val_is_function(g) && g->addr == mpos && g->module == m && g->nargs == nargs ) { f->t = VAL_FUNCTION; f->env = env; f->addr = mpos; f->nargs = nargs; f->module = m; return (value)f; } } { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has been modified"); bfailure(b); } } return val_null; } case 'x': { value mname = unserialize_rec(b,loader); value data = unserialize_rec(b,loader); value exports = val_ocall2(loader,id_loadmodule,mname,loader); value s; if( !val_is_object(exports) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," is not an object"); bfailure(b); } s = val_field(exports,id_unserialize); if( !val_is_function(s) || (val_fun_nargs(s) != 1 && val_fun_nargs(s) != VAR_ARGS) ) { buffer b = alloc_buffer("module "); val_buffer(b,mname); buffer_append(b," has invalid __unserialize function"); } s = val_call1(s,data); add_ref(b,s); return s; } case 'h': { int i; vhash *h = (vhash*)alloc(sizeof(vhash)); h->ncells = read_int(b); h->nitems = read_int(b); h->cells = (hcell**)alloc(sizeof(hcell*)*h->ncells); for(i=0;i<h->ncells;i++) h->cells[i] = NULL; for(i=0;i<h->nitems;i++) { hcell **p; hcell *c = (hcell*)alloc(sizeof(hcell)); c->hkey = read_int(b); c->key = unserialize_rec(b,loader); c->val = unserialize_rec(b,loader); c->next = NULL; p = &h->cells[c->hkey % h->ncells]; while( *p != NULL ) p = &(*p)->next; *p = c; } return alloc_abstract(k_hash,h); } default: ERROR(); return val_null; } }
void serialize_rec( sbuffer *b, value o ) { b->nrec++; if( b->nrec > 350 ) failure("Serialization stack overflow"); switch( val_type(o) ) { case VAL_NULL: write_char(b,'N'); break; case VAL_BOOL: if( val_bool(o) ) write_char(b,'T'); else write_char(b,'F'); break; case VAL_INT: write_char(b,'i'); write_int(b,val_int(o)); break; case VAL_FLOAT: write_char(b,'f'); write_str(b,sizeof(tfloat),&val_float(o)); break; case VAL_STRING: if( !write_ref(b,o,NULL) ) { write_char(b,'s'); write_int(b,val_strlen(o)); write_str(b,val_strlen(o),val_string(o)); } break; case VAL_OBJECT: { value s; if( !write_ref(b,o,&s) ) { if( s != NULL ) { // reference was not written if( !val_is_function(s) || (val_fun_nargs(s) != 0 && val_fun_nargs(s) != VAR_ARGS) ) failure("Invalid __serialize method"); write_char(b,'x'); serialize_rec(b,((neko_module*)((vfunction*)s)->module)->name); serialize_rec(b,val_ocall0(o,id_serialize)); // put reference back write_ref(b,o,NULL); break; } write_char(b,'o'); val_iter_fields(o,serialize_fields_rec,b); write_int(b,0); o = (value)((vobject*)o)->proto; if( o == NULL ) write_char(b,'z'); else { write_char(b,'p'); serialize_rec(b,o); } } } break; case VAL_ARRAY: if( !write_ref(b,o,NULL) ) { int i; int n = val_array_size(o); write_char(b,'a'); write_int(b,n); for(i=0;i<n;i++) serialize_rec(b,val_array_ptr(o)[i]); } break; case VAL_FUNCTION: if( !write_ref(b,o,NULL) ) { neko_module *m; if( val_tag(o) == VAL_PRIMITIVE ) { // assume that alloc_array(0) return a constant array ptr // we don't want to access custom memory (maybe not a ptr) if( ((vfunction*)o)->env != alloc_array(0) ) failure("Cannot Serialize Primitive with environment"); write_char(b,'p'); write_int(b,((vfunction*)o)->nargs); serialize_rec(b,((vfunction*)o)->module); break; } if( val_tag(o) == VAL_JITFUN ) failure("Cannot Serialize JIT method"); write_char(b,'L'); m = (neko_module*)((vfunction*)o)->module; serialize_rec(b,m->name); write_int(b,(int)((int_val*)((vfunction*)o)->addr - m->code)); write_int(b,((vfunction*)o)->nargs); serialize_rec(b,((vfunction*)o)->env); } break; case VAL_INT32: write_char(b,'I'); write_int(b,val_int32(o)); break; case VAL_ABSTRACT: if( val_is_kind(o,k_hash) ) { int i; vhash *h = val_hdata(o); write_char(b,'h'); write_int(b,h->ncells); write_int(b,h->nitems); for(i=0;i<h->ncells;i++) { hcell *c = h->cells[i]; while( c != NULL ) { write_int(b,c->hkey); serialize_rec(b,c->key); serialize_rec(b,c->val); c = c->next; } } break; } default: failure("Cannot Serialize Abstract"); break; } b->nrec--; }
value ftIterateGlyphs( value font, value callbacks ) { if( !val_is_object(callbacks) ) { ft_failure_v("not a callback function object: ", callbacks ); } // printf("A\n"); field endGlyph = val_id("endGlyph"); field startContour = val_id("startContour"); field endContour = val_id("endContour"); field lineTo = val_id("lineTo"); field curveTo = val_id("curveTo"); // printf("B\n"); if( !val_is_object(font) ) { ft_failure_v("not a freetype font face: ", font ); } value __f = val_field( font, val_id("__f") ); if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) { ft_failure_v("not a freetype font face: ", font ); } FT_Face *face = val_data( __f ); // printf("C\n"); FT_UInt glyph_index; FT_ULong character; FT_Outline *outline; field f_character = val_id("character"); field f_advance = val_id("advance"); character = FT_Get_First_Char( *face, &glyph_index ); // printf("D\n"); while( character != 0 ) { if( FT_Load_Glyph( *face, glyph_index, FT_LOAD_NO_BITMAP ) ) { // ignore (TODO report?) } else if( (*face)->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) { // ignore (TODO) } else { outline = &((*face)->glyph->outline); int start = 0, end, contour, p; char control, cubic; int n,i; // printf(" 1\n"); for( contour = 0; contour < outline->n_contours; contour++ ) { end = outline->contours[contour]; n=0; for( p = start; p<=end; p++ ) { control = !(outline->tags[p] & 0x01); cubic = outline->tags[p] & 0x02; if( p==start ) { val_ocall2( callbacks, startContour, alloc_int( outline->points[p-n].x ), alloc_int( outline->points[p-n].y ) ); } if( !control && n > 0 ) { importGlyphPoints( &(outline->points[(p-n)+1]), n-1, callbacks, lineTo, curveTo, cubic ); n=1; } else { n++; } } if( n ) { // special case: repeat first point FT_Vector points[n+1]; int s=(end-n)+2; for( i=0; i<n-1; i++ ) { points[i].x = outline->points[s+i].x; points[i].y = outline->points[s+i].y; } points[n-1].x = outline->points[start].x; points[n-1].y = outline->points[start].y; importGlyphPoints( points, n-1, callbacks, lineTo, curveTo, false ); } start = end+1; val_ocall0( callbacks, endContour ); } // printf(" 2\n"); val_ocall2( callbacks, endGlyph, alloc_int( character ), alloc_int( (*face)->glyph->advance.x ) ); // printf(" 3\n"); } // printf(" E\n"); character = FT_Get_Next_Char( *face, character, &glyph_index ); // printf(" F\n"); } // printf(" Goo\n"); return val_true; }