diff --git a/ChangeLog b/ChangeLog index 2716922a..b41140cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2016-05-14 (0.12.6) + Fix to prevent const overwriting another const + Updated MID and REPLACE for performance + POINT(0) and POINT(1) values now reset with each program run + POINT(-x, -y) now provides access to the base screen image. For better + performance use the IMAGE.SAVE sub command + +2016-05-07 (0.12.6) + Reverted LASTX/LASTY. Data was already accessible via POINT command + Reverted getPixel from SCREEN for performance. Can still access this by passed -ve x/y values + Reverted using var V_FUNC handling for int sys vars due to eval issues + 2016-04-26 (0.12.6) Fixes for unit case sensitivity diff --git a/samples/distro-examples/apps/calc.bas b/samples/distro-examples/apps/calc.bas index cf4ffec0..d1858dba 100644 --- a/samples/distro-examples/apps/calc.bas +++ b/samples/distro-examples/apps/calc.bas @@ -209,7 +209,7 @@ func showResult(result) rect out_x, out_y STEP w, h, COLOR bgnd FILLED rect out_x - 1, out_y - 1 STEP w + 1, h + 1, COLOR 2 - local out_str = chr(27) + "[15 C" + result + local out_str = result local out_str_w = textwidth(result) local x = (out_x + w) - out_str_w - textwidth("0") diff --git a/samples/distro-examples/examples/Circles_and_arcs.bas b/samples/distro-examples/examples/Circles_and_arcs.bas index a8aad6d0..bb8dbefb 100644 --- a/samples/distro-examples/examples/Circles_and_arcs.bas +++ b/samples/distro-examples/examples/Circles_and_arcs.bas @@ -1,4 +1,4 @@ -color 0,15 +color 1,2:cls circle ymax/4,ymax/4,ymax/8 circle ymax/2,ymax/4,ymax/8 FILLED circle ymax/4,ymax/2,ymax/8,.75 diff --git a/samples/distro-examples/examples/Predefined_Variables.bas b/samples/distro-examples/examples/Predefined_Variables.bas index 2632b698..781c1cad 100644 --- a/samples/distro-examples/examples/Predefined_Variables.bas +++ b/samples/distro-examples/examples/Predefined_Variables.bas @@ -1,6 +1,5 @@ ? cat(1);"Predefined Variables";cat(0) -? "OS VER =0x"; HEX$(osver) -? "SB VER =0x"; HEX$(sbver) +? "SB VER ="; sbver ? "PI ="; pi ? "XMAX ="; xmax ? "YMAX ="; ymax diff --git a/samples/distro-examples/games/UFO.bas b/samples/distro-examples/games/UFO.bas index 984eadfe..27d6de81 100644 Binary files a/samples/distro-examples/games/UFO.bas and b/samples/distro-examples/games/UFO.bas differ diff --git a/samples/distro-examples/games/sokoban.bas b/samples/distro-examples/games/sokoban.bas index 7629acb6..db405f33 100644 --- a/samples/distro-examples/games/sokoban.bas +++ b/samples/distro-examples/games/sokoban.bas @@ -514,7 +514,7 @@ sub play_game(byref game) game.game_over = false while game.game_over = false - pause true: k = inkey + k = inkey(1) if len(k) = 2 then ch = asc(right(k,1)) select case ch diff --git a/samples/distro-examples/graphics/3dtorus.bas b/samples/distro-examples/graphics/3dtorus.bas index e1f735f4..346aa205 100644 --- a/samples/distro-examples/graphics/3dtorus.bas +++ b/samples/distro-examples/graphics/3dtorus.bas @@ -6,12 +6,9 @@ ' Jelly 2004 ' Http://rel.betterwebber.com -const Xmax = 640 -const Ymax = 480 const Xmid = Xmax/2 const Ymid = Ymax/2 const Lens = 256 -const PI = 3.141593 const rings = 14 const bands = 15 const ringradius = 100 diff --git a/samples/distro-examples/graphics/Charts.bas b/samples/distro-examples/graphics/Charts.bas index faf3ff0e..feafb1ed 100644 --- a/samples/distro-examples/graphics/Charts.bas +++ b/samples/distro-examples/graphics/Charts.bas @@ -2,8 +2,9 @@ ' CHART examples const VN=10 +const LINECHART=1 +const BARCHART=2 dim v(1 to VN) - randomize timer cls diff --git a/samples/distro-examples/graphics/Simple_3D.bas b/samples/distro-examples/graphics/Simple_3D.bas index f1fa0b39..faf2cde9 100644 --- a/samples/distro-examples/graphics/Simple_3D.bas +++ b/samples/distro-examples/graphics/Simple_3D.bas @@ -33,6 +33,7 @@ for i=1 to 15 calcPt line sx,sy next +showpage end ' diff --git a/samples/distro-examples/tests/array.bas b/samples/distro-examples/tests/array.bas index e949ef63..7d5d9cb4 100644 --- a/samples/distro-examples/tests/array.bas +++ b/samples/distro-examples/tests/array.bas @@ -69,4 +69,16 @@ if (sim(0) <> 50) then throw "dim sim not tasty" fi +rem ==6866== Source and destination overlap in memcpy(0xfc3f090, 0xfc3f096, 13) +rem ==6866== at 0x4C32513: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +rem ==6866== by 0x48D4A3: memcpy (string3.h:53) +rem ==6866== by 0x48D4A3: comp_text_line_let (scan.c:1874) + +dim dots(1) +dots(0).y = 100 +dots(0).dy = 1 +dots(0).y += dots(0).dy +if (dots(0).y != 101) then + throw "not 101 !!!" +endif diff --git a/samples/distro-examples/tests/call_tau.bas b/samples/distro-examples/tests/call_tau.bas index 02f5181a..05bd36e7 100644 --- a/samples/distro-examples/tests/call_tau.bas +++ b/samples/distro-examples/tests/call_tau.bas @@ -30,8 +30,10 @@ foyer.name= "my name is PI" ? "end" -tau.addRoom(foyer,x) - +for i = 0 to 1000 + tau.addRoom(foyer,x) + jj = tau.calcRoomSize(foyer,x) +next i sub addRoom(the_thing, d) print the_thing.name, d diff --git a/samples/distro-examples/tests/output/trycatch.out b/samples/distro-examples/tests/output/trycatch.out index 3e756074..da08b8b0 100644 --- a/samples/distro-examples/tests/output/trycatch.out +++ b/samples/distro-examples/tests/output/trycatch.out @@ -4,12 +4,6 @@ open failed FS(2): NO SUCH FILE OR DIRECTORY after try catch by error name outer after try - - - * RTE-ERROR AT ../../../samples/distro-examples/tests/trycatch.bas:200 * -Description: -Division by zero - Stack: TRY: 199 TRY: 198 @@ -20,4 +14,9 @@ Stack: IF: 193 IF: 192 SUB: 216 + + + * RTE-ERROR AT ../../../samples/distro-examples/tests/trycatch.bas:200 * +Description: +Division by zero diff --git a/samples/distro-examples/tests/tau.bas b/samples/distro-examples/tests/tau.bas index 0189794d..31812007 100644 --- a/samples/distro-examples/tests/tau.bas +++ b/samples/distro-examples/tests/tau.bas @@ -2,7 +2,7 @@ Unit Tau Import TauChild Export expvar, foof, foop -export addRoom +export addRoom,calcRoomSize export print_expvar, ta, build_ta, cerr expvar = "Tau's exported variable" @@ -37,7 +37,10 @@ sub cerr end sub addRoom(the_thing,d) +end +func calcRoomSize(the_thing,d) + calcRoomSize = 1 end rem initialization diff --git a/samples/distro-examples/tests/trycatch.bas b/samples/distro-examples/tests/trycatch.bas index c31c1ead..e44956e1 100644 --- a/samples/distro-examples/tests/trycatch.bas +++ b/samples/distro-examples/tests/trycatch.bas @@ -198,15 +198,15 @@ if 1 == 1 then try try a = 1 / 0 - catch + catch "X" end try - catch + catch "X" end try - catch + catch "X" end try - catch + catch "X" end try - catch + catch "X" end try fi fi diff --git a/src/common/blib.c b/src/common/blib.c index 2fe5cb82..995a39fd 100644 --- a/src/common/blib.c +++ b/src/common/blib.c @@ -23,11 +23,11 @@ * LET v[(x)] = any * CONST v[(x)] = any */ -void cmd_let(int allowConst) { +void cmd_let(int is_const) { var_t *v_left = code_getvarptr(); if (!prog_error) { - if (v_left->const_flag && !allowConst) { + if (v_left->const_flag) { err_const(); return; } @@ -46,7 +46,7 @@ void cmd_let(int allowConst) { eval(&v_right); if (!prog_error) { v_set(v_left, &v_right); - v_left->const_flag = allowConst; + v_left->const_flag = is_const; } v_free(&v_right); } @@ -84,6 +84,7 @@ void cmd_dim(int preserve) { code_skipnext(); zaf = 0; do { + v_init(&arg); eval(&arg); if (prog_error) { return; @@ -1474,9 +1475,8 @@ void cmd_endif() { stknode_t node; code_pop(&node, kwIF); - while (node.type != kwIF) { + while (node.type != kwIF && !prog_error) { code_pop(&node, kwIF); - IF_ERR_BREAK; } if (!prog_error) { @@ -1755,7 +1755,6 @@ void cmd_next() { jump_ip = node.x.vfor.jump_ip; var_p = node.x.vfor.var_ptr; - // v_init(&var_to); var_step.const_flag = 0; var_step.type = V_INT; var_step.v.i = 1; @@ -1766,6 +1765,7 @@ void cmd_next() { // prog_ip = node.x.vfor.to_expr_ip; + v_init(&var_to); eval(&var_to); if (!prog_error && (var_to.type == V_INT || var_to.type == V_NUM)) { diff --git a/src/common/blib.h b/src/common/blib.h index e0d33522..8c5b0ca2 100644 --- a/src/common/blib.h +++ b/src/common/blib.h @@ -92,7 +92,7 @@ void cmd_deriv(void); void cmd_diffeq(void); // not basic, but speed is needed -void graph_reset(void); // graphics module - reset +void graph_reset(void); void cmd_pset(void); void cmd_line(void); void cmd_rect(void); diff --git a/src/common/blib_db.c b/src/common/blib_db.c index b02dfb4a..a39059d1 100644 --- a/src/common/blib_db.c +++ b/src/common/blib_db.c @@ -564,7 +564,6 @@ void cmd_floadln() { int eof, eol, bufLen, bufIndex; dword unreadBytes; - err_reset(); if (code_peek() == kwTYPE_SEP) { // "filename" is an already open file number flags = 0; @@ -646,7 +645,7 @@ void cmd_floadln() { unreadBytes -= bufLen; dev_fread(handle, (byte *)buf, bufLen); - if (err_has_error()) { + if (prog_error) { eof = 1; break; } @@ -666,7 +665,7 @@ void cmd_floadln() { } } // read line - if (err_has_error()) { + if (prog_error) { // clear & exit v_free(array_p); v_init(array_p); @@ -716,7 +715,6 @@ void cmd_fsaveln() { int flags = DEV_FILE_OUTPUT; int handle, i; - err_reset(); if (code_peek() == kwTYPE_SEP) { // "filename" is an already open file number flags = 0; diff --git a/src/common/blib_func.c b/src/common/blib_func.c index 35c1f221..1968ce4f 100644 --- a/src/common/blib_func.c +++ b/src/common/blib_func.c @@ -21,10 +21,6 @@ #include "common/messages.h" #include "common/keymap.h" -#if defined(_UnixOS) -#include -#endif - struct code_array_node_s { var_t *v; var_int_t col; @@ -397,8 +393,9 @@ void date_fmt(char *fmt, char *buf, long d, long m, long y) { // full name strcat(buf, date_mN_table[m - 1]); } - } else + } else { strcat(buf, "***"); + } } mc = 0; @@ -462,7 +459,7 @@ void date_tim2hms(long t, long *h, long *m, long *s) { * f <- FUNC (f|i) */ var_num_t cmd_math1(long funcCode, var_t *arg) { - var_num_t r = 0.0, x; + var_num_t r, x; IF_ERR_RETURN_0; x = v_getval(arg); @@ -613,6 +610,7 @@ var_num_t cmd_math1(long funcCode, var_t *arg) { break; default: rt_raise("Unsupported built-in function call %ld, please report this bug (2)", funcCode); + r = 0.0; }; return r; @@ -720,7 +718,7 @@ var_int_t cmd_fre(var_int_t arg) { * i <- FUNC (f|i) */ var_int_t cmd_imath1(long funcCode, var_t *arg) { - var_int_t r = 0; + var_int_t r; IF_ERR_RETURN_0; var_int_t x = v_getint(arg); @@ -796,6 +794,7 @@ var_int_t cmd_imath1(long funcCode, var_t *arg) { default: rt_raise("Unsupported built-in function call %ld, please report this bug (3)", funcCode); + r = 0; }; return r; @@ -1300,7 +1299,9 @@ void cmd_str0(long funcCode, var_t *r) { // str <- FUNC (...) // void cmd_strN(long funcCode, var_t *r) { - var_t arg1; + var_t arg1, arg2; + var_t *var_p1 = NULL; + var_t *var_p2 = NULL; var_int_t i, count, lsrc, len, start, pc; char tmp[2], *tmp_p; char *s1 = NULL, *s2 = NULL, *s3 = NULL; @@ -1334,8 +1335,9 @@ void cmd_strN(long funcCode, var_t *r) { r->v.p.ptr[strlen(r->v.p.ptr) - 1] = '\0'; r->type = V_STR; r->v.p.size = strlen(r->v.p.ptr) + 1; - } else + } else { v_zerostr(r); + } } break; case kwSTRING: @@ -1497,8 +1499,9 @@ void cmd_strN(long funcCode, var_t *r) { strcpy(r->v.p.ptr, s1); r->v.p.size = l; *p = lc; - } else + } else { v_zerostr(r); + } } break; @@ -1612,13 +1615,15 @@ void cmd_strN(long funcCode, var_t *r) { // // str <- REPLACE$ ( source, pos, str [, len] ) // - count = -1; - par_massget("SISi", &s1, &start, &s2, &count); - if (!prog_error) { - int ls1, ls2; + v_init(&arg2); - ls1 = strlen(s1); - ls2 = strlen(s2); + var_p1 = par_next_str(&arg1, 1); + start = par_next_int(1); + var_p2 = par_next_str(&arg2, 0); + count = par_getval(-1); + if (!prog_error) { + int ls1 = v_strlen(var_p1); + int ls2 = v_strlen(var_p2); start--; if (start < 0 || start > ls1) { @@ -1630,36 +1635,37 @@ void cmd_strN(long funcCode, var_t *r) { // copy the left-part if (start > 0) { - memcpy(r->v.p.ptr, s1, start); + memcpy(r->v.p.ptr, var_p1->v.p.ptr, start); r->v.p.ptr[start] = '\0'; - } else + } else { *r->v.p.ptr = '\0'; - + } // insert the string - strcat(r->v.p.ptr, s2); + strcat(r->v.p.ptr, var_p2->v.p.ptr); // add the right-part if (count == -1) { count = ls2; } if (start + count < ls1) { - strcat(r->v.p.ptr, (s1 + start + count)); + strcat(r->v.p.ptr, (var_p1->v.p.ptr + start + count)); } r->v.p.ptr[ls1 + ls2] = '\0'; r->v.p.size = ls1 + ls2 + 1; } - + v_free(&arg2); break; case kwMID: // // str <- MID$ ( str, start [, len] ) // - len = -1; - par_massget("SIi", &s1, &start, &len); + var_p1 = par_next_str(&arg1, 1); + start = par_next_int(0); + len = par_getval(-1); if (!prog_error) { - lsrc = strlen(s1); - if (start <= 0 || start > (int) strlen(s1)) { + lsrc = v_strlen(var_p1); + if (start <= 0 || start > lsrc) { err_stridx(start); } else { start--; @@ -1667,13 +1673,13 @@ void cmd_strN(long funcCode, var_t *r) { len = lsrc - start; } r->v.p.ptr = malloc(len + 1); - memcpy(r->v.p.ptr, s1 + start, len); + memcpy(r->v.p.ptr, var_p1->v.p.ptr + start, len); r->v.p.ptr[len] = '\0'; r->v.p.size = len + 1; } } - break; + default: rt_raise("Unsupported built-in function call %ld, please report this bug (7)", funcCode); } @@ -1873,7 +1879,6 @@ void cmd_intN(long funcCode, var_t *r) { code_skipnext(); var_p = tvar[code_getaddr()]; if (var_p->type == V_ARRAY) { - l = 1; if (code_peek() == kwTYPE_SEP) { par_getcomma(); @@ -2354,7 +2359,7 @@ void cmd_genfunc(long funcCode, var_t *r) { err_argerr(); else { x = v_getint(v_elem(v, 0)); - y = v_getint(v_elem(v, 0)); + y = v_getint(v_elem(v, 1)); } } else { x = v_getint(v); @@ -2471,10 +2476,11 @@ void cmd_genfunc(long funcCode, var_t *r) { r->type = V_NUM; - if (funcCode == kwPTDISTLN) + if (funcCode == kwPTDISTLN) { r->v.n = geo_distfromline(B.x, B.y, C.x, C.y, A.x, A.y); - else + } else { r->v.n = geo_distfromseg(B.x, B.y, C.x, C.y, A.x, A.y); + } } break; // @@ -2554,12 +2560,13 @@ void cmd_genfunc(long funcCode, var_t *r) { if (first) { dar_first(funcCode, r, elem_p); first = 0; - } else + } else { dar_next(funcCode, r, elem_p); - + } tcount++; - } else + } else { return; + } } break; } @@ -2568,17 +2575,19 @@ void cmd_genfunc(long funcCode, var_t *r) { // no 'break' here default: // default --- expression + v_init(&arg); eval(&arg); if (!prog_error) { if (first) { dar_first(funcCode, r, &arg); first = 0; - } else + } else { dar_next(funcCode, r, &arg); - + } tcount++; - } else + } else { return; + } v_free(&arg); } @@ -2586,9 +2595,9 @@ void cmd_genfunc(long funcCode, var_t *r) { } while (!ready); // final - if (!prog_error) + if (!prog_error) { dar_final(funcCode, r, tcount); - + } break; // // @@ -2639,6 +2648,7 @@ void cmd_genfunc(long funcCode, var_t *r) { // no 'break' here default: // default --- expression + v_init(&arg); eval(&arg); if (!prog_error) { if (tcount >= len) { diff --git a/src/common/blib_graph.c b/src/common/blib_graph.c index a74e93be..0e98c4fc 100644 --- a/src/common/blib_graph.c +++ b/src/common/blib_graph.c @@ -7,12 +7,6 @@ // // Copyright(C) 2000 Nicholas Christopoulos -#include "common/sys.h" -#include "common/str.h" -#include "common/kw.h" -#include "common/panic.h" -#include "common/var.h" -#include "common/blib.h" #include "common/pproc.h" #include "common/messages.h" @@ -20,10 +14,8 @@ int gra_x; int gra_y; -// void graph_reset() { gra_x = gra_y = 0; - dev_cls(); } // @@ -1518,8 +1510,7 @@ void cmd_m3apply() { for (i = 0; i < count; i++) { e = v_elem(p, i); - if (e->type != V_ARRAY - ) + if (e->type != V_ARRAY) err_parsepoly(i, 10); else if ((e->v.a.size % 2) != 0) err_parsepoly(i, 11); diff --git a/src/common/brun.c b/src/common/brun.c old mode 100755 new mode 100644 index bda142b6..e279c744 --- a/src/common/brun.c +++ b/src/common/brun.c @@ -35,6 +35,9 @@ static char fileName[OS_FILENAME_SIZE + 1]; static int exec_tid; #define EVT_CHECK_EVERY 50 +#define IF_ERR_BREAK if (prog_error) { \ + if (prog_error == errThrow) \ + prog_error = errNone; else break;} /** * jump to label @@ -92,8 +95,10 @@ void free_node(stknode_t *node) { break; case kwFUNC: + case kwPROC: if (node->x.vcall.rvid != INVALID_ADDR) { - tvar[node->x.vcall.rvid] = node->x.vcall.retvar; // restore ptr + free(tvar[node->x.vcall.rvid]); + tvar[node->x.vcall.rvid] = node->x.vcall.retvar; } break; @@ -211,7 +216,6 @@ void setsysvar_int(int index, var_int_t value) { activate_task(i); if (ctask->has_sysvars) { var_t *var_p = tvar[index]; - var_p->type = V_INT; var_p->const_flag = 1; var_p->v.i = value; @@ -273,10 +277,10 @@ void setsysvar_str(int index, const char *value) { */ void exec_setup_predefined_variables() { char homedir[OS_PATHNAME_SIZE + 1]; + homedir[0] = '\0'; // needed here (otherwise task will not updated) ctask->has_sysvars = 1; - setsysvar_str(SYSVAR_SBVER, SB_STR_VER); setsysvar_num(SYSVAR_PI, SB_PI); setsysvar_int(SYSVAR_XMAX, os_graf_mx - 1); @@ -298,19 +302,16 @@ void exec_setup_predefined_variables() { homedir[l] = OS_DIRSEP; homedir[l + 1] = '\0'; } - setsysvar_str(SYSVAR_HOME, homedir); #elif defined(_Win32) - if (dev_getenv("HOME")) { // this works on cygwin + if (dev_getenv("HOME")) { + // this works on cygwin strcpy(homedir, dev_getenv("HOME")); } else { - char *p; - - GetModuleFileName(NULL, homedir, 1024); - p = strrchr(homedir, '\\'); + GetModuleFileName(NULL, homedir, sizeof(homedir) - 1); + char *p = strrchr(homedir, '\\'); *p = '\0'; strcat(homedir, "\\"); - if (OS_DIRSEP == '/') { p = homedir; while (*p) { @@ -320,25 +321,15 @@ void exec_setup_predefined_variables() { } } } - setsysvar_str(SYSVAR_HOME, homedir); // mingw32 - - { - static char stupid_os_envsblog[1024]; // it must be static at - // least by default on DOS - // or Win32(BCB) - sprintf(stupid_os_envsblog, "SBLOG=%s%csb.log", homedir, OS_DIRSEP); - putenv(stupid_os_envsblog); - } -#else - setsysvar_str(SYSVAR_HOME, ""); #endif + setsysvar_str(SYSVAR_HOME, homedir); } /** * BREAK */ void brun_stop() { - prog_error = -3; + prog_error = errBreak; } /** @@ -433,7 +424,7 @@ void cmd_chain(void) { if (success == 0) { close_task(tid_base); activate_task(tid_prev); - prog_error = 1; + prog_error = errCompile; return; } @@ -460,7 +451,7 @@ void cmd_chain(void) { strcpy(gsb_last_errmsg, ""); if (success == 0) { - prog_error = 1; + prog_error = errRuntime; } } @@ -512,7 +503,7 @@ static inline void bc_loop_call_proc() { pcode_t pcode = code_getaddr(); switch (pcode) { case kwCLS: - graph_reset(); + dev_cls(); break; case kwTHROW: cmd_throw(); @@ -683,7 +674,7 @@ static inline void bc_loop_call_proc() { dev_print("\nSTKDUMP:\n"); dump_stack(); // end of program - prog_error = -1; + prog_error = errEnd; break; case kwDEFINEKEY: cmd_definekey(); @@ -734,7 +725,7 @@ static inline void bc_loop_end() { } } // end of program - prog_error = -1; + prog_error = errEnd; } /** @@ -787,7 +778,7 @@ void bc_loop(int isf) { // break event break; case -2: - prog_error = -2; + prog_error = errBreak; inf_break(prog_line); break; default: @@ -1287,7 +1278,7 @@ int brun_create_task(const char *filename, byte *preloaded_bc, int libf) { eval_sp = 0; // initialize the rest tasks globals - prog_error = 0; + prog_error = errNone; prog_line = 0; prog_dp = data_org = hdr.data_ip; prog_length = hdr.bc_count; @@ -1451,7 +1442,7 @@ int exec_close_task() { prog_timer = NULL; } - if (prog_error != -1 && prog_error != 0) { + if (prog_error != errEnd && prog_error != errNone) { return 1; } return 0; @@ -1545,10 +1536,10 @@ int sbasic_exec_task(int tid) { prev_tid = activate_task(tid); - bc_loop(0); // natural the value -1 is end of program - success = (prog_error == 0 || prog_error == -1); + bc_loop(0); + success = (prog_error == errNone || prog_error == errEnd); if (success) { - prog_error = 0; + prog_error = errNone; } activate_task(prev_tid); return success; @@ -1697,6 +1688,7 @@ void sbasic_exec_prepare(const char *filename) { } // reset system cmd_play_reset(); + graph_reset(); } /* diff --git a/src/common/device.c b/src/common/device.c index c64192a1..ccb92c6b 100644 --- a/src/common/device.c +++ b/src/common/device.c @@ -355,24 +355,26 @@ void dev_clear_sound_queue() { /** * printf - * - * WARNING: Win32/Unix ver is limited to 1024 bytes */ -void dev_printf(const char *fmt, ...) { - char *buf; - va_list ap; +void dev_printf(const char *format, ...) { + va_list args; + va_start(args, format); + unsigned size = vsnprintf(NULL, 0, format, args); + va_end(args); - va_start(ap, fmt); - buf = malloc(1024); -#if defined(_DOS) || defined(_Win32) - vsprintf(buf, fmt, ap); -#else - vsnprintf(buf, 1024, fmt, ap); -#endif - va_end(ap); + if (size) { + char *buf = malloc(size + 1); + buf[0] = '\0'; + va_start(args, format); + vsnprintf(buf, size + 1, format, args); + va_end(args); + + buf[size] = '\0'; + va_end(args); - dev_print(buf); - free(buf); + dev_print(buf); + free(buf); + } } /** @@ -398,7 +400,6 @@ void log_printf(const char *format, ...) { buf[i--] = '\0'; } strcat(buf, "\r\n"); - #if defined(IMPL_LOG_WRITE) lwrite(buf); #else @@ -420,3 +421,9 @@ void dev_trace_line(int lineNo) { dev_printf("<%d>", lineNo); } #endif + +#ifndef IMPL_LOG_WRITE +void lwrite(const char *buf) { + fprintf(stderr, "%s\n", buf); +} +#endif diff --git a/src/common/eval.c b/src/common/eval.c index 837ac638..c3ed603f 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -26,6 +26,12 @@ (v)->type == V_ARRAY)) { \ v_free((v)); \ } +#define V_FREE2(v) \ + if (((v)->type == V_STR || \ + (v)->type == V_MAP || \ + (v)->type == V_ARRAY)) { \ + v_free((v)); \ + } /** * matrix: convert var_t to double[r][c] @@ -268,13 +274,15 @@ int v_wc_match(var_t *vwc, var_t *v) { if (!prog_error) { ri = wc_match((char *) vwc->v.p.ptr, (char *) vt->v.p.ptr); } - v_free(vt); + V_FREE(vt); free(vt); } return ri; } -static inline void oper_add(var_t *r, var_t *left, byte op) { +static inline void oper_add(var_t *r, var_t *left) { + byte op = CODE(IP); + IP++; if (r->type == V_INT && v_is_type(left, V_INT)) { if (op == '+') { r->v.i += left->v.i; @@ -332,18 +340,21 @@ static inline void oper_add(var_t *r, var_t *left, byte op) { break; } v_set(r, &vtmp); - v_free(&vtmp); + V_FREE2(&vtmp); } V_FREE(left); } } -static inline void oper_mul(var_t *r, var_t *left, byte op) { +static inline void oper_mul(var_t *r, var_t *left) { var_num_t lf; var_num_t rf; var_int_t li; var_int_t ri; + byte op = CODE(IP); + IP++; + if (r->type == V_ARRAY || v_is_type(left, V_ARRAY)) { // arrays if (r->type == V_ARRAY && v_is_type(left, V_ARRAY)) { @@ -425,10 +436,13 @@ static inline void oper_mul(var_t *r, var_t *left, byte op) { } } -static inline void oper_unary(var_t *r, byte op) { +static inline void oper_unary(var_t *r) { var_int_t ri; var_num_t rf; + byte op = CODE(IP); + IP++; + switch (op) { case '-': if (r->type == V_INT) { @@ -463,12 +477,16 @@ static inline void oper_unary(var_t *r, byte op) { } } -static inline void oper_log(var_t *r, var_t *left, byte op) { +static inline void oper_log(var_t *r, var_t *left) { var_int_t li; var_int_t ri; var_int_t a, b; int i, set; + // logical/bit + byte op = CODE(IP); + IP++; + if (op != OPLOG_IN) { li = v_igetval(left); ri = v_igetval(r); @@ -550,9 +568,13 @@ static inline void oper_log(var_t *r, var_t *left, byte op) { r->v.i = ri; } -static inline void oper_cmp(var_t *r, var_t *left, byte op) { +static inline void oper_cmp(var_t *r, var_t *left) { var_int_t ri; + // compare + byte op = CODE(IP); + IP++; + switch (op) { case OPLOG_EQ: ri = (v_compare(left, r) == 0); @@ -597,7 +619,7 @@ static inline void oper_cmp(var_t *r, var_t *left, byte op) { v = v_clone(left); v_tostr(v); ri = (strstr(r->v.p.ptr, v->v.p.ptr) != NULL); - v_free(v); + V_FREE(v); free(v); } } else if (r->type == V_NUM || r->type == V_INT) { @@ -623,6 +645,9 @@ static inline void oper_cmp(var_t *r, var_t *left, byte op) { static inline void oper_powr(var_t *r, var_t *left) { var_num_t rf; + // pow + IP++; + rf = pow(v_getval(left), v_getval(r)); V_FREE(r); r->type = V_NUM; @@ -632,10 +657,22 @@ static inline void oper_powr(var_t *r, var_t *left) { V_FREE(left); } -static inline void eval_shortc(var_t *r, bcip_t addr, byte op) { +static inline void eval_shortc(var_t *r) { + // short-circuit evaluation + // see cev_log() in ceval.c for layout details var_int_t li; var_int_t ri; + // skip code kwTYPE_LOGOPR + IP++; + + // read operator + byte op = CODE(IP); + IP++; + + // read shortcut jump offset + bcip_t addr = code_getaddr(); + // read left side result li = v_igetval(&eval_stk[eval_sp - 1]); ri = -1; @@ -695,6 +732,9 @@ static inline void eval_var(var_t *r, var_t *var_p) { eval_var(r, var_deref); } break; + case V_FUNC: + var_p->v.fn.cb(r); + break; } } @@ -828,7 +868,7 @@ static inline void eval_callf_num(long fcode, var_t *r) { } else { IP++; cmd_ns1(fcode, &vtmp, r); - v_free(&vtmp); + V_FREE2(&vtmp); } } } @@ -876,8 +916,8 @@ static inline void eval_callf_imathI1(long fcode, var_t *r) { } static inline void eval_callf_imathI2(long fcode, var_t *r) { - var_t vtmp; // int FUNC(void) + var_t vtmp; vtmp.type = V_INT; vtmp.v.i = 0; r->type = V_INT; @@ -899,7 +939,7 @@ static inline void eval_callf_mathN1(long fcode, var_t *r) { IP++; r->type = V_NUM; r->v.n = cmd_math1(fcode, &vtmp); - v_free(&vtmp); + V_FREE2(&vtmp); } } } @@ -1126,7 +1166,7 @@ static inline void eval_call_udf(var_t *r) { } else { v_set(r, udf_rv.x.vdvar.vptr); // free ret-var - v_free(udf_rv.x.vdvar.vptr); + V_FREE(udf_rv.x.vdvar.vptr); free(udf_rv.x.vdvar.vptr); } } @@ -1136,21 +1176,12 @@ static inline void eval_call_udf(var_t *r) { * executes the expression (Code[IP]) and returns the result (r) */ void eval(var_t *r) { - code_t code; - byte op; - var_t *var_p; - bcip_t addr; - var_t *left = NULL; bcip_t eval_pos = eval_sp; byte level = 0; - r->const_flag = 0; - r->type = V_INT; - r->v.i = 0L; - - do { - code = CODE(IP); + while (!prog_error) { + code_t code = CODE(IP); IP++; switch (code) { case kwTYPE_INT: @@ -1173,91 +1204,41 @@ void eval(var_t *r) { v_eval_str(r); break; - case kwTYPE_PTR: - // UDF pointer - constant - V_FREE(r); - r->type = V_PTR; - r->const_flag = 1; - r->v.ap.p = code_getaddr(); - r->v.ap.v = code_getaddr(); - break; - - case kwTYPE_VAR: - // variable - V_FREE(r); - IP--; - var_p = code_getvarptr(); - if (prog_error) { - return; - } - eval_var(r, var_p); - break; - - case kwTYPE_EVPUSH: - // stack = push result - eval_push(r); + case kwTYPE_LOGOPR: + oper_log(r, left); break; - case kwTYPE_EVPOP: - // pop left - eval_sp--; - left = &eval_stk[eval_sp]; + case kwTYPE_CMPOPR: + oper_cmp(r, left); break; case kwTYPE_ADDOPR: - op = CODE(IP); - IP++; - oper_add(r, left, op); + oper_add(r, left); break; case kwTYPE_MULOPR: - op = CODE(IP); - IP++; - oper_mul(r, left, op); + oper_mul(r, left); break; - case kwTYPE_UNROPR: - // unary - op = CODE(IP); - IP++; - oper_unary(r, op); - break; - - case kwTYPE_EVAL_SC: - // short-circuit evaluation - // see cev_log() in ceval.c for layout details - - // skip code kwTYPE_LOGOPR - IP++; - - // read operator - op = CODE(IP); - IP++; - - // read shortcut jump offset - addr = code_getaddr(); - eval_shortc(r, addr, op); - break; - - case kwTYPE_LOGOPR: - // logical/bit - op = CODE(IP); - IP++; - oper_log(r, left, op); + case kwTYPE_POWOPR: + oper_powr(r, left); break; - case kwTYPE_CMPOPR: - // compare - op = CODE(IP); - IP++; - oper_cmp(r, left, op); + case kwTYPE_UNROPR: + // unary + oper_unary(r); break; - case kwTYPE_POWOPR: - // pow - op = CODE(IP); - IP++; - oper_powr(r, left); + case kwTYPE_VAR: { + // variable + V_FREE(r); + IP--; + var_t *var_p = code_getvarptr(); + if (prog_error) { + return; + } + eval_var(r, var_p); + } break; case kwTYPE_LEVEL_BEGIN: @@ -1276,9 +1257,19 @@ void eval(var_t *r) { level--; break; - case kwTYPE_CALLEXTF: - // [lib][index] external functions - eval_extf(r); + case kwTYPE_EVPUSH: + // stack = push result + eval_push(r); + break; + + case kwTYPE_EVPOP: + // pop left + eval_sp--; + left = &eval_stk[eval_sp]; + break; + + case kwTYPE_EVAL_SC: + eval_shortc(r); break; case kwTYPE_CALLF: @@ -1290,33 +1281,47 @@ void eval(var_t *r) { eval_call_udf(r); break; - case kwBYREF: - // unexpected code - err_evsyntax(); - break; - default: - if (code == kwTYPE_EOC || kw_check_evexit(code)) { - IP--; - // restore stack pointer - eval_sp = eval_pos; - - // normal exit - return; - } - rt_raise("UNKNOWN ERROR. IP:%d=0x%02X", IP, code); - if (!opt_quiet) { - hex_dump(prog_source, prog_length); - } - }; + // less used codes + switch (code) { + case kwTYPE_CALLEXTF: + // [lib][index] external functions + eval_extf(r); + break; - // run-time error check - if (prog_error) { - break; - } + case kwTYPE_PTR: + // UDF pointer - constant + V_FREE(r); + r->type = V_PTR; + r->const_flag = 1; + r->v.ap.p = code_getaddr(); + r->v.ap.v = code_getaddr(); + break; - } while (1); + case kwBYREF: + // unexpected code + err_evsyntax(); + break; + default: + if (code == kwTYPE_EOC || + code == kwTYPE_SEP || + code == kwTO || + kw_check_evexit(code)) { + IP--; + // restore stack pointer + eval_sp = eval_pos; + + // normal exit + return; + } + rt_raise("UNKNOWN ERROR. IP:%d=0x%02X", IP, code); + if (!opt_quiet) { + hex_dump(prog_source, prog_length); + } + } + }; + } // restore stack pointer eval_sp = eval_pos; } diff --git a/src/common/file.c b/src/common/file.c index d5a96db7..13573a6e 100644 --- a/src/common/file.c +++ b/src/common/file.c @@ -96,18 +96,13 @@ int dev_freefilehandle() { */ dev_file_t *dev_getfileptr(const int handle) { dev_file_t *result; - if (!opt_file_permitted) { - rt_raise(ERR_FILE_PERM); + // BASIC handles start from 1 + int hnd = handle - 1; + if (hnd < 0 || hnd >= OS_FILEHANDLES) { + rt_raise(FSERR_HANDLE); result = NULL; } else { - // BASIC handles start from 1 - int hnd = handle - 1; - if (hnd < 0 || hnd >= OS_FILEHANDLES) { - rt_raise(FSERR_HANDLE); - result = NULL; - } else { - result = &file_table[hnd]; - } + result = &file_table[hnd]; } return result; } @@ -162,11 +157,6 @@ int dev_fopen(int sb_handle, const char *name, int flags) { dev_file_t *f; int i; - if (!opt_file_permitted) { - rt_raise(ERR_FILE_PERM); - return 0; - } - if ((f = dev_getfileptr(sb_handle)) == NULL) { return 0; } @@ -238,6 +228,11 @@ int dev_fopen(int sb_handle, const char *name, int flags) { } } // device + if (!opt_file_permitted && f->type != ft_http_client) { + rt_raise(ERR_FILE_PERM); + return 0; + } + // // open // diff --git a/src/common/panic.c b/src/common/panic.c old mode 100755 new mode 100644 diff --git a/src/common/pproc.h b/src/common/pproc.h index 5a33168a..f0734bd7 100644 --- a/src/common/pproc.h +++ b/src/common/pproc.h @@ -196,6 +196,24 @@ var_num_t par_getnum(void); #define par_getreal() par_getnum() +/** + * @ingroup par + * + * get next parameter as integer + * + * @return the integer + */ +var_int_t par_next_int(int sep); + +/** + * @ingroup par + * + * get next parameter as string + * + * @return the string var + */ +var_t *par_next_str(var_t *arg, int sep); + /** * @ingroup par * diff --git a/src/common/proc.c b/src/common/proc.c index c79a6647..84b9f59b 100644 --- a/src/common/proc.c +++ b/src/common/proc.c @@ -200,45 +200,6 @@ void exec_usefunc3(var_t *var1, var_t *var2, var_t *var3, bcip_t ip) { free(old_z); } -#ifndef IMPL_LOG_WRITE - -/** - * Write to the log file - */ -void lwrite(const char *buf) { - int log_dev; /* logfile file handle */ - char log_name[OS_PATHNAME_SIZE + 1]; /* LOGFILE filename */ - - // open -#if defined(_Win32) || defined(__MINGW32__) - if (getenv("SBLOG")) { - strcpy(log_name, getenv("SBLOG")); - } - else { - sprintf(log_name, "c:%csb.log", OS_DIRSEP); - } -#else - sprintf(log_name, "%ctmp%csb.log", OS_DIRSEP, OS_DIRSEP); -#endif - - log_dev = open(log_name, O_RDWR, 0660); - lseek(log_dev, 0, SEEK_END); - if (log_dev == -1) { - log_dev = open(log_name, O_CREAT | O_RDWR, 0660); - } - if (log_dev == -1) { - panic("LOG: Error on creating log file"); - } - - // write - if (write(log_dev, buf, strlen(buf)) == -1) { - panic("LOG: write failed"); - } - - close(log_dev); -} -#endif // NOT IMPL_LOG_WRITE - /* * Write string to output device */ @@ -471,6 +432,7 @@ void par_getstr(var_t *var) { err_syntax(-1, "%S"); return; default: + v_init(var); eval(var); break; }; @@ -510,19 +472,59 @@ var_num_t par_getnum() { return f; } -var_int_t par_getval(var_int_t def) { +var_int_t par_next_int(int sep) { var_int_t result; - byte code = code_peek(); - if (code == kwTYPE_VAR) { + if (prog_error) { + result = 0; + } else { result = par_getint(); - } else if (code == kwTYPE_INT) { - code_skipnext(); - result = code_getint(); - } else if (code == kwTYPE_NUM) { - code_skipnext(); - result = code_getreal(); + } + if (!prog_error && (sep || code_peek() == kwTYPE_SEP)) { + par_getcomma(); + } + return result; +} + +var_t *par_next_str(var_t *arg, int sep) { + var_t *result; + if (prog_error) { + result = NULL; + } else if (code_isvar()) { + result = code_getvarptr(); } else { + eval(arg); + result = arg; + if (result->type != V_STR) { + v_tostr(arg); + } + } + if (!prog_error && (sep || code_peek() == kwTYPE_SEP)) { + par_getcomma(); + } + return result; +} + +var_int_t par_getval(var_int_t def) { + var_int_t result; + if (prog_error) { result = def; + } else { + var_t var; + switch (code_peek()) { + case kwTYPE_LINE: + case kwTYPE_EOC: + case kwTYPE_SEP: + case kwTYPE_LEVEL_END: + case kwTYPE_EVPUSH: + result = def; + break; + default: + v_init(&var); + eval(&var); + result = prog_error ? 0 : v_getint(&var); + v_free(&var); + break; + } } return result; } @@ -615,7 +617,6 @@ pt_t par_getpt() { par_getcomma(); if (!prog_error) { var_t v2; - eval(&v2); if (!prog_error) { pt.y = v_getreal(&v2); @@ -667,10 +668,11 @@ ipt_t par_getipt() { par_getcomma(); if (!prog_error) { var_t v2; - + v_init(&v2); eval(&v2); - if (!prog_error) + if (!prog_error) { pt.y = v_getint(&v2); + } v_free(&v2); } } diff --git a/src/common/sberr.c b/src/common/sberr.c index 0d395ca3..152661cc 100644 --- a/src/common/sberr.c +++ b/src/common/sberr.c @@ -14,8 +14,6 @@ #include #include -int error_caught; - /** * common message handler */ @@ -32,11 +30,38 @@ void err_common_msg(const char *seg, const char *file, int line, const char *des log_printf("\033[80m\033[0m"); } +void err_stack_dump() { + int i_stack, i_kw; + + if (prog_stack_count) { + log_printf("\033[4mStack:\033[0m\n"); + } + + // log the stack trace + for (i_stack = prog_stack_count; i_stack > 0; i_stack--) { + stknode_t node = prog_stack[i_stack - 1]; + switch (node.type) { + case 0xFF: + case kwBYREF: + case kwTYPE_CRVAR: + // ignore these types + break; + + default: + for (i_kw = 0; keyword_table[i_kw].name[0] != '\0'; i_kw++) { + if (node.type == keyword_table[i_kw].code) { + log_printf(" %s: %d", keyword_table[i_kw].name, node.line); + } + } + } + } +} + /** * raise a compiler error */ void sc_raise2(const char *sec, int scline, const char *buff) { - prog_error = 0x40; + prog_error = errCompile; err_common_msg(WORD_COMP, sec, scline, buff); } @@ -46,44 +71,16 @@ void sc_raise2(const char *sec, int scline, const char *buff) { void rt_raise(const char *fmt, ...) { char *buff; va_list ap; - int i_stack, i_kw; - - if (!gsb_last_error) { - prog_error = 0x80; + if (!gsb_last_error && !prog_error && prog_source) { + prog_error = errRuntime; va_start(ap, fmt); buff = malloc(SB_TEXTLINE_SIZE + 1); vsprintf(buff, fmt, ap); va_end(ap); - + err_stack_dump(); err_common_msg(WORD_RTE, prog_file, prog_line, buff); free(buff); - - if (prog_stack_count) { - log_printf("\033[4mStack:\033[0m\n"); - } - - // log the stack trace - for (i_stack = prog_stack_count; i_stack > 0; i_stack--) { - stknode_t node = prog_stack[i_stack - 1]; - switch (node.type) { - case 0xFF: - case kwBYREF: - case kwTYPE_CRVAR: - // ignore these types - break; - - default: - for (i_kw = 0; keyword_table[i_kw].name[0] != '\0'; i_kw++) { - if (node.type == keyword_table[i_kw].code) { - log_printf(" %s: %d", keyword_table[i_kw].name, node.line); - } - } - } - } - if (prog_stack_count) { - log_printf("\n"); - } } } @@ -91,11 +88,11 @@ void rt_raise(const char *fmt, ...) { * run-time syntax error */ void err_syntax(int keyword, const char *fmt) { - if (!gsb_last_error) { + if (!gsb_last_error && prog_source) { char *buff = malloc(SB_TEXTLINE_SIZE + 1); char *fmt_p = (char *)fmt; - prog_error = 0x80; + prog_error = errSyntax; buff[0] = '\0'; if (keyword != -1) { if (kw_getfuncname(keyword, buff) || @@ -169,7 +166,7 @@ void err_arrmis_rp(void) { } void err_arridx(int i, int m) { - rt_raise(ERR_ARRAY_RANGE, i, m); + err_throw(ERR_ARRAY_RANGE, i, m); } void err_typemismatch(void) { @@ -182,15 +179,15 @@ void err_argerr(void) { } void err_varisarray(void) { - rt_raise(EVAL_VAR_IS_ARRAY); + err_throw(EVAL_VAR_IS_ARRAY); } void err_varisnotarray(void) { - rt_raise(EVAL_VAR_IS_NOT_ARRAY); + err_throw(EVAL_VAR_IS_NOT_ARRAY); } void err_vararridx(int i, int m) { - rt_raise(ERR_ARRAY_RANGE, i, m); + err_throw(ERR_ARRAY_RANGE, i, m); } void err_varnotnum(void) { @@ -226,7 +223,7 @@ void err_notarray(void) { } void err_out_of_range(void) { - rt_raise(ERR_RANGE); + err_throw(ERR_RANGE); } void err_missing_sep(void) { @@ -234,7 +231,7 @@ void err_missing_sep(void) { } void err_division_by_zero(void) { - rt_raise(ERR_DIVZERO); + err_throw(ERR_DIVZERO); } void err_matop(void) { @@ -259,7 +256,7 @@ void err_parm_byref(int n) { } void err_stridx(int n) { - rt_raise(ERR_STR_RANGE, n); + err_throw(ERR_STR_RANGE, n); } void err_fopen(void) { @@ -374,6 +371,7 @@ void err_throw_str(const char *err) { int throw_sp = prog_stack_count; int try_sp = err_find_try(throw_sp); int reset_sp; + int trace_done = 0; if (!prog_error && try_sp != -1) { bcip_t catch_ip = prog_stack[try_sp].x.vtry.catch_ip; @@ -411,6 +409,11 @@ void err_throw_str(const char *err) { } } + if (!caught) { + err_stack_dump(); + trace_done = 1; + } + // cleanup the stack stknode_t node; int sp; @@ -422,10 +425,14 @@ void err_throw_str(const char *err) { } } if (!caught) { - prog_error = 0x80; + prog_error = errRuntime; + if (!trace_done) { + err_stack_dump(); + } err_common_msg(WORD_RTE, prog_file, prog_line, err); + } else { + prog_error = errThrow; } - error_caught = caught; } // throw internal error @@ -469,17 +476,9 @@ void err_file(dword code) { } } -void err_reset() { - error_caught = 0; -} - -int err_has_error() { - return error_caught || prog_error; -} - int err_handle_error(const char *err, var_p_t var) { int result; - if (error_caught == 1) { + if (prog_error == errThrow) { result = 1; } else if (prog_error) { rt_raise(err); diff --git a/src/common/sberr.h b/src/common/sberr.h index ceddee07..56c98c83 100644 --- a/src/common/sberr.h +++ b/src/common/sberr.h @@ -16,7 +16,16 @@ extern "C" { #endif -#define IF_ERR_BREAK if (prog_error) {break;} +typedef enum { + errNone = 0, + errEnd, + errBreak, + errThrow, + errCompile, + errRuntime, + errSyntax +} ErrorState; + #define IF_ERR_RETURN if (prog_error) {return;} #define IF_ERR_RETURN_0 if (prog_error) {return 0;} @@ -71,13 +80,11 @@ void err_ref_var(); void err_ref_circ_var(); void err_array(); void err_form_input(); +void err_throw(const char *fmt, ...); +int err_handle_error(const char *err, var_p_t var); void inf_done(void); void inf_break(int pline); -void err_throw(const char *fmt, ...); void cmd_throw(); -void err_reset(); -int err_handle_error(const char *err, var_p_t var); -int err_has_error(); #if defined(__cplusplus) } diff --git a/src/common/scan.c b/src/common/scan.c index c2a4700a..94aeb30f 100644 --- a/src/common/scan.c +++ b/src/common/scan.c @@ -244,18 +244,20 @@ int comp_is_external_func(const char *name) { * error messages */ void sc_raise(const char *fmt, ...) { - char *buff; - va_list ap; + if (!prog_error) { + char *buff; + va_list ap; - va_start(ap, fmt); - comp_error = 1; + va_start(ap, fmt); + comp_error = 1; - buff = malloc(SB_SOURCELINE_SIZE + 1); - vsnprintf(buff, SB_SOURCELINE_SIZE, fmt, ap); - va_end(ap); + buff = malloc(SB_SOURCELINE_SIZE + 1); + vsnprintf(buff, SB_SOURCELINE_SIZE, fmt, ap); + va_end(ap); - sc_raise2(comp_bc_sec, comp_line, buff); // sberr.h - free(buff); + sc_raise2(comp_bc_sec, comp_line, buff); // sberr.h + free(buff); + } } /* @@ -1868,7 +1870,7 @@ void comp_text_line_let(long idx, int ladd, int linc, int ldec, int leqop) { // store plain operator in comp_bc_parm int len = strlen(p); - memcpy(comp_bc_parm, p, len); + memmove(comp_bc_parm, p, len); comp_bc_parm[len] = '\0'; comp_get_unary(comp_bc_parm, &ladd, &linc, &ldec, &leqop); diff --git a/src/common/screen.c b/src/common/screen.c index eb7dcb44..bd8117b0 100644 --- a/src/common/screen.c +++ b/src/common/screen.c @@ -13,6 +13,7 @@ #include "common/messages.h" #include "common/osd.h" #include "common/sberr.h" +#include "common/blib.h" #define W2X(x) (((((x) - dev_Wx1) * dev_Vdx) / dev_Wdx) + dev_Vx1) #define W2Y(y) (((((y) - dev_Wy1) * dev_Vdy) / dev_Wdy) + dev_Vy1) @@ -155,6 +156,7 @@ void dev_print(const char *str) { * clears the screen */ void dev_cls() { + graph_reset(); osd_cls(); } diff --git a/src/common/str.h b/src/common/str.h old mode 100755 new mode 100644 diff --git a/src/common/units.c b/src/common/units.c index 5844b610..459d4173 100644 --- a/src/common/units.c +++ b/src/common/units.c @@ -266,7 +266,7 @@ int unit_exec(int lib_id, int index, var_t *ret) { break; case stt_procedure: exec_sync_variables(1); - cmd_call_unit_udp(kwPROC, ps->task_id, us->address, 0); + cmd_call_unit_udp(kwPROC, ps->task_id, us->address, INVALID_ADDR); activate_task(ps->task_id); if (prog_error) { gsb_last_error = prog_error; diff --git a/src/common/var.c b/src/common/var.c index cc55fdea..809c6c56 100644 --- a/src/common/var.c +++ b/src/common/var.c @@ -32,7 +32,7 @@ var_t *v_new() { int v_isempty(var_t *var) { switch (var->type) { case V_STR: - return (strlen(var->v.p.ptr) == 0); + return (v_strlen(var) == 0); case V_INT: return (var->v.i == 0); case V_MAP: @@ -50,6 +50,19 @@ int v_isempty(var_t *var) { return 1; } +int v_strlen(const var_t *v) { + int result; + if (v->type == V_STR) { + result = v->v.p.size; + if (result && v->v.p.ptr[result - 1] == '\0') { + result--; + } + } else { + result = 0; + } + return result; +} + /* * returns the length of the variable */ @@ -58,7 +71,7 @@ int v_length(var_t *var) { switch (var->type) { case V_STR: - return strlen(var->v.p.ptr); + return v_strlen(var); case V_MAP: return map_length(var); case V_PTR: @@ -446,7 +459,7 @@ void v_set(var_t *dest, const var_t *src) { dest->v.i = src->v.i; break; case V_STR: - dest->v.p.size = strlen(src->v.p.ptr) + 1; + dest->v.p.size = v_strlen(src) + 1; dest->v.p.ptr = (char *)malloc(dest->v.p.size); strcpy(dest->v.p.ptr, src->v.p.ptr); break; diff --git a/src/common/var.h b/src/common/var.h index 5434b87d..5cccc9e2 100644 --- a/src/common/var.h +++ b/src/common/var.h @@ -651,6 +651,16 @@ void v_input2var(const char *str, var_t *var); */ char *v_getstr(var_t *v); +/** + * @ingroup var + * + * returns the length of the var string + * + * @param v is the variable + * @return the string length + */ +int v_strlen(const var_t *v); + /** * @ingroup var * diff --git a/src/common/var_eval.c b/src/common/var_eval.c index 15db01e5..1a642ed4 100644 --- a/src/common/var_eval.c +++ b/src/common/var_eval.c @@ -216,7 +216,11 @@ int code_isvar() { } if (var_p) { - if (kw_check_evexit(code_peek()) || code_peek() == kwTYPE_LEVEL_END) { + byte code = code_peek(); + if (code == kwTYPE_EOC || + code == kwTYPE_SEP || + code == kwTYPE_LEVEL_END || + kw_check_evexit(code)) { // restore IP prog_ip = cur_ip; return 1; diff --git a/src/languages/messages.en.h b/src/languages/messages.en.h index a6f32149..4e5712b8 100644 --- a/src/languages/messages.en.h +++ b/src/languages/messages.en.h @@ -172,7 +172,7 @@ #define EVAL_TYPE "Expr/RT: Type mismatch" #define EVAL_PARAM "Expr/RT: Invalid parameter" #define ERR_UNSUPPORTED "Unsupported" -#define ERR_CONST "LET: Cannot change a constant" +#define ERR_CONST "LET: Cannot change a constant (CONST always has global scope)" #define ERR_NOT_A_VAR "Not a variable" #define ERR_NOT_ARR_OR_FUNC "NOT an array OR function" #define ERR_RANGE "Out of range" diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index 7dc34b0c..83fa9ce3 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -19,6 +19,7 @@ using namespace strlib; String g_exportAddr; String g_exportToken; int cursorPos; +bool returnToLine; void onlineHelp(Runtime *runtime, TextEditInput *widget) { char path[100]; @@ -109,7 +110,12 @@ void System::editSource(String loadPath) { editWidget->updateUI(NULL, NULL); editWidget->setLineNumbers(); editWidget->setFocus(true); - editWidget->setCursorPos(cursorPos); + + if (isBreak() && returnToLine) { + editWidget->setCursorRow(gsb_last_line); + } else { + editWidget->setCursorPos(cursorPos); + } cursorPos = 0; if (gsb_last_error && !isBack()) { @@ -285,6 +291,12 @@ void System::editSource(String loadPath) { widget = helpWidget; showRecentFiles(helpWidget, loadPath); break; + case SB_KEY_ALT('.'): + returnToLine = !returnToLine; + _output->setStatus(returnToLine ? + "Position the cursor to the last program line after BREAK" : + "BREAK restores current cursor position"); + break; case SB_KEY_ALT('1'): case SB_KEY_ALT('2'): case SB_KEY_ALT('3'): diff --git a/src/ui/ansiwidget.h b/src/ui/ansiwidget.h index fe2d2866..32198328 100755 --- a/src/ui/ansiwidget.h +++ b/src/ui/ansiwidget.h @@ -51,6 +51,7 @@ struct AnsiWidget { int getColor() { return _back->_fg; } int getFontSize() { return _fontSize; } FormInput *getNextField(FormInput *field) { return _back->getNextField(field); } + int getPixel(int x, int y) { return _back->getPixel(x, y); } int getScreenWidth() { return _back->_width; } void getScroll(int &x, int &y) { _back->getScroll(x, y); } int getHeight() { return _height; } diff --git a/src/ui/form.cpp b/src/ui/form.cpp index b5527f6a..05972347 100644 --- a/src/ui/form.cpp +++ b/src/ui/form.cpp @@ -144,8 +144,10 @@ void cmd_form_do_events(var_s *self) { focusInput->edit(event.key, sw, charWidth)) { dev_clrkb(); out->setDirty(); - } else if (event.key == SB_KEY_MK_PUSH || event.key == SB_KEY_MK_RELEASE || - SB_KEY_CTRL(SB_KEY_UP) || SB_KEY_CTRL(SB_KEY_DOWN)) { + } else if (event.key == SB_KEY_MK_PUSH || + event.key == SB_KEY_MK_RELEASE || + event.key == (int)SB_KEY_CTRL(SB_KEY_UP) || + event.key == (int)SB_KEY_CTRL(SB_KEY_DOWN)) { // no exit on mouse events dev_clrkb(); } else { diff --git a/src/ui/inputs.h b/src/ui/inputs.h index 005f2a0d..0d085d10 100644 --- a/src/ui/inputs.h +++ b/src/ui/inputs.h @@ -44,6 +44,7 @@ using namespace strlib; #define CHOICE_BN_W 6 #define GRAY_BG_COL 0x4e4c46 #define LABEL_TEXT_COL 0xdfdbd2 +#define FOCUS_COLOR 0x444999 #define FORM_VALUE "value" #define FORM_INPUTS "inputs" diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp index 8d12d0c2..a29e1959 100644 --- a/src/ui/screen.cpp +++ b/src/ui/screen.cpp @@ -509,6 +509,28 @@ void GraphicScreen::drawRectFilled(int x1, int y1, int x2, int y2) { maFillRect(x1, y1, x2 - x1, y2 - y1); } +// returns the color of the pixel at the given xy location +int GraphicScreen::getPixel(int x, int y) { + MARect rc; + rc.left = x; + rc.top = y; + rc.width = 1; + rc.height = 1; + int data[1]; + int result; + + if (x < 0 || y < 0) { + rc.left = x < 0 ? -x : x; + rc.top = y < 0 ? -y : y; + drawBase(false); + maGetImageData(HANDLE_SCREEN, &data, &rc, 1); + } else { + maGetImageData(_image, &data, &rc, 1); + } + result = -(data[0] & 0x00FFFFFF); + return result; +} + // extend the image to allow for additional content on the newline void GraphicScreen::imageAppend(MAHandle newImage) { MARect srcRect; diff --git a/src/ui/screen.h b/src/ui/screen.h index 760d0bf9..de7bbb2d 100755 --- a/src/ui/screen.h +++ b/src/ui/screen.h @@ -37,6 +37,7 @@ struct Screen : public Shape { virtual void drawRect(int x1, int y1, int x2, int y2) = 0; virtual void drawRectFilled(int x1, int y1, int x2, int y2) = 0; virtual void newLine(int lineHeight) = 0; + virtual int getPixel(int x, int y) = 0; virtual int print(const char *p, int lineHeight, bool allChars=false); virtual bool setGraphicsRendition(const char c, int escValue, int lineHeight) = 0; virtual void setPixel(int x, int y, int c) = 0; @@ -100,6 +101,7 @@ struct GraphicScreen : public Screen { void drawLine(int x1, int y1, int x2, int y2); void drawRect(int x1, int y1, int x2, int y2); void drawRectFilled(int x1, int y1, int x2, int y2); + int getPixel(int x, int y); void imageScroll(); void imageAppend(MAHandle newImage); void newLine(int lineHeight); @@ -317,6 +319,7 @@ struct TextScreen : public Screen { void drawLine(int x1, int y1, int x2, int y2); void drawRect(int x1, int y1, int x2, int y2); void drawRectFilled(int x1, int y1, int x2, int y2); + int getPixel(int x, int y) { return 0; } void inset(int x, int y, int w, int h, Screen *over); void newLine(int lineHeight); int print(const char *p, int lineHeight, bool allChars=false); diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 15302957..644799eb 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -128,6 +128,7 @@ bool System::execute(const char *bas) { } opt_command[0] = '\0'; + opt_file_permitted = 1; _output->resetFont(); _output->flush(true); return result; @@ -192,6 +193,14 @@ char *System::getText(char *dest, int maxSize) { FormInput *widget = new FormLineInput(NULL, maxSize, true, x, y, w, h); widget->setFocus(true); + + int bg = _output->getBackgroundColor(); + int fg = _output->getColor(); + if (bg != DEFAULT_BACKGROUND || fg != DEFAULT_FOREGROUND) { + widget->setColor(bg, fg); + } else { + widget->setColor(FOCUS_COLOR, DEFAULT_FOREGROUND); + } _output->addInput(widget); _output->redraw(); _state = kModalState; @@ -462,6 +471,7 @@ char *System::loadResource(const char *fileName) { dev_fclose(handle); v_free(var_p); free(var_p); + opt_file_permitted = 0; } } return buffer; @@ -1084,17 +1094,7 @@ int osd_getpen(int mode) { } long osd_getpixel(int x, int y) { - g_system->getOutput()->redraw(); - - MARect rc; - int data[1]; - rc.left = x; - rc.top = y; - rc.width = 1; - rc.height = 1; - maGetImageData(HANDLE_SCREEN, &data, &rc, 1); - int result = -(data[0] & 0x00FFFFFF); - return result; + return g_system->getOutput()->getPixel(x, y); } int osd_getx(void) { diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index da0e679b..725608a9 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -52,9 +52,9 @@ const int theme1[] = { }; const int theme2[] = { - 0xcccccc, 0x000077, 0x333333, 0xa7aebc, 0x0000aa, 0x008888, + 0xcccccc, 0x000077, 0x333333, 0x333333, 0x0000aa, 0x008888, 0x010101, 0xeeeeee, 0x010101, 0xffff00, 0x00ff00, 0x010101, - 0x00ffff, 0xff00ff, 0xffffff, 0x00ffff, 0x007777 + 0x00ffff, 0xff00ff, 0xffffff, 0x00ffff, 0x00aaff }; const int theme3[] = { @@ -103,6 +103,7 @@ const char *helpText = "A-g goto line\n" "A-n trim line-endings\n" "A-t select theme\n" + "A-. break mode\n" "A- recent file\n" "SHIFT- select\n" "TAB indent line\n" @@ -1007,19 +1008,8 @@ void TextEditInput::editTab() { } // adjust indent for statement terminators - if (strncasecmp(buf + curIndent, "wend", 4) == 0 || - strncasecmp(buf + curIndent, "fi", 2) == 0 || - strncasecmp(buf + curIndent, "endif", 5) == 0 || - strncasecmp(buf + curIndent, "elseif ", 7) == 0 || - strncasecmp(buf + curIndent, "elif ", 5) == 0 || - strncasecmp(buf + curIndent, "else", 4) == 0 || - strncasecmp(buf + curIndent, "next", 4) == 0 || - strncasecmp(buf + curIndent, "case", 4) == 0 || - strncasecmp(buf + curIndent, "end", 3) == 0 || - strncasecmp(buf + curIndent, "until ", 6) == 0) { - if (indent >= _indentLevel) { - indent -= _indentLevel; - } + if (indent >= _indentLevel && endStatement(buf + curIndent)) { + indent -= _indentLevel; } if (curIndent < indent) { // insert additional spaces @@ -1053,6 +1043,35 @@ void TextEditInput::editTab() { free(buf); } +bool TextEditInput::endStatement(const char *buf) { + static const struct Holder { + const char *symbol; + int len; + } term[] = { + {"wend", 4}, + {"fi", 2}, + {"endif", 5}, + {"elseif ", 7}, + {"elif ", 5}, + {"else", 4}, + {"next", 4}, + {"case", 4}, + {"end", 3}, + {"until ", 6} + }; + static const int len = sizeof(term) / sizeof(Holder); + bool result = false; + for (int i = 0; i < len && !result; i++) { + if (strncasecmp(buf, term[i].symbol, term[i].len) == 0) { + char c = buf[term[i].len]; + if (c == '\0' || IS_WHITE(c)) { + result = true; + } + } + } + return result; +} + void TextEditInput::findMatchingBrace() { char cursorChar = _state.cursor < _buf._len ? _buf._buffer[_state.cursor] : '\0'; char cursorMatch = '\0'; diff --git a/src/ui/textedit.h b/src/ui/textedit.h index f02316b7..1b22d1d5 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -131,6 +131,7 @@ struct TextEditInput : public FormEditInput { void editDeleteLine(); void editEnter(); void editTab(); + bool endStatement(const char *buf); void findMatchingBrace(); int getCursorRow() const; uint32_t getHash(const char *str, int offs, int &count);