====== 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