File I/O
CLOSE · SAVETEXT · SQL · WRITE · call_sql · deserialize · eof · fetch · fileexists · files · isopen · jmes · loadjson · loadtext · loc · lof · open · open_database · readline · serialize
CLOSE
Finishes with a file. What was written to it is saved now.
CLOSE file
close(file)
Parameters
- file
Example
SCREEN 320, 240
file = OPEN("save.txt") !! output
WRITE file, "checkpoint", 2
CLOSE file
PRINT EXISTS("save.txt")
Notes
It’s also the function close, for when you want what it gives back.
SAVETEXT
Saves text as a file in the game’s folder, in place of what was there.
SAVETEXT path, content
savetext(path, content)
Parameters
- path AS STRING
- content AS STRING
Example
SCREEN 320, 240
SAVETEXT "notes.txt", "remember the key"
PRINT LOADTEXT("notes.txt")
Notes
It’s also the function savetext, for when you want what it gives back.
SQL
Defines a statement for a database, by name: USE lines for its parameters, NULLS lines, then the SQL itself, with each parameter as @name.
A USE line’s DEFAULT and a NULLS value are a number of 0 or more, or a string. For a negative one, let the SQL choose it: SELECT COALESCE(seconds, -1) AS seconds. A USE or NULLS line that can’t be read stops the program at the block, naming the line.
SQL name
...
END SQL
Parameters
- name AS STRING - What the statement is called, for
CALL_SQL.
Example
SCREEN 320, 240
SQL "make"
CREATE TABLE IF NOT EXISTS scores (name TEXT, points INTEGER)
END SQL
SQL "add"
USE STRING name
USE NUMBER points
INSERT INTO scores (name, points) VALUES (@name, @points)
END SQL
SQL "all"
SELECT name, points FROM scores ORDER BY points DESC
END SQL
db = OPEN_DATABASE("scores.db") !! writable
CALL_SQL(db, "make")
CALL_SQL db, "add" !! name("ada") points(100)
FOR row = CALL_SQL(db, "all")
PRINT row.name, row.points
END FOR
CLOSE db
Notes
Opens a block of text. I don’t read it: I hand it over just as you wrote it. It’s sql.
WRITE
Writes its values to a file as one line, with a space between them.
WRITE file, values...
write(file, values...)
Parameters
- file
- values…
Example
SCREEN 320, 240
file = OPEN("log.txt") !! output
WRITE file, "level", 3, "cleared"
CLOSE file
PRINT LOADTEXT("log.txt")
Notes
It’s also the function write, for when you want what it gives back.
call_sql
Runs a statement a SQL block named. A statement that reads gives its rows, each a map of its columns; one that writes gives rows_affected and last_id.
call_sql(database, name AS STRING, values = NULL)
Parameters
- database - What
OPEN_DATABASEgave. - name AS STRING - The
SQLblock’s name. - values = NULL - The statement’s parameters. Each is written by its name after
!!.
Example
SCREEN 320, 240
SQL "make"
CREATE TABLE IF NOT EXISTS scores (name TEXT, points INTEGER)
END SQL
SQL "add"
USE STRING name
USE NUMBER points
INSERT INTO scores (name, points) VALUES (@name, @points)
END SQL
SQL "top"
USE NUMBER least DEFAULT 0
SELECT name, points FROM scores
WHERE points >= @least
ORDER BY points DESC
END SQL
db = OPEN_DATABASE("scores.db") !! writable
CALL_SQL(db, "make")
CALL_SQL db, "add" !! name("ada") points(100)
CALL_SQL db, "add" !! name("bob") points(80)
best = CALL_SQL(db, "top") !! least(90)
FOR row = best
PRINT row.name, row.points
END FOR
CLOSE db
deserialize
Parses a JSON string back into its original data structure. Used to restore game state, player data, settings, and other complex data from storage. Accepts any valid JSON, including data from external APIs or files.
deserialize(serialized_data)
Parameters
- serialized_data - A JSON string, typically from serialize or LOADTEXT
Example
SCREEN 320, 240
saved = "{\"name\": \"ada\", \"level\": 3, \"items\": [\"key\", \"map\"]}"
player = deserialize(saved)
PRINT player.name, player.level, player.items(1)
eof
Returns TRUE (1) if the handle is exhausted, FALSE (0) otherwise. Works for both DATA block handles (exhausted when every value has been READ) and file-stream handles opened FOR INPUT (exhausted when every line has been read). For a closed or invalid handle, EOF returns TRUE — so a stray WHILE NOT EOF(n) on a never-opened handle terminates immediately rather than spinning.
eof(filenumber)
Parameters
- filenumber - A file that
OPENgave
Example
SCREEN 320, 240
SAVETEXT "notes.txt", "one\ntwo\nthree"
file = OPEN("notes.txt")
WHILE NOT eof(file)
PRINT READLINE(file)
END WHILE
PRINT eof(file)
CLOSE file
fetch
Synchronous HTTP client. Returns an Object with exactly two fields: STATUSCODE (Integer) and MESSAGE (String). On success, STATUSCODE is the HTTP status (200, 404, 500, …) and MESSAGE is the response body as text. On failure to complete an HTTP exchange (DNS failure, connection refused, TLS error, invalid URL, invalid method, timeout), STATUSCODE is 0 and MESSAGE is a human-readable error description. Network errors do NOT halt the interpreter — the BASIC program detects them via STATUSCODE. A non-Object headers argument is handled the same way (STATUSCODE=0 with the error in MESSAGE; it does not halt). Only a wrong argument count halts.
fetch(url, method, body = NULL, headers = NULL)
Parameters
- url - Full URL of the resource
- method - HTTP method (case-insensitive: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, …)
- body = NULL - Optional body. String sent as-is. Object/Array auto-encode as JSON with Content-Type: application/json. Other types stringified.
- headers = NULL - Optional 4th-arg Object of header names → values (e.g. {“Authorization”: “Bearer xyz”})
Example
SCREEN 320, 240
answer = fetch("not a url", "GET")
// A request that never reached a server answers 0, with why in MESSAGE
IF answer.statuscode = 0
PRINT "no answer:", LEN(answer.message) > 0
ELSE
PRINT answer.statuscode
END IF
fileexists
Checks whether a file exists in the project’s local storage (the same VFS that LOADTEXT, SAVETEXT, and OPEN use). Returns 1 if the file is present, 0 otherwise.
fileexists(filename)
Parameters
- filename - Path to test, same form accepted by LOADTEXT / OPEN
Example
SCREEN 320, 240
PRINT fileexists("save.txt")
SAVETEXT "save.txt", "checkpoint 2"
PRINT fileexists("save.txt")
files
Returns a 1D array of filenames in the bus root or in path. Used to discover what’s loadable / saved / available without hardcoding lists in BASIC.
files
files(path = NULL)
Parameters
- path = NULL - Optional directory inside the bus root. Omit (or pass empty) for the root.
Example
SCREEN 320, 240
SAVETEXT "notes.txt", "hello"
FOR name = files()
IF name = "notes.txt" THEN PRINT "found", name
END FOR
isopen
Returns 1 if the given file or DATA block handle is currently open, 0 otherwise. Useful for cleanup paths that may run without knowing whether OPEN succeeded, and for guarding a CLOSE against an unopened handle (which would otherwise be a silent no-op rather than an error, but the guard reads more clearly).
isopen(filenumber)
Parameters
- filenumber - Handle to test (1-255)
Example
SCREEN 320, 240
file = OPEN("log.txt") !! output
PRINT isopen(file)
WRITE file, "started"
CLOSE file
PRINT isopen(file)
jmes
Runs a JMESPath query against an array or object (or any value) and returns the result. JMESPath is a compact query language for JSON-like data — it reaches into nested fields, slices and filters arrays, projects values, and applies built-in functions such as max, length, and sort_by. The data is matched as if it were JSON, so objects, arrays, numbers, strings, and booleans all work.
jmes(data, query)
Parameters
- data - An array, object, or any value to query (commonly the result of deserialize or LOADJSON)
- query - A JMESPath query string
Example
SCREEN 320, 240
scores = [{name: "ada", points: 100}, {name: "bob", points: 80}, {name: "cy", points: 95}]
PRINT jmes(scores, "[?points > `90`].name")
PRINT jmes(scores, "max_by(@, &points).name")
PRINT jmes(scores, "length(@)")
loadjson
Loads and parses JSON data from files in the project bundle. Returns the parsed data as CrashBasic objects and arrays. Excellent for loading structured game data, level definitions, sprite configurations, and complex settings. The object comes back untyped, with no user TYPE and therefore no methods. Ending the assignment with AS typename turns it into an instance of a declared type — every declared field present, the file’s values laid over the type’s defaults. See TYPE.
loadjson(filename)
Parameters
- filename - Name of JSON file in project bundle (relative to project root)
Example
SCREEN 320, 240
level = loadjson("level.map.json")
PRINT level.mapwidth, level.mapheight, level.tileset
loadtext
Loads text content from files in the project bundle. Returns the complete file content as a string. Ideal for loading game data, configuration files, level definitions, dialog text, and any text-based resources.
loadtext(filename)
Parameters
- filename - Name of text file in project bundle (relative to project root)
Example
SCREEN 320, 240
notes = loadtext("input-files-notes.txt")
PRINT LEN(notes) > 0
SAVETEXT "hello.txt", "hi there"
PRINT loadtext("hello.txt")
loc
Returns the current read/write position of an open handle. For a DATA block handle, this is the 0-based index of the next value to be read. For a file-stream handle (OPEN … FOR INPUT / OUTPUT / APPEND), this is the 0-based line number — how many lines have been read or written so far. Returns -1 if the handle is closed or invalid.
loc(filenumber)
Parameters
- filenumber - Handle from OPEN or OPEN DATA
Example
SCREEN 320, 240
SAVETEXT "notes.txt", "one\ntwo\nthree"
file = OPEN("notes.txt")
PRINT loc(file)
first = READLINE(file)
second = READLINE(file)
// Two lines read
PRINT loc(file)
CLOSE file
lof
Returns the total size of the resource backing an open handle. For a DATA block handle, this is the total number of values in the block. For a file-stream handle, this is the total number of lines in the buffered file. Returns -1 if the handle is closed or invalid.
lof(filenumber)
Parameters
- filenumber - Handle from OPEN or OPEN DATA
Example
SCREEN 320, 240
SAVETEXT "notes.txt", "one\ntwo\nthree"
file = OPEN("notes.txt")
PRINT lof(file), "lines"
CLOSE file
open
Opens a file in the game’s folder, and gives the file to read from or write to. Without a modifier it is opened to read.
open(path AS STRING, output = FALSE, append = FALSE)
Also documents: append, output
Parameters
- path AS STRING - The file, in the game’s folder.
- output = FALSE
- append = FALSE
After !!
- append(on = TRUE) - Add to the end of the file, keeping what is there.
- output(on = TRUE) - Write the file afresh, in place of what was there.
Example
SCREEN 320, 240
file = OPEN("scores.txt") !! output
WRITE file, "ada", 100
CLOSE file
file = OPEN("scores.txt") !! append
WRITE file, "bob", 80
CLOSE file
file = OPEN("scores.txt")
WHILE NOT EOF(file)
PRINT READLINE(file)
END WHILE
CLOSE file
open_database
Opens a database in the game’s folder, and gives it, for CALL_SQL and CLOSE. Without a modifier it is opened to read.
open_database(path AS STRING, writable = FALSE)
Also documents: writable
Parameters
- path AS STRING - The file, in the game’s folder.
- writable = FALSE
After !!
- writable(on = TRUE) - Open it to change as well as to read.
Example
SCREEN 320, 240
SQL "make"
CREATE TABLE IF NOT EXISTS scores (name TEXT, points INTEGER)
END SQL
db = OPEN_DATABASE("scores.db") !! writable
CALL_SQL(db, "make")
CLOSE db
readline
The next line of a file, or NULL when there are no more.
readline(file)
Parameters
- file
Example
SCREEN 320, 240
SAVETEXT "notes.txt", "first\nsecond"
file = OPEN("notes.txt")
PRINT READLINE(file)
PRINT READLINE(file)
PRINT READLINE(file) = NULL
CLOSE file
serialize
Converts objects, arrays, or any data structure to a JSON string for storage or transmission. Essential for saving game state, player progress, settings, and complex data structures to persistent storage. The output is standard JSON, so it can be used with external tools or APIs that accept JSON.
serialize(data)
Parameters
- data - Any data type (Object, Array, String, Number, Boolean, TYPE structure)
Example
SCREEN 320, 240
player = {name: "ada", level: 3, items: ["key", "map"]}
SAVETEXT "save.json", serialize(player)
PRINT LOADTEXT("save.json")
back = deserialize(LOADTEXT("save.json"))
PRINT back.items(0)