diff --git a/ChangeLog b/ChangeLog index 4bc7758a..d7b158e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-12-28 (0.12.15) + Fix crash when using GOTO with a non-existent label + Fix crash in editor when double tapping empty document + Fix menu display on chromebook and other devices + 2018-11-11 (0.12.14) CONSOLE: added support for IMAGE command diff --git a/configure.ac b/configure.ac index f9af3299..af504e20 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ dnl This program is distributed under the terms of the GPL v2.0 dnl Download the GNU Public License (GPL) from www.gnu.org dnl -AC_INIT([smallbasic], [0.12.14]) +AC_INIT([smallbasic], [0.12.15]) AC_CONFIG_SRCDIR([configure.ac]) AC_CANONICAL_TARGET diff --git a/debian/changelog b/debian/changelog index a2711668..259597e6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,8 @@ +smallbasic (0.12.15) unstable; urgency=low + * Various see web site + + -- Chris Warren-Smith Fri, 28 Dec 2018 09:45:25 +1000 + smallbasic (0.12.14) unstable; urgency=low * Various see web site diff --git a/samples/distro-examples/tests/goto.bas b/samples/distro-examples/tests/goto.bas new file mode 100644 index 00000000..73644546 --- /dev/null +++ b/samples/distro-examples/tests/goto.bas @@ -0,0 +1,2 @@ +REM Don't crash when label does not exist +goto 1 diff --git a/samples/distro-examples/tests/output/goto.out b/samples/distro-examples/tests/output/goto.out new file mode 100644 index 00000000..63d021d2 --- /dev/null +++ b/samples/distro-examples/tests/output/goto.out @@ -0,0 +1,6 @@ + + + * COMP-ERROR AT Main:2 * +Description: +Label '1' is not defined + diff --git a/src/common/scan.c b/src/common/scan.c index 63e1cbd5..16776038 100644 --- a/src/common/scan.c +++ b/src/common/scan.c @@ -3401,7 +3401,7 @@ void comp_pass2_scan() { w = label->ip; // adjust the address to compensate for optimisation to remove adjoining kwEOC - if (comp_prog.ptr[w] != kwTYPE_LINE && comp_prog.ptr[w - 1] == kwTYPE_LINE) { + if (w > 0 && w < comp_prog.count && comp_prog.ptr[w] != kwTYPE_LINE && comp_prog.ptr[w - 1] == kwTYPE_LINE) { w--; } memcpy(comp_prog.ptr + node->pos + (j * ADDRSZ) + (ADDRSZ + ADDRSZ + 3), &w, ADDRSZ); @@ -3419,7 +3419,7 @@ void comp_pass2_scan() { w = label->ip; // adjust the address to compensate for optimisation to remove adjoining kwEOC - if (comp_prog.ptr[w] != kwTYPE_LINE && comp_prog.ptr[w - 1] == kwTYPE_LINE) { + if (w > 0 && w < comp_prog.count && comp_prog.ptr[w] != kwTYPE_LINE && comp_prog.ptr[w - 1] == kwTYPE_LINE) { w--; } @@ -3697,12 +3697,14 @@ bcip_t comp_optimise_line_goto(bcip_t ip) { ip = comp_read_goto(ip + 1, &addr, &level); bcip_t goto_ip = addr; - if (comp_prog.ptr[goto_ip] == kwTYPE_EOC) { + + // note: INVALID_ADDR is assumed to be > comp_prog.count + if (goto_ip < comp_prog.count && comp_prog.ptr[goto_ip] == kwTYPE_EOC) { new_addr = goto_ip + 1; } - while (goto_ip > 0 && comp_prog.ptr[goto_ip] == kwTYPE_LINE) { + while (goto_ip > -1 && comp_prog.ptr[goto_ip] == kwTYPE_LINE) { goto_ip += 1 + sizeof(bcip_t); - if (comp_prog.ptr[goto_ip] == kwGOTO) { + if (goto_ip < comp_prog.count && comp_prog.ptr[goto_ip] == kwGOTO) { code_t next_level; comp_read_goto(goto_ip + 1, &addr, &next_level); goto_ip = addr; diff --git a/src/platform/android/app/build.gradle b/src/platform/android/app/build.gradle index f144e62d..f8e48a08 100644 --- a/src/platform/android/app/build.gradle +++ b/src/platform/android/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId 'net.sourceforge.smallbasic' minSdkVersion 16 targetSdkVersion 27 - versionCode 31 - versionName "0.12.14.2" + versionCode 32 + versionName "0.12.15" resConfigs "en" } diff --git a/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java index 0bf5af61..a60c6412 100644 --- a/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/app/src/main/java/net/sourceforge/smallbasic/MainActivity.java @@ -12,6 +12,7 @@ import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.location.Criteria; @@ -101,6 +102,7 @@ public class MainActivity extends NativeActivity { System.loadLibrary("smallbasic"); } + public static native void onActivityPaused(boolean paused); public static native void onResize(int width, int height); public static native void onUnicodeChar(int ch); public static native boolean optionSelected(int index); @@ -378,7 +380,17 @@ public void optionsBox(final String[] items) { this._options = items; runOnUiThread(new Runnable() { public void run() { - openOptionsMenu(); + invalidateOptionsMenu(); + Configuration config = getResources().getConfiguration(); + // https://stackoverflow.com/questions/9996333/openoptionsmenu-function-not-working-in-ics/17903128#17903128 + if ((config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) > Configuration.SCREENLAYOUT_SIZE_LARGE) { + int originalScreenLayout = config.screenLayout; + config.screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE; + openOptionsMenu(); + config.screenLayout = originalScreenLayout; + } else { + openOptionsMenu(); + } } }); } @@ -589,6 +601,18 @@ protected void onCreate(Bundle savedInstanceState) { checkFilePermission(); } + @Override + protected void onPause() { + super.onPause(); + onActivityPaused(true); + } + + @Override + protected void onResume() { + super.onResume(); + onActivityPaused(false); + } + @Override protected void onStop() { super.onStop(); diff --git a/src/platform/android/jni/display.cpp b/src/platform/android/jni/display.cpp index fe8c1feb..6ff21441 100644 --- a/src/platform/android/jni/display.cpp +++ b/src/platform/android/jni/display.cpp @@ -118,7 +118,8 @@ Graphics::Graphics(android_app *app) : ui::Graphics(), _fontBufferB(NULL), _app(app), _w(0), - _h(0) { + _h(0), + _paused(false) { } Graphics::~Graphics() { @@ -154,7 +155,7 @@ bool Graphics::construct(int fontId) { } void Graphics::redraw() { - if (_app->window != NULL) { + if (_app->window != NULL && !_paused) { ANativeWindow_Buffer buffer; if (ANativeWindow_lock(_app->window, &buffer, NULL) < 0) { trace("Unable to lock window buffer"); diff --git a/src/platform/android/jni/display.h b/src/platform/android/jni/display.h index 8182edf7..7baa370a 100644 --- a/src/platform/android/jni/display.h +++ b/src/platform/android/jni/display.h @@ -25,6 +25,7 @@ struct Graphics : ui::Graphics { bool construct(int fontId); void redraw(); void resize(); + void onPaused(bool paused) { _paused=paused; } void setSize(int w, int h) { _w = w; _h = h; } private: @@ -35,6 +36,7 @@ struct Graphics : ui::Graphics { FT_Byte *_fontBufferB; android_app *_app; int _w, _h; + bool _paused; }; #endif diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 59c855b0..b12b080e 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -130,6 +130,14 @@ int get_sensor_events(int fd, int events, void *data) { return 1; } +extern "C" JNIEXPORT void JNICALL Java_net_sourceforge_smallbasic_MainActivity_onActivityPaused + (JNIEnv *env, jclass jclazz, jboolean paused) { + if (runtime != NULL && !runtime->isClosing() && runtime->isActive() && os_graphics) { + trace("paused=%d", paused); + runtime->onPaused(paused); + } +} + // callback from MainActivity.java extern "C" JNIEXPORT jboolean JNICALL Java_net_sourceforge_smallbasic_MainActivity_optionSelected (JNIEnv *env, jclass jclazz, jint index) { diff --git a/src/platform/android/jni/runtime.h b/src/platform/android/jni/runtime.h index 475f0824..7536eab6 100644 --- a/src/platform/android/jni/runtime.h +++ b/src/platform/android/jni/runtime.h @@ -66,6 +66,7 @@ struct Runtime : public System { void share(const char *path) { setString("share", path); } void showCursor(CursorType cursorType) {} void showKeypad(bool show); + void onPaused(bool paused) { if (_graphics != NULL) _graphics->onPaused(paused); } void onResize(int w, int h); void onUnicodeChar(int ch); void loadConfig(); diff --git a/src/platform/console/Makefile.am b/src/platform/console/Makefile.am index 79fb0f47..f4a191e6 100644 --- a/src/platform/console/Makefile.am +++ b/src/platform/console/Makefile.am @@ -27,7 +27,7 @@ TEST_DIR=../../../samples/distro-examples/tests UNIT_TESTS=array break byref eval-test iifs matrices metaa ongoto \ uds hash pass1 call_tau short-circuit strings stack-test \ replace-test read-data proc optchk letbug ptr \ - trycatch chain stream-files split-join sprint all scope + trycatch chain stream-files split-join sprint all scope goto test: ${bin_PROGRAMS} @for utest in $(UNIT_TESTS); do \ diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index f371c138..28f11fc5 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -1707,7 +1707,7 @@ void TextEditInput::updateScroll() { int TextEditInput::wordEnd() { int i = _state.cursor; - while (IS_VAR_CHAR(_buf._buffer[i]) && i < _buf._len) { + while (i >= 0 && i < _buf._len && IS_VAR_CHAR(_buf._buffer[i])) { i++; } return i; @@ -1715,7 +1715,7 @@ int TextEditInput::wordEnd() { int TextEditInput::wordStart() { int cursor = _state.cursor == 0 ? 0 : _state.cursor - 1; - return (_buf._buffer[cursor] == '\n' ? _state.cursor : + return ((cursor >= 0 && cursor < _buf._len && _buf._buffer[cursor] == '\n') ? _state.cursor : is_word_boundary(&_buf, _state.cursor) ? _state.cursor : stb_textedit_move_to_word_previous(&_buf, _state.cursor)); }