//definitions common to qbxlib & qbx-qbmain
#include "common.cpp"

//forward references
extern int QBMAIN(void *);

//extern functions
extern void sub__screenprint(qbs *txt);
extern void sub__screenclick(int32 x,int32 y);
extern int32 func__screenimage();
extern void sub_lock(int32 i,int64 start,int64 end,int32 passed);
extern void sub_unlock(int32 i,int64 start,int64 end,int32 passed);
void chain_restorescreenstate(int32);
void chain_savescreenstate(int32);
extern void sub__fullscreen(int32 method);
extern int32 func__fullscreen();
extern void sub__clipboard(qbs*);
extern qbs *func__clipboard();
extern int32 func__exit();
extern char *fixdir(qbs*);
extern void revert_input_check();
extern int32 func__openhost(qbs*);
extern int32 func__openconnection(int32);
extern int32 func__openclient(qbs*);
extern int32 func__connected(int32);
extern qbs *func__connectionaddress(int32);
//extern int MessageBox(int p1,char* p2,char* p3,int p4);
extern qbs *func_environ(qbs*);
extern qbs *func_environ(long);
extern void sub_environ(qbs*);
extern void sub_draw(qbs*);
extern void qbs_maketmp(qbs*);
extern void sub_run(qbs*);
extern void sub_run_init();
extern void sndcloseall();
extern void freeallimages();
extern void call_interrupt(long,void*,void*);
extern void call_interruptx(long,void*,void*);
extern uint32 _lrotl(uint32 word,uint32 shift);
extern int64 qbr(long double f);
extern uint64 qbr_longdouble_to_uint64(long double f);
extern long qbr_float_to_long(float f);
extern long qbr_double_to_long(double f);
extern int64 qbr(long double f);
extern uint64 qbr_longdouble_to_uint64(long double f);
extern long qbr_float_to_long(float f);
extern long qbr_double_to_long(double f);
extern void restorepalette(img_struct* im);
extern void pset(long x,long y,unsigned long col);
extern unsigned long newimg();
extern long freeimg(unsigned long i);
extern void imgrevert(long i);
extern long imgframe(unsigned char *o,long x,long y,long bpp);
extern long imgnew(long x,long y,long bpp);
extern long imgload(char *filename,long bpp);
extern void sub__putimage(long dstep1,double f_dx1,double f_dy1,long dstep2,double f_dx2,double f_dy2,long src,long dst,long sstep1,double f_sx1,double f_sy1,long sstep2,double f_sx2,double f_sy2,long passed);
extern long fontopen(char *name,double d_height,long flags);
extern long selectfont(long f,img_struct *im);
extern void sndsetup();
extern uint32 sib();
extern uint32 sib_mod0();
extern uint8 *rm8();
extern uint16 *rm16();
extern uint32 *rm32();
extern void cpu_call();
extern int64 build_int64(unsigned long val2,unsigned long val1);
extern uint64 build_uint64(unsigned long val2,unsigned long val1);
extern void fix_error();
extern void error(long error_number);
extern double get_error_erl();
extern unsigned long get_error_err();
extern void end();
extern unsigned char *mem_static_malloc(unsigned long size);
extern void mem_static_restore(unsigned char* restore_point);
extern unsigned char *cmem_dynamic_malloc(unsigned long size);
extern void cmem_dynamic_free(unsigned char *block);
extern void sub_defseg(long segment,long passed);
extern long func_peek(long offset);
extern void sub_poke(long offset,long value);
extern long array_check(unsigned long index,unsigned long limit);
extern void more_return_points();
extern void qb64_generatesound(double f,double l,unsigned char wait);
extern unsigned char *soundwave(double frequency,double length,double volume,double fadein,double fadeout);
extern long wavesize(double length);
extern qbs *qbs_new_descriptor();
extern void qbs_free_descriptor(qbs *str);
extern void qbs_free(qbs *str);
extern void qbs_cmem_concat_list();
extern void qbs_concat_list();
extern void qbs_tmp_concat_list();
extern void qbs_concat(unsigned long bytesrequired);
extern void qbs_concat_cmem(unsigned long bytesrequired);
extern qbs *qbs_new_cmem(long size,unsigned char tmp);
extern qbs *qbs_new_txt(const char *txt);
extern qbs *qbs_new_txt_len(const char *txt,long len);
extern qbs *qbs_new_fixed(unsigned char *offset,unsigned long size,unsigned char tmp);
extern qbs *qbs_new(long size,unsigned char tmp);
extern qbs *qbs_set(qbs *deststr,qbs *srcstr);
extern qbs *qbs_add(qbs *str1,qbs *str2);
extern qbs *qbs_ucase(qbs *str);
extern qbs *qbs_lcase(qbs *str);
extern qbs *func_chr(long value);
extern qbs *func_varptr_helper(unsigned char type,unsigned short offset);
extern qbs *qbs_left(qbs *str,long l);
extern qbs *qbs_right(qbs *str,long l);
extern qbs *func_mksmbf(float val);
extern qbs *func_mkdmbf(double val);
extern float func_cvsmbf(qbs *str);
extern double func_cvdmbf(qbs *str);
extern qbs *bit2string(unsigned long bsize,int64 v);
extern qbs *ubit2string(unsigned long bsize,uint64 v);
extern uint64 string2ubit(qbs*str,unsigned long bsize);
extern int64 string2bit(qbs*str,unsigned long bsize);
extern void sub_lset(qbs *dest,qbs *source);
extern void sub_rset(qbs *dest,qbs *source);
extern qbs *func_space(long spaces);
extern qbs *func_string(long characters,long asciivalue);
extern long func_instr(long start,qbs *str,qbs *substr,long passed);
extern void sub_mid(qbs *dest,long start,long l,qbs* src,long passed);
extern qbs *func_mid(qbs *str,long start,long l,long passed);
extern qbs *qbs_ltrim(qbs *str);
extern qbs *qbs_rtrim(qbs *str);
extern qbs *qbs_inkey();
extern qbs *qbs_str(int64 value);
extern qbs *qbs_str(int32 value);
extern qbs *qbs_str(int16 value);
extern qbs *qbs_str(int8 value);
extern qbs *qbs_str(uint64 value);
extern qbs *qbs_str(uint32 value);
extern qbs *qbs_str(uint16 value);
extern qbs *qbs_str(uint8 value);
extern qbs *qbs_str(float value);
extern qbs *qbs_str(double value);
extern qbs *qbs_str(long double value);
extern long qbs_equal(qbs *str1,qbs *str2);
extern long qbs_notequal(qbs *str1,qbs *str2);
extern long qbs_greaterthan(qbs *str1,qbs *str2);
extern long qbs_lessthan(qbs *str1,qbs *str2);
extern long qbs_lessorequal(qbs *str1,qbs *str2);
extern long qbs_greaterorequal(qbs *str1,qbs *str2);
extern long qbs_asc(qbs*);
extern long qbs_asc(qbs*,unsigned long);
extern long qbs_len(qbs *str);
extern void lineclip(long x1,long y1,long x2,long y2,long xmin,long ymin,long xmax,long ymax);
extern void qbg_palette(unsigned long attribute,unsigned long col,long passed);
extern void qbg_sub_color(unsigned long col1,unsigned long col2,unsigned long bordercolor,long passed);
extern void defaultcolors();
extern void validatepage(long n);
extern void qbg_screen(long mode,long color_switch,long active_page,long visual_page,long refresh,long passed);
extern void sub_pcopy(long src,long dst);
extern void qbsub_width(long option,long value1,long value2,long passed);
extern void pset(long x,long y,unsigned long col);
extern void pset_and_clip(long x,long y,unsigned long col);
extern void qb32_boxfill(float x1f,float y1f,float x2f,float y2f,unsigned long col);
extern void fast_boxfill(long x1,long y1,long x2,long y2,unsigned long col);
extern void fast_line(long x1,long y1,long x2,long y2,unsigned long col);
extern void qb32_line(float x1f,float y1f,float x2f,float y2f,unsigned long col,unsigned long style);
extern void sub_line(long step1,float x1,float y1,long step2,float x2,float y2,unsigned long col,long bf,unsigned long style,long passed);
extern void sub_paint32(long step,float x,float y,unsigned long fillcol,unsigned long bordercol,long passed);
extern void sub_paint32x(long step,float x,float y,unsigned long fillcol,unsigned long bordercol,long passed);
extern void sub_paint(long step,float x,float y,unsigned long fillcol,unsigned long bordercol,qbs *backgroundstr,long passed);
extern void sub_paint(long step,float x,float y,qbs *fillstr,unsigned long bordercol,qbs *backgroundstr,long passed);
extern void sub_circle(long step,double x,double y,double r,unsigned long col,double start,double end,double aspect,long passed);
extern unsigned long point(long x,long y);
extern double func_point(float x,float y,long passed);
extern void qbg_pset(long step,float x,float y,unsigned long col,long passed);
extern void sub_preset(long step,float x,float y,unsigned long col,long passed);
extern void printchr(long character);
extern long printchr2(long x,long y,unsigned long character,long i);
extern long chrwidth(long character);
extern void newline();
extern void makefit(qbs *text);
extern void tab();
extern void qbs_print(qbs* str,long finish_on_new_line);
extern long qbs_cleanup(unsigned long base,long passvalue);
extern void qbg_sub_window(long screen,float x1,float y1,float x2,float y2,long passed);
extern void qbg_sub_view_print(long topline,long bottomline,long passed);
extern void qbg_sub_view(long coords_relative_to_screen,long x1,long y1,long x2,long y2,long fillcolor,long bordercolor,long passed);
extern void sub_cls(long method,unsigned long use_color,long passed);
extern void qbg_sub_locate(long row,long column,long cursor,long start,long stop,long passed);
extern long hexoct2uint64(qbs* h);
extern void qbs_input(long numvariables,unsigned char newline);
extern double func_val(qbs *s);
extern void sub_out(long port,long data);
extern void sub_randomize (double seed,long passed);
extern float func_rnd(float n,long passed);
extern double func_timer(double accuracy,long passed);
extern void sub_sound(double frequency,double lengthinclockticks);
//following are declared below to allow for inlining
//extern double func_abs(double d);
//extern long double func_abs(long double d);
//extern float func_abs(float d);

//extern void sub_open(qbs *name,long type,long access,long sharing,long i,long record_length,long passed);
extern void sub_open(qbs *name,int32 type,int32 access,int32 sharing,int32 i,int64 record_length,int32 passed);

extern void sub_close(int32 i2,int32 passed);
extern long file_input_chr(long i);
extern void file_input_nextitem(long i,long lastc);
extern void sub_file_print(long i,qbs *str,long extraspace,long tab,long newline);
extern long n_roundincrement();
extern long n_float();
extern long n_int64();
extern long n_uint64();
extern long n_inputnumberfromdata(unsigned char *data,unsigned long *data_offset,unsigned long data_size);
extern long n_inputnumberfromfile(long fileno);
extern void sub_file_line_input_string(int32 fileno,qbs *deststr);
extern void sub_file_input_string(int32 fileno,qbs *deststr);
extern int64 func_file_input_int64(int32 fileno);
extern uint64 func_file_input_uint64(int32 fileno);
extern void sub_read_string(unsigned char *data,unsigned long *data_offset,unsigned long data_size,qbs *deststr);
extern long double func_read_float(unsigned char *data,unsigned long *data_offset,unsigned long data_size,long typ);
extern long double func_file_input_float(long fileno,long typ);
extern void *byte_element(uint64 offset,long length);

extern void sub_get(int32 i,int64 offset,void *element,int32 passed);
extern void sub_get2(int32 i,int64 offset,qbs *str,int32 passed);

extern void sub_put(int32 i,int64 offset,void *element,int32 passed);
extern void sub_put2(int32 i,int64 offset,void *element,int32 passed);
extern void sub_graphics_get(int32 step1,float x1f,float y1f,int32 step2,float x2f,float y2f,void *element,uint32 mask,int32 passed);
extern void sub_graphics_put(int32 step,float x1f,float y1f,void *element,int32 clip,int32 option,uint32 mask,int32 passed);
extern void sub_date(qbs* date);
extern qbs *func_date();
extern void sub_time(qbs* str);
extern qbs *func_time();
extern long func_csrlin();
extern long func_pos(long ignore);
extern double func_log(double value);
extern double func_csng_float(long double value);
extern double func_csng_double(double value);
extern double func_cdbl_float(long double value);
extern short func_cint_double(double value);
extern short func_cint_float(long double value);
extern short func_cint_long(long value);
extern short func_cint_ulong(unsigned long value);
extern short func_cint_int64(int64 value);
extern short func_cint_uint64(uint64 value);
extern long func_clng_double(double value);
extern long func_clng_float(long double value);
extern long func_clng_ulong(unsigned long value);
extern long func_clng_int64(int64 value);
extern long func_clng_uint64(uint64 value);
extern int64 func_round_double(double value);
extern int64 func_round_float(long double value);
extern double func_fix_double(double value);
extern long double func_fix_float(long double value);
extern double func_exp_single(double value);
extern long double func_exp_float(long double value);
extern void sub_sleep(long seconds,long passed);
extern qbs *func_oct(int64 value,int32 neg_bits);
extern qbs *func_oct_float(long double value);
extern qbs *func_hex(int64 value,int32 neg_size);
extern qbs *func_hex_float(long double value);
extern long func_lbound(long *array,long index,long num_indexes);
extern long func_ubound(long *array,long index,long num_indexes);
extern long func_sgn(unsigned char v);
extern long func_sgn(char v);
extern long func_sgn(unsigned short v);
extern long func_sgn(short v);
extern long func_sgn(unsigned long v);
extern long func_sgn(long v);
extern long func_sgn(uint64 v);
extern long func_sgn(int64 v);
extern long func_sgn(float v);
extern long func_sgn(double v);
extern long func_sgn(long double v);
extern long func_inp(long port);
extern void sub_wait(long port,long andexpression,long xorexpression,long passed);
extern qbs *func_tab(long pos);
extern qbs *func_spc(long spaces);
extern float func_pmap(float val,long option);
extern unsigned long func_screen(long y,long x,long returncol,long passed);
extern void sub_bsave(qbs *filename,long offset,long size);
extern void sub_bload(qbs *filename,long offset,long passed);

extern int64 func_lof(int32 i);
extern int32 func_eof(int32 i);
extern void sub_seek(int32 i,int64 pos);
extern int64 func_seek(int32 i);
extern int64 func_loc(int32 i);
extern qbs *func_input(int32 n,int32 i,int32 passed);

extern double func_sqr(double value);
extern void sub_beep();
extern void snd_check();
extern unsigned long func__sndraw(unsigned char* data,unsigned long bytes);
extern unsigned long func__sndopen(qbs* filename,qbs* requirements,long passed);
extern double func__sndlen(unsigned long handle);
extern void sub__sndlimit(unsigned long handle,double limit);
extern void sub__sndstop(unsigned long handle);
extern void sub__sndsetpos(unsigned long handle,double sec);
extern double func__sndgetpos(unsigned long handle);
extern void sub__sndbal(unsigned long handle,double x,double y,double z,long passed);
extern void sub__sndplay(unsigned long handle);
extern void sub__sndloop(unsigned long handle);
extern unsigned long func__sndcopy(unsigned long handle);
extern void sub__sndvol(unsigned long handle,float volume);
extern void sub__sndpause(unsigned long handle);
extern long func__sndpaused(unsigned long handle);
extern long func__sndplaying(unsigned long handle);
extern void sub__sndclose(unsigned long handle);
extern void sub__sndplayfile(qbs *filename,long sync,double volume,long passed);
extern void sub__sndplaycopy(unsigned long handle,double volume,long passed);
extern qbs *func_command();
extern void sub_shell(qbs *str,long passed);
extern void sub_shell2(qbs *str);
extern void sub_shell3(qbs *str);
extern void sub_kill(qbs *str);
extern void sub_name(qbs *oldname,qbs *newname);
extern void sub_chdir(qbs *str);
extern void sub_mkdir(qbs *str);
extern void sub_rmdir(qbs *str);
extern double pow2(double x,double y);
extern int32 func_freefile();
extern void sub__mousehide();
extern void sub__mouseshow();
extern float func__mousex();
extern float func__mousey();
extern long func__mouseinput();
extern long func__mousebutton(long i);
extern long func__mousewheel();
extern void call_absolute(long args,uint16 offset);
extern void call_interrupt(long i);
extern void sub_play(qbs *str);
extern long func__newimage(long x,long y,long bpp,long passed);
extern long func__loadimage(qbs *f,long bpp,long passed);
extern long func__copyimage(long i,long passed);
extern void sub__freeimage(long i,long passed);
extern void sub__source(long i);
extern void sub__dest(long i);
extern long func__source();
extern long func__dest();
extern long func__display();
extern void sub__blend(long i,long passed);
extern void sub__dontblend(long i,long passed);
extern void sub__clearcolor(long none,unsigned long c,long i,long passed);
extern void sub__setalpha(long a,unsigned long c,unsigned long c2,long i,long passed);
extern long func__width(long i,long passed);
extern long func__height(long i,long passed);
extern long func__pixelsize(long i,long passed);
extern long func__clearcolor(long i,long passed);
extern long func__blend(long i,long passed);
extern unsigned long func__defaultcolor(long i,long passed);
extern unsigned long func__backgroundcolor(long i,long passed);
extern unsigned long func__palettecolor(long n,long i,long passed);
extern void sub__palettecolor(long n,unsigned long c,long i,long passed);
extern void sub__copypalette(long i,long i2,long passed);
extern void sub__printstring(long step,double f_x,double f_y,qbs* text,long i,long passed);
extern long func__printwidth(qbs* text,long i,long passed);
extern long func__loadfont(qbs *filename,double size,qbs *requirements,long passed);
extern void sub__font(long f,long i,long passed);
extern long func__fontwidth(long f,long passed);
extern long func__fontheight(long f,long passed);
extern long func__font(long i,long passed);
extern void sub__freefont(long f);
extern void sub__printmode(long mode,long i,long passed);
extern long func__printmode(long i,long passed);
extern unsigned long func__rgb32(long r,long g,long b);
extern unsigned long func__rgba32(long r,long g,long b,long a);
extern long func__alpha32(unsigned long col);
extern long func__red32(unsigned long col);
extern long func__green32(unsigned long col);
extern long func__blue32(unsigned long col);
extern unsigned long matchcol(long r,long g,long b);
extern unsigned long matchcol(long r,long g,long b,long i);
extern unsigned long func__rgb(long r,long g,long b,long i,long passed);
extern unsigned long func__rgba(long r,long g,long b,long a,long i,long passed);
extern long func__alpha(unsigned long col,long i,long passed);
extern long func__red(unsigned long col,long i,long passed);
extern long func__green(unsigned long col,long i,long passed);
extern long func__blue(unsigned long col,long i,long passed);
extern void sub_end();
extern long print_using(qbs *f, long s2, qbs *dest, qbs* pu_str);
extern long print_using_integer64(qbs* format, int64 value, long start, qbs *output);
extern long print_using_uinteger64(qbs* format, uint64 value, long start, qbs *output);
extern long print_using_single(qbs* format, float value, long start, qbs *output);
extern long print_using_double(qbs* format, double value, long start, qbs *output);
extern long print_using_float(qbs* format, double value, long start, qbs *output);
extern qbs *b2string(char v);
extern qbs *ub2string(char v);
extern qbs *i2string(short v);
extern qbs *ui2string(short v);
extern qbs *l2string(long v);
extern qbs *ul2string(unsigned long v);
extern qbs *i642string(int64 v);
extern qbs *ui642string(uint64 v);
extern qbs *s2string(float v);
extern qbs *d2string(double v);
extern qbs *f2string(long double v);
extern char string2b(qbs*str);
extern unsigned char string2ub(qbs*str);
extern short string2i(qbs*str);
extern unsigned short string2ui(qbs*str);
extern long string2l(qbs*str);
extern unsigned long string2ul(qbs*str);
extern int64 string2i64(qbs*str);
extern uint64 string2ui64(qbs*str);
extern float string2s(qbs*str);
extern double string2d(qbs*str);
extern long double string2f(qbs*str);

//shared global variables
extern qbs *func_command_str;
int32 event_return=0;//inc/dec as each GOSUB to QBMAIN() begins/ends
int32 timer_event_occurred=0;//inc/dec as each GOSUB to QBMAIN() begins/ends
int32 timer_event_id=0;
unsigned long ercl;
uint16 call_absolute_offsets[256];
unsigned long dbgline;
unsigned long qbs_cmem_sp=256;
unsigned long cmem_sp=65536;
unsigned long dblock;//32bit offset of dblock
unsigned char close_program=0;
long tab_spc_cr_size=1;//default
uint64 *nothingvalue;
unsigned long error_err=0;
double error_erl=0;
unsigned long qbs_tmp_list_nexti=1;
unsigned long error_occurred=0;
unsigned long new_error=0;
qbs* nothingstring;
uint32 qbevent=0;
unsigned char suspend_program=0;
unsigned char stop_program=0;
unsigned long error_retry=0;
unsigned char cmem[1114099];//16*65535+65535+3 (enough for highest referencable dword in conv memory)
unsigned char *cmem_static_pointer=&cmem[0]+1280+65536;
unsigned char *cmem_dynamic_base=&cmem[0]+655360;
unsigned char *mem_static;
unsigned char *mem_static_pointer;
unsigned char *mem_static_limit;
double last_line=0;
unsigned long error_goto_line=0;
unsigned long error_handling=0;
unsigned long next_return_point=0;
unsigned long *return_point=(unsigned long*)malloc(4*16384);
unsigned long return_points=16384;
void *qbs_input_variableoffsets[257];
long qbs_input_variabletypes[257];

//qbmain specific global variables
char g_tmp_char;
unsigned char g_tmp_uchar;
short g_tmp_short;
unsigned short g_tmp_ushort;
long g_tmp_long;
unsigned long g_tmp_ulong;

int8 g_tmp_int8;
uint8 g_tmp_uint8;
int16 g_tmp_int16;
uint16 g_tmp_uint16;
int32 g_tmp_int32;
uint32 g_tmp_uint32;
int64 g_tmp_int64;
uint64 g_tmp_uint64;
float g_tmp_float;
double g_tmp_double;
long double g_tmp_longdouble;




qbs *g_swap_str;
qbs *pass_str;
unsigned long data_offset=0;

//inline functions
inline void swap_8(void *a,void*b){
uint8 x;
x=*(uint8*)a;
*(uint8*)a=*(uint8*)b;
*(uint8*)b=x;
}
inline void swap_16(void *a,void*b){
uint16 x;
x=*(uint16*)a;
*(uint16*)a=*(uint16*)b;
*(uint16*)b=x;
}
inline void swap_32(void *a,void*b){
uint32 x;
x=*(uint32*)a;
*(uint32*)a=*(uint32*)b;
*(uint32*)b=x;
}
inline void swap_64(void *a,void*b){
uint64 x;
x=*(uint64*)a;
*(uint64*)a=*(uint64*)b;
*(uint64*)b=x;
}
inline void swap_longdouble(void *a,void*b){
long double x;
x=*(long double*)a;
*(long double*)a=*(long double*)b;
*(long double*)b=x;
}
void swap_string(qbs *a,qbs *b){
static qbs *c;
c=qbs_new(a->len,0);
memcpy(c->chr,a->chr,a->len);
qbs_set(a,b);
qbs_set(b,c);
qbs_free(c);
}
void swap_block(void *a,void *b,uint32 bytes){
static uint32 quads;
quads=bytes>>2;
static uint32 *a32,*b32;
a32=(uint32*)a; b32=(uint32*)b;
while(quads--){
static uint32 c;
c=*a32;
*a32++=*b32;
*b32++=c;
}
bytes&=3;
static uint8 *a8,*b8;
a8=(uint8*)a32; b8=(uint8*)b32;
while(bytes--){
static uint8 c;
c=*a8;
*a8++=*b8;
*b8++=c;
}
}

//CSNG
inline double func_csng_float(long double value){
if ((value<=3.402823466E38)&&(value>=-3.402823466E38)){
return value;
}
error(6); return 0;
}
inline double func_csng_double(double value){
if ((value<=3.402823466E38)&&(value>=-3.402823466E38)){
return value;
}
error(6); return 0;
}

//CDBL
inline double func_cdbl_float(long double value){
if ((value<=1.7976931348623157E308)&&(value>=-1.7976931348623157E308)){
return value;
}
error(6); return 0;
}

//CINT
//func_cint_single uses func_cint_double
inline short func_cint_double(double value){
if ((value<32767.5)&&(value>-32768.5)){
if (value<0) return(value-0.5); else return(value+0.5);
}
error(6); return 0;
}
inline short func_cint_float(long double value){
if ((value<32767.5)&&(value>-32768.5)){
if (value<0) return(value-0.5); else return(value+0.5);
}
error(6); return 0;
}
inline short func_cint_long(long value){
if ((value>=-32768)&&(value<=32767)) return value;
error(6); return 0;
}
inline short func_cint_ulong(unsigned long value){
if (value<=32767) return value;
error(6); return 0;
}
inline short func_cint_int64(int64 value){
if ((value>=-32768)&&(value<=32767)) return value;
error(6); return 0;
}
inline short func_cint_uint64(uint64 value){
if (value<=32767) return value;
error(6); return 0;
}

//CLNG
//func_clng_single uses func_clng_double
//–2147483648 to 2147483647
inline long func_clng_double(double value){
if ((value<2147483647.5)&&(value>-2147483648.5)){
if (value<0) return(value-0.5); else return(value+0.5);
}
error(6); return 0;
}
inline long func_clng_float(long double value){
if ((value<2147483647.5)&&(value>-2147483648.5)){
if (value<0) return(value-0.5); else return(value+0.5);
}
error(6); return 0;
}
inline long func_clng_ulong(unsigned long value){
if (value<=2147483647) return value;
error(6); return 0;
}
inline long func_clng_int64(int64 value){
if ((value>=-2147483648)&&(value<=2147483647)) return value;
error(6); return 0;
}
inline long func_clng_uint64(uint64 value){
if (value<=2147483647) return value;
error(6); return 0;
}

//_ROUND (note: round performs no error checking)
inline int64 func_round_double(double value){
if (value<0) return(value-0.5f); else return(value+0.5f);
}
inline int64 func_round_float(long double value){
if (value<0) return(value-0.5f); else return(value+0.5f);
}

//force abs to return floating point numbers correctly
inline double func_abs(double d){
return fabs(d);
}
inline long double func_abs(long double d){
return fabs(d);
}
inline float func_abs(float d){
return fabs(d);
}

inline uint8 func_abs(uint8 d){return d;}
inline uint16 func_abs(uint16 d){return d;}
inline uint32 func_abs(uint32 d){return d;}
inline uint64 func_abs(uint64 d){return d;}
inline int8 func_abs(int8 d){return abs(d);}
inline int16 func_abs(int16 d){return abs(d);}
inline int32 func_abs(int32 d){return abs(d);}
//inline int64 func_abs(int64 d){return abs(d);}
inline int64 func_abs(int64 d){return abs((long)d);}

inline long array_check(unsigned long index,unsigned long limit){
//nb. forces signed index into an unsigned variable for quicker comparison
if (index<limit) return index;
error(9); return 0;
}

inline long func_sgn(unsigned char v){
if (v) return 1; else return 0;
}
inline long func_sgn(char v){
if (v) if (v>0) return 1; else return -1;
return 0;
}
inline long func_sgn(unsigned short v){
if (v) return 1; else return 0;
}
inline long func_sgn(short v){
if (v) if (v>0) return 1; else return -1;
return 0;
}
inline long func_sgn(unsigned long v){
if (v) return 1; else return 0;
}
inline long func_sgn(long v){
if (v) if (v>0) return 1; else return -1;
return 0;
}
inline long func_sgn(uint64 v){
if (v) return 1; else return 0;
}
inline long func_sgn(int64 v){
if (v) if (v>0) return 1; else return -1;
return 0;
}
inline long func_sgn(float v){
if (v) if (v>0) return 1; else return -1;
return 0;
}
inline long func_sgn(double v){
if (v) if (v>0) return 1; else return -1;
return 0;
}
inline long func_sgn(long double v){
if (v) if (v>0) return 1; else return -1;
return 0;
}

//Working with 32bit colors:
inline unsigned long func__rgb32(long r,long g,long b){
if (r<0) r=0;
if (r>255) r=255;
if (g<0) g=0;
if (g>255) g=255;
if (b<0) b=0;
if (b>255) b=255;
return (r<<16)+(g<<8)+b|0xFF000000;
}
inline unsigned long func__rgba32(long r,long g,long b,long a){
if (r<0) r=0;
if (r>255) r=255;
if (g<0) g=0;
if (g>255) g=255;
if (b<0) b=0;
if (b>255) b=255;
if (a<0) a=0;
if (a>255) a=255;
return (a<<24)+(r<<16)+(g<<8)+b;
}
inline long func__alpha32(unsigned long col){
return col>>24;
}
inline long func__red32(unsigned long col){
return col>>16&0xFF;
}
inline long func__green32(unsigned long col){
return col>>8&0xFF;
}
inline long func__blue32(unsigned long col){
return col&0xFF;
}

inline unsigned short varptr_dblock_check(unsigned char *off){
//note: 66816 is the top of DBLOCK (SEG:80+OFF:65536)
if (off<(&cmem[66816])){//in DBLOCK?
return ((unsigned short)(off-&cmem[1280]));
}else{
return ((unsigned long)(off-cmem))&15;
}
}

inline unsigned short varseg_dblock_check(unsigned char *off){
//note: 66816 is the top of DBLOCK (SEG:80+OFF:65536)
if (off<(&cmem[66816])){//in DBLOCK?
return 80;
}else{
return ((unsigned long)(off-cmem))/16;
}
}


const unsigned char QBMAIN_data[]={
#ifdef QB64_WINDOWS
 #include "..\\temp\\userdata.txt"
#else
 #include "../temp/userdata.txt"
#endif
};
unsigned char *data=(unsigned char*)&QBMAIN_data[0];

/*
#include "..\\temp\\userdata.txt"
uint8 *data;
uint32 data_size=0;
int32 data_loaded=0;
*/


#ifdef QB64_WINDOWS
 #include "..\\temp\\regsf.txt"
 #include "..\\temp\\global.txt"
#else
 #include "../temp/regsf.txt"
 #include "../temp/global.txt"
#endif

void sub_clear(long stack,long passed){
static long tmp_long;
//note: stack can be ignored
#ifdef QB64_WINDOWS
 #include "..\\temp\\clear.txt"
#else
 #include "../temp/clear.txt"
#endif
//reset DATA read offset
data_offset=0;
//close open files
sub_close(NULL,NULL);//closes all open files
//free images
freeallimages();
//stop & free sounds (note: QB also stops any sound from the PLAY command)
sndcloseall();
//invalidate RETURN location(s)
next_return_point=0;
//reset error goto location to 'unhandled'
error_goto_line=0;
//invalidate RESUME
error_handling=0;
return;
}

int32 run_from_line=0;
//run_from_line's value is an index in a list of possible "run from" locations
//when 0, the program runs from the beginning

void sub__icon(long i);
void sub__limit(double fps);
void sub__display();
void sub__autodisplay();

void sub__title(qbs *s){
if (new_error) return;
static qbs *sz=NULL; if (!sz) sz=qbs_new(0,0);
static qbs *cz=NULL; if (!cz){cz=qbs_new(1,0); cz->chr[0]=0;}
qbs_set(sz,qbs_add(s,cz));
SDL_WM_SetCaption((const char *)sz->chr,(const char *)sz->chr);
}

void sub__delay(double seconds){
if (new_error) return;
static unsigned long ms;
//range check
if (seconds<0){error(5); return;}
if (seconds>2147483.647){error(5); return;}
ms=seconds*1000.0;
Sleep(ms);
}

int32 func__errorline(){
return ercl;
}

#include "myip.cpp"

void chain_input(){
//note: common data or not, every program must check for chained data,
//      it could be sharing files or screen state

//check if command$ contains a tmp chain directive
long FF;

if ((func_command())->len>= 32 ){
if (qbs_equal(qbs_right(func_command(), 4 ),qbs_new_txt_len(".tmp",4))){
if (qbs_equal(func_mid(func_command(),(func_command())->len- 31 , 25 ,1),qbs_new_txt_len("(unique-tag:=/@*$+-)chain",25))){
FF=func_freefile();
sub_open(func_mid(func_command(),(func_command())->len- 11 , 12 ,1), 2 ,NULL,NULL,FF,NULL,0);

static int32 int32val,int32val2;
static int64 int64val,int64val2;
static int64 bytes,bytei;
static qbs *tqbs;
static int32 tmp_long;

//CHDIR directive
static uint8 chdir_data[4096];
sub_get(FF,NULL,byte_element((uint64)&int32val,4),0);//assume CHDIR directive 512
sub_get(FF,NULL,byte_element((uint64)&int32val,4),0);//assume len
sub_get(FF,NULL,byte_element((uint64)chdir_data,int32val),0);//data
chdir_data[int32val]=0;

chain_restorescreenstate(FF);

//get first command
sub_get(FF,NULL,byte_element((uint64)&int32val,4),0);

//read COMMON data
#ifdef QB64_WINDOWS
 #include "..\\temp\\inpchain.txt"
#else
 #include "../temp/inpchain.txt"
#endif

sub_close(FF,1);

sub_kill(func_mid(func_command(),(func_command())->len- 11 , 12 ,1));

chdir((char*)chdir_data);

//remove chain tag from COMMAND$
func_command_str->len-=32;
//remove trailing space (if any)
if (func_command_str->len) func_command_str->len--;

}
}
}

}

void sub_chain(qbs* f){
if (new_error) return;





//run program
static qbs *str=NULL; if (str==NULL) str=qbs_new(0,0);
static qbs *str2=NULL; if (str2==NULL) str2=qbs_new(0,0);


static long i,i2,x;
static qbs *strz=NULL;
if (!strz) strz=qbs_new(0,0);
static char *cp;

if (!f->len){error(53); return;}//file not found (as in QB)
qbs_set(str,f);
qbs_set(str2,qbs_ucase(str));

static qbs *f_exe=NULL; if (!f_exe) f_exe=qbs_new(0,0);
static qbs *f_bas=NULL; if (!f_bas) f_bas=qbs_new(0,0);//no parameters
static qbs *f_path=NULL; if (!f_path) f_path=qbs_new(0,0);
static int32 path_len;
static qbs *current_path=NULL; if (!current_path) current_path=qbs_new(0,0);
static qbs *thisexe_path=NULL; if (!thisexe_path) thisexe_path=qbs_new(0,0);

//note: supports arguments after filename

f_bas->len=0;
for (i=0;i<str->len;i++){
if (str->chr[i]==46){
//.bas?
if ((i+3)<str->len){
if ((str2->chr[i+1]==66)&&(str2->chr[i+2]==65)&&(str2->chr[i+3]==83)){//"BAS"
qbs_set(f_bas,str); f_bas->len=i+4;//arguments truncated
qbs_set(f_exe,str);//change .bas to .exe
f_exe->chr[i+1]=101; f_exe->chr[i+2]=120; f_exe->chr[i+3]=101;//"exe"
goto extensions_ready;
}//"BAS"
}//bas
//.exe?
if ((i+3)<str->len){
if ((str2->chr[i+1]==69)&&(str2->chr[i+2]==88)&&(str2->chr[i+3]==69)){//"EXE"
qbs_set(f_bas,str); f_bas->len=i+4;//arguments truncated, change .exe to .bas
f_bas->chr[i+1]=98; f_bas->chr[i+2]=97; f_exe->chr[i+3]=115;//"bas"
qbs_set(f_exe,str);//note: exe kept as is
goto extensions_ready;
}//"EXE"
}//exe
break;//no meaningful extension found
}//"."
}

//no extension given!
//note: It is more 'likely' that the user will want to pass arguments than chain a
//      filename containing spaces. Therefore, only everything left of left-most space
//      will be considered the path+filename.
i2=str->len;//last character index of filename
for (i=str->len-1;i;i--){
if (str->chr[i]==32) i2=i;
}
qbs_set(str2,qbs_right(str,str->len-i2));//[+extension]
str->len=i2;//[path+]file
qbs_set(f_exe,qbs_add(qbs_add(str,qbs_new_txt(".exe ")),str2));
qbs_set(f_bas,qbs_add(str,qbs_new_txt(".bas")));

extensions_ready:

//normalize dir slashes
fixdir(f_exe);
fixdir(f_bas);

//get path (strip paths from f_exe & f_bas)
f_path->len=0;
for (i=f_bas->len-1;i>=0;i--){
if ((f_bas->chr[i]==92)||(f_bas->chr[i]==47)||(f_bas->chr[i]==58)){
qbs_set(f_path,f_bas); f_path->len=i+1;
if (f_bas->chr[i]==58){f_path->chr[i+1]=92; f_path->len++;}//add "\" to ":"
//strip paths
memmove(f_exe->chr,&f_exe->chr[i+1],f_exe->len-(i+1)); f_exe->len-=(i+1);
memmove(f_bas->chr,&f_bas->chr[i+1],f_bas->len-(i+1)); f_bas->len-=(i+1);
break;
}
}

static uint8 path_data[4096];
static int32 defaultpath;

defaultpath=0;
if (!f_path->len){//use current path if no path specified
defaultpath=1;
//get current path (add \ if necessary)
i=GetCurrentDirectory(4096,(char*)path_data);
qbs_set(f_path,func_space(i+1));
memcpy(f_path->chr,path_data,i);
if ((f_path->chr[i-1]!=92)&&(f_path->chr[i-1]!=47)){
f_path->chr[i]=92;
}else{
f_path->len--;
}
}

//get current program's exe's path (including "\")
GetModuleFileName(NULL,(char*)path_data,4096);
i=strlen((char*)path_data);
for (i2=i-1;i2>=0;i2--){
x=path_data[i2];
if ((x==92)||(x==47)||(x==58)){
if (x==58) i2++;
i2++;
break;
}
}
qbs_set(thisexe_path,func_space(i2));
memcpy(thisexe_path->chr,path_data,i2);
thisexe_path->chr[i2]=92;//"\"




//1. create & open a temporary file to pass information to the chained program
double TD;
int32 TL,FF;
qbs *TS=NULL; if (TS==NULL) TS=qbs_new(0,0);
qbs *TFS=NULL; if (TFS==NULL) TFS=qbs_new(0,0);
TD=func_timer(0.001E+0,1);
TL=qbr(floor(TD));
TL=qbr((TD-TL)*999);
if (TL<100) TL=100;//ensure value is a 3 digit number
qbs_set(TS,qbs_ltrim(qbs_str((int32)(TL))));
qbs_set(TFS,qbs_add(qbs_add(qbs_new_txt_len("chain",5),TS),qbs_new_txt_len(".tmp",4)));
FF=func_freefile();
sub_open(TFS, 2 ,NULL,NULL,FF,NULL,0); //opened in BINARY mode

//add common data
static int32 int32val,int32val2;
static int64 int64val,int64val2;
static qbs *tqbs;
static int64 bytes,bytei;
static int32 tmp_long;

//CHDIR directive
int32val=512; sub_put(FF,NULL,byte_element((uint64)&int32val,4),0);
int32val=f_path->len-1; sub_put(FF,NULL,byte_element((uint64)&int32val,4),0);
sub_put(FF,NULL,byte_element((uint64)f_path->chr,f_path->len-1),0);//-1 removes trailing "\"

chain_savescreenstate(FF);

#ifdef QB64_WINDOWS
 #include "..\\temp\\chain.txt"
#else
 #include "../temp/chain.txt"
#endif
//add "end of commands" value
int32val=0; sub_put(FF,NULL,byte_element((uint64)&int32val,4),0);

sub_close(FF,1);

//move chain???.tmp file to path
if (!defaultpath){
	qbs_set(str,qbs_new_txt("move /Y "));
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
	qbs_set(str,qbs_add(str,TFS));
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
	qbs_set(str,qbs_add(str,qbs_new_txt(" ")));
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
	qbs_set(str,qbs_add(str,f_path));
	str->len--;//remove trailing "\" of dest path
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
qbs_set(strz,qbs_add(str,qbs_new_txt_len("\0",1)));
WinExec((char *)strz->chr,SW_HIDE);
}

static int32 method;
method=1;

chain_retry:

if (method==1){
qbs_set(str,qbs_add(f_path,f_exe));
}

if (method==2){
//move chain???.tmp file to 'thisexe_path' path
	qbs_set(str,qbs_new_txt("move /Y "));
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
	qbs_set(str,qbs_add(str,f_path));
	qbs_set(str,qbs_add(str,TFS));
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
	qbs_set(str,qbs_add(str,qbs_new_txt(" ")));
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
	qbs_set(str,qbs_add(str,thisexe_path));
	str->len--;//remove trailing "\" of dest path
	qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
qbs_set(strz,qbs_add(str,qbs_new_txt_len("\0",1)));
sub_shell(str,1);
qbs_set(str,qbs_add(thisexe_path,f_exe));
}

if (method==3){
//attempt .bas compilation
qbs_set(str,qbs_new_txt_len("\x022",1));
qbs_set(str,qbs_add(str,thisexe_path));
qbs_set(str,qbs_add(str,qbs_new_txt("qb64.exe")));
qbs_set(str,qbs_add(str,qbs_new_txt_len("\x022",1)));
qbs_set(str,qbs_add(str,qbs_new_txt(" -c ")));
qbs_set(str,qbs_add(str,f_path));
qbs_set(str,qbs_add(str,f_bas));
sub_shell(str,1);
qbs_set(str,qbs_add(thisexe_path,f_exe));
}

//add a space
qbs_set(str,qbs_add(str,qbs_new_txt(" ")));
//add chain tag
qbs_set(str,qbs_add(str,qbs_new_txt_len("(unique-tag:=/@*$+-)",20)));
//add chain file name
qbs_set(str,qbs_add(str,TFS));
//add NULL terminator
qbs_set(strz,qbs_add(str,qbs_new_txt_len("\0",1)));

#ifdef QB64_WINDOWS

if (WinExec((char *)strz->chr,SW_SHOWDEFAULT)>31){
goto run_exit;
}else{
goto run_failed;
}

#else

system((char*)strz->chr);
//success?
goto run_exit;

#endif

//exit this program
run_exit:
close_program=1;
end();
exit(99);//<--this line should never actually be executed

//failed
run_failed:

if (method==1){method=2; goto chain_retry;}
if (method==2){method=3; goto chain_retry;}

qbs_set(str,qbs_add(thisexe_path,TFS));
sub_kill(str); //remove tmp file (chain specific)
error(53); return;//file not found

}

int32 ontimer_nextfree=1;
int32 *ontimer_freelist=(int32*)malloc(32);
uint32 ontimer_freelist_size=8;//number of elements in the freelist
uint32 ontimer_freelist_available=0;//element (if any) which is available)

ontimer_struct *ontimer=(ontimer_struct*)malloc(sizeof(ontimer_struct));
//note: index 0 of the above cannot be allocated/freed

int32 ontimerthread_lock=0;

int32 func__freetimer(){
if (new_error) return 0;
static int32 i;
if (ontimer_freelist_available){
i=ontimer_freelist[ontimer_freelist_available--];
}else{
ontimerthread_lock=1; while(ontimerthread_lock==1) Sleep(0);//mutex
ontimer=(ontimer_struct*)realloc(ontimer,sizeof(ontimer_struct)*(ontimer_nextfree+1));
if (!ontimer) error(257);//out of memory
ontimerthread_lock=0;//mutex
i=ontimer_nextfree;
ontimer[i].state=0;//state is not set to 0 if reusing an existing index as event could still be in progress
}
ontimer[i].active=0;
ontimer[i].id=0;
ontimer[i].allocated=1;
if (i==ontimer_nextfree) ontimer_nextfree++;
return i;
}

void freetimer(int32 i){
ontimer[i].allocated=0;
ontimer[i].id=0;
if (ontimer_freelist_available==ontimer_freelist_size){
ontimer_freelist_size*=2;
ontimer_freelist=(int32*)realloc(ontimer_freelist,ontimer_freelist_size*4);
}
ontimer_freelist[++ontimer_freelist_available]=i;
}

void ontimer_setup(int32 i,double sec,uint32 id,int64 pass){
//note: pass is ignored by ids not requiring a pass value
if (new_error) return;
if ((i<0)||(i>=ontimer_nextfree)){error(5); return;}
if (!ontimer[i].allocated){error(5); return;}
if (ontimer[i].state==1) ontimer[i].state=0;//retract prev event if not in progress
ontimer[i].seconds=sec;
ontimer[i].pass=pass;
ontimer[i].last_time=0;
ontimer[i].id=id;//id must be set last because it is the trigger variable
}

void sub_timer(int32 i,int32 option,int32 passed){
//ref: "[(?)]{ON|OFF|STOP|FREE}"
if (new_error) return;
if (!passed) i=0;
if ((i<0)||(i>=ontimer_nextfree)){error(5); return;}
if (!ontimer[i].allocated){error(5); return;}
//ref: uint8 active;//0=OFF, 1=ON, 2=STOP
if (option==1){//ON
ontimer[i].active=1;
return;
}
if (option==2){//OFF
ontimer[i].active=0;
if (ontimer[i].state==1) ontimer[i].state=0;//retract event if not in progress
ontimer[i].last_time=0;//when ON is next used, event will be triggered immediately
return;
}
if (option==3){//STOP
ontimer[i].active=2;
return;
}
if (option==4){//FREE
if (i==0){error(5); return;}
ontimer[i].active=0;
if (ontimer[i].state==1) ontimer[i].state=0;//retract event if not in progress
freetimer(i);
//note: if an event is still in progress, it will set state to 0 when it finishes
//      which may delay the first instance of this index if it is immediately reused
return;
}
}

int TIMERTHREAD(void *unused){
static int32 i,z=0;
static double time_now=0;
while(1){
quick_lock:
if (ontimerthread_lock==1) ontimerthread_lock=2;//mutex, verify lock
if (!ontimerthread_lock){//mutex
time_now=((double)SDL_GetTicks())*0.001;
for (i=0;i<ontimer_nextfree;i++){
if (ontimer[i].allocated){
if (ontimer[i].id){
if (ontimer[i].active){
if (!ontimer[i].state){
if (time_now-ontimer[i].last_time>ontimer[i].seconds){
//keep measured time for accurate number of calls overall
ontimer[i].last_time+=ontimer[i].seconds;
//if difference between actual time and measured time is beyond 'seconds' set measured to actual
if (fabs(time_now-ontimer[i].last_time)>=ontimer[i].seconds) ontimer[i].last_time=time_now;
ontimer[i].state=1;
qbevent=1;
}//time check
}//state==0
}//active
}//id
}//allocated
if (ontimerthread_lock==1) goto quick_lock;
}//i
z++; if (z==4){Sleep(1); z=0;} else Sleep(0);
}else{//mutex
Sleep(0);
}
}
return NULL;
}

void events(){
int32 i,x;
int64 i64;

//ontimer events
if (!error_handling){//no new on timer calls happen whilst error handling
for (i=0;i<ontimer_nextfree;i++){
if (ontimer[i].allocated){
if (ontimer[i].id){
if (ontimer[i].active==1){//if timer STOPped, event will be postponed
if (ontimer[i].state==1){
ontimer[i].state=2;//event in progress
x=ontimer[i].id;
i64=ontimer[i].pass;
switch(x){

#ifdef QB64_WINDOWS
 #include "..\\temp\\ontimer.txt"
#else
 #include "../temp/ontimer.txt"
#endif
//example.....
//case 1:
//...
//break;

default:
break;
}//switch
ontimer[i].state=0;//event finished
}//state==1
}//active==1
}//id
}//allocated
}//i
}//!error_handling



}

uint32 r;
void evnt(uint32 linenumber){
qbevent=0;
r=0;
while(suspend_program||stop_program){
if (stop_program) end();
Sleep(10);
}
if(new_error){
ercl=linenumber;
fix_error();
if (error_retry){error_retry=0; r=1;}
}else{
events();
}
}

uint8 *redim_preserve_cmem_buffer=(uint8*)malloc(65536);//used for temporary storage only (move to libqbx?)

int QBMAIN(void *unused)
{
long tmp_long;
long tmp_fileno;
qbs* tqbs;
unsigned long qbs_tmp_base=qbs_tmp_list_nexti;

#ifdef QB64_WINDOWS
 #include "..\\temp\\maindata.txt"
 #include "..\\temp\\runline.txt"
 #include "..\\temp\\mainerr.txt"
 if (timer_event_occurred){
 timer_event_occurred--;
 event_return++;
 #include "..\\temp\\ontimerj.txt"
 }
 chain_input();
#include "..\\temp\\main.txt"
#else
 #include "../temp/maindata.txt"
 #include "../temp/runline.txt"
 #include "../temp/mainerr.txt"
 if (timer_event_occurred){
 timer_event_occurred--;
 event_return++;
 #include "../temp/ontimerj.txt"
 }
 chain_input();
 #include "../temp/main.txt"
#endif

//} (closed by main.txt)

