ChangeLog
---------

Version 0.8 alpha 1 - 24-Sep-2026:
  - Added support for console I/O to graphics windows:
      OPTION CONSOLE BOTH ' or OPTION CONSOLE SCREEN
      GRAPHICS WINDOW 0, 300, 300
      GRAPHICS WRITE 0
      PRINT "Hello World"
      - Enabled automatically for simulated platforms where appropriate.
  - Added simulation of additional platforms:
      - PicoMiteHDMI
      - PicoMiteVGAUSB
      - PicoCalc
  - Added internal editor ported/rewritten from PicoMite:
      - Do a single edit using the internal editor:
          EDIT INTERNAL "helloworld.bas"
      - Do a persisted switch to the internal editor:
          OPTION EDITOR INTERNAL
      - ** Still has some bugs that need ironing out. **
      - ** Not feature-complete c.f. very latest PicoMite editor. **
  - Added BLIT RESIZE command:
      BLIT RESIZE src_id, dst_id, sx, sy, sw, sh, dx, dy, dw, dh [, transparent]
  - Added BREAKPOINT command to assist debugging the interpreter:
      BREAKPOINT
      - Placing a BREAKPOINT statement in an MMBasic program gives a developer
        a named, stable symbol at which a gdb breakpoint can be set, allowing
        execution to be paused at a precise MMBasic line.
  - Added DEVICE GAMEPAD sub-commands:
      DEVICE GAMEPAD INTERRUPT ENABLE id, interrupt [, bitmask]
      DEVICE GAMEPAD INTERRUPT DISABLE id
      DEVICE GAMEPAD LED id, red, green, blue
      DEVICE GAMEPAD RUMBLE id [, low_freq] [, high_freq] [, duration_ms]
      DEVICE GAMEPAD RUMBLE id, OFF
      DEVICE GAMEPAD RUMBLE TRIGGERS id [, left] [, right] [, duration_ms]
      DEVICE GAMEPAD RUMBLE TRIGGERS id, OFF
      - LED and RUMBLE TRIGGERS are currently untested as I don't have
        compatible hardware.
      - Note: DEVICE GAMEPAD VIBRATE has been renamed to DEVICE GAMEPAD RUMBLE.
  - Added DRIVE command as no-op for PicoMite simulation.
  - Added IN and OUT commands as no-op for PicoMite simulation:
      - On the PicoMite these are used with the PIO.
      - Having them in MMB4L, even if they don't do anything, prevents IN and
        OUT being used as variable names in programs intended to also run on
        the PicoMite.
  - Added LIST VARS command:
      LIST VARIABLES [ALL|GLOBAL|LOCAL|level%]
  - Added LOAD JPG command:
      LOAD JPG file$ [, x] [, y] [, mode] [, ximage] [, yimage]
  - Added LOG command:
      LOG [ DEBUG | INFO | WARNING | ERROR | FATAL ]? expression ...
      - See further description of logging support below.
  - Added MKFILE command for creating an empty file:
      MKFILE filename$
      - Helpful for testing, limited use in production.
  - Added OPTION KEYBOARD command as no-op for PicoMite simulation.
  - Added OPTION LOG command:
      OPTION LOG [ NONE | DEBUG | INFO | WARNING | ERROR ]
      - See further description of logging support below.
  - Added SAVE IMAGE command for saving .bmp files:
      SAVE [COMPRESSED|IMAGE|1BPP|24BPP|32BPP|RGB121|RGB121_RLE4|RGB222|
          RGB222_RLE8|RGB332|RGB332_RLE8|RGB555|RGB565] file$ [, x, y, w, h]
  - Added SAVE JPG command:
      SAVE JPG file$ [, x, y, w, h]
  - Added SETTICK PAUSE and SETTICK RESUME commands.
  - Added SPRITE LOADARRAY command:
      SPRITE LOADARRAY [#]id, w, h, array%()
  - Added ATAN2() function.
  - Added KEYDOWN() function for PicoMiteVGA + PicoMiteHDMI:
      - Available for all simulated platforms except Game*Mite and PicoCalc.
  - Added MM.INFO(FONT), MM.INFO(BCOLOUR), MM.INFO(FCOLOUR) functions.
  - Added PIXEL() function.
  - Added support for long lines, i.e. greater than console width, at prompt.
  - Added logging support to assist debugging the interpreter:
      - Writes "mmb4l.log" to directory in which MMB4L is started.
      - Set initial log level at command line with:
          --log [ none | debug | info | warning | error ]
      - Set via non-persistent option from within MMB4L:
          OPTION LOG [ NONE | DENUG | INFO | WARNING | ERROR ]
      - Write directly to the log:
          LOG [ DEBUG | INFO | WARNING | ERROR | FATAL ]? expression ...
  - Added support for 2nd FRAMEBUFFER to PicoMite simulation.
  - Added support for Fonts 8 and 9 from PicoMite.
  - Added BYVAL and BYREF keywords.
  - Added support for ANSI default terminal colour.
  - Added support for reading stdin from pipe or redirected input.
  - Added support for multibyte function tokens:
      - Removes the previous limit of 127/128 function tokens.
  - Added support for specifying a platform to simulate on the command line:
      RUN [filename$] [, cmdargs$] [AS {<device> | device$}]
      - e.g. RUN "foo.bas", "wombat" AS CMM2
      - Also via the * command, e.g. *CMM2 foo --wom --bat
      - If a platform is supplied at the command line then it is used as the
        default returned to by the NEW and RUN commands.
  - Added character coordinate variants of MM.INFO(HPOS|VPOS|HRES|VRES) and
    PRINT @:
        MM.INFO(HPOS C), MM.INFO(VPOS C), MM.INFO(HRES C), MM.INFO(VRES C)
        PRINT @C(x, y) "Hello World"
  - Added SETENV name$ = value$ as synonym for SYSTEM SETENV.
  - Added prompt history saved and restored to/from file.
  - Removed OPTION RESOLUTION command:
    - Replaced with explicit character coordinate variants of
      MM.INFO(HPOS|VPOS|HRES|VRES) and PRINT @; see above.
  - Changed FILES command to be reimplemented PicoMite-alike instead of
    delegating to operating-system 'ls'.
  - Changed MEMORY report to show used vs. available function and variable
    slots, and renamed "General RAM" to "Heap".
  - Changed termgfx cursor to use cell inversion instead of a flashing
    underline for improved visibility.
  - Changed platform switching: NEW and RUN no longer destroy graphics
    surfaces unless the platform is actually switched.
  - Changed EOF() behaviour to match PicoMite.
  - Changed CMM2 simulation: colour depth of 8 or 16 now treated as 32 in
    MODE command.
  - Changed MM.INFO(HRES|VRES) so they are disallowed for simulated platforms.
  - Changed SDL event polling to occur every 5ms rather than continuously:
      - Excessive polling was a major performance bottleneck.
  - Changed STDIN reading to use a worker thread:
      - The principal reason for this is that on Windows reading from STDIN
        is very slow.
  - Fixed bug in SDL audio buffering. Callback now processes full stereo frames
    instead of assuming a 1-sample buffer which reduces underruns and the
    crackling and popping in the sound that they were causing.
  - Fixed bug in single-line IF <expr> THEN <stmt1> ELSE <stmt2>:
      - Was broken if <stmt1> began with a command whose command token id was
        equal to ELSE's function token id.
  - Fixed bug where DefinedSubFun did not restore state when throwing an error.
  - Fixed bug where BLIT had edge condition errors with horizontal and vertical
    flip.
  - Fixed bug where block drawing characters in FONT 4 were incorrect.
  - Fixed bug where INC/CAT did not respect string array element length.
  - Fixed bug where SDL was not properly cleaned up on exit.
  - Fixed bug where display was not updated until the first button press on
    the R36S (dirty flag not set on SDL_WINDOWEVENT_SHOWN).
  - Fixed bug where gamepad struct id was 0 after gamepad_close().
  - Fixed bug where Mstrcpy() would segfault when src == NULL.
  - Fixed bug where MATH function complex number support used incorrect return
    type (test suite contributed by Peter Mather).
  - Fixed bug where INPUT$ returned no error given an invalid file number.
  - Fixed bug where temporary buffers were not released during SELECT/CASE
    processing.
  - Fixed bug where all files were not closed when program_process_file()
    exited.
  - Fixed bug where saving options to a directory instead of a file did not
    return an error.
  - Fixed bug where trailing separator was not stripped in file_getcwd() and
    file_get_home().
  - Fixed bug where audio track current used unsigned type with -1 sentinel.
  - Fixed bug where popen() output was not trimmed of leading/trailing
    whitespace.
  - Fixed bug where --version command-line option did not work correctly.
  - Fixed bug where console carriage-return was not handled correctly.
  - Fixed bug where backspace in the first column would move the cursor up
    in termgfx.
  - Fixed bug with [Delete] key behaviour in termgfx.
  - Fixed bug where show/hide cursor was not correct in MMgetchar().
  - Fixed bug where memory was not allocated for return values from
    MM.INFO(CPUSPEED), MM.INFO(CPUTIME) and MM.INFO(DRIVE)
      - Fix by @TomSchimana.
  - Fixed various uninitialised local variables reported by MSVC.
  - Fixed codepage pointer dereferencing for output.

Version 0.7 alpha 1 - 19-Jan-2025:
  - Added support for hi-res graphics:
    - The GRAPHICS command is used to create and manipulate up to 256 hi-res
      surfaces with ids 0 - 255:
        GRAPHICS BUFFER id, width, height
          - Creates an off-screen buffer surface.
          - Note that surface 0 cannot be a buffer.
        GRAPHICS CLS id [, colour]
          - Clears a surface.
        GRAPHICS COPY src_id TO dst_id [, when] [, transparent]
          - Copies one surface to another (c.f. PAGE COPY on the CMM2).
        GRAPHICS DESTROY { id | ALL }
          - Destroys a surface.
        GRAPHICS INTERRUPT id, {interrupt|0}
          - Sets or clears the interrupt handler for a window surface.
        GRAPHICS LIST
          - Lists all surfaces.
        GRAPHICS SPRITE id, width, height
          - Creates a sprite surface.
          - Note that all graphics primitive commands can be used on sprite
            surfaces; this is different to other MMBasics.
          - Note that surface 0 cannot be a sprite.
        GRAPHICS TITLE id, title$
          - Sets the title of a window surface.
        GRAPHICS WINDOW id, width, height [, x] [, y] [, title$] [, scale]
                        [, interrupt]
          - Creates a window surface.
          - Note that surface 0 can (only) be a window.
        GRAPHICS WRITE { id | NONE }
          - Selects the surface to direct other graphics commands to
            (c.f. PAGE WRITE on the CMM2).

    - The following standard MMBasic graphics commands are implemented including
      supporting array parameters where appropriate:
        ARC x, y, r1, [r2], arcrad1, arcrad2 [, colour]
        BLIT x1, y1, x2, y2, width, height [, src_id] [, flags]
        BLIT CLOSE [#]id
        BLIT CLOSE ALL
        BLIT COMPRESSED address, x, y [, transparent]
        BLIT MEMORY address, x, y [, transparent]
        BLIT READ [#]dst_id, x, y, width, height [, src_id]
        BLIT WRITE [#]src_id, x, y [, orientation]
        BOX x, y, w, h [, lw] [, c] [, fill]
        CIRCLE x, y, radius [, line_width] [, aspect_ratio] [, colour] [, fill]
        CLS [colour]
          - Note that if there is no current graphics write surface then this
            will clear the console. To clear the console explicitly use the
            CLS CONSOLE or CONSOLE CLEAR commands.
        DEFINEFONT [#]font_id
        FONT [#]font_id [, scale]
        GUI BITMAP x, y, bits [, width] [, height] [, scale] [, fcolour] [, bcolour]
        IMAGE RESIZE_FAST x, y, width, height, new_x, new_y, new_width, new_height [, src_id]
                          [, flag]
        LINE x1, y1, x2, y2 [, width [, colour]]
        LINE GRAPH x(), y() [, colour]
        LINE PLOT ydata() [, nbr] [, xstart] [, xinc] [, ystart] [, yinc] [, colour]
        LOAD BMP file$ [, x] [, y]
        LOAD IMAGE file$ [, x] [, y]
        LOAD PNG file$ [, x] [, y] [, transparency_cut_off]
        PIXEL x, y [, colour]
        POLYGON n, x(), y() [, bordercolour] [, fillcolour]
        RBOX x, y, width, height [, radius] [, colour] [, fill]
        SPRITE CLOSE [#]id
        SPRITE CLOSE ALL
        SPRITE HIDE [#]id
        SPRITE INTERRUPT interrupt
        SPRITE HIDE ALL
        SPRITE HIDE SAFE [#]id
        SPRITE LOAD file$ [, start_sprite] [, colour_mode]
        SPRITE MOVE
        SPRITE NEXT [#]id, x, y
        SPRITE NOINTERRUPT
        SPRITE READ [#]id, x, y, w, h [, src_id]
        SPRITE RESTORE
        SPRITE SCROLL x, y [, colour]
        SPRITE SET TRANSPARENT rgb121_colour
        SPRITE SHOW [#]id, x, y, layer [, flags]
        SPRITE SHOW SAFE [#]id, x, y, layer [, flags] [, ontop]
        SPRITE WRITE [#]id, x, y [, flags]
        TEXT x, y, string$ [, alignment$] [, font] [, scale] [, fcolour] [, bcolour]
        TRIANGLE x1, y1, x2, y2, x3, y3 [, colour] [, fill]

    - The following standard MMBasic SPRITE functions are implemented:
        SPRITE(A, [#]id)
        SPRITE(C, [#]id [, m])
        SPRITE(D, [#]id1, [#]id2)
        SPRITE(E, [#]id)
        SPRITE(H, [#]id)
        SPRITE(L, [#]id)
        SPRITE(N [, layer])
        SPRITE(S)
        SPRITE(V, [#]id1, [#]id2)
        SPRITE(T, [#]id)
        SPRITE(W, [#]id)
        SPRITE(X, [#]id)
        SPRITE(Y, [#]id)

  - Added support for music and sound-fx playback.
    - The following standard MMBasic audio commands are supported:
        PLAY EFFECT file$ [, interrupt]
        PLAY FLAC file$ [, interrupt]
        PLAY MODFILE file$ [, sample_rate] [, interrupt]
        PLAY MODSAMPLE sample_num, channel_num [, volume] [, sample_rate]
        PLAY MP3 file$ [, interrupt]
        PLAY PAUSE
        PLAY PREVIOUS
        PLAY RESUME
        PLAY SOUND sound_no, channel_no, type [, frequency] [, volume]
        PLAY STOP
        PLAY TONE left [, right] [, duration] [, interrupt]
        PLAY VOLUME left [, right]
        PLAY WAV file$ [, interrupt]

  - Added support for up to 4 USB gamepads:
    - Commands:
        DEVICE GAMEPAD CLOSE id
        DEVICE GAMEPAD OPEN id [, interrupt] [, bitmask]
        DEVICE GAMEPAD VIBRATE id [, low_freq] [, high_freq] [, duration_ms]
        DEVICE GAMEPAD VIBRATE id OFF
    - Functions:
        DEVICE(GAMEPAD id, funct)
        MM.INFO$(GAMEPAD id)
          - Retrieves SDL mapping for gamepad.

  - Added OPTION SIMULATE to enable platform specific compatibility with other
    MMBasics.
      OPTION SIMULATE device$
        - device$ is one of "Colour Maximite 2", "Game*Mite", "PicoMiteVGA",
          "MMBasic for Windows" or "MMB4L" to return to default behaviour.
    - Causes MM.DEVICE$, MM.INFO$(DEVICE) and MM.INFO$(PLATFORM) to return
      the appropriate simulated value.
    - If required MM.INFO$(DEVICE X) can be used to retrieve the real device
      name; this relies on the lenient error checking currently exhibited by
      other MMBasic platforms not reporting the "extraneous" X as a syntax
      error.

      Colour Maximite 2:
        - Simulates USB controllers 1-3 being read as if they were Wii Classic
          controllers attached to I2C channels 1-3:
          - USB1 = I2C3, USB2 = I2C1, USB1 = I2C2.
        - Commands:
            CONTROLLER CLASSIC CLOSE [i2c]
            CONTROLLER CLASSIC OPEN [i2c] [, interrupt] [, bitmask]
            MODE, PAGE COPY, PAGE SCROLL, PAGE WRITE
        - Functions:
            CLASSIC({B | LX | LY | RX | RY | L | R | T} [, i2c])

      Game*Mite (RP2040):
        - Simulates sufficient GPIO to support USB controller 1 being read
          using SETPIN and PORT() as if it were the 8-button Game*Mite
          controller.
        - Commands:
            FRAMEBUFFER, BLIT FRAMEBUFFER, FLASH DISK LOAD, SETPIN
        - Functions:
            MM.INFO(CPUSPEED), MM.INFO(DRIVE), MM.INFO(FLASH ADDRESS),
            MM.INFO(PINNO GPxx), PORT()

      MMBasic for Windows:
        - As "Colour Maximite 2" except supports a single USB controller being
          read with the GAMEPAD command and function.

      PicoMiteVGA (RP2040):
        - Simulates sufficient GPIO to support USB controllers 1 & 2 being
          read using PIN, PULSE and SETPIN as if they were 12-button SNES
          controllers wired according to the PicoGAME VGA 2.0 schematic.
        - Commands:
            FRAMEBUFFER, BLIT FRAMEBUFFER, FLASH DISK LOAD, MODE, PIN,
            PULSE, SETPIN
        - Functions:
            MM.INFO(CPUSPEED), MM.INFO(DRIVE), MMM.INFO(FLASH ADDRESS),
            MM.INFO(PINNO GPxx), PIN()
        - Note that MODE 1 coloured tiles are not currently supported.

    Added other commands:
        ON PS2 {interrupt | 0}
          - As per PicoMite.
        OPTION ANGLE {DEGREES | RADIANS}
          - As per PicoMite.
        OPTION AUDIO {ON | OFF}
          - Persistent option to enable/disable audio.
          - Default ON.
          - The intended purpose of this OPTION is to allow MMB4L to be
            easily run on Linux devices (in particular Docker containers)
            where the SDL audio is too difficult for the user to be bothered to
            configure ;-).
          - Note that when OFF all the underlying audio boilerplate is still
            executed except for the bit that makes the noise and the calling of
            audio interrupts.
        OPTION AUTOSCALE {ON | OFF}
          - Persistent option to enable/disable automatic scaling of windows when
            using OPTION SIMULATE.
          - Default ON.
          - When ON the window for the simulated device will be scaled up (in
            whole number multipliers) to be the largest that will fit on the
            display.
        SETENV name$ = value$
          - Synonym for existing SYSTEM SETENV.
          - Note that the value may also be an integer array containing a
            LONGSTRING.

    Added other functions:
        ATAN2(y, x)
        KEYDOWN(n)
        MM.INFO(PS2)

  - Added CONSOLE TITLE command as preferred synonym for CONSOLE SETTITLE so
    as to match the GRAPHICS TITLE command.

  - Added optional parameter to MM.INFO$(ERRMSG [errno%]) so it can now be used
    to retrieve the default message for any given 'errno%' as well as the
    current error message (when errno% is not specified).
    - Note that currently error numbers are not stable between MMB4L releases.

  - Changed DATE$(), DATETIME$(), DAY$() and TIME$() to be consistent with other
    MMBasics that do not have timezone support whilst returning local timezone
    values where most appropriate:
      TIME$()          - returns current time in local timezone.
      DATE$()          - returns current date in local timezone.
      DATETIME$(NOW)   - returns current date/time in local timezone.
      DATETIME$(epoch) - returns date/time in UTC.
      DAY$(NOW)        - returns current day in local timezone.
      DAY$(epoch)      - returns day in UTC.
    Additionally:
      EPOCH(datetme$)  - assumes the date/time is in UTC.

  - Changed MATH(SD a()) function to use "Sample Standard Deviation Formula"
    instead of "Population Standard Deviation Formula".
    - This matches PicoMite MMBasic v6.0.0.

  - Changed SORT to allow bit 2 of the 'flags' to be set when sorting strings so
    that empty strings are considered to have the "biggest" value.
    - This matches PicoMite MMBasic v0.6.0

  - Fixed bug where ANSI control codes for setting the terminal title, showing
    the cursor, and resetting graphics styles and colours were written to
    STDOUT even when running without the MMBasic prompt.

Version 0.6.1 - 28-Sep-2024:
  - Fixed bug where would show endless 'Cannot determine terminal size' errors.
  - Minor corrections to v0.6.0 ChangeLog entry.

Version 0.6.0 - 4-Feb-2024:
  - Added BIN2STR$() and STR2BIN() functions.
  - Added MM.INFO(LINE) function to return the number of the current line.
  - Added NOP implementation of PAGE command.
  - Changed file path reported in an error message to be canonicalised.
  - Changed maximum error message length to 255 characters (from 127).
  - Changed implementation of MODE so that it clears the console instead of
    just being a NOP.
  - Changed parser to allow any non-name character to be used as a keyword
    terminator, i.e. DIM i AS INTEGER=10 is now valid.
  - Changed 'micro' version in semantic versioning from 2 digits to 3, the most
    significant digit indicates whether it is an alpha, beta, RC or release
    version:
      0      - alpha
      1      - beta
      2      - RC (release candidate)
      3 .. 9 - release, in which case the "real" MICRO version is the
               3-digit number minus 300.
    e.g. version 1230560001 => 1.23 alpha 56 build 1
                 1231560012 => 1.23 beta 56 build 12
                 1232560123 => 1.23 RC 56 build 123
                 1233561234 => 1.23.56 build 1234
                 1234567890 => 1.23.156 build 7890
    Currently the version is 63000000 => 0.6.0 build 0.
  - Changed MM.VER to return an INTEGER instead of a FLOAT, the same as
    MM.INFO(VERSION).
  - Changed maximum length of command line when starting MMB4L from 256 to 512
    characters.
      - Also improved error message when that command line is too long.
      - Note that the length of a command entered at the MMB4L prompt is still
        limited to the width of the console.
  - Fixed bugs in DIR$() function that would cause a crash if called with no
    arguments:
        - If it had never been initialised with a pattern to match.
        - If the empty string indicating the end of the directory stream had
          already been returned.
  - Fixed bug in CALL command and function to allow the function/subroutine
    name to be provided by a non-trivial expression.
  - Fixed bug in variable declaration where 2nd and subsequent dimensions
    of a multi-dimensional array could be declared with 1 element.
  - Fixed bug with left and right arrow glyphs being swapped when using
    OPTION CODEPAGE CMM2.

Version 0.5.0 - 3-Feb-2023:
  - Changed to semantic versioning scheme.
    Note that MMB4L is still versioned independently of Geoff and Peter's
    "mainline" MMBasic platforms.
        - MM.INFO(VERSION) will return the integer 5000000 for this release,
          divide by 10000000 to get float equivalent, e.g. 0.5
        - MM.INFO(VERSION MAJOR) will return major version, 0 for this release.
        - MM.INFO(VERSION MINOR) will return minor version, 5 for this release.
        - MM.INFO(VERSION MICRO) will return minor/patch version, 0 for this
          release.
        - MM.INFO(VERSION BUILD) will return the build number, 0 for this
          release and only included for use in some theoretical future.
  - Added "automatic path completion" to the MMBasic prompt.
        - Pressing TAB will attempt to complete (as far as can be unambiguously
          determined) a filename that the user is typing at the prompt, or sound
          the console bell if no completion is possible.
  - Added MM.INFO(CALLDEPTH) to return the current function/subroutine call
    depth.
        - 0 when at the global level, i.e. not in a function/subroutine.
        - Primarily for debugging purposes, though a possible production
          use-case would be to allow a program to "bail out" if recursion gets
          too deep.
  - Added MM.INFO(PID) to get the process ID of the MM4L process.
  - Added MM.INFO(CPUTIME) to get the value (in nanoseconds) of the CPU timer
    for the MMB4L process.
  - Changed function, label, subroutine and variable lookup to use hashmap.
        - Depending on the problem this might be expected to produce a 3-5%
          improvement in performance.
  - Changed syntax of RUN command to:
        RUN [file$] [, cmdline$]
    Both file$ and cmdline$ can now be string expressions instead of
    the legacy behaviour where the command line argument was "not processed" by
    MMBasic and was copied verbatim into the MM.CMDLINE$ of the new program.
        - This change means that cmdline$ can now be constructed from other
          variables and functions instead of having to be hardcoded, or
          finessed by using EXECUTE to construct the RUN statement.
        - If the text following the comma contains an unquoted minus sign then
          for backward compatibility MMB4L trys to use the legacy behaviour,
          but this does not work for all possible legacy command lines.
    Note that the behaviour of the * command is unchanged; expressions in any
    command line provided via * are not evaluated by MMB4L, e.g.
        *foo a$ + b$
    is equivalent to:
        RUN "foo", "a$ + b$"
  - Changed RUN file$ so that it is not necessary for file$ to have a ".bas"
    extension.
        - If file$ does not exist then will try appending the extensions
          ".bas", ".BAS" and ".Bas" in turn.
  - Changed #INCLUDE "<file>" so that it is not necessary for <file> to have
    a ".inc" extension.
        - If <file> does not exist then will try appending the extension
          ".inc", ".INC" and ".Inc" in turn.
  - Changed XMODEM to improve read/write performance.
        - It now reads/writes 128 characters at a time instead of 1.
  - Changed MMBasic prompt so that you can access the history with the up
    and down cursors even after you start typing a command.
  - Changed some error messages to be clearer and/or more specific.
  - Changed "mmbasic.syntax.nanorc" to improve syntax highlighting of comments.
        - Even so it is still not 100% correct.
  - Fixed bug where relative #INCLUDE files could not be found when running
    a symbolic link to an MMBasic file.
        - The path to the #INCLUDE files was incorrectly being resolved relative
          to the parent of the symbolic link instead of the parent of the target
          file.
  - Fixed several bugs with identifiers allowing / being limited to 32
    characters (not including variable/function type suffix).
  - Fixed bug with GOSUB/RETURN corrupting the interpreter state when using
    ON ERROR SKIP.
  - Fixed bug where function returns corrupted the interpreter state when using
    ON ERROR SKIP.
  - Fixed bug where an "Internal fault" error would be reported immediately if
    the console/tty dimensions could not be determined when displaying the
    MMBasic prompt.
        - This can be a transient problem so MMB4L now retries for 1 second
          before reporting a "Cannot determine terminal size" error.
  - Fixed bug in OPTION LIST for F<num> function key options whose values
    contained carriage-return character.

Version 2022.01.00-a4 - 15-May-2022:
  - MMB4L is now open-source and licensed under a modified 4-clause BSD license
    similar to that for the PicoMite firmware and MMBasic for Windows. See the
    LICENSE file for details. My thanks to Geoff and Peter for allowing this to
    be possible.
  - Added * command which may be used at the MMBasic prompt (but not within
    programs) as a short-cut for RUN, e.g.
        *foo --bar "wombat"
    is translated to:
        RUN "foo", --bar "wombat"
  - Added ! command which may be used at the MMBasic prompt (but not within
    programs) as a short-cut for SYSTEM, e.g.
        !cp foo bar
    is translated to:
        SYSTEM "cp foo bar"
    An exception is !cd, e.g.
        !cd foo
    is translated to:
        CHDIR "foo"
    This is required because "!cd foo" would otherwise appear to do nothing
    due to the fact that each SYSTEM command is run in the context of a separate
    forked process instead of the MMBasic process itself.
  - Added SYSTEM sub-commands for getting and setting environment variables:
        - SYSTEM GETENV name$, {value$ | value%()}
        - SYSTEM SETENV name$, {value$ | value%()}
    This supplements MM.INFO$(ENVVAR) because it allows values > 255 characters
    to be read into a LONGSTRING.
  - Added option persistence to file "~/.mmbasic/mmbasic.options" for all
    options except for BASE, BREAK, CASE, CODEPAGE, CONSOLE, EXPLICIT and
    RESOLUTION:
        - only options that differ from their defaults are saved to this file.
  - Added OPTION EDITOR <editor> command to change the EDITor.
    Supported editors are:
        - ATOM
        - CODE     (synonym for VSCODE)
        - DEFAULT  (synonym for NANO)
        - GEANY
        - GEDIT
        - LEAFPAD
        - NANO
        - SUBLIME
        - VI
        - VIM
        - VSCODE
        - XED      (untested because I couldn't get a version for Ubuntu 21.)
        - or a string specifying a command to run, e.g.
              OPTION EDITOR "code -g ${file}:${line}"
          ${file} is a placeholder for the filename to edit, the filename will
                  be automatically enclosed in double-quoted.
          ${line} is a placeholder for the line number to set the initial
                  cursor position to.
  - Added OPTION F<num> string$ sub-commands to define the strings that will be
    generated when pressing function keys at the MMBasic prompt:
        - all of F1-F12 can be redefined.
        - beware that some function keys may be captured by the Linux window
          manager and never passed on to MMBasic.
  - Added OPTION SEARCH PATH <path> command as per CMM2.
  - Added OPTION {SAVE | LOAD} <filename> command.
  - Added OPTION RESET {ALL | <option>} command.
  - Added PEEK(DATAPTR) function and POKE DATAPTR ptr% command for getting
    and setting the DATA read pointer.
  - Added READ {RESTORE | SAVE} command for pushing and popping the DATA read
    position to an internal stack as per PicoMite.
  - Changed OPTION LIST to only show options that differ from their defaults:
         - use OPTION LIST ALL to list all options.
  - Changed OPTION <option> <value> command so that for all options with
    enumerated values the value can now be supplied as a string, e.g.
        OPTION CODEPAGE NONE
        OPTION CODEPAGE "NONE"
        DIM none$ = "NONE"
        OPTION CODEPAGE none$
  - Changed RESTORE command to support targets given as string or number
    expressions as per PicoMite.
  - Changed SYSTEM execute command to have a 3rd optional argument to capture
    the exit status of the executed command, e.g.
        SYSTEM command$, out$, exit_status%
        SYSTEM command$, out%(), exit_status%
    The SYSTEM command now only reports an error if it cannot run the command.
    If the command runs but fails then no error is reported and the failure
    code will be captured in exit_status%.
  - Changed LOAD and RUN so that if a filename without a [.bas|.BAS|.Bas]
    extension is not provided then one is automatically appended:
        - unlike other MMBasic ports MMB4L has a case-sensitive file-system
          and expects MMBasic program files to have one of three possible
          extensions: .bas, .BAS, or .Bas.
        - if no extension is specified then MMB4L will check for the existence
          of a file with each extension in order, if no such file is found then
          it assumes the .bas extension.
  - Changed assignment of values to MM.ERRNO, they are now:
           0      : no error.
       1  ..  255 : standard error numbers (errno) for C library calls.
          256     : unclassified MMBasic error.
      257 .. 1023 : other standard MMBasic errors.
         1024+    : recommended range for program specific errors.
  - Removed LS as an alias of FILES:
        - LS was a non-standard aberration inherited from the CMM2.
        - use !ls instead to execute the 'ls' Linux shell command with all its
          power and with no requirement to enquote its arguments.
  - Fixed bug where could not open non-existing file for RANDOM access.
  - Fixed bug where when one program tried to RUN another it would resolve the
    path to the new program from the current program directory instead of from
    the current working directory.
  - Fixed bugs in interaction between ON ERROR and interrupts.
    The normal thread of execution and the execution of interrupts now maintain
    independent error states.
  - Fixed bug where MM.ERRMSG$ would contain trailing newline character after
    an uncaught ERROR.
  - Fixed more issues with "mmbasic.syntax.nanorc".

Version 2022.01.00-a3 - 16-Jan-2022:
  - Added serial port support, e.g.
        OPEN "/dev/ttyS0: 115200" As #1
    this is very preliminary and in need of extensive user testing,
    see README for details.
  - Added XMODEM {SEND | RECEIVE} file$, #fnbr command:
    - #fnbr must first have been OPENed as a serial port.
    - unlike other MMBasic versions, MMB4L cannot use XMODEM to send to or
      receive from the console.
  - Added OPTION CODEPAGE page$ command:
    - causes character bytes in the range 128-255 to be translated to Unicode
      (UTF-8) when printed to the console according to a given code page /
      mapping.
    - supported values of page$ are currently:
      - "NONE"   : no mapping, characters 128-255 are written as-is.
      - "CMM2"   : best effort mapping to the characters of the CMM2 font.
      - "CP437"  : characters 128-255 of the original IBM PC code 437.
                   Note this was a non-ANSI code page which also included
                   characters 1-31 which are not available in this mapping,
                   but see "MMB4L".
      - "CP1252" : the classic Windows-1252 Latin alphabet code page.
      - "MMB4L"  : as "CP437" but with characters 129-159 replaced by the
                   original non-ANSI CP437 characters 1-31 and with additional
                   "useful" characters in positions 128, 161-170 and 255.
  - Added CHR$(UTF8 codepoint%) function:
    - given a Unicode code-point this returns the 1-4 character string encoding
      that character in UTF-8 format.
    - printing such characters is not compatible with OPTION CODEPAGE being
      set.
  - Added AUTOSAVE file$ command:
    - note that as with the CMM2 there is no CRUNCH option; AUTOSAVE writes to a
      file and MMB4L always crunches the program automatically when it loads it
      for execution.
  - Added CONSOLE SETSIZE [ATLEAST] width%, height% command:
    - sends an XTerm control sequence to set the terminal size.
    - if the optional ATLEAST modifier is used then this will not reduce the
      terminal width or height.
  - Added PRINT @(x%, y%) expression:
    - unlike the CMM2, x% & y% are obligatory and in character coordinates,
      there is no mode parameter.
    - equivalent to:
        CONSOLE SETCURSOR x, y : PRINT expression
  - Added missing LIST FILES command:
    - just another synonym for FILES and LS and only present for compatibility
      with the CMM2.
  - Changed SYSTEM command to allow standard output to be captured in a STRING
    (as an alternative to existing functionality to capture it in a LONGSTRING),
    e.g.
        DIM out$
        SYSTEM "echo `date`", out$
        PRINT out$
    Also any trailing whitespace, including CRLF is now trimmed from the
    captured STRING or LONGSTRING output.
  - Changed EOF() function to return 1 when at the end of file (like the CMM2),
    previously it returned -1.
  - Fixed bug so that MEMORY COPY command correctly handles overlapping source
    and destination.
  - Fixed bug with MM.INFO$(...) not being recognised in interactive mode:
    - synonym for MM.INFO(...).
    - interim fix pending rewrite of pre-processor and its use from interactive
      mode.
  - Fixed bug where error messages over 127 characters would overflow into
    the storage for MM.CMDLINE$
    - error messages are now truncated to 127 characters.

Version 2021.01.00-a2 - 6-Nov-2021:
  - Added ability to specify at the Linux shell a BASIC program that MMB4L
    should RUN when it starts, e.g.
        ./mmbasic myprogram.bas arg1 arg2 arg3
    see README for details.
  - Added optional integer argument (default 0) to END and QUIT that can be
    used to return an exit code to the Linux shell, see README for details.
  - Added SETTICK command from the CMM2:
    - SETTICK FAST is not supported.
    - Be aware that Since Linux is not a Real Time Operating System all timing
      commands such as PAUSE and SETTICK are subject to more error and variation
      than on the microcontroller MMBasic implementations.
  - Added JSON$() function from the CMM2:
    - MMB4L adds an optional 3rd parameter which is a 2 bit argument controlling
      how explicit nulls and missing values are handled in the JSON:
        - &b00 : return empty strings for both.
        - &b01 : return "<null>" for explicit null.
        - &b10 : return "<missing>" for missing value.
        - &b11 : return both "<null>" and "<missing>".
  - Added DAY$(), DATETIME$() and EPOCH() functions from the CMM2:
    - note that unlike DATE$ and TIME$ the DATETIME$(NOW) function will return
      the date & time in UTC, not in the local timezone.
  - Added missing MEMORY, PEEK and POKE sub-commands.
    Now implements the same as the CMM2 (5.07.01) with the exception of the
    undocumented/legacy:
        PEEK(hiaddr, loaddr)
        POKE hiaddr, loaddr, byte
    And with the addition of:
        MEMORY COPY BYTE src, dst, number_of_bytes
          - which is equivalent to MEMORY COPY src, dst, number_of_bytes
        MEMORY COPY SHORT src, dst, number_of_shorts
        MEMORY COPY WORD src, dst, number_of_words
  - Added optional integer array parameter to SYSTEM command to allow any
    standard output generated to be captured in a LONGSTRING, e.g.
        DIM out%(100)
        SYSTEM "ls", out%()
        LONGSTRING PRINT out%()
  - Added support for prefixing paths with '~' which is expanded to the
    users home directory (the value of the HOME environment variable).
  - Added optional integer argument (default 1) to ERROR command allowing an
    error code to be specified, this can be retrieved using MM.ERRNO, e.g.
        ERROR "error message", 220
    For MMB4L the values of MM.ERRNO are:
      - 0        : no error.
      - 1        : unclassified MMBasic error, also reported if a C library call
                   reports the error EPERM (Operation not permitted).
                   Note this differs from other versions of MMBasic which use
                   the value of 16 for general errors, this would correspond to
                   the EBUSY (Device or resource busy) error from a C library
                   call.
      - 2..150   : standard error numbers (errno) for C library calls.
      - 151..200 : reserved for future classification of MMBasic errors.
      - 201..255 : suggested range for program specific error codes.
      - error codes from the SYSTEM command are an exception to this rule,
        see the next entry.
  - Changed SYSTEM command to set MM.ERRNO equal to the executed program's
    exit code. Also changed error message to include this value.
  - Changed CONSOLE SETCURSOR command to allow a maximum x, y of 1023
    (previously 255) and updated "examples/mandelbrot.bas" to support this.
  - Changed "mmbasic.nanorc" to make behaviour more like the CMM2 editor:
      - added 'set constantshow' so the cursor position display is always
        visible.
      - added 'set zap' so that [Delete] and [Backspace] erase all the selected
        text instead of just a single character.
      - either of these can be commented out with # if you prefer.
  - Fixed issues with "mmbasic.syntax.nanorc":
      - command keywords always highlighted, not just when they are the first
        token on a line.
      - hexadecimal and binary constants highlighted as numbers (green).
      - comments correctly highlighted following string constants containing
        apostrophes.
      - highlighting of additional keywords.
  - Fixed timeout bugs with CONSOLE GETCURSOR:
      - increase the timeout to 10s.
      - correct the signed 64-bit arithmetic used in timing code.
  - Fixed bug where navigating the MMBasic prompt history with up/down arrow
    keys would show display artifacts when using PuTTY; though not sure why
    the issue was not generally visible.
  - Many other fixes and tweaks for minor issues encountered along the way.

Version 2021.01.00-a1 - 23-Sep-2021:
  - First alpha version.
