BBC Micro disc image tool - DFS and ADFS catalogue, extract, create, and build with BBC BASIC detokenizer
Project description
beebtools
A Python tool for working with BBC Micro DFS and ADFS disc images.
beebtools reads DFS (.ssd/.dsd) and ADFS (.adf/.adl) disc images.
It can list catalogues, extract and detokenize BBC BASIC programs to a more
human-readable (and text editor friendly) format, and includes a pretty-printer
that makes dense BBC BASIC code more legible.
Disc images
BBC Micro software is widely preserved as disc images - raw sector-by-sector
dumps of original floppy discs. beebtools supports two filing systems:
-
DFS (Disc Filing System) -
.ssd(single-sided) and.dsd(double-sided interleaved) images. Flat catalogue with up to 31 files per side, single-character directory prefixes ($,T, etc.). -
ADFS (Advanced Disc Filing System) -
.adf(single-sided) and.adl(double-sided) images. Hierarchical directory tree with up to 47 entries per directory, full path names like$.GAMES.ELITE. Supports ADFS-S (160K), ADFS-M (320K), and ADFS-L (640K) old-map disc images.
beebtools reads catalogues from both formats and can list them in a
human-readable table, sorted by name, catalogue order, or file size.
Files are extracted by name (T.MYPROG, $.GAMES.ELITE) or by bare name when
unambiguous. On a double-sided .dsd image both sides are catalogued; if the
same bare name appears on both sides, beebtools tells you and asks you to be
specific. Bulk extraction (-a) pulls every file off the disc at once.
Programs: BBC BASIC and binary files
Most files you will want to look at on a BBC Micro disc are BBC BASIC programs.
They are not stored as text. The BBC Micro's BASIC ROM tokenizes programs before
saving them: keywords like PRINT, GOTO, and FOR are replaced with single
bytes in the range 0x80-0xFF, GOTO and GOSUB targets are encoded as compact
3-byte line-number references, and the whole thing is written as a sequence of
binary line records with no human-readable structure.
Binary files (machine code, data, sound samples) are stored as raw bytes and extracted as-is.
For BASIC files, beebtools does two things in sequence when extracting:
-
Detokenize - decode the binary line records back to
LIST-style text, expanding keyword tokens, decoding line-number references, and handlingREMandDATAtails correctly (they are literal ASCII and must not be expanded). -
Pretty-print (optional,
--pretty) - add operator spacing to the raw detokenized text. BBC BASIC stores only the spaces the programmer explicitly typed, so code likeIFx>100THENx=0:y=0is normal. The pretty-printer adds spaces around operators and punctuation while leaving string literals,REMtails, andDATAtails completely untouched.beebtoolsalso handles anti-listing traps, a simply constructed statement that was embedded within a BASIC program. A line starting with*|followed byVDU 21(disable output) bytes. A simple and effective copy-protection trick. The pretty-printer converts*|statements toREM *|and strips the control characters so the program is readable.
When creating images, beebtools performs the reverse - plain-text BASIC (as produced
by step 1 or 2) is retokenized back to the binary format the BBC Micro
expects. The anti-listing trick is not reversed and re-injected into the program
though in this case.
Features
-
Read DFS catalogues from
.ssdand.dsddisc images -
Read ADFS catalogues from
.adfand.adldisc images (old-map, Hugo directories) -
Extract individual files by name (
T.MYPROG,$.GAMES.ELITE, or bareMYPROG) -
Bulk-extract everything from a disc image at once
-
Detokenize BBC BASIC II programs to
LIST-style plain text -
Retokenize plain-text BASIC back to binary - enabling a full detokenize-edit-retokenize workflow
-
Pretty-printer: add operator spacing to make terse BASIC readable
- Anti-listing trap detection: neutralise copy-protection
*|traps
- Anti-listing trap detection: neutralise copy-protection
-
Star command awareness:
*SCUMPIis passed through verbatim, no false spacing -
.infsidecar format support: parse and produce the standard community interchange format for preserving DFS/ADFS file metadata alongside extracted files -
Create, modify, and build disc images from the command line or as a library
-
Zero dependencies - pure Python 3.8+, single package
Installation
pip install beebtools
For development (installs pytest and uses an editable install):
git clone https://github.com/acscpt/beebtools
cd beebtools
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
Commands
beebtools provides commands for inspecting, extracting, and building disc
images. All commands work with both DFS and ADFS images. Each command has its
own detailed reference page.
| Command | Description |
|---|---|
cat |
List disc catalogue with file types and metadata |
search |
Search BASIC source for a text pattern or regex |
extract |
Extract a single file or bulk-extract all files |
create |
Create a blank formatted disc image |
add |
Add a file to an existing disc image |
delete |
Delete a file from a disc image |
build |
Build a disc image from files with .inf sidecars |
Usage
# List what is on a disc image
beebtools cat mydisc.dsd
# Extract and detokenize a BASIC program
beebtools extract mydisc.dsd T.MYPROG
# Extract with operator spacing added
beebtools extract mydisc.dsd T.MYPROG --pretty
# Extract everything from a double-sided disc
beebtools extract mydisc.dsd -a --pretty -d output/
# Extract everything with .inf sidecars preserving file metadata
beebtools extract mydisc.dsd -a --inf -d output/
# List an ADFS disc catalogue
beebtools cat game.adf
# Extract a file from an ADFS disc by full path
beebtools extract game.adf $.GAMES.ELITE --pretty
# Bulk-extract an ADFS disc
beebtools extract game.adf -a -d output/
# Create a blank disc image
beebtools create blank.ssd --title "MY DISC" --boot EXEC
# Add a file to an existing image
beebtools add mydisc.ssd loader.bin --name $.LOADER --load 1900 --exec 1900
# Add a file using its .inf sidecar for metadata
beebtools add mydisc.ssd loader.bin --inf
# Delete a file from an image
beebtools delete mydisc.ssd $.LOADER
# Build a disc image from a directory of files with .inf sidecars
beebtools build output/ rebuilt.ssd --title "REBUILT"
# Create a blank ADFS image (320K)
beebtools create blank.adf -t 80 --title "MY ADFS" --boot RUN
# Add a file to an ADFS image with a hierarchical path
beebtools add mydisc.adf loader.bin --name $.GAMES.LOADER --load 1900 --exec 1900
# Build an ADFS image from a directory tree
beebtools build output/ rebuilt.adl --title "REBUILT"
Pretty-printer
When extracting BASIC files from a disc image, the --pretty flag adds
operator spacing to make the dense tokenized code more readable.
100 IFx>100ORy<0THENx=0:y=0
110 FORi=1TO8:s=s+x*x:NEXTi
120 SOUND1,-15,s,5:IFs>9999THENs=0
With --pretty:
100 IFx > 100ORy < 0THENx = 0 : y = 0
110 FORi = 1TO8 : s = s + x * x : NEXTi
120 SOUND1, -15, s, 5 : IFs > 9999THENs = 0
See docs/pretty-printer.md for the full list of spacing rules and anti-listing trap handling.
Using as a library
from beebtools import openImage, detokenize, tokenize, prettyPrint
# openImage auto-detects DFS (.ssd/.dsd) or ADFS (.adf/.adl)
with openImage("mydisc.dsd") as image:
for side in image:
for entry in side.readCatalogue():
if entry.isBasic:
data = side.readFile(entry)
lines = prettyPrint(detokenize(data))
print("\n".join(lines))
# Retokenize edited plain text back to binary
edited_lines = [" 10PRINT\"HELLO\"", " 20END"]
binary = tokenize(edited_lines)
See docs/library.md for creating disc images, building from
.inf sidecars, and working with the .inf format programmatically.
Supported formats
| Format | Filing system | Description |
|---|---|---|
.ssd |
DFS | Single-sided 40 or 80 track |
.dsd |
DFS | Double-sided interleaved |
.adf |
ADFS | Single-sided (ADFS-S 160K, ADFS-M 320K) |
.adl |
ADFS | Double-sided (ADFS-L 640K) |
DFS: both 40-track and 80-track images are supported. Watford DFS extended catalogues (62-file discs) are not supported.
ADFS: old-map (small directory, "Hugo" format) images are supported for both reading and writing. New-map large-directory formats (ADFS-D/E/F/G) are not supported.
Documentation
See the docs/ folder for full command reference, pretty-printer details, and library API guide.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file beebtools-0.5.0.tar.gz.
File metadata
- Download URL: beebtools-0.5.0.tar.gz
- Upload date:
- Size: 109.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0bfe069a7528faf2fbc1225cb8998b5d872567ee422c91bbe53fab58de0e255
|
|
| MD5 |
b06ffc4d0b4731c9c7e842115c7c675e
|
|
| BLAKE2b-256 |
49d2134850d443d2e556e3620beb9e4c2170cb4ae163e76ef21288352461626d
|
Provenance
The following attestation bundles were made for beebtools-0.5.0.tar.gz:
Publisher:
publish.yml on acscpt/beebtools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
beebtools-0.5.0.tar.gz -
Subject digest:
e0bfe069a7528faf2fbc1225cb8998b5d872567ee422c91bbe53fab58de0e255 - Sigstore transparency entry: 1228257747
- Sigstore integration time:
-
Permalink:
acscpt/beebtools@e9fa7aea53b42ab00cda0340c7f1855d28abd558 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/acscpt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e9fa7aea53b42ab00cda0340c7f1855d28abd558 -
Trigger Event:
push
-
Statement type:
File details
Details for the file beebtools-0.5.0-py3-none-any.whl.
File metadata
- Download URL: beebtools-0.5.0-py3-none-any.whl
- Upload date:
- Size: 57.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
791725a05e9a67c228bd86fcb16ca0903f41d528d1a88fefe7ddfb060918e0b8
|
|
| MD5 |
7a3a45ae9cc402434c6cdf1da2f8326d
|
|
| BLAKE2b-256 |
6afc995c99b28b6d108d4f5160874595580324d6ea758ce58c84811e36b60ae7
|
Provenance
The following attestation bundles were made for beebtools-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on acscpt/beebtools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
beebtools-0.5.0-py3-none-any.whl -
Subject digest:
791725a05e9a67c228bd86fcb16ca0903f41d528d1a88fefe7ddfb060918e0b8 - Sigstore transparency entry: 1228257805
- Sigstore integration time:
-
Permalink:
acscpt/beebtools@e9fa7aea53b42ab00cda0340c7f1855d28abd558 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/acscpt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e9fa7aea53b42ab00cda0340c7f1855d28abd558 -
Trigger Event:
push
-
Statement type: