/** 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; }
/** 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; }
static void HL_NAME(error)( sqlite3 *db, bool close ) { hl_buffer *b = hl_alloc_buffer(); hl_buffer_str(b, USTR("SQLite error: ")); hl_buffer_str(b, sqlite3_errmsg16(db)); if ( close ) sqlite3_close(db); hl_error_msg(hl_buffer_content(b, NULL)); }
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; }
HL_PRIM ereg *regexp_regexp_new_options( vbyte *str, vbyte *opts ) { ereg *r; const char *error; int err_offset; int errorcode; pcre16 *p; uchar *o = (uchar*)opts; 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 NULL; } } p = pcre16_compile2((PCRE_SPTR16)str,options,&errorcode,&error,&err_offset,NULL); if( p == NULL ) { hl_buffer *b = hl_alloc_buffer(); hl_buffer_str(b,USTR("Regexp compilation error : ")); hl_buffer_cstr(b,error); hl_buffer_str(b,USTR(" in ")); hl_buffer_str(b,(uchar*)str); hl_error_msg(USTR("%s"),hl_buffer_content(b,NULL)); } r = (ereg*)hl_gc_alloc_finalizer(sizeof(ereg)); r->finalize = regexp_finalize; r->p = p; r->nmatches = 0; r->matched = 0; pcre16_fullinfo(p,NULL,PCRE_INFO_CAPTURECOUNT,&r->nmatches); r->nmatches++; r->matches = (int*)malloc(sizeof(int) * 3 * r->nmatches); limit.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION; limit.match_limit_recursion = 3500; // adapted based on Windows 1MB stack size return r; }
HL_PRIM void HL_NAME(zip_flush_mode)( fmt_zip *z, int flush ) { switch( flush ) { case 0: z->flush = Z_NO_FLUSH; break; case 1: z->flush = Z_SYNC_FLUSH; break; case 2: z->flush = Z_FULL_FLUSH; break; case 3: z->flush = Z_FINISH; break; case 4: z->flush = Z_BLOCK; break; default: hl_error_msg(USTR("Invalid flush mode %d"),flush); break; } }
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 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; }