====== std.edi.core ====== EDIFACT-Interchange-Engine — das Fundament aller ''std.edi.*''-Units. Implementiert die vollständige Umschlag-Hierarchie (UNA / UNB / UNZ / UNG / UNE / UNH / UNT), den Segment-Tokenizer mit Escape-Behandlung, laufende Sequenznummern und Duplikatserkennung pro Partner. Alle anderen EDI-Units importieren ''std.edi.core'' und setzen die hier definierten Structs und Konstanten voraus. import std.edi.core; // 1. Kontext allozieren und initialisieren var ctx: int64 := alloc(EDI_CTX_SIZE); EdiCtxInit(ctx); // Absender / Empfänger setzen (Zeiger in eigene Puffer, kein Copy) poke64(ctx + EDI_CTX_SENDER, "MYCOMPANY" as int64); poke64(ctx + EDI_CTX_SNDLEN, 9); poke64(ctx + EDI_CTX_RCVR, "PARTNER01" as int64); poke64(ctx + EDI_CTX_RCVLEN, 9); // 2. State für Sequenznummern / Duplikatserkennung var state: int64 := alloc(EDI_STATE_SIZE); EdiStateInit(state); // 3. UNB-Header schreiben var out: int64 := alloc(65536); var pos: int64 := EdiUnbWrite(ctx, out, 65536); free(out, 65536); free(state, EDI_STATE_SIZE); free(ctx, EDI_CTX_SIZE); ---- ===== Imports ===== * ''std.alloc'' ---- ===== Konstanten & Standardtrennzeichen ===== Wenn kein UNA-Segment vorhanden ist, gelten folgende Standardwerte (UNOA-Zeichensatz): ^ Konstante ^ Wert ^ Bedeutung ^ | ''EDI_DEF_COMP'' | '':'' (58) | Komponenten-Trenner | | ''EDI_DEF_DATA'' | ''+'' (43) | Datenelement-Trenner | | ''EDI_DEF_DEC'' | ''.'' (46) | Dezimalzeichen | | ''EDI_DEF_REL'' | ''?'' (63) | Release-Zeichen (Escape) | | ''EDI_DEF_SEG'' | '''' (39) | Segmentabschluss | Zeichensatz-Codes: ^ Konstante ^ Bedeutung ^ | ''EDI_CHARSET_UNOA'' | A–Z, 0–9 + wenige Sonderzeichen | | ''EDI_CHARSET_UNOB'' | Latin-1 / ISO 8859-1 | | ''EDI_CHARSET_UNOC'' | UTF-8 | Fehlercodes: ^ Konstante ^ Bedeutung ^ | ''EDI_OK'' | Kein Fehler | | ''EDI_ERR_TRUNC'' | Puffer zu klein | | ''EDI_ERR_NOUNA'' | Kein UNA-Segment gefunden | | ''EDI_ERR_SYNTAX'' | Syntaxfehler im Segment | | ''EDI_ERR_DUP'' | Doppelte Interchange-Referenz erkannt | | ''EDI_ERR_OVERFLOW'' | Zu viele Partner-Slots belegt | | ''EDI_ERR_PARTNER'' | Partner nicht gefunden | ---- ===== Structs ===== Alle Structs werden vom Caller alloziert. Größen sind über Konstanten verfügbar. ==== EdiUna (EDI_UNA_SIZE = 48 Bytes) ==== Hält die Trennzeichen aus dem UNA-Segment oder die Standardwerte. ^ Offset-Konstante ^ Offset ^ Inhalt ^ | ''EDI_UNA_COMP'' | 0 | Komponenten-Trenner (int64) | | ''EDI_UNA_DATA'' | 8 | Datenelement-Trenner (int64) | | ''EDI_UNA_DEC'' | 16 | Dezimalzeichen (int64) | | ''EDI_UNA_REL'' | 24 | Release-Zeichen (int64) | | ''EDI_UNA_RES'' | 32 | Reserviert (int64) | | ''EDI_UNA_SEG'' | 40 | Segmentabschluss (int64) | ==== EdiCtx — Interchange-Kontext (EDI_CTX_SIZE = 128 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_CTX_SENDER / EDI_CTX_SNDLEN'' | Absender-ID (Zeiger + Länge) | | ''EDI_CTX_RCVR / EDI_CTX_RCVLEN'' | Empfänger-ID (Zeiger + Länge) | | ''EDI_CTX_ICREF / EDI_CTX_ICREFLEN'' | Interchange-Referenz (ICR) | | ''EDI_CTX_DATE / EDI_CTX_TIME'' | Datum (YYYYMMDD oder YYMMDD) / Zeit (HHMM) | | ''EDI_CTX_CHARSET'' | Zeichensatz-Code (UNOA/UNOB/UNOC) | | ''EDI_CTX_TESTFLAG'' | 0 = Produktion, 1 = Testmodus | | ''EDI_CTX_COMP / DATA / DEC / REL / SEG'' | Trennzeichen (0 = Standard) | | ''EDI_CTX_MSGCOUNT'' | Anzahl Nachrichten im Interchange | ==== EdiSegCtx — Segment-Iterator (EDI_SEGCTX_SIZE = 40 Bytes) ==== Hält die aktuelle Position im Lesepuffer. Wird von ''EdiSegCtxInit'' initialisiert und von ''EdiSegmentNext'' fortgeschrieben. ==== EdiSeg — Segment-Ergebnis (EDI_SEG_SIZE = 16 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_SEG_PTR'' | Zeiger in den Originalpuffer (Zero-Copy) | | ''EDI_SEG_LEN'' | Byte-Länge ohne Segmentabschluss | ==== EdiElem — Element/Komponenten-Slot (EDI_ELEM_SIZE = 16 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_ELEM_PTR'' | Zeiger in den Originalpuffer | | ''EDI_ELEM_LEN'' | Byte-Länge des Elements/der Komponente | ==== EdiState — Partner-State (EDI_STATE_SIZE = 16 776 Bytes) ==== Speichert pro Partner (max. 16) die laufende Sequenznummer und einen Ring-Buffer von 128 ICR-Hashes zur Duplikatserkennung. ---- ===== Funktionen ===== ==== Initialisierung ==== ^ Signatur ^ Beschreibung ^ | ''EdiCtxInit(ctx: int64): void'' | Nullt alle Felder des Interchange-Kontexts | | ''EdiStateInit(state: int64): void'' | Nullt alle Felder des Partner-State | ==== UNA lesen / schreiben ==== ^ Signatur ^ Beschreibung ^ | ''EdiUnaRead(buf: int64, bufLen: int64, out: int64): int64'' | Liest UNA-Segment aus ''buf''; füllt ''out'' (EDI_UNA_SIZE). Kein UNA → Standardwerte. Gibt ''EDI_OK'' zurück. | | ''EdiUnaWrite(ctx: int64, out: int64, outMax: int64): int64'' | Schreibt UNA-Segment mit den im Kontext gesetzten Trennzeichen; gibt geschriebene Bytes zurück. | ==== Segment-Tokenizer ==== ^ Signatur ^ Beschreibung ^ | ''EdiSegCtxInit(sctx: int64, una: int64, startPos: int64): void'' | Initialisiert Iterator ab Byte-Position ''startPos'' mit Trennzeichen aus ''una'' | | ''EdiSegmentNext(buf: int64, bufLen: int64, sctx: int64, seg: int64): int64'' | Holt nächstes Segment. Gibt 1 (gefunden) oder 0 (Ende) zurück. Zeiger in ''seg'' zeigen in ''buf'' (Zero-Copy). | | ''EdiElementSplit(seg: int64, out: int64, maxOut: int64): int64'' | Spaltet Segment in Datenelemente auf; befüllt ''out''-Array (je EDI_ELEM_SIZE). Gibt Anzahl zurück. | | ''EdiComponentSplit(ptr: int64, len: int64, out: int64, maxOut: int64): int64'' | Spaltet ein Datenelement in Komponenten auf. Gibt Anzahl zurück. | | ''EdiUnescape(src: int64, srcLen: int64, dst: int64, dstMax: int64): int64'' | Entfernt Release-Zeichen (''?'') aus einem String. Gibt Länge des Ergebnisses zurück. | ==== UNB / UNZ — Interchange-Umschlag ==== ^ Signatur ^ Beschreibung ^ | ''EdiUnbRead(buf: int64, bufLen: int64, ctx: int64): int64'' | Parst UNB-Segment; füllt Absender/Empfänger/ICR/Datum ins ''ctx''. Gibt ''EDI_OK'' oder Fehlercode. | | ''EdiUnbWrite(ctx: int64, out: int64, outMax: int64): int64'' | Schreibt UNB-Segment; gibt geschriebene Bytes zurück. | | ''EdiUnzWrite(ctx: int64, msgCount: int64, out: int64, outMax: int64): int64'' | Schreibt UNZ-Trailer (Interchange-Ende). | ==== UNG / UNE — Gruppen-Umschlag ==== ^ Signatur ^ Beschreibung ^ | ''EdiUngWrite(ctx: int64, msgType: int64, grpRef: int64, out: int64, outMax: int64): int64'' | Schreibt UNG-Gruppen-Header | | ''EdiUneWrite(ctx: int64, msgCount: int64, grpRef: int64, out: int64, outMax: int64): int64'' | Schreibt UNE-Gruppen-Trailer | ==== UNH / UNT — Nachrichten-Umschlag ==== ^ Signatur ^ Beschreibung ^ | ''EdiUnhWrite(ctx: int64, msgRef: int64, msgType: int64, out: int64, outMax: int64): int64'' | Schreibt UNH-Nachrichten-Header | | ''EdiUntWrite(ctx: int64, segCount: int64, msgRef: int64, out: int64, outMax: int64): int64'' | Schreibt UNT-Nachrichten-Trailer | ==== Sequenznummern & Duplikatserkennung ==== ^ Signatur ^ Beschreibung ^ | ''EdiSeqNext(state: int64, partnerKey: int64): int64'' | Erhöht Sequenznummer für diesen Partner; gibt nächste Nummer zurück | | ''EdiDuplicateCheck(state: int64, partnerKey: int64, icRef: int64): int64'' | Prüft ob ICR bereits bekannt; gibt ''1'' (Duplikat) oder ''0'' (neu). Trägt neue ICRs automatisch ein (Ring-Buffer mit 128 Einträgen). | ---- ===== Codebeispiel — Eingehende Nachricht parsen ===== import std.edi.core; fn parseEdi(buf: int64, bufLen: int64): void { // 1. UNA-Trennzeichen ermitteln (oder Standardwerte) var una: int64 := alloc(EDI_UNA_SIZE); EdiUnaRead(buf, bufLen, una); // UNB steht nach UNA (9 Bytes) oder am Anfang var startPos: int64 := 0; if (peek8(buf) == 85 && peek8(buf+1) == 78 && peek8(buf+2) == 65) { startPos := 9; } // 2. Segment-Iterator initialisieren var sctx: int64 := alloc(EDI_SEGCTX_SIZE); EdiSegCtxInit(sctx, una, startPos); var seg: int64 := alloc(EDI_SEG_SIZE); var elems: int64 := alloc(16 * EDI_ELEM_SIZE); var done: int64 := 0; while (done == 0) { var r: int64 := EdiSegmentNext(buf, bufLen, sctx, seg); if (r == 0) { done := 1; } else { var n: int64 := EdiElementSplit(seg, elems, 16); // Segment-Tag aus erstem Element auslesen var tag: int64 := peek64(seg + EDI_SEG_PTR); PrintLn("Segment: " + (tag as pchar)); } } free(elems, 16 * EDI_ELEM_SIZE); free(seg, EDI_SEG_SIZE); free(sctx, EDI_SEGCTX_SIZE); free(una, EDI_UNA_SIZE); } ---- ===== Hinweise ===== * **Zero-Copy-Parsing**: ''EdiSegmentNext'', ''EdiElementSplit'' und ''EdiComponentSplit'' setzen Zeiger in den Originalpuffer — keine Kopien. Der Puffer muss während der gesamten Verarbeitung gültig bleiben. * **Caller alloziert**: Alle Structs (UNA, CTX, SEGCTX, SEG, Elem-Arrays) werden vom Caller alloziert und freigegeben. Die Größenkonstanten (''EDI_*_SIZE'') geben die benötigte Byte-Anzahl an. * **Escape-Behandlung**: ''EdiSegmentNext'' behandelt das Release-Zeichen (Standard: ''?'') korrekt — es schützt das darauffolgende Trennzeichen vor Interpretation. Explizite Daten müssen danach durch ''EdiUnescape'' bereinigt werden. * **Duplikatserkennung**: ''EdiDuplicateCheck'' nutzt einen Ring-Buffer mit 128 Hash-Einträgen pro Partner. Bei mehr als 128 ICRs pro Partner kann ein alter ICR wieder als "neu" erscheinen. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.edi.core'' | ''std/edi/core.lyx'' | Letzte Aktualisierung: 2026-06-16