diff --git a/ChangeLog b/ChangeLog index 136bffaa..e0e633fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2017-11-28 (0.12.10/11) + COMMON: owner strings + 2017-11-28 (0.12.10) COMMON: Fix some coverty warnings diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index 0d5efde5..5f253d92 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -25,6 +25,7 @@ const setupId = "_setup" const aboutId = "_about" const backId = "_back" const scratchId = "_scratch" +const scratch_file = HOME + "scratch.bas" func mk_bn(value, lab, fg) local bn @@ -50,10 +51,9 @@ end func mk_scratch() local text - local file = "scratch.bas" local result = false - if (not exist(file)) then + if (not exist(scratch_file)) then dim text text << "rem Welcome to SmallBASIC" text << "rem" @@ -66,7 +66,7 @@ func mk_scratch() text << "rem Press the 3 vertical dots for menu options." endif try - tsave file, text + tsave scratch_file, text result = true catch e local wnd = window() @@ -232,6 +232,7 @@ end sub loadFileList(path, byref basList) erase basList + local emptyNode func walker(node) if (node.depth==0) then @@ -246,6 +247,14 @@ sub loadFileList(path, byref basList) return node.depth == 0 end dirwalk path, "", use walker(x) + + if (path = "/" && len(basList) == 0 && !is_sdl) then + emptyNode.name = "sdcard" + emptyNode.dir = true + emptyNode.size = "" + emptyNode.mtime = 0 + basList << emptyNode + endif end sub listFiles(byref frm, path, sortDir, byref basList) @@ -641,7 +650,7 @@ sub main frm = makeUI(path, sortDir) elif frm.value == scratchId then if (mk_scratch()) - frm.close("scratch.bas") + frm.close(scratch_file) endif elif frm.value == backId then cls diff --git a/samples/distro-examples/games/sokoban.bas b/samples/distro-examples/games/sokoban.bas index 926745b8..b0397fb6 100644 --- a/samples/distro-examples/games/sokoban.bas +++ b/samples/distro-examples/games/sokoban.bas @@ -383,6 +383,7 @@ sub main frm.inputs(0).value = game_names frm.inputs(1).label = "Open" frm.inputs(2).label = "Play" + frm.focus = 0 frm = form(frm) end diff --git a/samples/distro-examples/tests/output/array.out b/samples/distro-examples/tests/output/array.out index a758914a..eeeca324 100644 --- a/samples/distro-examples/tests/output/array.out +++ b/samples/distro-examples/tests/output/array.out @@ -1,2 +1,2 @@ TEST: Arrays, unound, lbound -array: {"cat":{"name":"lots"},"zz":"thing","zz":"memleak","other":"thing"} +array: {"cat":{"name":"lots"},"zz":"memleak","other":"thing"} diff --git a/src/common/bc.c b/src/common/bc.c index b9348fcb..063b0298 100644 --- a/src/common/bc.c +++ b/src/common/bc.c @@ -174,12 +174,13 @@ void bc_add_creal(bc_t *bc, var_num_t v) { */ void bc_add_strn(bc_t *bc, const char *str, int len) { bc_add_code(bc, kwTYPE_STR); - bc_add_dword(bc, len); + bc_add_dword(bc, len + 1); if (bc->count + len >= bc->size) { bc_resize(bc, bc->size + BC_ALLOC_INCR + len); } memcpy(bc->ptr + bc->count, str, len); bc->count += len; + bc_add1(bc, 0); } /* diff --git a/src/common/blib.c b/src/common/blib.c index 66b9f4b5..2c9e2426 100644 --- a/src/common/blib.c +++ b/src/common/blib.c @@ -562,6 +562,7 @@ void cmd_print(int output) { vuser_p->type = V_STR; vuser_p->v.p.ptr = NULL; vuser_p->v.p.length = 0; + vuser_p->v.p.owner = 1; handle = (intptr_t)vuser_p; } @@ -1964,6 +1965,7 @@ void cmd_read() { prog_dp += OS_STRLEN; vp->v.p.ptr = malloc(len + 1); + vp->v.p.owner = 1; memcpy(vp->v.p.ptr, prog_source + prog_dp, len); *((char *) (vp->v.p.ptr + len)) = '\0'; vp->v.p.length = len; @@ -2288,6 +2290,7 @@ void cmd_wjoin() { v_free(str); str->type = V_STR; str->v.p.ptr = malloc(size); + str->v.p.owner = 1; str->v.p.ptr[0] = '\0'; for (i = 0; i < v_asize(var_p); i++) { diff --git a/src/common/blib_db.c b/src/common/blib_db.c index 7c1021be..5d9b1e98 100644 --- a/src/common/blib_db.c +++ b/src/common/blib_db.c @@ -589,8 +589,7 @@ void cmd_floadln() { // build var for line var_p = v_elem(array_p, index); int size = GROW_SIZE; - var_p->type = V_STR; - var_p->v.p.ptr = malloc(size); + v_init_str(var_p, size); index++; // process the next line @@ -654,9 +653,7 @@ void cmd_floadln() { } else { // if type=1 // build string v_free(var_p); - var_p->type = V_STR; - var_p->v.p.length = dev_flength(handle) + 1; - var_p->v.p.ptr = malloc(var_p->v.p.length); + v_init_str(var_p, dev_flength(handle)); if (var_p->v.p.length > 1) { dev_fread(handle, (byte *)var_p->v.p.ptr, var_p->v.p.length - 1); } diff --git a/src/common/blib_func.c b/src/common/blib_func.c index ae319f50..5ef49f4d 100644 --- a/src/common/blib_func.c +++ b/src/common/blib_func.c @@ -933,8 +933,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // str <- CBS$(str) // convert C-Style string to BASIC-style string // - v_tostr(arg); - IF_ERR_RETURN; r->v.p.ptr = cstrdup(arg->v.p.ptr); r->v.p.length = strlen(r->v.p.ptr) + 1; break; @@ -943,9 +941,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // str <- BCS$(str) // convert BASIC-Style string to C-style string // - v_tostr(arg); - IF_ERR_RETURN; - r->v.p.ptr = bstrdup(arg->v.p.ptr); r->v.p.length = strlen(r->v.p.ptr) + 1; break; @@ -988,8 +983,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // // str <- LCASE$(s) // - v_tostr(arg); - IF_ERR_RETURN; r->v.p.ptr = (char *)malloc(strlen(arg->v.p.ptr) + 1); strcpy(r->v.p.ptr, arg->v.p.ptr); p = r->v.p.ptr; @@ -1003,8 +996,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // // str <- UCASE$(s) // - v_tostr(arg); - IF_ERR_RETURN; r->v.p.ptr = (char *)malloc(strlen(arg->v.p.ptr) + 1); strcpy(r->v.p.ptr, arg->v.p.ptr); p = r->v.p.ptr; @@ -1018,8 +1009,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // // str <- LTRIM$(s) // - v_tostr(arg); - IF_ERR_RETURN; p = arg->v.p.ptr; while (is_wspace(*p)) { p++; @@ -1036,8 +1025,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // // str <- RTRIM$(s) // - v_tostr(arg); - IF_ERR_RETURN; p = arg->v.p.ptr; if (*p != '\0') { while (*p) { @@ -1144,8 +1131,6 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // // str <- ENVIRON$(str) // - v_tostr(arg); - IF_ERR_RETURN; if (*arg->v.p.ptr != '\0') { // return the variable const char *v = dev_getenv(arg->v.p.ptr); @@ -1293,6 +1278,7 @@ void cmd_str0(long funcCode, var_t *r) { tms = *localtime(&now); r->type = V_STR; r->v.p.ptr = malloc(32); + r->v.p.owner = 1; sprintf(r->v.p.ptr, "%02d/%02d/%04d", tms.tm_mday, tms.tm_mon + 1, tms.tm_year + 1900); r->v.p.length = strlen(r->v.p.ptr) + 1; break; @@ -1304,6 +1290,7 @@ void cmd_str0(long funcCode, var_t *r) { tms = *localtime(&now); r->type = V_STR; r->v.p.ptr = malloc(32); + r->v.p.owner = 1; sprintf(r->v.p.ptr, "%02d:%02d:%02d", tms.tm_hour, tms.tm_min, tms.tm_sec); r->v.p.length = strlen(r->v.p.ptr) + 1; break; @@ -2216,9 +2203,7 @@ void cmd_genfunc(long funcCode, var_t *r) { if (funcCode == kwDATEFMT) { // format - r->type = V_STR; - r->v.p.ptr = date_fmt(arg.v.p.ptr, d, m, y); - r->v.p.length = strlen(r->v.p.ptr) + 1; + v_move_str(r, date_fmt(arg.v.p.ptr, d, m, y)); v_free(&arg); } else { // weekday @@ -2247,6 +2232,7 @@ void cmd_genfunc(long funcCode, var_t *r) { r->type = V_STR; r->v.p.ptr = malloc((count << 1) + 1); r->v.p.ptr[0] = '\0'; + r->v.p.owner = 1; len = 0; char tmp[3]; for (int i = 0; i < count; i++) { @@ -2279,9 +2265,7 @@ void cmd_genfunc(long funcCode, var_t *r) { r->v.p.ptr[len] = '\0'; } else { // file - r->type = V_STR; - r->v.p.ptr = malloc(count + 1); - r->v.p.length = count + 1; + v_init_str(r, count); dev_fread(handle, (byte *)r->v.p.ptr, count); r->v.p.ptr[count] = '\0'; } @@ -2837,9 +2821,7 @@ void cmd_genfunc(long funcCode, var_t *r) { // add the entries for (int i = 0; i < count; i++) { var_t *elem_p = v_elem(r, i); - elem_p->type = V_STR; - elem_p->v.p.length = strlen(list[i]) + 1; - elem_p->v.p.ptr = malloc(elem_p->v.p.length); + v_init_str(elem_p, strlen(list[i])); strcpy(elem_p->v.p.ptr, list[i]); } } else { diff --git a/src/common/brun.c b/src/common/brun.c index 1ffff5fe..4c0cbaa1 100644 --- a/src/common/brun.c +++ b/src/common/brun.c @@ -269,37 +269,38 @@ void exec_setup_predefined_variables() { setsysvar_var(SYSVAR_NONE, 0, V_NIL); setsysvar_num(SYSVAR_MAXINT, VAR_MAX_INT); -#if defined(_UnixOS) +#if defined(_ANDROID) + strcpy(homedir, "/sdcard/"); +#else +#if defined(_Win32) + if (getenv("HOMEPATH")) { + strlcpy(homedir, getenv("HOMEPATH"), sizeof(homedir)); + } + else { + GetModuleFileName(NULL, homedir, sizeof(homedir) - 1); + char *p = strrchr(homedir, '\\'); + if (p) { + *p = '\0'; + } + } + for (char *p = homedir; *p; p++) { + if (*p == '\\') { + *p = '/'; + } + } +#elif defined(_UnixOS) if (getenv("HOME")) { strlcpy(homedir, getenv("HOME"), sizeof(homedir)); } else { strcpy(homedir, "/tmp/"); } +#endif int l = strlen(homedir); if (homedir[l - 1] != OS_DIRSEP) { homedir[l] = OS_DIRSEP; homedir[l + 1] = '\0'; } -#elif defined(_Win32) - if (getenv("HOME")) { - // this works on cygwin - strlcpy(homedir, getenv("HOME"), sizeof(homedir)); - } - else { - GetModuleFileName(NULL, homedir, sizeof(homedir) - 1); - char *p = strrchr(homedir, '\\'); - *p = '\0'; - strcat(homedir, "\\"); - if (OS_DIRSEP == '/') { - p = homedir; - while (*p) { - if (*p == '\\') - *p = '/'; - p++; - } - } - } #endif setsysvar_str(SYSVAR_HOME, homedir); } @@ -1643,7 +1644,8 @@ void sbasic_exec_prepare(const char *filename) { * remember the directory location of the running program */ void sbasic_set_bas_dir(const char *bas_file) { - int path_len = strrchr(bas_file, OS_DIRSEP) - bas_file; + const char *sep = strrchr(bas_file, OS_DIRSEP); + int path_len = sep == NULL ? 0 : (sep - bas_file); char cwd[OS_PATHNAME_SIZE + 1]; cwd[0] = '\0'; diff --git a/src/common/eval.c b/src/common/eval.c index e2bc0c8d..3dab1f09 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -795,6 +795,7 @@ static inline void eval_push(var_t *r) { len = r->v.p.length; eval_stk[eval_sp].type = V_STR; eval_stk[eval_sp].v.p.ptr = malloc(len + 1); + eval_stk[eval_sp].v.p.owner = 1; strcpy(eval_stk[eval_sp].v.p.ptr, r->v.p.ptr); eval_stk[eval_sp].v.p.length = len; break; @@ -852,6 +853,7 @@ static inline void eval_callf_str1(long fcode, var_t *r) { IP++; r->type = V_STR; r->v.p.ptr = NULL; + r->v.p.owner = 1; cmd_str1(fcode, &vtmp, r); v_free(&vtmp); } @@ -865,6 +867,7 @@ static inline void eval_callf_strn(long fcode, var_t *r) { err_missing_lp(); } else { r->type = V_STR; + r->v.p.owner = 1; r->v.p.ptr = NULL; IP++; // '(' cmd_strN(fcode, r); diff --git a/src/common/fs_socket_client.c b/src/common/fs_socket_client.c index 0371fd91..3d825268 100644 --- a/src/common/fs_socket_client.c +++ b/src/common/fs_socket_client.c @@ -153,6 +153,7 @@ int http_read(dev_file_t *f, var_t *var_p) { if (rxbuff[i + 2] == '\n') { var_p->v.p.length = bytes - i - 3; var_p->v.p.ptr = malloc(var_p->v.p.length + 1); + var_p->v.p.owner = 1; memcpy(var_p->v.p.ptr, rxbuff + i + 3, var_p->v.p.length); var_p->v.p.ptr[var_p->v.p.length] = 0; inHeader = 0; diff --git a/src/common/hashmap.c b/src/common/hashmap.c index 605f5508..ff5363e8 100644 --- a/src/common/hashmap.c +++ b/src/common/hashmap.c @@ -56,7 +56,15 @@ void tree_delete_node(Node *node) { } static inline int tree_compare(const char *key, int length, var_p_t vkey) { - return strcaselessn(key, length, vkey->v.p.ptr, vkey->v.p.length - 1); + int len1 = length; + if (len1 && key[len1 - 1] == '\0') { + len1--; + } + int len2 = vkey->v.p.length; + if (len2 && vkey->v.p.ptr[len2 - 1] == '\0') { + len2--; + } + return strcaselessn(key, len1, vkey->v.p.ptr, len2); } void tree_destroy(Node *node) { @@ -195,6 +203,21 @@ var_p_t hashmap_put(var_p_t map, const char *key, int length) { return node->value; } +var_p_t hashmap_putc(var_p_t map, const char *key, int length) { + Node *node = hashmap_search(map, key, length); + if (node->key == NULL) { + var_t *var_key = v_new(); + var_key->type = V_STR; + var_key->v.p.length = length; + var_key->v.p.ptr = (char *)key; + var_key->v.p.owner = 0; + node->key = var_key; + node->value = v_new(); + map->v.m.count++; + } + return node->value; +} + var_p_t hashmap_putv(var_p_t map, const var_p_t key) { // hashmap takes ownership of key if (key->type != V_STR) { diff --git a/src/common/hashmap.h b/src/common/hashmap.h index a5617384..70ae73f2 100644 --- a/src/common/hashmap.h +++ b/src/common/hashmap.h @@ -29,6 +29,7 @@ typedef int (*hashmap_foreach_func)(hashmap_cb *cb, var_p_t k, var_p_t v); void hashmap_create(var_p_t map, int size); int hashmap_destroy(var_p_t map); var_p_t hashmap_put(var_p_t map, const char *key, int length); +var_p_t hashmap_putc(var_p_t map, const char *key, int length); var_p_t hashmap_putv(var_p_t map, const var_p_t key); var_p_t hashmap_get(var_p_t map, const char *key); void hashmap_foreach(var_p_t map, hashmap_foreach_func func, hashmap_cb *data); diff --git a/src/common/hotspots.h b/src/common/hotspots.h index 11e0a5b2..998ee8b1 100644 --- a/src/common/hotspots.h +++ b/src/common/hotspots.h @@ -206,7 +206,9 @@ static inline void v_detach(var_t *v) { static inline void v_free(var_t *v) { switch (v->type) { case V_STR: - free(v->v.p.ptr); + if (v->v.p.owner) { + free(v->v.p.ptr); + } break; case V_ARRAY: v_array_free(v); diff --git a/src/common/proc.c b/src/common/proc.c index 120f269e..2e99ebbb 100644 --- a/src/common/proc.c +++ b/src/common/proc.c @@ -183,6 +183,7 @@ void pv_write(char *str, int method, int handle) { vp->v.p.length += strlen(str); if (vp->v.p.ptr == NULL) { vp->v.p.ptr = malloc(vp->v.p.length + 1); + vp->v.p.owner = 1; strcpy((char *)vp->v.p.ptr, str); } else { vp->v.p.ptr = realloc(vp->v.p.ptr, vp->v.p.length + 1); diff --git a/src/common/var.c b/src/common/var.c index 5c4b6fd2..2ad3988c 100644 --- a/src/common/var.c +++ b/src/common/var.c @@ -83,6 +83,21 @@ void v_array_free(var_t *var) { } } +void v_init_str(var_t *var, int length) { + var->type = V_STR; + var->v.p.ptr = malloc(length + 1); + var->v.p.ptr[0] = '\0'; + var->v.p.length = length + 1; + var->v.p.owner = 1; +} + +void v_move_str(var_t *var, char *str) { + var->type = V_STR; + var->v.p.ptr = str; + var->v.p.length = strlen(str) + 1; + var->v.p.owner = 1; +} + /* * returns true if the user's program must use this var as an empty var * this is usefull for arrays @@ -385,12 +400,9 @@ void v_add(var_t *result, var_t *a, var_t *b) { if (a->type == V_STR && b->type == V_STR) { int length = strlen(a->v.p.ptr) + strlen(b->v.p.ptr); - result->type = V_STR; - result->v.p.ptr = malloc(length + 1); + v_init_str(result, length); strcpy(result->v.p.ptr, a->v.p.ptr); strcat(result->v.p.ptr, b->v.p.ptr); - result->v.p.ptr[length] = '\0'; - result->v.p.length = length + 1; return; } else if (a->type == V_INT && b->type == V_INT) { result->type = V_INT; @@ -417,8 +429,7 @@ void v_add(var_t *result, var_t *a, var_t *b) { result->v.n = b->v.n + v_getval(a); } } else { - result->type = V_STR; - result->v.p.ptr = (char *)malloc(strlen(a->v.p.ptr) + INT_STR_LEN); + v_init_str(result, strlen(a->v.p.ptr) + INT_STR_LEN); strcpy(result->v.p.ptr, a->v.p.ptr); if (b->type == V_INT) { ltostr(b->v.i, tmpsb); @@ -437,8 +448,7 @@ void v_add(var_t *result, var_t *a, var_t *b) { result->v.n = a->v.n + v_getval(b); } } else { - result->type = V_STR; - result->v.p.ptr = (char *)malloc(strlen(b->v.p.ptr) + INT_STR_LEN); + v_init_str(result, strlen(b->v.p.ptr) + INT_STR_LEN); if (a->type == V_INT) { ltostr(a->v.i, tmpsb); } else { @@ -472,9 +482,16 @@ void v_set(var_t *dest, const var_t *src) { dest->v.n = src->v.n; break; case V_STR: - dest->v.p.length = v_strlen(src) + 1; - dest->v.p.ptr = (char *)malloc(dest->v.p.length); - strcpy(dest->v.p.ptr, src->v.p.ptr); + if (src->v.p.owner) { + dest->v.p.length = v_strlen(src) + 1; + dest->v.p.ptr = (char *)malloc(dest->v.p.length); + dest->v.p.owner = 1; + strcpy(dest->v.p.ptr, src->v.p.ptr); + } else { + dest->v.p.length = src->v.p.length; + dest->v.p.ptr = src->v.p.ptr; + dest->v.p.owner = 0; + } break; case V_ARRAY: if (src->v.a.size) { @@ -488,7 +505,7 @@ void v_set(var_t *dest, const var_t *src) { v_set(dest_vp, v_elem(src, i)); } } else { - v_init_array(dest); + v_init_array(dest); } break; case V_PTR: @@ -531,6 +548,7 @@ void v_move(var_t *dest, const var_t *src) { case V_STR: dest->v.p.ptr = src->v.p.ptr; dest->v.p.length = src->v.p.length; + dest->v.p.owner = src->v.p.owner; break; case V_ARRAY: memcpy(&dest->v.a, &src->v.a, sizeof(src->v.a)); @@ -600,10 +618,7 @@ int v_sign(var_t *x) { * setup a string variable */ void v_createstr(var_t *v, const char *src) { - int l = strlen(src) + 1; - v->type = V_STR; - v->v.p.ptr = malloc(l); - v->v.p.length = l; + v_init_str(v, strlen(src)); strcpy(v->v.p.ptr, src); } @@ -651,12 +666,8 @@ char *v_str(var_t *arg) { void v_tostr(var_t *arg) { if (arg->type != V_STR) { char *tmp = v_str(arg); - int len = strlen(tmp) + 1; - v_free(arg); - arg->type = V_STR; - arg->v.p.ptr = malloc(len); - arg->v.p.length = len; + v_init_str(arg, strlen(tmp)); strcpy(arg->v.p.ptr, tmp); free(tmp); } @@ -665,38 +676,43 @@ void v_tostr(var_t *arg) { /* * set the value of 'var' to string */ -void v_setstr(var_t *var, const char *string) { - if (var->type != V_STR || strcmp(string, var->v.p.ptr) != 0) { +void v_setstr(var_t *var, const char *str) { + if (var->type != V_STR || strcmp(str, var->v.p.ptr) != 0) { v_free(var); - var->type = V_STR; - var->v.p.length = strlen(string) + 1; - var->v.p.ptr = malloc(var->v.p.length); - strcpy(var->v.p.ptr, string); + v_init_str(var, strlen(str)); + strcpy(var->v.p.ptr, str); } } -void v_setstrn(var_t *var, const char *string, int len) { - if (var->type != V_STR || strncmp(string, var->v.p.ptr, len) != 0) { +void v_setstrn(var_t *var, const char *str, int len) { + if (var->type != V_STR || strncmp(str, var->v.p.ptr, len) != 0) { v_free(var); - var->type = V_STR; - var->v.p.length = len + 1; - var->v.p.ptr = malloc(var->v.p.length); - strncpy(var->v.p.ptr, string, len); - var->v.p.ptr[len] = '\0'; + v_init_str(var, len); + strlcpy(var->v.p.ptr, str, len + 1); } } /* * adds a string to current string value */ -void v_strcat(var_t *var, const char *string) { +void v_strcat(var_t *var, const char *str) { if (var->type == V_INT || var->type == V_NUM) { v_tostr(var); } if (var->type == V_STR) { - var->v.p.length = strlen(var->v.p.ptr) + strlen(string) + 1; - var->v.p.ptr = realloc(var->v.p.ptr, var->v.p.length); - strcat(var->v.p.ptr, string); + if (var->v.p.owner) { + var->v.p.length = strlen(var->v.p.ptr) + strlen(str) + 1; + var->v.p.ptr = realloc(var->v.p.ptr, var->v.p.length); + strcat(var->v.p.ptr, str); + } else { + // mutate into owner string + char *p = var->v.p.ptr; + int len = var->v.p.length + strlen(str); + v_init_str(var, len); + strcpy(var->v.p.ptr, p); + strcat(var->v.p.ptr, str); + } + } else { err_typemismatch(); } @@ -735,10 +751,8 @@ char *v_getstr(var_t *var) { */ void v_zerostr(var_t *r) { v_free(r); - r->type = V_STR; - r->v.p.ptr = malloc(1); + v_init_str(r, 0); r->v.p.ptr[0] = '\0'; - r->v.p.length = 1; } /* diff --git a/src/common/var.h b/src/common/var.h index 8f75d469..b6d50342 100644 --- a/src/common/var.h +++ b/src/common/var.h @@ -109,6 +109,7 @@ typedef struct var_s { struct { char *ptr; /**< data ptr (possibly, string pointer) */ uint32_t length; /**< the string length */ + byte owner; } p; // array @@ -276,6 +277,20 @@ void v_new_array(var_t *var, unsigned size); */ void v_array_free(var_t *var); +/** + * @ingroup var + * + * initialise the variable as a string of the given length + */ +void v_init_str(var_t *var, int length); + +/** + * @ingroup var + * + * takes ownership of the given allocated string + */ +void v_move_str(var_t *var, char *str); + /** * @ingroup var * diff --git a/src/common/var_eval.c b/src/common/var_eval.c index 8395d3e5..fb41136b 100644 --- a/src/common/var_eval.c +++ b/src/common/var_eval.c @@ -340,9 +340,8 @@ void v_eval_str(var_p_t v) { int len = code_getstrlen(); v->type = V_STR; v->v.p.length = len; - v->v.p.ptr = malloc(len + 1); - memcpy(v->v.p.ptr, &prog_source[prog_ip], len); - *((char *)(v->v.p.ptr + len)) = '\0'; + v->v.p.ptr = (char *)&prog_source[prog_ip]; + v->v.p.owner = 0; prog_ip += len; } diff --git a/src/common/var_map.c b/src/common/var_map.c index f26f166f..a5372fed 100644 --- a/src/common/var_map.c +++ b/src/common/var_map.c @@ -208,7 +208,7 @@ var_p_t map_resolve_fields(var_p_t base, var_p_t *parent) { int len = code_getstrlen(); const char *key = (const char *)&prog_source[prog_ip]; prog_ip += len; - field = hashmap_put(base, key, len); + field = hashmap_putc(base, key, len); if (parent != NULL) { *parent = base; } diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 50a66180..3cc0582c 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -933,24 +933,35 @@ void System::editSource(strlib::String loadPath) { int charWidth = _output->getCharWidth(); int charHeight = _output->getCharHeight(); int prevScreenId = _output->selectScreen(SOURCE_SCREEN); - TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); + TextEditInput *editWidget; + if (_editor != NULL) { + editWidget = _editor; + editWidget->_width = w; + editWidget->_height = h; + } else { + editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); + } TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight, false); TextEditInput *widget = editWidget; _modifiedTime = getModifiedTime(); editWidget->updateUI(NULL, NULL); editWidget->setLineNumbers(); editWidget->setFocus(true); - if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { - editWidget->setCursorRow(gsb_last_line - 1); - } - if (gsb_last_error && !isBack()) { - editWidget->setCursorRow(gsb_last_line - 1); - runtime->alert(gsb_last_errmsg); - } - _srcRendered = false; + _output->clearScreen(); _output->addInput(editWidget); _output->addInput(helpWidget); + + if (gsb_last_line && isBreak()) { + String msg = "Break at line: "; + msg.append(gsb_last_line); + runtime->alert(msg); + } else if (gsb_last_error && !isBack()) { + // program stopped with an error + editWidget->setCursorRow(gsb_last_line + editWidget->getSelectionRow() - 1); + runtime->alert(gsb_last_errmsg); + } + _srcRendered = false; _output->setStatus(cleanFile); _output->redraw(); _state = kEditState; @@ -1058,6 +1069,18 @@ void System::editSource(strlib::String loadPath) { } } + if (_state == kRunState) { + // allow the editor to be restored on return + if (!_output->removeInput(editWidget)) { + trace("Failed to remove editor input"); + } + _editor = editWidget; + _editor->setFocus(false); + } else { + _editor = NULL; + } + + // deletes editWidget unless it has been removed _output->removeInputs(); if (!isClosing()) { _output->selectScreen(prevScreenId); @@ -1170,7 +1193,9 @@ int sensor_off(int param_count, slib_par_t *params, var_t *retval) { int tts_speak(int param_count, slib_par_t *params, var_t *retval) { int result; - if (param_count == 1 && v_is_type(params[0].var_p, V_STR)) { + if (opt_mute_audio) { + result = 1; + } else if (param_count == 1 && v_is_type(params[0].var_p, V_STR)) { runtime->speak(v_getstr(params[0].var_p)); result = 1; } else { diff --git a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java index 700861ae..6d4cd727 100644 --- a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java @@ -444,11 +444,12 @@ public void run() { } } - public void setTtsLocale(String locale) { + public void setTtsLocale(final byte[] localeBytes) { if (_tts == null) { _tts = new TextToSpeechAdapter(this, ""); } try { + final String locale = new String(localeBytes, CP1252); _tts.setLocale(new Locale(locale)); } catch (Exception e) { Log.i(TAG, "setttsLocale failed:", e); diff --git a/src/platform/console/main.c b/src/platform/console/main.c index bbb426ca..2f078f0b 100644 --- a/src/platform/console/main.c +++ b/src/platform/console/main.c @@ -253,6 +253,14 @@ int process_options(int argc, char *argv[]) { return 1; } +#if defined(__GNUC__) +// for analysing excessive malloc calls using kdbg +extern void *__libc_malloc(size_t size); +void* malloc (size_t size) { + return __libc_malloc(size); +} +#endif + /* * program entry point */ diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index f5e1ce05..d448dbc7 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -95,14 +95,14 @@ void onlineHelp(Runtime *runtime, TextEditInput *widget) { char path[100]; const char *nodeId = widget->getNodeId(); if (nodeId != NULL && nodeId[0] != '0') { - sprintf(path, "http://smallbasic.sf.net/?q=node/%s", nodeId); + sprintf(path, "https://smallbasic.sourceforge.io?q=node/%s", nodeId); } else { char *selection = widget->getWordBeforeCursor(); if (selection != NULL) { - sprintf(path, "http://smallbasic.sf.net/?q=search/node/%s", selection); + sprintf(path, "https://smallbasic.sourceforge.io?q=search/node/%s", selection); free(selection); } else { - sprintf(path, "http://smallbasic.sf.net"); + sprintf(path, "https://smallbasic.sourceforge.io"); } } runtime->browseFile(path); diff --git a/src/ui/form.cpp b/src/ui/form.cpp index 7030828a..4e7e0b7f 100644 --- a/src/ui/form.cpp +++ b/src/ui/form.cpp @@ -178,16 +178,16 @@ void cmd_form_do_events(var_s *self) { } } } - form = NULL; } } int get_selected_index(var_p_t v_field) { var_p_t value = map_get(v_field, FORM_INPUT_INDEX); - int result = 0; + int result; if (value == NULL) { - value = map_add_var(v_field, FORM_INPUT_INDEX, result); + result = 0; + map_add_var(v_field, FORM_INPUT_INDEX, result); } else { result = v_getint(value); } diff --git a/src/ui/system.cpp b/src/ui/system.cpp index baabcd9e..d0b224db 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -610,7 +610,9 @@ void System::runMain(const char *mainBasPath) { if (fileExists(_loadPath)) { _mainBas = false; activePath = _loadPath; - setupPath(_loadPath); + if (!isEditReady()) { + setupPath(_loadPath); + } } else { _mainBas = true; _loadPath = mainBasPath; @@ -618,8 +620,7 @@ void System::runMain(const char *mainBasPath) { } } - if (!_mainBas && !isRestart() && isEditEnabled() && - !isNetworkLoad() && loadSource(_loadPath)) { + if (!_mainBas && isEditReady() && loadSource(_loadPath)) { editSource(_loadPath); if (isBack()) { _loadPath.clear(); diff --git a/src/ui/system.h b/src/ui/system.h index 12015fc4..16de4a62 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -29,17 +29,17 @@ struct System { int getPen(int code); char *getText(char *dest, int maxSize); - bool isActive() { return _state != kInitState && _state != kDoneState; } - bool isBack() { return _state == kBackState; } - bool isBreak() { return _state >= kBreakState; } - bool isClosing() { return _state >= kClosingState; } - bool isEditing() { return _state == kEditState; } - bool isInitial() { return _state == kInitState; } - bool isModal() { return _state == kModalState; } - bool isRestart() { return _state == kRestartState; } - bool isRunning() { return _state == kRunState || _state == kModalState; } - bool isThreadActive() { return _state == kActiveState; } - bool isSystemScreen() { return _userScreenId != -1; } + bool isActive() const { return _state != kInitState && _state != kDoneState; } + bool isBack() const { return _state == kBackState; } + bool isBreak() const { return _state >= kBreakState; } + bool isClosing() const { return _state >= kClosingState; } + bool isEditing() const { return _state == kEditState; } + bool isInitial() const { return _state == kInitState; } + bool isModal() const { return _state == kModalState; } + bool isRestart() const { return _state == kRestartState; } + bool isRunning() const { return _state == kRunState || _state == kModalState; } + bool isThreadActive() const { return _state == kActiveState; } + bool isSystemScreen() const { return _userScreenId != -1; } void logStack(const char *keyword, int type, int line); char *readSource(const char *fileName); void setBack(); @@ -81,6 +81,7 @@ struct System { void handleEvent(MAEvent &event); void handleMenu(MAEvent &event); bool isEditEnabled() const {return opt_ide == IDE_INTERNAL || isScratchLoad();} + bool isEditReady() const {return !isRestart() && isEditEnabled() && !isNetworkLoad();} bool isNetworkLoad() const {return _loadPath.indexOf("://", 1) != -1;} bool isScratchLoad() const {return _loadPath.indexOf("scratch", 0) != -1;} bool loadSource(const char *fileName);