Instant PET: Commodore BASIC as Data-URL

mass:werk proudly presents: Running BASIC on a virtual PET 2001 from URL-data.

Network URLs for a virtual PET

So you want to show your friends a little BASIC program or want to solve some problem with (retro) style? Despair no more, since help is near…

More specifically, just a click away, at www.masswerk.at/pet, where you find my enhanced version of Thomas Skibo’s in-browser PET 2001 emulation. What’s new is an additional mode, where the emulator loads (and runs) a program from data encoded in URL-parameters — as provided either in the query-string or in the URL-fragment (hash). And you may use this for immediate execution in direct mode, as well!

(Yes, an advert.)

And here is how we do it:

Loading BASIC Programs from URL-Data

Entire programs may be submitted in the URL, encoded in an optional URL-parameter “data”. The plain text of the program may be either encoded as URL-encoded text (default) or in base64 (using the prefix “base64:” before your data stream. The program text may be either in upper-case or lower-case (auto-detected) and may contain encoded linebreaks.

Let’s say we want to encode this terrific little BASIC program:

10 PRINT "HELLO WORLD"
20 GOTO 10

To link this program, we encode the BASIC text as URI-encoded (x-www-form-urlencoded) and get something like this:

https://www.masswerk.at/pet/?data=10%20PRINT%20%22HELLO%20WORLD%22%0A20%20GOTO%2010

Note: Mind to replace any PETSCII screen characters by CHR$() sequences! The emulator does this for you, see below.

This will load the decoded text as a program into memory, but will not start the program. In order to execute it automatically, we add the parameter “autostart=true”:

https://www.masswerk.at/pet/?data=10%20PRINT%20%22HELLO%20WORLD%22%0A20%20GOTO%2010&autorun=true

Alternatively, we may want to encode the program in base64. For this, we use the prefix “base64:” just before the encoded program:

https://www.masswerk.at/pet/?data=base64:MTAgUFJJTlQgIkhFTExPIFdPUkxEIgoyMCBHT1RPIDEw&autorun=true

We may also choose to supply the program in the URL-fragment (has) instead of in the query string:

https://www.masswerk.at/pet/#data=10%20PRINT%20%22HELLO%20WORLD%22%0A20%20GOTO%2010&autorun=true

Technically, the encoded text will be converted and tokenized and then transferred into the virtual PET by executing a load instruction. The default filename for this is “URL-DATA”, but we may supply our own by use of the parameter “filname” (or “fname”, or just “name”).

Note: For technical reasons (JavaScript’s methods “atob()” and “btoa()” for converting base64-encoded data to and from text) the special character π has to be escaped as “\pi” (which may also come handy, when writing a short snippet — see below).

Here’s the full grammar (case insensitive):

<data-url> ::= ( "?" | "#" ) <parameters>

<parameters> ::= <data-paramter>
                 ["&" <autostart-parameter>]
                 ["&" <filenname-parameter>]

<data-paramter> ::= "data=" ( "base64:"<base64-data> | <uri-component> )

<autostart-parameter> ::= "autostart=" ( "true" | "yes" | "y" | "1" )

<filenname-parameter> ::= ( "filename" | "fname" | "name" ) "=" <filename>

<escaped-π> ::= "\pi"
Running URL-data in the emulator
Loading a script from the URL and running it.
(You may set the screen color in the query-string using “color=(green|white)” [default: green].)

Ecexuting Snippets in Direct Mode

We may also submit a tiny problem in direct mode to solve it at once in (retro) style: Just use “exec” or “execute” instead of the “data” keyword! Direct mode will be always executed at once, no need for the autostart-parameter. (You may still use the URL-fragment/hash instead of the query-string and base64-encoding as well.)

This will automatically type and enter the provided text line by line.

For example,

https://www.masswerk.at/pet/?exec=print(100+20)*5

or

https://www.masswerk.at/pet/?exec=printsin(\pi/6)

Note: In case a snippet starts with a number, it will be treated as a program and executed at once.

Executing a snippet from the URL
Executing a snippet from the URL.

Query String or Fragment (Hash)?

Both methods have their pros and cons: A query string is more robust and will pass through redirects, however, it is subject to logging and may be truncated due to limits set in server or proxy/gateway configurations. A hash is more private and will be handled in the browser only, but is likely to be lost in redirects.

Too Complicated? Let the Emulator Do the Work!

If this sounds too complicated, just let the emulator do the work: Type and test your program in the emulator. When happy, open the “Export” menu at the bottom of the emulated screen and select “BASIC Program as URL”. This will bring up the follow dialog, where you may select encoding, format and auto-start to your liking. Finally, copy the link by a right-click onto the displayed URL.

Executing a snippet from the URL
Generating a portable data-URL in the emulator.

Just like the “portable listing” option, this will also take care of any special PETSCII characters and convert them automatically to “CHR$()” sequences!

Further Examples

Some examples for some real program demos:

Hello World — More or Less

This will run a program producing an output like this:

### COMMODORE BASIC ###

 7167 BYTES FREE

READY.
LOAD "URL-DATA",8

SEARCHING FOR URL-DATA
LOADING
READY.
RUN
HELLO WORLD

MORE OF THIS? [Y,N] Y
HELLO WORLD   HELLO WORLD   HELLO WORLD
  HELLO WORLD   HELLO WORLD   HELLO WORL
D   HELLO WORLD   HELLO WORLD   HELLO WO
RLD   HELLO WORLD   HELLO WORLD   HELLO
WORLD   HELLO WORLD   HELLO WORLD   HELL
O WORLD   HELLO WORLD   HELLO WORLD   HE

Mind the “Screen Text as Unicode” export option to copy any output. :-)

Data-Link: Hello World (more or less).

A Fancy Password Routine

Here’s a subroutine for hidden password input, just give it a try…

10 PRINT:PRINT "PASSWORD: ";
20 GOSUB 3000
30 PRINT "YOU ENTERED: ";PW$
40 END
3000 REM PASSWORD INPUT, RESULT IN PW$
3001 ML=20:REM MAX LENGTH (1..255)
3002 REM CF: CURSOR FLAG, REM 3004 OR 3006
3003 REM PET (ROM 1 & 2)
3004 CF=548:IF PEEK(50003) THEN CF=167
3005 REM C64
3006 REM CF=204
3010 GET C$:IF C$<>"" THEN 3010
3020 PW$="":POKE CF,0
3030 PL=LEN(PW$)
3040 GET C$:IF C$="" THEN 3040
3050 A=ASC(C$):IF A=13 THEN POKE CF,1:PRINT " ":RETURN
3060 IF A=20 AND PL>0 THEN 3090
3070 IF (A AND 127) > 31 AND PL<ML THEN PW$=PW$+C$:PRINT "*";
3080 GOTO 3030
3090 PW$=MID$(PW$,1,PL-1):PRINT" ";CHR$(157);CHR$(157);" ";CHR$(157);:GOTO 3030

Data-Link: Password Demo.

10 Line Adventure

And here’s Robin Harbron’s 10 Line Adventure”, a port to Commodore BASIC of Einar Saukas' Tenliner Cave Adventure (for Sinclair ZX81, 2016), encoded in a data-URL. A tiny text adventure in just 10 lines of BASIC and encoded in a single link! (Mind the use of a custom filename in the data-link.)

Data-Link: 10 Line URL-Data Adv.

An A-Mazing Code Snippet

Finally, here’s a maze oneliner as a code snippet (direct mode), no GOTO involved:

Data-Link: No-Go Maze.

A Console to Assemble Your BASIC Link

Hint: Use “\pi” for “π”.

For a refresher on Commodore BASIC, see the “Pocket Reference Guide To Commodore’s 2001 PET™(PDF).

P.S.: Just in case you didn’t know, you may also run BASIC programs in the emulator by drag and drop, from binary files (.prg, .pet and .d64) or BASIC source files (.txt or .bas).
Just use your favorite text editor and drop the file onto the virtual screen…