hBasic Manual System
changes
|
||||||||||||||||||||||||||||||||||||||||||||||
Interrupt Scope Fixes
By 'scope' we mean the list/s that Basic! searches
through when trying to find a variable.
There are mainly two types of scopes which a basic program is running in.
1. The main
scope i.e
the main
program or
the main block
of an interrupt e.g OnBackKey
OR
2. A local
scope i.e
inside a
function
An interrupt could happen in the middle of a function. In Legacy v01.91, Basic would detect this and change the scope (from local) to the 'global' list which starts at the main program list. If the variable is not found, it would keep searching through the list of the first function that was called, then the next function, and so on until it reached the end of the last called function (the function that was interrupted). This normally works fine if the variable exists in the main list. Many uses of Interrupts rely on finding a variable in a convenient 'global' area such as the main list. There are two problems with this design;
A) If the
variable does not exist in the main list. Then it
might (un-intentionally) be found in one of the other
lists. This can lead to errors which could be
difficult to trace. and
B) If a
function is called inside an interrupt's main
block,
e.g
OnBackKey:
myfunc ()
Back.Resume
Basic still thinks it's inside an interrupt (which it
is) and uses the 'global' scope. This means any local
variable inside the function would be searched
starting from 'main'. Only if the variable does not
exist in main or any other preceeding function call,
would the correct list be finally searched. In Legacy v01.91, Functions called by an interrupt block were getting wrong scope. This is clearly undesirable, and is a side-effect of an interrupt handling system not intended to call functions. The following fixes were done. Fixed scope during an interrupt.
Fixed Case
A) Variable searches inside the main-block or
an interrupt-main-block will search only the main list
and nothing but the main list. Fixed Case B) Variable searches inside a function-block (no matter when they are called) will only search the function's local variable list. Fixed scope for new variables created during an interrupt
Made sure new variables in main-block and
interrupt-main-block are always created in main
scope. Made sure new variables in function-block are always created in local scope.
Exceptions
The only exception to these fixes is code run inside
an OnError block.
OnError is treated differently than other interrupts and it's behaviour (regarding scope) has been left alone. That is, it's scope is the scope that was interrupted. e,g If an error occurred in a function, then the scope of the OnError block is that of the function. The rationale behind being that it is sometimes useful to return to the error point with a GOTO, in which a flag or variable (in the same scope) is neccessary to transfer meaning. |
||||||||||||||||||||||||||||||||||||||||||||||
Fix for volkeys at start of
run
When VOLKEYS.OFF is run in
the editor, the next program that is run does not reset
a system flag, so volume keys stay blocked. Fix was to reset that flag at start of a run. |
||||||||||||||||||||||||||||||||||||||||||||||
Faster
BYTE.WRITE.BUFFER
BYTE.WRITE.BUFFER
<file_table_nexp>,
<buffer_sexp>
(Legacy Basic
v01.91 writes this output one low byte at a time,
each time ignoring the high byte ( each character is
two bytes).) which is rather slow. This enhancement converts the string to a byte array and writes the whole array at once. The conversion (from a string to a byte array) assumes this;
from UTF-16 (i.e a Basic/Java string) to ISO-8859-1 (by default -intentionally to save lower byte after translation). It is essentially a two-byte to one-byte conversion. If there's anything in the high byte of the source (i.e >255) then a question mark glyph (3F) is used to mark unknown data because it can't find anything to map to. |
||||||||||||||||||||||||||||||||||||||||||||||
Array Pointers
Assignments
e.g a[] = b[] or LET a[] = b[] e.g a$[] = b$[]
a[] = b[] Makes an exact copy of b[] to a[] including the size and dimensions Background references, i.e passed by referenced variables, are preserved for a[]. hBasic uses the term "array pointer" (e.g a[] )as representing the whole array. An array pointer has no indices within the brackets. It is a reference to an array as opposed to just one element. (This syntax is inline with traditional Basic 01.91 which already uses the syntax for some commands and functions.) Evaluation (place holder for future development).
Evaluation of a[] always returns
0 ( might be
changed in the future ) Evaluation of a$[] always returns "" ( might be changed in the future ) Evaluation of non-existent a[] leads to an error. e.g PRINT a[]$, b[] will print ", 0.0" |
||||||||||||||||||||||||||||||||||||||||||||||
Array
Functions
Functions can now return an Array (pointer) by
adding "[]" Array function names cannot be the same as existing non-array functions. e.g fn.def func_a$(n)[] % define an Array Function dim b$[3] b$[2] = "nice" if n=1 then fn.rtn % returns a useless default array if n=99 then fn.rtn b$[] % return specified array fn.end % returns default array ! fn.def func_a$() % (error) Function previously defined at: a$[] = func_a$(99)[] % Array function assignment (deep copy) ! print func_a$(99)[] % Error> Array functions cannot be evaluated : print a$[2] % only normal arrays can be evaluated with an index |
||||||||||||||||||||||||||||||||||||||||||||||
TEXT/BYTE.OPEN change on
failure
Before, if TEXT.OPEN or BYTE.OPEN fails to open a file,
an unusable filetable entry was still created.
This no longer happens for v2.80+, there is no new filetable entry upon failure. |
||||||||||||||||||||||||||||||||||||||||||||||
Shortcut and File-Share
Support
First off, there is a difference between a shortcut and
a fileshare. A shortcut is a widget on the home screen that calls the app with a string of data. Note that shortcut creation requires the app to be run once beforehand. A file-share is a request (normally by a file-manger) to hBasic with a filename. A) Legacy Basic only has shortcut support for a filename <something>.bas which is passed to the Standard app (i.e with editor) for execution. This is the same for hBasic (Standard).
B) hBasic also has
shortcut support for StandAlone (i.e without
editor) only if you had compiled the app as StandAlone
with included the supporting patch H0290.
For (B), a shortcut can be created on the Android home screen. It can launch the app and send a string of data. This feature will entertain any shortcut data string being sent by a shortcut launch and put the string into an undocumented function called COMMAND$(). Shortcuts to Standard APKs (non-standalone) will not be affected since they are always assumed to be <something>.bas. Note that COMMAND$() is also used for a file-share data string (e.g from a file-manager) , the difference between a shortcut and a file-share is that a file-share will prepend a relative path to a file-name. Shortcut data strings are not prepended with anything, the data string is what the user typed in and is clean. The string can be any text and can have spaces, e.g "Dark Theme". Shortcut fixes since v4.49
Standard (i.e with editor)
Shortcuts (and Standard fileshares) with a new
program request were being ignored if there was an
old instance of the interpreter still hanging
around.
From now on, the interpreter will let any new program take over, even if there's a old one still running. File-Share fixes since v4.49
Standard (i.e with editor)
Because of scoped storage, newer file managers are
sending a uri instead of a regular path to
hBasic. Standalone (apk)hBasic will now attempt to match these to it's source directory. If it can't be found, then you will get an error comment in the Editor.
E.g ..a file manager sending a file to a Standalone
apk (fileshare);
If the file is within scoped storage, the apk will receive a relative path from /data. If the file is outside of scoped storage, the apk will receive a full path (as best that hBasic can extract a path) starting with a slash "/". This does not affect shortcuts to a Standalone apk, which will always send the shortcut data cleanly. |
||||||||||||||||||||||||||||||||||||||||||||||
DEVICE
Fixes
Ack: dkal - forum
member. Permissions Fix 1 -
Android 10+
DEVICE
command would crash on devices with Android-10+
because Google decided not to allow access to
'Non-resettable device identifiers' which can
potentially be tracked or used for ads. So they are
banned for normal apps. The two keys which did this was 'DeviceID' and 'SIM SN' They both require READ_PRIVILEGED_PHONE_STATE or hasCarrierPrivileges, of which normal apps/users are unlikely to get. To fix the crash ->
If the device is
< Android Q
DeviceID
is supposed to return the IMEI or MEID.
SIM SN is
supposed to return the card serial number.
If the device is
>= Android Q
DeviceID
will return the Android_ID. (ANDROID_ID is per device (not card) and is generated on device set-up. It is not 100% reliable and could change on a factory reset or after an OTA update + app re-install). SIM SN will return "Not available". Permissions Fix 2 - Android 11+
DEVICE
command would crash on devices with Android-11+. Fix was to add READ_PHONE_NUMBERS to manifest. Permissions Fix 3 - No-Grant-Run-Time-Error
Run-Time Error is triggered If permissions are not
granted by user. A condition that does not merit a
program crash. Fix was to return either an empty string or an invalid bundle number (-1). |
||||||||||||||||||||||||||||||||||||||||||||||
Sensors
Fix
Ack: dkal,daveacre
- forum member. SENSORS command would
crash on devices with Android-10+ if (internal)
parameters were less than 3.The fix code is from aFox from a github issue. |
||||||||||||||||||||||||||||||||||||||||||||||
Gr.Modify List
Fix
Ack: afox -
forum.
|
||||||||||||||||||||||||||||||||||||||||||||||
Gr.Open StatusBar
Fix
Ack: dkal -
forum.
Status bar would not show in graphics mode, even if
flagged with GR.OPEN for Android 11+ devices.
Upgraded and used new API. The status bar flag has been superceded with Decors Flag since v4.13. |
||||||||||||||||||||||||||||||||||||||||||||||
FTP
Server
Ack: dkal,
@MoStueck Android-11's scoped storage prevents outside
access to source, data ..etc.So an ftp server (hFTP server) was embedded. (This is thanks to server code from MoStueck / hk University). The new built-in ftp server (hFTP) allows any ftp-client (or plugin) to access the base ( /Android/data/com.rfo.hbasic ) for management of your source, data & databases files). To start the server; Editor menu > Start FTP server.
A pop-up will confirm the ip-address of the server
together with the command port.
<server-ip>:<port-number>
(enter this
info for your ftp-client.) To stop the server Editor menu > Stop FTP server. To change the ftp command port number Editor menu > Preferences > FTP server port, you can change the ftp command port. On your ftp client, default cmd port : 1025 2345 (since version 3.04) user Name : hbasic password : hbasic mode : passive or active (passive recommended) type : unix auth : plain text You can also control the server programmatically with FTPS commands. Where are you scoped ? The root of the server starts at ( /Android/data/com.rfo.hbasic ).
This is known as the base_drive
i.e the
parent of the
base_directory
[rfo-basic]. Typically the contents of this base are [rfo-basic] and [files]. You are recommended to put files inside [rfo-basic/source], [rfo-basic/data] or [rfo-basic/databases] even though you will have write-access to anywhere below the base_drive. Server Exiting The server will close if; a) You tell it to stop via the Editor menu.
or b) hBasic is killed via the
android recents list
or c) android removes it in the
background.If hBasic is 'Exit' ed, either via Editor menu or Basic command, the server is still running. You will have to re-enter the hBasic app in order to stop it. It will be killed if android decides to remove hBasic from memory. |
||||||||||||||||||||||||||||||||||||||||||||||
MyPhoneNumber was
removed.
Due to the same functionality within DEVICE
command.
DEVICE
b Bundle.contain b,"PhoneNumber" , exists IF exists THEN BUNDLE.GET b, "PhoneNumber", p$ PRINT p$ ELSE PRINT "Not Available" ENDIF |
||||||||||||||||||||||||||||||||||||||||||||||
Command
Pre-Loading
Legacy Basic remembers commands per line as a form of
tokenisation to circumvent future command searches.
This happens only after the first execution of that
command. hBasic adds Pre-Loading by default, so that all lines have commands pre-loaded before the program starts. This ensures that all commands start off without needing a search and with equal footing. |
||||||||||||||||||||||||||||||||||||||||||||||
Control Stacks
Modified
In legacy Basic, there were 6 seperate control stacks
for loops, gosubs, if-blocks and functions. hBasic is the first to combine 5 of them into one block control stack (BCS). The remaining function stack is still separate but each called function gets to have it's own local BCS.
Where before, you had to make sure inner loops were
exited before exiting outer loops, a central BCS can
cancel all inner loops/blocks automatically.
The
Rules are; 1. You can execute; W_R.break, D_U.break, F_N.break, W_R.continue, D_U.continue, F_N.continue RETURN
..inside of other loop types, GOSUBs and IF
blocks. 1.a You can execute;Any other different type in-between will be cleaned out. The nearest same type inner block will be matched. REPEAT, UNTIL, NEXT,
..inside of other loop types, GOSUBs and IF
blocks. Loop bottoms must begin a line
by itself, they cannot be part of THEN statements.Any other different type in-between will be cleaned out. All same type inner blocks will also be cleaned out. (loop bottoms can cancel same types). 2. You cannot stagger an ELSE, ELSEIF or ENDIF to cancel a loop or gosub. e.g you cannot do stuff like this IF a THEN DO ELSE % Error - Misplaced ELSE PRINT "impossible" UNTIL ++a > 3 ENDIF 3. You can safely use FN.RTN in the middle of a loop, a gosub, or an IF block only if they started inside the function. 4. You can only use <x>.BREAK. , <x>.CONTINUE, REPEAT, UNTIL, NEXT, or RETURN if their headers also began inside the function e.g FN.DEF myfunc() NEXT % error: NEXT without FOR FN.END otherwise you will get
an error.5. No support for Multiple Bottoms.
You can only have one loop bottom per loop e.g you cannot do this;FOR a=1 TO 5 IF a<3 THEN GOTO SKIP1 IF a>3 THEN GOTO SKIP2 b++ NEXT % true-bottom (only one) END SKIP1: NEXT % false-bottom1 % Error> NEXT without FOR SKIP2: IF a<5 THEN NEXT % false-bottom2 (and illegal) % Error> NEXT without FOR ? "found 5" END Instead, to make the above work, you must use <loop>.CONTINUE which has the same effect;
FOR a=1 TO 5 IF a<3 THEN GOTO SKIP1 IF a>3 THEN GOTO SKIP2 b++ NEXT % true-bottom (only one) END SKIP1: F_N.CONTINUE % no error SKIP2: IF a<5 THEN F_N.CONTINUE % no error ? "found 5" END |
||||||||||||||||||||||||||||||||||||||||||||||
FILE - Absolute
Paths
Originally, paths for FILE commands were designed for
relative paths.
These paths are relative to the data directory at <BasePath>/App_Path/data e.g <BasePath>/rfo-basic/data e.g /storage/emulated/0/Android/data/com.rfo.hbasic/rfo-basic/data. This means to get to the root directory you need a path like "../../../../../../../.." and this is just to get to the root. Normally you would not need to navigate too far away from data or even rfo-basic. Also, since Android 11's, scoped storage, you probably wouldn't have access to anywhere before the BasePath. But for rooted phones or special places where you do have access, e.g to get to internal private storage, or native library areas, using relative paths to these places can be cumbersome. hBasic now allows Absolute Paths for these FILE operations. To specify an absolute path, just begin it with a slash '/'. Examples
debug.on
FILE.DIR "/storage/emulated/0/DCIM/Camera" , a$[] debug.dump.array a$[] FILE.DIR "/sdcard/Download" , a$[] debug.dump.array a$[] |
||||||||||||||||||||||||||||||||||||||||||||||
Acceleration
Editor GPU Acceleration.
The Editor and the rest of the Standard app now uses
GPU acceleration by default. This cannot be turned
off. Graphics Hardware overlay layer.
The setting in the Editor >
Preferences labeled "Graphic acceleration"
has always (in legacy Basic) referred to Hardware overlay layer (not GPU acceleration as above). It further boosts performance for the graphics screen (only). This preference setting is now ON by default. It can be turned off either in Preferences or programmatically with the new command GR.SETACC. It uses less power than direct GPU rendering at the expense of causing lag in some animations. But in most cases it is faster. |
||||||||||||||||||||||||||||||||||||||||||||||
Directives @@
Directives are used to configure the intepreter and the
console. These directives should be put the before the start of a program together on their own. They all start with "@@". Any line that isn't a directive or a comment will stop directive processing and furthur directives will be ignored. (Note: Prior to v4.13, the directive prefixes used to be a single"@". The change to "@@" is to allow through variables that start with a single "@") Directives are processed before the a program is run. Therefore you cannot use any variables for arguments.
Deprecated
Directives
The following directives are no longer in use;
@@PRELOAD, @@LOCALSTACKS, @@DARK_STATUSTXT
@@HIDE_ACTIONBAR
This hides the console Action Bar at startup. The console actionbar default title is "Program Output". You may want to avoid displaying the actionbar when your program starts up. The actionbar will remain hidden until the next CONSOLE.TITLE. CONSOLE.TITLE will always show the actionbar. Warning: If you choose not to restore the actionbar after (with CONSOLE.TITLE), then the user will not see the console title and cannot interact with the menu. Also, MENU.SHOW will be ignored if there is no actionbar. E.g
@@HIDE_ACTIONBAR
% prevent flash of console
title GR.OPEN "white",1,1 % graphics now in front CONSOLE.TITLE "My Title" % restore actionbar in background GR.COLOR "black" : GR.TEXT.SIZE 40 GR.TEXT.DRAW o, 50,100,"Tap BackKey to quit" GR.RENDER DO : pause 100 : UNTIL 0 OnBackKey : print "Done" END % console now in front with title If you do not use this directive, the actionbar will be shown by default with the default title "Program Output". @@VOID_COLOR "<color>" e.g @@void_color "blue"
This directive sets the console background (void)
color. It is the color you see if there is no text on
top.
It is equivalent to CONSOLE.SET "voidcolor <color>" but occurs before the console is displayed. The color must be a string and is the same format as the color strings for other hBasic commands. Because this is a directive, you cannot use a string variable, it must be literal. You may want to use this directive if you don't want a flash of the default void color (white) when starting your program.
This directive sets the console window background color.
It is the color you see if the void color is
transparent. It may also be the color you see behind the statusbar and/or navbar depending on the configuration. The color must be a string and is the same format as the color strings for other hBasic commands. Because this is a directive, you cannot use a string variable, it must be literal. You may want to use this directive to set the background color for the statusbar and/or navbar. |
||||||||||||||||||||||||||||||||||||||||||||||