# Dateiformate Terminal Basic liest und schreibt die Textformate des Vorbilds, durchgängig in UTF-8 (Abweichung: das Vorbild nutzte die DOS-Codepage). Binäre „Fast-Load"-Varianten des Vorbilds sind Nicht-Ziel — nur Textformate. ## Quelltext: `.BAS` Reiner Text, eine Anweisung(sfolge) pro Zeile. Optionale Kopfzeilen der IDE (`DECLARE`-Prototypen) werden beim Speichern erzeugt/aktualisiert. Metabefehle in Kommentaren: `'$INCLUDE: 'datei.bi'`, `'$STATIC`, `'$DYNAMIC`. ## Formular: `.FRM` Das Vorbild kannte zwei Speicherformate: **binär** („Fast load and save", Standard) und **Text** („Readable by other programs"). Terminal Basic implementiert nur das Textformat; das Binärformat ist Nicht-Ziel (FT.EXE des Vorbilds konvertierte zwischen beiden). Textformat, zwei Abschnitte: Formular-Beschreibung, dann Code. Schema wie beim Windows-Schwesterprodukt: `VERSION`-Zeile, verschachtelte `Begin … End`-Blöcke (Klassennamen siehe forms-referenz.md), `Eigenschaft = Wert`-Zeilen. Der Parser des Vorbilds akzeptiert Version 1.00 und 2.00 (Import aus dem Windows-Produkt via Übersetzer). ``` VERSION 1.00 Begin Form Form1 Caption = "Beispiel" Height = 15 Left = 10 Top = 4 Width = 50 Begin CommandButton cmdOK Caption = "&OK" Height = 1 Left = 18 Top = 11 Width = 10 End End SUB cmdOK_Click () UNLOAD Form1 END SUB ``` - `VERSION`-Zeile, dann verschachtelte `Begin … End`-Blöcke mit `Eigenschaft = Wert`-Zeilen (Strings in `"…"`). - Danach normaler BASIC-Code des Formular-Moduls. - TODO: Ein wörtliches Original-Beispiel einer Text-`.FRM` war online nicht auffindbar (Beispieldateien des Originalpakets liegen alle binär vor). Exakte Serialisierung (Kopfzeile, Einrückung, welche Eigenschaften geschrieben werden) ist daher festzulegen: wir folgen dem Windows-1.0-Schema und dokumentieren unsere Fassung als Referenz. ## Projekt: `.MAK` Reine Textdatei ohne Kopfzeile, **eine Projektdatei pro Zeile** (`.BAS`/`.FRM`; belegt durch die Originalbeispiele). Terminal Basic akzeptiert zusätzlich Kommentarzeilen mit `'`. ## Record-Dateien (`GET`/`PUT`, `OPEN … FOR RANDOM`) Feste Strings (`STRING * n`) in Records werden als **UTF-32LE** gespeichert (4 Bytes pro Zeichen → feste Record-Länge bleibt erhalten). Entscheidung 2026-09-02: Die Binärdateien sind damit bewusst inkompatibel zu Dateien des Vorbilds; numerische Felder behalten ihr klassisches Layout (INTEGER i16, LONG i32, SINGLE f32, DOUBLE f64, CURRENCY i64, little-endian). ## ISAM-Datenbank (`OPEN … FOR ISAM`) Eigenes Format, **bewusst nicht binärkompatibel** zu Datenbankdateien des Vorbilds — dieselbe Linie wie bei den UTF-32-Records oben. Ein Konvertierungswerkzeug ist Nicht-Ziel; das Vorbildformat wird weder gelesen noch geschrieben. **Träger.** Die Datei ist eine [`redb`](https://crates.io/crates/redb)-Datei (eingebetteter transaktionaler B-Baum). `redb` liefert Seitenverwaltung, Transaktionen und Crash-Sicherheit; die ISAM-Semantik darüber ist eigener Code (siehe `tb-runtime::isam`). **Formatversion.** Die Datei trägt in ihrer Metatabelle unter `version` eine 32-Bit-Formatversion (little-endian), derzeit **1**. Eine Datei mit höherer Version wird beim Öffnen mit Laufzeitfehler 88 („ISAM - Database inconsistent") abgewiesen, statt fehlinterpretiert zu werden. Ebenso abgewiesen wird eine bestehende Datei ohne Versionsmarke sowie jede strukturell unlesbare Datei. **Tabellen in der Datei.** Je Datenbankdatei: | `redb`-Tabelle | Schlüssel → Wert | Inhalt | |---|---|---| | `tb_meta` | `&str → Bytes` | Formatversion, Layout, Indexdefinitionen, ID-Zähler | | `satz/` | `u64 → Bytes` | ein Satz je Eintrag, Schlüssel ist die Satz-ID | | `idx//` | `Bytes → u64` | Indexeintrag: Schlüsselbytes → Satz-ID | Die Einträge in `tb_meta` je Tabelle `T`: - `tab:T` — Layoutkurzform `spalte:typ;…` mit den Typkürzeln `I2`, `I4`, `R4`, `R8`, `CY`, `T` (fester Text mit `n` Zeichen). Beim Öffnen einer bestehenden Tabelle wird sie gegen den angegebenen Satztyp geprüft; Abweichung ist Fehler 88. - `idx:T` — eine Zeile je Index, `nameeindeutigspalten`, Spalten als Feldnummern mit `-` für absteigend. - `seq:T` — nächste Satz-ID (u64, little-endian). IDs werden **monoton** vergeben und **nie wiederverwendet**: ein Cursor merkt sich eine Satz-ID, und eine nach `DELETE` neu vergebene ID ließe ihn still auf einen fremden Satz zeigen. **Satzbytes.** Ein Satz liegt genau so im Speicher wie ein Record bei `PUT` auf eine `RANDOM`-Datei: numerische Felder klassisch und little-endian, feste Strings als UTF-32LE. Daher gilt die Inkompatibilität zum Vorbild aus demselben Grund wie oben. **Indexschlüssel.** Die Schlüsselbytes sind **ordnungserhaltend** kodiert — ihr Byte-Vergleich entspricht dem fachlichen Vergleich, weil `redb` nach Bytes ordnet: - Ganzzahlen: Big-Endian fester Breite mit gekipptem Vorzeichenbit. - Gleitkommazahlen: Big-Endian der Bitdarstellung; bei negativem Vorzeichen alle Bits invertiert, sonst das oberste Bit gesetzt. - Text: UTF-8 (dessen Bytereihenfolge ist die Codepoint-Reihenfolge, siehe „Sortierordnung" der Sprachreferenz). `00` im Text wird zu `00 FF` verdoppelt, den Abschluss bildet `00 00` — damit ordnet ein echtes Präfix vor jedem längeren Text. - Absteigende Spalten: alle Bytes dieser Spalte invertiert. - Mehrspaltig: Verkettung in Spaltenreihenfolge. An jeden Indexschlüssel sind acht Bytes Satz-ID (Big-Endian) angehängt. Das macht auch Einträge eines mehrdeutigen Index eindeutig, hält Dubletten in Einfügereihenfolge und macht die Präfixsuche zur Bereichsabfrage. ## Kompilat: `.tbc` (neu, eigenes Format) Container für TBVM-Bytecode, Entwurf in [tbvm-design.md](tbvm-design.md). `tbc build` erzeugt wahlweise `.tbc` oder ein eigenständiges Executable (Runner + eingebettetes `.tbc`).