Files
TerminalBasic/docs/dateiformate.md

10 KiB

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"-Formulare des Vorbilds werden nur durch den Konverter gelesen, aber nie geschrieben.

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 schreibt das Textformat und liest das Binärformat ausschließlich zur Konvertierung.

Textformat, zwei Abschnitte: Formular-Beschreibung, dann Code. Schema wie beim Windows-Schwesterprodukt: VERSION-Zeile, verschachtelte Begin <Klassenname> <Name> … 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 <Typ> <Name> … End-Blöcke mit Eigenschaft = Wert-Zeilen (Strings in "…").
  • Danach normaler BASIC-Code des Formular-Moduls.
  • Terminal Basic schreibt VERSION groß, Klassen- und Eigenschaftsnamen in der Schreibweise der Forms-Referenz und drei Leerzeichen je Blockebene.
  • Der Eigenschaftsname belegt 16 Spalten; danach folgen = und der Wert.
  • Eigenschaften stehen in der alphabetischen Reihenfolge der Forms-Referenz und werden nur geschrieben, wenn ihr Wert vom Vorgabewert der Klasse abweicht.
  • Unverändert gelesene Dateien werden bytegleich zurückgegeben; für neu erzeugte oder veränderte Beschreibungen gilt die kanonische Form oben.
  • Zeichenketten verdoppeln ein enthaltenes ". Wahrheitswerte werden als -1 und 0 geschrieben.

Die minimale kanonische Referenz ist vollständig:

VERSION 1.00
Begin Form Form1
   Caption          =  "Beispiel"
   Height           =  15
   Begin CommandButton cmdOK
      Caption          =  "&OK"
   End
End

Binäres VBDOS-1.0-Formular

Der Binärleser ist ausschließlich ein Importpfad. Er erkennt keine Datei an der Endung, sondern an FC 08 01 00. Aus den Originaldateien und dem cout/vbdos-Bestand ergibt sich folgender Aufbau:

Bereich Kodierung Bedeutung
0x0000 FC 08 01 00 Kennung und VBDOS-Formatversion
0x001c u16 little-endian + 0x16 Dateiposition des Objektkatalogs
0x001e u16 little-endian Länge des versionsgebundenen Objekt-/Eigenschaftsbereichs
0x0020 Wurzelkopf und klassenabhängiger Datensatz; danach je Objekt ein 7-Byte-Kopf und der klassenabhängige Datensatz Der Objektkopf nennt Katalogindex, Klasse und Flags; der Datensatz enthält Eigenschaften, Array-Index und Containerverweis
danach Folgen aus u16 Länge und CP437-Bytes Zeichenkettenpool; ein Datensatzverweis p bezeichnet den Längeneintrag bei Dateiposition p + 0x16, die Bytes werden beim Import nach UTF-8 gewandelt
danach u16 Verweis, u8 Klasse, u8 Länge, Name Objektkatalog; Bit 7 der Klasse kennzeichnet ein Steuerelementfeld, die unteren sieben Bit entsprechen der Klassen-ID; Verweis = 0 beendet den Katalog
Ende des Objektbereichs aufsteigende u16-Verweise Verweise auf Datensätze bei Datensatzanfang + 3, unter anderem für Feldinstanzen und physisch umgeordnete Objekte; jeder Verweis muss auf einen gelesenen Datensatz zeigen
Rest Symboltabelle, Modulblöcke und tokenisierter BASIC-Code Bezeichner und der in Text zurückübersetzte BASIC-Code

In den Datensätzen liegen Containerverweis, Tag-Verweis und Arrayindex bei +0, +2 und +4, die Geometrie bei +8 bis +11 und TabIndex bei +13. Beim Form-Root liegen CurrentX/CurrentY bei +19/+20 und BackColor/ForeColor bei +21/+22. Klassenabhängig folgen unter anderem TextBox.BorderStyle/ScrollBars bei +19/+20; bei TextBoxen kodiert außerdem das Common-Flag 0x08 MultiLine. ComboBox.Style liegt bei +31, Label.BorderStyle/Alignment bei +19/+20 und PictureBox.BorderStyle/CurrentX/CurrentY bei +16/+17/+19; Timer.Interval ist ein u16 bei +17. Das Common-Flag 0x10 eines CommandButton kodiert Cancel. Das AutoRedraw-Bit 0x08 von Form und PictureBox steht im Objektkopf; bei Forms kodiert 0x02 zusätzlich FormType = 1. Dort kodiert 0x80 bei ListBoxen Sorted und 0x20 bei Labels AutoSize; bei Menüs kodieren 0x01 und 0x40 Separator und Checked. Scrollbars verwenden ab +14 ein eigenes Layout: Attached, SmallChange, LargeChange, Max und Min; ihr Anfangswert ist Min. Diese Bytes sind ausdrücklich keine Farbwerte.

Der Import ordnet jeden physischen Datensatz über dessen 7-Byte-Kopf dem Katalogeintrag zu; die Katalogreihenfolge ist dafür ausdrücklich nicht maßgeblich. Array-Indizes müssen eindeutig, Containerverweise auf bereits gelesene Objekte gerichtet und Zeichenkettenverweise exakt auf einen Pooleintrag auflösbar sein; auch bei Custom Controls darf kein Pooleintrag unbelegt bleiben. Nicht unterstützte Custom Controls der binären Klasse 17 werden nicht als Screen ausgegeben, sondern mit Objektname und tatsächlicher Byteposition gemeldet. Eine gespeicherte, vom Objektmodell nicht unterstützte Menü-Tastenkombination liegt im erweiterten Menüdatensatz als u16 little-endian bei +19; sie wird als <Menüname>.Shortcut mit ihrer Byteposition gemeldet und übersprungen. Eine unbekannte Klasse, ein ungültiger Verweis, ein unbelegter String oder ein abgeschnittener Bereich führt an der Fundstelle zum Abbruch; eine Ausgabedatei wird erst nach erfolgreichem Lesen angelegt.

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-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/<tabelle> u64 → Bytes ein Satz je Eintrag, Schlüssel ist die Satz-ID
idx/<tabelle>/<index> 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<n> (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, name<TAB>eindeutig<TAB>spalten, 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. tbc build erzeugt wahlweise .tbc oder ein eigenständiges Executable (Runner + eingebettetes .tbc).