mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-09-09 14:00:17 +00:00
2290 lines
78 KiB
C++
Executable file
2290 lines
78 KiB
C++
Executable file
#include "audio.h"
|
|
#include "common.h"
|
|
#include "compression.h"
|
|
#include "datetime.h"
|
|
#include "event.h"
|
|
#include "extended_math.h"
|
|
#include "filepath.h"
|
|
#include "filesystem.h"
|
|
#include "font.h"
|
|
#include "gui.h"
|
|
#include "image.h"
|
|
#include "rounding.h"
|
|
|
|
extern int32 func__cinp(int32 toggle,
|
|
int32 passed); // Console INP scan code reader
|
|
extern int func__capslock();
|
|
extern int func__scrolllock();
|
|
extern int func__numlock();
|
|
extern void sub__capslock(int32 options);
|
|
extern void sub__scrolllock(int32 options);
|
|
extern void sub__numlock(int32 options);
|
|
extern void sub__consolefont(qbs *FontName, int FontSize);
|
|
extern void sub__console_cursor(int32 visible, int32 cursorsize, int32 passed);
|
|
extern int32 func__getconsoleinput();
|
|
|
|
extern void unlockvWatchHandle();
|
|
extern int32 vWatchHandle();
|
|
|
|
#ifdef QB64_MACOSX
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
#endif
|
|
|
|
/* testing only
|
|
#ifdef QB64_WINDOWS
|
|
|
|
HWND FindMyTopMostWindow()
|
|
{
|
|
DWORD dwProcID = GetCurrentProcessId();
|
|
HWND hWnd = GetTopWindow(GetDesktopWindow());
|
|
while(hWnd)
|
|
{
|
|
DWORD dwWndProcID = 0;
|
|
GetWindowThreadProcessId(hWnd, &dwWndProcID);
|
|
if(dwWndProcID == dwProcID)
|
|
return hWnd;
|
|
hWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void SetMidiVolume(int32 vol){
|
|
//DWORD vol = MAKELONG(((volume*65535L)/100), ((volume*65535L)/100));
|
|
MIDIOUTCAPS midiCaps;
|
|
midiOutGetDevCaps(0, &midiCaps, sizeof(midiCaps));
|
|
if (midiCaps.dwSupport & MIDICAPS_VOLUME)
|
|
midiOutSetVolume(0, vol);
|
|
}
|
|
|
|
#endif
|
|
*/
|
|
|
|
extern int32 sub_gl_called;
|
|
|
|
#ifdef QB64_GUI
|
|
#ifdef DEPENDENCY_GL
|
|
|
|
#include "parts/core/gl_header_for_parsing/temp/gl_helper_code.h"
|
|
|
|
double pi_as_double = 3.14159265358979;
|
|
void gluPerspective(double fovy, double aspect, double zNear, double zFar) {
|
|
double xmin, xmax, ymin, ymax;
|
|
ymax = zNear * std::tan(fovy * pi_as_double / 360.0);
|
|
ymin = -ymax;
|
|
xmin = ymin * aspect;
|
|
xmax = ymax * aspect;
|
|
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
// forward references
|
|
void QBMAIN(void *);
|
|
void TIMERTHREAD(void *);
|
|
|
|
extern int32 requestedKeyboardOverlayImage;
|
|
void requestKeyboardOverlayImage(int32 handle) {
|
|
requestedKeyboardOverlayImage = handle;
|
|
}
|
|
|
|
// extern functions
|
|
|
|
extern int32 func__scaledwidth();
|
|
extern int32 func__scaledheight();
|
|
|
|
extern void sub__fps(double fps, int32 passed);
|
|
|
|
extern void sub__resize(int32 on_off, int32 stretch_smooth);
|
|
extern int32 func__resize();
|
|
extern int32 func__resizewidth();
|
|
extern int32 func__resizeheight();
|
|
|
|
extern void sub__title(qbs *title);
|
|
extern void sub__echo(qbs *message);
|
|
extern void sub__assert(int32 expression, qbs *assert_message, int32 passed);
|
|
extern void sub__finishdrop();
|
|
extern int32 func__filedrop();
|
|
extern void sub__filedrop(int32 on_off = NULL);
|
|
extern int32 func__totaldroppedfiles();
|
|
extern qbs *func__droppedfile(int32 fileIndex, int32 passed);
|
|
|
|
extern void sub__glrender(int32 method);
|
|
extern void sub__displayorder(int32 method1, int32 method2, int32 method3,
|
|
int32 method4);
|
|
|
|
extern int64 GetTicks();
|
|
|
|
extern int32 func__memexists(void *blk);
|
|
extern void sub__memfill(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
ptrszint soff, ptrszint sbytes);
|
|
extern void sub__memfill_nochecks(ptrszint doff, ptrszint dbytes, ptrszint soff,
|
|
ptrszint sbytes);
|
|
extern void sub__memfill_1(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
int8 val);
|
|
extern void sub__memfill_nochecks_1(ptrszint doff, ptrszint dbytes, int8 val);
|
|
extern void sub__memfill_2(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
int16 val);
|
|
extern void sub__memfill_nochecks_2(ptrszint doff, ptrszint dbytes, int16 val);
|
|
extern void sub__memfill_4(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
int32 val);
|
|
extern void sub__memfill_nochecks_4(ptrszint doff, ptrszint dbytes, int32 val);
|
|
extern void sub__memfill_8(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
int64 val);
|
|
extern void sub__memfill_nochecks_8(ptrszint doff, ptrszint dbytes, int64 val);
|
|
extern void sub__memfill_SINGLE(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
float val);
|
|
extern void sub__memfill_nochecks_SINGLE(ptrszint doff, ptrszint dbytes,
|
|
float val);
|
|
extern void sub__memfill_DOUBLE(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
double val);
|
|
extern void sub__memfill_nochecks_DOUBLE(ptrszint doff, ptrszint dbytes,
|
|
double val);
|
|
extern void sub__memfill_FLOAT(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
long double val);
|
|
extern void sub__memfill_nochecks_FLOAT(ptrszint doff, ptrszint dbytes,
|
|
long double val);
|
|
extern void sub__memfill_OFFSET(mem_block *dblk, ptrszint doff, ptrszint dbytes,
|
|
ptrszint val);
|
|
extern void sub__memfill_nochecks_OFFSET(ptrszint doff, ptrszint dbytes,
|
|
ptrszint val);
|
|
extern void *func__memget(mem_block *blk, ptrszint off, ptrszint bytes);
|
|
extern void new_mem_lock();
|
|
extern void free_mem_lock(mem_lock *lock);
|
|
extern mem_block func__mem(ptrszint offset, ptrszint size, int32 type,
|
|
ptrszint elementsize, mem_lock *lock);
|
|
extern mem_block func__mem_at_offset(ptrszint offset, ptrszint size);
|
|
extern void sub__memfree(void *);
|
|
extern void sub__memcopy(void *sblk, ptrszint soff, ptrszint bytes, void *dblk,
|
|
ptrszint doff);
|
|
extern mem_block func__memnew(ptrszint);
|
|
extern mem_block func__memimage(int32, int32);
|
|
|
|
extern int64 func__shellhide(qbs *str);
|
|
extern int64 func_shell(qbs *str);
|
|
extern void sub_shell(qbs *str, int32 passed);
|
|
extern void sub_shell2(qbs *str, int32 passed);
|
|
extern void sub_shell3(qbs *str, int32 passed);
|
|
extern void sub__consoletitle(qbs *);
|
|
extern void sub__screenshow();
|
|
extern void sub__screenhide();
|
|
extern int32 func__screenhide();
|
|
extern int32 func_windowexists();
|
|
extern int32 func_screenicon();
|
|
extern int32 func_screenwidth();
|
|
extern int32 func_screenheight();
|
|
extern void sub_screenicon();
|
|
extern void sub__console(int32);
|
|
extern int32 func__console();
|
|
extern void sub__controlchr(int32);
|
|
extern int32 func__controlchr();
|
|
extern void sub__blink(int32);
|
|
extern int32 func__blink();
|
|
extern int32 func__hasfocus();
|
|
extern void set_foreground_window(ptrszint i);
|
|
extern qbs *func__title();
|
|
extern int32 func__handle();
|
|
extern int32 func_stick(int32 i, int32 axis_group, int32 passed);
|
|
extern int32 func_strig(int32 i, int32 controller, int32 passed);
|
|
extern void sub__maptriangle(int32 cull_options, float sx1, float sy1,
|
|
float sx2, float sy2, float sx3, float sy3,
|
|
int32 si, float dx1, float dy1, float dz1,
|
|
float dx2, float dy2, float dz2, float dx3,
|
|
float dy3, float dz3, int32 di,
|
|
int32 smooth_options, int32 passed);
|
|
extern void sub__depthbuffer(int32 options, int32 dst, int32 passed);
|
|
extern void sub_paletteusing(void *element, int32 bits);
|
|
extern int64 func_read_int64(uint8 *data, ptrszint *data_offset,
|
|
ptrszint data_size);
|
|
extern int64 func_read_uint64(uint8 *data, ptrszint *data_offset,
|
|
ptrszint data_size);
|
|
extern void key_on();
|
|
extern void key_off();
|
|
extern void key_list();
|
|
extern void key_assign(int32 i, qbs *str);
|
|
extern int32 func__screeny();
|
|
extern int32 func__screenx();
|
|
extern void sub__screenmove(int32 x, int32 y, int32 passed);
|
|
extern void sub__mousemove(float x, float y);
|
|
extern qbs *func__os();
|
|
extern void sub__mapunicode(int32 unicode_code, int32 ascii_code);
|
|
extern int32 func__mapunicode(int32 ascii_code);
|
|
extern void field_new(int32 fileno);
|
|
extern void field_add(qbs *str, int64 size);
|
|
extern void field_get(int32 fileno, int64 seekpos, int32 passed);
|
|
extern void field_put(int32 fileno, int64 seekpos, int32 passed);
|
|
extern int32 func__keydown(int32 x);
|
|
extern int32 func__keyhit();
|
|
extern int32 func_lpos(int32);
|
|
extern void sub__printimage(int32 i);
|
|
extern float func__mousemovementx(int32 context, int32 passed);
|
|
extern float func__mousemovementy(int32 context, int32 passed);
|
|
extern void sub__screenprint(qbs *txt);
|
|
extern void sub__screenclick(int32 x, int32 y, int32 button, int32 passed);
|
|
extern int32 func__screenimage(int32 x1, int32 y1, int32 x2, int32 y2,
|
|
int32 passed);
|
|
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, int32 passed);
|
|
extern void sub__allowfullscreen(int32 method, int32 smooth);
|
|
extern int32 func__fullscreen();
|
|
extern int32 func__fullscreensmooth();
|
|
extern void sub__clipboard(qbs *);
|
|
extern qbs *func__clipboard();
|
|
extern int32 func__clipboardimage();
|
|
extern void sub__clipboardimage(int32 src);
|
|
extern int32 func__exit();
|
|
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 int32 func__environcount();
|
|
extern qbs *func_environ(qbs *);
|
|
extern qbs *func_environ(int32);
|
|
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 freeallimages();
|
|
extern void call_interrupt(int32, void *, void *);
|
|
extern void call_interruptx(int32, void *, void *);
|
|
extern void restorepalette(img_struct *im);
|
|
extern void pset(int32 x, int32 y, uint32 col);
|
|
extern uint32 newimg();
|
|
extern int32 freeimg(uint32);
|
|
extern void imgrevert(int32);
|
|
extern int32 imgframe(uint8 *o, int32 x, int32 y, int32 bpp);
|
|
extern int32 imgnew(int32 x, int32 y, int32 bpp);
|
|
extern void sub__putimage(double f_dx1, double f_dy1, double f_dx2,
|
|
double f_dy2, int32 src, int32 dst, double f_sx1,
|
|
double f_sy1, double f_sx2, double f_sy2,
|
|
int32 passed);
|
|
extern int32 selectfont(int32 f, img_struct *im);
|
|
extern uint32 sib();
|
|
extern uint32 sib_mod0();
|
|
extern uint8 *rm8();
|
|
extern uint16 *rm16();
|
|
extern uint32 *rm32();
|
|
extern void cpu_call();
|
|
extern int64 build_int64(uint32 val2, uint32 val1);
|
|
extern uint64 build_uint64(uint32 val2, uint32 val1);
|
|
extern void fix_error();
|
|
extern double get_error_erl();
|
|
extern uint32 get_error_err();
|
|
extern char *human_error(int32 errorcode);
|
|
extern void end();
|
|
extern int32 stop_program_state();
|
|
extern uint8 *mem_static_malloc(uint32 size);
|
|
extern void mem_static_restore(uint8 *restore_point);
|
|
extern uint8 *cmem_dynamic_malloc(uint32 size);
|
|
extern void cmem_dynamic_free(uint8 *block);
|
|
extern void sub_defseg(int32 segment, int32 passed);
|
|
extern int32 func_peek(int32 offset);
|
|
extern void sub_poke(int32 offset, int32 value);
|
|
extern void more_return_points();
|
|
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(uint32 bytesrequired);
|
|
extern void qbs_concat_cmem(uint32 bytesrequired);
|
|
extern qbs *qbs_new_cmem(int32 size, uint8 tmp);
|
|
extern qbs *qbs_new_txt(const char *txt);
|
|
extern qbs *qbs_new_txt_len(const char *txt, int32 len);
|
|
extern qbs *qbs_new_fixed(uint8 *offset, uint32 size, uint8 tmp);
|
|
extern qbs *qbs_new(int32 size, uint8 tmp);
|
|
extern void set_qbs_size(ptrszint *target_qbs, int32 newlength);
|
|
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(int32 value);
|
|
extern qbs *func_varptr_helper(uint8 type, uint16 offset);
|
|
extern qbs *qbs_left(qbs *str, int32 l);
|
|
extern qbs *qbs_right(qbs *str, int32 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(uint32 bsize, int64 v);
|
|
extern qbs *ubit2string(uint32 bsize, uint64 v);
|
|
extern uint64 string2ubit(qbs *str, uint32 bsize);
|
|
extern int64 string2bit(qbs *str, uint32 bsize);
|
|
extern void sub_lset(qbs *dest, qbs *source);
|
|
extern void sub_rset(qbs *dest, qbs *source);
|
|
extern qbs *func_space(int32 spaces);
|
|
extern qbs *func_string(int32 characters, int32 asciivalue);
|
|
extern int32 func_instr(int32 start, qbs *str, qbs *substr, int32 passed);
|
|
extern int32 func__instrrev(int32 start, qbs *str, qbs *substr, int32 passed);
|
|
extern void sub_mid(qbs *dest, int32 start, int32 l, qbs *src, int32 passed);
|
|
extern qbs *func_mid(qbs *str, int32 start, int32 l, int32 passed);
|
|
extern qbs *qbs_ltrim(qbs *str);
|
|
extern qbs *qbs_rtrim(qbs *str);
|
|
extern qbs *qbs__trim(qbs *str);
|
|
extern int32 func__str_nc_compare(qbs *s1, qbs *s2);
|
|
extern int32 func__str_compare(qbs *s1, qbs *s2);
|
|
extern qbs *qbs_inkey();
|
|
extern void sub__keyclear(int32 buf, int32 passed);
|
|
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 int32 qbs_equal(qbs *str1, qbs *str2);
|
|
extern int32 qbs_notequal(qbs *str1, qbs *str2);
|
|
extern int32 qbs_greaterthan(qbs *str1, qbs *str2);
|
|
extern int32 qbs_lessthan(qbs *str1, qbs *str2);
|
|
extern int32 qbs_lessorequal(qbs *str1, qbs *str2);
|
|
extern int32 qbs_greaterorequal(qbs *str1, qbs *str2);
|
|
extern int32 qbs_asc(qbs *);
|
|
extern int32 qbs_asc(qbs *, uint32);
|
|
extern int32 qbs_len(qbs *str);
|
|
extern void lineclip(int32 x1, int32 y1, int32 x2, int32 y2, int32 xmin,
|
|
int32 ymin, int32 xmax, int32 ymax);
|
|
extern void qbg_palette(uint32 attribute, uint32 col, int32 passed);
|
|
extern void qbg_sub_color(uint32 col1, uint32 col2, uint32 bordercolor,
|
|
int32 passed);
|
|
extern void defaultcolors();
|
|
extern void validatepage(int32 n);
|
|
extern void qbg_screen(int32 mode, int32 color_switch, int32 active_page,
|
|
int32 visual_page, int32 refresh, int32 passed);
|
|
extern void sub_pcopy(int32 src, int32 dst);
|
|
extern void qbsub_width(int32 option, int32 value1, int32 value2, int32 value3,
|
|
int32 value4, int32 passed);
|
|
extern void pset(int32 x, int32 y, uint32 col);
|
|
extern void pset_and_clip(int32 x, int32 y, uint32 col);
|
|
extern void qb32_boxfill(float x1f, float y1f, float x2f, float y2f,
|
|
uint32 col);
|
|
extern void fast_boxfill(int32 x1, int32 y1, int32 x2, int32 y2, uint32 col);
|
|
extern void fast_line(int32 x1, int32 y1, int32 x2, int32 y2, uint32 col);
|
|
extern void qb32_line(float x1f, float y1f, float x2f, float y2f, uint32 col,
|
|
uint32 style);
|
|
extern void sub_line(float x1, float y1, float x2, float y2, uint32 col,
|
|
int32 bf, uint32 style, int32 passed);
|
|
extern void sub_paint32(float x, float y, uint32 fillcol, uint32 bordercol,
|
|
int32 passed);
|
|
extern void sub_paint32x(float x, float y, uint32 fillcol, uint32 bordercol,
|
|
int32 passed);
|
|
extern void sub_paint(float x, float y, uint32 fillcol, uint32 bordercol,
|
|
qbs *backgroundstr, int32 passed);
|
|
extern void sub_paint(float x, float y, qbs *fillstr, uint32 bordercol,
|
|
qbs *backgroundstr, int32 passed);
|
|
extern void sub_circle(double x, double y, double r, uint32 col, double start,
|
|
double end, double aspect, int32 passed);
|
|
extern uint32 point(int32 x, int32 y);
|
|
extern double func_point(float x, float y, int32 passed);
|
|
extern void sub_pset(float x, float y, uint32 col, int32 passed);
|
|
extern void sub_preset(float x, float y, uint32 col, int32 passed);
|
|
extern void printchr(int32 character);
|
|
extern int32_t chrwidth(uint32_t character);
|
|
extern void newline();
|
|
extern void makefit(qbs *text);
|
|
extern void lprint_makefit(qbs *text);
|
|
extern void tab();
|
|
extern void qbs_print(qbs *str, int32 finish_on_new_line);
|
|
extern void qbs_lprint(qbs *str, int32 finish_on_new_line);
|
|
extern void qbg_sub_window(float x1, float y1, float x2, float y2,
|
|
int32 passed);
|
|
extern void qbg_sub_view_print(int32 topline, int32 bottomline, int32 passed);
|
|
extern void qbg_sub_view(int32 x1, int32 y1, int32 x2, int32 y2,
|
|
int32 fillcolor, int32 bordercolor, int32 passed);
|
|
extern void sub_clsDest(int32 method, uint32 use_color, int32 dest, int32 passed);
|
|
extern void sub_cls(int32 method, uint32 use_color, int32 passed);
|
|
extern void qbg_sub_locate(int32 row, int32 column, int32 cursor, int32 start,
|
|
int32 stop, int32 passed);
|
|
extern int32 hexoct2uint64(qbs *h);
|
|
extern void qbs_input(int32 numvariables, uint8 newline);
|
|
extern long double func_val(qbs *s);
|
|
extern void sub_out(int32 port, int32 data);
|
|
extern void sub_randomize(double seed, int32 passed);
|
|
extern float func_rnd(float n, int32 passed);
|
|
// 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,int32 type,int32 access,int32 sharing,int32
|
|
// i,int32 record_length,int32 passed);
|
|
extern void sub_open(qbs *name, int32 type, int32 access, int32 sharing,
|
|
int32 i, int64 record_length, int32 passed);
|
|
extern void sub_open_gwbasic(qbs *typestr, int32 i, qbs *name,
|
|
int64 record_length, int32 passed);
|
|
|
|
extern void sub_close(int32 i2, int32 passed);
|
|
extern int32 file_input_chr(int32 i);
|
|
extern void file_input_nextitem(int32 i, int32 lastc);
|
|
extern void sub_file_print(int32 i, qbs *str, int32 extraspace, int32 tab,
|
|
int32 newline);
|
|
extern int32 n_roundincrement();
|
|
extern int32 n_float();
|
|
extern int32 n_int64();
|
|
extern int32 n_uint64();
|
|
extern int32 n_inputnumberfromdata(uint8 *data, ptrszint *data_offset,
|
|
ptrszint data_size);
|
|
extern int32 n_inputnumberfromfile(int32 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(uint8 *data, ptrszint *data_offset,
|
|
ptrszint data_size, qbs *deststr);
|
|
extern long double func_read_float(uint8 *data, ptrszint *data_offset,
|
|
ptrszint data_size, int32 typ);
|
|
extern long double func_file_input_float(int32 fileno, int32 typ);
|
|
extern void *byte_element(uint64 offset, int32 length);
|
|
extern void *byte_element(uint64 offset, int32 length,
|
|
byte_element_struct *info);
|
|
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(float x1f, float y1f, float x2f, float y2f,
|
|
void *element, uint32 mask, int32 passed);
|
|
extern void sub_graphics_put(float x1f, float y1f, void *element, 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 int32 func_csrlin();
|
|
extern int32 func_pos(int32 ignore);
|
|
extern double func_log(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(int32 seconds, int32 passed);
|
|
extern qbs *func__bin(int64 value, int32 neg_bits);
|
|
extern qbs *func__bin_float(long double value);
|
|
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 ptrszint func_lbound(ptrszint *array, int32 index, int32 num_indexes);
|
|
extern ptrszint func_ubound(ptrszint *array, int32 index, int32 num_indexes);
|
|
|
|
extern int32 func_sgn(uint8 v);
|
|
extern int32 func_sgn(int8 v);
|
|
extern int32 func_sgn(uint16 v);
|
|
extern int32 func_sgn(int16 v);
|
|
extern int32 func_sgn(uint32 v);
|
|
extern int32 func_sgn(int32 v);
|
|
extern int32 func_sgn(uint64 v);
|
|
extern int32 func_sgn(int64 v);
|
|
extern int32 func_sgn(float v);
|
|
extern int32 func_sgn(double v);
|
|
extern int32 func_sgn(long double v);
|
|
|
|
extern int32 func_inp(int32 port);
|
|
extern void sub_wait(int32 port, int32 andexpression, int32 xorexpression,
|
|
int32 passed);
|
|
extern qbs *func_tab(int32 pos);
|
|
extern qbs *func_spc(int32 spaces);
|
|
extern float func_pmap(float val, int32 option);
|
|
extern uint32 func_screen(int32 y, int32 x, int32 returncol, int32 passed);
|
|
extern void sub_bsave(qbs *filename, int32 offset, int32 size);
|
|
extern void sub_bload(qbs *filename, int32 offset, int32 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 int32 func__statusCode(int32 handle);
|
|
|
|
extern double func_sqr(double value);
|
|
extern qbs *func_command(int32 index, int32 passed);
|
|
extern int32 func__commandcount();
|
|
extern long double pow2(long double x, long double y);
|
|
extern int32 func_freefile();
|
|
extern void sub__mousehide();
|
|
extern void sub__mouseshow(qbs *style, int32 passed);
|
|
extern float func__mousex(int32 context, int32 passed);
|
|
extern float func__mousey(int32 context, int32 passed);
|
|
extern int32 func__mouseinput(int32 context, int32 passed);
|
|
extern int32 func__mousebutton(int32 i, int32 context, int32 passed);
|
|
extern int32 func__mousewheel(int32 context, int32 passed);
|
|
|
|
extern int32 func__mousepipeopen();
|
|
extern void sub__mouseinputpipe(int32 context);
|
|
extern void sub__mousepipeclose(int32 context);
|
|
|
|
extern void call_absolute(int32 args, uint16 offset);
|
|
extern int32 func__newimage(int32 x, int32 y, int32 bpp, int32 passed);
|
|
extern int32 func__copyimage(int32 i, int32 mode, int32 passed);
|
|
extern void sub__freeimage(int32 i, int32 passed);
|
|
extern void sub__source(int32 i);
|
|
extern void sub__dest(int32 i);
|
|
extern int32 func__source();
|
|
extern int32 func__dest();
|
|
extern int32 func__display();
|
|
extern void sub__blend(int32 i, int32 passed);
|
|
extern void sub__dontblend(int32 i, int32 passed);
|
|
extern void sub__clearcolor(uint32 c, int32 i, int32 passed);
|
|
extern void sub__setalpha(int32 a, uint32 c, uint32 c2, int32 i, int32 passed);
|
|
extern int32 func__width(int32 i, int32 passed);
|
|
extern int32 func__height(int32 i, int32 passed);
|
|
extern int32 func__pixelsize(int32 i, int32 passed);
|
|
extern int32 func__clearcolor(int32 i, int32 passed);
|
|
extern int32 func__blend(int32 i, int32 passed);
|
|
extern uint32 func__defaultcolor(int32 i, int32 passed);
|
|
extern uint32 func__backgroundcolor(int32 i, int32 passed);
|
|
extern uint32 func__palettecolor(int32 n, int32 i, int32 passed);
|
|
extern void sub__palettecolor(int32 n, uint32 c, int32 i, int32 passed);
|
|
extern void sub__copypalette(int32 i, int32 i2, int32 passed);
|
|
extern void sub__printstring(float x, float y, qbs *text, int32 i,
|
|
int32 passed);
|
|
extern int32 func__printwidth(qbs *text, int32 i, int32 passed);
|
|
extern int32_t func__loadfont(qbs *file_name, int32_t size, qbs *requirements, int32_t font_index, int32_t passed);
|
|
extern void sub__font(int32 f, int32 i, int32 passed);
|
|
extern int32 func__fontwidth(int32 f, int32 passed);
|
|
extern int32 func__fontheight(int32 f, int32 passed);
|
|
extern int32 func__font(int32 i, int32 passed);
|
|
extern void sub__freefont(int32 f);
|
|
extern void sub__printmode(int32 mode, int32 i, int32 passed);
|
|
extern int32 func__printmode(int32 i, int32 passed);
|
|
uint32 func__rgb32(int32 r, int32 g, int32 b, int32 a);
|
|
uint32 func__rgb32(int32 r, int32 g, int32 b);
|
|
uint32 func__rgb32(int32 i, int32 a);
|
|
uint32 func__rgb32(int32 i);
|
|
uint32 func__rgba32(int32 r, int32 g, int32 b, int32 a);
|
|
int32 func__alpha32(uint32 col);
|
|
int32 func__red32(uint32 col);
|
|
int32 func__green32(uint32 col);
|
|
int32 func__blue32(uint32 col);
|
|
extern uint32 matchcol(int32 r, int32 g, int32 b);
|
|
extern uint32 matchcol(int32 r, int32 g, int32 b, int32 i);
|
|
extern uint32 func__rgb(int32 r, int32 g, int32 b, int32 i, int32 passed);
|
|
extern uint32 func__rgba(int32 r, int32 g, int32 b, int32 a, int32 i,
|
|
int32 passed);
|
|
extern int32 func__alpha(uint32 col, int32 i, int32 passed);
|
|
extern int32 func__red(uint32 col, int32 i, int32 passed);
|
|
extern int32 func__green(uint32 col, int32 i, int32 passed);
|
|
extern int32 func__blue(uint32 col, int32 i, int32 passed);
|
|
extern void sub_end();
|
|
extern int32 print_using(qbs *f, int32 s2, qbs *dest, qbs *pu_str);
|
|
extern int32 print_using_integer64(qbs *format, int64 value, int32 start,
|
|
qbs *output);
|
|
extern int32 print_using_uinteger64(qbs *format, uint64 value, int32 start,
|
|
qbs *output);
|
|
extern int32 print_using_single(qbs *format, float value, int32 start,
|
|
qbs *output);
|
|
extern int32 print_using_double(qbs *format, double value, int32 start,
|
|
qbs *output);
|
|
extern int32 print_using_float(qbs *format, long double value, int32 start,
|
|
qbs *output);
|
|
extern qbs *b2string(char v);
|
|
extern qbs *ub2string(char v);
|
|
extern qbs *i2string(int16 v);
|
|
extern qbs *ui2string(int16 v);
|
|
extern qbs *l2string(int32 v);
|
|
extern qbs *ul2string(uint32 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 qbs *o2string(ptrszint v);
|
|
extern qbs *uo2string(uptrszint v);
|
|
extern char string2b(qbs *str);
|
|
extern uint8 string2ub(qbs *str);
|
|
extern int16 string2i(qbs *str);
|
|
extern uint16 string2ui(qbs *str);
|
|
extern int32 string2l(qbs *str);
|
|
extern uint32 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);
|
|
extern ptrszint string2o(qbs *str);
|
|
extern uptrszint string2uo(qbs *str);
|
|
// Cobalt(aka Dave) added the next 2 lines
|
|
uint64 func__shr(uint64 a1, int b1);
|
|
uint64 func__shl(uint64 a1, int b1);
|
|
int64 func__readbit(uint64 a1, int b1);
|
|
uint64 func__setbit(uint64 a1, int b1);
|
|
uint64 func__resetbit(uint64 a1, int b1);
|
|
uint64 func__togglebit(uint64 a1, int b1);
|
|
#ifndef QB64_WINDOWS
|
|
extern void ZeroMemory(void *ptr, int64 bytes);
|
|
#endif
|
|
|
|
extern uint64 getubits(uint32 bsize, uint8 *base, ptrszint i);
|
|
extern int64 getbits(uint32 bsize, uint8 *base, ptrszint i);
|
|
extern void setbits(uint32 bsize, uint8 *base, ptrszint i, int64 val);
|
|
|
|
// shared global variables
|
|
extern int32 sleep_break;
|
|
extern uint64 mem_lock_id;
|
|
extern mem_lock *mem_lock_tmp;
|
|
extern int64 exit_code;
|
|
extern int32 lock_mainloop; // 0=unlocked, 1=lock requested, 2=locked
|
|
extern int64 device_event_index;
|
|
extern int32 exit_ok;
|
|
extern qbs *func_command_str;
|
|
int32 timer_event_occurred = 0; // inc/dec as each GOSUB to QBMAIN ()
|
|
// begins/ends
|
|
int32 timer_event_id = 0;
|
|
int32 key_event_occurred = 0; // inc/dec as each GOSUB to QBMAIN () begins/ends
|
|
int32 key_event_id = 0;
|
|
int32 strig_event_occurred = 0; // inc/dec as each GOSUB to QBMAIN ()
|
|
// begins/ends
|
|
int32 strig_event_id = 0;
|
|
uint32 ercl;
|
|
uint32 inclercl;
|
|
char *includedfilename;
|
|
uint16 call_absolute_offsets[256];
|
|
uint32 dbgline;
|
|
uint32 qbs_cmem_sp = 256;
|
|
uint32 cmem_sp = 65536;
|
|
ptrszint dblock; // 32bit offset of dblock
|
|
uint8 close_program = 0;
|
|
int32 tab_spc_cr_size = 1; // 1=PRINT(default), 2=FILE
|
|
int32 tab_fileno = 0; // only valid if tab_spc_cr_size=2
|
|
int32 tab_LPRINT = 0; // 1=dest is LPRINT image
|
|
|
|
uint64 *nothingvalue; // a pointer to 8 empty bytes in dblock
|
|
uint32 error_err = 0;
|
|
double error_erl = 0;
|
|
uint32 qbs_tmp_list_nexti = 1;
|
|
uint32 error_occurred = 0;
|
|
uint32 new_error = 0;
|
|
uint32 bkp_new_error = 0;
|
|
qbs *nothingstring;
|
|
uint32 qbevent = 0;
|
|
uint8 suspend_program = 0;
|
|
uint8 stop_program = 0;
|
|
uint32 error_retry = 0;
|
|
uint8 cmem[1114099]; // 16*65535+65535+3 (enough for highest referencable dword
|
|
// in conv memory)
|
|
uint8 *cmem_static_pointer = &cmem[0] + 1280 + 65536;
|
|
uint8 *cmem_dynamic_base = &cmem[0] + 655360;
|
|
uint8 *mem_static;
|
|
uint8 *mem_static_pointer;
|
|
uint8 *mem_static_limit;
|
|
double last_line = 0;
|
|
uint32 error_goto_line = 0;
|
|
uint32 error_handling = 0;
|
|
uint32 next_return_point = 0;
|
|
uint32 *return_point = (uint32 *)malloc(4 * 16384);
|
|
uint32 return_points = 16384;
|
|
void *qbs_input_variableoffsets[257];
|
|
int32 qbs_input_variabletypes[257];
|
|
|
|
// qbmain specific global variables
|
|
char g_tmp_char;
|
|
uint8 g_tmp_uchar;
|
|
int16 g_tmp_short;
|
|
uint16 g_tmp_ushort;
|
|
int32 g_tmp_long;
|
|
uint32 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_tmp_str;
|
|
qbs *g_swap_str;
|
|
qbs *pass_str;
|
|
ptrszint 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;
|
|
}
|
|
}
|
|
extern ptrszint *qbs_tmp_list;
|
|
template <typename T> static T qbs_cleanup(uint32 base, T passvalue) {
|
|
while (qbs_tmp_list_nexti > base) {
|
|
qbs_tmp_list_nexti--;
|
|
if (qbs_tmp_list[qbs_tmp_list_nexti] != -1)
|
|
qbs_free((qbs *)qbs_tmp_list[qbs_tmp_list_nexti]);
|
|
} // clear any temp. strings created
|
|
return passvalue;
|
|
}
|
|
|
|
|
|
// force abs to return floating point numbers correctly
|
|
inline double func_abs(double d) { return std::fabs(d); }
|
|
inline long double func_abs(long double d) { return std::fabs(d); }
|
|
inline float func_abs(float d) { return std::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 std::abs(d); }
|
|
inline int16 func_abs(int16 d) { return std::abs(d); }
|
|
inline int32 func_abs(int32 d) { return std::abs(d); }
|
|
inline int64 func_abs(int64 d) { return std::llabs(d); }
|
|
|
|
extern int32 disableEvents;
|
|
|
|
ptrszint check_lbound(ptrszint *array, int32 index, int32 num_indexes) {
|
|
static ptrszint ret;
|
|
disableEvents = 1;
|
|
ret = func_lbound((ptrszint *)(*array), index, num_indexes);
|
|
new_error = 0;
|
|
disableEvents = 0;
|
|
return ret;
|
|
}
|
|
|
|
ptrszint check_ubound(ptrszint *array, int32 index, int32 num_indexes) {
|
|
static ptrszint ret;
|
|
disableEvents = 1;
|
|
ret = func_ubound((ptrszint *)(*array), index, num_indexes);
|
|
new_error = 0;
|
|
disableEvents = 0;
|
|
return ret;
|
|
}
|
|
|
|
uint64 call_getubits(uint32 bsize, ptrszint *array, ptrszint i) {
|
|
return getubits(bsize, (uint8 *)(*array), i);
|
|
}
|
|
|
|
int64 call_getbits(uint32 bsize, ptrszint *array, ptrszint i) {
|
|
return getbits(bsize, (uint8 *)(*array), i);
|
|
}
|
|
|
|
void call_setbits(uint32 bsize, ptrszint *array, ptrszint i, int64 val) {
|
|
setbits(bsize, (uint8 *)(*array), i, val);
|
|
}
|
|
|
|
int32 logical_drives() {
|
|
#ifdef QB64_WINDOWS
|
|
return GetLogicalDrives();
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
inline ptrszint array_check(uptrszint index, uptrszint limit) {
|
|
// nb. forces signed index into an unsigned variable for quicker comparison
|
|
if (index < limit)
|
|
return index;
|
|
error(9);
|
|
return 0;
|
|
}
|
|
|
|
inline int32 func_sgn(uint8 v) {
|
|
if (v)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(int8 v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(uint16 v) {
|
|
if (v)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(int16 v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(uint32 v) {
|
|
if (v)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(int32 v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(uint64 v) {
|
|
if (v)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(int64 v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(float v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(double v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
inline int32 func_sgn(long double v) {
|
|
if (v)
|
|
if (v > 0)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
// a740g: ROR & ROL additions start
|
|
// The rotation functions below are the way they are for a couple of reasons:
|
|
// 1. They are safer (well folks seem to think so; see https://en.wikipedia.org/wiki/Circular_shift#Implementing_circular_shifts)
|
|
// 2. We are using C library constants and there is just 1 numeric literal - '1'
|
|
// 3. GGC recognizes the 'pattern' and will optimize it out to 'roX' and 3 more instructions when using O2
|
|
inline uint8_t func__rol8(uint8_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value << count) | (value >> (-count & mask));
|
|
}
|
|
|
|
inline uint8_t func__ror8(uint8_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value >> count) | (value << (-count & mask));
|
|
}
|
|
|
|
inline uint16_t func__rol16(uint16_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value << count) | (value >> (-count & mask));
|
|
}
|
|
|
|
inline uint16_t func__ror16(uint16_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value >> count) | (value << (-count & mask));
|
|
}
|
|
|
|
inline uint32_t func__rol32(uint32_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value << count) | (value >> (-count & mask));
|
|
}
|
|
|
|
inline uint32_t func__ror32(uint32_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value >> count) | (value << (-count & mask));
|
|
}
|
|
|
|
inline uint64_t func__rol64(uint64_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value << count) | (value >> (-count & mask));
|
|
}
|
|
|
|
inline uint64_t func__ror64(uint64_t value, unsigned int count) {
|
|
const unsigned int mask = CHAR_BIT * sizeof(value) - 1;
|
|
count &= mask;
|
|
return (value >> count) | (value << (-count & mask));
|
|
}
|
|
// a740g: ROR & ROL additions end
|
|
|
|
// bit-shifting
|
|
inline uint64 func__shl(uint64 a1, int b1) { return a1 << b1; }
|
|
|
|
inline uint64 func__shr(uint64 a1, int b1) { return a1 >> b1; }
|
|
|
|
inline int64 func__readbit(uint64 a1, int b1) {
|
|
if (a1 & 1ull << b1)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
inline uint64 func__setbit(uint64 a1, int b1) { return a1 | 1ull << b1; }
|
|
|
|
inline uint64 func__resetbit(uint64 a1, int b1) { return a1 & ~(1ull << b1); }
|
|
|
|
inline uint64 func__togglebit(uint64 a1, int b1) { return a1 ^ 1ull << b1; }
|
|
|
|
// Working with 32bit colors:
|
|
inline uint32 func__rgb32(int32 r, int32 g, int32 b, int32 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 uint32 func__rgb32(int32 r, int32 g, int32 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 uint32 func__rgb32(int32 i, int32 a) {
|
|
if (i < 0)
|
|
i = 0;
|
|
if (i > 255)
|
|
i = 255;
|
|
if (a < 0)
|
|
a = 0;
|
|
if (a > 255)
|
|
a = 255;
|
|
return (a << 24) + (i << 16) + (i << 8) + i;
|
|
}
|
|
|
|
inline uint32 func__rgb32(int32 i) {
|
|
if (i < 0)
|
|
i = 0;
|
|
if (i > 255)
|
|
i = 255;
|
|
return (i << 16) + (i << 8) + i | 0xFF000000;
|
|
}
|
|
|
|
inline uint32 func__rgba32(int32 r, int32 g, int32 b, int32 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 int32 func__alpha32(uint32 col) { return col >> 24; }
|
|
inline int32 func__red32(uint32 col) { return col >> 16 & 0xFF; }
|
|
inline int32 func__green32(uint32 col) { return col >> 8 & 0xFF; }
|
|
inline int32 func__blue32(uint32 col) { return col & 0xFF; }
|
|
|
|
inline uint16 varptr_dblock_check(uint8 *off) {
|
|
// note: 66816 is the top of DBLOCK (SEG:80+OFF:65536)
|
|
if (off < (&cmem[66816])) { // in DBLOCK?
|
|
return ((uint16)(off - &cmem[1280]));
|
|
} else {
|
|
return ((uint32)(off - cmem)) & 15;
|
|
}
|
|
}
|
|
|
|
inline uint16 varseg_dblock_check(uint8 *off) {
|
|
// note: 66816 is the top of DBLOCK (SEG:80+OFF:65536)
|
|
if (off < (&cmem[66816])) { // in DBLOCK?
|
|
return 80;
|
|
} else {
|
|
return ((uint32)(off - cmem)) / 16;
|
|
}
|
|
}
|
|
|
|
#include "../temp/global.txt"
|
|
#include "../temp/regsf.txt"
|
|
|
|
extern int32 ScreenResize;
|
|
extern int32 ScreenResizeScale;
|
|
|
|
// set_dynamic_info is called immediately when
|
|
// main() begins, to set global, static variables
|
|
// controlling app init
|
|
void set_dynamic_info() {
|
|
#include "../temp/dyninfo.txt"
|
|
}
|
|
|
|
void sub_clear(int32 ignore, int32 ignore2, int32 stack, int32 passed) {
|
|
static ptrszint tmp_long;
|
|
// note: stack can be ignored
|
|
#include "../temp/clear.txt"
|
|
// 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)
|
|
// 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(int32 i, int32 i2, int32 passed);
|
|
|
|
void sub__display();
|
|
void sub__autodisplay();
|
|
int32 func__autodisplay();
|
|
|
|
int32 func__errorline() { return ercl; }
|
|
|
|
int32 func__inclerrorline() { return inclercl; }
|
|
|
|
qbs *func__inclerrorfile() { return qbs_new_txt(includedfilename); }
|
|
|
|
qbs *func__errormessage(int32 errorcode, int32 passed) {
|
|
if (!passed)
|
|
errorcode = get_error_err();
|
|
return qbs_new_txt(human_error(errorcode));
|
|
}
|
|
|
|
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
|
|
int32 FF;
|
|
|
|
if ((func_command(0, 0))->len >= 32) {
|
|
if (qbs_equal(qbs_right(func_command(0, 0), 4),
|
|
qbs_new_txt_len(".tmp", 4))) {
|
|
if (qbs_equal(func_mid(func_command(0, 0),
|
|
(func_command(0, 0))->len - 31, 25, 1),
|
|
qbs_new_txt_len("(unique-tag:=/@*$+-)chain", 25))) {
|
|
FF = func_freefile();
|
|
sub_open(func_mid(func_command(0, 0),
|
|
(func_command(0, 0))->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 ptrszint 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
|
|
#include "../temp/inpchain.txt"
|
|
|
|
sub_close(FF, 1);
|
|
|
|
sub_kill(func_mid(func_command(0, 0),
|
|
(func_command(0, 0))->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;
|
|
|
|
#ifdef QB64_WINDOWS
|
|
|
|
// 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 int32 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
|
|
filepath_fix_directory(f_exe);
|
|
filepath_fix_directory(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(std::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 ptrszint 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);
|
|
|
|
#include "../temp/chain.txt"
|
|
// 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("qb64pe.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
|
|
|
|
#endif
|
|
}
|
|
|
|
// note: index 0 is unused
|
|
int32 device_last = 0; // last used device
|
|
int32 device_max = 1000; // number of allocated indexes
|
|
device_struct *devices =
|
|
(device_struct *)calloc(1000 + 1, sizeof(device_struct));
|
|
|
|
// device_struct helper functions
|
|
uint8 getDeviceEventButtonValue(device_struct *device, int32 eventIndex,
|
|
int32 objectIndex) {
|
|
return *(device->events + eventIndex * device->event_size +
|
|
device->lastaxis * 4 + device->lastwheel * 4 + objectIndex);
|
|
}
|
|
void setDeviceEventButtonValue(device_struct *device, int32 eventIndex,
|
|
int32 objectIndex, uint8 value) {
|
|
*(device->events + eventIndex * device->event_size + device->lastaxis * 4 +
|
|
device->lastwheel * 4 + objectIndex) = value;
|
|
}
|
|
float getDeviceEventAxisValue(device_struct *device, int32 eventIndex,
|
|
int32 objectIndex) {
|
|
return *(float *)(device->events + eventIndex * device->event_size +
|
|
objectIndex * 4);
|
|
}
|
|
void setDeviceEventAxisValue(device_struct *device, int32 eventIndex,
|
|
int32 objectIndex, float value) {
|
|
*(float *)(device->events + eventIndex * device->event_size +
|
|
objectIndex * 4) = value;
|
|
}
|
|
float getDeviceEventWheelValue(device_struct *device, int32 eventIndex,
|
|
int32 objectIndex) {
|
|
return *(float *)(device->events + eventIndex * device->event_size +
|
|
device->lastaxis * 4 + objectIndex * 4);
|
|
}
|
|
void setDeviceEventWheelValue(device_struct *device, int32 eventIndex,
|
|
int32 objectIndex, float value) {
|
|
*(float *)(device->events + eventIndex * device->event_size +
|
|
device->lastaxis * 4 + objectIndex * 4) = value;
|
|
}
|
|
void setupDevice(device_struct *device) {
|
|
int32 size =
|
|
device->lastaxis * 4 + device->lastwheel * 4 + device->lastbutton;
|
|
size += 8; // for appended ordering index
|
|
size += 7;
|
|
size = size - (size & 7); // align to closest 8-byte boundary
|
|
device->event_size = size;
|
|
device->events = (uint8 *)calloc(
|
|
2,
|
|
device->event_size); // create initial 'current' and 'previous' events
|
|
device->max_events = 2;
|
|
device->queued_events = 2;
|
|
device->connected = 1;
|
|
device->used = 1;
|
|
}
|
|
int32 createDeviceEvent(device_struct *device) {
|
|
uint8 *cp, *cp2;
|
|
if (device->queued_events ==
|
|
device->max_events) { // expand/shift event buffer
|
|
if (device->max_events >= QUEUED_EVENTS_LIMIT) {
|
|
// discard base message
|
|
memmove(device->events, device->events + device->event_size,
|
|
(device->queued_events - 1) * device->event_size);
|
|
device->queued_events--;
|
|
} else {
|
|
cp = (uint8 *)calloc(device->max_events * 2,
|
|
device->event_size); // create new buffer
|
|
memcpy(cp, device->events,
|
|
device->queued_events *
|
|
device->event_size); // copy events from old buffer into
|
|
// new buffer
|
|
cp2 = device->events;
|
|
device->events = cp;
|
|
device->max_events *= 2;
|
|
free(cp2);
|
|
}
|
|
}
|
|
// copy previous event data into new event
|
|
memmove(device->events + device->queued_events * device->event_size,
|
|
device->events + (device->queued_events - 1) * device->event_size,
|
|
device->event_size);
|
|
*(int64 *)(device->events + (device->queued_events * device->event_size) +
|
|
(device->event_size - 8)) =
|
|
device_event_index++; // set global event index
|
|
int32 eventIndex = device->queued_events;
|
|
return eventIndex;
|
|
}
|
|
void commitDeviceEvent(device_struct *device) { device->queued_events++; }
|
|
|
|
int32 func__devices() { return device_last; }
|
|
|
|
int32 device_selected = 0;
|
|
|
|
qbs *func__device(int32 i, int32 passed) {
|
|
if (!passed)
|
|
i = device_selected;
|
|
if (i < 1 || i > device_last) {
|
|
error(5);
|
|
return qbs_new(0, 1);
|
|
}
|
|
return qbs_new_txt(devices[i].name);
|
|
}
|
|
|
|
int32 func__deviceinput(int32 i, int32 passed) {
|
|
static device_struct *d;
|
|
static int32 retval;
|
|
retval = -1;
|
|
device_selected = -1;
|
|
|
|
if (!passed) {
|
|
// find oldest event across all devices
|
|
static int32 i2;
|
|
static int64 index, lowest_index;
|
|
i2 = -1;
|
|
for (i = 1; i <= device_last; i++) {
|
|
d = &devices[i];
|
|
if (d->queued_events > 2) {
|
|
index = *(int64 *)((d->events + d->event_size * 2) +
|
|
(d->event_size - 8));
|
|
if ((i2 == -1) || (index < lowest_index)) {
|
|
i2 = i;
|
|
lowest_index = index;
|
|
retval = i2;
|
|
} // first/lower
|
|
} // queued_events>2
|
|
} // i
|
|
if (i2 != -1)
|
|
i = i2;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
if (i < 1 || i > device_last)
|
|
error(5);
|
|
d = &devices[i];
|
|
|
|
device_selected = i;
|
|
|
|
if (d->queued_events > 2) {
|
|
memmove(d->events, ((uint8 *)d->events) + d->event_size,
|
|
(d->queued_events - 1) * d->event_size);
|
|
d->queued_events--;
|
|
return retval;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32 func__button(int32 i, int32 passed) {
|
|
if (device_selected < 1 || device_selected > device_last) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
static device_struct *d;
|
|
d = &devices[device_selected];
|
|
if (!passed)
|
|
i = 1;
|
|
if (i < 1 || i > d->lastbutton) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
if (getDeviceEventButtonValue(d, 1, i - 1))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int32 func__buttonchange(int32 i, int32 passed) {
|
|
if (device_selected < 1 || device_selected > device_last) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
static device_struct *d;
|
|
d = &devices[device_selected];
|
|
if (!passed)
|
|
i = 1;
|
|
if (i < 1 || i > d->lastbutton) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
static int32 old_value, value;
|
|
value = getDeviceEventButtonValue(d, 1, i - 1);
|
|
old_value = getDeviceEventButtonValue(d, 0, i - 1);
|
|
if (value > old_value)
|
|
return -1;
|
|
if (value < old_value)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
float func__axis(int32 i, int32 passed) {
|
|
if (device_selected < 1 || device_selected > device_last) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
static device_struct *d;
|
|
d = &devices[device_selected];
|
|
if (!passed)
|
|
i = 1;
|
|
if (i < 1 || i > d->lastaxis) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
return getDeviceEventAxisValue(d, 1, i - 1);
|
|
}
|
|
|
|
float func__wheel(int32 i, int32 passed) {
|
|
if (device_selected < 1 || device_selected > device_last) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
static device_struct *d;
|
|
d = &devices[device_selected];
|
|
if (!passed)
|
|
i = 1;
|
|
if (i < 1 || i > d->lastwheel) {
|
|
error(5);
|
|
return 0;
|
|
}
|
|
return getDeviceEventWheelValue(d, 1, i - 1);
|
|
}
|
|
|
|
int32 func__lastbutton(int32 di, int32 passed) {
|
|
if (!passed)
|
|
di = device_selected;
|
|
if (di < 1 || di > device_last)
|
|
error(5);
|
|
static device_struct *d;
|
|
d = &devices[di];
|
|
return d->lastbutton;
|
|
}
|
|
|
|
int32 func__lastaxis(int32 di, int32 passed) {
|
|
if (!passed)
|
|
di = device_selected;
|
|
if (di < 1 || di > device_last)
|
|
error(5);
|
|
static device_struct *d;
|
|
d = &devices[di];
|
|
return d->lastaxis;
|
|
}
|
|
|
|
int32 func__lastwheel(int32 di, int32 passed) {
|
|
if (!passed)
|
|
di = device_selected;
|
|
if (di < 1 || di > device_last)
|
|
error(5);
|
|
static device_struct *d;
|
|
d = &devices[di];
|
|
return d->lastwheel;
|
|
}
|
|
|
|
onstrig_struct *onstrig = (onstrig_struct *)calloc(
|
|
65536, sizeof(onstrig_struct)); // note: up to 256 controllers with up to
|
|
// 256 buttons each supported
|
|
int32 onstrig_inprogress = 0;
|
|
|
|
void onstrig_setup(int32 i, int32 controller, int32 controller_passed,
|
|
uint32 id, int64 pass) {
|
|
// note: pass is ignored by ids not requiring a pass value
|
|
if (new_error)
|
|
return;
|
|
if (i < 0 || i > 65535) {
|
|
error(5);
|
|
return;
|
|
}
|
|
if (controller_passed) {
|
|
if (controller < 1 || controller > 65535) {
|
|
error(5);
|
|
return;
|
|
}
|
|
} else {
|
|
controller = 1;
|
|
if (i & 2) {
|
|
controller = 2;
|
|
i -= 2;
|
|
}
|
|
}
|
|
static int32 button;
|
|
button = (i >> 2) + 1;
|
|
if (i & 1) {
|
|
error(5);
|
|
return;
|
|
} //'currently down' state cannot be used as an ON STRIG event
|
|
if (controller > 256 || button > 256)
|
|
return; // error-less exit for (currently) unsupported ranges
|
|
i = (controller - 1) * 256 + (button - 1); // reindex
|
|
onstrig[i].state = 0;
|
|
onstrig[i].pass = pass;
|
|
onstrig[i].id = id; // id must be set last because it is the trigger
|
|
// variable
|
|
if (device_last == 0)
|
|
func__devices(); // init device interface (if not already setup)
|
|
}
|
|
|
|
void sub_strig(int32 i, int32 controller, int32 option, int32 passed) {
|
|
// ref: "[(?[,?])]{ON|OFF|STOP}"
|
|
if (new_error)
|
|
return;
|
|
// Note: QuickBASIC ignores STRIG ON and STRIG OFF statements--the
|
|
// statements are provided for compatibility with earlier versions,
|
|
// Reference: http://www.antonis.de/qbebooks/gwbasman/strig.html
|
|
// QB64 makes STRIG ON/OFF/STOP change the checking status for all
|
|
// buttons
|
|
static int32 i1, i2;
|
|
if (passed > 0) {
|
|
if (i < 0 || i > 65535) {
|
|
error(5);
|
|
return;
|
|
}
|
|
if (passed & 2) {
|
|
if (controller < 1 || controller > 65535) {
|
|
error(5);
|
|
return;
|
|
}
|
|
} else {
|
|
controller = 1;
|
|
if (i & 2) {
|
|
controller = 2;
|
|
i -= 2;
|
|
}
|
|
}
|
|
static int32 button;
|
|
button = (i >> 2) + 1;
|
|
if (i & 1) {
|
|
error(5);
|
|
return;
|
|
} //'currently down' state cannot be used as an ON STRIG event
|
|
if (controller > 256 || button > 256)
|
|
return; // error-less exit for (currently) unsupported ranges
|
|
i = (controller - 1) * 256 + (button - 1); // reindex
|
|
i1 = i;
|
|
i2 = i;
|
|
} else {
|
|
i1 = 0;
|
|
i2 = 65535;
|
|
}
|
|
for (i = i1; i <= i2; i++) {
|
|
// ref: uint8 active;//0=OFF, 1=ON, 2=STOP
|
|
if (option == 1) { // ON
|
|
onstrig[i].active = 1;
|
|
if (onstrig[i].state)
|
|
qbevent = 1;
|
|
}
|
|
if (option == 2) { // OFF
|
|
onstrig[i].active = 0;
|
|
onstrig[i].state = 0;
|
|
}
|
|
if (option == 3) { // STOP
|
|
onstrig[i].active = 2;
|
|
if (onstrig[i].state)
|
|
onstrig[i].state = 1;
|
|
}
|
|
} // i
|
|
}
|
|
|
|
onkey_struct *onkey = (onkey_struct *)calloc(32, sizeof(onkey_struct));
|
|
int32 onkey_inprogress = 0;
|
|
|
|
void onkey_setup(int32 i, uint32 id, int64 pass) {
|
|
// note: pass is ignored by ids not requiring a pass value
|
|
if (new_error)
|
|
return;
|
|
if ((i < 1) || (i > 31)) {
|
|
error(5);
|
|
return;
|
|
}
|
|
onkey[i].state = 0;
|
|
onkey[i].pass = pass;
|
|
onkey[i].id = id; // id must be set last because it is the trigger variable
|
|
}
|
|
|
|
void sub_key(int32 i, int32 option) {
|
|
// ref: "(?){ON|OFF|STOP}"
|
|
if (new_error)
|
|
return;
|
|
if ((i < 0) || (i > 31)) {
|
|
error(5);
|
|
return;
|
|
}
|
|
static int32 i1, i2;
|
|
i1 = i;
|
|
i2 = i;
|
|
if (!i) {
|
|
i1 = i;
|
|
i2 = 31;
|
|
} // set all keys!
|
|
for (i = i1; i <= i2; i++) {
|
|
// ref: uint8 active;//0=OFF, 1=ON, 2=STOP
|
|
if (option == 1) { // ON
|
|
onkey[i].active = 1;
|
|
if (onkey[i].state)
|
|
qbevent = 1;
|
|
}
|
|
if (option == 2) { // OFF
|
|
onkey[i].active = 0;
|
|
onkey[i].state = 0;
|
|
}
|
|
if (option == 3) { // STOP
|
|
onkey[i].active = 2;
|
|
if (onkey[i].state)
|
|
onkey[i].state = 1;
|
|
}
|
|
} // i
|
|
}
|
|
|
|
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;
|
|
|
|
void stop_timers() {
|
|
ontimerthread_lock = 1;
|
|
while (ontimerthread_lock != 2)
|
|
;
|
|
}
|
|
|
|
void start_timers() { 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;
|
|
|
|
// This is necessary so that if a timer triggered while stopped we will run it now.
|
|
qbevent = 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, the timer will start over
|
|
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;
|
|
}
|
|
}
|
|
|
|
void TIMERTHREAD(void *unused) {
|
|
static int32 i;
|
|
static double time_now = 100000;
|
|
while (1) {
|
|
quick_lock:
|
|
if (ontimerthread_lock == 1)
|
|
ontimerthread_lock = 2; // mutex, verify lock
|
|
if (!ontimerthread_lock) { // mutex
|
|
time_now = ((double)GetTicks()) * 0.001;
|
|
for (i = 0; i < ontimer_nextfree; i++) {
|
|
if (ontimer[i].allocated && ontimer[i].id && ontimer[i].active && !ontimer[i].state) {
|
|
if (!ontimer[i].last_time) {
|
|
ontimer[i].last_time = time_now;
|
|
} else 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 (std::fabs(time_now -
|
|
ontimer[i].last_time) >=
|
|
ontimer[i].seconds)
|
|
ontimer[i].last_time = time_now;
|
|
ontimer[i].state = 1;
|
|
qbevent = 1;
|
|
} // time check
|
|
}
|
|
if (ontimerthread_lock == 1)
|
|
goto quick_lock;
|
|
} // i
|
|
} // not locked
|
|
Sleep(1);
|
|
if (stop_program) {
|
|
exit_ok |= 2;
|
|
return;
|
|
} // close thread #2
|
|
} // while(1)
|
|
return;
|
|
}
|
|
|
|
void events() {
|
|
int32 i, x, d, di;
|
|
int64 i64;
|
|
|
|
// onstrig events
|
|
onstrig_recheck:
|
|
if (!error_handling) { // no new calls happen whilst error handling
|
|
di = 0;
|
|
for (d = 1; d <= device_last; d++) {
|
|
if (devices[d].type == 1) {
|
|
if (di <= 255) {
|
|
for (i = 0; i <= 255; i++) {
|
|
if (onstrig[(di << 8) + i].id) {
|
|
if (onstrig[(di << 8) + i].active ==
|
|
1) { // if STOPped, event will be postponed
|
|
if (onstrig[(di << 8) + i].state) {
|
|
if (!onstrig_inprogress) {
|
|
onstrig_inprogress = 1;
|
|
onstrig[(di << 8) + i].state--;
|
|
x = onstrig[(di << 8) + i].id;
|
|
i64 = onstrig[(di << 8) + i].pass;
|
|
switch (x) {
|
|
#include "../temp/onstrig.txt"
|
|
// example.....
|
|
// case 1:
|
|
//...
|
|
// break;
|
|
default:
|
|
break;
|
|
} // switch
|
|
onstrig_inprogress = 0;
|
|
goto onstrig_recheck;
|
|
} //! inprogress
|
|
} // state
|
|
} // active==1
|
|
} // id
|
|
} // i
|
|
} // di<=255
|
|
di++;
|
|
} // type==1
|
|
} // d
|
|
} //! error_handling
|
|
|
|
// onkey events
|
|
onkey_recheck:
|
|
if (!error_handling) { // no new calls happen whilst error handling
|
|
for (i = 1; i <= 31; i++) {
|
|
if (onkey[i].id) {
|
|
if (onkey[i].active ==
|
|
1) { // if STOPped, event will be postponed
|
|
if (onkey[i].state) {
|
|
if (!onkey_inprogress) {
|
|
onkey_inprogress = 1;
|
|
onkey[i].state--;
|
|
x = onkey[i].id;
|
|
i64 = onkey[i].pass;
|
|
switch (x) {
|
|
#include "../temp/onkey.txt"
|
|
// example.....
|
|
// case 1:
|
|
//...
|
|
// break;
|
|
default:
|
|
break;
|
|
} // switch
|
|
onkey_inprogress = 0;
|
|
goto onkey_recheck;
|
|
} //! inprogress
|
|
} // state
|
|
} // active==1
|
|
} // id
|
|
} // i
|
|
} //! error_handling
|
|
|
|
// 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) {
|
|
#include "../temp/ontimer.txt"
|
|
// example.....
|
|
// case 1:
|
|
//...
|
|
// break;
|
|
default:
|
|
break;
|
|
} // switch
|
|
ontimer[i].state = 0; // event finished
|
|
sleep_break = 1;
|
|
} // state==1
|
|
} // active==1
|
|
} // id
|
|
} // allocated
|
|
} // i
|
|
} //! error_handling
|
|
}
|
|
|
|
extern int64 display_lock_request;
|
|
extern int64 display_lock_confirmed;
|
|
extern int64 display_lock_released;
|
|
|
|
uint32 r;
|
|
void evnt(uint32 linenumber, uint32 inclinenumber, const char *incfilename) {
|
|
if (disableEvents)
|
|
return;
|
|
|
|
qbevent = 0;
|
|
|
|
if (sub_gl_called == 0) {
|
|
if (display_lock_request > display_lock_confirmed) {
|
|
display_lock_confirmed = display_lock_request;
|
|
while ((display_lock_released < display_lock_confirmed) &&
|
|
(!close_program) && (!suspend_program) && (!stop_program))
|
|
Sleep(1);
|
|
}
|
|
}
|
|
|
|
r = 0;
|
|
|
|
while (suspend_program || stop_program) {
|
|
if (stop_program)
|
|
end();
|
|
Sleep(10);
|
|
}
|
|
|
|
if (new_error) {
|
|
ercl = linenumber;
|
|
inclercl = inclinenumber;
|
|
includedfilename = (char *)incfilename;
|
|
fix_error();
|
|
if (error_retry) {
|
|
error_retry = 0;
|
|
r = 1;
|
|
}
|
|
} else {
|
|
if (sub_gl_called == 0)
|
|
events();
|
|
}
|
|
}
|
|
|
|
uint8 *redim_preserve_cmem_buffer =
|
|
(uint8 *)malloc(65536); // used for temporary storage only (move to libqbx?)
|
|
|
|
#include "myip.cpp"
|
|
|
|
void division_by_zero_handler(int ignore) { error(11); }
|
|
|
|
// void SIGSEGV_handler(int ignore){
|
|
// error(256);//assume stack overflow? (the most likely cause)
|
|
//}
|
|
|
|
void QBMAIN(void *unused) {
|
|
fpu_reinit();
|
|
#ifdef QB64_WINDOWS
|
|
signal(SIGFPE, division_by_zero_handler);
|
|
// signal(SIGSEGV, SIGSEGV_handler);
|
|
#else
|
|
struct sigaction sig_act;
|
|
sig_act.sa_handler = division_by_zero_handler;
|
|
sigemptyset(&(sig_act.sa_mask));
|
|
sig_act.sa_flags = 0;
|
|
sigaction(SIGFPE, &sig_act, NULL);
|
|
#endif
|
|
|
|
ptrszint tmp_long;
|
|
int32 tmp_fileno;
|
|
qbs *tqbs;
|
|
uint32 qbs_tmp_base = qbs_tmp_list_nexti;
|
|
static mem_lock *sf_mem_lock = NULL;
|
|
if (!sf_mem_lock) {
|
|
new_mem_lock();
|
|
sf_mem_lock = mem_lock_tmp;
|
|
sf_mem_lock->type = 3;
|
|
}
|
|
|
|
#include "../temp/maindata.txt"
|
|
#include "../temp/mainerr.txt"
|
|
#include "../temp/runline.txt"
|
|
if (timer_event_occurred) {
|
|
timer_event_occurred--;
|
|
#include "../temp/ontimerj.txt"
|
|
}
|
|
if (key_event_occurred) {
|
|
key_event_occurred--;
|
|
#include "../temp/onkeyj.txt"
|
|
}
|
|
if (strig_event_occurred) {
|
|
strig_event_occurred--;
|
|
#include "../temp/onstrigj.txt"
|
|
}
|
|
chain_input();
|
|
#include "../temp/main.txt"
|
|
|
|
//} (closed by main.txt)
|