A complete Informix 4GL CRUD application driven through BLT: 4GL source (printers.4gl), screen-form spec (printers.per), and DDL (printers.sql) on the input side; the generated functional specification on the output side. The application maintains a printers table with id, name, description, command, destination, and active columns. BLT recovers what each user-facing function does to that table and emits the result as evidence-cited findings with explicit confidence levels.
DATABASE fms
DEFINE m_current RECORD
id INTEGER,
name CHAR(20),
desc CHAR(60),
cmd CHAR(20),
dest CHAR(1),
active CHAR(1)
END RECORD
MAIN
DEFER INTERRUPT
DEFER QUIT
OPTIONS
INPUT WRAP,
PROMPT LINE LAST,
MESSAGE LINE LAST,
NEXT KEY CONTROL-F,
PREVIOUS KEY CONTROL-B
LET int_flag = 0
CALL main_code()
EXIT PROGRAM
END MAIN
FUNCTION main_code()
OPEN FORM autoform FROM "printers"
DISPLAY FORM autoform
MENU "Action"
COMMAND "Query" "Find a record" CALL query_det()
COMMAND "Add" "Add a record" CALL add_det()
COMMAND "Update" "Update a record" CALL update_det()
COMMAND "Delete" "Delete a record" CALL delete_det()
COMMAND KEY ("E") "Exit" "Exit this program" EXIT MENU
END MENU
END FUNCTION
FUNCTION add_det()
CALL init_buf()
INPUT BY NAME
m_current.id, m_current.name, m_current.desc,
m_current.cmd, m_current.dest, m_current.active
AFTER INPUT
INSERT INTO printers (
id, name, desc, cmd, dest, active
) VALUES (
m_current.id, m_current.name, m_current.desc,
m_current.cmd, m_current.dest, m_current.active
)
IF SQLCA.SQLCODE != 0 THEN
ERROR "ERROR: Row not added: ", SQLCA.SQLCODE
ELSE
MESSAGE "Row added"
END IF
END INPUT
END FUNCTION
database fms@dmi_on
screen size 24 by 80
{
id [f000 ]
name [f001 ]
desc [f002 ]
[f003 ]
cmd [f004 ]
dest [a]
active [b]
}
end
tables
printers
attributes
f000 = formonly.id type int;
f001 = printers.name;
f002 = printers.desc[1,30];
f003 = printers.desc[31,60];
f004 = printers.cmd;
a = printers.dest;
b = printers.active;
end
create table "informix".printers (
id serial not null,
name char(20) not null,
desc char(60) not null,
cmd char(20) not null,
dest char(1),
active char(1),
check (active IN ('Y', 'N')),
check (dest IN ('E', 'S', 'P', 'D', 'T'))
constraint "informix".printers_dest
);
create unique index "informix".iu_printers
on "informix".printers (id) using btree;
Run against the three inputs above, BLT produces a deterministic behavioural specification covering the printers application's user-facing behaviour. Every finding is cited to the underlying source artefact and carries an explicit confidence level so a reviewer can trust the spec or drill into the citation.
| Surface | What BLT recovers for printers |
|---|---|
| Program type | Each application is classified as interactive or batch based on whether the source contains any user-interaction surface — a menu, an open form, a PROMPT read, or a CONSTRUCT query-builder. Printers is interactive (a menu drives every CRUD action through an attached form). A pure-DML or report-only program with no operator input is classified as batch. |
| Programs | When a Makefile sits alongside the 4GL source, BLT reads it and lists every compiled program it builds — one JSON entry per program, each carrying the program name, the on-disk binary filename, the Makefile it came from, and which signal identified it (variable assignment, all: rule, or compile-command line). A multi-target Makefile (one all: ProgA.4ge ProgB.4ge line) surfaces as multiple entries; a Makefile-less project leaves the list empty. Recognised on common Informix patterns: the PROG = name / PROGRAM = name / TARGET = name variable, the all: rule target, and c4gl / fglcomp / fglrun compile invocations (with variable references resolved against the rest of the Makefile). Each program entry also carries a missing_files list flagging any source file the Makefile names but that doesn’t exist on disk — the consumer sees an incomplete source set explicitly rather than silently processing a broken build. Point BLT at a Makefile alone and BLT auto-discovers every referenced 4GL module and every form-spec file in the same directory — the full pipeline runs without the operator having to enumerate sources by hand. |
| Database operations | Per CRUD function (add_det, update_det, delete_det): which DML it performs against the informix.printers table. All at high confidence (the schema confirms the table exists; the source confirms the operation). |
| Form layout | Each screen field carries its on-screen label, row/column position, and display width recovered from the form spec’s visual layout block. Fields appear in top-to-bottom visual order. Every recovered form carries a unique id across the spec, even when two form-spec files share a basename in different directories — collisions are disambiguated deterministically so a UI generator can address each form unambiguously. The form’s title defaults to the form’s filename. |
| Fields | Each form field bound to its backing column with type, nullability, and any check-constraint predicates that apply. Form-only fields recognised explicitly and not flagged as unbound. Fields with no visible placement (or marked noentry) are flagged hidden. A column split across multiple visual rows — printers.desc[1,30] + printers.desc[31,60] — collapses into one logical field with a multi-row hint, while the audit-grade spec keeps the underlying bindings atomic. |
| Menus | Every menu command appears in the order it was declared in the source — including the Exit entry and key-only entries (like INTERRUPT) that the side-effect projection filters out. HIDE OPTION and SHOW OPTION visibility-control statements are captured per menu so a UI generator can model conditional visibility. Each menu also carries a default command — the entry the operator’s cursor lands on when the menu opens. Recovered from BEFORE MENU initial-focus overrides when present; otherwise the first command in declared order. |
| Workflows | Each menu command chained to its handler function and the screen form the handler operates on, in source order. Direct DML handlers reach the table; cursor-driven handlers chain through the navigation primitives. |
| Function call tree | Every function entry carries its outgoing call edges — the other functions it invokes (intra-program calls) and the external programs it launches (cross-program runs are tagged separately so a UI generator can render them differently). Multi-call counts are aggregated, so a helper invoked twice in different code paths shows once with a count of 2. Mirrors the binary side’s call graph in shape, so a consumer can cross-reference source vs binary call trees uniformly. |
| Dispatch styles | BLT recognises both canonical menu blocks and the alternative form-input + value-dispatch idiom (where a value is read from a form field and a multi-branch decoder picks the handler). Both styles surface in the menu section with the same shape, so the UI generator doesn’t need separate code paths for each — and a per-menu kind field discriminates the two so the UI tool can pick its rendering (letter-shortcut buttons for canonical menus, numbered choices for prompt-style dispatchers) without heuristics. The branch threshold is set so accidental value-decoder structures (yes/no answer checks, error-code handlers) don’t misfire as menus. User-visible labels on numbered-dispatcher commands are sourced from the static text in the linked form’s layout (lines like “1. General Ledger”) and projected straight onto each command, so a generated UI shows “[1 General Ledger]” rather than bare “[1]” buttons. Labels on canonical menus stay sourced from their own source-declared COMMAND text. Help/tooltip text per command comes from the canonical “help” string on a MENU/COMMAND block; for numbered-dispatcher commands BLT pulls it from each handler module’s file-header synopsis comment, so a tooltip ends up with the documented purpose of the target module. |
| Screen-menu-function linkage | The three concepts are wired together explicitly. Each screen lists the functions that open it; each menu lists the screen(s) its enclosing function drives. The linkage is deterministic in both directions, so a downstream tool doesn’t need to fall back to convention-based string matching (e.g. inferring that the apmenu screen pairs with the apmain function from name overlap). When a function opens a form indirectly via a load-from-database helper, that’s captured the same way as a direct open. |
| Audit signals | BLT surfaces an audit list at the top of the spec for findings that look worth a second look but aren’t hard errors. The first such signal is a label/help mismatch: when a menu command’s on-screen label and its tooltip help come from genuinely independent sources (the form text and the handler module’s documentation respectively) and don’t share a single substantive word even after abbreviation and stop-word tolerance, BLT emits an audit entry naming the menu, key, label, and help text. Catches real source drift — for example, a form whose option says “Sales System” routing into a module documented as “Payroll System Main Module” in its header comment. The downstream tool can decide whether to surface the warning, suppress the help, or proceed; BLT just flags the divergence. |
| Rules | Validation guards (IF-around-DML) and post-condition checks (the canonical IF SQLCA.SQLCODE != 0 pattern after each insert/update/delete) extracted as explicit business rules with their predicate text. |
| Messages | Every DISPLAY, MESSAGE, ERROR, and PROMPT string captured with its enclosing function and (when applicable) the predicate that gates it. |
| Transactions | Each BEGIN WORK / COMMIT WORK / ROLLBACK WORK marker captured with its in-function scope. |
| Confidence | Every finding tagged High / Medium / Low / Unknown. The summary block tallies the breakdown; review-flagged items are surfaced separately for human attention. |
| Review items | Low-confidence findings and unresolved bindings raised in the review log so they don’t pass silently into the spec. |
The same source produces a byte-identical specification on every run — determinism is a hard property of the output, not a best-effort one.
To discuss how Oninit ® can assist please call on +1-913-732-8892 or alternatively just send an email specifying your requirements.
You get all this for free.. think about what you get if you pay us