Menu

SVN-Code Commit Log


Commit Date  
[r13049] by mikeaubury

.NET: REPORT engine

Page and line tracking, the four margins, COLUMN positioning, SKIP, NEED,
page breaks, and the aggregates. A probe compares a report's output
against the C runtime line for line - nothing normalised, since a report
is entirely about column and page layout - and all 66 lines match.

The state follows BaseFGLReport from the original C# library, which had
the data model right even though the behaviour was never written. The
layout defaults were read out of the generated C rather than guessed:
page length 66, margins top 3, bottom 3, left 5, right 132.

COUNT(*) and SUM/AVG keep separate counters: COUNT counts rows while the
others only see non-null values, so a row with a NULL still counts but
does not drag the average down.

2026-09-02 07:33:32 Tree
[r13048] by mikeaubury

.NET: USING format engine

Thirty formats now render identically to the C runtime, checked by a new
probe. Padding is significant here, so values are bracketed and compared
exactly rather than trimmed.

Four rules the probe corrected me on, all of which look wrong coming
from another language:

0 is a LITERAL, not a digit placeholder - the zero-fill character is &.
"###,##0.00" is valid in Oracle and means something else entirely in
4GL, and the C is right to render 1234.5 as 12,340.00 for it.

A zero integer part is blank under #: 0 with "###" is three spaces.

Fill is per position, not per field - one & in "##&" does not zero-fill
the other two.

Sign and currency characters occupy digit positions, so "-----" is five
of them; treating them as decoration overflows the field to asterisks.
Parentheses are the exception and never hold a digit. A single sign sits
where the mask puts it, a run of them floats to the first digit.

2026-09-02 07:29:25 Tree
[r13047] by mikeaubury

.NET: 4GL builtin functions

LENGTH, CLIPPED, UPSHIFT, DOWNSHIFT, ORD, ASCII, the substring operator,
MDY, DAY, MONTH, YEAR, WEEKDAY and DBDATE-aware date formatting - all
checked against the C runtime through the probe, which now compares 27
values rather than 13.

Two details worth having pinned down: the substring operator is 1-based
and inclusive at both ends, so s[1,5] is five characters and not four;
and WEEKDAY counts Sunday as 0, which the C confirms by giving 4 for
29 February 2024. The probe also agrees on day number 45350 for that
date, which independently checks the epoch.

Substrings step in characters, so a subscript cannot cut a surrogate
pair in half.

The divergence note in the probe was stale and has been corrected: the C
no longer leaves a partial character behind when a CHAR is truncated,
but the width is still counted in bytes there and in characters here.

2026-09-02 07:06:32 Tree
[r13046] by mikeaubury

.NET: protocol probe covers MENU; two mismatches it found

The probe now compares canonical JSON rather than text. The C wraps its
output in an envelope and spreads nested objects over many lines, so a
textual diff was only testing formatting; both streams are now parsed
and re-emitted sorted, with the C's array terminators dropped.

Two real differences surfaced once MENU was covered:

Dialog contexts were numbered from 1 here and from 0 in the C. Clients
key on the value, so they now start at 0.

EXIT MENU compiles to a menu action entry the C sends alongside the
commands - {"ACTION":"fgl_exit_menu","CMD_NO_TIMEOUT":n} - which was
never emitted. AddAction() sends it, so a menu built here is the same
menu on the wire.

Eight messages now identical, including the whole nested MENU.

2026-09-02 07:02:03 Tree
[r13045] by mikeaubury

.NET: protocol-level fidelity probe, and a row/column fix it found

dotnet/fidelity/ui/ runs the same sequence of UI operations through both
runtimes and diffs the message streams. The envelope and PROGRAMSTARTUP
are filtered out - a .NET program does not reproduce those and should
not - so what is compared is the message bodies.

It failed on its first run, and the bug was mine: in DISPLAYAT, X is the
COLUMN and Y is the ROW, so 4GL's "AT row, column" is transposed on the
wire. I had it the wrong way round in both the probe and the reference
example, where DISPLAY ... AT n, 1 was emitting X:n, Y:1. It only shows
up when the row and column differ, which is why AT 1,1 looked fine.

Now six messages byte-identical across the two runtimes. DisplayAt says
which field is which, so it does not get repeated.

2026-09-02 06:53:09 Tree
[r13044] by mikeaubury

.NET: complete UI protocol coverage

The remaining 38 verbs, with field names and order transcribed from the
format strings in lib/libui/ui_json. All 66 verbs the C runtime emits
now have a .NET counterpart.

A coverage test guards it: it lists every verb the C emits and fails if
one has no .NET message, which is the only way a protocol split across
two runtimes stays in step. A second test rejects two messages claiming
the same verb - which immediately caught WAITFOREVENT being declared
twice. The C emits it both bare and with CONTEXT/CACHED, so one type now
covers both and omits the fields rather than sending nulls.

2026-09-02 06:51:35 Tree
[r13043] by mikeaubury

.NET: CONSTRUCT, DISPLAY ARRAY and INPUT ARRAY

CONSTRUCT is close to INPUT but not the same - no WITHOUT_DEFAULTS, and
a Columns array naming the database column each screen field searches,
which is what the WHERE clause it produces is written in terms of.

The array dialogs send their rows up front. Row data keeps its padding,
unlike a menu option's text, because it fills fixed-width screen fields.
ARRLINE and SCRLINE are tracked separately: they differ once the list
has scrolled, and conflating them is a standard porting bug.

INPUT ARRAY turned out not to be DISPLAY ARRAY with a different verb -
it carries MAXARRSIZE, WITHOUT_DEFAULTS, ALLOWINSERT, ALLOWDELETE,
NONEWLINES and WRAP as well. Caught by checking the emitter rather than
assuming the two matched.

2026-09-02 06:49:04 Tree
[r13042] by mikeaubury

.NET: INPUT dialog

Modelled from what the C runtime emits for INPUT BY NAME, not from the
source. Three details that only show up in the real output: Fields is
not null-terminated while Events is, event entries use a lowercase
"event" key rather than "type", and event ids are 1-based.

The dialog is declared once - fields, then the events wanted - and the
client drives it, reporting each event by id. Field values arrive with
the events (the reply's SVS array of FN/FT/T/Value) and accumulate, so
a program reads them by name and field_touched() works.

Nested arrays now carry their own null-termination flag, since MENU and
INPUT disagree about it.

2026-09-02 06:45:14 Tree
[r13041] by mikeaubury

.NET MENU: variable option names, and SHOW/HIDE/NEXT OPTION

COMMAND takes char_or_var_vl, so an option's name is often a variable
and only known at run time. Two consequences, both verified against the
C runtime:

Option text is trimmed before it goes on the wire - a CHAR(20) variable
holding "Customer" must not reach the client as "Customer ".
The menu title is deliberately NOT trimmed, because the C does not trim
it either.

SHOW OPTION, HIDE OPTION and NEXT OPTION address an option by its text
rather than its position, so they take a string. The enum still names
the COMMAND clause for dispatch - the clause count is fixed by the
source however dynamic the names are - and TextOf() maps a clause back
to its current text for callers that only hold the enum.

2026-09-02 06:38:11 Tree
[r13040] by mikeaubury

UI protocol: normalise remaining field names; .NET MENU support

Two more lowercase field names missed by r13038, both found by checking
the uilib layer rather than only json.c/xml.c: a second OPTIONS emitter
in ui_json/uilib/uilib.c, and CLEAR's todefault. All emitters now use
one casing for scalar fields; TitleCase names like Fields and
MenuCommands are nested payloads and are left as they are.

.NET: MENU over the wire, checked against what the C runtime actually
emits rather than against the source - which corrected three things.
The objects nested in MenuCommands carry no "type" field, their ids are
1-based, and they include KEYS and HELPNO. That needed a UiPayload /
UiMessage split, since only top-level messages carry a verb.

Menu commands are identified by a caller-supplied enum, so generated
dispatch reads as "case MainMenu.Customer" rather than the old
"case 0: /* COMMAND */".

2026-09-02 06:28:32 Tree
Older >