Exemple #1
0
static value loader_loadprim( value prim, value nargs ) {
	value o = val_this();
	value libs;
	val_check(o,object);
	val_check(prim,string);
	val_check(nargs,int);
	libs = val_field(o,id_loader_libs);
	val_check_kind(libs,k_loader_libs);
	if( val_int(nargs) >= 10 || val_int(nargs) < -1 )
		neko_error();
	{
		neko_vm *vm = NEKO_VM();
		void *ptr = load_primitive(val_string(prim),val_int(nargs),val_field(o,id_path),(liblist**)(void*)&val_data(libs));
		vfunction *f;
		if( ptr == NULL ) {
			buffer b = alloc_buffer("Primitive not found : ");
			val_buffer(b,prim);
			buffer_append(b,"(");
			val_buffer(b,nargs);
			buffer_append(b,")");
			bfailure(b);
		}
		f = (vfunction*)alloc_function(ptr,val_int(nargs),val_string(copy_string(val_string(prim),val_strlen(prim))));
		if( vm->pstats && val_int(nargs) <= 6 ) {
			value env = alloc_array(2);
			val_array_ptr(env)[0] = f->module;
			val_array_ptr(env)[1] = (value)(((int_val)f->addr) | 1);
			f->addr = stats_proxy;
			f->env = env;
		}
		return (value)f;
	}
}
Exemple #2
0
static void report( neko_vm *vm, value exc, int isexc ) {
	int i;
	buffer b = alloc_buffer(NULL);
	value st = neko_exc_stack(vm);
	for(i=0;i<val_array_size(st);i++) {
		value s = val_array_ptr(st)[i];
		buffer_append(b,"Called from ");
		if( val_is_null(s) )
			buffer_append(b,"a C function");
		else if( val_is_string(s) ) {
			buffer_append(b,val_string(s));
			buffer_append(b," (no debug available)");
		} else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) {
			val_buffer(b,val_array_ptr(s)[0]);
			buffer_append(b," line ");
			val_buffer(b,val_array_ptr(s)[1]);
		} else
			val_buffer(b,s);
		buffer_append_char(b,'\n');
	}
	if( isexc )
		buffer_append(b,"Uncaught exception - ");
	val_buffer(b,exc);
#	ifdef NEKO_STANDALONE
	neko_standalone_error(val_string(buffer_to_string(b)));
#	else
	fprintf(stderr,"%s\n",val_string(buffer_to_string(b)));
#	endif
}
Exemple #3
0
EXTERN value neko_select_file( value path, const char *file, const char *ext ) {
	struct stat s;
	value ff;
	buffer b = alloc_buffer(file);
	buffer_append(b,ext);
	ff = buffer_to_string(b);
	if( stat(val_string(ff),&s) == 0 ) {
		char *p = strchr(file,'/');
		if( p == NULL )
			p = strchr(file,'\\');
		if( p != NULL )
			return ff;
		b = alloc_buffer("./");
		buffer_append(b,file);
		buffer_append(b,ext);
		return buffer_to_string(b);
	}
	while( val_is_array(path) && val_array_size(path) == 2 ) {
		value p = val_array_ptr(path)[0];
		buffer b = alloc_buffer(NULL);
		path = val_array_ptr(path)[1];
		val_buffer(b,p);
		val_buffer(b,ff);
		p = buffer_to_string(b);
		if( stat(val_string(p),&s) == 0 )
			return p;
	}
	return ff;
}
Exemple #4
0
/**
	request : 'db -> sql:string -> 'result
	<doc>Executes the SQL request and returns its result</doc>
**/
static value request( value v, value sql ) {
	database *db;
	result *r;
	const char *tl;
	int i,j;
	val_check_kind(v,k_db);
	val_check(sql,string);
	db = val_db(v);
	r = (result*)alloc(sizeof(result));
	r->db = db;
	if( sqlite3_prepare(db->db,val_string(sql),val_strlen(sql),&r->r,&tl) != SQLITE_OK ) {
		buffer b = alloc_buffer("Sqlite error in ");
		val_buffer(b,sql);
		buffer_append(b," : ");
		buffer_append(b,sqlite3_errmsg(db->db));
		val_throw(buffer_to_string(b));
	}
	if( *tl ) {
		sqlite3_finalize(r->r);
		val_throw(alloc_string("Cannot execute several SQL requests at the same time"));
	}
	r->ncols = sqlite3_column_count(r->r);
	r->names = (field*)alloc_private(sizeof(field)*r->ncols);
	r->bools = (int*)alloc_private(sizeof(int)*r->ncols);
	r->first = 1;
	r->done = 0;
	for(i=0;i<r->ncols;i++) {
		field id = val_id(sqlite3_column_name(r->r,i));
		const char *dtype = sqlite3_column_decltype(r->r,i);
		for(j=0;j<i;j++)
			if( r->names[j] == id ) {
				if( strcmp(sqlite3_column_name(r->r,i),sqlite3_column_name(r->r,j)) == 0 ) {
					buffer b = alloc_buffer("Error, same field is two times in the request ");
					val_buffer(b,sql);
					sqlite3_finalize(r->r);
					val_throw(buffer_to_string(b));
				} else {
					buffer b = alloc_buffer("Error, same field ids for : ");
					buffer_append(b,sqlite3_column_name(r->r,i));
					buffer_append(b," and ");
					buffer_append(b,sqlite3_column_name(r->r,j));
					buffer_append_char(b,'.');
					sqlite3_finalize(r->r);
					val_throw(buffer_to_string(b));
				}
			}
		r->names[i] = id;
		r->bools[i] = dtype?(strcmp(dtype,"BOOL") == 0):0;
	}
	// changes in an update/delete
	if( db->last != NULL )
		finalize_result(val_result(db->last),0);
	db->last = alloc_abstract(k_result,r);
	return db->last;
}
Exemple #5
0
value hxfcgi_set_cookie(value hreq, value name, value v) {
	val_check_kind(hreq,hxRequest);
	val_check(name,string);
	val_check(v,string);
	buffer b;
	value str;
	hxfcgi::Request *req = get_request(hreq);
	b = alloc_buffer(NULL);
	val_buffer(b,name);
	buffer_append(b,"=");
	val_buffer(b,v);
	buffer_append(b,";");
	str = buffer_to_string(b);
	req->addHeader("Set-Cookie",val_string(str));
	return val_true;
}
Exemple #6
0
/**
	set_cookie : name:string -> val:string -> void
	<doc>Set a cookie</doc>
**/
static value set_cookie( value name, value v ) {
	mcontext *c = CONTEXT();
	buffer b;
	value str;
	val_check(name,string);
	val_check(v,string);
	HEADERS_NOT_SENT("Cookie");
	b = alloc_buffer(NULL);
	val_buffer(b,name);
	buffer_append(b,"=");
	val_buffer(b,v);
	buffer_append(b,";");
	str = buffer_to_string(b);
	ap_table_add(c->r->headers_out,"Set-Cookie",val_string(str));
	return val_true;
}
Exemple #7
0
/**
	module_read_path : string list -> name:string -> loader:object -> 'module
	<doc>
	Read a module using the specified search path.
	</doc>
**/
static value module_read_path( value path, value name, value loader ) {
	FILE *f;
	value fname;
	char *mname, *ext;
	neko_module *m;
	val_check(name,string);
	val_check(loader,object);
	mname = val_string(name);
	ext = strrchr(mname,'.');
	if( ext && ext[1] == 'n' && ext[2] == 0 )
		fname = neko_select_file(path,mname,"");
	else
		fname = neko_select_file(path,mname,".n");
	f = fopen(val_string(fname),"rb");
	if( f == NULL ) {
		buffer b = alloc_buffer("Module not found : ");
		buffer_append(b,mname);
		bfailure(b);
	}
	m = neko_read_module(neko_file_reader,f,loader);
	fclose(f);
	if( m == NULL ) {
		buffer b = alloc_buffer("Invalid module : ");
		val_buffer(b,name);
		bfailure(b);
	}
	m->name = alloc_string(val_string(name));
	return alloc_abstract(neko_kind_module,m);
}
Exemple #8
0
/**
	result_next : 'result -> object?
	<doc>Returns the next row in the result or [null] if no more result.</doc>
**/
static value result_next( value v ) {
	int i;
	result *r;
	val_check_kind(v,k_result);
	r = val_result(v);
	if( r->done )
		return val_null;
	switch( sqlite3_step(r->r) ) {
	case SQLITE_ROW:
		r->first = 0;
		v = alloc_object(NULL);
		for(i=0;i<r->ncols;i++) {
			value f;
			switch( sqlite3_column_type(r->r,i) ) {
			case SQLITE_NULL:
				f = val_null;
				break;
			case SQLITE_INTEGER:
				if( r->bools[i] )
					f = alloc_bool(sqlite3_column_int(r->r,i));
				else
					f = alloc_int(sqlite3_column_int(r->r,i));
				break;
			case SQLITE_FLOAT:
				f = alloc_float(sqlite3_column_double(r->r,i));
				break;
			case SQLITE_TEXT:
				f = alloc_string((char*)sqlite3_column_text(r->r,i));
				break;
			case SQLITE_BLOB:
				{
					int size = sqlite3_column_bytes(r->r,i);
					f = alloc_empty_string(size);
					memcpy(val_string(f),sqlite3_column_blob(r->r,i),size);
					break;
				}
			default:
				{
					buffer b = alloc_buffer("Unknown Sqlite type #");
					val_buffer(b,alloc_int(sqlite3_column_type(r->r,i)));
					val_throw(buffer_to_string(b));
				}
			}
			alloc_field(v,r->names[i],f);
		}
		return v;
	case SQLITE_DONE:
		finalize_result(r,1);
		return val_null;
	case SQLITE_BUSY:
		val_throw(alloc_string("Database is busy"));
	case SQLITE_ERROR:
		sqlite_error(r->db->db);
	default:
		neko_error();
	}
	return val_null;
}
Exemple #9
0
/**
	put_env : var:string -> val:string -> void
	<doc>Set some environment variable value</doc>
**/
static value put_env( value e, value v ) {
#ifdef NEKO_WINDOWS
	buffer b;
	val_check(e,string);
	val_check(v,string);
	b = alloc_buffer(NULL);
	val_buffer(b,e);
	buffer_append_sub(b,"=",1);
	val_buffer(b,v);
	if( putenv(val_string(buffer_to_string(b))) != 0 )
		neko_error();
#else
	val_check(e,string);
	val_check(v,string);
	if( setenv(val_string(e),val_string(v),1) != 0 )
		neko_error();
#endif
	return val_true;
}
Exemple #10
0
static void report( neko_vm *vm, value exc ) {
#if OSX
	CFStringRef title = CFSTR("Uncaught exception");
	CFStringRef message;
#endif
	int i = 0;
	buffer b = alloc_buffer(NULL);
	value st = neko_exc_stack(vm);
	if( val_array_size(st) > 20 ) {
		i = val_array_size(st) - 20;
		buffer_append(b,"...\n");
	}
	for(i;i<val_array_size(st);i++) {
		value s = val_array_ptr(st)[i];
		if( val_is_null(s) )
			buffer_append(b,"Called from a C function\n");
		else if( val_is_string(s) ) {
			buffer_append(b,"Called from ");
			buffer_append(b,val_string(s));
			buffer_append(b," (no debug available)\n");
		} else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) ) {
			buffer_append(b,"Called from ");
			buffer_append(b,val_string(val_array_ptr(s)[0]));
			buffer_append(b," line ");
			val_buffer(b,val_array_ptr(s)[1]);
			buffer_append(b,"\n");
		} else {
			buffer_append(b,"Called from ");
			val_buffer(b,s);
			buffer_append(b,"\n");
		}
	}
	val_buffer(b,exc);
#if _WIN32
	MessageBox(NULL,val_string(buffer_to_string(b)),"Uncaught exception",MB_OK | MB_ICONERROR);
#elif OSX
	message = CFStringCreateWithCString(NULL,val_string(buffer_to_string(b)), kCFStringEncodingUTF8);
	CFUserNotificationDisplayNotice(0,0,NULL,NULL,NULL,title,message,NULL);
#elif LINUX
	fprintf(stderr,"Uncaught Exception: %s\n",val_string(buffer_to_string(b)));
#endif
}
Exemple #11
0
static void zlib_error( z_stream *z, int err ) {
	buffer b = alloc_buffer("ZLib Error : ");
	if( z && z->msg ) {
		buffer_append(b,z->msg);
		buffer_append(b," (");
	}
	val_buffer(b,alloc_int(err));
	if( z && z->msg )
		buffer_append_char(b,')');
	val_throw(buffer_to_string(b));
}
/**
	regexp_new_options : reg:string -> options:string -> 'regexp
	<doc>Build a new regexpr with the following options :
	<ul>
		<li>i : case insensitive matching</li>
		<li>s : . match anything including newlines</li>
		<li>m : treat the input as a multiline string</li>
		<li>u : run in utf8 mode</li>
		<li>g : turn off greedy behavior</li>
	</ul>
	</doc>
**/
static value regexp_new_options( value s, value opt ) {
	val_check(s,string);
	val_check(opt,string);
	{
		value v;
		const char *error;
		int err_offset;
		pcre *p;
		pcredata *pdata;
		const char *o = val_string(opt);
		int options = 0;
		while( *o ) {
			switch( *o++ ) {
			case 'i':
				options |= PCRE_CASELESS;
				break;
			case 's':
				options |= PCRE_DOTALL;
				break;
			case 'm':
				options |= PCRE_MULTILINE;
				break;
			case 'u':
				options |= PCRE_UTF8;
				break;
			case 'g':
				options |= PCRE_UNGREEDY;
				break;
			default:
				return alloc_null();
				break;
			}
		}
		p = pcre_compile(val_string(s),options,&error,&err_offset,NULL);
		if( p == NULL ) {
			buffer b = alloc_buffer("Regexp compilation error : ");
			buffer_append(b,error);
			buffer_append(b," in ");
			val_buffer(b,s);
			bfailure(b);
		}
		v = alloc_abstract(k_regexp,malloc(sizeof(pcredata)));
		pdata = PCRE(v);
		pdata->r = p;
		pdata->str = alloc_null();
                val_gc_add_root(&pdata->str);
		pdata->nmatchs = 0;
		pcre_fullinfo(p,NULL,PCRE_INFO_CAPTURECOUNT,&pdata->nmatchs);
		pdata->nmatchs++;
		pdata->matchs = (int*)malloc(sizeof(int) * 3 * pdata->nmatchs);
		val_gc(v,free_regexp);
		return v;
	}	
}
Exemple #13
0
/**
	put_env : var:string -> val:string -> void
	<doc>Set some environment variable value</doc>
**/
static value put_env( value e, value v ) {
#ifdef HX_WINRT
   // Do nothing
	return alloc_null();
#elif defined(NEKO_WINDOWS)
	val_check(e,string);
	val_check(v,string);
	buffer b = alloc_buffer(0);
	val_buffer(b,e);
	buffer_append_sub(b,"=",1);
	val_buffer(b,v);
	if( putenv(buffer_data(b)) != 0 )
		return alloc_null();
#else
	val_check(e,string);
	val_check(v,string);
	if( setenv(val_string(e),val_string(v),1) != 0 )
		return alloc_null();
#endif
	return alloc_bool(true);
}
Exemple #14
0
static void val_buffer_fields( value v, field f, void *_l ) {
	vlist2 *l = (vlist2*)_l;
	if( l->prev )
		buffer_append_sub(l->b,", ",2);
	else {
		buffer_append_sub(l->b," ",1);
		l->prev = 1;
	}
	val_buffer(l->b,val_field_name(f));
	buffer_append_sub(l->b," => ",4);
	val_buffer_rec(l->b,v,(vlist*)l);
}
Exemple #15
0
static value alloc_result( connection *c, MYSQL_RES *r ) {
	result *res = (result*)alloc(sizeof(result));
	value o = alloc_abstract(k_result,res);
	int num_fields = mysql_num_fields(r);
	int i,j;
	MYSQL_FIELD *fields = mysql_fetch_fields(r);
	res->r = r;
	res->conv_date = c->conv_date;
	res->conv_bytes = c->conv_bytes;
	res->conv_string = c->conv_string;
	res->current = NULL;
	res->nfields = num_fields;
	res->fields_ids = (field*)alloc_private(sizeof(field)*num_fields);
	res->fields_convs = (CONV*)alloc_private(sizeof(CONV)*num_fields);	
	for(i=0;i<num_fields;i++) {
		field id;
		if( strchr(fields[i].name,'(') )
			id = val_id("???"); // looks like an inner request : prevent hashing + cashing it
		else {
			id = val_id(fields[i].name);
			for(j=0;j<i;j++)
				if( res->fields_ids[j] == id ) {
					buffer b = alloc_buffer("Error, same field ids for : ");
					buffer_append(b,fields[i].name);
					buffer_append(b,":");
					val_buffer(b,alloc_int(i));
					buffer_append(b," and ");
					buffer_append(b,fields[j].name);
					buffer_append(b,":");
					val_buffer(b,alloc_int(j));
					buffer_append(b,".");
					bfailure(b);
				}
		}
		res->fields_ids[i] = id;
		res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length);
	}
	val_gc(o,free_result);
	return o;
}
Exemple #16
0
/**
	$print : any* -> void
	<doc>Can print any value</doc>
**/
static value builtin_print( value *args, int nargs ) {
	buffer b;
	int i;
	if( nargs == 1 && val_is_string(*args) ) {
		val_print(*args);
		return neko_builtins[1];
	}
	b = alloc_buffer(NULL);
	for(i=0;i<nargs;i++)
		val_buffer(b,args[i]);
	val_print(buffer_to_string(b));
	return neko_builtins[1];
}
Exemple #17
0
static void thread_loop( void *_p ) {
	tparams *p = (tparams*)_p;
	value exc = NULL;
	val_callEx(val_null,p->callb,&p->callparam,1,&exc);
	// display exception
	if( exc != NULL ) {
		buffer b = alloc_buffer(NULL);
		fprintf(stderr,"An exception occured in a neko Thread :\n");
		val_buffer(b,exc);
		fprintf(stderr,"%s\n",val_string(buffer_to_string(b)));
	}
	// cleanup
	neko_vm_select(NULL);
	p->t->v = val_null;
	p->t->vm = NULL;
}
Exemple #18
0
static void xml_error( const char *xml, const char *p, int *line, const char *msg ) {
	buffer b = alloc_buffer("Xml parse error : ");
	int l = (int)strlen(p);
	int nchars = 30;
	buffer_append(b,msg);
	buffer_append(b," at line ");
	val_buffer(b,alloc_int(*line));
	buffer_append(b," : ");
	if( p != xml )
		buffer_append(b,"...");
	buffer_append_sub(b,p,(l < nchars)?l:nchars);
	if( l > nchars )
		buffer_append(b,"...");
	if( l == 0 )
		buffer_append(b,"<eof>");
	bfailure(b);
}
Exemple #19
0
static void preload_module( const char *name, server_rec *serv ) {
	value exc = NULL;
	neko_vm *vm = neko_vm_alloc(NULL);
	value mload = neko_default_loader(NULL,0);
	value m, read_path, exec;
	time_t time = 0;
	neko_vm_select(vm);
	if( config.use_jit ) neko_vm_jit(vm,1);
	if( !exc ) {
		value args[] = { alloc_string("std@module_read_path"), alloc_int(3) };
		read_path = val_callEx(mload,val_field(mload,val_id("loadprim")),args,2,&exc);
	}
	if( !exc ) {
		value args[] = { alloc_string("std@module_exec"), alloc_int(1) };
		exec = val_callEx(mload,val_field(mload,val_id("loadprim")),args,2,&exc);
	}
	if( !exc ) {
		value args[] = { val_null, alloc_string(name), mload };
		char *p = strrchr(val_string(args[1]),'.');
		if( p != NULL ) *p = 0;
		m = val_callEx(mload,read_path,args,3,&exc);
	}
	if( !exc ) {
		struct stat t;
		if( stat(name,&t) )
			exc = alloc_string("failed to stat()");
		else
			time = t.st_mtime;
	}
	if( !exc ) {
		value f = alloc_function(init_module,0,"init_module");
		value env = alloc_array(2);
		val_array_ptr(env)[0] = exec;
		val_array_ptr(env)[1] = m;
		((vfunction*)f)->env = env;
		cache_module(name,time,f);
	}
	if( exc ) {
		buffer b = alloc_buffer(NULL);
		val_buffer(b,exc);
		ap_log_error(APLOG_MARK,APLOG_WARNING,LOG_SUCCESS serv,"Failed to preload module '%s' : %s",name,val_string(buffer_to_string(b)));
	}
	neko_vm_select(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);
	}
}
Exemple #21
0
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;
	}
}
Exemple #22
0
/**
	sprintf : fmt:string -> params:(any | array) -> string
	<doc>
	Format a string. If only one parameter is needed then it can be
	directly passed, either the parameters need to be stored in an array.
	The following formats are accepted (with corresponding types) :
	<ul>
		<li>[%s] : string</li>
		<li>[%d] [%x] [%X] : int</li>
		<li>[%c] : int in the 0..255 range</li>
		<li>[%b] : bool</li>
		<li>[%f] : float</li>
	</ul>
	</doc>
**/
static value neko_sprintf( value fmt, value params ) {
	const char *last, *cur, *end;
	int count = 0;
	buffer b;
	val_check(fmt,string);
	b = alloc_buffer(0);
	last = val_string(fmt);
	cur = last;
	end = cur + val_strlen(fmt);
	while( cur != end ) {
		if( *cur == '%' ) {
			int width = 0, prec = 0, flags = 0;
			buffer_append_sub(b,last,cur - last);
			cur++;
			while( *cur >= '0' && *cur <= '9' ) {
				width = width * 10 + (*cur - '0');
				cur++;
			}
			if( *cur == '.' ) {
				cur++;
				while( *cur >= '0' && *cur <= '9' ) {
					prec = prec * 10 + (*cur - '0');
					cur++;
				}
			}
			if( *cur == '%' ) {
				buffer_append_sub(b,"%",1);
				cur++;
			} else {
				value param;
				if( count == 0 && !val_is_array(params) ) { // first ?
					param = params;
					count++;
				} else if( !val_is_array(params) || val_array_size(params) <= count )
					return alloc_null();
				else
					param = val_array_i(params,count++);
				switch( *cur ) {
				case 'c':
					{
						int c;
						char cc;
						val_check(param,int);
						c = val_int(param);
						if( c < 0 || c > 255 )
							return alloc_null();
						cc = (char)c;
						buffer_append_sub(b,&cc,1);
					}
					break;
				case 'x':
					flags |= HEX_SMALL;
				case 'X':
					flags |= HEX;
				case 'd':
					{
						char tmp[10];
						int sign = 0;
						int size = 0;
						int tsize;
						int n;
						val_check(param,int);
						n = val_int(param);
						if( !(flags & HEX) && n < 0 ) {
							sign++;
							prec--;
							n = -n;
						} else if( n == 0 )
							tmp[9-size++] = '0';
						if( flags & HEX ) {
							unsigned int nn = (unsigned int)n;
							while( nn > 0 ) {
								int k = nn&15;
								if( k < 10 )
									tmp[9-size++] = k + '0';
								else
									tmp[9-size++] = (k - 10) + ((flags & HEX_SMALL)?'a':'A');
								nn = nn >> 4;
							}
						} else {
							while( n > 0 ) {
								tmp[9-size++] = (n % 10) + '0';
								n = n / 10;
							}
						}
						tsize = (size > prec)?size:prec + sign;
						while( width > tsize ) {
							width--;
							buffer_append_sub(b," ",1);
						}
						if( sign )
							buffer_append_sub(b,"-",1);
						while( prec > size ) {
							prec--;
							buffer_append_sub(b,"0",1);
						}
						buffer_append_sub(b,tmp+10-size,size);
					}
					break;
				case 'f':
					{
						val_check(param,float);
						val_buffer(b,param);
					}
					break;
				case 's':
					{
						int size;
						int tsize;
						val_check(param,string);
						size = val_strlen(param);
						tsize = (size > prec)?size:prec;
						while( width > tsize ) {
							width--;
							buffer_append_sub(b," ",1);
						}
						while( prec > size ) {
							prec--;
							buffer_append_sub(b," ",1);
						}
						buffer_append_sub(b,val_string(param),size);
					}
					break;
				case 'b':
					{
						val_check(param,bool);
						buffer_append_sub(b,val_bool(param)?"true":"false",val_bool(param)?4:5);
					}
					break;
				default:
					return alloc_null();
					break;
				}
			}
Exemple #23
0
/**
	process_run : cmd:string -> args:string array -> 'process
	<doc>
	Start a process using a command and the specified arguments.
	</doc>
**/
static value process_run( value cmd, value vargs ) {
	int i;
	vprocess *p;
	val_check(cmd,string);
	val_check(vargs,array);
#	ifdef NEKO_WINDOWS
	{		 
		SECURITY_ATTRIBUTES sattr;		
		STARTUPINFO sinf;
		HANDLE proc = GetCurrentProcess();
		HANDLE oread,eread,iwrite;
		// creates commandline
		buffer b = alloc_buffer(NULL);
		value sargs;
		buffer_append_char(b,'"');
		val_buffer(b,cmd);
		buffer_append_char(b,'"');
		for(i=0;i<val_array_size(vargs);i++) {
			value v = val_array_ptr(vargs)[i];
			int j,len;
			val_check(v,string);
			len = val_strlen(v);
			buffer_append(b," \"");
			for(j=0;j<len;j++) {
				char c = val_string(v)[j];
				switch( c ) {
				case '"':
					buffer_append(b,"\\\"");
					break;
				case '\\':
					buffer_append(b,"\\\\");
					break;
				default:
					buffer_append_char(b,c);
					break;
				}
			}
			buffer_append_char(b,'"');
		}
		sargs = buffer_to_string(b);
		p = (vprocess*)alloc_private(sizeof(vprocess));
		// startup process
		sattr.nLength = sizeof(sattr);
		sattr.bInheritHandle = TRUE;
		sattr.lpSecurityDescriptor = NULL;
		memset(&sinf,0,sizeof(sinf));
		sinf.cb = sizeof(sinf);
		sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
		sinf.wShowWindow = SW_HIDE;
		CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
		CreatePipe(&eread,&sinf.hStdError,&sattr,0);
		CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
		DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS);
		DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS);
		DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
		CloseHandle(oread);
		CloseHandle(eread);
		CloseHandle(iwrite);
		if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) )			
			neko_error();
		// close unused pipes
		CloseHandle(sinf.hStdOutput);
		CloseHandle(sinf.hStdError);
		CloseHandle(sinf.hStdInput);
	}
#	else
	char **argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2));
	argv[0] = val_string(cmd);
	for(i=0;i<val_array_size(vargs);i++) {
		value v = val_array_ptr(vargs)[i];
		val_check(v,string);
		argv[i+1] = val_string(v);
	}
	argv[i+1] = NULL;
	int input[2], output[2], error[2];
	if( pipe(input) || pipe(output) || pipe(error) )
		neko_error();
	p = (vprocess*)alloc_private(sizeof(vprocess));
	p->pid = fork();
	if( p->pid == -1 ) {
		do_close(input[0]);
		do_close(input[1]);
		do_close(output[0]);
		do_close(output[1]);
		do_close(error[0]);
		do_close(error[1]);
		neko_error();
	}
	// child
	if( p->pid == 0 ) {
		close(input[1]);
		close(output[0]);
		close(error[0]);
		dup2(input[0],0);
		dup2(output[1],1);
		dup2(error[1],2);
		execvp(val_string(cmd),argv);
		fprintf(stderr,"Command not found : %s\n",val_string(cmd));
		exit(1);
	}
	// parent
	do_close(input[0]);
	do_close(output[1]);
	do_close(error[1]);
	p->iwrite = input[1];
	p->oread = output[0];
	p->eread = error[0];
#	endif
	{
		value vp = alloc_abstract(k_process,p);
		val_gc(vp,free_process);
		return vp;
	}
}
Exemple #24
0
/**
	process_run : cmd:string -> args:string array -> 'process
	<doc>
	Start a process using a command and the specified arguments.
	When args is not null, cmd and args will be auto-quoted/escaped.
	If no auto-quoting/escaping is desired, you should append necessary 
	arguments to cmd as if it is inputted to the shell directly, and pass
	null as args.
	</doc>
**/
static value process_run( value cmd, value vargs ) {
	int i, isRaw;
	vprocess *p;
	val_check(cmd,string);
	isRaw = val_is_null(vargs);
	if (!isRaw) {
		val_check(vargs,array);
	}
#	ifdef NEKO_WINDOWS
	{		 
		SECURITY_ATTRIBUTES sattr;		
		STARTUPINFO sinf;
		HANDLE proc = GetCurrentProcess();
		HANDLE oread,eread,iwrite;
		// creates commandline
		buffer b = alloc_buffer(NULL);
		value sargs;
		if (isRaw) {
			char* cmdexe = getenv("COMSPEC");
			if (!cmdexe) cmdexe = "cmd.exe";
			buffer_append(b,"\"");
			buffer_append(b,cmdexe);
			buffer_append(b,"\" /C \"");
			buffer_append(b,val_string(cmd));
			buffer_append_char(b,'"');
		} else {
			buffer_append_char(b,'"');
			val_buffer(b,cmd);
			buffer_append_char(b,'"');
			for(i=0;i<val_array_size(vargs);i++) {
				value v = val_array_ptr(vargs)[i];
				int j,len;
				unsigned int bs_count = 0;
				unsigned int k;
				val_check(v,string);
				len = val_strlen(v);
				buffer_append(b," \"");
				for(j=0;j<len;j++) {
					char c = val_string(v)[j];
					switch( c ) {
					case '"':
						// Double backslashes.
						for (k=0;k<bs_count*2;k++) {
							buffer_append_char(b,'\\');
						}
						bs_count = 0;
						buffer_append(b, "\\\"");
						break;
					case '\\':
						// Don't know if we need to double yet.
						bs_count++;
						break;
					default:
						// Normal char
						for (k=0;k<bs_count;k++) {
							buffer_append_char(b,'\\');
						}
						bs_count = 0;
						buffer_append_char(b,c);
						break;
					}
				}
				// Add remaining backslashes, if any.
				for (k=0;k<bs_count*2;k++) {
					buffer_append_char(b,'\\');
				}
				buffer_append_char(b,'"');
			}
		}
		sargs = buffer_to_string(b);
		p = (vprocess*)alloc_private(sizeof(vprocess));
		// startup process
		sattr.nLength = sizeof(sattr);
		sattr.bInheritHandle = TRUE;
		sattr.lpSecurityDescriptor = NULL;
		memset(&sinf,0,sizeof(sinf));
		sinf.cb = sizeof(sinf);
		sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
		sinf.wShowWindow = SW_HIDE;
		CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
		CreatePipe(&eread,&sinf.hStdError,&sattr,0);
		CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
		DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS);
		DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS);
		DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
		CloseHandle(oread);
		CloseHandle(eread);
		CloseHandle(iwrite);
		if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) )			
			neko_error();
		// close unused pipes
		CloseHandle(sinf.hStdOutput);
		CloseHandle(sinf.hStdError);
		CloseHandle(sinf.hStdInput);
	}
#	else
	char **argv;
	if (isRaw) {
		argv = (char**)alloc_private(sizeof(char*)*4);
		argv[0] = "/bin/sh";
		argv[1] = "-c";
		argv[2] = val_string(cmd);
		argv[3] = NULL;
	} else {
		argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2));
		argv[0] = val_string(cmd);
		for(i=0;i<val_array_size(vargs);i++) {
			value v = val_array_ptr(vargs)[i];
			val_check(v,string);
			argv[i+1] = val_string(v);
		}
		argv[i+1] = NULL;
	}
	int input[2], output[2], error[2];
	if( pipe(input) || pipe(output) || pipe(error) )
		neko_error();
	p = (vprocess*)alloc_private(sizeof(vprocess));
	p->pid = fork();
	if( p->pid == -1 ) {
		do_close(input[0]);
		do_close(input[1]);
		do_close(output[0]);
		do_close(output[1]);
		do_close(error[0]);
		do_close(error[1]);
		neko_error();
	}
	// child
	if( p->pid == 0 ) {
		close(input[1]);
		close(output[0]);
		close(error[0]);
		dup2(input[0],0);
		dup2(output[1],1);
		dup2(error[1],2);
		execvp(argv[0],argv);
		fprintf(stderr,"Command not found : %s\n",val_string(cmd));
		exit(1);
	}
	// parent
	do_close(input[0]);
	do_close(output[1]);
	do_close(error[1]);
	p->iwrite = input[1];
	p->oread = output[0];
	p->eread = error[0];
#	endif
	{
		value vp = alloc_abstract(k_process,p);
		val_gc(vp,free_process);
		return vp;
	}
}
Exemple #25
0
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;
	}
}
Exemple #26
0
/**
   process_run : cmd:string -> args:string array -> 'process
   <doc>
   Start a process using a command and the specified arguments.
   </doc>
**/
static value process_run( value cmd, value vargs ) {
   int i;
   vprocess *p;
   val_check(cmd,string);
   val_check(vargs,array);
#   ifdef NEKO_WINDOWS
   {       
      SECURITY_ATTRIBUTES sattr;      
      STARTUPINFOW sinf;
      HANDLE proc = GetCurrentProcess();
      HANDLE oread,eread,iwrite;
      // creates commandline
      buffer b = alloc_buffer("\"");
      val_buffer(b,cmd);
      buffer_append(b,"\"");

      int n = val_array_size(vargs);
      for(i=0;i<n;i++) {
         value v = val_array_i(vargs,i);
         val_check(v,string);
         buffer_append(b," \"");
         val_buffer(b,v);
         buffer_append(b,"\"");
      }
      wchar_t *name = val_dup_wstring(buffer_to_string(b));
      gc_enter_blocking();
      p = (vprocess*)malloc(sizeof(vprocess));
      // startup process
      sattr.nLength = sizeof(sattr);
      sattr.bInheritHandle = TRUE;
      sattr.lpSecurityDescriptor = NULL;
      memset(&sinf,0,sizeof(sinf));
      sinf.cb = sizeof(sinf);
      sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
      sinf.wShowWindow = SW_NORMAL;
      CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
      CreatePipe(&eread,&sinf.hStdError,&sattr,0);
      CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
      DuplicateHandle(proc,oread,proc,&p->oread,0,FALSE,DUPLICATE_SAME_ACCESS);
      DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS);
      DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
      CloseHandle(oread);
      CloseHandle(eread);
      CloseHandle(iwrite);
      //printf("Cmd %s\n",val_string(cmd));
      if( !CreateProcessW(NULL,name,NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) )
      {
         free(p);
         gc_exit_blocking();
			val_throw(alloc_null());
         return alloc_null();
      }
      // close unused pipes
      CloseHandle(sinf.hStdOutput);
      CloseHandle(sinf.hStdError);
      CloseHandle(sinf.hStdInput);
      gc_exit_blocking();
   }
#else
   char **argv = (char**)malloc(sizeof(char*)*(val_array_size(vargs)+2));

   argv[0] = strdup(val_string(cmd));
   for(i=0;i<val_array_size(vargs);i++) {
      value v = val_array_i(vargs,i);
      val_check(v,string);
      argv[i+1] = strdup(val_string(v));
   }
   argv[i+1] = NULL;
   int input[2], output[2], error[2];
   if( pipe(input) || pipe(output) || pipe(error) )
      return alloc_null();
   p = (vprocess*)malloc(sizeof(vprocess));
   p->pid = fork();
   if( p->pid == -1 )
      return alloc_null();
   gc_enter_blocking();
   // child
   if( p->pid == 0 ) {
      close(input[1]);
      close(output[0]);
      close(error[0]);
      dup2(input[0],0);
      dup2(output[1],1);
      dup2(error[1],2);
      execvp(val_string(cmd),argv);
      fprintf(stderr,"Command not found : %s\n",val_string(cmd));
      exit(1);
   }
   // parent
   for(i=0;i<=val_array_size(vargs);i++)
           free(argv[i]);
        free(argv);
   do_close(input[0]);
   do_close(output[1]);
   do_close(error[1]);
   p->iwrite = input[1];
   p->oread = output[0];
   p->eread = error[0];
   gc_exit_blocking();
#   endif
   {
      value vp = alloc_abstract(k_process,p);
      val_gc(vp,free_process);
      return vp;
   }
}
Exemple #27
0
void ft_failure_v( const char *one, value v ) {
    buffer b = alloc_buffer(one);
    val_buffer(b,v);
    val_throw(buffer_to_string(b));
}
Exemple #28
0
/**
	$string : any -> string
	<doc>Convert any value to a string. This will make a copy of string.</doc>
**/
static value builtin_string( value v ) {
	buffer b = alloc_buffer(NULL);
	val_buffer(b,v);
	return buffer_to_string(b);
}
Exemple #29
0
/**
	buffer_add : 'buffer -> any -> void
	<doc>Add a value to a buffer</doc>
**/
static value buffer_add( value b, value v ) {
	val_check_kind(b,k_buffer);
	val_buffer( (buffer)val_data(b), v );
	return val_true;
}
Exemple #30
0
static int neko_handler_rec( request_rec *r ) {
	mcontext ctx;
	neko_vm *vm;
	const char *ctype;
	value exc = NULL;

/*
	Seems to crash on Windows. And on Linux, we rarely have libGC 7.x installed anyway

#	if defined(APACHE_2_X) || defined(NEKO_WINDOWS)
	// we are using threads, so let's make sure that the current thread is registered
	neko_thread_register(true);
#	endif
*/

	config.hits++;

	ctx.r = r;
	ctx.main = cache_find(r);
	ctx.post_data = val_null;
	ctx.headers_sent = false;
	ctx.content_type = alloc_string("text/html");
    r->content_type = val_string(ctx.content_type);

	if( ap_setup_client_block(r,REQUEST_CHUNKED_ERROR) != 0 ) {
		send_headers(&ctx);
		apache_error(APLOG_WARNING,r,"ap_setup_client_block failed");
		return OK;
	}

	ctype = ap_table_get(r->headers_in,"Content-Type");
	if( (!ctype || strstr(ctype,"multipart/form-data") == NULL) && ap_should_client_block(r) ) {
#		define MAXLEN 1024
		char buf[MAXLEN];
		int len;
		int tlen = 0;
		buffer b = alloc_buffer(NULL);
		while( (len = ap_get_client_block(r,buf,MAXLEN)) > 0 ) {
			if( tlen < config.max_post_size )
				buffer_append_sub(b,buf,len);
			tlen += len;
		}
		if( tlen >= config.max_post_size ) {
			send_headers(&ctx);
			apache_error(APLOG_WARNING,r,"Maximum POST data exceeded. Try using multipart encoding");
			return OK;
		}
		ctx.post_data = buffer_to_string(b);
	}

	vm = neko_vm_alloc(NULL);
	if( config.use_stats ) neko_vm_set_stats(vm,neko_stats_measure,config.use_prim_stats?neko_stats_measure:NULL);

	neko_vm_set_custom(vm,k_mod_neko,&ctx);
	if( config.use_jit && !neko_vm_jit(vm,1) ) {
		send_headers(&ctx);
		apache_error(APLOG_WARNING,r,"JIT required by env. var but not enabled in NekoVM");
		return OK;
	}

	neko_vm_redirect(vm,request_print,&ctx);
	neko_vm_select(vm);

	if( ctx.main != NULL ) {
		value old = ctx.main;
		if( config.use_stats ) neko_stats_measure(vm,r->filename,1);
		val_callEx(val_null,old,NULL,0,&exc);
		if( config.use_stats ) neko_stats_measure(vm,r->filename,0);
		if( old != ctx.main ) cache_module(r->filename,FTIME(r),ctx.main);
	} else {
		char *base_uri = request_base_uri(r);
		value mload = neko_default_loader(&base_uri,1);
		value args[] = { alloc_string(r->filename), mload };
		char *p = strrchr(val_string(args[0]),'.');
		if( p != NULL )
			*p = 0;
		val_callEx(mload,val_field(mload,val_id("loadmodule")),args,2,&exc);
		if( ctx.main != NULL && config.use_cache )
			cache_module(r->filename,FTIME(r),ctx.main);
	}

	if( exc != NULL ) {
		buffer b = alloc_buffer(NULL);
		value v;
		int i;
		const char *p, *start;
		value st = neko_exc_stack(vm);
		val_buffer(b,exc);
		config.exceptions++;
		ap_soft_timeout("Client Timeout",r);
		send_headers(&ctx);
		v = buffer_to_string(b);
		p = val_string(v);
		start = p;
		ap_rprintf(r,"Uncaught exception - ");
		while( *p ) {
			if( *p == '<' || *p == '>' ) {
				ap_rwrite(start,(int)(p - start),r);
				ap_rwrite((*p == '<')?"&lt;":"&gt;",4, r);
				start = p + 1;
			}
			p++;
		}
		ap_rwrite(start,(int)(p - start),r);
		ap_rprintf(r,"<br/><br/>");
		for(i=0;i<val_array_size(st);i++) {
			value s = val_array_ptr(st)[i];
			if( val_is_null(s) )
				ap_rprintf(r,"Called from a C function<br/>");
			else if( val_is_string(s) ) {
				ap_rprintf(r,"Called from %s (no debug available)<br/>",val_string(s));
			} else if( val_is_array(s) && val_array_size(s) == 2 && val_is_string(val_array_ptr(s)[0]) && val_is_int(val_array_ptr(s)[1]) )
				ap_rprintf(r,"Called from %s line %d<br/>",val_string(val_array_ptr(s)[0]),val_int(val_array_ptr(s)[1]));
			else {
				b = alloc_buffer(NULL);
				val_buffer(b,s);
				ap_rprintf(r,"Called from %s<br/>",val_string(buffer_to_string(b)));
			}
		}
		ap_kill_timeout(r);
		return OK;
	}

	send_headers(&ctx);
    return OK;
}