Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,111 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM varray *hl_alloc_array( hl_type *at, int size ) {
if( size == 0 && at->kind == HDYN ) {
static varray empty_array = { &hlt_array, &hlt_dyn };
return &empty_array;
}
int esize = hl_type_size(at);
varray *a;
if( size < 0 ) hl_error("Invalid array size");
a = (varray*)hl_gc_alloc_gen(&hlt_array, sizeof(varray) + esize*size, (hl_is_ptr(at) ? MEM_KIND_DYNAMIC : MEM_KIND_NOPTR) | MEM_ZERO);
a->t = &hlt_array;
a->at = at;
a->size = size;
return a;
}
HL_PRIM void hl_array_blit( varray *dst, int dpos, varray *src, int spos, int len ) {
int size = hl_type_size(dst->at);
memmove( hl_aptr(dst,vbyte) + dpos * size, hl_aptr(src,vbyte) + spos * size, len * size);
}
HL_PRIM hl_type *hl_array_type( varray *a ) {
return a->at;
}
DEFINE_PRIM(_ARR,alloc_array,_TYPE _I32);
DEFINE_PRIM(_VOID,array_blit,_ARR _I32 _ARR _I32 _I32);
DEFINE_PRIM(_TYPE,array_type,_ARR);
typedef struct {
hl_type *at;
int osize;
int size;
} hl_carray;
HL_PRIM void *hl_alloc_carray( hl_type *at, int size ) {
if( at->kind != HOBJ && at->kind != HSTRUCT )
hl_error("Invalid array type");
if( size < 0 )
hl_error("Invalid array size");
hl_runtime_obj *rt = at->obj->rt;
if( rt == NULL || rt->methods == NULL ) rt = hl_get_obj_proto(at);
int osize = rt->size;
if( osize & (HL_WSIZE-1) ) osize += HL_WSIZE - (osize & (HL_WSIZE-1));
hl_carray *arr;
int header = sizeof(hl_carray);
if( at->kind == HSTRUCT ) {
header += sizeof(vdynamic) * size;
arr = (hl_carray*)hl_gc_alloc_gen(at, header + size * osize, (rt->hasPtr ? MEM_KIND_RAW : MEM_KIND_NOPTR) | MEM_ZERO);
arr->osize = sizeof(vdynamic);
} else {
arr = (hl_carray*)hl_gc_alloc_gen(at, header + size * osize, (rt->hasPtr ? MEM_KIND_DYNAMIC : MEM_KIND_NOPTR) | MEM_ZERO);
arr->osize = osize;
}
arr->size = size;
arr->at = at;
int i,k;
for(k=0;k<size;k++) {
vobj *o = (vobj*)((char*)arr + header + osize * k);
if( at->kind == HOBJ )
o->t = at;
else {
vdynamic *d = (vdynamic*)((char*)(arr + 1) + k * sizeof(vdynamic));
d->t = at;
d->v.ptr = o;
}
for(i=0;i<rt->nbindings;i++) {
hl_runtime_binding *b = rt->bindings + i;
*(void**)(((char*)o) + rt->fields_indexes[b->fid]) = b->closure ? hl_alloc_closure_ptr(b->closure,b->ptr,o) : b->ptr;
}
}
return arr;
}
HL_PRIM int hl_carray_length( hl_carray *arr ) {
return arr->size;
}
HL_PRIM vdynamic *hl_carray_get( hl_carray *arr, int pos ) {
if( pos < 0 || pos >= arr->size ) return NULL;
return (vdynamic*)((char*)(arr + 1) + pos * arr->osize);
}
#define _CARRAY _ABSTRACT(hl_carray)
DEFINE_PRIM(_CARRAY,alloc_carray,_TYPE _I32);
DEFINE_PRIM(_DYN,carray_get,_CARRAY _I32);
DEFINE_PRIM(_I32,carray_length,_CARRAY);

View File

@ -0,0 +1,396 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef PRId64
# define PR_I64 USTR("%" PRId64)
#else
# define PR_I64 USTR("%lld")
#endif
typedef struct _stringitem {
uchar *str;
int size;
int len;
struct _stringitem *next;
} * stringitem;
struct hl_buffer {
int totlen;
int blen;
stringitem data;
};
HL_PRIM hl_buffer *hl_alloc_buffer() {
hl_buffer *b = (hl_buffer*)hl_gc_alloc_raw(sizeof(hl_buffer));
b->totlen = 0;
b->blen = 16;
b->data = NULL;
return b;
}
static void buffer_append_new( hl_buffer *b, const uchar *s, int len ) {
int size;
stringitem it;
while( b->totlen >= (b->blen << 2) )
b->blen <<= 1;
size = (len < b->blen)?b->blen:len;
it = (stringitem)hl_gc_alloc_raw(sizeof(struct _stringitem));
it->str = (uchar*)hl_gc_alloc_noptr(size<<1);
memcpy(it->str,s,len<<1);
it->size = size;
it->len = len;
it->next = b->data;
b->data = it;
}
HL_PRIM void hl_buffer_str_sub( hl_buffer *b, const uchar *s, int len ) {
stringitem it;
int offset = 0;
if( s == NULL || len <= 0 )
return;
b->totlen += len;
it = b->data;
if( it ) {
int free = it->size - it->len;
if( free >= len ) {
memcpy(it->str + it->len,s,len<<1);
it->len += len;
return;
} else {
memcpy(it->str + it->len,s,free<<1);
it->len += free;
offset = free;
len -= free;
}
}
buffer_append_new(b,s + offset,len);
}
HL_PRIM void hl_buffer_str( hl_buffer *b, const uchar *s ) {
if( s ) hl_buffer_str_sub(b,s,(int)ustrlen(s)); else hl_buffer_str_sub(b,USTR("NULL"),4);
}
HL_PRIM void hl_buffer_cstr( hl_buffer *b, const char *s ) {
if( s ) {
int len = (int)hl_utf8_length((vbyte*)s,0);
uchar *out = (uchar*)malloc(sizeof(uchar)*(len+1));
hl_from_utf8(out,len,s);
hl_buffer_str_sub(b,out,len);
free(out);
} else hl_buffer_str_sub(b,USTR("NULL"),4);
}
HL_PRIM void hl_buffer_char( hl_buffer *b, uchar c ) {
stringitem it;
b->totlen++;
it = b->data;
if( it && it->len != it->size ) {
it->str[it->len++] = c;
return;
}
buffer_append_new(b,(uchar*)&c,1);
}
HL_PRIM uchar *hl_buffer_content( hl_buffer *b, int *len ) {
uchar *buf = (uchar*)hl_gc_alloc_noptr((b->totlen+1)<<1);
stringitem it = b->data;
uchar *s = ((uchar*)buf) + b->totlen;
*s = 0;
while( it != NULL ) {
stringitem tmp;
s -= it->len;
memcpy(s,it->str,it->len<<1);
tmp = it->next;
it = tmp;
}
if( len ) *len = b->totlen;
return buf;
}
int hl_buffer_length( hl_buffer *b ) {
return b->totlen;
}
typedef struct vlist {
vdynamic *v;
struct vlist *next;
} vlist;
static void hl_buffer_rec( hl_buffer *b, vdynamic *v, vlist *stack );
static void hl_buffer_addr( hl_buffer *b, void *data, hl_type *t, vlist *stack ) {
uchar buf[32];
switch( t->kind ) {
case HUI8:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),(int)*(unsigned char*)data));
break;
case HUI16:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),(int)*(unsigned short*)data));
break;
case HI32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),*(int*)data));
break;
case HI64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,PR_I64,*(int64*)data));
break;
case HF32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.9f"),*(float*)data));
break;
case HF64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.17g"),*(double*)data));
break;
case HBYTES:
hl_buffer_str(b,*(uchar**)data);
break;
case HTYPE:
case HREF:
case HABSTRACT:
{
vdynamic tmp;
tmp.t = t;
tmp.v.ptr = *(void**)data;
hl_buffer_rec(b, tmp.v.ptr ? &tmp : NULL, stack);
}
break;
case HBOOL:
if( *(unsigned char*)data )
hl_buffer_str_sub(b,USTR("true"),4);
else
hl_buffer_str_sub(b,USTR("false"),5);
break;
default:
hl_buffer_rec(b, *(vdynamic**)data, stack);
break;
}
}
static void hl_buffer_rec( hl_buffer *b, vdynamic *v, vlist *stack ) {
uchar buf[32];
if( v == NULL ) {
hl_buffer_str_sub(b,USTR("null"),4);
return;
}
switch( v->t->kind ) {
case HVOID:
hl_buffer_str_sub(b,USTR("void"),4);
break;
case HUI8:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),v->v.ui8));
break;
case HUI16:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),v->v.ui16));
break;
case HI32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%d"),v->v.i));
break;
case HI64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,PR_I64,v->v.i64));
break;
case HF32:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.9f"),v->v.f));
break;
case HF64:
hl_buffer_str_sub(b,buf,usprintf(buf,32,USTR("%.17g"),v->v.d));
break;
case HBOOL:
if( v->v.b )
hl_buffer_str_sub(b,USTR("true"),4);
else
hl_buffer_str_sub(b,USTR("false"),5);
break;
case HBYTES:
hl_buffer_str(b,(uchar*)v->v.bytes);
break;
case HFUN:
hl_buffer_str_sub(b,USTR("function#"),9);
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT,(int_val)v));
break;
case HMETHOD:
hl_buffer_str_sub(b,USTR("method#"),7);
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT,(int_val)v->v.ptr));
break;
case HOBJ:
case HSTRUCT:
{
hl_type_obj *o = v->t->obj;
if( o->rt == NULL || hl_get_obj_proto(v->t)->toStringFun == NULL ) {
if( v->t->kind == HSTRUCT ) hl_buffer_char(b,'@');
hl_buffer_str(b,o->name);
} else
hl_buffer_str(b,o->rt->toStringFun(v->t->kind == HSTRUCT ? (vdynamic*)v->v.ptr : v));
}
break;
case HARRAY:
{
int i;
varray *a = (varray*)v;
hl_type *at = a->at;
int stride = hl_type_size(at);
vlist l;
vlist *vtmp = stack;
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
hl_buffer_char(b,'[');
for(i=0;i<a->size;i++) {
if( i )
hl_buffer_str_sub(b,USTR(", "),2);
hl_buffer_addr(b,hl_aptr(a,char) + i * stride,at,&l);
}
hl_buffer_char(b,']');
}
break;
case HTYPE:
hl_buffer_str(b, hl_type_str((hl_type*)v->v.ptr));
break;
case HREF:
hl_buffer_str_sub(b, USTR("ref"), 3);
break;
case HVIRTUAL:
{
vvirtual *vv = (vvirtual*)v;
int i;
vlist l;
vlist *vtmp = stack;
if( vv->value ) {
hl_buffer_rec(b, vv->value, stack);
return;
}
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
hl_buffer_char(b, '{');
for(i=0;i<vv->t->virt->nfields;i++) {
hl_field_lookup *f = vv->t->virt->lookup + i;
if( i ) hl_buffer_str_sub(b,USTR(", "),2);
hl_buffer_str(b,(uchar*)hl_field_name(f->hashed_name));
hl_buffer_str_sub(b,USTR(" : "),3);
hl_buffer_addr(b, (char*)v + vv->t->virt->indexes[f->field_index], f->t, &l);
}
hl_buffer_char(b, '}');
}
break;
case HDYNOBJ:
{
vdynobj *o = (vdynobj*)v;
int i;
vlist l;
vlist *vtmp = stack;
hl_field_lookup *f;
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
f = hl_lookup_find(o->lookup,o->nfields,hl_hash_gen(USTR("__string"),false));
if( f && f->t->kind == HFUN && f->t->fun->nargs == 0 && f->t->fun->ret->kind == HBYTES ) {
vclosure *v = (vclosure*)o->values[f->field_index];
if( v ) {
hl_buffer_str(b, v->hasValue ? ((uchar*(*)(void*))v->fun)(v->value) : ((uchar*(*)())v->fun)());
break;
}
}
hl_buffer_char(b, '{');
for(i=0;i<o->nfields;i++) {
hl_field_lookup *f = o->lookup + i;
if( i ) hl_buffer_str_sub(b,USTR(", "),2);
hl_buffer_str(b,(uchar*)hl_field_name(f->hashed_name));
hl_buffer_str_sub(b,USTR(" : "),3);
hl_buffer_addr(b, hl_is_ptr(f->t) ? (void*)(o->values + f->field_index) : (void*)(o->raw_data + f->field_index), f->t, &l);
}
hl_buffer_char(b, '}');
}
break;
case HABSTRACT:
hl_buffer_char(b, '~');
hl_buffer_str(b, v->t->abs_name);
hl_buffer_char(b, ':');
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT,(int_val)v->v.ptr));
break;
case HENUM:
{
int i;
vlist l;
vlist *vtmp = stack;
hl_enum_construct *c = v->t->tenum->constructs + ((venum*)v)->index;
if( !c->nparams ) {
hl_buffer_str(b, c->name);
break;
}
while( vtmp != NULL ) {
if( vtmp->v == v ) {
hl_buffer_str_sub(b,USTR("..."),3);
return;
}
vtmp = vtmp->next;
}
l.v = v;
l.next = stack;
hl_buffer_str(b, c->name);
hl_buffer_char(b,'(');
for(i=0;i<c->nparams;i++) {
if( i ) hl_buffer_char(b,',');
hl_buffer_addr(b,(char*)v + c->offsets[i],c->params[i], &l);
}
hl_buffer_char(b,')');
}
break;
case HNULL:
hl_buffer_str_sub(b, USTR("_null_"), 6);
break;
default:
hl_buffer_str_sub(b, buf, usprintf(buf, 32, _PTR_FMT USTR("H"),(int_val)v));
break;
}
}
HL_PRIM void hl_buffer_val( hl_buffer *b, vdynamic *v ) {
hl_buffer_rec(b,v,NULL);
}
HL_PRIM uchar *hl_to_string( vdynamic *v ) {
if( v == NULL )
return USTR("null");
if( v->t->kind == HBOOL )
return v->v.b ? USTR("true") : USTR("false");
hl_buffer *b = hl_alloc_buffer();
hl_buffer_val(b,v);
hl_buffer_char(b,0);
return hl_buffer_content(b,NULL);
}

View File

@ -0,0 +1,280 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM vbyte *hl_alloc_bytes( int size ) {
return (vbyte*)hl_gc_alloc_noptr(size);
}
HL_PRIM vbyte *hl_copy_bytes( const vbyte *ptr, int size ) {
vbyte *b = hl_alloc_bytes(size);
memcpy(b,ptr,size);
return b;
}
HL_PRIM void hl_bytes_blit( char *dst, int dpos, char *src, int spos, int len ) {
memmove(dst + dpos,src+spos,len);
}
HL_PRIM int hl_bytes_compare( vbyte *a, int apos, vbyte *b, int bpos, int len ) {
return memcmp(a+apos,b+bpos,len);
}
HL_PRIM int hl_bytes_compare16( vbyte *a, vbyte *b, int len ) {
unsigned short *s1 = (unsigned short *)a;
unsigned short *s2 = (unsigned short *)b;
int i;
for(i=0;i<len;i++)
if( s1[i] != s2[i] )
return ((int)s1[i]) - ((int)s2[i]);
return 0;
}
typedef unsigned char byte;
static void *
memfind_rb (const void *in_block, /* Block containing data */
size_t block_size, /* Size of block in bytes */
const void *in_pattern, /* Pattern to search for */
size_t pattern_size, /* Size of pattern block */
size_t *shift, /* Shift table (search buffer) */
bool *repeat_find) /* TRUE: search buffer already init */
{
size_t
byte_nbr, /* Distance through block */
match_size; /* Size of matched part */
const byte
*match_base = NULL, /* Base of match of pattern */
*match_ptr = NULL, /* Point within current match */
*limit = NULL; /* Last potiental match point */
const byte
*block = (byte *) in_block, /* Concrete pointer to block data */
*pattern = (byte *) in_pattern; /* Concrete pointer to search value */
if (block == NULL || pattern == NULL || shift == NULL)
return (NULL);
/* Pattern must be smaller or equal in size to string */
if (block_size < pattern_size)
return (NULL); /* Otherwise it's not found */
if (pattern_size == 0) /* Empty patterns match at start */
return ((void *)block);
/* Build the shift table unless we're continuing a previous search */
/* The shift table determines how far to shift before trying to match */
/* again, if a match at this point fails. If the byte after where the */
/* end of our pattern falls is not in our pattern, then we start to */
/* match again after that byte; otherwise we line up the last occurence */
/* of that byte in our pattern under that byte, and try match again. */
if (!repeat_find || !*repeat_find)
{
for (byte_nbr = 0; byte_nbr < 256; byte_nbr++)
shift [byte_nbr] = pattern_size + 1;
for (byte_nbr = 0; byte_nbr < pattern_size; byte_nbr++)
shift [(byte) pattern [byte_nbr]] = pattern_size - byte_nbr;
if (repeat_find)
*repeat_find = true;
}
/* Search for the block, each time jumping up by the amount */
/* computed in the shift table */
limit = block + (block_size - pattern_size + 1);
for (match_base = block;
match_base < limit;
match_base += shift [*(match_base + pattern_size)])
{
match_ptr = match_base;
match_size = 0;
/* Compare pattern until it all matches, or we find a difference */
while (*match_ptr++ == pattern [match_size++])
{
/* If we found a match, return the start address */
if (match_size >= pattern_size)
return ((void*)(match_base));
}
}
return NULL;
}
HL_PRIM int hl_bytes_find( vbyte *where, int pos, int len, vbyte *which, int wpos, int wlen ) {
size_t searchbuf [256];
bool repeat_find = false;
vbyte *found = (vbyte*)memfind_rb(where + pos,len,which+wpos,wlen,searchbuf,&repeat_find);
if( found == NULL ) return -1;
return (int)(size_t)(found - where);
}
HL_PRIM int hl_bytes_rfind( vbyte *where, int len, vbyte *which, int wlen ) {
if( wlen > len ) return -1;
if( wlen == 0 ) return len; // at end
int pos = len - wlen;
while( pos >= 0 ) {
if( memcmp(where+pos,which,wlen) == 0 )
return pos;
pos--;
}
return -1;
}
HL_PRIM void hl_bytes_fill( vbyte *bytes, int pos, int len, int value ) {
memset(bytes+pos,value,len);
}
static int ms_gcd( int m, int n ) {
while( n != 0 ) {
int t = m % n;
m=n; n=t;
}
return m;
}
#define TSORT int
#define TID(t) t##_i32
#include "sort.h"
#define TSORT double
#define TID(t) t##_f64
#include "sort.h"
HL_PRIM void hl_bsort_i32( vbyte *bytes, int pos, int len, vclosure *cmp ) {
m_sort_i32 m;
m.arr = (int*)(bytes + pos);
m.c = cmp;
merge_sort_rec_i32(&m,0,len);
}
HL_PRIM void hl_bsort_f64( vbyte *bytes, int pos, int len, vclosure *cmp ) {
m_sort_f64 m;
m.arr = (double*)(bytes + pos);
m.c = cmp;
merge_sort_rec_f64(&m,0,len);
}
static inline bool is_space_char(uchar c) {
return c == 32 || (c > 8 && c < 14);
}
HL_PRIM double hl_parse_float( vbyte *bytes, int pos, int len ) {
const uchar *str = (uchar*)(bytes+pos);
uchar *end = NULL;
while( is_space_char(*str) ) str++;
double d = utod(str,&end);
if( end == str )
return hl_nan();
return d;
}
static inline bool has_hex_prefix( const uchar *c, int len, bool is_signed ) {
if (is_signed)
return len >= 3 && c[1] == '0' && (c[2] == 'x' || c[2] == 'X');
return len >= 2 && c[0] == '0' && (c[1] == 'x' || c[1] == 'X');
}
HL_PRIM vdynamic *hl_parse_int( vbyte *bytes, int pos, int len ) {
const uchar *c = (uchar*)(bytes + pos);
const uchar *start = c;
int h;
while( is_space_char(*c) ) c++;
uchar sign = c[0];
bool is_signed = sign == '-' || sign == '+';
if( has_hex_prefix(c,(int)(len+start-c),is_signed) ) {
h = 0;
c += is_signed ? 3 : 2;
while( *c ) {
uchar k = *c++;
if( k >= '0' && k <= '9' )
h = (h << 4) | (k - '0');
else if( k >= 'A' && k <= 'F' )
h = (h << 4) | ((k - 'A') + 10);
else if( k >= 'a' && k <= 'f' )
h = (h << 4) | ((k - 'a') + 10);
else
break;
}
if( sign == '-' ) h = -h;
} else {
uchar *end = NULL;
h = utoi(c,&end);
if( c == end )
return NULL;
}
return hl_make_dyn(&h,&hlt_i32);
}
// pointer manipulation
HL_PRIM vbyte *hl_bytes_offset( vbyte *src, int offset ) {
return src + offset;
}
HL_PRIM int hl_bytes_subtract( vbyte *a, vbyte *b ) {
return (int)(a - b);
}
HL_PRIM int hl_bytes_address( vbyte *a, int *high ) {
# ifdef HL_64
*high = (int)(((uint64)a)>>32);
# else
*high = 0;
# endif
return (int)(int_val)a;
}
HL_PRIM vbyte *hl_bytes_from_address( int low, int high ) {
# ifdef HL_64
// MSVC does overflow on <<32 even on uint64...
struct { int low; int high; } i64;
i64.low = low;
i64.high = high;
return *(vbyte**)&i64;
# else
return (vbyte*)low;
# endif
}
HL_PRIM int hl_string_compare( vbyte *a, vbyte *b, int len ) {
return memcmp(a,b,len * sizeof(uchar));
}
DEFINE_PRIM(_BYTES,alloc_bytes,_I32);
DEFINE_PRIM(_VOID,bytes_blit,_BYTES _I32 _BYTES _I32 _I32);
DEFINE_PRIM(_I32,bytes_compare,_BYTES _I32 _BYTES _I32 _I32);
DEFINE_PRIM(_I32,bytes_compare16,_BYTES _BYTES _I32);
DEFINE_PRIM(_I32,string_compare,_BYTES _BYTES _I32);
DEFINE_PRIM(_I32,bytes_find,_BYTES _I32 _I32 _BYTES _I32 _I32);
DEFINE_PRIM(_I32,bytes_rfind,_BYTES _I32 _BYTES _I32);
DEFINE_PRIM(_VOID,bytes_fill,_BYTES _I32 _I32 _I32);
DEFINE_PRIM(_F64, parse_float,_BYTES _I32 _I32);
DEFINE_PRIM(_NULL(_I32), parse_int, _BYTES _I32 _I32);
DEFINE_PRIM(_VOID,bsort_i32,_BYTES _I32 _I32 _FUN(_I32,_I32 _I32));
DEFINE_PRIM(_VOID,bsort_f64,_BYTES _I32 _I32 _FUN(_I32,_F64 _F64));
DEFINE_PRIM(_BYTES,bytes_offset, _BYTES _I32);
DEFINE_PRIM(_I32,bytes_subtract, _BYTES _BYTES);
DEFINE_PRIM(_I32,bytes_address, _BYTES _REF(_I32));
DEFINE_PRIM(_BYTES,bytes_from_address, _I32 _I32);

View File

@ -0,0 +1,574 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <math.h>
#define TK2(a,b) ((a) | ((b)<<5))
static void invalid_cast( hl_type *from, hl_type *to ) {
hl_error("Can't cast %s to %s",hl_type_str(from),hl_type_str(to));
}
HL_PRIM vdynamic *hl_make_dyn( void *data, hl_type *t ) {
vdynamic *v;
switch( t->kind ) {
case HUI8:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i = *(unsigned char*)data;
return v;
case HUI16:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i = *(unsigned short*)data;
return v;
case HI32:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i = *(int*)data;
return v;
case HI64:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.i64 = *(int64*)data;
return v;
case HF32:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.f = *(float*)data;
return v;
case HF64:
v = (vdynamic*)hl_gc_alloc_noptr(sizeof(vdynamic));
v->t = t;
v->v.d = *(double*)data;
return v;
case HBOOL:
return hl_alloc_dynbool(*(bool*)data);
case HBYTES:
case HTYPE:
case HREF:
case HABSTRACT:
{
void *p = *(void**)data;
if( p == NULL ) return NULL;
v = hl_alloc_dynamic(t);
v->v.ptr = p;
return v;
}
default:
return *(vdynamic**)data;
}
}
HL_PRIM int hl_dyn_casti( void *data, hl_type *t, hl_type *to ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,to));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return *(int*)data;
case HI64:
return (int)*(int64*)data;
case HF32:
return (int)*(float*)data;
case HF64:
return (int)*(double*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_casti(&v->v,t->tparam,to);
}
default:
break;
}
invalid_cast(t,to);
return 0;
}
HL_PRIM int64 hl_dyn_casti64( void *data, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_i64));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return *(int*)data;
case HI64:
return *(int64*)data;
case HF32:
return (int64)*(float*)data;
case HF64:
return (int64)*(double*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_casti64(&v->v,t->tparam);
}
default:
break;
}
invalid_cast(t,&hlt_i64);
return 0;
}
HL_PRIM void *hl_dyn_castp( void *data, hl_type *t, hl_type *to ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,to));
if( to->kind == HDYN && hl_is_dynamic(t) )
return *(vdynamic**)data;
if( t->kind == HDYN || t->kind == HNULL ) {
vdynamic *v = *(vdynamic**)data;
if( v == NULL )
return NULL;
if( to->kind == HNULL && v->t == to->tparam && hl_is_gc_ptr(v) )
return v; // v might be a vdynamic on the stack
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
} else if( hl_is_dynamic(t) ) {
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return NULL;
t = v->t;
}
if( t == to || hl_safe_cast(t,to) )
return *(void**)data;
switch( TK2(t->kind,to->kind) ) {
case TK2(HOBJ,HOBJ):
case TK2(HSTRUCT,HSTRUCT):
{
hl_type_obj *t1 = t->obj;
hl_type_obj *t2 = to->obj;
while( true ) {
if( t1 == t2 )
return *(void**)data;
if( t1->super == NULL )
break;
t1 = t1->super->obj;
}
if( t->obj->rt->castFun ) {
vdynamic *v = t->obj->rt->castFun(*(vdynamic**)data,to);
if( v ) return v;
}
break;
}
case TK2(HFUN,HFUN):
{
vclosure *c = *(vclosure**)data;
if( c == NULL ) return NULL;
c = hl_make_fun_wrapper(c,to);
if( c ) return c;
}
break;
case TK2(HOBJ,HVIRTUAL):
case TK2(HDYNOBJ,HVIRTUAL):
case TK2(HVIRTUAL,HVIRTUAL):
return hl_to_virtual(to,*(vdynamic**)data);
case TK2(HVIRTUAL,HOBJ):
{
vvirtual *v = *(vvirtual**)data;
if( v->value == NULL ) break;
return hl_dyn_castp( &v->value, v->value->t, to);
}
case TK2(HOBJ,HDYN):
case TK2(HDYNOBJ,HDYN):
case TK2(HFUN,HDYN):
case TK2(HNULL,HDYN):
case TK2(HARRAY,HDYN):
// NO(HSTRUCT,HDYN)
return *(void**)data;
}
if( to->kind == HDYN )
return hl_make_dyn(data,t);
if( to->kind == HNULL ) {
if( to->tparam->kind == t->kind )
return hl_make_dyn(data,t);
switch( to->tparam->kind ) {
case HUI8:
case HUI16:
case HI32:
case HBOOL:
{
int v = hl_dyn_casti(data,t,to->tparam);
return hl_make_dyn(&v,to->tparam);
}
case HI64:
{
int64 v = hl_dyn_casti64(data,t);
return hl_make_dyn(&v,to->tparam);
}
case HF32:
{
float f = hl_dyn_castf(data,t);
return hl_make_dyn(&f,to->tparam);
}
case HF64:
{
double d = hl_dyn_castd(data,t);
return hl_make_dyn(&d,to->tparam);
}
default:
break;
}
}
if( to->kind == HREF ) {
switch( to->tparam->kind ) {
case HUI8:
case HUI16:
case HI32:
case HBOOL:
{
int *v = (int*)hl_gc_alloc_noptr(sizeof(int));
*v = hl_dyn_casti(data,t,to->tparam);
return v;
}
case HI64:
{
int64 *d = (int64*)hl_gc_alloc_noptr(sizeof(int64));
*d = hl_dyn_casti64(data,t);
return d;
}
case HF32:
{
float *f = (float*)hl_gc_alloc_noptr(sizeof(float));
*f = hl_dyn_castf(data,t);
return f;
}
case HF64:
{
double *d = (double*)hl_gc_alloc_noptr(sizeof(double));
*d = hl_dyn_castd(data,t);
return d;
}
default:
{
void **p = (void**)hl_gc_alloc_raw(sizeof(void*));
*p = hl_dyn_castp(data,t,to->tparam);
return p;
}
break;
}
}
invalid_cast(t,to);
return 0;
}
HL_PRIM double hl_dyn_castd( void *data, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_f64));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HF32:
return *(float*)data;
case HF64:
return *(double*)data;
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return *(int*)data;
case HI64:
return (double)*(int64*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_castd(&v->v,t->tparam);
}
default:
break;
}
invalid_cast(t,&hlt_f64);
return 0.;
}
HL_PRIM float hl_dyn_castf( void *data, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(t,&hlt_f32));
if( t->kind == HDYN ) {
vdynamic *v = *((vdynamic**)data);
if( v == NULL ) return 0;
t = v->t;
if( !hl_is_dynamic(t) ) data = &v->v;
}
switch( t->kind ) {
case HF32:
return *(float*)data;
case HF64:
return (float)*(double*)data;
case HUI8:
return *(unsigned char*)data;
case HUI16:
return *(unsigned short*)data;
case HI32:
return (float)*(int*)data;
case HI64:
return (float)*(int64*)data;
case HBOOL:
return *(bool*)data;
case HNULL:
{
vdynamic *v = *(vdynamic**)data;
if( v == NULL ) return 0;
return hl_dyn_castf(&v->v,t->tparam);
}
default:
break;
}
invalid_cast(t,&hlt_f32);
return 0;
}
static int fcompare( float a, float b ) {
float d = a - b;
if( d != d )
return a == b ? 0 : hl_invalid_comparison; // +INF=+INF
return d == 0.f ? 0 : (d > 0.f ? 1 : -1);
}
static int dcompare( double a, double b ) {
double d = a - b;
if( d != d )
return a == b ? 0 : hl_invalid_comparison; // +INF=+INF
return d == 0. ? 0 : (d > 0. ? 1 : -1);
}
HL_PRIM int hl_ptr_compare( vdynamic *a, vdynamic *b ) {
if( a == b )
return 0;
return a > b ? 1 : -1;
}
HL_PRIM int hl_dyn_compare( vdynamic *a, vdynamic *b ) {
hl_track_call(HL_TRACK_CAST, on_cast(a?a->t:&hlt_dyn,b?b->t:&hlt_dyn));
if( a == b )
return 0;
if( a == NULL )
return -1;
if( b == NULL )
return 1;
switch( TK2(a->t->kind,b->t->kind) ) {
case TK2(HUI8,HUI8):
return (int)a->v.ui8 - (int)b->v.ui8;
case TK2(HUI16,HUI16):
return (int)a->v.ui16 - (int)b->v.ui16;
case TK2(HI32,HI32):
{
int d = a->v.i - b->v.i;
return d == hl_invalid_comparison ? -1 : d;
}
case TK2(HI64,HI64):
{
int64 d = a->v.i64 - b->v.i64;
return d == 0 ? 0 : (d > 0 ? 1 : -1);
}
case TK2(HF32,HF32):
return fcompare(a->v.f,b->v.f);
case TK2(HF64,HF64):
return dcompare(a->v.d,b->v.d);
case TK2(HBOOL,HBOOL):
return (int)a->v.b - (int)b->v.b;
case TK2(HF64, HI32):
return dcompare(a->v.d,(double)b->v.i);
case TK2(HI32, HF64):
return dcompare((double)a->v.i,b->v.d);
case TK2(HF64, HF32):
return dcompare(a->v.d,(double)b->v.f);
case TK2(HF32, HF64):
return dcompare((double)a->v.f,b->v.d);
case TK2(HOBJ,HOBJ):
case TK2(HSTRUCT,HSTRUCT):
if( a->t->obj->rt->compareFun )
return a->t->obj->rt->compareFun(a,b);
return a > b ? 1 : -1;
case TK2(HENUM,HENUM):
return a > b ? 1 : -1;
case TK2(HTYPE,HTYPE):
case TK2(HBYTES,HBYTES):
return a->v.ptr != b->v.ptr;
case TK2(HOBJ,HVIRTUAL):
case TK2(HDYNOBJ,HVIRTUAL):
return hl_dyn_compare(a,((vvirtual*)b)->value);
case TK2(HVIRTUAL,HOBJ):
case TK2(HVIRTUAL,HDYNOBJ):
return hl_dyn_compare(((vvirtual*)a)->value,b);
case TK2(HFUN,HFUN):
if( ((vclosure*)a)->hasValue == 2 )
return hl_dyn_compare((vdynamic*)((vclosure_wrapper*)a)->wrappedFun,b);
if( ((vclosure*)b)->hasValue == 2 )
return hl_dyn_compare(a,(vdynamic*)((vclosure_wrapper*)b)->wrappedFun);
if( ((vclosure*)a)->fun != ((vclosure*)b)->fun )
return hl_invalid_comparison;
return hl_dyn_compare(((vclosure*)a)->value,((vclosure*)b)->value);
case TK2(HVIRTUAL,HVIRTUAL):
if( ((vvirtual*)a)->value && ((vvirtual*)b)->value )
return hl_dyn_compare(((vvirtual*)a)->value,((vvirtual*)b)->value);
return hl_invalid_comparison;
}
return hl_invalid_comparison;
}
HL_PRIM void hl_write_dyn( void *data, hl_type *t, vdynamic *v, bool is_tmp ) {
hl_track_call(HL_TRACK_CAST, on_cast(v?v->t:&hlt_dyn,t));
switch( t->kind ) {
case HUI8:
*(unsigned char*)data = (unsigned char)hl_dyn_casti(&v,&hlt_dyn,t);
break;
case HBOOL:
*(bool*)data = hl_dyn_casti(&v,&hlt_dyn,t) != 0;
break;
case HUI16:
*(unsigned short*)data = (unsigned short)hl_dyn_casti(&v,&hlt_dyn,t);
break;
case HI32:
*(int*)data = hl_dyn_casti(&v,&hlt_dyn,t);
break;
case HI64:
*(int64*)data = hl_dyn_casti64(&v,&hlt_dyn);
break;
case HF32:
*(float*)data = hl_dyn_castf(&v,&hlt_dyn);
break;
case HF64:
*(double*)data = hl_dyn_castd(&v,&hlt_dyn);
break;
default:
{
void *ret = (v && hl_same_type(t,v->t)) ? v : hl_dyn_castp(&v,&hlt_dyn,t);
if( is_tmp && ret == v ) {
ret = hl_alloc_dynamic(v->t);
((vdynamic*)ret)->v = v->v;
}
*(void**)data = ret;
}
break;
}
}
HL_PRIM vdynamic* hl_value_cast( vdynamic *v, hl_type *t ) {
hl_track_call(HL_TRACK_CAST, on_cast(v?v->t:&hlt_dyn,t));
if( t->kind == HDYN || v == NULL || hl_safe_cast(v->t,t) )
return v;
invalid_cast(v->t,t);
return NULL;
}
HL_PRIM bool hl_type_safe_cast( hl_type *a, hl_type *b ) {
return hl_safe_cast(a,b);
}
#define NULL_VAL HLAST
#define OP(op,t1,t2) (TK2(t1,t2) | (op << 10))
#define OP_ADD 0
#define OP_SUB 1
#define OP_MUL 2
#define OP_MOD 3
#define OP_DIV 4
#define OP_SHL 5
#define OP_SHR 6
#define OP_USHR 7
#define OP_AND 8
#define OP_OR 9
#define OP_XOR 10
static vdynamic *hl_dynf64( double v ) {
vdynamic *d = hl_alloc_dynamic(&hlt_f64);
d->v.d = v;
return d;
}
static vdynamic *hl_dyni32( int v ) {
vdynamic *d = hl_alloc_dynamic(&hlt_i32);
d->v.i = v;
return d;
}
static bool is_number( hl_type *t ) {
return t->kind >= HUI8 && t->kind <= HBOOL;
}
#define FOP(op) { double va = hl_dyn_castd(&a,&hlt_dyn); double vb = hl_dyn_castd(&b,&hlt_dyn); return hl_dynf64(va op vb); }
#define IOP(op) { int va = hl_dyn_casti(&a,&hlt_dyn,&hlt_i32); int vb = hl_dyn_casti(&b,&hlt_dyn,&hlt_i32); return hl_dyni32(va op vb); }
HL_PRIM vdynamic *hl_dyn_op( int op, vdynamic *a, vdynamic *b ) {
static uchar *op_names[] = { USTR("+"), USTR("-"), USTR("*"), USTR("%"), USTR("/"), USTR("<<"), USTR(">>"), USTR(">>>"), USTR("&"), USTR("|"), USTR("^") };
if( op < 0 || op >= OpLast ) hl_error("Invalid op %d",op);
hl_track_call(HL_TRACK_CAST, on_cast(a?a->t:&hlt_dyn,b?b->t:&hlt_dyn));
if( !a && !b ) return op == OP_DIV || op == OP_MOD ? hl_dynf64(hl_nan()) : NULL;
if( (!a || is_number(a->t)) && (!b || is_number(b->t)) ) {
switch( op ) {
case OP_ADD: FOP(+);
case OP_SUB: FOP(-);
case OP_MUL: FOP(*);
case OP_MOD: {
double va = hl_dyn_castd(&a,&hlt_dyn);
double vb = hl_dyn_castd(&b,&hlt_dyn);
return hl_dynf64(fmod(va,vb));
}
case OP_DIV: FOP(/);
case OP_SHL: IOP(<<);
case OP_SHR: IOP(>>);
case OP_USHR: {
int va = hl_dyn_casti(&a,&hlt_dyn,&hlt_i32);
int vb = hl_dyn_casti(&b,&hlt_dyn,&hlt_i32);
return hl_dyni32( ((unsigned)va) >> ((unsigned)vb) );
}
case OP_AND: IOP(&);
case OP_OR: IOP(|);
case OP_XOR: IOP(^);
}
}
hl_error("Can't perform dyn op %s %s %s",hl_type_str(a->t),op_names[op],hl_type_str(b->t));
return NULL;
}
DEFINE_PRIM(_I32, dyn_compare, _DYN _DYN);
DEFINE_PRIM(_DYN, value_cast, _DYN _TYPE);
DEFINE_PRIM(_BOOL, type_safe_cast, _TYPE _TYPE);
DEFINE_PRIM(_DYN, dyn_op, _I32 _DYN _DYN);
DEFINE_PRIM(_I32, ptr_compare, _DYN _DYN);

View File

@ -0,0 +1,155 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef HL_CONSOLE
# include <posix/posix.h>
#else
# include <time.h>
#endif
#ifdef HL_WIN
static struct tm *localtime_r( time_t *t, struct tm *r ) {
struct tm *r2 = localtime(t);
if( r2 == NULL ) return NULL;
*r = *r2;
return r;
}
static struct tm *gmtime_r( time_t *t, struct tm *r ) {
struct tm *r2 = gmtime(t);
if( r2 == NULL ) return NULL;
*r = *r2;
return r;
}
#endif
HL_PRIM int hl_date_now() {
return (int)time(NULL);
}
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;
}
HL_PRIM double hl_date_get_time( int date ) {
return ((unsigned)date) * 1000.;
}
HL_PRIM int hl_date_from_time( double time ) {
return (int)(unsigned int)(time / 1000.);
}
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 int hl_date_new( int y, int mo, int d, int h, int m, int s ) {
struct tm t;
memset(&t,0,sizeof(struct tm));
t.tm_year = y - 1900;
t.tm_mon = mo;
t.tm_mday = d;
t.tm_hour = h;
t.tm_min = m;
t.tm_sec = s;
t.tm_isdst = -1;
return (int)mktime(&t);
}
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 void hl_date_get_utc_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( !gmtime_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;
}
DEFINE_PRIM(_I32, date_now, _NO_ARG);
DEFINE_PRIM(_BYTES, date_to_string, _I32 _REF(_I32));
DEFINE_PRIM(_F64, date_get_time, _I32);
DEFINE_PRIM(_I32, date_from_time, _F64);
DEFINE_PRIM(_I32, date_from_string, _BYTES _I32);
DEFINE_PRIM(_I32, date_new, _I32 _I32 _I32 _I32 _I32 _I32);
DEFINE_PRIM(_VOID, date_get_inf, _I32 _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32));
DEFINE_PRIM(_VOID, date_get_utc_inf, _I32 _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32) _REF(_I32));

View File

@ -0,0 +1,413 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_LINUX) && (defined(__i386__) || defined(__x86_64__))
# include <sys/ptrace.h>
# include <sys/wait.h>
# include <sys/user.h>
# include <signal.h>
# define USE_PTRACE
#endif
#ifdef HL_MAC
# include <mdbg/mdbg.h>
#endif
#if defined(HL_WIN)
static HANDLE last_process = NULL, last_thread = NULL;
static int last_pid = -1;
static int last_tid = -1;
static HANDLE OpenPID( int pid ) {
if( pid == last_pid )
return last_process;
CloseHandle(last_process);
last_pid = pid;
last_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
return last_process;
}
static HANDLE OpenTID( int tid ) {
if( tid == last_tid )
return last_thread;
CloseHandle(last_thread);
last_tid = tid;
last_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid);
return last_thread;
}
static void CleanHandles() {
last_pid = -1;
last_tid = -1;
CloseHandle(last_process);
CloseHandle(last_thread);
last_process = NULL;
last_thread = NULL;
}
#endif
HL_API bool hl_debug_start( int pid ) {
# if defined(HL_WIN)
last_pid = -1;
return (bool)DebugActiveProcess(pid);
# elif defined(HL_MAC)
return mdbg_session_attach(pid);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_ATTACH,pid,0,0) >= 0;
# else
return false;
# endif
}
HL_API bool hl_debug_stop( int pid ) {
# if defined(HL_WIN)
BOOL b = DebugActiveProcessStop(pid);
CleanHandles();
return (bool)b;
# elif defined(HL_MAC)
return mdbg_session_detach(pid);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_DETACH,pid,0,0) >= 0;
# else
return false;
# endif
}
HL_API bool hl_debug_breakpoint( int pid ) {
# if defined(HL_WIN)
return (bool)DebugBreakProcess(OpenPID(pid));
# elif defined(HL_MAC)
return mdbg_session_pause(pid);
# elif defined(USE_PTRACE)
return kill(pid,SIGTRAP) == 0;
# else
return false;
# endif
}
HL_API bool hl_debug_read( int pid, vbyte *addr, vbyte *buffer, int size ) {
# if defined(HL_WIN)
return (bool)ReadProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
# elif defined(HL_MAC)
return mdbg_read_memory(pid, addr, buffer, size);
# elif defined(USE_PTRACE)
while( size ) {
long v = ptrace(PTRACE_PEEKDATA,pid,addr,0);
if( size >= sizeof(long) )
*(long*)buffer = v;
else {
memcpy(buffer,&v,size);
break;
}
addr += sizeof(long);
size -= sizeof(long);
buffer += sizeof(long);
}
return true;
# else
return false;
# endif
}
HL_API bool hl_debug_write( int pid, vbyte *addr, vbyte *buffer, int size ) {
# if defined(HL_WIN)
return (bool)WriteProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
# elif defined(HL_MAC)
return mdbg_write_memory(pid, addr, buffer, size);
# elif defined(USE_PTRACE)
while( size ) {
int sz = size >= sizeof(long) ? sizeof(long) : size;
long v = *(long*)buffer;
if( sz != sizeof(long) ) {
long cur = ptrace(PTRACE_PEEKDATA,pid,addr);
memcpy((char*)&v+sz,(char*)&cur+sz,sizeof(long)-sz);
}
if( ptrace(PTRACE_POKEDATA,pid,addr,v) < 0 )
return false;
addr += sz;
size -= sz;
buffer += sz;
}
return true;
# else
return false;
# endif
}
HL_API bool hl_debug_flush( int pid, vbyte *addr, int size ) {
# if defined(HL_WIN)
return (bool)FlushInstructionCache(OpenPID(pid),addr,size);
# elif defined(HL_MAC)
return true;
# elif defined(USE_PTRACE)
return true;
# else
return false;
# endif
}
#ifdef HL_MAC
static int get_reg( int r ) {
switch( r ) {
case 0: return REG_RSP;
case 1: return REG_RBP;
case 2: return REG_RIP;
case 3: return REG_RFLAGS;
case 4: return REG_DR0;
case 5: return REG_DR1;
case 6: return REG_DR2;
case 7: return REG_DR3;
case 8: return REG_DR6;
case 9: return REG_DR7;
case 10: return REG_RAX;
}
return -1;
}
#endif
#ifdef USE_PTRACE
static void *get_reg( int r ) {
struct user_regs_struct *regs = NULL;
struct user *user = NULL;
struct user_fpregs_struct *fp = NULL;
switch( r ) {
case -1: return &user->u_fpstate;
# ifdef HL_64
case 0: return &regs->rsp;
case 1: return &regs->rbp;
case 2: return &regs->rip;
case 10: return &regs->rax;
case 11: return (void*)(-((int_val)&fp->xmm_space[0])-1);
# else
case 0: return &regs->esp;
case 1: return &regs->ebp;
case 2: return &regs->eip;
case 10: return &regs->eax;
case 11: return -1;
# endif
case 3: return &regs->eflags;
default: return &user->u_debugreg[r-4];
}
return NULL;
}
#endif
HL_API int hl_debug_wait( int pid, int *thread, int timeout ) {
# if defined(HL_WIN)
DEBUG_EVENT e;
if( !WaitForDebugEvent(&e,timeout) )
return -1;
*thread = e.dwThreadId;
switch( e.dwDebugEventCode ) {
case EXCEPTION_DEBUG_EVENT:
switch( e.u.Exception.ExceptionRecord.ExceptionCode ) {
case EXCEPTION_BREAKPOINT:
case 0x4000001F: // STATUS_WX86_BREAKPOINT
return 1;
case EXCEPTION_SINGLE_STEP:
case 0x4000001E: // STATUS_WX86_SINGLE_STEP
return 2;
case 0x406D1388: // MS_VC_EXCEPTION (see SetThreadName)
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_CONTINUE);
break;
case 0xE06D7363: // C++ EH EXCEPTION
case 0x6BA: // File Dialog EXCEPTION
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
break;
case EXCEPTION_STACK_OVERFLOW:
return 5;
default:
return 3;
}
break;
case EXIT_PROCESS_DEBUG_EVENT:
return 0;
default:
ContinueDebugEvent(e.dwProcessId, e.dwThreadId, DBG_CONTINUE);
break;
}
return 4;
# elif defined(HL_MAC)
return mdbg_session_wait(pid, thread, timeout);
# elif defined(USE_PTRACE)
int status;
int ret = waitpid(pid,&status,0);
//printf("WAITPID=%X %X\n",ret,status);
*thread = ret;
if( WIFEXITED(status) )
return 0;
if( WIFSTOPPED(status) ) {
int sig = WSTOPSIG(status);
//printf(" STOPSIG=%d\n",sig);
if( sig == SIGSTOP || sig == SIGTRAP )
return 1;
return 3;
}
return 4;
# else
return 0;
# endif
}
HL_API bool hl_debug_resume( int pid, int thread ) {
# if defined(HL_WIN)
return (bool)ContinueDebugEvent(pid, thread, DBG_CONTINUE);
# elif defined(HL_MAC)
return mdbg_session_resume(pid);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_CONT,pid,0,0) >= 0;
# else
return false;
# endif
}
#ifdef HL_WIN
#define DefineGetReg(type,GetFun) \
REGDATA *GetFun( type *c, int reg ) { \
switch( reg ) { \
case 0: return GET_REG(sp); \
case 1: return GET_REG(bp); \
case 2: return GET_REG(ip); \
case 4: return &c->Dr0; \
case 5: return &c->Dr1; \
case 6: return &c->Dr2; \
case 7: return &c->Dr3; \
case 8: return &c->Dr6; \
case 9: return &c->Dr7; \
case 10: return GET_REG(ax); \
default: return GET_REG(ax); \
} \
}
#define GET_REG(x) &c->E##x
#define REGDATA DWORD
#ifdef HL_64
DefineGetReg(WOW64_CONTEXT,GetContextReg32);
# undef GET_REG
# undef REGDATA
# define GET_REG(x) &c->R##x
# define REGDATA DWORD64
# endif
DefineGetReg(CONTEXT,GetContextReg);
#endif
HL_API void *hl_debug_read_register( int pid, int thread, int reg, bool is64 ) {
# if defined(HL_WIN)
# ifdef HL_64
if( !is64 ) {
WOW64_CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !Wow64GetThreadContext(OpenTID(thread),&c) )
return NULL;
if( reg == 3 )
return (void*)(int_val)c.EFlags;
if( reg == 11 )
return NULL; // TODO
return (void*)(int_val)*GetContextReg32(&c,reg);
}
# else
if( is64 ) return NULL;
# endif
CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !GetThreadContext(OpenTID(thread),&c) )
return NULL;
if( reg == 3 )
return (void*)(int_val)c.EFlags;
if( reg == 11 )
#ifdef HL_64
return (void*)(int_val)c.FltSave.XmmRegisters[0].Low;
#else
return (void*)*(int_val*)&c.ExtendedRegisters[10*16];
#endif
return (void*)*GetContextReg(&c,reg);
# elif defined(HL_MAC)
return mdbg_read_register(pid, thread, get_reg(reg), is64);
# elif defined(USE_PTRACE)
void *r = get_reg(reg);
if( ((int_val)r) < 0 ) {
// peek FP ptr
char *addr = (char*)ptrace(PTRACE_PEEKUSER,thread,get_reg(-1),0);
void *out = NULL;
hl_debug_read(pid, addr + (-((int_val)r)-1), (vbyte*)&out, sizeof(void*));
return out;
}
return (void*)ptrace(PTRACE_PEEKUSER,thread,r,0);
# else
return NULL;
# endif
}
HL_API bool hl_debug_write_register( int pid, int thread, int reg, void *value, bool is64 ) {
# if defined(HL_WIN)
# ifdef HL_64
if( !is64 ) {
WOW64_CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !Wow64GetThreadContext(OpenTID(thread),&c) )
return false;
if( reg == 3 )
c.EFlags = (int)(int_val)value;
else if( reg == 11 )
return false; // TODO
else
*GetContextReg32(&c,reg) = (DWORD)(int_val)value;
return (bool)Wow64SetThreadContext(OpenTID(thread),&c);
}
# else
if( is64 ) return false;
# endif
CONTEXT c;
c.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
if( !GetThreadContext(OpenTID(thread),&c) )
return false;
if( reg == 3 )
c.EFlags = (int)(int_val)value;
else if( reg == 11 )
# ifdef HL_64
c.FltSave.XmmRegisters[0].Low = (int_val)value;
# else
*(int_val*)&c.ExtendedRegisters[10*16] = (int_val)value;
# endif
else
*GetContextReg(&c,reg) = (REGDATA)value;
return (bool)SetThreadContext(OpenTID(thread),&c);
# elif defined(HL_MAC)
return mdbg_write_register(pid, thread, get_reg(reg), value, is64);
# elif defined(USE_PTRACE)
return ptrace(PTRACE_POKEUSER,thread,get_reg(reg),value) >= 0;
# else
return false;
# endif
}
DEFINE_PRIM(_BOOL, debug_start, _I32);
DEFINE_PRIM(_VOID, debug_stop, _I32);
DEFINE_PRIM(_BOOL, debug_breakpoint, _I32);
DEFINE_PRIM(_BOOL, debug_read, _I32 _BYTES _BYTES _I32);
DEFINE_PRIM(_BOOL, debug_write, _I32 _BYTES _BYTES _I32);
DEFINE_PRIM(_BOOL, debug_flush, _I32 _BYTES _I32);
DEFINE_PRIM(_I32, debug_wait, _I32 _REF(_I32) _I32);
DEFINE_PRIM(_BOOL, debug_resume, _I32 _I32);
DEFINE_PRIM(_BYTES, debug_read_register, _I32 _I32 _I32 _BOOL);
DEFINE_PRIM(_BOOL, debug_write_register, _I32 _I32 _I32 _BYTES _BOOL);

View File

@ -0,0 +1,265 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <stdarg.h>
#include <string.h>
#ifdef HL_CONSOLE
#include <posix/posix.h>
#endif
HL_PRIM void *hl_fatal_error( const char *msg, const char *file, int line ) {
hl_blocking(true);
# ifdef HL_WIN_DESKTOP
HWND consoleWnd = GetConsoleWindow();
DWORD pid;
GetWindowThreadProcessId(consoleWnd, &pid);
if( consoleWnd == NULL || GetActiveWindow() != NULL || GetCurrentProcessId() == pid ) {
char buf[256];
sprintf(buf,"%s\n\n%s(%d)",msg,file,line);
MessageBoxA(NULL,buf,"Fatal Error", MB_OK | MB_ICONERROR);
}
# endif
printf("%s(%d) : FATAL ERROR : %s\n",file,line,msg);
hl_blocking(false);
hl_debug_break();
exit(1);
return NULL;
}
typedef uchar *(*resolve_symbol_type)( void *addr, uchar *out, int *outSize );
typedef int (*capture_stack_type)( void **stack, int size );
static resolve_symbol_type resolve_symbol_func = NULL;
static capture_stack_type capture_stack_func = NULL;
int hl_internal_capture_stack( void **stack, int size ) {
return capture_stack_func(stack,size);
}
HL_PRIM uchar *hl_resolve_symbol( void *addr, uchar *out, int *outSize ) {
return resolve_symbol_func(addr, out, outSize);
}
static void (*throw_jump)( jmp_buf, int ) = NULL;
HL_PRIM void hl_setup_longjump( void *j ) {
throw_jump = j;
}
HL_PRIM void hl_setup_exception( void *resolve_symbol, void *capture_stack ) {
resolve_symbol_func = resolve_symbol;
capture_stack_func = capture_stack;
}
HL_PRIM void hl_set_error_handler( vclosure *d ) {
hl_thread_info *t = hl_get_thread();
t->trap_uncaught = t->trap_current;
t->exc_handler = d;
}
static bool break_on_trap( hl_thread_info *t, hl_trap_ctx *trap, vdynamic *v ) {
while( true ) {
if( trap == NULL || trap == t->trap_uncaught || t->trap_current == NULL || trap->prev == NULL ) return true;
if( !trap->tcheck || !v ) return false;
hl_type *ot = ((hl_type**)trap->tcheck)[1]; // it's an obj with first field is a hl_type
if( !ot || hl_safe_cast(v->t,ot) ) return false;
trap = trap->prev;
}
return false;
}
HL_PRIM void hl_throw( vdynamic *v ) {
hl_thread_info *t = hl_get_thread();
hl_trap_ctx *trap = t->trap_current;
bool call_handler = false;
if( !(t->flags & HL_EXC_RETHROW) )
t->exc_stack_count = capture_stack_func(t->exc_stack_trace, HL_EXC_MAX_STACK);
t->exc_value = v;
t->trap_current = trap->prev;
call_handler = trap == t->trap_uncaught || t->trap_current == NULL;
if( (t->flags&HL_EXC_CATCH_ALL) || break_on_trap(t,trap,v) ) {
if( trap == t->trap_uncaught ) t->trap_uncaught = NULL;
t->flags |= HL_EXC_IS_THROW;
hl_debug_break();
t->flags &= ~HL_EXC_IS_THROW;
}
t->flags &= ~HL_EXC_RETHROW;
if( t->exc_handler && call_handler ) hl_dyn_call_safe(t->exc_handler,&v,1,&call_handler);
if( throw_jump == NULL ) throw_jump = longjmp;
throw_jump(trap->buf,1);
HL_UNREACHABLE;
}
HL_PRIM void hl_null_access() {
hl_error("Null access");
HL_UNREACHABLE;
}
HL_PRIM void hl_throw_buffer( hl_buffer *b ) {
vdynamic *d = hl_alloc_dynamic(&hlt_bytes);
d->v.ptr = hl_buffer_content(b,NULL);
hl_throw(d);
}
HL_PRIM void hl_dump_stack() {
void *stack[0x1000];
int count = capture_stack_func(stack, 0x1000);
int i;
for(i=0;i<count;i++) {
void *addr = stack[i];
uchar sym[512];
int size = 512;
uchar *str = resolve_symbol_func(addr, sym, &size);
if( str == NULL ) {
int iaddr = (int)(int_val)addr;
usprintf(sym,512,USTR("@0x%X"),iaddr);
str = sym;
}
uprintf(USTR("%s\n"),str);
}
fflush(stdout);
}
HL_PRIM varray *hl_exception_stack() {
hl_thread_info *t = hl_get_thread();
varray *a = hl_alloc_array(&hlt_bytes, t->exc_stack_count);
int i, pos = 0;
for(i=0;i<t->exc_stack_count;i++) {
void *addr = t->exc_stack_trace[i];
uchar sym[512];
int size = 512;
uchar *str = resolve_symbol_func(addr, sym, &size);
if( str == NULL ) continue;
hl_aptr(a,vbyte*)[pos++] = hl_copy_bytes((vbyte*)str,sizeof(uchar)*(size+1));
}
a->size = pos;
return a;
}
HL_PRIM int hl_exception_stack_raw( varray *arr ) {
hl_thread_info *t = hl_get_thread();
if( arr ) memcpy(hl_aptr(arr,void*), t->exc_stack_trace, t->exc_stack_count*sizeof(void*));
return t->exc_stack_count;
}
HL_PRIM int hl_call_stack_raw( varray *arr ) {
if( !arr )
return capture_stack_func(NULL,0);
return capture_stack_func(hl_aptr(arr,void*), arr->size);
}
HL_PRIM void hl_rethrow( vdynamic *v ) {
hl_get_thread()->flags |= HL_EXC_RETHROW;
hl_throw(v);
}
HL_PRIM vdynamic *hl_alloc_strbytes( const uchar *fmt, ... ) {
uchar _buf[256];
vdynamic *d;
int len;
uchar *buf = _buf;
int bsize = sizeof(_buf) / sizeof(uchar);
va_list args;
while( true ) {
va_start(args, fmt);
len = uvszprintf(buf,bsize,fmt,args);
va_end(args);
if( (len + 2) << 1 < bsize ) break;
if( buf != _buf ) free(buf);
bsize <<= 1;
buf = (uchar*)malloc(bsize * sizeof(uchar));
}
d = hl_alloc_dynamic(&hlt_bytes);
d->v.ptr = hl_copy_bytes((vbyte*)buf,(len + 1) << 1);
if( buf != _buf ) free(buf);
return d;
}
HL_PRIM void hl_fatal_fmt( const char *file, int line, const char *fmt, ...) {
char buf[256];
va_list args;
va_start(args, fmt);
vsprintf(buf,fmt, args);
va_end(args);
hl_fatal_error(buf,file,line);
}
#ifdef HL_VCC
# pragma optimize( "", off )
#endif
HL_PRIM HL_NO_OPT void hl_breakpoint() {
hl_debug_break();
}
#ifdef HL_VCC
# pragma optimize( "", on )
#endif
#ifdef HL_LINUX__
#include <signal.h>
static int debugger_present = -1;
static void _sigtrap_handler(int signum) {
debugger_present = 0;
signal(SIGTRAP,SIG_DFL);
}
#endif
#ifdef HL_MAC
extern bool kinc_debugger_attached(void);
#endif
HL_PRIM bool hl_detect_debugger() {
# if defined(HL_WIN)
return (bool)IsDebuggerPresent();
# elif defined(HL_LINUX__)
if( debugger_present == -1 ) {
debugger_present = 1;
signal(SIGTRAP,_sigtrap_handler);
raise(SIGTRAP);
}
return (bool)debugger_present;
# elif defined(HL_MAC)
return kinc_debugger_attached();
# else
return false;
# endif
}
#ifdef HL_VCC
# pragma optimize( "", off )
#endif
HL_PRIM HL_NO_OPT void hl_assert() {
hl_debug_break();
hl_error("assert");
}
#ifdef HL_VCC
# pragma optimize( "", on )
#endif
#define _SYMBOL _ABSTRACT(hl_symbol)
DEFINE_PRIM(_ARR,exception_stack,_NO_ARG);
DEFINE_PRIM(_I32,exception_stack_raw,_ARR);
DEFINE_PRIM(_I32,call_stack_raw,_ARR);
DEFINE_PRIM(_VOID,set_error_handler,_FUN(_VOID,_DYN));
DEFINE_PRIM(_VOID,breakpoint,_NO_ARG);
DEFINE_PRIM(_BYTES,resolve_symbol, _SYMBOL _BYTES _REF(_I32));

View File

@ -0,0 +1,276 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#if defined(__GNUC__) && !defined(__APPLE__)
# define _FILE_OFFSET_BITS 64
#endif
#include <hl.h>
#include <stdio.h>
#ifdef HL_CONSOLE
# include <posix/posix.h>
#endif
#ifdef HL_WIN
#ifdef HL_WIN_DESKTOP
# include <windows.h>
# include <io.h>
# include <fcntl.h>
#else
# include<xdk.h>
#endif
# define fopen(name,mode) _wfopen(name,mode)
# define HL_UFOPEN
#else
#include <errno.h>
#endif
#ifdef HL_WIN_DESKTOP
# define SET_IS_STD(f,b) (f)->is_std = b
#else
# define SET_IS_STD(f,b)
#endif
typedef struct _hl_fdesc hl_fdesc;
struct _hl_fdesc {
void (*finalize)( hl_fdesc * );
FILE *f;
# ifdef HL_WIN_DESKTOP
bool is_std;
# endif
};
static void fdesc_finalize( hl_fdesc *f ) {
if( f->f ) fclose(f->f);
}
HL_PRIM hl_fdesc *hl_file_open( vbyte *name, int mode, bool binary ) {
# ifdef HL_UFOPEN
static const uchar *MODES[] = { USTR("r"), USTR("w"), USTR("a"), USTR("r+"), USTR("rb"), USTR("wb"), USTR("ab"), USTR("rb+") };
FILE *f = fopen((uchar*)name,MODES[mode|(binary?4:0)]);
# else
static const char *MODES[] = { "r", "w", "a", "r+", "rb", "wb", "ab", "rb+" };
FILE *f = fopen((char*)name,MODES[mode|(binary?4:0)]);
# endif
hl_fdesc *fd;
if( f == NULL ) return NULL;
fd = (hl_fdesc*)hl_gc_alloc_finalizer(sizeof(hl_fdesc));
fd->finalize = fdesc_finalize;
fd->f = f;
SET_IS_STD(fd, false);
return fd;
}
HL_PRIM bool hl_file_is_locked( vbyte *name ) {
# ifdef HL_WIN
HANDLE h = CreateFile((uchar*)name,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if( h == INVALID_HANDLE_VALUE ) return true;
CloseHandle(h);
return false;
# else
return false;
# endif
}
HL_PRIM void hl_file_close( hl_fdesc *f ) {
if( !f ) return;
if( f->f ) fclose(f->f);
f->f = NULL;
f->finalize = NULL;
}
HL_PRIM int hl_file_write( hl_fdesc *f, vbyte *buf, int pos, int len ) {
int ret;
if( !f ) return -1;
hl_blocking(true);
# ifdef HL_WIN_DESKTOP
if( f->is_std ) {
// except utf8, handle the case where it's not \0 terminated
uchar *out = (uchar*)malloc((len+1)*2);
vbyte prev = buf[pos+len-1];
if( buf[pos+len] ) buf[pos+len-1] = 0;
int olen = hl_from_utf8(out,len,(const char*)(buf+pos));
buf[pos+len-1] = prev;
_setmode(fileno(f->f),_O_U8TEXT);
ret = _write(fileno(f->f),out,olen<<1);
_setmode(fileno(f->f),_O_TEXT);
if( ret > 0 ) ret = len;
free(out);
} else
# endif
ret = (int)fwrite(buf+pos,1,len,f->f);
hl_blocking(false);
return ret;
}
HL_PRIM int hl_file_read( hl_fdesc *f, vbyte *buf, int pos, int len ) {
int ret;
if( !f ) return -1;
hl_blocking(true);
ret = (int)fread((char*)buf+pos,1,len,f->f);
hl_blocking(false);
return ret;
}
HL_PRIM bool hl_file_write_char( hl_fdesc *f, int c ) {
size_t ret;
unsigned char cc = (unsigned char)c;
if( !f ) return false;
hl_blocking(true);
# ifdef HL_WIN_DESKTOP
if( f->is_std ) {
uchar wcc = cc;
_setmode(fileno(f->f),_O_U8TEXT);
ret = _write(fileno(f->f),&wcc,2);
_setmode(fileno(f->f),_O_TEXT);
if( ret > 0 ) ret = 1;
} else
# endif
ret = fwrite(&cc,1,1,f->f);
hl_blocking(false);
return ret == 1;
}
HL_PRIM int hl_file_read_char( hl_fdesc *f ) {
unsigned char cc;
hl_blocking(true);
if( !f || fread(&cc,1,1,f->f) != 1 ) {
hl_blocking(false);
return -2;
}
hl_blocking(false);
return cc;
}
HL_PRIM bool hl_file_seek( hl_fdesc *f, int pos, int kind ) {
if( !f ) return false;
return fseek(f->f,pos,kind) == 0;
}
HL_PRIM int hl_file_tell( hl_fdesc *f ) {
if( !f ) return -1;
return (int)ftell(f->f);
}
HL_PRIM bool hl_file_seek2( hl_fdesc *f, double pos, int kind ) {
if( !f ) return false;
# ifdef HL_WIN
return _fseeki64(f->f,(__int64)pos,kind) == 0;
# else
return fseek(f->f,(int64)pos,kind) == 0;
# endif
}
HL_PRIM double hl_file_tell2( hl_fdesc *f ) {
if( !f ) return -1;
# ifdef HL_WIN
return (double)_ftelli64(f->f);
# else
return (double)ftell(f->f);
# endif
}
HL_PRIM bool hl_file_eof( hl_fdesc *f ) {
if( !f ) return true;
return (bool)feof(f->f);
}
HL_PRIM int hl_file_error_code() {
return errno;
}
HL_PRIM bool hl_file_flush( hl_fdesc *f ) {
int ret;
if( !f ) return false;
hl_blocking(true);
ret = fflush( f->f );
hl_blocking(false);
return ret == 0;
}
#define MAKE_STDIO(k) \
HL_PRIM hl_fdesc *hl_file_##k() { \
hl_fdesc *f; \
f = (hl_fdesc*)hl_gc_alloc_noptr(sizeof(hl_fdesc)); \
f->f = k; \
f->finalize = NULL; \
SET_IS_STD(f, true); \
return f; \
}
MAKE_STDIO(stdin);
MAKE_STDIO(stdout);
MAKE_STDIO(stderr);
HL_PRIM vbyte *hl_file_contents( vbyte *name, int *size ) {
int len;
int p = 0;
vbyte *content;
# ifdef HL_UFOPEN
FILE *f = fopen((uchar*)name,USTR("rb"));
# else
FILE *f = fopen((char*)name,"rb");
# endif
if( f == NULL )
return NULL;
hl_blocking(true);
fseek(f,0,SEEK_END);
len = ftell(f);
if( size ) *size = len;
fseek(f,0,SEEK_SET);
hl_blocking(false);
content = (vbyte*)hl_gc_alloc_noptr(size ? len : len+1);
hl_blocking(true);
if( !size ) content[len] = 0; else if( !len ) content = (vbyte*)""; // final 0 for UTF8
while( len > 0 ) {
int d = (int)fread((char*)content + p,1,len,f);
if( d <= 0 ) {
hl_blocking(false);
fclose(f);
return NULL;
}
p += d;
len -= d;
}
fclose(f);
hl_blocking(false);
return content;
}
#define _FILE _ABSTRACT(hl_fdesc)
DEFINE_PRIM(_FILE, file_open, _BYTES _I32 _BOOL);
DEFINE_PRIM(_VOID, file_close, _FILE);
DEFINE_PRIM(_I32, file_write, _FILE _BYTES _I32 _I32);
DEFINE_PRIM(_I32, file_read, _FILE _BYTES _I32 _I32);
DEFINE_PRIM(_BOOL, file_write_char, _FILE _I32);
DEFINE_PRIM(_I32, file_read_char, _FILE);
DEFINE_PRIM(_BOOL, file_seek, _FILE _I32 _I32);
DEFINE_PRIM(_I32, file_tell, _FILE);
DEFINE_PRIM(_BOOL, file_seek2, _FILE _F64 _I32);
DEFINE_PRIM(_F64, file_tell2, _FILE);
DEFINE_PRIM(_BOOL, file_eof, _FILE);
DEFINE_PRIM(_BOOL, file_flush, _FILE);
DEFINE_PRIM(_FILE, file_stdin, _NO_ARG);
DEFINE_PRIM(_FILE, file_stdout, _NO_ARG);
DEFINE_PRIM(_FILE, file_stderr, _NO_ARG);
DEFINE_PRIM(_BYTES, file_contents, _BYTES _REF(_I32));
DEFINE_PRIM(_BOOL, file_is_locked, _BYTES);
DEFINE_PRIM(_I32, file_error_code, _NO_ARG);

View File

@ -0,0 +1,479 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM int hl_closure_stack_capture = 0;
static void fun_var_args() {
hl_error("Variable fun args was not cast to typed function");
}
HL_PRIM vclosure *hl_alloc_closure_void( hl_type *t, void *fvalue ) {
vclosure *c = (vclosure*)hl_gc_alloc_noptr(sizeof(vclosure));
c->t = t;
c->fun = fvalue;
c->hasValue = 0;
c->value = NULL;
return c;
}
static hl_type *hl_get_closure_type( hl_type *t ) {
hl_type_fun *ft = t->fun;
if( ft->closure_type.kind != HFUN ) {
if( ft->nargs == 0 ) hl_fatal("assert");
ft->closure_type.kind = HFUN;
ft->closure_type.p = &ft->closure;
ft->closure.nargs = ft->nargs - 1;
ft->closure.args = ft->closure.nargs ? ft->args + 1 : NULL;
ft->closure.ret = ft->ret;
ft->closure.parent = t;
}
return (hl_type*)&ft->closure_type;
}
int hl_internal_capture_stack( void **stack, int size );
HL_PRIM vclosure *hl_alloc_closure_ptr( hl_type *fullt, void *fvalue, void *v ) {
hl_type *t = hl_get_closure_type(fullt);
vclosure *c = (vclosure*)hl_gc_alloc(t, sizeof(vclosure) + sizeof(void*) * hl_closure_stack_capture);
c->t = t;
c->fun = fvalue;
c->hasValue = 1;
# ifdef HL_64
int stack = 0;
if( hl_closure_stack_capture ) stack = hl_internal_capture_stack((void**)(c + 1), hl_closure_stack_capture);
c->stackCount = stack;
# endif
c->value = v;
return c;
}
HL_PRIM vdynamic *hl_no_closure( vdynamic *c ) {
vclosure *cl = (vclosure*)c;
if( !cl->hasValue ) return c;
if( cl->hasValue == 2 )
return hl_no_closure((vdynamic*)((vclosure_wrapper*)c)->wrappedFun);
return (vdynamic*)hl_alloc_closure_void(cl->t->fun->parent,cl->fun);
}
HL_PRIM vdynamic *hl_make_closure( vdynamic *c, vdynamic *v ) {
vclosure *cl = (vclosure*)c;
hl_type *t = cl->hasValue ? cl->t->fun->parent : cl->t;
if( cl->hasValue == 2 )
return hl_make_closure((vdynamic*)((vclosure_wrapper*)c)->wrappedFun, v);
if( t->fun->nargs == 0 || !v || !hl_safe_cast(v->t,t->fun->args[0]) )
return NULL;
return (vdynamic*)hl_alloc_closure_ptr( t, cl->fun, v );
}
HL_PRIM vdynamic* hl_get_closure_value( vdynamic *c ) {
vclosure *cl = (vclosure*)c;
if( !cl->hasValue )
return NULL;
if( cl->hasValue == 2 )
return hl_get_closure_value((vdynamic*)((vclosure_wrapper*)c)->wrappedFun);
if( cl->fun == fun_var_args )
return NULL;
return hl_make_dyn(&cl->value, cl->t->fun->parent->fun->args[0]);
}
HL_PRIM bool hl_fun_compare( vdynamic *a, vdynamic *b ) {
vclosure *ca, *cb;
if( a == b )
return true;
if( !a || !b )
return false;
if( a->t->kind != b->t->kind || a->t->kind != HFUN )
return false;
ca = (vclosure*)a;
cb = (vclosure*)b;
if( ca->fun != cb->fun )
return false;
if( ca->hasValue && ca->value != cb->value )
return false;
return true;
}
// ------------ DYNAMIC CALLS
typedef void *(*fptr_static_call)(void *fun, hl_type *t, void **args, vdynamic *out);
typedef void *(*fptr_get_wrapper)(hl_type *t);
static fptr_static_call hlc_static_call = NULL;
static fptr_get_wrapper hlc_get_wrapper = NULL;
static int hlc_call_flags = 0;
HL_PRIM void hl_setup_callbacks2( void *c, void *w, int flags ) {
hlc_static_call = (fptr_static_call)c;
hlc_get_wrapper = (fptr_get_wrapper)w;
hlc_call_flags = flags;
}
HL_PRIM void hl_setup_callbacks( void *c, void *w ) {
hl_setup_callbacks2(c,w,0);
}
#define HL_MAX_ARGS 9
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; int64 i64; } 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("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 HI64:
tmp[i].i64 = hl_dyn_casti64(vargs + i, &hlt_dyn);
p = &tmp[i].i64;
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(hlc_call_flags & 1 ? &cl->fun : cl->fun,cl->t,pargs,&out);
tret = cl->t->fun->ret;
if( !hl_is_ptr(tret) ) {
vdynamic *r;
switch( tret->kind ) {
case HVOID:
return NULL;
case HBOOL:
return hl_alloc_dynbool(out.v.b);
default:
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;
}
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);
}
HL_PRIM void *hl_wrapper_call( void *_c, void **args, vdynamic *ret ) {
vclosure_wrapper *c = (vclosure_wrapper*)_c;
hl_type_fun *tfun = c->cl.t->fun;
union { double d; int i; float f; int64 i64; } tmp[HL_MAX_ARGS];
void *vargs[HL_MAX_ARGS+1];
vdynamic out;
vclosure *w = c->wrappedFun;
int i;
int p = 0;
void *pret, *aret;
if( ret == NULL )
ret = &out;
if( w->fun == fun_var_args ) {
varray *a;
w = (vclosure*)w->value; // the real callback
a = hl_alloc_array(&hlt_dyn,tfun->nargs);
for(i=0;i<tfun->nargs;i++) {
hl_type *t = tfun->args[i];
void *v = hl_is_ptr(t) ? args + i : args[i];
hl_aptr(a,void*)[i] = hl_make_dyn(v,t);
}
if( w->hasValue )
vargs[p++] = (vdynamic*)w->value;
vargs[p++] = (vdynamic*)a;
} else {
if( w->hasValue )
vargs[p++] = (vdynamic*)w->value;
for(i=0;i<w->t->fun->nargs;i++) {
hl_type *t = tfun->args[i];
hl_type *to = w->t->fun->args[i];
void *v = hl_is_ptr(t) ? args + i : args[i];
switch( to->kind ) {
case HUI8:
case HUI16:
case HI32:
case HBOOL:
tmp[i].i = hl_dyn_casti(v,t,to);
v = &tmp[i].i;
break;
case HI64:
tmp[i].i64 = hl_dyn_casti64(v,t);
v = &tmp[i].i64;
break;
case HF32:
tmp[i].f = hl_dyn_castf(v,t);
v = &tmp[i].f;
break;
case HF64:
tmp[i].d = hl_dyn_castd(v,t);
v = &tmp[i].d;
break;
default:
v = hl_dyn_castp(v,t,to);
break;
}
vargs[p++] = v;
}
}
pret = hlc_static_call(hlc_call_flags & 1 ? &w->fun : w->fun,w->hasValue ? w->t->fun->parent : w->t,vargs,ret);
aret = hl_is_ptr(w->t->fun->ret) ? &pret : pret;
if( aret == NULL ) aret = &pret;
switch( tfun->ret->kind ) {
case HVOID:
return NULL;
case HUI8:
case HUI16:
case HI32:
case HBOOL:
ret->v.i = hl_dyn_casti(aret,w->t->fun->ret,tfun->ret);
break;
case HI64:
ret->v.i64 = hl_dyn_casti64(aret,w->t->fun->ret);
break;
case HF32:
ret->v.f = hl_dyn_castf(aret,w->t->fun->ret);
break;
case HF64:
ret->v.d = hl_dyn_castd(aret,w->t->fun->ret);
break;
default:
pret = hl_dyn_castp(aret,w->t->fun->ret,tfun->ret);
break;
}
return pret;
}
HL_PRIM void *hl_dyn_call_obj( vdynamic *o, hl_type *ft, int hfield, void **args, vdynamic *ret ) {
switch( o->t->kind ) {
case HDYNOBJ:
{
vdynobj *d = (vdynobj*)o;
hl_field_lookup *l = hl_lookup_find(d->lookup,d->nfields, hfield);
if( l != NULL && l->t->kind != HFUN )
hl_error("Field %s is of type %s and cannot be called", hl_field_name(hfield), hl_type_str(l->t));
vclosure *tmp = (vclosure*)d->values[l->field_index];
if( tmp ) {
vclosure_wrapper w;
w.cl.t = ft;
w.cl.fun = hlc_get_wrapper(ft);
w.cl.hasValue = 2;
# ifdef HL_64
w.cl.stackCount = 0;
# endif
w.cl.value = &w;
w.wrappedFun = tmp;
return hl_wrapper_call(&w,args,ret);
}
hl_error("%s has no method %s",hl_type_str(o->t),hl_field_name(hfield));
}
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->t->kind != HFUN )
hl_error("Field %s is of type %s and cannot be called", hl_field_name(hfield), hl_type_str(l->t));
if( l != NULL ) {
vclosure_wrapper w;
vclosure tmp;
w.cl.t = ft;
w.cl.fun = hlc_get_wrapper(ft);
w.cl.hasValue = 2;
# ifdef HL_64
w.cl.stackCount = 0;
# endif
w.cl.value = &w;
if( l->field_index < 0 ) {
tmp.t = hl_get_closure_type(l->t);
tmp.fun = o->t->obj->rt->methods[-l->field_index-1];
tmp.hasValue = 1;
# ifdef HL_64
tmp.stackCount = 0;
# endif
tmp.value = o;
w.wrappedFun = &tmp;
} else {
vclosure *tmp = *(vclosure**)((char*)o + l->field_index);
if( !tmp ) break;
w.wrappedFun = tmp;
}
return hl_wrapper_call(&w,args,ret);
}
rt = rt->parent;
if( rt == NULL ) break;
}
hl_error("%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 vclosure *hl_make_fun_wrapper( vclosure *v, hl_type *to ) {
vclosure_wrapper *c;
void *wrap = hlc_get_wrapper(to);
if( wrap == NULL ) return NULL;
if( v->fun != fun_var_args && v->t->fun->nargs != to->fun->nargs )
return NULL;
c = (vclosure_wrapper*)hl_gc_alloc(to, sizeof(vclosure_wrapper));
c->cl.t = to;
c->cl.fun = wrap;
c->cl.hasValue = 2;
# ifdef HL_64
c->cl.stackCount = 0;
# endif
c->cl.value = c;
c->wrappedFun = v;
return (vclosure*)c;
}
static hl_type hlt_var_args = { HFUN };
static hl_type_fun hlt_var_fun = { NULL, &hlt_void, -1, &hlt_var_args, { HFUN, NULL }, { NULL, &hlt_void, -1, &hlt_var_args} };
HL_PRIM vdynamic *hl_make_var_args( vclosure *c ) {
hlt_var_args.fun = &hlt_var_fun;
hlt_var_fun.closure_type.p = &hlt_var_fun;
return (vdynamic*)hl_alloc_closure_ptr(&hlt_var_args,fun_var_args,c);
}
HL_PRIM void hl_prim_not_loaded() {
hl_error("Primitive or library is missing");
}
HL_PRIM bool hl_is_prim_loaded( vdynamic *f ) {
return f && f->t->kind == HFUN && ((vclosure*)f)->fun != hl_prim_not_loaded;
}
DEFINE_PRIM(_DYN, no_closure, _DYN);
DEFINE_PRIM(_DYN, make_closure, _DYN _DYN);
DEFINE_PRIM(_DYN, get_closure_value, _DYN);
DEFINE_PRIM(_BOOL, fun_compare, _DYN _DYN);
DEFINE_PRIM(_DYN, make_var_args, _FUN(_DYN,_ARR));
DEFINE_PRIM(_DYN, call_method, _DYN _ARR);
DEFINE_PRIM(_BOOL, is_prim_loaded, _DYN);
#if defined(HL_VCC) && !defined(HL_XBO)
static LONG CALLBACK global_handler( PEXCEPTION_POINTERS inf ) {
switch( inf->ExceptionRecord->ExceptionCode ) {
case EXCEPTION_ACCESS_VIOLATION: hl_error("Access violation");
case EXCEPTION_STACK_OVERFLOW: hl_error("Stack overflow");
default: break;
}
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
HL_PRIM vdynamic *hl_dyn_call_safe( vclosure *c, vdynamic **args, int nargs, bool *isException ) {
hl_trap_ctx trap;
vdynamic *ret, *exc;
*isException = false;
hl_trap(trap, exc, on_exception);
# if defined(HL_VCC) && !defined(HL_XBO)
ULONG size = 32<<10;
SetThreadStackGuarantee(&size);
static bool first = true;
if( first && !hl_detect_debugger() ) {
first = false;
AddVectoredExceptionHandler(1,global_handler);
}
# endif
ret = hl_dyn_call(c,args,nargs);
hl_endtrap(trap);
return ret;
on_exception:
hl_endtrap(trap);
*isException = true;
return exc;
}

View File

@ -0,0 +1,291 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef HL_VCC
# pragma warning(disable:4034) // sizeof(void) == 0
#endif
#define H_SIZE_INIT 3
// successive primes that double every time
static int H_PRIMES[] = {
7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87613,175229,350459,700919,1401857,2803727,5607457,11214943,22429903,44859823,89719661,179424673,373587883,776531401,1611623773
};
// ----- FREE LIST ---------------------------------
typedef struct {
int pos;
int count;
} hl_free_bucket;
typedef struct {
hl_free_bucket *buckets;
int head;
int nbuckets;
} hl_free_list;
static void hl_freelist_resize( hl_free_list *f, int newsize ) {
hl_free_bucket *buckets = (hl_free_bucket*)hl_gc_alloc_noptr(sizeof(hl_free_bucket)*newsize);
memcpy(buckets,f->buckets,f->head * sizeof(hl_free_bucket));
f->buckets = buckets;
f->nbuckets = newsize;
}
static void hl_freelist_init( hl_free_list *f ) {
memset(f,0,sizeof(hl_free_list));
}
static void hl_freelist_add_range( hl_free_list *f, int pos, int count ) {
hl_free_bucket *b = f->buckets;
hl_free_bucket *prev = NULL;
if( !b ) {
// special handling for countinuous space
if( f->nbuckets == 0 ) {
f->head = pos;
f->nbuckets = count;
return;
} else if( f->head + f->nbuckets == pos ) {
f->nbuckets += count;
return;
} else if( pos + count == f->head ) {
f->head -= count;
f->nbuckets += count;
return;
} else {
int cur_pos = f->head, cur_count = f->nbuckets;
f->head = 0;
f->nbuckets = 0;
hl_freelist_resize(f,2);
if( cur_count ) hl_freelist_add_range(f,cur_pos,cur_count);
b = f->buckets;
}
}
while( b < f->buckets + f->head ) {
if( b->pos > pos ) break;
prev = b;
b++;
}
if( b < f->buckets + f->head && b->pos == pos + count ) {
b->pos -= count;
b->count += count;
// merge
if( prev && prev->pos + prev->count == b->pos ) {
prev->count += b->count;
memmove(b,b+1,((f->buckets + f->head) - (b+1)) * sizeof(hl_free_bucket));
f->head--;
}
return;
}
if( prev && prev->pos + prev->count == pos ) {
prev->count += count;
return;
}
// insert
if( f->head == f->nbuckets ) {
int pos = (int)(b - f->buckets);
hl_freelist_resize(f,((f->nbuckets * 3) + 1) >> 1);
b = f->buckets + pos;
}
memmove(b+1,b,((f->buckets + f->head) - b) * sizeof(hl_free_bucket));
b->pos = pos;
b->count = count;
f->head++;
}
static void hl_freelist_add( hl_free_list *f, int pos ) {
hl_freelist_add_range(f,pos,1);
}
static int hl_freelist_get( hl_free_list *f ) {
hl_free_bucket *b;
int p;
if( !f->buckets ) {
if( f->nbuckets == 0 ) return -1;
f->nbuckets--;
return f->head++;
}
if( f->head == 0 )
return -1;
b = f->buckets + f->head - 1;
b->count--;
p = b->pos + b->count;
if( b->count == 0 ) {
f->head--;
if( f->head < (f->nbuckets>>1) )
hl_freelist_resize(f,f->nbuckets>>1);
}
return p;
}
// ----- INT MAP ---------------------------------
typedef struct {
int key;
} hl_hi_entry;
typedef struct {
vdynamic *value;
} hl_hi_value;
#define hlt_key hlt_i32
#define hl_hifilter(key) key
#define hl_hihash(h) ((unsigned)(h))
#define _MKEY_TYPE int
#define _MNAME(n) hl_hi##n
#define _MMATCH(c) m->entries[c].key == key
#define _MKEY(m,c) m->entries[c].key
#define _MSET(c) m->entries[c].key = key
#define _MERASE(c)
#include "maps.h"
// ----- INT64 MAP ---------------------------------
typedef struct {
int64 key;
} hl_hi64_entry;
typedef struct {
vdynamic *value;
} hl_hi64_value;
#define hlt_key hlt_i64
#define hl_hi64filter(key) key
#define hl_hi64hash(h) (((unsigned int)h) ^ ((unsigned int)(h>>32)))
#define _MKEY_TYPE int64
#define _MNAME(n) hl_hi64##n
#define _MMATCH(c) m->entries[c].key == key
#define _MKEY(m,c) m->entries[c].key
#define _MSET(c) m->entries[c].key = key
#define _MERASE(c)
#include "maps.h"
// ----- BYTES MAP ---------------------------------
typedef struct {
unsigned int hash;
} hl_hb_entry;
typedef struct {
uchar *key;
vdynamic *value;
} hl_hb_value;
#define hlt_key hlt_bytes
#define hl_hbfilter(key) key
#define hl_hbhash(key) ((unsigned)hl_hash_gen(key,false))
#define _MKEY_TYPE uchar*
#define _MNAME(n) hl_hb##n
#define _MMATCH(c) m->entries[c].hash == hash && ucmp(m->values[c].key,key) == 0
#define _MKEY(m,c) m->values[c].key
#define _MSET(c) m->entries[c].hash = hash; m->values[c].key = key
#define _MERASE(c) m->values[c].key = NULL
#include "maps.h"
// ----- OBJECT MAP ---------------------------------
typedef void hl_ho_entry;
typedef struct {
vdynamic *key;
vdynamic *value;
} hl_ho_value;
static vdynamic *hl_hofilter( vdynamic *key ) {
if( key )
switch( key->t->kind ) {
// erase virtual (prevent mismatch once virtualized)
case HVIRTUAL:
key = hl_virtual_make_value((vvirtual*)key);
break;
// store real pointer instead of dynamic wrapper
case HBYTES:
case HTYPE:
case HABSTRACT:
case HREF:
case HENUM:
key = (vdynamic*)key->v.ptr;
break;
default:
break;
}
return key;
}
#define hlt_key hlt_dyn
#define hl_hohash(key) ((unsigned int)(int_val)(key))
#define _MKEY_TYPE vdynamic*
#define _MNAME(n) hl_ho##n
#define _MMATCH(c) m->values[c].key == key
#define _MKEY(m,c) m->values[c].key
#define _MSET(c) m->values[c].key = key
#define _MERASE(c) m->values[c].key = NULL
#include "maps.h"
#define _IMAP _ABSTRACT(hl_int_map)
DEFINE_PRIM( _IMAP, hialloc, _NO_ARG );
DEFINE_PRIM( _VOID, hiset, _IMAP _I32 _DYN );
DEFINE_PRIM( _BOOL, hiexists, _IMAP _I32 );
DEFINE_PRIM( _DYN, higet, _IMAP _I32 );
DEFINE_PRIM( _BOOL, hiremove, _IMAP _I32 );
DEFINE_PRIM( _ARR, hikeys, _IMAP );
DEFINE_PRIM( _ARR, hivalues, _IMAP );
DEFINE_PRIM( _VOID, hiclear, _IMAP );
DEFINE_PRIM( _I32, hisize, _IMAP );
#define _I64MAP _ABSTRACT(hl_int64_map)
DEFINE_PRIM( _I64MAP, hi64alloc, _NO_ARG );
DEFINE_PRIM( _VOID, hi64set, _I64MAP _I64 _DYN );
DEFINE_PRIM( _BOOL, hi64exists, _I64MAP _I64 );
DEFINE_PRIM( _DYN, hi64get, _I64MAP _I64 );
DEFINE_PRIM( _BOOL, hi64remove, _I64MAP _I64 );
DEFINE_PRIM( _ARR, hi64keys, _I64MAP );
DEFINE_PRIM( _ARR, hi64values, _I64MAP );
DEFINE_PRIM( _VOID, hi64clear, _I64MAP );
DEFINE_PRIM( _I32, hi64size, _I64MAP );
#define _BMAP _ABSTRACT(hl_bytes_map)
DEFINE_PRIM( _BMAP, hballoc, _NO_ARG );
DEFINE_PRIM( _VOID, hbset, _BMAP _BYTES _DYN );
DEFINE_PRIM( _BOOL, hbexists, _BMAP _BYTES );
DEFINE_PRIM( _DYN, hbget, _BMAP _BYTES );
DEFINE_PRIM( _BOOL, hbremove, _BMAP _BYTES );
DEFINE_PRIM( _ARR, hbkeys, _BMAP );
DEFINE_PRIM( _ARR, hbvalues, _BMAP );
DEFINE_PRIM( _VOID, hbclear, _BMAP );
DEFINE_PRIM( _I32, hbsize, _BMAP );
#define _OMAP _ABSTRACT(hl_obj_map)
DEFINE_PRIM( _OMAP, hoalloc, _NO_ARG );
DEFINE_PRIM( _VOID, hoset, _OMAP _DYN _DYN );
DEFINE_PRIM( _BOOL, hoexists, _OMAP _DYN );
DEFINE_PRIM( _DYN, hoget, _OMAP _DYN );
DEFINE_PRIM( _BOOL, horemove, _OMAP _DYN );
DEFINE_PRIM( _ARR, hokeys, _OMAP );
DEFINE_PRIM( _ARR, hovalues, _OMAP );
DEFINE_PRIM( _VOID, hoclear, _OMAP );
DEFINE_PRIM( _I32, hosize, _OMAP );

View File

@ -0,0 +1,224 @@
#undef t_map
#undef t_entry
#undef t_value
#undef t_key
#define t_key _MKEY_TYPE
#define t_map _MNAME(_map)
#define t_entry _MNAME(_entry)
#define t_value _MNAME(_value)
#define _MLIMIT 128
#define _MINDEX(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((signed char*)(m)->cells)[ckey] : ((int*)(m)->cells)[ckey])
#define _MNEXT(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((signed char*)(m)->nexts)[ckey] : ((int*)(m)->nexts)[ckey])
typedef struct {
void *cells;
void *nexts;
t_entry *entries;
t_value *values;
hl_free_list lfree;
int ncells;
int nentries;
int maxentries;
} t_map;
HL_PRIM t_map *_MNAME(alloc)() {
t_map *m = (t_map*)hl_gc_alloc_raw(sizeof(t_map));
memset(m,0,sizeof(t_map));
return m;
}
static vdynamic **_MNAME(find)( t_map *m, t_key key ) {
int c, ckey;
unsigned int hash;
if( !m->values ) return NULL;
hash = _MNAME(hash)(key);
ckey = hash % ((unsigned)m->ncells);
c = _MINDEX(m,ckey);
while( c >= 0 ) {
if( _MMATCH(c) )
return &m->values[c].value;
c = _MNEXT(m,c);
}
return NULL;
}
static void _MNAME(resize)( t_map *m );
static void _MNAME(set_impl)( t_map *m, t_key key, vdynamic *value ) {
int c, ckey = 0;
unsigned int hash = _MNAME(hash)(key);
if( m->values ) {
ckey = hash % ((unsigned)m->ncells);
c = _MINDEX(m,ckey);
while( c >= 0 ) {
if( _MMATCH(c) ) {
m->values[c].value = value;
return;
}
c = _MNEXT(m,c);
}
}
c = hl_freelist_get(&m->lfree);
if( c < 0 ) {
_MNAME(resize)(m);
ckey = hash % ((unsigned)m->ncells);
c = hl_freelist_get(&m->lfree);
}
_MSET(c);
if( m->maxentries < _MLIMIT ) {
((signed char*)m->nexts)[c] = ((signed char*)m->cells)[ckey];
((signed char*)m->cells)[ckey] = (signed char)c;
} else {
((int*)m->nexts)[c] = ((int*)m->cells)[ckey];
((int*)m->cells)[ckey] = c;
}
m->values[c].value = value;
m->nentries++;
}
static void _MNAME(resize)( t_map *m ) {
// save
t_map old = *m;
if( m->nentries != m->maxentries ) hl_error("assert");
// resize
int i = 0;
int nentries = m->maxentries ? ((m->maxentries * 3) + 1) >> 1 : H_SIZE_INIT;
int ncells = nentries >> 2;
while( H_PRIMES[i] < ncells ) i++;
ncells = H_PRIMES[i];
int ksize = nentries < _MLIMIT ? 1 : sizeof(int);
m->entries = (t_entry*)hl_gc_alloc_noptr(nentries * sizeof(t_entry));
m->values = (t_value*)hl_gc_alloc_raw(nentries * sizeof(t_value));
m->maxentries = nentries;
if( old.ncells == ncells && (nentries < _MLIMIT || old.maxentries >= _MLIMIT) ) {
// simply expand
m->nexts = hl_gc_alloc_noptr(nentries * ksize);
memcpy(m->entries,old.entries,old.maxentries * sizeof(t_entry));
memcpy(m->values,old.values,old.maxentries * sizeof(t_value));
memcpy(m->nexts,old.nexts,old.maxentries * ksize);
memset(m->values + old.maxentries, 0, (nentries - old.maxentries) * sizeof(t_value));
hl_freelist_add_range(&m->lfree,old.maxentries,m->maxentries - old.maxentries);
} else {
// expand and remap
m->cells = hl_gc_alloc_noptr((ncells + nentries) * ksize);
m->nexts = (signed char*)m->cells + ncells * ksize;
m->ncells = ncells;
m->nentries = 0;
memset(m->cells,0xFF,ncells * ksize);
memset(m->values, 0, nentries * sizeof(t_value));
hl_freelist_init(&m->lfree);
hl_freelist_add_range(&m->lfree,0,m->maxentries);
for(i=0;i<old.ncells;i++) {
int c = old.maxentries < _MLIMIT ? ((signed char*)old.cells)[i] : ((int*)old.cells)[i];
while( c >= 0 ) {
_MNAME(set_impl)(m,_MKEY((&old),c),old.values[c].value);
c = _MNEXT(&old,c);
}
}
}
}
HL_PRIM void _MNAME(set)( t_map *m, t_key key, vdynamic *value ) {
_MNAME(set_impl)(m,_MNAME(filter)(key),value);
}
HL_PRIM bool _MNAME(exists)( t_map *m, t_key key ) {
return _MNAME(find)(m,_MNAME(filter)(key)) != NULL;
}
HL_PRIM vdynamic* _MNAME(get)( t_map *m, t_key key ) {
vdynamic **v = _MNAME(find)(m,_MNAME(filter)(key));
if( v == NULL ) return NULL;
return *v;
}
HL_PRIM bool _MNAME(remove)( t_map *m, t_key key ) {
int c, prev = -1, ckey;
unsigned int hash;
if( !m->cells ) return false;
key = _MNAME(filter)(key);
hash = _MNAME(hash)(key);
ckey = hash % ((unsigned)m->ncells);
c = _MINDEX(m,ckey);
while( c >= 0 ) {
if( _MMATCH(c) ) {
hl_freelist_add(&m->lfree,c);
m->nentries--;
_MERASE(c);
m->values[c].value = NULL;
if( m->maxentries < _MLIMIT ) {
if( prev >= 0 )
((signed char*)m->nexts)[prev] = ((signed char*)m->nexts)[c];
else
((signed char*)m->cells)[ckey] = ((signed char*)m->nexts)[c];
} else {
if( prev >= 0 )
((int*)m->nexts)[prev] = ((int*)m->nexts)[c];
else
((int*)m->cells)[ckey] = ((int*)m->nexts)[c];
}
return true;
}
prev = c;
c = _MNEXT(m,c);
}
return false;
}
HL_PRIM varray* _MNAME(keys)( t_map *m ) {
varray *a = hl_alloc_array(&hlt_key,m->nentries);
t_key *keys = hl_aptr(a,t_key);
int p = 0;
int i;
for(i=0;i<m->ncells;i++) {
int c = _MINDEX(m,i);
while( c >= 0 ) {
keys[p++] = _MKEY(m,c);
c = _MNEXT(m,c);
}
}
return a;
}
HL_PRIM varray* _MNAME(values)( t_map *m ) {
varray *a = hl_alloc_array(&hlt_dyn,m->nentries);
vdynamic **values = hl_aptr(a,vdynamic*);
int p = 0;
int i;
for(i=0;i<m->ncells;i++) {
int c = _MINDEX(m,i);
while( c >= 0 ) {
values[p++] = m->values[c].value;
c = _MNEXT(m,c);
}
}
return a;
}
HL_PRIM void _MNAME(clear)( t_map *m ) {
memset(m,0,sizeof(t_map));
}
HL_PRIM int _MNAME(size)( t_map *m ) {
return m->nentries;
}
#undef hlt_key
#undef hl_hbhash
#undef _MKEY_TYPE
#undef _MNAME
#undef _MMATCH
#undef _MKEY
#undef _MSET
#undef _MERASE
#undef _MOLD_KEY
#undef _MINDEX
#undef _MNEXT

View File

@ -0,0 +1,155 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <math.h>
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *) __nan)
#endif
HL_PRIM double hl_nan() {
return NAN;
}
HL_PRIM double hl_math_abs( double a ) {
return fabs(a);
}
HL_PRIM bool hl_math_isnan( double a ) {
#ifdef HL_WIN
return isnan(a);
#else
return a != a; //does not work on some platforms
#endif
}
typedef union {
double d;
struct {
unsigned int l;
unsigned int h;
} i;
} qw;
HL_PRIM bool hl_math_isfinite( double a ) {
qw q;
unsigned int h, l;
if( a != a )
return false;
q.d = a;
h = q.i.h;
l = q.i.l;
l = l | (h & 0xFFFFF);
h = h & 0x7FF00000;
return h != 0x7FF00000 || l;
}
HL_PRIM double hl_math_fceil( double d ) {
return ceil(d);
}
HL_PRIM double hl_math_fround( double d ) {
return floor(d + 0.5);
}
HL_PRIM double hl_math_ffloor( double d ) {
return floor(d);
}
HL_PRIM int hl_math_round( double d ) {
return (int)hl_math_fround(d);
}
HL_PRIM int hl_math_ceil( double d ) {
return (int)hl_math_fceil(d);
}
HL_PRIM int hl_math_floor( double d ) {
return (int)hl_math_ffloor(d);
}
HL_PRIM double hl_math_cos( double a ) {
return cos(a);
}
HL_PRIM double hl_math_sin( double a ) {
return sin(a);
}
HL_PRIM double hl_math_tan( double a ) {
return tan(a);
}
HL_PRIM double hl_math_acos( double a ) {
return acos(a);
}
HL_PRIM double hl_math_asin( double a ) {
return asin(a);
}
HL_PRIM double hl_math_atan( double a ) {
return atan(a);
}
HL_PRIM double hl_math_atan2( double a, double b ) {
return atan2(a,b);
}
HL_PRIM double hl_math_pow( double a, double b ) {
return pow(a,b);
}
HL_PRIM double hl_math_log( double a ) {
return log(a);
}
HL_PRIM double hl_math_exp( double a ) {
return exp(a);
}
HL_PRIM double hl_math_sqrt( double a ) {
return sqrt(a);
}
DEFINE_PRIM(_F64, nan, _NO_ARG);
DEFINE_PRIM(_F64, math_abs, _F64);
DEFINE_PRIM(_BOOL, math_isnan, _F64);
DEFINE_PRIM(_BOOL, math_isfinite, _F64);
DEFINE_PRIM(_F64, math_fceil, _F64);
DEFINE_PRIM(_F64, math_fround, _F64);
DEFINE_PRIM(_F64, math_ffloor, _F64);
DEFINE_PRIM(_I32, math_round, _F64);
DEFINE_PRIM(_I32, math_ceil, _F64);
DEFINE_PRIM(_I32, math_floor, _F64);
DEFINE_PRIM(_F64, math_cos, _F64);
DEFINE_PRIM(_F64, math_sin, _F64);
DEFINE_PRIM(_F64, math_tan, _F64);
DEFINE_PRIM(_F64, math_acos, _F64);
DEFINE_PRIM(_F64, math_asin, _F64);
DEFINE_PRIM(_F64, math_atan, _F64);
DEFINE_PRIM(_F64, math_atan2, _F64 _F64);
DEFINE_PRIM(_F64, math_pow, _F64 _F64);
DEFINE_PRIM(_F64, math_log, _F64);
DEFINE_PRIM(_F64, math_exp, _F64);
DEFINE_PRIM(_F64, math_sqrt, _F64);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_CONSOLE)
# include <posix/posix.h>
#elif !defined(HL_WIN)
# include <sys/types.h>
# include <unistd.h>
# include <errno.h>
# include <signal.h>
# if !defined(HL_MAC)
# if defined(HL_BSD) || defined (HL_IOS) || defined (HL_TVOS)
# include <sys/wait.h>
# else
# include <wait.h>
# endif
# endif
#endif
#include <stdio.h>
#include <stdlib.h>
typedef struct _vprocess vprocess;
struct _vprocess {
void (*finalize)( vprocess * );
#ifdef HL_WIN
HANDLE oread;
HANDLE eread;
HANDLE iwrite;
PROCESS_INFORMATION pinf;
#else
int oread;
int eread;
int iwrite;
int pid;
#endif
};
static void process_finalize( vprocess *p ) {
# ifdef HL_WIN
CloseHandle(p->eread);
CloseHandle(p->oread);
CloseHandle(p->iwrite);
CloseHandle(p->pinf.hProcess);
CloseHandle(p->pinf.hThread);
# else
close(p->eread);
close(p->oread);
close(p->iwrite);
# endif
}
HL_PRIM vprocess *hl_process_run( vbyte *cmd, varray *vargs, bool detached ) {
vprocess *p;
# ifdef HL_WIN
SECURITY_ATTRIBUTES sattr;
STARTUPINFO sinf;
HANDLE proc = GetCurrentProcess();
HANDLE oread,eread,iwrite;
if( vargs )
return NULL; // should have been pre-processed by toplevel
p = (vprocess*)hl_gc_alloc_finalizer(sizeof(vprocess));
p->finalize = process_finalize;
// startup process
sattr.nLength = sizeof(sattr);
sattr.bInheritHandle = detached ? FALSE : TRUE;
sattr.lpSecurityDescriptor = NULL;
memset(&sinf,0,sizeof(sinf));
sinf.cb = sizeof(sinf);
sinf.dwFlags = detached ? 0 : STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
sinf.wShowWindow = SW_HIDE;
if( !detached ) {
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);
} else {
p->oread = NULL;
p->eread = NULL;
p->iwrite = NULL;
}
if( !CreateProcess(NULL,(uchar*)cmd,NULL,NULL,detached?FALSE:TRUE,detached?CREATE_NEW_CONSOLE:0,NULL,NULL,&sinf,&p->pinf) ) {
// handles will be finalized
return NULL;
}
// close unused pipes
if( !detached ) {
CloseHandle(sinf.hStdOutput);
CloseHandle(sinf.hStdError);
CloseHandle(sinf.hStdInput);
}
# else
char **argv;
if( !vargs ) {
argv = (char**)malloc(sizeof(char*)*4);
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = (char*)cmd;
argv[3] = NULL;
} else {
int i;
if( vargs->at->kind != HBYTES )
return NULL;
argv = (char**)malloc(sizeof(char*)*(vargs->size+2));
argv[0] = (char*)cmd;
for(i=0;i<vargs->size;i++)
argv[i+1] = hl_aptr(vargs,char*)[i];
argv[i+1] = NULL;
}
int input[2], output[2], error[2];
if( pipe(input) || pipe(output) || pipe(error) )
return NULL;
p = (vprocess*)hl_gc_alloc_finalizer(sizeof(vprocess));
#ifdef HL_TVOS
hl_error("hl_process_run() not available for this platform");
p->pid = -1;
#else
p->pid = fork();
#endif
if( p->pid == -1 ) {
close(input[0]);
close(input[1]);
close(output[0]);
close(output[1]);
close(error[0]);
close(error[1]);
return NULL;
}
// 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);
#ifdef HL_TVOS
hl_error("hl_process_run() not available for this platform");
#else
execvp(argv[0],argv);
#endif
fprintf(stderr,"Command not found : %s\n",cmd);
exit(1);
}
// parent
close(input[0]);
close(output[1]);
close(error[1]);
p->iwrite = input[1];
p->oread = output[0];
p->eread = error[0];
# endif
p->finalize = process_finalize;
return p;
}
HL_PRIM int hl_process_stdout_read( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !ReadFile(p->oread,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = read(p->oread,str+pos,len);
if( nbytes <= 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM int hl_process_stderr_read( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !ReadFile(p->eread,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = read(p->eread,str+pos,len);
if( nbytes <= 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM int hl_process_stdin_write( vprocess *p, vbyte *str, int pos, int len ) {
# ifdef HL_WIN
DWORD nbytes;
if( !WriteFile(p->iwrite,str+pos,len,&nbytes,NULL) )
return -1;
return nbytes;
# else
int nbytes = write(p->iwrite,str+pos,len);
if( nbytes < 0 )
return -1;
return nbytes;
# endif
}
HL_PRIM bool hl_process_stdin_close( vprocess *p ) {
# ifdef HL_WIN
if( !CloseHandle(p->iwrite) )
return false;
# else
if( close(p->iwrite) )
return false;
p->iwrite = -1;
# endif
return true;
}
HL_PRIM int hl_process_exit( vprocess *p, bool *running ) {
# ifdef HL_WIN
DWORD rval;
if( !running )
WaitForSingleObject(p->pinf.hProcess,INFINITE);
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
return -1;
if( running ) {
*running = rval == STILL_ACTIVE;
if( *running ) rval = 0;
}
return rval;
# else
int rval = 0;
int wret = waitpid(p->pid,&rval,running ? WNOHANG : 0);
if( running ) *running = false;
if( wret != p->pid ) {
if( running ) {
if( wret == 0 )
*running = true;
return 0;
} else
return -1;
}
if( !WIFEXITED(rval) ) {
if( WIFSIGNALED(rval) )
return 0x40000000 | WTERMSIG(rval);
return -2;
}
return WEXITSTATUS(rval);
# endif
}
HL_PRIM int hl_process_pid( vprocess *p ) {
# ifdef HL_WIN
return p->pinf.dwProcessId;
# else
return p->pid;
# endif
}
HL_PRIM void hl_process_close( vprocess *p ) {
if( !p->finalize ) return;
p->finalize = NULL;
process_finalize(p);
}
HL_PRIM void hl_process_kill( vprocess *p ) {
# ifdef HL_WIN
TerminateProcess(p->pinf.hProcess,0xCDCDCDCD);
# elif defined(HL_IOS) || defined(HL_TVOS)
hl_error("hl_process_kill() not available on this platform");
# else
kill(p->pid,9);
# endif
}
#define _PROCESS _ABSTRACT(hl_process)
DEFINE_PRIM( _PROCESS, process_run, _BYTES _ARR _BOOL);
DEFINE_PRIM( _I32, process_stdout_read, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _I32, process_stderr_read, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _BOOL, process_stdin_close, _PROCESS);
DEFINE_PRIM( _I32, process_stdin_write, _PROCESS _BYTES _I32 _I32);
DEFINE_PRIM( _I32, process_exit, _PROCESS _REF(_BOOL));
DEFINE_PRIM( _I32, process_pid, _PROCESS);
DEFINE_PRIM( _VOID, process_close, _PROCESS);
DEFINE_PRIM( _VOID, process_kill, _PROCESS);
/* ************************************************************************ */

View File

@ -0,0 +1,120 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <time.h>
#include <string.h>
#if defined(HL_WIN_DESKTOP)
# include <windows.h>
# include <process.h>
#elif defined(HL_CONSOLE)
# include <posix/posix.h>
#else
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
#endif
#define NSEEDS 25
#define MAX 7
typedef struct _rnd rnd;
struct _rnd {
unsigned long seeds[NSEEDS];
unsigned long cur;
};
static unsigned long mag01[2]={
0x0, 0x8ebfd028 // magic, don't change
};
static const unsigned long init_seeds[] = {
0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23,
0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825,
0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f,
0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9,
0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb
};
HL_PRIM rnd *hl_rnd_alloc() {
return (rnd*)hl_gc_alloc_noptr(sizeof(rnd));
}
HL_PRIM void hl_rnd_set_seed( rnd *r, int s ) {
int i;
r->cur = 0;
memcpy(r->seeds,init_seeds,sizeof(init_seeds));
for(i=0;i<NSEEDS;i++)
r->seeds[i] ^= s;
}
HL_PRIM rnd *hl_rnd_init_system() {
rnd *r = hl_rnd_alloc();
int pid = getpid();
unsigned int time;
#ifdef HL_WIN
time = GetTickCount();
#else
struct timeval t;
gettimeofday(&t,NULL);
time = t.tv_sec * 1000000 + t.tv_usec;
#endif
#ifdef HL_DEBUG_REPRO
// fixed random seed
time = 4644546;
pid = 0;
#endif
hl_rnd_set_seed(r,time ^ (pid | (pid << 16)));
return r;
}
HL_PRIM unsigned int hl_rnd_int( rnd *r ) {
unsigned int y;
int pos = r->cur++;
if( pos >= NSEEDS ) {
int kk;
for(kk=0;kk<NSEEDS-MAX;kk++)
r->seeds[kk] = r->seeds[kk+MAX] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
for(;kk<NSEEDS;kk++)
r->seeds[kk] = r->seeds[kk+(MAX-NSEEDS)] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
r->cur = 1;
pos = 0;
}
y = r->seeds[pos];
y ^= (y << 7) & 0x2b5b2500;
y ^= (y << 15) & 0xdb8b0000;
y ^= (y >> 16);
return y;
}
HL_PRIM double hl_rnd_float( rnd *r ) {
double big = 4294967296.0;
return ((hl_rnd_int(r) / big + hl_rnd_int(r)) / big + hl_rnd_int(r)) / big;
}
#define _RND _ABSTRACT(hl_random)
DEFINE_PRIM(_RND,rnd_alloc,_NO_ARG);
DEFINE_PRIM(_RND,rnd_init_system, _NO_ARG);
DEFINE_PRIM(_VOID,rnd_set_seed, _RND _I32);
DEFINE_PRIM(_I32,rnd_int, _RND);
DEFINE_PRIM(_F64,rnd_float, _RND);

View File

@ -0,0 +1,131 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#define PCRE2_STATIC
#include <pcre2.h>
typedef struct _ereg ereg;
struct _ereg {
void (*finalize)( ereg * );
/* The compiled regex code */
pcre2_code *regex;
/* Pointer to the allocated memory for match data */
pcre2_match_data *match_data;
/* Number of capture groups */
int n_groups;
/* Whether the last string was matched successfully */
bool matched;
};
static void regexp_finalize( ereg *e ) {
pcre2_code_free(e->regex);
pcre2_match_data_free(e->match_data);
}
HL_PRIM ereg *hl_regexp_new_options( vbyte *str, vbyte *opts ) {
ereg *r;
int error_code;
size_t error_offset;
pcre2_code *p;
uchar *o = (uchar*)opts;
int options = PCRE2_UCP | PCRE2_UTF | PCRE2_ALT_BSUX | PCRE2_ALLOW_EMPTY_CLASS | PCRE2_MATCH_UNSET_BACKREF;
while( *o ) {
switch( *o++ ) {
case 'i':
options |= PCRE2_CASELESS;
break;
case 's':
options |= PCRE2_DOTALL;
break;
case 'm':
options |= PCRE2_MULTILINE;
break;
case 'u':
break;
case 'g':
options |= PCRE2_UNGREEDY;
break;
default:
return NULL;
}
}
p = pcre2_compile((PCRE2_SPTR)str,PCRE2_ZERO_TERMINATED,options,&error_code,&error_offset,NULL);
if( p == NULL ) {
hl_buffer *b = hl_alloc_buffer();
vdynamic *d = hl_alloc_dynamic(&hlt_bytes);
PCRE2_UCHAR error_buffer[256];
pcre2_get_error_message(error_code,error_buffer,sizeof(error_buffer));
hl_buffer_str(b,USTR("Regexp compilation error : "));
hl_buffer_str(b,error_buffer);
hl_buffer_str(b,USTR(" in "));
hl_buffer_str(b,(uchar*)str);
d->v.bytes = (vbyte*)hl_buffer_content(b,NULL);
hl_throw(d);
}
r = (ereg*)hl_gc_alloc_finalizer(sizeof(ereg));
r->finalize = regexp_finalize;
r->regex = p;
r->matched = 0;
r->n_groups = 0;
pcre2_pattern_info(p,PCRE2_INFO_CAPTURECOUNT,&r->n_groups);
r->n_groups++;
r->match_data = pcre2_match_data_create_from_pattern(r->regex,NULL);
return r;
}
HL_PRIM int hl_regexp_matched_pos( ereg *e, int m, int *len ) {
int start;
size_t *matches = pcre2_get_ovector_pointer(e->match_data);
if( !e->matched )
hl_error("Calling regexp_matched_pos() on an unmatched regexp");
if( m < 0 || m >= e->n_groups )
hl_error("Matched index %d outside bounds",m);
start = matches[m*2];
if( len ) *len = matches[m*2+1] - start;
return start;
}
HL_PRIM int hl_regexp_matched_num( ereg *e ) {
if( !e->matched )
return -1;
else
return e->n_groups;
}
HL_PRIM bool hl_regexp_match( ereg *e, vbyte *s, int pos, int len ) {
int res = pcre2_match(e->regex,(PCRE2_SPTR)s,pos+len,pos,PCRE2_NO_UTF_CHECK,e->match_data,NULL);
e->matched = res >= 0;
if( res >= 0 )
return true;
if( res != PCRE2_ERROR_NOMATCH )
hl_error("An error occurred while running pcre2_match()");
return false;
}
#define _EREG _ABSTRACT(ereg)
DEFINE_PRIM( _EREG, regexp_new_options, _BYTES _BYTES);
DEFINE_PRIM( _I32, regexp_matched_pos, _EREG _I32 _REF(_I32));
DEFINE_PRIM( _I32, regexp_matched_num, _EREG );
DEFINE_PRIM( _BOOL, regexp_match, _EREG _BYTES _I32 _I32);

View File

@ -0,0 +1,504 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef _WIN32
#define FD_SETSIZE 65536
#pragma warning(disable:4548)
# include <string.h>
# define _WINSOCKAPI_
# include <hl.h>
# include <winsock2.h>
# define FDSIZE(n) (sizeof(void*) + (n) * sizeof(SOCKET))
# define SHUT_WR SD_SEND
# define SHUT_RD SD_RECEIVE
# define SHUT_RDWR SD_BOTH
typedef int _sockaddr;
typedef int socklen_t;
#else
#if defined(__ORBIS__) || defined(__NX__)
# include <hl.h>
# include <posix/posix.h>
#else
# define _GNU_SOURCE
# include <string.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <unistd.h>
# include <netdb.h>
# include <poll.h>
# include <fcntl.h>
# include <errno.h>
# include <stdio.h>
#endif
typedef int SOCKET;
# define closesocket close
# define SOCKET_ERROR (-1)
# define INVALID_SOCKET (-1)
typedef unsigned int _sockaddr;
#endif
#ifdef HL_LINUX
# include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44)
# include <sys/epoll.h>
# define HAS_EPOLL
#endif
#endif
#ifndef HAS_EPOLL
# define EPOLLIN 0x001
# define EPOLLOUT 0x004
#endif
#include <hl.h>
#if defined(HL_WIN) || defined(HL_MAC) || defined(HL_IOS) || defined(HL_TVOS)
# define MSG_NOSIGNAL 0
#endif
typedef struct _hl_socket {
SOCKET sock;
} hl_socket;
static int block_error() {
#ifdef HL_WIN
int err = WSAGetLastError();
if( err == WSAEWOULDBLOCK || err == WSAEALREADY || err == WSAETIMEDOUT )
#else
if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
#endif
return -1;
return -2;
}
HL_PRIM void hl_socket_init() {
#ifdef HL_WIN
static bool init_done = false;
static WSADATA init_data;
if( !init_done ) {
WSAStartup(MAKEWORD(2,0),&init_data);
init_done = true;
}
#endif
}
HL_PRIM hl_socket *hl_socket_new( bool udp ) {
SOCKET s;
if( udp )
s = socket(AF_INET,SOCK_DGRAM,0);
else
s = socket(AF_INET,SOCK_STREAM,0);
if( s == INVALID_SOCKET )
return NULL;
# ifdef HL_MAC
setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0);
# endif
# ifdef HL_POSIX
// we don't want sockets to be inherited in case of exec
{
int old = fcntl(s,F_GETFD,0);
if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC);
}
# endif
{
hl_socket *hs = hl_gc_alloc_noptr(sizeof(hl_socket));
hs->sock = s;
return hs;
}
}
HL_PRIM void hl_socket_close( hl_socket *s ) {
if( !s ) return;
closesocket(s->sock);
s->sock = INVALID_SOCKET;
}
HL_PRIM int hl_socket_send_char( hl_socket *s, int c ) {
char cc;
cc = (char)(unsigned char)c;
if( !s )
return -2;
if( send(s->sock,&cc,1,MSG_NOSIGNAL) == SOCKET_ERROR )
return block_error();
return 1;
}
HL_PRIM int hl_socket_send( hl_socket *s, vbyte *buf, int pos, int len ) {
int r;
if( !s )
return -2;
r = send(s->sock, (char*)buf + pos, len, MSG_NOSIGNAL);
if( r == SOCKET_ERROR )
return block_error();
return len;
}
HL_PRIM int hl_socket_recv( hl_socket *s, vbyte *buf, int pos, int len ) {
int ret;
if( !s )
return -2;
hl_blocking(true);
ret = recv(s->sock, (char*)buf + pos, len, MSG_NOSIGNAL);
hl_blocking(false);
if( ret == SOCKET_ERROR )
return block_error();
return ret;
}
HL_PRIM int hl_socket_recv_char( hl_socket *s ) {
char cc;
int ret;
if( !s ) return -2;
hl_blocking(true);
ret = recv(s->sock,&cc,1,MSG_NOSIGNAL);
hl_blocking(false);
if( ret == SOCKET_ERROR )
return block_error();
if( ret == 0 )
return -2;
return (unsigned char)cc;
}
HL_PRIM int hl_host_resolve( vbyte *host ) {
unsigned int ip;
hl_blocking(true);
ip = inet_addr((char*)host);
if( ip == INADDR_NONE ) {
struct hostent *h;
# if defined(HL_WIN) || defined(HL_MAC) || defined(HL_IOS) || defined(HL_TVOS) || defined (HL_CYGWIN) || defined(HL_CONSOLE)
h = gethostbyname((char*)host);
# else
struct hostent hbase;
char buf[1024];
int errcode;
gethostbyname_r((char*)host,&hbase,buf,1024,&h,&errcode);
# endif
if( h == NULL ) {
hl_blocking(false);
return -1;
}
ip = *((unsigned int*)h->h_addr_list[0]);
}
hl_blocking(false);
return ip;
}
HL_PRIM vbyte *hl_host_to_string( int ip ) {
struct in_addr i;
*(int*)&i = ip;
return (vbyte*)inet_ntoa(i);
}
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 vbyte *hl_host_local() {
char buf[256];
if( gethostname(buf,256) == SOCKET_ERROR )
return NULL;
return hl_copy_bytes((vbyte*)buf,(int)strlen(buf)+1);
}
HL_PRIM bool hl_socket_connect( hl_socket *s, int host, int port ) {
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
*(int*)&addr.sin_addr.s_addr = host;
if( !s ) return false;
hl_blocking(true);
if( connect(s->sock,(struct sockaddr*)&addr,sizeof(addr)) != 0 ) {
int err = block_error();
hl_blocking(false);
if( err == -1 ) return true; // in progress
return false;
}
hl_blocking(false);
return true;
}
HL_PRIM bool hl_socket_listen( hl_socket *s, int n ) {
if( !s ) return false;
return listen(s->sock,n) != SOCKET_ERROR;
}
HL_PRIM bool hl_socket_bind( hl_socket *s, int host, int port ) {
struct sockaddr_in addr;
if( !s ) return false;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
*(int*)&addr.sin_addr.s_addr = host;
#ifndef HL_WIN
int opt = 1;
setsockopt(s->sock,SOL_SOCKET,SO_REUSEADDR,(char*)&opt,sizeof(opt));
#endif
return bind(s->sock,(struct sockaddr*)&addr,sizeof(addr)) != SOCKET_ERROR;
}
HL_PRIM hl_socket *hl_socket_accept( hl_socket *s ) {
struct sockaddr_in addr;
_sockaddr addrlen = sizeof(addr);
SOCKET nsock;
hl_socket *hs;
if( !s ) return NULL;
hl_blocking(true);
nsock = accept(s->sock,(struct sockaddr*)&addr,&addrlen);
hl_blocking(false);
if( nsock == INVALID_SOCKET )
return NULL;
hs = (hl_socket*)hl_gc_alloc_noptr(sizeof(hl_socket));
hs->sock = nsock;
return hs;
}
HL_PRIM bool hl_socket_peer( hl_socket *s, int *host, int *port ) {
struct sockaddr_in addr;
_sockaddr addrlen = sizeof(addr);
if( !s || getpeername(s->sock,(struct sockaddr*)&addr,&addrlen) == SOCKET_ERROR )
return false;
*host = *(int*)&addr.sin_addr;
*port = ntohs(addr.sin_port);
return true;
}
HL_PRIM bool hl_socket_host( hl_socket *s, int *host, int *port ) {
struct sockaddr_in addr;
_sockaddr addrlen = sizeof(addr);
if( !s || getsockname(s->sock,(struct sockaddr*)&addr,&addrlen) == SOCKET_ERROR )
return false;
*host = *(int*)&addr.sin_addr;
*port = ntohs(addr.sin_port);
return true;
}
static void init_timeval( double f, struct timeval *t ) {
t->tv_usec = (int)((f - (int)f) * 1000000);
t->tv_sec = (int)f;
}
HL_PRIM bool hl_socket_set_timeout( hl_socket *s, double t ) {
#ifdef HL_WIN
int time = (int)(t * 1000);
#else
struct timeval time;
init_timeval(t,&time);
#endif
if( !s ) return false;
if( setsockopt(s->sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&time,sizeof(time)) != 0 )
return false;
if( setsockopt(s->sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&time,sizeof(time)) != 0 )
return false;
return true;
}
HL_PRIM bool hl_socket_shutdown( hl_socket *s, bool r, bool w ) {
if( !s )
return false;
if( !r && !w )
return true;
return shutdown(s->sock,r?(w?SHUT_RDWR:SHUT_RD):SHUT_WR) == 0;
}
HL_PRIM bool hl_socket_set_blocking( hl_socket *s, bool b ) {
#ifdef HL_WIN
unsigned long arg = b?0:1;
if( !s ) return false;
return ioctlsocket(s->sock,FIONBIO,&arg) == 0;
#else
int rights;
if( !s ) return false;
rights = fcntl(s->sock,F_GETFL);
if( rights == -1 )
return false;
if( b )
rights &= ~O_NONBLOCK;
else
rights |= O_NONBLOCK;
return fcntl(s->sock,F_SETFL,rights) != -1;
#endif
}
HL_PRIM bool hl_socket_set_fast_send( hl_socket *s, bool b ) {
int fast = b;
if( !s ) return false;
return setsockopt(s->sock,IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) == 0;
}
HL_PRIM int hl_socket_send_to( hl_socket *s, char *data, int len, int host, int port ) {
struct sockaddr_in addr;
if( !s ) return -2;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
*(int*)&addr.sin_addr.s_addr = host;
len = sendto(s->sock, data, len, MSG_NOSIGNAL, (struct sockaddr*)&addr, sizeof(addr));
if( len == SOCKET_ERROR )
return block_error();
return len;
}
HL_PRIM int hl_socket_recv_from( hl_socket *s, char *data, int len, int *host, int *port ) {
struct sockaddr_in saddr;
socklen_t slen = sizeof(saddr);
if( !s ) return -2;
hl_blocking(true);
len = recvfrom(s->sock, data, len, MSG_NOSIGNAL, (struct sockaddr*)&saddr, &slen);
hl_blocking(false);
if( len == SOCKET_ERROR ) {
#ifdef HL_WIN
if( WSAGetLastError() == WSAECONNRESET )
len = 0;
else
#endif
return block_error();
}
*host = *(int*)&saddr.sin_addr;
*port = ntohs(saddr.sin_port);
return len;
}
HL_PRIM int hl_socket_fd_size( int size ) {
if( size > FD_SETSIZE )
return -1;
# ifdef HL_WIN
return FDSIZE(size);
# else
return sizeof(fd_set);
# endif
}
static fd_set *make_socket_set( varray *a, char **tmp, int *tmp_size, unsigned int *max ) {
fd_set *set = (fd_set*)*tmp;
int i, req;
if( a == NULL )
return set;
req = hl_socket_fd_size(a->size);
if( *tmp_size < req )
return NULL;
*tmp_size -= req;
*tmp += req;
FD_ZERO(set);
for(i=0;i<a->size;i++) {
hl_socket *s= hl_aptr(a,hl_socket*)[i];
if( s== NULL ) break;
if( s->sock > *max ) *max = (int)s->sock;
FD_SET(s->sock,set);
}
return set;
}
static void make_array_result( fd_set *set, varray *a ) {
int i;
int pos = 0;
hl_socket **aptr = hl_aptr(a,hl_socket*);
if( a == NULL )
return;
for(i=0;i<a->size;i++) {
hl_socket *s = aptr[i];
if( s == NULL )
break;
if( FD_ISSET(s->sock,set) )
aptr[pos++] = s;
}
if( pos < a->size )
aptr[pos++] = NULL;
}
HL_PRIM bool hl_socket_select( varray *ra, varray *wa, varray *ea, char *tmp, int tmp_size, double timeout ) {
struct timeval tval, *tt;
fd_set *rs, *ws, *es;
unsigned int max = 0;
rs = make_socket_set(ra,&tmp,&tmp_size,&max);
ws = make_socket_set(wa,&tmp,&tmp_size,&max);
es = make_socket_set(ea,&tmp,&tmp_size,&max);
if( rs == NULL || ws == NULL || es == NULL )
return false;
if( timeout < 0 )
tt = NULL;
else {
tt = &tval;
init_timeval(timeout,tt);
}
hl_blocking(true);
if( select((int)(max+1),ra?rs:NULL,wa?ws:NULL,ea?es:NULL,tt) == SOCKET_ERROR ) {
hl_blocking(false);
return false;
}
hl_blocking(false);
make_array_result(rs,ra);
make_array_result(ws,wa);
make_array_result(es,ea);
return true;
}
#define _SOCK _ABSTRACT(hl_socket)
DEFINE_PRIM(_VOID,socket_init,_NO_ARG);
DEFINE_PRIM(_SOCK,socket_new,_BOOL);
DEFINE_PRIM(_VOID,socket_close,_SOCK);
DEFINE_PRIM(_I32,socket_send_char,_SOCK _I32);
DEFINE_PRIM(_I32,socket_send,_SOCK _BYTES _I32 _I32 );
DEFINE_PRIM(_I32,socket_recv,_SOCK _BYTES _I32 _I32 );
DEFINE_PRIM(_I32,socket_recv_char, _SOCK);
DEFINE_PRIM(_I32,host_resolve,_BYTES);
DEFINE_PRIM(_BYTES,host_to_string,_I32);
DEFINE_PRIM(_BYTES,host_reverse,_I32);
DEFINE_PRIM(_BYTES,host_local,_NO_ARG);
DEFINE_PRIM(_BOOL,socket_connect,_SOCK _I32 _I32);
DEFINE_PRIM(_BOOL,socket_listen,_SOCK _I32);
DEFINE_PRIM(_BOOL,socket_bind,_SOCK _I32 _I32);
DEFINE_PRIM(_SOCK,socket_accept,_SOCK);
DEFINE_PRIM(_BOOL,socket_peer,_SOCK _REF(_I32) _REF(_I32));
DEFINE_PRIM(_BOOL,socket_host,_SOCK _REF(_I32) _REF(_I32));
DEFINE_PRIM(_BOOL,socket_set_timeout,_SOCK _F64);
DEFINE_PRIM(_BOOL,socket_shutdown,_SOCK _BOOL _BOOL);
DEFINE_PRIM(_BOOL,socket_set_blocking,_SOCK _BOOL);
DEFINE_PRIM(_BOOL,socket_set_fast_send,_SOCK _BOOL);
DEFINE_PRIM(_I32, socket_send_to, _SOCK _BYTES _I32 _I32 _I32);
DEFINE_PRIM(_I32, socket_recv_from, _SOCK _BYTES _I32 _REF(_I32) _REF(_I32));
DEFINE_PRIM(_I32, socket_fd_size, _I32 );
DEFINE_PRIM(_BOOL, socket_select, _ARR _ARR _ARR _BYTES _I32 _F64);

View File

@ -0,0 +1,130 @@
#define m_sort TID(m_sort)
#define ms_compare TID(ms_compare)
#define ms_swap TID(ms_swap)
#define ms_lower TID(ms_lower)
#define ms_upper TID(ms_upper)
#define ms_rotate TID(ms_rotate)
#define ms_do_merge TID(ms_do_merge)
#define merge_sort_rec TID(merge_sort_rec)
typedef struct {
TSORT *arr;
vclosure *c;
} m_sort;
static int ms_compare( m_sort *m, int a, int b ) {
return m->c->hasValue ? ((int(*)(void*,TSORT,TSORT))m->c->fun)(m->c->value,m->arr[a],m->arr[b]) : ((int(*)(TSORT,TSORT))m->c->fun)(m->arr[a],m->arr[b]);
}
static void ms_swap( m_sort *m, int a, int b ) {
TSORT tmp = m->arr[a];
m->arr[a] = m->arr[b];
m->arr[b] = tmp;
}
static int ms_lower( m_sort *m, int from, int to, int val ) {
int len = to - from, half, mid;
while( len > 0 ) {
half = len>>1;
mid = from + half;
if( ms_compare(m, mid, val) < 0 ) {
from = mid+1;
len = len - half -1;
} else
len = half;
}
return from;
}
static int ms_upper( m_sort *m, int from, int to, int val ) {
int len = to - from, half, mid;
while( len > 0 ) {
half = len>>1;
mid = from + half;
if( ms_compare(m, val, mid) < 0 )
len = half;
else {
from = mid+1;
len = len - half -1;
}
}
return from;
}
static void ms_rotate( m_sort *m, int from, int mid, int to ) {
int n;
if( from==mid || mid==to ) return;
n = ms_gcd(to - from, mid - from);
while (n-- != 0) {
TSORT val = m->arr[from+n];
int shift = mid - from;
int p1 = from+n, p2=from+n+shift;
while (p2 != from + n) {
m->arr[p1] = m->arr[p2];
p1=p2;
if( to - p2 > shift) p2 += shift;
else p2=from + (shift - (to - p2));
}
m->arr[p1] = val;
}
}
static void ms_do_merge( m_sort *m, int from, int pivot, int to, int len1, int len2 ) {
int first_cut, second_cut, len11, len22, new_mid;
if( len1 == 0 || len2==0 )
return;
if( len1+len2 == 2 ) {
if( ms_compare(m, pivot, from) < 0 )
ms_swap(m, pivot, from);
return;
}
if (len1 > len2) {
len11=len1>>1;
first_cut = from + len11;
second_cut = ms_lower(m, pivot, to, first_cut);
len22 = second_cut - pivot;
} else {
len22 = len2>>1;
second_cut = pivot + len22;
first_cut = ms_upper(m, from, pivot, second_cut);
len11=first_cut - from;
}
ms_rotate(m, first_cut, pivot, second_cut);
new_mid=first_cut+len22;
ms_do_merge(m, from, first_cut, new_mid, len11, len22);
ms_do_merge(m, new_mid, second_cut, to, len1 - len11, len2 - len22);
}
static void merge_sort_rec( m_sort *m, int from, int to ) {
int middle;
if( to - from < 12 ) {
// insert sort
int i;
if( to <= from ) return;
for(i=from+1;i<to;i++) {
int j = i;
while( j > from ) {
if( ms_compare(m,j,j-1) < 0 )
ms_swap(m,j-1,j);
else
break;
j--;
}
}
return;
}
middle = (from + to)>>1;
merge_sort_rec(m, from, middle);
merge_sort_rec(m, middle, to);
ms_do_merge(m, from, middle, to, middle-from, to - middle);
}
#undef ms_compare
#undef ms_swap
#undef ms_lower
#undef ms_upper
#undef ms_rotate
#undef ms_do_merge
#undef merge_sort_rec
#undef m_sort
#undef TSORT
#undef TID

View File

@ -0,0 +1,383 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM vbyte *hl_itos( int i, int *len ) {
uchar tmp[24];
int k = (int)usprintf(tmp,24,USTR("%d"),i);
*len = k;
return hl_copy_bytes((vbyte*)tmp,(k + 1)<<1);
}
HL_PRIM vbyte *hl_ftos( double d, int *len ) {
uchar tmp[24];
int k;
if( d != d ) {
*len = 3;
return hl_copy_bytes((vbyte*)USTR("NaN"),8);
}
// don't use the last digit (eg 5.1 = 5.09999..996)
// also cut one more digit for some numbers (eg 86.57 and 85.18) <- to fix since we lose one PI digit
k = (int)usprintf(tmp,24,USTR("%.15g"),d);
# if defined(HL_WIN) && _MSC_VER <= 1800
// fix for window : 1e-5 is printed as 1e-005 whereas it's 1e-05 on other platforms
// note : this is VS2013 std bug, VS2015 works correctly
{
int i;
for(i=0;i<k;i++)
if( tmp[i] == 'e' ) {
if( tmp[i+1] == '+' || tmp[i+1] == '-' ) i++;
if( tmp[i+1] != '0' || tmp[i+2] != '0' ) break;
memmove(tmp+i+1,tmp+i+2,(k-(i+1))*2);
k--;
break;
}
}
# endif
*len = k;
return hl_copy_bytes((vbyte*)tmp,(k + 1) << 1);
}
HL_PRIM vbyte *hl_value_to_string( vdynamic *d, int *len ) {
if( d == NULL ) {
*len = 4;
return (vbyte*)USTR("null");
}
switch( d->t->kind ) {
case HI32:
return hl_itos(d->v.i,len);
case HF64:
return hl_ftos(d->v.d,len);
default:
{
hl_buffer *b = hl_alloc_buffer();
hl_buffer_val(b, d);
return (vbyte*)hl_buffer_content(b,len);
}
}
}
HL_PRIM int hl_ucs2length( vbyte *str, int pos ) {
return (int)ustrlen((uchar*)(str + pos));
}
HL_PRIM int hl_utf8_length( const vbyte *s, int pos ) {
int len = 0;
s += pos;
while( true ) {
unsigned char c = (unsigned)*s;
len++;
if( c < 0x80 ) {
if( c == 0 ) {
len--;
break;
}
s++;
} else if( c < 0xC0 )
return len - 1;
else if( c < 0xE0 ) {
if( (s[1]&0x80) == 0 ) return len - 1;
s += 2;
} else if( c < 0xF0 ) {
if( ((s[1]&s[2])&0x80) == 0 ) return len - 1;
s+=3;
} else if( c < 0xF8 ) {
if( ((s[1]&s[2]&s[3])&0x80) == 0 ) return len - 1;
len++; // surrogate pair
s+=4;
} else
return len;
}
return len;
}
HL_PRIM int hl_from_utf8( uchar *out, int outLen, const char *str ) {
int p = 0;
unsigned int c, c2, c3;
while( p++ < outLen ) {
c = *(unsigned char *)str++;
if( c < 0x80 ) {
if( c == 0 ) break;
// nothing
} else if( c < 0xE0 ) {
c = ((c & 0x3F) << 6) | ((*str++)&0x7F);
} else if( c < 0xF0 ) {
c2 = (unsigned)*str++;
c = ((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | ((*str++) & 0x7F);
} else {
c2 = (unsigned)*str++;
c3 = (unsigned)*str++;
c = (((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | ((*str++) & 0x7F)) - 0x10000;
// surrogate pair
if( p++ == outLen ) break;
*out++ = (uchar)((c >> 10) + 0xD800);
*out++ = (uchar)((c & 0x3FF) | 0xDC00);
continue;
}
*out++ = (uchar)c;
}
*out = 0;
return --p;
}
HL_PRIM uchar *hl_to_utf16( const char *str ) {
int len = hl_utf8_length((vbyte*)str,0);
uchar *out = (uchar*)hl_gc_alloc_noptr((len + 1) * sizeof(uchar));
hl_from_utf8(out,len,str);
return out;
}
HL_PRIM vbyte* hl_utf8_to_utf16( vbyte *str, int pos, int *size ) {
int ulen = hl_utf8_length(str, pos);
uchar *s = (uchar*)hl_gc_alloc_noptr((ulen + 1)*sizeof(uchar));
hl_from_utf8(s,ulen,(char*)(str+pos));
*size = ulen << 1;
return (vbyte*)s;
}
#include "unicase.h"
HL_PRIM vbyte* hl_ucs2_upper( vbyte *str, int pos, int len ) {
uchar *cstr = (uchar*)(str + pos);
uchar *out = (uchar*)hl_gc_alloc_noptr((len + 1) * sizeof(uchar));
int i;
uchar *cout = out;
memcpy(out,cstr,len << 1);
for(i=0;i<len;i++) {
unsigned int c = *cstr++;
int up = c >> UL_BITS;
if( up < UMAX ) {
unsigned int c2 = UPPER[up][c&((1<<UL_BITS)-1)];
if( c2 != 0 ) *cout = (uchar)c2;
}
cout++;
}
*cout = 0;
return (vbyte*)out;
}
HL_PRIM vbyte* hl_ucs2_lower( vbyte *str, int pos, int len ) {
uchar *cstr = (uchar*)(str + pos);
uchar *out = (uchar*)hl_gc_alloc_noptr((len + 1) * sizeof(uchar));
uchar *cout = out;
int i;
memcpy(out,cstr,len << 1);
for(i=0;i<len;i++) {
unsigned int c = *cstr++;
int up = c >> UL_BITS;
if( up < LMAX ) {
unsigned int c2 = LOWER[up][c&((1<<UL_BITS)-1)];
if( c2 != 0 ) *cout = (uchar)c2;
}
cout++;
}
*cout = 0;
return (vbyte*)out;
}
HL_PRIM vbyte *hl_utf16_to_utf8( vbyte *str, int len, int *size ) {
vbyte *out;
uchar *c = (uchar*)str;
uchar *end = len == 0 ? NULL : c + len;
int utf8bytes = 0;
int p = 0;
while( c != end ) {
unsigned int v = (unsigned int)*c;
if( v == 0 && end == NULL ) break;
if( v < 0x80 )
utf8bytes++;
else if( v < 0x800 )
utf8bytes += 2;
else if( v >= 0xD800 && v <= 0xDFFF ) {
utf8bytes += 4;
c++;
} else
utf8bytes += 3;
c++;
}
out = hl_gc_alloc_noptr(utf8bytes + 1);
c = (uchar*)str;
while( c != end ) {
unsigned int v = (unsigned int)*c;
if( v < 0x80 ) {
out[p++] = (vbyte)v;
if( v == 0 && end == NULL ) break;
} else if( v < 0x800 ) {
out[p++] = (vbyte)(0xC0|(v>>6));
out[p++] = (vbyte)(0x80|(v&63));
} else if( v >= 0xD800 && v <= 0xDFFF ) {
int k = ((((int)v - 0xD800) << 10) | (((int)*++c) - 0xDC00)) + 0x10000;
out[p++] = (vbyte)(0xF0|(k>>18));
out[p++] = (vbyte)(0x80 | ((k >> 12) & 63));
out[p++] = (vbyte)(0x80 | ((k >> 6) & 63));
out[p++] = (vbyte)(0x80 | (k & 63));
} else {
out[p++] = (vbyte)(0xE0|(v>>12));
out[p++] = (vbyte)(0x80|((v>>6)&63));
out[p++] = (vbyte)(0x80|(v&63));
}
c++;
}
if( size ) *size = utf8bytes;
return out;
}
HL_PRIM char *hl_to_utf8( const uchar *bytes ) {
int size;
return (char*)hl_utf16_to_utf8((vbyte*)bytes, 0, &size);
}
static void hl_buffer_hex( hl_buffer *b, int c ) {
static const uchar *hex = USTR("0123456789ABCDEF");
hl_buffer_char(b,'%');
hl_buffer_char(b,hex[c>>4]);
hl_buffer_char(b,hex[c&0xF]);
}
HL_PRIM vbyte *hl_url_encode( vbyte *str, int *len ) {
hl_buffer *b = hl_alloc_buffer();
uchar *cstr = (uchar*)str;
unsigned int sur;
while( true ) {
unsigned int c = (unsigned)*cstr++;
if( c == 0 ) break;
if( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.' )
hl_buffer_char(b,(uchar)c);
else {
if( c < 0x80 ) {
hl_buffer_hex(b,c);
} else if( c < 0x800 ) {
hl_buffer_hex(b, 0xC0|(c>>6));
hl_buffer_hex(b, 0x80|(c&63));
} else if( c >= 0xD800 && c <= 0xDBFF ) {
sur = (unsigned)*cstr;
if( sur >= 0xDC00 && sur < 0xDFFF ) {
cstr++;
c = ((((int)c - 0xD800) << 10) | ((int)sur - 0xDC00)) + 0x10000;
hl_buffer_hex(b, 0xF0|(c>>18));
hl_buffer_hex(b, 0x80|((c >> 12) & 63));
hl_buffer_hex(b, 0x80|((c >> 6) & 63));
hl_buffer_hex(b, 0x80|(c & 63));
} else {
hl_buffer_hex(b, 0xE0|(c>>12));
hl_buffer_hex(b, 0x80|((c>>6)&63));
hl_buffer_hex(b, 0x80|(c&63));
}
} else {
hl_buffer_hex(b, 0xE0|(c>>12));
hl_buffer_hex(b, 0x80|((c>>6)&63));
hl_buffer_hex(b, 0x80|(c&63));
}
}
}
return (vbyte*)hl_buffer_content(b,len);
}
static uchar decode_hex_char( uchar c ) {
if( c >= '0' && c <= '9' )
c -= '0';
else if( c >= 'a' && c <= 'f' )
c -= 'a' - 10;
else if( c >= 'A' && c <= 'F' )
c -= 'A' - 10;
else
return (uchar)-1;
return c;
}
static uchar decode_hex( uchar **cstr ) {
uchar *c = *cstr;
uchar p1 = decode_hex_char(c[0]);
uchar p2;
if( p1 == (uchar)-1 ) return p1;
p2 = decode_hex_char(c[1]);
if( p2 == (uchar)-1 ) return p2;
*cstr = c + 2;
return (p1 << 4) | p2;
}
HL_PRIM vbyte *hl_url_decode( vbyte *str, int *len ) {
hl_buffer *b = hl_alloc_buffer();
uchar *cstr = (uchar*)str;
while( true ) {
uchar c = *cstr++;
if( c == 0 )
return (vbyte*)hl_buffer_content(b,len);
if( c == '+' )
c = ' ';
else if( c == '%' ) {
uchar p1 = decode_hex(&cstr);
if( p1 == (uchar)-1 ) {
hl_buffer_char(b,'%');
continue;
}
if( p1 < 0x80 ) {
c = p1;
} else if( p1 < 0xE0 ) {
uchar p2;
if( *cstr++ != '%' ) break;
p2 = decode_hex(&cstr);
if( p2 < 0 ) break;
c = ((p1 & 0x3F) << 6) | (p2&0x7F);
} else if( p1 < 0xF0 ) {
uchar p2, p3;
if( *cstr++ != '%' ) break;
p2 = decode_hex(&cstr);
if( p2 < 0 ) break;
if( *cstr++ != '%' ) break;
p3 = decode_hex(&cstr);
if( p3 < 0 ) break;
c = ((p1 & 0x1F) << 12) | ((p2 & 0x7F) << 6) | (p3 & 0x7F);
} else {
int k;
uchar p2, p3, p4;
if( *cstr++ != '%' ) break;
p2 = decode_hex(&cstr);
if( p2 < 0 ) break;
if( *cstr++ != '%' ) break;
p3 = decode_hex(&cstr);
if( p3 < 0 ) break;
if( *cstr++ != '%' ) break;
p4 = decode_hex(&cstr);
if( p4 < 0 ) break;
k = (((p1 & 0x0F) << 18) | ((p2 & 0x7F) << 12) | ((p3 & 0x7F) << 6) | (p4 & 0x7F)) - 0x10000;
hl_buffer_char(b,(uchar)((k >> 10) + 0xD800));
c = (uchar)((k & 0x3FF) | 0xDC00);
}
}
hl_buffer_char(b,c);
}
hl_error("Malformed URL encoded");
return NULL;
}
DEFINE_PRIM(_BYTES,itos,_I32 _REF(_I32));
DEFINE_PRIM(_BYTES,ftos,_F64 _REF(_I32));
DEFINE_PRIM(_BYTES,value_to_string,_DYN _REF(_I32));
DEFINE_PRIM(_I32,ucs2length,_BYTES _I32);
DEFINE_PRIM(_BYTES,utf8_to_utf16,_BYTES _I32 _REF(_I32));
DEFINE_PRIM(_BYTES,utf16_to_utf8,_BYTES _I32 _REF(_I32));
DEFINE_PRIM(_BYTES,ucs2_upper,_BYTES _I32 _I32);
DEFINE_PRIM(_BYTES,ucs2_lower,_BYTES _I32 _I32);
DEFINE_PRIM(_BYTES,url_encode,_BYTES _REF(_I32));
DEFINE_PRIM(_BYTES,url_decode,_BYTES _REF(_I32));

View File

@ -0,0 +1,720 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#ifdef HL_CONSOLE
# include <posix/posix.h>
#endif
#if !defined(HL_CONSOLE) || defined(HL_WIN_DESKTOP)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(HL_WIN)
# include <windows.h>
# include <direct.h>
# include <conio.h>
# include <fcntl.h>
# include <io.h>
# define getenv _wgetenv
# define putenv _wputenv
# define getcwd(buf,size) (void*)(int_val)GetCurrentDirectoryW(size,buf)
# define chdir !SetCurrentDirectoryW
# define system _wsystem
typedef struct _stat32 pstat;
# define stat _wstat32
# define unlink _wunlink
# define rename _wrename
# define mkdir(path,mode) _wmkdir(path)
# define rmdir _wrmdir
#else
# include <errno.h>
# include <unistd.h>
# include <limits.h>
# include <sys/time.h>
# include <dirent.h>
# include <termios.h>
# include <sys/times.h>
# include <sys/wait.h>
# include <locale.h>
# define HL_UTF8PATH
typedef struct stat pstat;
#endif
#endif
#ifdef HL_UTF8PATH
typedef char pchar;
#define pstrchr strchr
#define pstrlen strlen
#else
typedef uchar pchar;
#define pstrchr wcschr
#define pstrlen ustrlen
#endif
#ifdef HL_MAC
# include <sys/syslimits.h>
# include <limits.h>
# include <mach-o/dyld.h>
#endif
#ifndef CLK_TCK
# define CLK_TCK 100
#endif
static pchar *pstrdup( const pchar *s, int len ) {
pchar *ret;
if( len < 0 ) len = (int)pstrlen(s);
ret = (pchar*)hl_copy_bytes((vbyte*)s,sizeof(pchar)*(len+1));;
ret[len] = 0;
return ret;
}
HL_PRIM bool hl_sys_utf8_path() {
#ifdef HL_UTF8PATH
return true;
#else
return false;
#endif
}
HL_PRIM vbyte *hl_sys_string() {
#if defined(HL_CONSOLE)
return (vbyte*)sys_platform_name();
#elif defined(HL_WIN) || defined(HL_CYGWIN) || defined(HL_MINGW)
return (vbyte*)USTR("Windows");
#elif defined(HL_BSD)
return (vbyte*)USTR("BSD");
#elif defined(HL_MAC)
return (vbyte*)USTR("Mac");
#elif defined(HL_IOS)
return (vbyte*)USTR("iOS");
#elif defined(HL_TVOS)
return (vbyte*)USTR("tvOS");
#elif defined(HL_ANDROID)
return (vbyte*)USTR("Android");
#elif defined(HL_GNUKBSD)
return (vbyte*)USTR("GNU/kFreeBSD");
#elif defined(HL_LINUX)
return (vbyte*)USTR("Linux");
#else
#error Unknown system string
#endif
}
HL_PRIM vbyte *hl_sys_locale() {
#if defined(HL_WIN_DESKTOP)
wchar_t loc[LOCALE_NAME_MAX_LENGTH];
int len = GetSystemDefaultLocaleName(loc,LOCALE_NAME_MAX_LENGTH);
return len == 0 ? NULL : hl_copy_bytes((vbyte*)loc,(len+1)*2);
#elif defined(HL_CONSOLE)
return (vbyte*)sys_get_user_lang();
#else
return (vbyte*)getenv("LANG");
#endif
}
#define PR_WIN_UTF8 1
#define PR_AUTO_FLUSH 2
static int print_flags = PR_AUTO_FLUSH;
HL_PRIM int hl_sys_set_flags( int flags ) {
return print_flags = flags;
}
HL_PRIM void hl_sys_print( vbyte *msg ) {
hl_blocking(true);
# ifdef HL_XBO
OutputDebugStringW((LPCWSTR)msg);
# else
# ifdef HL_WIN_DESKTOP
if( print_flags & PR_WIN_UTF8 ) _setmode(_fileno(stdout),_O_U8TEXT);
# endif
uprintf(USTR("%s"),(uchar*)msg);
if( print_flags & PR_AUTO_FLUSH ) fflush(stdout);
# ifdef HL_WIN_DESKTOP
if( print_flags & PR_WIN_UTF8 ) _setmode(_fileno(stdout),_O_TEXT);
# endif
# endif
hl_blocking(false);
}
static void *f_before_exit = NULL;
static void *f_profile_event = NULL;
HL_PRIM void hl_setup_profiler( void *profile_event, void *before_exit ) {
f_before_exit = before_exit;
f_profile_event = profile_event;
}
HL_PRIM void hl_sys_profile_event( int code, vbyte *data, int dataLen ) {
if( f_profile_event ) ((void(*)(int,vbyte*,int))f_profile_event)(code,data,dataLen);
}
HL_PRIM void hl_sys_exit( int code ) {
if( f_before_exit ) ((void(*)())f_before_exit)();
exit(code);
}
#ifdef HL_DEBUG_REPRO
static double CURT = 0;
#endif
HL_PRIM double hl_sys_time() {
#ifdef HL_DEBUG_REPRO
CURT += 0.001;
return CURT;
#endif
#ifdef HL_WIN
#define EPOCH_DIFF (134774*24*60*60.0)
static double time_diff = 0.;
static double freq = 0.;
LARGE_INTEGER time;
if( freq == 0 ) {
QueryPerformanceFrequency(&time);
freq = (double)time.QuadPart;
}
QueryPerformanceCounter(&time);
if( time_diff == 0 ) {
FILETIME ft;
LARGE_INTEGER start_time;
GetSystemTimeAsFileTime(&ft);
start_time.LowPart = ft.dwLowDateTime;
start_time.HighPart = ft.dwHighDateTime;
time_diff = (((double)start_time.QuadPart) / 10000000.0) - (((double)time.QuadPart) / freq) - EPOCH_DIFF;
}
return time_diff + ((double)time.QuadPart) / freq;
#else
struct timeval tv;
if( gettimeofday(&tv,NULL) != 0 )
return 0.;
return tv.tv_sec + ((double)tv.tv_usec) / 1000000.0;
#endif
}
HL_PRIM vbyte *hl_sys_get_env( vbyte *v ) {
return (vbyte*)getenv((pchar*)v);
}
HL_PRIM bool hl_sys_put_env( vbyte *e, vbyte *v ) {
#if defined(HL_WIN)
hl_buffer *b = hl_alloc_buffer();
hl_buffer_str(b,(uchar*)e);
hl_buffer_char(b,'=');
if( v ) hl_buffer_str(b,(uchar*)v);
return putenv(hl_buffer_content(b,NULL)) == 0;
#else
if( v == NULL ) return unsetenv((char*)e) == 0;
return setenv((char*)e,(char*)v,1) == 0;
#endif
}
#ifdef HL_MAC
# define environ (*_NSGetEnviron())
#endif
#ifdef HL_WIN_DESKTOP
# undef environ
# define environ _wenviron
#else
extern pchar **environ;
#endif
HL_PRIM varray *hl_sys_env() {
varray *a;
pchar **e = environ;
pchar **arr;
int count = 0;
# ifdef HL_WIN_DESKTOP
if( e == NULL ) {
_wgetenv(L"");
e = environ;
}
# endif
while( *e ) {
pchar *x = pstrchr(*e,'=');
if( x == NULL ) {
e++;
continue;
}
count++;
e++;
}
a = hl_alloc_array(&hlt_bytes,count*2);
e = environ;
arr = hl_aptr(a,pchar*);
while( *e ) {
pchar *x = pstrchr(*e,'=');
if( x == NULL ) {
e++;
continue;
}
*arr++ = pstrdup(*e,(int)(x - *e));
*arr++ = pstrdup(x+1,-1);
e++;
}
return a;
}
HL_PRIM void hl_sys_sleep( double f ) {
hl_blocking(true);
#if defined(HL_WIN)
Sleep((DWORD)(f * 1000));
#else
struct timespec t;
t.tv_sec = (int)f;
t.tv_nsec = (int)((f - t.tv_sec) * 1e9);
nanosleep(&t,NULL);
#endif
hl_blocking(false);
}
HL_PRIM bool hl_sys_set_time_locale( vbyte *l ) {
#ifdef HL_POSIX
locale_t lc, old;
lc = newlocale(LC_TIME_MASK,(char*)l,NULL);
if( lc == NULL ) return false;
old = uselocale(lc);
if( old == NULL ) {
freelocale(lc);
return false;
}
if( old != LC_GLOBAL_LOCALE )
freelocale(old);
return true;
#else
return setlocale(LC_TIME,(char*)l) != NULL;
#endif
}
HL_PRIM vbyte *hl_sys_get_cwd() {
pchar buf[256];
int l;
if( getcwd(buf,256) == NULL )
return NULL;
l = (int)pstrlen(buf);
if( buf[l-1] != '/' && buf[l-1] != '\\' ) {
buf[l] = '/';
buf[l+1] = 0;
}
return (vbyte*)pstrdup(buf,-1);
}
HL_PRIM bool hl_sys_set_cwd( vbyte *dir ) {
return chdir((pchar*)dir) == 0;
}
HL_PRIM bool hl_sys_is64() {
#ifdef HL_64
return true;
#else
return false;
#endif
}
HL_PRIM int hl_sys_command( vbyte *cmd ) {
#if defined(HL_WIN)
int ret;
hl_blocking(true);
ret = system((pchar*)cmd);
hl_blocking(false);
return ret;
#else
int status;
hl_blocking(true);
#if defined(HL_IOS) || defined(HL_TVOS)
status = 0;
hl_error("hl_sys_command() not available on this platform");
#else
status = system((pchar*)cmd);
#endif
hl_blocking(false);
return WEXITSTATUS(status) | (WTERMSIG(status) << 8);
#endif
}
HL_PRIM bool hl_sys_exists( vbyte *path ) {
pstat st;
return stat((pchar*)path,&st) == 0;
}
HL_PRIM bool hl_sys_delete( vbyte *path ) {
return unlink((pchar*)path) == 0;
}
HL_PRIM bool hl_sys_rename( vbyte *path, vbyte *newname ) {
return rename((pchar*)path,(pchar*)newname) == 0;
}
HL_PRIM varray *hl_sys_stat( vbyte *path ) {
pstat s;
varray *a;
int *i;
if( stat((pchar*)path,&s) != 0 )
return NULL;
a = hl_alloc_array(&hlt_i32,12);
i = hl_aptr(a,int);
*i++ = s.st_gid;
*i++ = s.st_uid;
*i++ = s.st_atime;
*i++ = s.st_mtime;
*i++ = s.st_ctime;
*i++ = s.st_size;
*i++ = s.st_dev;
*i++ = s.st_ino;
*i++ = s.st_nlink;
*i++ = s.st_rdev;
*i++ = s.st_mode;
return a;
}
HL_PRIM bool hl_sys_is_dir( vbyte *path ) {
pstat s;
if( stat((pchar*)path,&s) != 0 )
return false;
return (s.st_mode & S_IFDIR) != 0;
}
HL_PRIM bool hl_sys_create_dir( vbyte *path, int mode ) {
return mkdir((pchar*)path,mode) == 0;
}
HL_PRIM bool hl_sys_remove_dir( vbyte *path ) {
return rmdir((pchar*)path) == 0;
}
HL_PRIM int hl_sys_getpid() {
#ifdef HL_WIN
return GetCurrentProcessId();
#else
return getpid();
#endif
}
HL_PRIM double hl_sys_cpu_time() {
#if defined(HL_WIN)
FILETIME unused;
FILETIME stime;
FILETIME utime;
if( !GetProcessTimes(GetCurrentProcess(),&unused,&unused,&stime,&utime) )
return 0.;
return ((double)(utime.dwHighDateTime+stime.dwHighDateTime)) * 65.536 * 6.5536 + (((double)utime.dwLowDateTime + (double)stime.dwLowDateTime) / 10000000);
#else
struct tms t = {0};
times(&t);
return ((double)(t.tms_utime + t.tms_stime)) / CLK_TCK;
#endif
}
HL_PRIM 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) || defined(HL_CONSOLE)
hl_error("sys_thread_cpu_time not implemented on this platform");
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 varray *hl_sys_read_dir( vbyte *_path ) {
pchar *path = (pchar*)_path;
int count = 0;
int pos = 0;
varray *a = NULL;
pchar **current = NULL;
#ifdef HL_WIN
WIN32_FIND_DATAW d;
HANDLE handle;
hl_buffer *b = hl_alloc_buffer();
int len = (int)pstrlen(path);
hl_buffer_str(b,path);
if( len && path[len-1] != '/' && path[len-1] != '\\' )
hl_buffer_str(b,USTR("/*.*"));
else
hl_buffer_str(b,USTR("*.*"));
path = hl_buffer_content(b,NULL);
handle = FindFirstFileW(path,&d);
if( handle == INVALID_HANDLE_VALUE )
return NULL;
while( true ) {
// skip magic dirs
if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) ) {
if( pos == count ) {
int ncount = count == 0 ? 16 : count * 2;
varray *narr = hl_alloc_array(&hlt_bytes,ncount);
pchar **ncur = hl_aptr(narr,pchar*);
memcpy(ncur,current,count*sizeof(void*));
current = ncur;
a = narr;
count = ncount;
}
current[pos++] = pstrdup(d.cFileName,-1);
}
if( !FindNextFileW(handle,&d) )
break;
}
FindClose(handle);
#else
DIR *d;
struct dirent *e;
d = opendir(path);
if( d == NULL )
return NULL;
while( true ) {
e = readdir(d);
if( e == NULL )
break;
// skip magic dirs
if( e->d_name[0] == '.' && (e->d_name[1] == 0 || (e->d_name[1] == '.' && e->d_name[2] == 0)) )
continue;
if( pos == count ) {
int ncount = count == 0 ? 16 : count * 2;
varray *narr = hl_alloc_array(&hlt_bytes,ncount);
pchar **ncur = hl_aptr(narr,pchar*);
memcpy(ncur,current,count*sizeof(void*));
current = ncur;
a = narr;
count = ncount;
}
current[pos++] = pstrdup(e->d_name,-1);
}
closedir(d);
#endif
if( a == NULL ) a = hl_alloc_array(&hlt_bytes,0);
a->size = pos;
return a;
}
HL_PRIM vbyte *hl_sys_full_path( vbyte *path ) {
#if defined(HL_WIN)
pchar out[MAX_PATH+1];
int len, i, last;
HANDLE handle;
WIN32_FIND_DATA data;
const char sep = '\\';
if( GetFullPathNameW((pchar*)path,MAX_PATH+1,out,NULL) == 0 )
return NULL;
len = (int)ustrlen(out);
i = 0;
if (len >= 2 && out[1] == ':') {
// convert drive letter to uppercase
if (out[0] >= 'a' && out[0] <= 'z')
out[0] += (pchar)('A' - 'a');
if (len >= 3 && out[2] == sep)
i = 3;
else
i = 2;
}
last = i;
while (i < len) {
// skip until separator
while (i < len && out[i] != sep)
i++;
// temporarily strip string to last found component
out[i] = 0;
// get actual file/dir name with proper case
if ((handle = FindFirstFileW(out, &data)) != INVALID_HANDLE_VALUE) {
// replace the component with proper case
memcpy(out + last, data.cFileName, i - last);
FindClose(handle);
}
// if we're not at the end, restore the path
if (i < len)
out[i] = sep;
// advance
i++;
last = i;
}
return (vbyte*)pstrdup(out,len);
#else
pchar buf[PATH_MAX];
if( realpath((pchar*)path,buf) == NULL )
return NULL;
return (vbyte*)pstrdup(buf,-1);
#endif
}
HL_PRIM vbyte *hl_sys_exe_path() {
#if defined(HL_WIN)
pchar path[MAX_PATH];
if( GetModuleFileNameW(NULL,path,MAX_PATH) == 0 )
return NULL;
return (vbyte*)pstrdup(path,-1);
#elif defined(HL_MAC)
pchar path[PATH_MAX+1];
uint32_t path_len = PATH_MAX;
if( _NSGetExecutablePath(path, &path_len) )
return NULL;
return (vbyte*)pstrdup(path,-1);
#elif defined(HL_CONSOLE)
return sys_exe_path();
#else
const pchar *p = getenv("_");
if( p != NULL )
return (vbyte*)pstrdup(p,-1);
{
pchar path[PATH_MAX];
int length = readlink("/proc/self/exe", path, sizeof(path));
if( length < 0 )
return NULL;
path[length] = '\0';
return (vbyte*)pstrdup(path,-1);
}
#endif
}
HL_PRIM int hl_sys_get_char( bool b ) {
# if defined(HL_WIN_DESKTOP)
return b?getche():getch();
# elif defined(HL_CONSOLE)
return -1;
# else
// took some time to figure out how to do that
// without relying on ncurses, which clear the
// terminal on initscr()
int c;
struct termios term, old;
tcgetattr(fileno(stdin), &old);
term = old;
cfmakeraw(&term);
tcsetattr(fileno(stdin), 0, &term);
c = getchar();
tcsetattr(fileno(stdin), 0, &old);
if( b ) fputc(c,stdout);
return c;
# endif
}
static pchar **sys_args;
static int sys_nargs;
HL_PRIM varray *hl_sys_args() {
varray *a = hl_alloc_array(&hlt_bytes,sys_nargs);
int i;
for(i=0;i<sys_nargs;i++)
hl_aptr(a,pchar*)[i] = sys_args[i];
return a;
}
static void *hl_file = NULL;
HL_PRIM void hl_sys_init(void **args, int nargs, void *hlfile) {
sys_args = (pchar**)args;
sys_nargs = nargs;
hl_file = hlfile;
# ifdef HL_WIN_DESKTOP
setlocale(LC_CTYPE, ""); // printf to current locale
# endif
}
HL_PRIM vbyte *hl_sys_hl_file() {
return (vbyte*)hl_file;
}
static void *reload_fun = NULL;
static void *reload_param = NULL;
HL_PRIM void hl_setup_reload_check( void *freload, void *param ) {
reload_fun = freload;
reload_param = param;
}
HL_PRIM bool hl_sys_check_reload( vbyte *debug_alt_file ) {
if( debug_alt_file && reload_param ) {
*((vbyte**)reload_param) = debug_alt_file;
}
return reload_fun && ((bool(*)(void*))reload_fun)(reload_param);
}
extern int hl_closure_stack_capture;
HL_PRIM bool hl_sys_has_debugger() {
return hl_closure_stack_capture != 0;
}
#ifndef HL_MOBILE
const char *hl_sys_special( const char *key ) {
hl_error("Unknown sys_special key");
return NULL;
}
DEFINE_PRIM(_BYTES, sys_special, _BYTES);
#endif
DEFINE_PRIM(_BYTES, sys_hl_file, _NO_ARG);
DEFINE_PRIM(_BOOL, sys_utf8_path, _NO_ARG);
DEFINE_PRIM(_BYTES, sys_string, _NO_ARG);
DEFINE_PRIM(_BYTES, sys_locale, _NO_ARG);
DEFINE_PRIM(_VOID, sys_print, _BYTES);
DEFINE_PRIM(_VOID, sys_exit, _I32);
DEFINE_PRIM(_F64, sys_time, _NO_ARG);
DEFINE_PRIM(_BYTES, sys_get_env, _BYTES);
DEFINE_PRIM(_BOOL, sys_put_env, _BYTES _BYTES);
DEFINE_PRIM(_ARR, sys_env, _NO_ARG);
DEFINE_PRIM(_VOID, sys_sleep, _F64);
DEFINE_PRIM(_BOOL, sys_set_time_locale, _BYTES);
DEFINE_PRIM(_BYTES, sys_get_cwd, _NO_ARG);
DEFINE_PRIM(_BOOL, sys_set_cwd, _BYTES);
DEFINE_PRIM(_BOOL, sys_is64, _NO_ARG);
DEFINE_PRIM(_I32, sys_command, _BYTES);
DEFINE_PRIM(_BOOL, sys_exists, _BYTES);
DEFINE_PRIM(_BOOL, sys_delete, _BYTES);
DEFINE_PRIM(_BOOL, sys_rename, _BYTES _BYTES);
DEFINE_PRIM(_ARR, sys_stat, _BYTES);
DEFINE_PRIM(_BOOL, sys_is_dir, _BYTES);
DEFINE_PRIM(_BOOL, sys_create_dir, _BYTES _I32);
DEFINE_PRIM(_BOOL, sys_remove_dir, _BYTES);
DEFINE_PRIM(_F64, sys_cpu_time, _NO_ARG);
DEFINE_PRIM(_F64, sys_thread_cpu_time, _NO_ARG);
DEFINE_PRIM(_ARR, sys_read_dir, _BYTES);
DEFINE_PRIM(_BYTES, sys_full_path, _BYTES);
DEFINE_PRIM(_BYTES, sys_exe_path, _NO_ARG);
DEFINE_PRIM(_I32, sys_get_char, _BOOL);
DEFINE_PRIM(_ARR, sys_args, _NO_ARG);
DEFINE_PRIM(_I32, sys_getpid, _NO_ARG);
DEFINE_PRIM(_BOOL, sys_check_reload, _BYTES);
DEFINE_PRIM(_VOID, sys_profile_event, _I32 _BYTES _I32);
DEFINE_PRIM(_I32, sys_set_flags, _I32);
DEFINE_PRIM(_BOOL, sys_has_debugger, _NO_ARG);

View File

@ -0,0 +1,242 @@
/*
* Copyright (C)2005-2018 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_MOBILE) && defined(HL_ANDROID)
#ifndef HL_ANDROID_ACTIVITY
# define HL_ANDROID_ACTIVITY "org/haxe/HashLinkActivity"
#endif
#include <jni.h>
#include <android/log.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef HL_JNI_LOG_TAG
#define HL_JNI_LOG_TAG "HL_JNI"
#endif
#define HL_ANDROID_EXTERNAL_STORAGE_NOT_MOUNTED (0)
#define HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RO (1)
#define HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RW (2 | HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RO)
/* #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,HL_JNI_LOG_TAG,__VA_ARGS__) */
/* #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,HL_JNI_LOG_TAG,__VA_ARGS__) */
#define LOGI(...) do {} while (0)
#define LOGE(...) do {} while (0)
/* Forward declaration for JNI thread management */
static void hl_android_jni_thread_destructor(void*);
/* pthread key for proper JVM thread handling */
static pthread_key_t hl_java_thread_key;
/* Java VM reference */
static JavaVM* hl_java_vm;
/* Main activity */
static jclass hl_java_activity_class;
/* Method signatures */
static jmethodID hl_java_method_id_get_context;
/* Paths */
static char *hl_android_external_files_path = NULL;
static char *hl_android_internal_files_path = NULL;
/* Function to retrieve JNI environment, and dealing with threading */
static JNIEnv* hl_android_jni_get_env(void)
{
/* Always try to attach if calling from a non-attached thread */
JNIEnv *env;
if((*hl_java_vm)->AttachCurrentThread(hl_java_vm, &env, NULL) < 0) {
LOGE("failed to attach current thread");
return 0;
}
pthread_setspecific(hl_java_thread_key, (void*) env);
return env;
}
/* JNI_OnLoad is automatically called when loading shared library through System.loadLibrary() Java call */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv *env;
jclass cls;
hl_java_vm = vm;
if ((*hl_java_vm)->GetEnv(hl_java_vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Failed to get the environment using GetEnv()");
return -1;
}
/* Create pthread "destructor" pthread key to detach properly all threads */
if (pthread_key_create(&hl_java_thread_key, hl_android_jni_thread_destructor) != 0) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Error initializing pthread key");
}
/* Make sure we are attached (we should) and setup pthread destructor */
env = hl_android_jni_get_env();
/* Try to retrieve local reference to our Activity class */
cls = (*env)->FindClass(env, HL_ANDROID_ACTIVITY);
if (!cls) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Error cannot find HashLink Activity class");
}
/* Create a global reference for our Activity class */
hl_java_activity_class = (jclass)((*env)->NewGlobalRef(env, cls));
/* Retrieve the getContext() method id */
hl_java_method_id_get_context = (*env)->GetStaticMethodID(env, hl_java_activity_class, "getContext","()Landroid/content/Context;");
if (!hl_java_method_id_get_context) {
__android_log_print(ANDROID_LOG_ERROR, HL_JNI_LOG_TAG, "Error cannot get getContext() method on specified Activity class (not an Activity ?)");
}
return JNI_VERSION_1_4;
}
static void hl_android_jni_thread_destructor(void* value)
{
/* The thread is being destroyed, detach it from the Java VM and set the hl_java_thread_key value to NULL as required */
JNIEnv *env = (JNIEnv*) value;
if (env != NULL) {
(*hl_java_vm)->DetachCurrentThread(hl_java_vm);
pthread_setspecific(hl_java_thread_key, NULL);
}
}
static int hl_sys_android_get_external_storage_state(void)
{
jmethodID mid;
jclass cls;
jstring stateString;
const char *state;
int status = HL_ANDROID_EXTERNAL_STORAGE_NOT_MOUNTED;
JNIEnv *env = hl_android_jni_get_env();
if (!env) {
LOGE("Couldn't get Android JNIEnv !");
return status;
}
cls = (*env)->FindClass(env, "android/os/Environment");
mid = (*env)->GetStaticMethodID(env, cls, "getExternalStorageState", "()Ljava/lang/String;");
stateString = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid);
if (!stateString) {
LOGE("Call to getExternalStorageState failed");
return status;
}
state = (*env)->GetStringUTFChars(env, stateString, NULL);
if (strcmp(state, "mounted") == 0) {
status = HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RW;
} else if (strcmp(state, "mounted_ro") == 0) {
status = HL_ANDROID_EXTERNAL_STORAGE_MOUNTED_RO;
}
(*env)->ReleaseStringUTFChars(env, stateString, state);
return status;
}
static char* hl_sys_android_get_absolute_path_from(const char* method, const char* signature)
{
jmethodID mid;
jobject context;
jobject fileObject;
jstring pathString;
const char *path;
char* retrievedPath = NULL;
JNIEnv *env = hl_android_jni_get_env();
if (!env) {
LOGE("Couldn't get Android JNIEnv !");
return NULL;
}
context = (*env)->CallStaticObjectMethod(env, hl_java_activity_class, hl_java_method_id_get_context);
if (!context) {
LOGE("Couldn't get Android context!");
return NULL;
}
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context), method, signature);
fileObject = (*env)->CallObjectMethod(env, context, mid, NULL);
if (!fileObject) {
LOGE("Couldn't call %s%s on the specified context", method, signature);
return NULL;
}
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, fileObject), "getAbsolutePath", "()Ljava/lang/String;");
pathString = (jstring)(*env)->CallObjectMethod(env, fileObject, mid);
if (!pathString) {
LOGE("Couldn't retrieve absolute path");
return NULL;
}
/* Retrieve as C string */
path = (*env)->GetStringUTFChars(env, pathString, NULL);
retrievedPath = strdup(path);
(*env)->ReleaseStringUTFChars(env, pathString, path);
return retrievedPath;
}
static const char* hl_sys_android_get_external_storage_path(void)
{
/* Make sure external storage is mounted (at least read-only) */
if (hl_sys_android_get_external_storage_state()==HL_ANDROID_EXTERNAL_STORAGE_NOT_MOUNTED)
return NULL;
if (!hl_android_external_files_path) {
hl_android_external_files_path = hl_sys_android_get_absolute_path_from("getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
}
return hl_android_external_files_path;
}
static const char* hl_sys_android_get_internal_storage_path(void)
{
/* Internal storage is always available */
if (!hl_android_internal_files_path) {
hl_android_internal_files_path = hl_sys_android_get_absolute_path_from("getFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
}
return hl_android_internal_files_path;
}
const char *hl_sys_special( const char *key ) {
if (strcmp(key, "android_external_storage_path")==0)
return hl_sys_android_get_external_storage_path();
else if (strcmp(key, "android_internal_storage_path")==0)
return hl_sys_android_get_internal_storage_path();
else
hl_error("Unknown sys_special key");
return NULL;
}
DEFINE_PRIM(_BYTES, sys_special, _BYTES);
#endif

View File

@ -0,0 +1,73 @@
/*
* Copyright (C)2005-2018 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#if defined(HL_MOBILE) && defined(HL_IOS)
#include <sys/utsname.h>
#include <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
static const char* ios_get_document_path()
{
NSString* string = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
const char* path = strdup([string fileSystemRepresentation]);
return path;
}
static const char* ios_get_resource_path()
{
NSString* string = [[NSBundle mainBundle] resourcePath];
const char* path = strdup([string UTF8String]);
return path;
}
static const char* ios_get_device_name()
{
struct utsname systemInfo;
uname(&systemInfo);
return strdup(systemInfo.machine);
}
static int ios_get_retina_scale_factor()
{
return [[UIScreen mainScreen] scale];
}
const char *hl_sys_special( const char *key ) {
if (strcmp(key, "ios_resource_path")==0)
return ios_get_resource_path();
else if (strcmp(key, "ios_document_path")==0)
return ios_get_document_path();
else if (strcmp(key, "ios_retina_scale_factor")==0)
return ios_get_retina_scale_factor();
else if (strcmp(key, "ios_device_name")==0)
return ios_get_device_name();
else
hl_error("Unknown sys_special key");
return NULL;
}
DEFINE_PRIM(_BYTES, sys_special, _BYTES);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,299 @@
/*
* Copyright (C)2005-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "hl.h"
#include <stdio.h>
static int track_depth = 10;
static int max_depth = 0;
#ifdef HL_TRACK_ENABLE
hl_track_info hl_track = {0};
#endif
typedef enum {
KALLOC,
KCAST,
KDYNFIELD,
KDYNCALL,
_KLAST
} bucket_kind;
typedef struct {
hl_type *t;
void **stack;
int stack_count;
int hit_count;
int info;
} bucket;
typedef struct {
unsigned int *hashes;
bucket *buckets;
int bcount;
int max_buckets;
unsigned int prev_hash;
unsigned int prev_hash2;
bucket *prev_b;
bucket *prev_b2;
} bucket_list;
static bucket_list all_data[_KLAST] = {{0}};
static hl_mutex *track_lock = NULL;
int hl_internal_capture_stack( void **stack, int size );
static bucket *bucket_find_insert( bucket_list *data, unsigned int hash, void **stack, int count ) {
int min = 0, mid;
int max = data->bcount;
bucket *b;
while( min < max ) {
mid = (min + max) >> 1;
if( data->hashes[mid] < hash )
min = mid + 1;
else if( data->hashes[mid] > hash )
max = mid;
else {
b = data->buckets + mid;
if( b->stack_count != count ) {
if( b->stack_count < count )
min = mid + 1;
else
max = mid;
} else {
int i;
for(i=0;i<count;i++)
if( b->stack[i] != stack[i] ) {
if( b->stack[i] < stack[i] )
min = mid + 1;
else
max = mid;
break;
}
if( i == count )
return b;
}
}
}
mid = (min + max) >> 1;
if( data->bcount == data->max_buckets ) {
int nbuckets = data->max_buckets ? data->max_buckets << 1 : 256;
bucket *bnew = (bucket*)malloc(sizeof(bucket)*nbuckets);
unsigned int *hnew = (unsigned int*)malloc(sizeof(int)*nbuckets);
memcpy(bnew,data->buckets,data->bcount*sizeof(bucket));
memcpy(hnew,data->hashes,data->bcount*sizeof(int));
free(data->buckets);
free(data->hashes);
data->buckets = bnew;
data->hashes = hnew;
data->max_buckets = nbuckets;
}
b = data->buckets + mid;
if( data->hashes[mid] == hash && b->stack_count == count ) {
int i;
for(i=0;i<count;i++)
if( b->stack[i] != stack[i] )
break;
if( i == count )
return b;
}
memmove(data->buckets + (mid + 1), data->buckets + mid, (data->bcount - mid) * sizeof(bucket));
memmove(data->hashes + (mid + 1), data->hashes + mid, (data->bcount - mid) * sizeof(int));
memset(b, 0, sizeof(bucket));
b->stack = malloc(sizeof(void*)*count);
memcpy(b->stack, stack, sizeof(void*)*count);
b->stack_count = count;
data->hashes[mid] = hash;
data->bcount++;
return b;
}
static void init_lock() {
hl_thread_info *tinf = hl_get_thread();
int flags = tinf->flags;
tinf->flags &= ~(HL_TRACK_ALLOC<<HL_TREAD_TRACK_SHIFT);
track_lock = hl_mutex_alloc(true);
hl_add_root(&track_lock);
tinf->flags = flags;
}
static bucket *fetch_bucket( bucket_kind kind ) {
int count, i;
unsigned int hash;
hl_thread_info *tinf = hl_get_thread();
bucket_list *data = &all_data[kind];
bucket *b;
if( track_lock == NULL ) init_lock();
count = hl_internal_capture_stack(tinf->exc_stack_trace,track_depth);
if( count > max_depth ) max_depth = count;
hash = -count;
for(i=0;i<count;i++)
hash = (hash * 31) + (((unsigned int)(int_val)tinf->exc_stack_trace[i]) >> 1);
// look for bucket
hl_mutex_acquire(track_lock);
if( hash == data->prev_hash && data->prev_b ) {
b = data->prev_b;
} else if( hash == data->prev_hash2 && data->prev_b2 ) {
b = data->prev_b2;
} else {
b = bucket_find_insert(data, hash, tinf->exc_stack_trace, count);
data->prev_hash2 = data->prev_hash;
data->prev_b2 = data->prev_b;
data->prev_hash = hash;
data->prev_b = b;
}
return b;
}
static void on_alloc( hl_type *t, int size, int flags, void *ptr ) {
bucket *b = fetch_bucket(KALLOC);
b->t = t;
b->hit_count++;
b->info += size;
hl_mutex_release(track_lock);
}
static void on_cast( hl_type *t1, hl_type *t2 ) {
bucket *b = fetch_bucket(KCAST);
b->t = t1;
b->hit_count++;
b->info = t2->kind;
hl_mutex_release(track_lock);
}
static void on_dynfield( vdynamic *d, int hfield ) {
bucket *b = fetch_bucket(KDYNFIELD);
b->t = d?d->t:&hlt_dyn;
b->hit_count++;
b->info = hfield;
hl_mutex_release(track_lock);
}
static void on_dyncall( vdynamic *d, int hfield ) {
bucket *b = fetch_bucket(KDYNCALL);
b->t = d?d->t:&hlt_dyn;
b->hit_count++;
b->info = hfield;
hl_mutex_release(track_lock);
}
HL_PRIM void hl_track_init() {
#ifdef HL_TRACK_ENABLE
char *env = getenv("HL_TRACK");
if( env )
hl_track.flags = atoi(env);
hl_track.on_alloc = on_alloc;
hl_track.on_cast = on_cast;
hl_track.on_dynfield = on_dynfield;
hl_track.on_dyncall = on_dyncall;
#endif
}
HL_PRIM void hl_track_lock( bool lock ) {
#ifdef HL_TRACK_ENABLE
if( !track_lock ) init_lock();
if( lock )
hl_mutex_acquire(track_lock);
else
hl_mutex_release(track_lock);
#endif
}
HL_PRIM int hl_track_count( int *depth ) {
int value = 0;
int i;
for(i=0;i<_KLAST;i++)
value += all_data[i].bcount;
*depth = max_depth;
return value;
}
HL_PRIM int hl_track_entry( int id, hl_type **t, int *count, int *info, varray *stack ) {
static bucket_list *cur = NULL;
static int prev_id = -10;
static int count_before = 0;
bucket *b = NULL;
if( id == prev_id + 1 ) {
if( id - count_before == cur->bcount ) {
if( cur - all_data == _KLAST ) return -1;
count_before += cur->bcount;
cur++;
}
b = cur->buckets + (id - count_before);
prev_id++;
} else {
int i;
count_before = 0;
for(i=0;i<_KLAST;i++) {
bucket_list *data = &all_data[i];
if( id - count_before < data->bcount ) break;
count_before += data->bcount;
}
if( i == _KLAST ) return -1; // out of range
prev_id = id;
cur = &all_data[i];
b = cur->buckets;
}
*t = b->t;
*count = b->hit_count;
*info = b->info;
stack->size = b->stack_count;
memcpy(hl_aptr(stack,void*), b->stack, b->stack_count * sizeof(void*));
return (int)(cur - all_data);
}
HL_PRIM int hl_track_get_bits( bool thread ) {
# ifdef HL_TRACK_ENABLE
return (thread ? (hl_get_thread()->flags>>HL_TREAD_TRACK_SHIFT) : hl_track.flags) & HL_TRACK_MASK;
# else
return 0;
# endif
}
HL_PRIM void hl_track_set_depth( int d ) {
track_depth = d;
}
HL_PRIM void hl_track_set_bits( int flags, bool thread ) {
# ifdef HL_TRACK_ENABLE
if( thread ) {
hl_thread_info *t = hl_get_thread();
if( t ) t->flags = (t->flags & ~(HL_TRACK_MASK<<HL_TREAD_TRACK_SHIFT)) | ((flags & HL_TRACK_MASK) << HL_TREAD_TRACK_SHIFT);
} else {
hl_track.flags = (hl_track.flags & ~HL_TRACK_MASK) | (flags & HL_TRACK_MASK);
}
# endif
}
HL_PRIM void hl_track_reset() {
int i;
for(i=0;i<_KLAST;i++)
all_data[i].bcount = 0;
}
DEFINE_PRIM(_VOID, track_init, _NO_ARG);
DEFINE_PRIM(_I32, track_count, _REF(_I32));
DEFINE_PRIM(_I32, track_entry, _I32 _REF(_TYPE) _REF(_I32) _REF(_I32) _ARR);
DEFINE_PRIM(_VOID, track_lock, _BOOL);
DEFINE_PRIM(_VOID, track_set_depth, _I32);
DEFINE_PRIM(_I32, track_get_bits, _BOOL);
DEFINE_PRIM(_VOID, track_set_bits, _I32 _BOOL);
DEFINE_PRIM(_VOID, track_reset, _NO_ARG);

View File

@ -0,0 +1,973 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
HL_PRIM hl_type hlt_array = { HARRAY };
HL_PRIM hl_type hlt_bytes = { HBYTES };
HL_PRIM hl_type hlt_dynobj = { HDYNOBJ };
HL_PRIM hl_type hlt_dyn = { HDYN };
HL_PRIM hl_type hlt_i32 = { HI32 };
HL_PRIM hl_type hlt_i64 = { HI64 };
HL_PRIM hl_type hlt_f32 = { HF32 };
HL_PRIM hl_type hlt_f64 = { HF64 };
HL_PRIM hl_type hlt_void = { HVOID };
HL_PRIM hl_type hlt_bool = { HBOOL };
HL_PRIM hl_type hlt_abstract = { HABSTRACT, {USTR("<abstract>")} };
static const uchar *TSTR[] = {
USTR("void"), USTR("i8"), USTR("i16"), USTR("i32"), USTR("i64"), USTR("f32"), USTR("f64"),
USTR("bool"), USTR("bytes"), USTR("dynamic"), NULL, NULL,
USTR("array"), USTR("type"), NULL, NULL, USTR("dynobj"),
NULL, NULL, NULL, NULL, NULL, NULL
};
static int T_SIZES[] = {
0, // VOID
1, // I8
2, // I16
4, // I32
8, // I64
4, // F32
8, // F64
sizeof(bool), // BOOL
HL_WSIZE, // BYTES
HL_WSIZE, // DYN
HL_WSIZE, // FUN
HL_WSIZE, // OBJ
HL_WSIZE, // ARRAY
HL_WSIZE, // TYPE
HL_WSIZE, // REF
HL_WSIZE, // VIRTUAL
HL_WSIZE, // DYNOBJ
HL_WSIZE, // ABSTRACT
HL_WSIZE, // ENUM
HL_WSIZE, // NULL
HL_WSIZE, // METHOD
HL_WSIZE, // STRUCT
0, // PACKED
};
HL_PRIM int hl_type_size( hl_type *t ) {
return T_SIZES[t->kind];
}
HL_PRIM int hl_pad_struct( int size, hl_type *t ) {
int align = sizeof(void*);
# define GET_ALIGN(type) { struct { unsigned char a; type b; } s = {0}; align = (int)((unsigned char *)&s.b - (unsigned char*)&s); }
switch( t->kind ) {
case HVOID:
return 0;
case HUI8:
GET_ALIGN(unsigned char);
break;
case HUI16:
GET_ALIGN(unsigned short);
break;
case HI32:
GET_ALIGN(unsigned int);
break;
case HI64:
GET_ALIGN(int64);
break;
case HF32:
GET_ALIGN(float);
break;
case HF64:
GET_ALIGN(double);
break;
case HBOOL:
GET_ALIGN(bool);
break;
default:
break;
}
return (-size) & (align - 1);
}
HL_PRIM bool hl_same_type( hl_type *a, hl_type *b ) {
if( a == b )
return true;
if( a->kind != b->kind )
return false;
switch( a->kind ) {
case HVOID:
case HUI8:
case HUI16:
case HI32:
case HI64:
case HF32:
case HF64:
case HBOOL:
case HTYPE:
case HBYTES:
case HDYN:
case HARRAY:
case HDYNOBJ:
return true;
case HREF:
case HNULL:
case HPACKED:
return hl_same_type(a->tparam, b->tparam);
case HFUN:
case HMETHOD:
{
int i;
if( a->fun->nargs != b->fun->nargs )
return false;
for(i=0;i<a->fun->nargs;i++)
if( !hl_same_type(a->fun->args[i],b->fun->args[i]) )
return false;
return hl_same_type(a->fun->ret, b->fun->ret);
}
case HOBJ:
case HSTRUCT:
return a->obj == b->obj;
case HVIRTUAL:
return a->virt == b->virt;
case HABSTRACT:
return a->abs_name == b->abs_name;
case HENUM:
return a->tenum == b->tenum;
default:
break;
}
return false;
}
HL_PRIM bool hl_is_dynamic( hl_type *t ) {
static bool T_IS_DYNAMIC[] = {
false, // HVOID,
false, // HI8
false, // HI16
false, // HI32
false, // HI64
false, // HF32
false, // HF64
false, // HBOOL
false, // HBYTES
true, // HDYN
true, // HFUN
true, // HOBJ
true, // HARRAY
false, // HTYPE
false, // HREF
true, // HVIRTUAL
true, // HDYNOBJ
false, // HABSTRACT
true, // HENUM
true, // HNULL
false, // HMETHOD
false, // HSTRUCT
false, // HPACKED
};
return T_IS_DYNAMIC[t->kind];
}
HL_PRIM bool hl_safe_cast( hl_type *t, hl_type *to ) {
if( t == to )
return true;
if( to->kind == HDYN )
return hl_is_dynamic(t);
if( t->kind != to->kind )
return false;
switch( t->kind ) {
case HVIRTUAL:
if( to->virt->nfields < t->virt->nfields ) {
int i;
for(i=0;i<to->virt->nfields;i++) {
hl_obj_field *f1 = t->virt->fields + i;
hl_obj_field *f2 = to->virt->fields + i;
if( f1->hashed_name != f2->hashed_name || !hl_same_type(f1->t,f2->t) )
break;
}
if( i == to->virt->nfields )
return true;
}
break;
case HOBJ:
case HSTRUCT:
{
hl_type_obj *o = t->obj;
hl_type_obj *oto = to->obj;
while( true ) {
if( o == oto ) return true;
if( o->super == NULL ) return false;
o = o->super->obj;
}
}
case HFUN:
case HMETHOD:
if( t->fun->nargs == to->fun->nargs ) {
int i;
if( !hl_safe_cast(t->fun->ret,to->fun->ret) )
return false;
for(i=0;i<t->fun->nargs;i++) {
hl_type *t1 = t->fun->args[i];
hl_type *t2 = to->fun->args[i];
if( !hl_safe_cast(t2,t1) && (t1->kind != HDYN || !hl_is_dynamic(t2)) )
return false;
}
return true;
}
break;
case HPACKED:
return hl_safe_cast(t->tparam, to);
default:
break;
}
return hl_same_type(t,to);
}
typedef struct tlist {
hl_type *t;
struct tlist *next;
} tlist;
static void hl_type_str_rec( hl_buffer *b, hl_type *t, tlist *parents ) {
const uchar *c = TSTR[t->kind];
tlist *l, cur;
int i;
if( c != NULL ) {
hl_buffer_str(b,c);
return;
}
l = parents;
while( l ) {
if( l->t == t ) {
hl_buffer_str(b,USTR("<...>"));
return;
}
l = l->next;
}
cur.t = t;
cur.next = parents;
l = &cur;
switch( t->kind ) {
case HFUN:
case HMETHOD:
hl_buffer_char(b,'(');
hl_type_str_rec(b,t->fun->ret,l);
hl_buffer_char(b,' ');
hl_buffer_char(b,'(');
for(i=0; i<t->fun->nargs; i++) {
if( i ) hl_buffer_char(b,',');
hl_type_str_rec(b,t->fun->args[i],l);
}
hl_buffer_char(b,')');
hl_buffer_char(b,')');
break;
case HSTRUCT:
hl_buffer_char(b,'@');
case HOBJ:
hl_buffer_str(b,t->obj->name);
break;
case HREF:
hl_buffer_str(b,USTR("ref<"));
hl_type_str_rec(b,t->tparam,l);
hl_buffer_char(b,'>');
break;
case HVIRTUAL:
hl_buffer_str(b,USTR("virtual<"));
for(i=0; i<t->virt->nfields; i++) {
hl_obj_field *f = t->virt->fields + i;
if( i ) hl_buffer_char(b,',');
hl_buffer_str(b,f->name);
hl_buffer_char(b,':');
hl_type_str_rec(b,f->t,l);
}
hl_buffer_char(b,'>');
break;
case HABSTRACT:
hl_buffer_str(b,t->abs_name);
break;
case HENUM:
hl_buffer_str(b,USTR("enum"));
if( t->tenum->name ) {
hl_buffer_char(b,'<');
hl_buffer_str(b,t->tenum->name);
hl_buffer_char(b,'>');
}
break;
case HNULL:
hl_buffer_str(b,USTR("null<"));
hl_type_str_rec(b,t->tparam,l);
hl_buffer_char(b,'>');
break;
case HPACKED:
hl_buffer_str(b, USTR("packed<"));
hl_type_str_rec(b,t->tparam,l);
hl_buffer_char(b,'>');
break;
default:
hl_buffer_str(b,USTR("???"));
break;
}
}
HL_PRIM const uchar *hl_type_str( hl_type *t ) {
const uchar *c = TSTR[t->kind];
hl_buffer *b;
if( c != NULL )
return c;
b = hl_alloc_buffer();
hl_type_str_rec(b,t,NULL);
return hl_buffer_content(b,NULL);
}
HL_PRIM vbyte* hl_type_name( hl_type *t ) {
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
return (vbyte*)t->obj->name;
case HENUM:
return (vbyte*)t->tenum->name;
case HABSTRACT:
return (vbyte*)t->abs_name;
default:
break;
}
return NULL;
}
HL_PRIM int hl_mark_size( int data_size );
HL_PRIM void hl_init_enum( hl_type *et, hl_module_context *m ) {
int i, j;
int mark_size = 0;
unsigned int *mark;
for(i=0;i<et->tenum->nconstructs;i++) {
hl_enum_construct *c = et->tenum->constructs + i;
c->hasptr = false;
c->size = sizeof(void*)+sizeof(int); // t + index
for(j=0;j<c->nparams;j++) {
hl_type *t = c->params[j];
c->size += hl_pad_struct(c->size,t);
c->offsets[j] = c->size;
if( hl_is_ptr(t) ) c->hasptr = true;
c->size += hl_type_size(t);
}
if( c->hasptr ) {
int max_pos = i * sizeof(int) + hl_mark_size(c->size - HL_WSIZE*2);
if( max_pos > mark_size ) mark_size = max_pos;
}
}
mark = (unsigned int*)hl_zalloc(&m->alloc,mark_size);
for(i=0;i<et->tenum->nconstructs;i++) {
hl_enum_construct *c = et->tenum->constructs + i;
if( !c->hasptr ) continue;
for(j=0;j<c->nparams;j++)
if( hl_is_ptr(c->params[j]) ) {
int pos = (c->offsets[j] / HL_WSIZE) - 2;
mark[i + (pos >> 5)] |= 1 << (pos & 31);
}
}
et->mark_bits = mark;
}
HL_PRIM varray* hl_type_enum_fields( hl_type *t ) {
varray *a = hl_alloc_array(&hlt_bytes,t->tenum->nconstructs);
int i;
for( i=0; i<t->tenum->nconstructs;i++)
hl_aptr(a,vbyte*)[i] = (vbyte*)t->tenum->constructs[i].name;
return a;
}
HL_PRIM varray* hl_type_enum_values( hl_type *t ) {
varray *a = hl_alloc_array(&hlt_dyn,t->tenum->nconstructs);
int i;
for( i=0; i<t->tenum->nconstructs;i++) {
hl_enum_construct *c = t->tenum->constructs + i;
if(c->nparams == 0)
hl_aptr(a,venum*)[i] = hl_alloc_enum(t, i);
}
return a;
}
HL_PRIM int hl_type_args_count( hl_type *t ) {
if( t->kind == HFUN || t->kind == HMETHOD )
return t->fun->nargs;
return 0;
}
HL_PRIM varray *hl_type_instance_fields( hl_type *t ) {
varray *a;
const uchar **names;
int mcount = 0;
int out = 0;
hl_type_obj *o;
hl_runtime_obj *rt;
if( t->kind == HVIRTUAL ) {
int i;
a = hl_alloc_array(&hlt_bytes,t->virt->nfields);
names = hl_aptr(a,const uchar *);
for(i=0;i<t->virt->nfields;i++)
names[i] = t->virt->fields[i].name;
return a;
}
if( t->kind != HOBJ && t->kind != HSTRUCT )
return NULL;
o = t->obj;
while( true ) {
int i;
for(i=0;i<o->nproto;i++) {
hl_obj_proto *p = o->proto + i;
if( p->pindex < 0 ) mcount++;
}
if( o->super == NULL ) break;
o = o->super->obj;
}
rt = hl_get_obj_rt(t);
a = hl_alloc_array(&hlt_bytes,mcount + rt->nproto + rt->nfields);
names = hl_aptr(a,const uchar*);
o = t->obj;
while( true ) {
int i;
int pproto = rt->parent ? rt->parent->nproto : 0;
for(i=0;i<o->nproto;i++) {
hl_obj_proto *p = o->proto + i;
if( p->pindex < 0 || p->pindex >= pproto )
names[out++] = p->name;
}
for(i=0;i<o->nfields;i++) {
hl_obj_field *f = o->fields + i;
names[out++] = f->name;
}
if( o->super == NULL ) break;
o = o->super->obj;
rt = o->rt;
}
return a;
}
HL_PRIM hl_type *hl_type_super( hl_type *t ) {
if( (t->kind == HOBJ || t->kind == HSTRUCT) && t->obj->super )
return t->obj->super;
return &hlt_void;
}
HL_PRIM vdynamic *hl_type_get_global( hl_type *t ) {
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
return t->obj->global_value ? *(vdynamic**)t->obj->global_value : NULL;
case HENUM:
return *(vdynamic**)t->tenum->global_value;
default:
break;
}
return NULL;
}
HL_PRIM bool hl_type_set_global( hl_type *t, vdynamic *v ) {
switch( t->kind ) {
case HOBJ:
case HSTRUCT:
if( t->obj->global_value ) {
*(vdynamic**)t->obj->global_value = v;
return true;
}
break;
case HENUM:
if( t->tenum->global_value ) {
*(vdynamic**)t->tenum->global_value = v;
return true;
}
break;
default:
break;
}
return false;
}
HL_PRIM bool hl_type_enum_eq( venum *a, venum *b ) {
int i;
hl_enum_construct *c;
if( a == b )
return true;
if( !a || !b || a->t != b->t )
return false;
if( a->index != b->index )
return false;
c = a->t->tenum->constructs + a->index;
for(i=0;i<c->nparams;i++) {
hl_type *t = c->params[i];
switch( t->kind ) {
case HENUM:
{
venum *pa = *(venum**)((char*)a + c->offsets[i]);
venum *pb = *(venum**)((char*)b + c->offsets[i]);
if( !hl_type_enum_eq(pa,pb) )
return false;
}
break;
default:
{
vdynamic *pa = hl_make_dyn((char*)a + c->offsets[i],t);
vdynamic *pb = hl_make_dyn((char*)b + c->offsets[i],t);
if( pa && pb && pa->t->kind == HENUM && pb->t->kind == HENUM ) {
if( !hl_type_enum_eq((venum*)pa,(venum*)pb) )
return false;
continue;
}
if( hl_dyn_compare(pa,pb) )
return false;
}
break;
}
}
return true;
}
HL_PRIM venum *hl_alloc_enum( hl_type *t, int index ) {
hl_enum_construct *c = t->tenum->constructs + index;
venum *v = (venum*)hl_gc_alloc_gen(t, c->size, MEM_KIND_DYNAMIC | (c->hasptr ? 0 : MEM_KIND_NOPTR) | MEM_ZERO);
v->t = t;
v->index = index;
return v;
}
HL_PRIM venum *hl_alloc_enum_dyn( hl_type *t, int index, varray *args, int nargs ) {
hl_enum_construct *c = t->tenum->constructs + index;
venum *e;
int i;
if( c->nparams < nargs || args->size < nargs )
return NULL;
if( nargs < c->nparams ) {
// allow missing params if they are null-able
for(i=nargs;i<c->nparams;i++)
if( !hl_is_ptr(c->params[i]) )
return NULL;
}
e = hl_alloc_enum(t, index);
for(i=0;i<nargs;i++)
hl_write_dyn((char*)e+c->offsets[i],c->params[i],hl_aptr(args,vdynamic*)[i],false);
return e;
}
HL_PRIM varray *hl_enum_parameters( venum *e ) {
varray *a;
hl_enum_construct *c = e->t->tenum->constructs + e->index;
int i;
a = hl_alloc_array(&hlt_dyn,c->nparams);
for(i=0;i<c->nparams;i++)
hl_aptr(a,vdynamic*)[i] = hl_make_dyn((char*)e+c->offsets[i],c->params[i]);
return a;
}
DEFINE_PRIM(_BYTES, type_str, _TYPE);
DEFINE_PRIM(_BYTES, type_name, _TYPE);
DEFINE_PRIM(_I32, type_args_count, _TYPE);
DEFINE_PRIM(_ARR, type_instance_fields, _TYPE);
DEFINE_PRIM(_TYPE, type_super, _TYPE);
DEFINE_PRIM(_DYN, type_get_global, _TYPE);
DEFINE_PRIM(_ARR, type_enum_fields, _TYPE);
DEFINE_PRIM(_ARR, type_enum_values, _TYPE);
DEFINE_PRIM(_BOOL, type_enum_eq, _DYN _DYN);
DEFINE_PRIM(_DYN, alloc_enum_dyn, _TYPE _I32 _ARR _I32);
DEFINE_PRIM(_ARR, enum_parameters, _DYN);
DEFINE_PRIM(_BOOL, type_set_global, _TYPE _DYN);
typedef struct {
char *buf;
int buf_pos;
int buf_size;
int *offsets;
int offsets_pos;
int offsets_size;
void **lookup;
int *lookup_index;
int lookup_pos;
int lookup_size;
int *remap_target;
int remap_pos;
int remap_size;
void **todos;
int todos_pos;
int todos_size;
int flags;
} mem_context;
#define compact_grow(buf,pos,size,req,type) \
if( ctx->pos + req > ctx->size ) { \
int nsize = ctx->size; \
if( nsize == 0 ) nsize = 256 /sizeof(type); \
while( nsize < ctx->pos + req ) nsize = (nsize * 3) / 2; \
type *nbuf = (type*)malloc(nsize * sizeof(type)); \
memcpy(nbuf,ctx->buf,ctx->pos * sizeof(type)); \
free(ctx->buf); \
ctx->buf = nbuf; \
ctx->size = nsize; \
}
static void compact_write_mem( mem_context *ctx, void *mem, int size ) {
compact_grow(buf,buf_pos,buf_size,size,char);
memcpy(ctx->buf + ctx->buf_pos, mem, size);
ctx->buf_pos += size;
}
static void compact_write_ptr( mem_context *ctx, void *ptr ) {
compact_write_mem(ctx,&ptr,sizeof(void*));
}
static void compact_write_int( mem_context *ctx, int v ) {
compact_write_mem(ctx,&v,4);
}
static void compact_write_offset( mem_context *ctx, int position ) {
compact_grow(offsets,offsets_pos,offsets_size,1,int);
ctx->offsets[ctx->offsets_pos++] = ctx->buf_pos;
compact_write_ptr(ctx,(void*)(int_val)position);
}
static int compact_lookup_index( mem_context *ctx, void *addr ) {
int min = 0;
int max = ctx->lookup_pos;
while( min < max ) {
int mid = (min + max) >> 1;
void *a = ctx->lookup[mid];
if( a < addr ) min = mid + 1; else if( a > addr ) max = mid; else return mid;
}
return -1;
}
#define BYTE_MARK 0x40000000
static int compact_lookup_ref( mem_context *ctx, void *addr, bool is_bytes ) {
int min = 0;
int max = ctx->lookup_pos;
while( min < max ) {
int mid = (min + max) >> 1;
void *a = ctx->lookup[mid];
if( a < addr ) min = mid + 1; else if( a > addr ) max = mid; else return ctx->remap_target[ctx->lookup_index[mid]&~BYTE_MARK];
}
if( ctx->lookup_pos == ctx->lookup_size ) {
int nsize = ctx->lookup_size == 0 ? 128 : (ctx->lookup_size * 3) / 2;
void **nlookup = (void**)malloc(nsize * sizeof(void*));
int *nindex = (int*)malloc(nsize * sizeof(int));
memcpy(nlookup,ctx->lookup,ctx->lookup_pos * sizeof(void*));
memcpy(nindex,ctx->lookup_index,ctx->lookup_pos * sizeof(int));
free(ctx->lookup);
free(ctx->lookup_index);
ctx->lookup = nlookup;
ctx->lookup_index = nindex;
ctx->lookup_size = nsize;
}
int pos = (min + max) >> 1;
memmove(ctx->lookup + pos + 1, ctx->lookup + pos, (ctx->lookup_pos - pos) * sizeof(void*));
memmove(ctx->lookup_index + pos + 1, ctx->lookup_index + pos, (ctx->lookup_pos - pos) * sizeof(int));
int id = ctx->lookup_pos++;
ctx->lookup[pos] = addr;
ctx->lookup_index[pos] = id | (is_bytes ? BYTE_MARK : 0);
compact_grow(todos,todos_pos,todos_size,1,void*);
ctx->todos[ctx->todos_pos++] = addr;
compact_grow(remap_target,remap_pos,remap_size,1,int);
int target = -id-1;
ctx->remap_target[ctx->remap_pos++] = target;
return target;
}
static void compact_write_ref( mem_context *ctx, void *ptr, bool is_bytes ) {
if( !ptr ) {
compact_write_ptr(ctx, NULL);
return;
}
int ref = compact_lookup_ref(ctx,ptr,is_bytes);
compact_write_offset(ctx, ref);
}
static void compact_write_data( mem_context *ctx, hl_type *t, void *addr ) {
if( hl_is_dynamic(t) ) {
vdynamic *v = *(vdynamic**)addr;
if( v == NULL || (v->t->kind == HENUM && v->t->tenum->constructs[((venum*)v)->index].nparams == 0) ) {
compact_write_ptr(ctx,v);
return;
}
compact_write_ref(ctx,v,false);
return;
}
switch( t->kind ) {
case HUI8:
compact_write_mem(ctx, addr, 1);
break;
case HUI16:
compact_write_mem(ctx, addr, 2);
break;
case HI32:
case HF32:
compact_write_mem(ctx, addr, 4);
break;
case HF64:
case HI64:
compact_write_mem(ctx, addr, 8);
break;
case HBOOL:
compact_write_mem(ctx, addr, sizeof(bool));
break;
case HBYTES:
{
void *bytes = *(void**)addr;
if( bytes == NULL || !hl_is_gc_ptr(bytes) ) {
compact_write_ptr(ctx, bytes);
break;
}
compact_write_ref(ctx, bytes, true);
}
break;
case HABSTRACT:
hl_error("Unsupported abstract %s", t->abs_name);
break;
default:
hl_error("Unsupported type %d", t->kind);
break;
}
}
static void compact_pad( mem_context *ctx, hl_type *t ) {
int sz = hl_pad_size(ctx->buf_pos,t);
ctx->buf_pos += sz;
}
static void compact_write_content( mem_context *ctx, vdynamic *d ) {
int i;
hl_type *t = d->t;
if( !hl_is_ptr(t) ) {
compact_write_ptr(ctx, t);
compact_write_mem(ctx,&d->v,hl_type_size(t));
return;
}
switch( t->kind ) {
case HOBJ: {
char *obj_data = (char*)d;
hl_runtime_obj *rt = hl_get_obj_rt(t);
compact_grow(buf,buf_pos,buf_size,rt->size,char);
memset(ctx->buf + ctx->buf_pos, 0xCD, rt->size);
int buf_start = ctx->buf_pos;
int fstart = rt->nfields;
compact_write_ptr(ctx,t);
while( t ) {
fstart -= t->obj->nfields;
for(i=0;i<t->obj->nfields;i++) {
int fid = i + fstart;
ctx->buf_pos = buf_start + rt->fields_indexes[fid];
compact_write_data(ctx, t->obj->fields[i].t, obj_data + rt->fields_indexes[fid]);
}
t = t->obj->super;
}
ctx->buf_pos = buf_start + rt->size;
break;
}
case HVIRTUAL: {
vvirtual *v = (vvirtual*)d;
int start = ctx->buf_pos;
compact_write_ptr(ctx, t);
if( ctx->flags & 4 )
compact_write_offset(ctx, start); // virtual self value
else if( ctx->flags & 2 )
compact_write_ptr(ctx, NULL); // optimize virtuals
else
compact_write_data(ctx, &hlt_dyn, &v->value);
compact_write_data(ctx, &hlt_dyn, &v->next);
if( !v->value || (ctx->flags&6) ) {
int target = ctx->buf_pos + t->virt->nfields * sizeof(void*);
for(i=0;i<t->virt->nfields;i++) {
hl_type *ft = t->virt->fields[i].t;
target += hl_pad_size(target, ft);
compact_write_offset(ctx, target);
target += hl_type_size(ft);
}
for(i=0;i<t->virt->nfields;i++) {
void *addr = ((void**)(v + 1))[i];
hl_type *ft = t->virt->fields[i].t;
compact_pad(ctx,ft);
if( !addr ) {
if( !hl_is_ptr(ft) ) hl_error("assert");
compact_write_ptr(ctx,NULL);
} else
compact_write_data(ctx,ft,addr);
}
} else {
vdynobj *obj = (vdynobj*)v->value;
if( obj->t->kind != HDYNOBJ ) hl_error("assert");
int todo_save = ctx->todos_pos;
for(i=0;i<t->virt->nfields;i++) {
void *addr = ((void**)(v + 1))[i];
compact_write_ref(ctx, addr, false);
}
ctx->todos_pos = todo_save;
}
break;
}
case HDYNOBJ: {
vdynobj *obj = (vdynobj*)d;
int lookup_data = ctx->buf_pos + sizeof(vdynobj);
int raw_data = lookup_data + obj->nfields * sizeof(hl_field_lookup);
int values_data = raw_data + obj->raw_size;
values_data += hl_pad_size(values_data,&hlt_dyn);
compact_write_ptr(ctx, t);
if( obj->lookup )
compact_write_offset(ctx, lookup_data);
else
compact_write_ptr(ctx, NULL);
if( obj->raw_data )
compact_write_offset(ctx, raw_data);
else
compact_write_ptr(ctx, NULL);
if( obj->values )
compact_write_offset(ctx, values_data);
else
compact_write_ptr(ctx, NULL);
compact_write_int(ctx,obj->nfields);
compact_write_int(ctx,obj->raw_size);
compact_write_int(ctx,obj->nvalues);
# ifdef HL_64
compact_write_int(ctx,0);
# endif
compact_write_ref(ctx,obj->virtuals,false);
if( obj->lookup )
compact_write_mem(ctx,obj->lookup,sizeof(hl_field_lookup) * obj->nfields);
if( obj->raw_data )
compact_write_mem(ctx,obj->raw_data,obj->raw_size);
if( obj->values ) {
compact_pad(ctx,&hlt_dyn);
for(i=0;i<obj->nvalues;i++) {
int j;
for(j=0;i<obj->nfields;j++) {
if( obj->lookup[j].field_index == i && hl_is_ptr(obj->lookup[j].t) ) {
compact_write_data(ctx, obj->lookup[j].t, obj->values + i);
break;
}
}
}
}
int save_pos = ctx->todos_pos;
for(i=0;i<obj->nfields;i++) {
hl_field_lookup *f = obj->lookup + i;
int idx = compact_lookup_ref(ctx, hl_is_ptr(f->t) ? (char*)(obj->values + f->field_index) : (char*)(obj->raw_data + f->field_index), false);
idx = -idx-1;
ctx->remap_target[idx] = hl_is_ptr(f->t) ? values_data + sizeof(void*)*f->field_index : raw_data + f->field_index;
}
ctx->todos_pos = save_pos;
break;
}
case HARRAY: {
varray *a = (varray*)d;
compact_write_ptr(ctx, a->t);
compact_write_ptr(ctx, a->at);
compact_write_int(ctx, a->size);
compact_write_int(ctx, 0);
char *array_data = (char*)(a + 1);
int stride = hl_type_size(a->at);
for(i=0;i<a->size;i++) {
compact_write_data(ctx,a->at, array_data + stride * i);
}
break;
}
case HENUM: {
venum *e = (venum*)d;
hl_enum_construct *c = &t->tenum->constructs[e->index];
int buf_start = ctx->buf_pos;
compact_write_ptr(ctx, e->t);
compact_write_int(ctx, e->index);
for(i=0;i<c->nparams;i++) {
compact_pad(ctx,c->params[i]);
compact_write_data(ctx,c->params[i],(char*)e+(ctx->buf_pos-buf_start));
}
break;
}
default:
hl_error("Unsupported type %d", t->kind);
}
}
HL_PRIM vdynamic *hl_mem_compact( vdynamic *d, varray *exclude, int flags, int *outCount ) {
mem_context _ctx;
mem_context *ctx = &_ctx;
int i;
int object_count = 0;
memset(ctx,0,sizeof(mem_context));
ctx->flags = flags;
compact_lookup_ref(ctx,d,false);
if( exclude ) {
for(i=0;i<exclude->size;i++) {
vdynamic *ptr = (vdynamic*)hl_aptr(exclude,void*)[i];
compact_lookup_ref(ctx,ptr,false);
ctx->todos_pos--;
}
}
while( ctx->todos_pos > 0 ) {
void *addr = ctx->todos[--ctx->todos_pos];
int pos = compact_lookup_index(ctx, addr);
int index = ctx->lookup_index[pos];
compact_pad(ctx, &hlt_dyn);
ctx->remap_target[index&~BYTE_MARK] = ctx->buf_pos;
if( index & BYTE_MARK ) {
int size = hl_gc_get_memsize(addr);
if( size < 0 ) hl_error("assert");
compact_write_mem(ctx, addr, size);
} else
compact_write_content(ctx, (vdynamic*)addr);
object_count++;
}
vbyte *data = NULL;
# ifdef HL_WIN
if( flags & 1 )
data = (vbyte*)VirtualAlloc(NULL,ctx->buf_pos,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
# endif
if( data == NULL )
data = hl_gc_alloc_noptr(ctx->buf_pos);
memcpy(data,ctx->buf,ctx->buf_pos);
int exclude_count = exclude ? exclude->size : 0;
for(i=0;i<ctx->offsets_pos;i++) {
int pos = ctx->offsets[i];
int target = *(int*)(data + pos);
if( target < 0 ) {
int eid = -target-1;
if( eid > 0 && eid <= exclude_count ) {
*(void**)(data+pos) = hl_aptr(exclude,void*)[eid-1];
continue;
}
target = ctx->remap_target[eid];
}
*(void**)(data+pos) = data + target;
}
free(ctx->buf);
free(ctx->offsets);
free(ctx->lookup);
free(ctx->lookup_index);
free(ctx->remap_target);
free(ctx->todos);
# ifdef HL_WIN
if( flags & 1 ) {
DWORD old = 0;
VirtualProtect(data,ctx->buf_pos,PAGE_READONLY,&old);
}
# endif
if( outCount )
*outCount = object_count;
return (vdynamic*)data;
}
DEFINE_PRIM(_DYN, mem_compact, _DYN _ARR _I32 _REF(_I32));

View File

@ -0,0 +1,274 @@
/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <stdarg.h>
#ifndef HL_NATIVE_UCHAR_FUN
#ifdef HL_ANDROID
# include <android/log.h>
# ifndef HL_ANDROID_LOG_TAG
# define HL_ANDROID_LOG_TAG "hl"
# endif
# ifndef HL_ANDROID_LOG_LEVEL
# define HL_ANDROID_LOG_LEVEL ANDROID_LOG_DEBUG
# endif
# define LOG_ANDROID(cfmt,cstr) __android_log_print(HL_ANDROID_LOG_LEVEL, HL_ANDROID_LOG_TAG, cfmt, cstr);
#endif
int ustrlen( const uchar *str ) {
const uchar *p = str;
while( *p ) p++;
return (int)(p - str);
}
static int ustrlen_utf8( const uchar *str ) {
int size = 0;
while(1) {
uchar c = *str++;
if( c == 0 ) break;
if( c < 0x80 )
size++;
else if( c < 0x800 )
size += 2;
else if( c >= 0xD800 && c <= 0xDFFF ) {
str++;
size += 4;
} else
size += 3;
}
return size;
}
uchar *ustrdup( const uchar *str ) {
int len = ustrlen(str);
int size = (len + 1) << 1;
uchar *d = (uchar*)malloc(size);
memcpy(d,str,size);
return d;
}
double utod( const uchar *str, uchar **end ) {
char buf[31];
char *bend;
double result;
int i = 0;
while( i < 30 ) {
int c = str[i];
if( (c < '0' || c > '9') && c != '.' && c != 'e' && c != 'E' && c != '-' && c != '+' )
break;
buf[i++] = (char)c;
}
buf[i] = 0;
result = strtod(buf,&bend);
*end = str + (bend - buf);
return result;
}
int utoi( const uchar *str, uchar **end ) {
char buf[17];
char *bend;
int result;
int i = 0;
uchar sign = str[0];
if( sign == '-' || sign == '+' ) {
buf[i++] = (char)sign;
}
while( i < 16 ) {
int c = str[i];
if( c < '0' || c > '9' )
break;
buf[i++] = (char)c;
}
buf[i] = 0;
result = strtol(buf,&bend,10);
*end = str + (bend - buf);
return result;
}
int ucmp( const uchar *a, const uchar *b ) {
while(true) {
int d = (unsigned)*a - (unsigned)*b;
if( d ) return d;
if( !*a ) return 0;
a++;
b++;
}
}
int usprintf( uchar *out, int out_size, const uchar *fmt, ... ) {
va_list args;
int ret;
va_start(args, fmt);
ret = uvszprintf(out, out_size, fmt, args);
va_end(args);
return ret;
}
// USE UTF-8 encoding
int utostr( char *out, int out_size, const uchar *str ) {
char *start = out;
char *end = out + out_size - 1; // final 0
if( out_size <= 0 ) return 0;
while( out < end ) {
unsigned int c = *str++;
if( c == 0 ) break;
if( c < 0x80 )
*out++ = (char)c;
else if( c < 0x800 ) {
if( out + 2 > end ) break;
*out++ = (char)(0xC0|(c>>6));
*out++ = 0x80|(c&63);
} else if( c >= 0xD800 && c <= 0xDFFF ) { // surrogate pair
if( out + 4 > end ) break;
unsigned int full = (((c - 0xD800) << 10) | ((*str++) - 0xDC00)) + 0x10000;
*out++ = (char)(0xF0|(full>>18));
*out++ = 0x80|((full>>12)&63);
*out++ = 0x80|((full>>6)&63);
*out++ = 0x80|(full&63);
} else {
if( out + 3 > end ) break;
*out++ = (char)(0xE0|(c>>12));
*out++ = 0x80|((c>>6)&63);
*out++ = 0x80|(c&63);
}
}
*out = 0;
return (int)(out - start);
}
static char *utos( const uchar *s ) {
int len = ustrlen_utf8(s);
char *out = (char*)malloc(len + 1);
if( utostr(out,len+1,s) < 0 )
*out = 0;
return out;
}
void uprintf( const uchar *fmt, const uchar *str ) {
char *cfmt = utos(fmt);
char *cstr = utos(str);
#ifdef HL_ANDROID
LOG_ANDROID(cfmt,cstr);
#else
printf(cfmt,cstr);
#endif
free(cfmt);
free(cstr);
}
#endif
#if !defined(HL_NATIVE_UCHAR_FUN) || defined(HL_WIN)
#ifdef HL_VCC
#pragma warning(disable:4774)
#endif
HL_PRIM int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist ) {
uchar *start = out;
uchar *end = out + out_size - 1;
char cfmt[20];
char tmp[32];
uchar c;
while(true) {
sprintf_loop:
c = *fmt++;
if( out == end ) c = 0;
switch( c ) {
case 0:
*out = 0;
return (int)(out - start);
case '%':
{
int i = 0, size = 0;
cfmt[i++] = '%';
while( true ) {
c = *fmt++;
cfmt[i++] = (char)c;
switch( c ) {
case 'd':
cfmt[i++] = 0;
if( cfmt[i-3] == 'l' ) {
size = sprintf(tmp,cfmt,va_arg(arglist,int64));
} else {
size = sprintf(tmp,cfmt,va_arg(arglist,int));
}
goto sprintf_add;
case 'f':
cfmt[i++] = 0;
size = sprintf(tmp,cfmt,va_arg(arglist,double)); // according to GCC warning, float is promoted to double in var_args
goto sprintf_add;
case 'g':
cfmt[i++] = 0;
size = sprintf(tmp,cfmt,va_arg(arglist,double));
goto sprintf_add;
case 'x':
case 'X':
cfmt[i++] = 0;
if( cfmt[i-3] == 'l' )
size = sprintf(tmp,cfmt,va_arg(arglist,void*));
else
size = sprintf(tmp,cfmt,va_arg(arglist,int));
goto sprintf_add;
case 's':
if( i != 2 ) hl_fatal("Unsupported printf format"); // no support for precision qualifier
{
uchar *s = va_arg(arglist,uchar *);
while( *s && out < end )
*out++ = *s++;
goto sprintf_loop;
}
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'l':
break;
default:
hl_fatal("Unsupported printf format");
break;
}
}
sprintf_add:
// copy from c string to u string
i = 0;
while( i < size && out < end )
*out++ = tmp[i++];
}
break;
default:
*out++ = c;
break;
}
}
return 0;
}
#endif

View File

@ -0,0 +1,97 @@
#define UL_BITS 6
#define UL_SIZE 64
static uchar _E[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L1[UL_SIZE] = {0,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L3[UL_SIZE] = {224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,0,248,249,250,251,252,253,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L4[UL_SIZE] = {257,0,259,0,261,0,263,0,265,0,267,0,269,0,271,0,273,0,275,0,277,0,279,0,281,0,283,0,285,0,287,0,289,0,291,0,293,0,295,0,297,0,299,0,301,0,303,0,105,0,307,0,309,0,311,0,0,314,0,316,0,318,0,320};
static uchar L5[UL_SIZE] = {0,322,0,324,0,326,0,328,0,0,331,0,333,0,335,0,337,0,339,0,341,0,343,0,345,0,347,0,349,0,351,0,353,0,355,0,357,0,359,0,361,0,363,0,365,0,367,0,369,0,371,0,373,0,375,0,255,378,0,380,0,382,0,0};
static uchar L6[UL_SIZE] = {0,595,387,0,389,0,596,392,0,598,599,396,0,0,477,601,603,402,0,608,611,0,617,616,409,0,0,0,623,626,0,629,417,0,419,0,421,0,640,424,0,643,0,0,429,0,648,432,0,650,651,436,0,438,0,658,441,0,0,0,445,0,0,0};
static uchar L7[UL_SIZE] = {0,0,0,0,454,454,0,457,457,0,460,460,0,462,0,464,0,466,0,468,0,470,0,472,0,474,0,476,0,0,479,0,481,0,483,0,485,0,487,0,489,0,491,0,493,0,495,0,0,499,499,0,501,0,405,447,505,0,507,0,509,0,511,0};
static uchar L8[UL_SIZE] = {513,0,515,0,517,0,519,0,521,0,523,0,525,0,527,0,529,0,531,0,533,0,535,0,537,0,539,0,541,0,543,0,414,0,547,0,549,0,551,0,553,0,555,0,557,0,559,0,561,0,563,0,0,0,0,0,0,0,11365,572,0,410,11366,0};
static uchar L9[UL_SIZE] = {0,578,0,384,649,652,583,0,585,0,587,0,589,0,591,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L13[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,881,0,883,0,0,0,887,0,0,0,0,0,0,0,0,1011};
static uchar L14[UL_SIZE] = {0,0,0,0,0,0,940,0,941,942,943,0,972,0,973,974,0,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,0,963,964,965,966,967,968,969,970,971,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L15[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,983,0,0,0,0,0,0,0,0,985,0,987,0,989,0,991,0,993,0,995,0,997,0,999,0,1001,0,1003,0,1005,0,1007,0,0,0,0,0,952,0,0,1016,0,1010,1019,0,0,891,892,893};
static uchar L16[UL_SIZE] = {1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L17[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1121,0,1123,0,1125,0,1127,0,1129,0,1131,0,1133,0,1135,0,1137,0,1139,0,1141,0,1143,0,1145,0,1147,0,1149,0,1151,0};
static uchar L18[UL_SIZE] = {1153,0,0,0,0,0,0,0,0,0,1163,0,1165,0,1167,0,1169,0,1171,0,1173,0,1175,0,1177,0,1179,0,1181,0,1183,0,1185,0,1187,0,1189,0,1191,0,1193,0,1195,0,1197,0,1199,0,1201,0,1203,0,1205,0,1207,0,1209,0,1211,0,1213,0,1215,0};
static uchar L19[UL_SIZE] = {1231,1218,0,1220,0,1222,0,1224,0,1226,0,1228,0,1230,0,0,1233,0,1235,0,1237,0,1239,0,1241,0,1243,0,1245,0,1247,0,1249,0,1251,0,1253,0,1255,0,1257,0,1259,0,1261,0,1263,0,1265,0,1267,0,1269,0,1271,0,1273,0,1275,0,1277,0,1279,0};
static uchar L20[UL_SIZE] = {1281,0,1283,0,1285,0,1287,0,1289,0,1291,0,1293,0,1295,0,1297,0,1299,0,1301,0,1303,0,1305,0,1307,0,1309,0,1311,0,1313,0,1315,0,1317,0,1319,0,1321,0,1323,0,1325,0,1327,0,0,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391};
static uchar L21[UL_SIZE] = {1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L66[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,11530,11531,11532,11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548,11549,11550,11551};
static uchar L67[UL_SIZE] = {11552,11553,11554,11555,11556,11557,0,11559,0,0,0,0,0,11565,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L78[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43888,43889,43890,43891,43892,43893,43894,43895,43896,43897,43898,43899,43900,43901,43902,43903,43904,43905,43906,43907,43908,43909,43910,43911,43912,43913,43914,43915,43916,43917,43918,43919};
static uchar L79[UL_SIZE] = {43920,43921,43922,43923,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934,43935,43936,43937,43938,43939,43940,43941,43942,43943,43944,43945,43946,43947,43948,43949,43950,43951,43952,43953,43954,43955,43956,43957,43958,43959,43960,43961,43962,43963,43964,43965,43966,43967,5112,5113,5114,5115,5116,5117,0,0,0,0,0,0,0,0,0,0};
static uchar L120[UL_SIZE] = {7681,0,7683,0,7685,0,7687,0,7689,0,7691,0,7693,0,7695,0,7697,0,7699,0,7701,0,7703,0,7705,0,7707,0,7709,0,7711,0,7713,0,7715,0,7717,0,7719,0,7721,0,7723,0,7725,0,7727,0,7729,0,7731,0,7733,0,7735,0,7737,0,7739,0,7741,0,7743,0};
static uchar L121[UL_SIZE] = {7745,0,7747,0,7749,0,7751,0,7753,0,7755,0,7757,0,7759,0,7761,0,7763,0,7765,0,7767,0,7769,0,7771,0,7773,0,7775,0,7777,0,7779,0,7781,0,7783,0,7785,0,7787,0,7789,0,7791,0,7793,0,7795,0,7797,0,7799,0,7801,0,7803,0,7805,0,7807,0};
static uchar L122[UL_SIZE] = {7809,0,7811,0,7813,0,7815,0,7817,0,7819,0,7821,0,7823,0,7825,0,7827,0,7829,0,0,0,0,0,0,0,0,0,223,0,7841,0,7843,0,7845,0,7847,0,7849,0,7851,0,7853,0,7855,0,7857,0,7859,0,7861,0,7863,0,7865,0,7867,0,7869,0,7871,0};
static uchar L123[UL_SIZE] = {7873,0,7875,0,7877,0,7879,0,7881,0,7883,0,7885,0,7887,0,7889,0,7891,0,7893,0,7895,0,7897,0,7899,0,7901,0,7903,0,7905,0,7907,0,7909,0,7911,0,7913,0,7915,0,7917,0,7919,0,7921,0,7923,0,7925,0,7927,0,7929,0,7931,0,7933,0,7935,0};
static uchar L124[UL_SIZE] = {0,0,0,0,0,0,0,0,7936,7937,7938,7939,7940,7941,7942,7943,0,0,0,0,0,0,0,0,7952,7953,7954,7955,7956,7957,0,0,0,0,0,0,0,0,0,0,7968,7969,7970,7971,7972,7973,7974,7975,0,0,0,0,0,0,0,0,7984,7985,7986,7987,7988,7989,7990,7991};
static uchar L125[UL_SIZE] = {0,0,0,0,0,0,0,0,8000,8001,8002,8003,8004,8005,0,0,0,0,0,0,0,0,0,0,0,8017,0,8019,0,8021,0,8023,0,0,0,0,0,0,0,0,8032,8033,8034,8035,8036,8037,8038,8039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L126[UL_SIZE] = {0,0,0,0,0,0,0,0,8064,8065,8066,8067,8068,8069,8070,8071,0,0,0,0,0,0,0,0,8080,8081,8082,8083,8084,8085,8086,8087,0,0,0,0,0,0,0,0,8096,8097,8098,8099,8100,8101,8102,8103,0,0,0,0,0,0,0,0,8112,8113,8048,8049,8115,0,0,0};
static uchar L127[UL_SIZE] = {0,0,0,0,0,0,0,0,8050,8051,8052,8053,8131,0,0,0,0,0,0,0,0,0,0,0,8144,8145,8054,8055,0,0,0,0,0,0,0,0,0,0,0,0,8160,8161,8058,8059,8165,0,0,0,0,0,0,0,0,0,0,0,8056,8057,8060,8061,8179,0,0,0};
static uchar L132[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,969,0,0,0,107,229,0,0,0,0,0,0,8526,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L133[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L134[UL_SIZE] = {0,0,0,8580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L146[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433};
static uchar L147[UL_SIZE] = {9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L176[UL_SIZE] = {11312,11313,11314,11315,11316,11317,11318,11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334,11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,11348,11349,11350,11351,11352,11353,11354,11355,11356,11357,11358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L177[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11361,0,619,7549,637,0,0,11368,0,11370,0,11372,0,593,625,592,594,0,11379,0,0,11382,0,0,0,0,0,0,0,0,575,576};
static uchar L178[UL_SIZE] = {11393,0,11395,0,11397,0,11399,0,11401,0,11403,0,11405,0,11407,0,11409,0,11411,0,11413,0,11415,0,11417,0,11419,0,11421,0,11423,0,11425,0,11427,0,11429,0,11431,0,11433,0,11435,0,11437,0,11439,0,11441,0,11443,0,11445,0,11447,0,11449,0,11451,0,11453,0,11455,0};
static uchar L179[UL_SIZE] = {11457,0,11459,0,11461,0,11463,0,11465,0,11467,0,11469,0,11471,0,11473,0,11475,0,11477,0,11479,0,11481,0,11483,0,11485,0,11487,0,11489,0,11491,0,0,0,0,0,0,0,0,11500,0,11502,0,0,0,0,11507,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L665[UL_SIZE] = {42561,0,42563,0,42565,0,42567,0,42569,0,42571,0,42573,0,42575,0,42577,0,42579,0,42581,0,42583,0,42585,0,42587,0,42589,0,42591,0,42593,0,42595,0,42597,0,42599,0,42601,0,42603,0,42605,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L666[UL_SIZE] = {42625,0,42627,0,42629,0,42631,0,42633,0,42635,0,42637,0,42639,0,42641,0,42643,0,42645,0,42647,0,42649,0,42651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar L668[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42787,0,42789,0,42791,0,42793,0,42795,0,42797,0,42799,0,0,0,42803,0,42805,0,42807,0,42809,0,42811,0,42813,0,42815,0};
static uchar L669[UL_SIZE] = {42817,0,42819,0,42821,0,42823,0,42825,0,42827,0,42829,0,42831,0,42833,0,42835,0,42837,0,42839,0,42841,0,42843,0,42845,0,42847,0,42849,0,42851,0,42853,0,42855,0,42857,0,42859,0,42861,0,42863,0,0,0,0,0,0,0,0,0,0,42874,0,42876,0,7545,42879,0};
static uchar L670[UL_SIZE] = {42881,0,42883,0,42885,0,42887,0,0,0,0,42892,0,613,0,0,42897,0,42899,0,0,0,42903,0,42905,0,42907,0,42909,0,42911,0,42913,0,42915,0,42917,0,42919,0,42921,0,614,604,609,620,0,0,670,647,669,43859,42933,0,42935,0,0,0,0,0,0,0,0,0};
static uchar L1020[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,0};
static uchar U1[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,0,0,0};
static uchar U2[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,0,0,0,0,0,0,0};
static uchar U3[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,0,216,217,218,219,220,221,222,376};
static uchar U4[UL_SIZE] = {0,256,0,258,0,260,0,262,0,264,0,266,0,268,0,270,0,272,0,274,0,276,0,278,0,280,0,282,0,284,0,286,0,288,0,290,0,292,0,294,0,296,0,298,0,300,0,302,0,73,0,306,0,308,0,310,0,0,313,0,315,0,317,0};
static uchar U5[UL_SIZE] = {319,0,321,0,323,0,325,0,327,0,0,330,0,332,0,334,0,336,0,338,0,340,0,342,0,344,0,346,0,348,0,350,0,352,0,354,0,356,0,358,0,360,0,362,0,364,0,366,0,368,0,370,0,372,0,374,0,0,377,0,379,0,381,83};
static uchar U6[UL_SIZE] = {579,0,0,386,0,388,0,0,391,0,0,0,395,0,0,0,0,0,401,0,0,502,0,0,0,408,573,0,0,0,544,0,0,416,0,418,0,420,0,0,423,0,0,0,0,428,0,0,431,0,0,0,435,0,437,0,0,440,0,0,0,444,0,503};
static uchar U7[UL_SIZE] = {0,0,0,0,453,453,453,456,456,456,459,459,459,0,461,0,463,0,465,0,467,0,469,0,471,0,473,0,475,398,0,478,0,480,0,482,0,484,0,486,0,488,0,490,0,492,0,494,0,498,498,498,0,500,0,0,0,504,0,506,0,508,0,510};
static uchar U8[UL_SIZE] = {0,512,0,514,0,516,0,518,0,520,0,522,0,524,0,526,0,528,0,530,0,532,0,534,0,536,0,538,0,540,0,542,0,0,0,546,0,548,0,550,0,552,0,554,0,556,0,558,0,560,0,562,0,0,0,0,0,0,0,0,571,0,0,11390};
static uchar U9[UL_SIZE] = {11391,0,577,0,0,0,0,582,0,584,0,586,0,588,0,590,11375,11373,11376,385,390,0,393,394,0,399,0,400,42923,0,0,0,403,42924,0,404,0,42893,42922,0,407,406,0,11362,42925,0,0,412,0,11374,413,0,0,415,0,0,0,0,0,0,0,11364,0,0};
static uchar U10[UL_SIZE] = {422,0,0,425,0,0,0,42929,430,580,433,434,581,0,0,0,0,0,439,0,0,0,0,0,0,0,0,0,0,42930,42928,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U13[UL_SIZE] = {0,0,0,0,0,921,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,882,0,0,0,886,0,0,0,1021,1022,1023,0,0};
static uchar U14[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,902,904,905,906,0,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927};
static uchar U15[UL_SIZE] = {928,929,931,931,932,933,934,935,936,937,938,939,908,910,911,0,914,920,0,0,0,934,928,975,0,984,0,986,0,988,0,990,0,992,0,994,0,996,0,998,0,1000,0,1002,0,1004,0,1006,922,929,1017,895,0,917,0,0,1015,0,0,1018,0,0,0,0};
static uchar U16[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055};
static uchar U17[UL_SIZE] = {1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,0,1120,0,1122,0,1124,0,1126,0,1128,0,1130,0,1132,0,1134,0,1136,0,1138,0,1140,0,1142,0,1144,0,1146,0,1148,0,1150};
static uchar U18[UL_SIZE] = {0,1152,0,0,0,0,0,0,0,0,0,1162,0,1164,0,1166,0,1168,0,1170,0,1172,0,1174,0,1176,0,1178,0,1180,0,1182,0,1184,0,1186,0,1188,0,1190,0,1192,0,1194,0,1196,0,1198,0,1200,0,1202,0,1204,0,1206,0,1208,0,1210,0,1212,0,1214};
static uchar U19[UL_SIZE] = {0,0,1217,0,1219,0,1221,0,1223,0,1225,0,1227,0,1229,1216,0,1232,0,1234,0,1236,0,1238,0,1240,0,1242,0,1244,0,1246,0,1248,0,1250,0,1252,0,1254,0,1256,0,1258,0,1260,0,1262,0,1264,0,1266,0,1268,0,1270,0,1272,0,1274,0,1276,0,1278};
static uchar U20[UL_SIZE] = {0,1280,0,1282,0,1284,0,1286,0,1288,0,1290,0,1292,0,1294,0,1296,0,1298,0,1300,0,1302,0,1304,0,1306,0,1308,0,1310,0,1312,0,1314,0,1316,0,1318,0,1320,0,1322,0,1324,0,1326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U21[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359};
static uchar U22[UL_SIZE] = {1360,1361,1362,1363,1364,1365,1366,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U79[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5104,5105,5106,5107,5108,5109,0,0};
static uchar U117[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42877,0,0,0,11363,0,0};
static uchar U120[UL_SIZE] = {0,7680,0,7682,0,7684,0,7686,0,7688,0,7690,0,7692,0,7694,0,7696,0,7698,0,7700,0,7702,0,7704,0,7706,0,7708,0,7710,0,7712,0,7714,0,7716,0,7718,0,7720,0,7722,0,7724,0,7726,0,7728,0,7730,0,7732,0,7734,0,7736,0,7738,0,7740,0,7742};
static uchar U121[UL_SIZE] = {0,7744,0,7746,0,7748,0,7750,0,7752,0,7754,0,7756,0,7758,0,7760,0,7762,0,7764,0,7766,0,7768,0,7770,0,7772,0,7774,0,7776,0,7778,0,7780,0,7782,0,7784,0,7786,0,7788,0,7790,0,7792,0,7794,0,7796,0,7798,0,7800,0,7802,0,7804,0,7806};
static uchar U122[UL_SIZE] = {0,7808,0,7810,0,7812,0,7814,0,7816,0,7818,0,7820,0,7822,0,7824,0,7826,0,7828,0,0,0,0,0,7776,0,0,0,0,0,7840,0,7842,0,7844,0,7846,0,7848,0,7850,0,7852,0,7854,0,7856,0,7858,0,7860,0,7862,0,7864,0,7866,0,7868,0,7870};
static uchar U123[UL_SIZE] = {0,7872,0,7874,0,7876,0,7878,0,7880,0,7882,0,7884,0,7886,0,7888,0,7890,0,7892,0,7894,0,7896,0,7898,0,7900,0,7902,0,7904,0,7906,0,7908,0,7910,0,7912,0,7914,0,7916,0,7918,0,7920,0,7922,0,7924,0,7926,0,7928,0,7930,0,7932,0,7934};
static uchar U124[UL_SIZE] = {7944,7945,7946,7947,7948,7949,7950,7951,0,0,0,0,0,0,0,0,7960,7961,7962,7963,7964,7965,0,0,0,0,0,0,0,0,0,0,7976,7977,7978,7979,7980,7981,7982,7983,0,0,0,0,0,0,0,0,7992,7993,7994,7995,7996,7997,7998,7999,0,0,0,0,0,0,0,0};
static uchar U125[UL_SIZE] = {8008,8009,8010,8011,8012,8013,0,0,0,0,0,0,0,0,0,0,0,8025,0,8027,0,8029,0,8031,0,0,0,0,0,0,0,0,8040,8041,8042,8043,8044,8045,8046,8047,0,0,0,0,0,0,0,0,8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,0,0};
static uchar U126[UL_SIZE] = {8072,8073,8074,8075,8076,8077,8078,8079,0,0,0,0,0,0,0,0,8088,8089,8090,8091,8092,8093,8094,8095,0,0,0,0,0,0,0,0,8104,8105,8106,8107,8108,8109,8110,8111,0,0,0,0,0,0,0,0,8120,8121,0,8124,0,0,0,0,0,0,0,0,0,0,921,0};
static uchar U127[UL_SIZE] = {0,0,0,8140,0,0,0,0,0,0,0,0,0,0,0,0,8152,8153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8168,8169,0,0,0,8172,0,0,0,0,0,0,0,0,0,0,0,0,0,8188,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U133[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,8498,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559};
static uchar U134[UL_SIZE] = {0,0,0,0,8579,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U147[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U176[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279};
static uchar U177[UL_SIZE] = {11280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,11310,0,0,11360,0,0,0,570,574,0,11367,0,11369,0,11371,0,0,0,0,0,0,11378,0,0,11381,0,0,0,0,0,0,0,0,0};
static uchar U178[UL_SIZE] = {0,11392,0,11394,0,11396,0,11398,0,11400,0,11402,0,11404,0,11406,0,11408,0,11410,0,11412,0,11414,0,11416,0,11418,0,11420,0,11422,0,11424,0,11426,0,11428,0,11430,0,11432,0,11434,0,11436,0,11438,0,11440,0,11442,0,11444,0,11446,0,11448,0,11450,0,11452,0,11454};
static uchar U179[UL_SIZE] = {0,11456,0,11458,0,11460,0,11462,0,11464,0,11466,0,11468,0,11470,0,11472,0,11474,0,11476,0,11478,0,11480,0,11482,0,11484,0,11486,0,11488,0,11490,0,0,0,0,0,0,0,0,11499,0,11501,0,0,0,0,11506,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U180[UL_SIZE] = {4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,0,4295,0,0,0,0,0,4301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U665[UL_SIZE] = {0,42560,0,42562,0,42564,0,42566,0,42568,0,42570,0,42572,0,42574,0,42576,0,42578,0,42580,0,42582,0,42584,0,42586,0,42588,0,42590,0,42592,0,42594,0,42596,0,42598,0,42600,0,42602,0,42604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U666[UL_SIZE] = {0,42624,0,42626,0,42628,0,42630,0,42632,0,42634,0,42636,0,42638,0,42640,0,42642,0,42644,0,42646,0,42648,0,42650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static uchar U668[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42786,0,42788,0,42790,0,42792,0,42794,0,42796,0,42798,0,0,0,42802,0,42804,0,42806,0,42808,0,42810,0,42812,0,42814};
static uchar U669[UL_SIZE] = {0,42816,0,42818,0,42820,0,42822,0,42824,0,42826,0,42828,0,42830,0,42832,0,42834,0,42836,0,42838,0,42840,0,42842,0,42844,0,42846,0,42848,0,42850,0,42852,0,42854,0,42856,0,42858,0,42860,0,42862,0,0,0,0,0,0,0,0,0,0,42873,0,42875,0,0,42878};
static uchar U670[UL_SIZE] = {0,42880,0,42882,0,42884,0,42886,0,0,0,0,42891,0,0,0,0,42896,0,42898,0,0,0,42902,0,42904,0,42906,0,42908,0,42910,0,42912,0,42914,0,42916,0,42918,0,42920,0,0,0,0,0,0,0,0,0,0,0,42932,0,42934,0,0,0,0,0,0,0,0};
static uchar U685[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039};
static uchar U686[UL_SIZE] = {5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103};
static uchar U1021[UL_SIZE] = {0,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#define LMAX 1021
#define UMAX 1022
static uchar *LOWER[LMAX] = {_E,L1,_E,L3,L4,L5,L6,L7,L8,L9,_E,_E,_E,L13,L14,L15,L16,L17,L18,L19,L20,L21,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L66,L67,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L78,L79,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L120,L121,L122,L123,L124,L125,L126,L127,_E,_E,_E,_E,L132,L133,L134,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L146,L147,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L176,L177,L178,L179,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L665,L666,_E,L668,L669,L670,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L1020};
static uchar *UPPER[UMAX] = {_E,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,_E,_E,U13,U14,U15,U16,U17,U18,U19,U20,U21,U22,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U79,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U117,_E,_E,U120,U121,U122,U123,U124,U125,U126,U127,_E,_E,_E,_E,_E,U133,U134,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U147,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U176,U177,U178,U179,U180,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U665,U666,_E,U668,U669,U670,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U685,U686,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U1021};