A Python tool for working with BBC Micro DFS disc images.
beebtools can read disc catalogues, extract and detokenize BBC BASIC programs to
a more human-readable (and text editor friendly) format, including a pretty-printer
that makes dense BBC BASIC code more legible.
BBC Micro software is widely preserved as .ssd (single-sided) and .dsd
(double-sided interleaved) disc images. Each image is a raw sector-by-sector
dump of the original floppy disc, laid out according to Acorn's Disc Filing
System (DFS).
The first two sectors of each disc side hold the catalogue: disc title, file
count, and one entry per file giving its name, DFS directory prefix, load and
exec addresses, byte length, and start sector. beebtools reads this catalogue
and can list it in a human-readable table, sorted by name, catalogue order, or
file size.
Files are extracted by DFS name (T.MYPROG, $.!BOOT) 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.
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 three things in sequence:
-
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. -
Anti-listing trap detection - some 1980s software used
*|followed byVDU 21(disable output) bytes as a copy-protection trick. TypingLISTon the real machine would blank the screen after that line.beebtoolsconverts*|statements toREM *|and strips the control characters, so the program is readable.
-
Read DFS catalogues from
.ssdand.dsddisc images -
Extract individual files by DFS name (
T.MYPROG, or bareMYPROG) -
Bulk-extract everything from a disc image at once
-
Detokenize BBC BASIC II programs to
LIST-style plain text -
Pretty-printer: add operator spacing to make terse BASIC readable
-
Anti-listing trap detection: neutralise copy-protection
*|traps -
Star command awareness:
*SCUMPIis passed through verbatim, no false spacing -
.infsidecar format support: parse and produce the standard community interchange format for preserving DFS 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
pip install beebtoolsFor 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]"beebtools provides commands for inspecting, extracting, and building DFS disc
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 |
# 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 DFS metadata
beebtools extract mydisc.dsd -a --inf -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"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=0With --pretty:
100 IFx > 100ORy < 0THENx = 0 : y = 0
110 FORi = 1TO8 : s = s + x * x : NEXTi
120 SOUND1, -15, s, 5 : IFs > 9999THENs = 0See docs/pretty-printer.md for the full list of spacing rules and anti-listing trap handling.
from beebtools import openDiscImage, detokenize, prettyPrint
image = openDiscImage("mydisc.dsd")
for side in image.sides:
catalogue = side.readCatalogue()
for entry in catalogue.entries:
if entry.isBasic:
data = side.readFile(entry)
lines = prettyPrint(detokenize(data))
print("\n".join(lines))See docs/library.md for creating disc images, building from
.inf sidecars, and working with the .inf format programmatically.
| Format | Description |
|---|---|
.ssd |
Single-sided 40 or 80 track |
.dsd |
Double-sided interleaved |
Both 40-track and 80-track images are supported. The tool does not currently support Watford DFS extended catalogues (62-file discs).
See the docs/ folder for full command reference, pretty-printer details, and library API guide.