/** set_conv_funs : 'connection -> function:1 -> function:1 -> function:1 -> void <doc>Set three wrapper methods to be be called when creating a string, a date, and binary data in results</doc> **/ static value set_conv_funs( value o, value fstring, value fdate, value fbytes ) { val_check_kind(o,k_connection); val_check_function(fstring,1); val_check_function(fdate,1); val_check_function(fbytes,1); CNX(o)->conv_string = fstring; CNX(o)->conv_date = fdate; CNX(o)->conv_bytes = fbytes; return val_null; }
/** $varargs : f:function:1 -> function <doc> Return a variable argument function that, when called, will callback [f] with the array of arguments. </doc> **/ static value builtin_varargs( value f ) { value fvar; val_check_function(f,1); fvar = alloc_function(varargs_callback,VAR_ARGS,"varargs"); ((vfunction*)fvar)->env = f; return fvar; }
/** result_set_conv_date : 'result -> function:1 -> void <doc>Set the function that will convert a Date or DateTime string to the corresponding value.</doc> **/ static value result_set_conv_date( value o, value c ) { val_check_function(c,1); if( val_is_int(o) ) return val_true; val_check_kind(o,k_result); RESULT(o)->conv_date = c; return val_true; }
/** cgi_set_main : function:0? -> void <doc>Set or disable the main entry point function</doc> **/ static value cgi_set_main( value f ) { if( val_is_null(f) ) { CONTEXT()->main = NULL; return val_true; } val_check_function(f,0); CONTEXT()->main = f; return val_true; }
/** $setresolver : function:2? -> void <doc>Set a function to callback with object and field id when an object field is not found.</doc> **/ static value builtin_setresolver( value f ) { neko_vm *vm = NEKO_VM(); if( val_is_null(f) ) vm->resolver = NULL; else { val_check_function(f,2); vm->resolver = f; } return val_null; }
static value print_redirect( value f ) { neko_vm *vm = neko_vm_current(); if( val_is_null(f) ) { neko_vm_redirect(vm,NULL,NULL); return val_null; } val_check_function(f,1); neko_vm_redirect(vm,print_callback,f); return val_null; }
/** thread_create : f:function:1 -> p:any -> 'thread <doc>Creates a thread that will be running the function [f(p)]</doc> **/ static value thread_create( value f, value param ) { tparams *p; val_check_function(f,1); p = (tparams*)alloc(sizeof(tparams)); p->callb = f; p->callparam = param; p->jit = neko_vm_jit(neko_vm_current(),-1); if( !neko_thread_create(thread_init,thread_loop,p,&p->handle) ) neko_error(); return p->t->v; }
static value os_winlog_new( value title, value f ) { window *w; val_check(title,string); val_check_function(f,0); w = (window*)alloc(sizeof(window)); w->click = f; w->p = sys_winlog_new(val_string(title),wnd_callback,w); if( w->p == NULL ) neko_error(); return alloc_abstract(k_winlog,w); }
/** module_read : fread:(buf:string -> pos:int -> len:int -> int) -> loader:object -> 'module <doc> Read a module using the specified read function and the specified loader. </doc> **/ static value module_read( value fread, value loader ) { value p; neko_module *m; val_check_function(fread,3); val_check(loader,object); p = alloc_array(2); val_array_ptr(p)[0] = fread; val_array_ptr(p)[1] = alloc_empty_string(READ_BUFSIZE); m = neko_read_module(read_proxy,p,loader); if( m == NULL ) neko_error(); m->name = alloc_string(""); return alloc_abstract(neko_kind_module,m); }
static value inputandroid_initialize(value onTouchBatchStartCallback, value onTouchCallback, value setCachedVariables) { val_check_function(onTouchBatchStartCallback, 1); // Is Func ? if (__onTouchBatchStartCallback == NULL) { __onTouchBatchStartCallback = alloc_root(); } *__onTouchBatchStartCallback = onTouchBatchStartCallback; val_check_function(onTouchCallback, 1); // Is Func ? if (__onTouchCallback == NULL) { __onTouchCallback = alloc_root(); } *__onTouchCallback = onTouchCallback; __touchValue = alloc_abstract(0, &__touch); __touchCountValue = alloc_abstract(0, &__touchCount); val_call2(setCachedVariables, __touchValue, __touchCountValue); return alloc_null(); }
/** $hiter : 'hash -> f:function:2 -> void <doc>Call the function [f] with every key and value in the hashtable</doc> **/ static value builtin_hiter( value vh, value f ) { int i; hcell *c; vhash *h; val_check_function(f,2); val_check_kind(vh,k_hash); h = val_hdata(vh); for(i=0;i<h->ncells;i++) { c = h->cells[i]; while( c != NULL ) { val_call2(f,c->key,c->val); c = c->next; } } return val_null; }
value hxfcgi_cache_module(value func) { val_check_function(func,1); hxfcgi::Request *req; while (true) { try { if(FCGX_IsCGI()) break; req = new hxfcgi::Request(); val_call1(func,alloc_abstract(hxRequest,req)); delete req; } catch (string error) { hx_failure(error.c_str()); break; } } return val_null; }
/** regexp_replace_fun : 'regexp -> from:string -> f:('regexp -> any) -> string <doc>Perform a replacement of all matched substrings by calling [f] for every match</doc> **/ static value regexp_replace_fun( value o, value s, value f ) { val_check_kind(o,k_regexp); val_check(s,string); val_check_function(f,1); { pcredata *d = PCRE(o); buffer b = alloc_buffer(NULL); int pos = 0; int len = val_strlen(s); const char *str = val_string(s); d->str = s; while( pcre_exec(d->r,NULL,str,len,pos,0,d->matchs,d->nmatchs * 3) >= 0 ) { buffer_append_sub(b,str+pos,d->matchs[0] - pos); val_buffer(b,val_call1(f,o)); pos = d->matchs[1]; } d->str = alloc_null(); buffer_append_sub(b,str+pos,len-pos); return buffer_to_string(b); } }
/** $hset : 'hash -> k:any -> v:any -> cmp:function:2? -> bool <doc> Set the value bound to key [k] to [v] or add it to the hashtable if not found. Return true if the value was added to the hashtable. </doc> **/ static value builtin_hset( value vh, value key, value val, value cmp ) { vhash *h; hcell *c; int hkey; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); hkey = val_hash(key); c = h->cells[hkey % h->ncells]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) { c->val = val; return val_false; } c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) { c->val = val; return val_false; } c = c->next; } } if( h->nitems >= (h->ncells << 1) ) builtin_hresize(vh,alloc_int(h->ncells << 1)); c = (hcell*)alloc(sizeof(hcell)); c->hkey = hkey; c->key = key; c->val = val; hkey %= h->ncells; c->next = h->cells[hkey]; h->cells[hkey] = c; h->nitems++; return val_true; }
/** $hremove : 'hash -> k:any -> cmp:function:2? -> bool <doc> Look for the value bound to the key [k] in the hashtable. Use the comparison function [cmp] or [$compare] if [null]. Return true if such value exists and remove it from the hash, false either. </doc> **/ static value builtin_hremove( value vh, value key, value cmp ) { vhash *h; hcell *c, *prev = NULL; int hkey; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); hkey = val_hash(key) % h->ncells; c = h->cells[hkey]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) { if( prev == NULL ) h->cells[hkey] = c->next; else prev->next = c->next; h->nitems--; return val_true; } prev = c; c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) { if( prev == NULL ) h->cells[hkey] = c->next; else prev->next = c->next; h->nitems--; return val_true; } prev = c; c = c->next; } } return val_false; }
/** $hmem : 'hash -> k:any -> cmp:function:2? -> bool <doc> Look for the value bound to the key [k] in the hashtable. Use the comparison function [cmp] or [$compare] if [null]. Return true if such value exists, false either. </doc> **/ static value builtin_hmem( value vh, value key, value cmp ) { vhash *h; hcell *c; if( !val_is_null(cmp) ) val_check_function(cmp,2); val_check_kind(vh,k_hash); h = val_hdata(vh); c = h->cells[val_hash(key) % h->ncells]; if( val_is_null(cmp) ) { while( c != NULL ) { if( val_compare(key,c->key) == 0 ) return val_true; c = c->next; } } else { while( c != NULL ) { if( val_call2(cmp,key,c->key) == alloc_int(0) ) return val_true; c = c->next; } } return val_false; }
/** ui_sync : callb:(void -> void) -> void <doc> Queue a method call [callb] to be executed by the main thread while running the UI event loop. This can be used to perform UI updates in the UI thread using results processed by another thread. </doc> **/ static value ui_sync( value f ) { value *r; val_check_function(f,0); r = alloc_root(1); *r = f; # if defined(NEKO_WINDOWS) while( !PostMessage(data.wnd,WM_SYNC_CALL,0,(LPARAM)r) ) Sleep(100); # elif defined(NEKO_MAC) EventRef e; CreateEvent(NULL,UIEvent,eCall,GetCurrentEventTime(),kEventAttributeUserEvent,&e); SetEventParameter(e,pFunc,typeVoidPtr,sizeof(void*),&r); PostEventToQueue(GetMainEventQueue(),e,kEventPriorityStandard); ReleaseEvent(e); # elif defined(NEKO_LINUX) // the lock should not be needed because GTK is MT-safe // however the GTK lock mechanism is a LOT slower than // using a pthread_mutex pthread_mutex_lock(&data.lock); gtk_timeout_add( 0, onSyncCall, (gpointer)r ); pthread_mutex_unlock(&data.lock); # endif return val_null; }
static value conf_set_servername_callback( value config, value cb ){ val_check_kind(config,k_ssl_conf); val_check_function(cb,1); mbedtls_ssl_conf_sni( val_conf(config), sni_callback, (void *)cb ); return val_true; }
value hxfcgi_parse_multipart_neko(value hreq, value onpart, value ondata ) { val_check_kind(hreq,hxRequest); val_check_function(onpart,2); val_check_function(ondata,3); hxfcgi::Request *req = get_request(hreq); char *buf; int len = 0; char *boundstr; hxfcgi::BasicData b; string ctype = b.getHeader("CONTENT_TYPE"); if(ctype.find("multipart/form-data") != 0) return val_null; // extract boundary value { const char *boundary, *bend; if( (boundary = strstr(ctype.c_str(),"boundary=")) == NULL ) neko_error(); boundary += 9; PARSE_HEADER(boundary,bend); len = (int)(bend - boundary); boundstr = (char *) malloc(sizeof(char) * (len+3)); if( strlen(boundstr) > BUFSIZE / 2 ) neko_error(); boundstr[0] = '-'; boundstr[1] = '-'; memcpy(boundstr+2,boundary,len); boundstr[len+2] = 0; } len = 0; buf = (char *) malloc(sizeof(char) * (BUFSIZE)); while( true ) { char *name, *end_name, *filename, *end_file_name, *data; int pos; // refill buffer // we assume here that the the whole multipart header can fit in the buffer req->bufferFill(buf,&len); // is boundary at the beginning of buffer ? if( len < (int) strlen(boundstr) || memcmp(buf,boundstr,strlen(boundstr)) != 0 ) { free(boundstr); free(buf); return val_null; } name = memfind(buf,len,"Content-Disposition:"); if( name == NULL ) break; name = memfind(name,len - (int)(name - buf),"name="); if( name == NULL ) { free(boundstr); free(buf); return val_null; } name += 5; PARSE_HEADER(name,end_name); data = memfind(end_name,len - (int)(end_name - buf),"\r\n\r\n"); if( data == NULL ) { free(boundstr); free(buf); return val_null; } filename = memfind(name,(int)(data - name),"filename="); if( filename != NULL ) { filename += 9; PARSE_HEADER(filename,end_file_name); } data += 4; pos = (int)(data - buf); // send part name val_call2(onpart,copy_string(name,(int)(end_name - name)),filename?copy_string(filename,(int)(end_file_name - filename)):val_null); // read data while( true ) { const char *boundary; // recall buffer memcpy(buf,buf+pos,len - pos); len -= pos; pos = 0; req->bufferFill(buf,&len); // lookup bounds boundary = memfind(buf,len,boundstr); if( boundary == NULL ) { if( len == 0 ) { free(boundstr); free(buf); return val_null; } // send as much buffer as possible to client if( len < BUFSIZE ) pos = len; else pos = len - strlen(boundstr) + 1; val_call3(ondata,copy_string(buf,pos),alloc_int(0),alloc_int(pos)); } else { // send remaining data pos = (int)(boundary - buf); val_call3(ondata,copy_string(buf,pos-2),alloc_int(0),alloc_int(pos-2)); // recall memcpy(buf,buf+pos,len - pos); len -= pos; break; } } } free(boundstr); free(buf); return val_null; }
/** parse_multipart_data : onpart:function:2 -> ondata:function:3 -> void <doc> Incrementally parse the multipart data. call [onpart(name,filename)] for each part found and [ondata(buf,pos,len)] when some data is available </doc> **/ static value parse_multipart_data( value onpart, value ondata ) { value buf; int len = 0; mcontext *c = CONTEXT(); const char *ctype = ap_table_get(c->r->headers_in,"Content-Type"); value boundstr; val_check_function(onpart,2); val_check_function(ondata,3); buf = alloc_empty_string(BUFSIZE); if( !ctype || strstr(ctype,"multipart/form-data") == NULL ) return val_null; // extract boundary value { const char *boundary, *bend; if( (boundary = strstr(ctype,"boundary=")) == NULL ) neko_error(); boundary += 9; PARSE_HEADER(boundary,bend); len = (int)(bend - boundary); boundstr = alloc_empty_string(len+2); if( val_strlen(boundstr) > BUFSIZE / 2 ) neko_error(); val_string(boundstr)[0] = '-'; val_string(boundstr)[1] = '-'; memcpy(val_string(boundstr)+2,boundary,len); } len = 0; if( !ap_should_client_block(c->r) ) neko_error(); while( true ) { char *name, *end_name, *filename, *end_file_name, *data; int pos; // refill buffer // we assume here that the the whole multipart header can fit in the buffer fill_buffer(c,buf,&len); // is boundary at the beginning of buffer ? if( len < val_strlen(boundstr) || memcmp(val_string(buf),val_string(boundstr),val_strlen(boundstr)) != 0 ) return discard_body(c); name = memfind(val_string(buf),len,"Content-Disposition:"); if( name == NULL ) break; name = memfind(name,len - (int)(name - val_string(buf)),"name="); if( name == NULL ) return discard_body(c); name += 5; PARSE_HEADER(name,end_name); data = memfind(end_name,len - (int)(end_name - val_string(buf)),"\r\n\r\n"); if( data == NULL ) return discard_body(c); filename = memfind(name,(int)(data - name),"filename="); if( filename != NULL ) { filename += 9; PARSE_HEADER(filename,end_file_name); } data += 4; pos = (int)(data - val_string(buf)); // send part name val_call2(onpart,copy_string(name,(int)(end_name - name)),filename?copy_string(filename,(int)(end_file_name - filename)):val_null); // read data while( true ) { const char *boundary; // recall buffer memmove(val_string(buf),val_string(buf)+pos,len - pos); len -= pos; pos = 0; fill_buffer(c,buf,&len); // lookup bounds boundary = memfind(val_string(buf),len,val_string(boundstr)); if( boundary == NULL ) { if( len == 0 ) return discard_body(c); // send as much buffer as possible to client if( len < BUFSIZE ) pos = len; else pos = len - val_strlen(boundstr) + 1; val_call3(ondata,buf,alloc_int(0),alloc_int(pos)); } else { // send remaining data pos = (int)(boundary - val_string(buf)); val_call3(ondata,buf,alloc_int(0),alloc_int(pos-2)); // recall memmove(val_string(buf),val_string(buf)+pos,len - pos); len -= pos; break; } } } return val_null; }