static int throw_handler( int code ) { switch( code ) { case EXCEPTION_ACCESS_VIOLATION: hl_error("Access violation"); case EXCEPTION_STACK_OVERFLOW: hl_error("Stack overflow"); default: hl_error("Unknown runtime error"); } return EXCEPTION_CONTINUE_SEARCH; }
HL_PRIM vdynamic *hl_dyn_call( vclosure *c, vdynamic **args, int nargs ) { struct { varray a; vdynamic *args[HL_MAX_ARGS+1]; } tmp; vclosure ctmp; int i = 0; if( nargs > HL_MAX_ARGS ) hl_error("Too many arguments"); tmp.a.t = &hlt_array; tmp.a.at = &hlt_dyn; tmp.a.size = nargs; if( c->hasValue && c->t->fun->nargs >= 0 ) { ctmp.t = c->t->fun->parent; ctmp.hasValue = 0; ctmp.fun = c->fun; tmp.args[0] = hl_make_dyn(&c->value,ctmp.t->fun->args[0]); tmp.a.size++; for(i=0;i<nargs;i++) tmp.args[i+1] = args[i]; c = &ctmp; } else { for(i=0;i<nargs;i++) tmp.args[i] = args[i]; } return hl_call_method((vdynamic*)c,&tmp.a); }
/** result_next : 'result -> object? <doc>Returns the next row in the result or [null] if no more result.</doc> **/ HL_PRIM varray *HL_NAME(result_next)( sqlite_result *r ) { if( r->done ) return NULL; switch( sqlite3_step(r->r) ) { case SQLITE_ROW: r->first = 0; varray *a = hl_alloc_array(&hlt_dyn, r->ncols); int i; for(i=0;i<r->ncols;i++) { vdynamic *v; switch( sqlite3_column_type(r->r,i) ) { case SQLITE_NULL: v = NULL; break; case SQLITE_INTEGER: { int vint = sqlite3_column_int(r->r, i); if (r->bools[i]) v = hl_make_dyn(&vint, &hlt_bool); else v = hl_make_dyn(&vint, &hlt_i32); break; } case SQLITE_FLOAT: { double d = sqlite3_column_double(r->r, i); v = hl_make_dyn(&d, &hlt_f64); break; } case SQLITE_TEXT: { uchar *text16 = (uchar *)sqlite3_column_text16(r->r, i); v = hl_make_dyn(&text16, &hlt_bytes); break; } case SQLITE_BLOB: { vbyte *blob = (vbyte *)sqlite3_column_blob(r->r, i); v = hl_make_dyn(&blob, &hlt_bytes); break; } default: hl_error_msg(USTR("SQLite error: Unknown type #%d"), sqlite3_column_type(r->r,i)); } hl_aptr(a, vdynamic*)[i] = v; } return a; case SQLITE_DONE: HL_NAME(finalize_request)(r, true); return NULL; case SQLITE_BUSY: hl_error("SQLite error: Database is busy"); case SQLITE_ERROR: HL_NAME(error)(r->db->db, false); default: return NULL; } return NULL; }
HL_PRIM int hl_date_from_string( vbyte *b, int len ) { struct tm t; int o = 0; const char *str = hl_to_utf8((uchar*)b); bool recal = true; memset(&t,0,sizeof(struct tm)); switch( strlen(str) ) { case 19: sscanf(str,"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); t.tm_isdst = -1; break; case 8: sscanf(str,"%2d:%2d:%2d",&t.tm_hour,&t.tm_min,&t.tm_sec); o = t.tm_sec + t.tm_min * 60 + t.tm_hour * 60 * 60; recal = false; break; case 10: sscanf(str,"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday); t.tm_isdst = -1; break; default: hl_error("Invalid date format"); break; } if( recal ) { t.tm_year -= 1900; t.tm_mon--; o = (int)mktime(&t); } return o; }
HL_PRIM bool HL_NAME(png_decode)( vbyte *data, int dataLen, vbyte *out, int width, int height, int stride, int format, int flags ) { # ifdef PNG_IMAGE_VERSION png_image img; memset(&img, 0, sizeof(img)); img.version = PNG_IMAGE_VERSION; if( png_image_begin_read_from_memory(&img,data,dataLen) == 0 ) { png_image_free(&img); return false; } switch( format ) { case 0: img.format = PNG_FORMAT_RGB; break; case 1: img.format = PNG_FORMAT_BGR; break; case 7: img.format = PNG_FORMAT_RGBA; break; case 8: img.format = PNG_FORMAT_BGRA; break; case 9: img.format = PNG_FORMAT_ABGR; break; case 10: img.format = PNG_FORMAT_ARGB; break; default: png_image_free(&img); hl_error("Unsupported format"); break; } if( img.width != width || img.height != height ) { png_image_free(&img); return false; } if( png_image_finish_read(&img,NULL,out,stride * (flags & 1 ? -1 : 1),NULL) == 0 ) { png_image_free(&img); return false; } png_image_free(&img); # else hl_error("PNG support is missing for this libPNG version"); # endif return true; }
HL_PRIM bool regexp_regexp_match( ereg *e, vbyte *s, int pos, int len ) { int res = pcre16_exec(e->p,&limit,(PCRE_SPTR16)s,pos+len,pos,0,e->matches,e->nmatches * 3); e->matched = res >= 0; if( res >= 0 ) return true; if( res != PCRE_ERROR_NOMATCH ) hl_error("An error occured while running pcre_exec"); return false; }
/** request : 'db -> sql:string -> 'result <doc>Executes the SQL request and returns its result</doc> **/ HL_PRIM sqlite_result *HL_NAME(request)(sqlite_database *db, vbyte *sql ) { sqlite_result *r; const char *tl; int i,j; r = (sqlite_result*)hl_gc_alloc_finalizer(sizeof(sqlite_result)); r->finalize = HL_NAME(finalize_result); r->db = db; if( sqlite3_prepare16_v2(db->db, sql, -1, &r->r, &tl) != SQLITE_OK ) { HL_NAME(error)(db->db, false); } if( *tl ) { sqlite3_finalize(r->r); hl_error("SQLite error: Cannot execute several SQL requests at the same time"); } r->ncols = sqlite3_column_count(r->r); r->names = (int*)hl_gc_alloc(sizeof(int)*r->ncols); r->bools = (int*)hl_gc_alloc(sizeof(int)*r->ncols); r->first = 1; r->done = 0; for(i=0;i<r->ncols;i++) { int id = hl_hash_gen((uchar*)sqlite3_column_name16(r->r,i), true); const char *dtype = sqlite3_column_decltype(r->r,i); for(j=0;j<i;j++) if( r->names[j] == id ) { if( strcmp(sqlite3_column_name16(r->r,i), sqlite3_column_name16(r->r,j)) == 0 ) { sqlite3_finalize(r->r); hl_buffer *b = hl_alloc_buffer(); hl_buffer_str(b, USTR("SQLite error: Same field is two times in the request: ")); hl_buffer_str(b, (uchar*)sql); hl_error_msg(hl_buffer_content(b, NULL)); } else { hl_buffer *b = hl_alloc_buffer(); hl_buffer_str(b, USTR("SQLite error: Same field ids for: ")); hl_buffer_str(b, sqlite3_column_name16(r->r,i)); hl_buffer_str(b, USTR(" and ")); hl_buffer_str(b, sqlite3_column_name16(r->r,j)); sqlite3_finalize(r->r); hl_error_msg(hl_buffer_content(b, NULL)); } } r->names[i] = id; r->bools[i] = dtype?(strcmp(dtype,"BOOL") == 0):0; } // changes in an update/delete if( db->last != NULL ) HL_NAME(finalize_request)(db->last, false); db->last = r; return db->last; }
HL_PRIM int regexp_regexp_matched_pos( ereg *e, int m, int *len ) { int start; if( !e->matched ) hl_error("Calling matchedPos() on an unmatched regexp"); if( m < 0 || m >= e->nmatches ) hl_error_msg(USTR("Matched index %d outside bounds"),m); start = e->matches[m*2]; *len = e->matches[m*2+1] - start; return start; }
static void HL_NAME(finalize_request)(sqlite_result *r, bool exc ) { r->first = 0; r->done = 1; if( r->ncols == 0 ) r->count = sqlite3_changes(r->db->db); if( sqlite3_finalize(r->r) != SQLITE_OK && exc ) hl_error("SQLite error: Could not finalize request"); r->r = NULL; r->db->last = NULL; r->db = NULL; }
HL_PRIM int hl_thread_id() { # ifdef HL_WIN return (int)GetCurrentThreadId(); # else # ifdef SYS_gettid return syscall(SYS_gettid); # else hl_error("hl_thread_id() not available for this platform"); return -1; # endif # endif }
HL_PRIM void hl_date_get_inf( int date, int *y, int *mo, int *day, int *h, int *m, int *s, int *wday ) { struct tm t; time_t d = (time_t)(unsigned)date; if( !localtime_r(&d,&t) ) hl_error("invalid date"); if( y ) *y = t.tm_year + 1900; if( mo ) *mo = t.tm_mon; if( day ) *day = t.tm_mday; if( h ) *h = t.tm_hour; if( m ) *m = t.tm_min; if( s ) *s = t.tm_sec; if( wday ) *wday = t.tm_wday; }
HL_PRIM vsentinel *HL_NAME(ui_start_sentinel)( double timeout, vclosure *c ) { vsentinel *s = (vsentinel*)malloc(sizeof(vsentinel)); if( c->hasValue ) hl_error("Cannot set sentinel on closure callback"); # ifdef HL_DEBUG timeout *= 2; # endif s->timeout = timeout; s->ticks = 0; s->original = hl_thread_current(); s->callback = c->fun; s->thread = hl_thread_start(sentinel_loop,s,false); return s; }
HL_PRIM vbyte *hl_date_to_string( int date, int *len ) { char buf[127]; struct tm t; time_t d = (time_t)(unsigned)date; int size; uchar *out; if( !localtime_r(&d,&t) ) hl_error("Invalid date"); size = (int)strftime(buf,127,"%Y-%m-%d %H:%M:%S",&t); out = (uchar*)hl_gc_alloc_noptr((size + 1) << 1); hl_from_utf8(out,size,buf); *len = size; return (vbyte*)out; }
double hl_sys_thread_cpu_time() { #if defined(HL_WIN) FILETIME unused; FILETIME utime; if( !GetThreadTimes(GetCurrentThread(),&unused,&unused,&unused,&utime) ) return 0.; return ((double)utime.dwHighDateTime) * 65.536 * 6.5536 + (((double)utime.dwLowDateTime) / 10000000); #elif defined(HL_MAC) hl_error("sys_thread_cpu_time not implemented on OSX"); return 0.; #else struct timespec t; if( clock_gettime(CLOCK_THREAD_CPUTIME_ID,&t) ) return 0.; return t.tv_sec + t.tv_nsec * 1e-9; #endif }
HL_PRIM vbyte *hl_host_reverse( int ip ) { struct hostent *h; hl_blocking(true); # if defined(HL_WIN) || defined(HL_MAC) || defined(HL_IOS) || defined(HL_TVOS) || defined(HL_CYGWIN) || defined(HL_CONSOLE) h = gethostbyaddr((char *)&ip,4,AF_INET); # elif defined(__ANDROID__) hl_error("hl_host_reverse() not available for this platform"); # else struct hostent htmp; int errcode; char buf[1024]; gethostbyaddr_r((char*)&ip,4,AF_INET,&htmp,buf,1024,&h,&errcode); # endif hl_blocking(false); if( h == NULL ) return NULL; return (vbyte*)h->h_name; }
HL_PRIM bool HL_NAME(deflate_buffer)( fmt_zip *zip, vbyte *src, int srcpos, int srclen, vbyte *dst, int dstpos, int dstlen, int *read, int *write ) { int slen, dlen, err; z_stream *z = zip->z; slen = srclen - srcpos; dlen = dstlen - dstpos; if( srcpos < 0 || dstpos < 0 || slen < 0 || dlen < 0 ) hl_error("Out of range"); z->next_in = (Bytef*)(src + srcpos); z->next_out = (Bytef*)(dst + dstpos); z->avail_in = slen; z->avail_out = dlen; if( (err = deflate(z,zip->flush)) < 0 ) zlib_error(z,err); z->next_in = NULL; z->next_out = NULL; *read = slen - z->avail_in; *write = dlen - z->avail_out; return err == Z_STREAM_END; }
HL_PRIM hl_thread *hl_thread_start( void *callback, void *param, bool withGC ) { if( withGC ) hl_error("Threads with garbage collector are currently not supported"); # ifdef HL_WIN DWORD tid; HANDLE h = CreateThread(NULL,0,callback,param,0,&tid); if( h == NULL ) return NULL; CloseHandle(h); return (hl_thread*)(int_val)tid; # else pthread_t t; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); if( pthread_create(&t,&attr,callback,param) != 0 ) { pthread_attr_destroy(&attr); return NULL; } pthread_attr_destroy(&attr); return (hl_thread*)t; # endif }
HL_PRIM void *hl_dyn_call_obj( vdynamic *o, hl_type *ft, int hfield, void **args, vdynamic *ret ) { switch( o->t->kind ) { case HDYNOBJ: hl_fatal("TODO"); break; case HOBJ: { hl_runtime_obj *rt = o->t->obj->rt; while( true ) { hl_field_lookup *l = hl_lookup_find(rt->lookup,rt->nlookup, hfield); if( l != NULL && l->field_index < 0 ) { vclosure tmp; vclosure_wrapper w; tmp.t = hl_get_closure_type(l->t); tmp.fun = rt->methods[-l->field_index-1]; tmp.hasValue = 1; tmp.value = o; w.cl.t = ft; w.cl.fun = hlc_get_wrapper(ft); w.cl.hasValue = 2; w.cl.value = &w; w.wrappedFun = &tmp; return hl_wrapper_call(&w,args,ret); } rt = rt->parent; if( rt == NULL ) break; } hl_error_msg(USTR("%s has no method %s"),o->t->obj->name,hl_field_name(hfield)); } break; default: hl_error("Invalid field access"); break; } return NULL; }
HL_PRIM HL_NO_OPT void hl_assert() { hl_debug_break(); hl_error("assert"); }
HL_PRIM vdynamic* hl_call_method( vdynamic *c, varray *args ) { vclosure *cl = (vclosure*)c; vdynamic **vargs = hl_aptr(args,vdynamic*); void *pargs[HL_MAX_ARGS]; void *ret; union { double d; int i; float f; } tmp[HL_MAX_ARGS]; hl_type *tret; vdynamic *dret; vdynamic out; int i; if( args->size > HL_MAX_ARGS ) hl_error("Too many arguments"); if( cl->hasValue ) { if( cl->fun == fun_var_args ) { cl = (vclosure*)cl->value; return cl->hasValue ? ((vdynamic* (*)(vdynamic*, varray*))cl->fun)(cl->value, args) : ((vdynamic* (*)(varray*))cl->fun)(args); } hl_error("Can't call closure with value"); } if( args->size < cl->t->fun->nargs ) hl_error_msg(USTR("Missing arguments : %d expected but %d passed"),cl->t->fun->nargs, args->size); for(i=0;i<cl->t->fun->nargs;i++) { vdynamic *v = vargs[i]; hl_type *t = cl->t->fun->args[i]; void *p; if( v == NULL ) { if( hl_is_ptr(t) ) p = NULL; else { tmp[i].d = 0; p = &tmp[i].d; } } else switch( t->kind ) { case HBOOL: case HUI8: case HUI16: case HI32: tmp[i].i = hl_dyn_casti(vargs + i, &hlt_dyn,t); p = &tmp[i].i; break; case HF32: tmp[i].f = hl_dyn_castf(vargs + i, &hlt_dyn); p = &tmp[i].f; break; case HF64: tmp[i].d = hl_dyn_castd(vargs + i, &hlt_dyn); p = &tmp[i].d; break; default: p = hl_dyn_castp(vargs + i,&hlt_dyn,t); break; } pargs[i] = p; } ret = hlc_static_call(cl->fun,cl->t,pargs,&out); tret = cl->t->fun->ret; if( !hl_is_ptr(tret) ) { vdynamic *r; if( tret->kind == HVOID ) return NULL; r = hl_alloc_dynamic(tret); r->t = tret; r->v.d = out.v.d; // copy return r; } if( ret == NULL || hl_is_dynamic(tret) ) return (vdynamic*)ret; dret = hl_alloc_dynamic(tret); dret->v.ptr = ret; return dret; }
static void fun_var_args() { hl_error("Variable fun args was not cast to typed function"); }