From 97cbc3e0e8a886aa5fb9820d3d9f7d3c4ffb669e Mon Sep 17 00:00:00 2001 From: Ken Johnson Date: Mon, 20 Apr 2026 08:21:48 -0700 Subject: [PATCH] Docs: refresh for v0.6.0 (UpdateMessage + mb.* namespace cleanup) Two related doc passes: 1. UpdateMessage docs. docs/API.md "Updating & deleting" section previously said "Optional operations. Not every backend implements them -- default returns False." Since v0.6.0 that's wrong: UpdateMessage has header-metadata-only semantics on every backend. Rewrote the section to describe the semantics, typical use cases (flipping attr bits, reply-chain pointers), and the boundary (body / CtrlInfo / SubFields / inline kludges untouched; need Delete + WriteMessage for body changes). Added a note by the .Native escape-hatch example that most previously- native-only operations now have uni-API equivalents. 2. ma.* -> mb.* namespace sweep. The 0.5.0 rename renamed every source unit but the docs kept the old names in code-block `uses` clauses and architecture diagrams. Copy-paste consumers hitting those would get compile errors. Replaced word-boundary ma. references in README.md, docs/API.md, docs/architecture.md, docs/ftsc- compliance.md, and docs/format-notes/dependencies.md with the mb.* form. Left docs/PROPOSAL.md alone -- that is the pre- rename design doc and reads as historical record. All 75 tests pass; full six-target build clean. Retagging v0.6.0 in place since no downstream has pinned yet. --- README.md | 26 +++++------ docs/API.md | 71 +++++++++++++++++++++---------- docs/architecture.md | 28 ++++++------ docs/format-notes/dependencies.md | 6 +-- docs/ftsc-compliance.md | 2 +- 5 files changed, 80 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index bb7b33e..1fb0936 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,14 @@ can target a single interface regardless of the underlying format on disk. | Format | Files | Backend unit | |-----------|--------------------------------------|---------------------------| -| Hudson | MSGINFO/IDX/HDR/TXT/TOIDX.BBS | `ma.fmt.hudson.pas` | -| JAM | `*.JHR` `*.JDT` `*.JDX` `*.JLR` | `ma.fmt.jam.pas` | -| Squish | `*.SQD` `*.SQI` `*.SQL` | `ma.fmt.squish.pas` | -| FTS-1 MSG | numbered `*.MSG` per directory | `ma.fmt.msg.pas` | -| PCBoard | `*.MSG` + `*.IDX` | `ma.fmt.pcboard.pas` | -| EzyCom | `MH#####.BBS` / `MT#####.BBS` | `ma.fmt.ezycom.pas` | -| GoldBase | MSGINFO/IDX/HDR/TXT/TOIDX.DAT | `ma.fmt.goldbase.pas` | -| Wildcat 4 | WC SDK databases | `ma.fmt.wildcat.pas` | +| Hudson | MSGINFO/IDX/HDR/TXT/TOIDX.BBS | `mb.fmt.hudson.pas` | +| JAM | `*.JHR` `*.JDT` `*.JDX` `*.JLR` | `mb.fmt.jam.pas` | +| Squish | `*.SQD` `*.SQI` `*.SQL` | `mb.fmt.squish.pas` | +| FTS-1 MSG | numbered `*.MSG` per directory | `mb.fmt.msg.pas` | +| PCBoard | `*.MSG` + `*.IDX` | `mb.fmt.pcboard.pas` | +| EzyCom | `MH#####.BBS` / `MT#####.BBS` | `mb.fmt.ezycom.pas` | +| GoldBase | MSGINFO/IDX/HDR/TXT/TOIDX.DAT | `mb.fmt.goldbase.pas` | +| Wildcat 4 | WC SDK databases | `mb.fmt.wildcat.pas` | **FTN PKT** is a transport-tier wire format and lives in the sibling [`fpc-ftn-transport`](../fpc-ftn-transport/) library @@ -54,7 +54,7 @@ in 0.4.0 because PKT is a wire format, not a storage format. - Event hooks for logging, progress, and status reporting. - Path / filename auto-derivation per format from a base directory plus optional area tag (`area` attribute auto-populated on Read). -- **Shared FTSC kludge plumbing** in `ma.kludge` — single source of truth +- **Shared FTSC kludge plumbing** in `mb.kludge` — single source of truth for kludge-line parse/emit (`ParseKludgeLine`, `SplitKludgeBlob`, `BuildKludgePrefix/Suffix`). Unknown FTSC kludges round-trip uniformly as `kludge.` regardless of which backend stored them, so @@ -69,8 +69,8 @@ with the unified-API factory. Forgetting it produces ```pascal uses - ma.types, ma.events, ma.api, - ma.fmt.jam, ma.fmt.jam.uni; { both — .uni registers } + mb.types, mb.events, mb.api, + mb.fmt.jam, mb.fmt.jam.uni; { both — .uni registers } ``` Native Linux: @@ -91,8 +91,8 @@ The repo includes a `fpc.cfg` template covering the multi-target build ## Layout ``` -src/ ma.api, ma.types, ma.events, ma.lock, ma.paths, ma.kludge -src/formats/ ma.fmt..pas — one per supported format +src/ mb.api, mb.types, mb.events, mb.lock, mb.paths, mb.kludge +src/formats/ mb.fmt..pas — one per supported format docs/ architecture, locking semantics, format notes tests/ FPCUnit tests, sample data examples/ small CLI programs that double as smoke tests diff --git a/docs/API.md b/docs/API.md index a858489..1c5294e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -29,8 +29,8 @@ program hello; {$mode objfpc}{$H+} uses SysUtils, - ma.types, ma.events, ma.api, - ma.fmt.jam, ma.fmt.jam.uni; + mb.types, mb.events, mb.api, + mb.fmt.jam, mb.fmt.jam.uni; var base: TMessageBase; @@ -58,15 +58,15 @@ end. | Format | Units to add to `uses` | |-----------|---------------------------------------------| -| Hudson | `ma.fmt.hudson, ma.fmt.hudson.uni` | -| JAM | `ma.fmt.jam, ma.fmt.jam.uni` | -| Squish | `ma.fmt.squish, ma.fmt.squish.uni` | -| FTS-1 MSG | `ma.fmt.msg, ma.fmt.msg.uni` | +| Hudson | `mb.fmt.hudson, mb.fmt.hudson.uni` | +| JAM | `mb.fmt.jam, mb.fmt.jam.uni` | +| Squish | `mb.fmt.squish, mb.fmt.squish.uni` | +| FTS-1 MSG | `mb.fmt.msg, mb.fmt.msg.uni` | | FTN PKT | (moved to `fpc-ftn-transport`; `uses tt.pkt.reader, tt.pkt.writer`) | -| PCBoard | `ma.fmt.pcboard, ma.fmt.pcboard.uni` | -| EzyCom | `ma.fmt.ezycom, ma.fmt.ezycom.uni` | -| GoldBase | `ma.fmt.goldbase, ma.fmt.goldbase.uni` | -| Wildcat | `ma.fmt.wildcat, ma.fmt.wildcat.uni` | +| PCBoard | `mb.fmt.pcboard, mb.fmt.pcboard.uni` | +| EzyCom | `mb.fmt.ezycom, mb.fmt.ezycom.uni` | +| GoldBase | `mb.fmt.goldbase, mb.fmt.goldbase.uni` | +| Wildcat | `mb.fmt.wildcat, mb.fmt.wildcat.uni` | The `.uni` unit's `initialization` section registers the factory; without it, `MessageBaseOpen(, ...)` raises `EMessageBase`. @@ -76,7 +76,7 @@ Threads on Unix need `cthreads` first in the program's `uses`: ```pascal uses {$IFDEF UNIX}cthreads,{$ENDIF} - ma.api, ...; + mb.api, ...; ``` --- @@ -256,7 +256,7 @@ if base.SupportsAttribute('attr.returnreceipt') then RenderReceiptCheckbox; ``` -### Canonical attribute bits (`ma.types`) +### Canonical attribute bits (`mb.types`) The MSG_ATTR_* cardinal constants stay as the internal pivot between native flag words and the individual `attr.*` boolean @@ -284,7 +284,7 @@ Bits 0..15 match FTS-0001 exactly; 16+ are for storage-layer flags (deleted/read/echo/etc.) that aren't part of the FTN wire format. Use `UniAttrBitsToAttributes` / `UniAttrBitsFromAttributes` -helpers in `ma.types` to bridge the bitset to/from individual +helpers in `mb.types` to bridge the bitset to/from individual `attr.*` boolean attributes. ### FTN addressing @@ -395,10 +395,28 @@ function UpdateMessage(Index: longint; var Msg: TUniMessage): boolean; function DeleteMessage(Index: longint): boolean; ``` -Optional operations. Not every backend implements them — the -default returns False. Attribute-only changes can also be made -through the native API (`.Native`) by flipping the MSG_ATTR_DELETED -bit and calling `Pack`; that pattern works on every backend. +**`UpdateMessage` — header-metadata-only, every backend (since v0.6.0).** +Reads the existing message, applies header-shaped attrs from +`Msg`, rewrites the fixed-size header / ISAM record in place. +Body, CtrlInfo (Squish), inline kludges (`*.MSG`), and SubFields +(JAM) are NOT touched. Typical use cases: flipping an attribute +bit (deleted / received / sent), updating reply-chain pointers +(`jam.reply1st` / `jam.replynext`, `squish.reply1st` / +`squish.replynext` list, `hudson.prevreply` / `hudson.nextreply`, +etc.), rewriting `cost` or `msg.timesread`. Callers that need +body-level changes should `DeleteMessage` + `WriteMessage`. + +Per-backend header-slot coverage — the attrs each backend honours +on Update are the same slots its `ClassSupportedAttributes` +publishes as "header-shaped." See +[`attributes-registry.md`](attributes-registry.md) for the full +matrix. + +`DeleteMessage` is currently optional — not every backend +implements it; the default returns False. Attribute-only +deletion also works via the native API (`.Native`) by flipping +the `attr.deleted` bit on `UpdateMessage` and calling `Pack`; +that pattern works on every backend. --- @@ -487,7 +505,7 @@ base.Events.MinLevel := metWarning; { drop info + debug } ## Locking -Three layers, all in `ma.lock`: +Three layers, all in `mb.lock`: 1. **TRTLCriticalSection** per `TMessageBase` instance — serialises concurrent Read/Write/Update/Delete calls on the same instance. @@ -540,8 +558,8 @@ Use it from there: ```pascal uses {$IFDEF UNIX}cthreads,{$ENDIF} - ma.api, { TMessageBase + factory } - ma.fmt.jam, ma.fmt.jam.uni, { destination msgbase } + mb.api, { TMessageBase + factory } + mb.fmt.jam, mb.fmt.jam.uni, { destination msgbase } tt.pkt.format, { wire-format types } tt.pkt.reader, { registers mbfPkt } tt.pkt.batch; { TPacketBatch + Run loop } @@ -556,7 +574,16 @@ See `fpc-ftn-transport/docs/` for the worker-pool details. Every `.uni` adapter exposes `Native` for callers who need format- specific features the unified API doesn't abstract (JAM subfields, Squish UMsgId, EzyCom dual-byte attributes, Wildcat NextMsg -walking, etc.): +walking, etc.). + +Note that many previously-native-only operations have uni-API +equivalents now — e.g. header rewrites go through +`base.UpdateMessage` since v0.6.0 and don't need the `Native` +dance below. Drop to `Native` only when the unified API really +can't express what you need. + +Native header-rewrite example (pre-v0.6.0 pattern, still +supported): ```pascal var @@ -618,7 +645,7 @@ Native class names: - `tests/` — test_read, test_roundtrip, test_roundtrip_attrs, test_lock, test_batch, test_wildcat, test_write_existing, test_pack, test_hwm, test_consumer_round1 -- `ma.kludge` — shared FTSC kludge parsing/emission helpers +- `mb.kludge` — shared FTSC kludge parsing/emission helpers (`ParseKludgeLine`, `SplitKludgeBlob`, `BuildKludgePrefix`, `BuildKludgeSuffix`) for callers that need to handle raw FTSC body blobs outside an adapter diff --git a/docs/architecture.md b/docs/architecture.md index cf34c9d..6139e47 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -9,17 +9,17 @@ │ ▼ ┌──────────────────────────────────────────────────┐ - │ ma.api (TMessageBase, factory, TUniMessage) │ + │ mb.api (TMessageBase, factory, TUniMessage) │ ├──────────────────────────────────────────────────┤ - │ ma.events ma.lock ma.paths ma.kludge │ + │ mb.events mb.lock mb.paths mb.kludge │ ├──────────────────────────────────────────────────┤ │ Format backends — two .pas units per format: │ - │ ma.fmt. - native record + I/O class │ - │ ma.fmt..uni - TMessageBase adapter │ - │ ma.fmt.hudson(.uni) ma.fmt.jam(.uni) │ - │ ma.fmt.squish(.uni) ma.fmt.msg(.uni) │ - │ ma.fmt.pcboard(.uni) ma.fmt.ezycom(.uni) │ - │ ma.fmt.goldbase(.uni) ma.fmt.wildcat(.uni) │ + │ mb.fmt. - native record + I/O class │ + │ mb.fmt..uni - TMessageBase adapter │ + │ mb.fmt.hudson(.uni) mb.fmt.jam(.uni) │ + │ mb.fmt.squish(.uni) mb.fmt.msg(.uni) │ + │ mb.fmt.pcboard(.uni) mb.fmt.ezycom(.uni) │ + │ mb.fmt.goldbase(.uni) mb.fmt.wildcat(.uni) │ ├──────────────────────────────────────────────────┤ │ RTL: TFileStream, BaseUnix/Windows for locking │ └──────────────────────────────────────────────────┘ @@ -33,7 +33,7 @@ ``` PKT is a wire format and lives in `fpc-ftn-transport`, not here. -The `mbfPkt` enum value stays in `ma.types` so `tt.pkt.reader` +The `mbfPkt` enum value stays in `mb.types` so `tt.pkt.reader` can register the backend with the unified-API factory. Consumers wanting to iterate `.pkt` files just `uses tt.pkt.reader` and call `MessageBaseOpen(mbfPkt, ...)` as usual. TPacketBatch @@ -41,14 +41,14 @@ call `MessageBaseOpen(mbfPkt, ...)` as usual. TPacketBatch **Integration gotcha:** to use a backend through the unified `TMessageBase` API you must include the `.uni` adapter unit in -your `uses` clause, not just the native `ma.fmt.` unit. +your `uses` clause, not just the native `mb.fmt.` unit. The adapter's `initialization` block is what registers the backend with the factory. ```pascal uses - ma.types, ma.events, ma.api, - ma.fmt.jam, ma.fmt.jam.uni; { both — .uni is what registers } + mb.types, mb.events, mb.api, + mb.fmt.jam, mb.fmt.jam.uni; { both — .uni is what registers } ``` Forgetting `.uni` produces `EMessageBase: No backend registered @@ -196,9 +196,9 @@ This saves echomail consumers from having to copy AreaTag into every message attribute manually. Multi-format scanners always get a populated `area` when the area is configured. -### Shared kludge plumbing — `ma.kludge` +### Shared kludge plumbing — `mb.kludge` -`ma.kludge` exposes the FTSC-form-kludge parsing/emission helpers +`mb.kludge` exposes the FTSC-form-kludge parsing/emission helpers the inline-kludge backends (MSG, PKT) and CtrlInfo-style backend (Squish) share, plus what JAM's FTSKLUDGE subfield walking uses: diff --git a/docs/format-notes/dependencies.md b/docs/format-notes/dependencies.md index 0ff8a06..61d67d5 100644 --- a/docs/format-notes/dependencies.md +++ b/docs/format-notes/dependencies.md @@ -35,12 +35,12 @@ jam.txt (JAM), squish.doc (Squish/Lanius), pcboard.doc, the EzyCom reference, and the WildCat 4 SDK headers vendored under `src/wc_sdk/`. When in doubt about an encoding or bit position, reference the spec -before changing the conversion tables in `ma.types.pas`. +before changing the conversion tables in `mb.types.pas`. -## ma.fmt.wildcat.pas +## mb.fmt.wildcat.pas The Wildcat backend uses the WildCat 4 SDK vendored at `src/wc_sdk/`. The SDK is kept on its own search-path entry (`-Fusrc/wc_sdk`) so callers that don't need Wildcat can omit the backend without forcing the SDK onto the build line. See the active cleanup pass to trim the -SDK to only what `ma.fmt.wildcat` actually uses. +SDK to only what `mb.fmt.wildcat` actually uses. diff --git a/docs/ftsc-compliance.md b/docs/ftsc-compliance.md index 51fa6fb..5da726f 100644 --- a/docs/ftsc-compliance.md +++ b/docs/ftsc-compliance.md @@ -7,7 +7,7 @@ packet headers, and kludge syntax must match the specs exactly. ## Specs applied -| Area | Spec | Status in `ma.types.pas` | +| Area | Spec | Status in `mb.types.pas` | |----------------------------------------|----------------|----------------------------------| | FTS-1 attribute word (bits 0..15) | fts-0001.016 | Verified: bits match spec | | FTS-1 *.MSG file layout (190 bytes) | fts-0001.016 | Implemented per spec |