SIMPINV/i — Inventory & Order Posting

SteelFrame X application operation manual  ·  ← back to Operation Manuals  ·  Sign On

SIMPINV/i is a compact inventory and order-posting application: it seeds an item master with reference data, posts a stream of receipt / issue / removal transactions against that master, and prints a class-summary report driven by the classic single-primary RPG cycle. It is written entirely in classic RPG III / OPM RPG/400 fixed-form source (H/F/I/E/C/O specifications, compile-time arrays, the RPG cycle) and compiled through CRTRPGPGM — SteelFrame X's rpg3.js front end that converts RPG III to RPG IV (via the CVTRPGSRC pipeline). This manual is honest about what it is: a language-reference / demo estate, deliberately built to exercise classic RPG III features against real business data, not a large production system. It is grounded entirely in the committed source (rpg3-app/src/sources.mjs, rpg_invseed.mjs, rpg_invpost.mjs, rpg_invclsr.mjs, seed.mjs, and the test/inv_build.mjs driver).

Contents

A. Overview & Architecture ↑ top

A.1 What it does

SIMPINV/i runs a three-step inventory flow, one RPG III program per step, all in library SIMPINV:

The three programs are independent CALLs; there is no menu or transaction monitor tying them together — the operator (or a test driver) calls each by name in sequence. Data flows one direction: INVSEED populates INVMAS; INVPOST mutates INVMAS from INVTXN; INVCLSR reports off a pre-summed extract (INVCLSX).

A.2 A classic RPG III estate (honest scope)

SIMPINV/i is a language-reference application: it was built to stress the classic RPG III / OPM RPG/400 surface of SteelFrame X's rpg3.js compiler front end (commit fe8342b11), using real inventory business rules rather than synthetic probes. Every feature it demonstrates — named constants, alternating compile-time arrays, multiple-occurrence data structures (MODS/OCCURS), PERRCD>1 layouts, alternating array comma references, O-spec exception output (EXCPT), the MHxZO zone-move family, and the single-primary RPG cycle with level breaks — is wired into a rule that a real inventory clerk would recognise (a re-order flag, a class total against a threshold, a packed status byte). The estate is deliberately compact: two data files, one flat extract, three programs. It is not, and does not claim to be, a full warehouse-management system; treat it as a faithful, runnable demonstration of classic RPG III against real data.

The whole estate compiles through the real toolchain: each program is created with CRTRPGPGM PGM(SIMPINV/xxx) SRCFILE(SIMPINV/QRPGSRC), which routes RPG III source through rpg3.js's CVTRPGSRC-style conversion to RPG IV and on to the standard build. Source members live in SIMPINV/QRPGSRC (RPG) and SIMPINV/QDDSSRC (DDS), loaded by the app's own seedSimpinv() loader — not auto-run by the emulator.

A.3 Component & flow

  SEED                     POST                      REPORT (RPG cycle)
  ----                     ----                      ------------------
  INVSEED  --WRITE-->      INVPOST  --CHAIN/UPDAT-->  INVCLSR  (P primary)
    INVMAS   (5 items)       INVMAS  (mutated)          INVCLSX (flat extract)
    DSPLY trace              INVTXN  (READ, in-key)     L1 break on GRP (class)
    named consts             QPRINT  (EXCPT report)     QSYSPRT (CLSLN / CLSALR)
    ALT array + LOKUP        AND/OR conditioning        total-time output
    MODS ring buffer         MHLZO status byte

  INVMAS  (item master, keyed ITNO)  <---  INVSEED writes, INVPOST updates/deletes
  INVTXN  (txn log, keyed TXNO)      --->  INVPOST reads in key order
  INVCLSX (program-described flat)   --->  INVCLSR cycle-reads (one pre-summed row per class)

A single flow runs: CALL INVSEED loads the five items → transactions are placed in INVTXNCALL INVPOST posts each against INVMAS and prints the posting report → CALL INVCLSR reads the class-sorted extract through the RPG cycle and prints the class-summary report. The report program reads a separate pre-summed extract (INVCLSX), not INVMAS directly — see section C.2 for why.

A.4 Object inventory

ObjectTypeRole
INVMASPF (DDS)Item master, keyed on ITNO.
INVTXNPF (DDS)Transaction log, keyed on TXNO.
INVCLSXSource PFProgram-described flat extract feeding the cycle report (one pre-summed row per class).
INVSEEDRPG III pgmSeed/reference-data loader for INVMAS.
INVPOSTRPG III pgmTransaction poster + posting report.
INVCLSRRPG III pgmSingle-primary-cycle class-summary report.
QPRINTPrinter fileINVPOST posting report (USROPN, 132-col).
QSYSPRTPrinter fileINVCLSR class-summary report (80-col).
QRPGSRCSource PFHolds the three RPG members.
QDDSSRCSource PFHolds the two DDS members.

The full catalogue is 2 DDS physical files + 1 program-described extract, driven by 3 RPG III programs writing 2 printer files, with source in 2 source PFs — all in library SIMPINV. Sections D and F expand each.

B. Online Transactions & Screens ↑ top

B.1 The command/entry line

SIMPINV/i has no CICS transids and no menu switch. On IBM i each program is reached by name from a 5250 command-entry line (or a JOBQ/scheduler). The operator equivalent of "type a transid and Enter" is "type a CALL command and Enter". Before invoking anything, the job's library list must include SIMPINV — the tested job runs with LIBL = QSYS QGPL SIMPINV QTEMP and CURLIB = SIMPINV.

To do thisType on the command line
Seed the item master (5 items)CALL SIMPINV/INVSEED
Post the transaction log against the item masterCALL SIMPINV/INVPOST (or SBMJOB it)
Print the class-summary cycle reportCALL SIMPINV/INVCLSR
Review the posting reportWRKSPLF → open the QPRINT spool
Review the class-summary reportWRKSPLF → open the QSYSPRT spool

All three programs take no CALL parameters — each reads its data from files, so a scheduled submission is a bare CALL. None of them is interactive; each runs to completion, DSPLYing a trace and/or writing a spooled report.

B.2 What the operator sees (honest: there is no 5250 screen)

Honest statement: SIMPINV/i has no 5250 display file and no interactive subfile. Unlike a screen-driven application, none of the three programs presents a panel, prompts for input, or accepts function keys. There is no DDS DSPF member in the estate — only the two PF members (INVMAS, INVTXN). The programs are batch/DSPLY workers. What the operator actually observes is:

For orientation only, the DSPLY trace INVSEED produces on a clean seed run looks like this (four lines, in order — the seed banner, the item count, the class description read back through the alternating array, and the ring-buffer's final occurrence-1 value):

DSPLY SEEDED DSPLY +000000000000005 DSPLY RawMaterls DSPLY IT0004

These are message-queue lines, not a formatted panel — the manual presents them as the trace they are, not a screen. The operationally meaningful output is the two spooled reports (sections C and E).

C. Batch Jobs & the RPG Cycle ↑ top

SIMPINV/i's work is three parameterless batch programs run in sequence: seed, post, and class report. The first two are ordinary linear RPG III programs (no cycle — an explicit DOWEQ/READ loop in INVPOST, straight-line writes in INVSEED). The third, INVCLSR, is the one program that uses the classic single-primary RPG cycle with an I-spec control level to drive automatic level-break output.

C.1 The three programs

ProgramPurposeReadsWritesCycle?
INVSEED Load 5 reference items into the item master, with a DSPLY trace. Compile-time arrays (CLSCD/CLSDS), named constants. INVMAS (5 WRITE), 4 DSPLY lines. No (straight-line).
INVPOST Post each transaction (receipt/issue/removal) against the item master; print a posting report. INVTXN (READ, key order), INVMAS (CHAIN). INVMAS (UPDAT/DELET), QPRINT (EXCPT report), DSPLY per txn. No (explicit DOWEQ loop).
INVCLSR Accumulate a per-class on-hand total and print a class-summary + reorder-alert report. INVCLSX (primary, cycle-read, one pre-summed row per class). QSYSPRT (CLSLN always; CLSALR when over threshold). Yes (single-primary, L1 break).

INVSEED — the seed loader

Straight-line: for each of five items it MOVELs an item number and description, sets class / on-hand / price, runs XLATE to partially upper-case the description, and WRITEs an INVMASR record. It records the last three item numbers written into a 3-occurrence MODS ring buffer (RECLOG, positioned with OCUR), and looks class descriptions up in the alternating compile-time array with LOKUP + comma index. It ends with a four-line DSPLY trace and SETON LR.

INVPOST — the transaction poster

Reads INVTXN in a structured *IN99 DOWEQ *OFF loop. Per transaction it validates the item number (SCAN for an embedded blank, CHECK for a non-digit suffix, CHEKR for the last significant character), maps the transaction type to a description through the comma-indexed TXDSC array, and CHAINs the item master. Then:

For each posted item it builds a packed 2-byte status code with MHLZO (a severity nibble folded onto the item-class letter), evaluates the REORDER indicator (low stock AND high value) and the REVIEW indicator (class RAW OR class FIN), computes the extended amount, and fires an EXCPT DETL that prints the detail line — plus a second, AND-conditioned marker line when both REORDER and REVIEW are on.

C.2 The single-primary cycle (INVCLSR)

INVCLSR is the estate's showcase of the classic RPG cycle. Its primary file INVCLSX is program-described (an F-spec with the P primary designation and an I-spec that declares the record fields and the control level). The I-spec names GRP (the class code) as an L1 control field and QOH as the class on-hand total. The RPG cycle reads each record automatically; when GRP changes value, an L1 level break fires, running the total-time C-specs and total-time O-spec output before the next detail cycle.

Why a pre-summed extract, not INVMAS. The cycle report reads INVCLSX — one pre-summed row per class (RAW = 4+500 = 504, FIN = 2+60 = 62) — rather than one row per item. This is deliberate: as documented in the source (RPG3-QA-05, logged and independently reproduced), the single-primary cycle's control-field comparison spuriously breaks between two consecutive records that share the same class code. Pre-summing to one row per class sidesteps that trigger while still exercising a real, non-trivial L1 break (RAW → FIN) plus the guaranteed end-of-file break. On this data the two class breaks land on opposite sides of the ALERT branch (504 > 100, 62 ≤ 100), so both branches of the reorder condition are genuinely covered.

Expected QSYSPRT (class-summary report):
  CLASS: RAW    QTY:    504
              ALERT
  CLASS: FIN    QTY:     62

C.3 Ordering & dependencies

D. Data Files (data dictionary) ↑ top

All files are in library SIMPINV, grounded in rpg3-app/src/sources.mjs. The two business files (INVMAS, INVTXN) are externally-described DDS physical files; the cycle report reads a third, program-described flat extract (INVCLSX). DDS field types below use the classic codes: A = character, S = zoned decimal (with a decimal-position digit).

INVMAS — Item master (record INVMASR, key ITNO)

FieldType (DDS)Meaning
ITNO6AItem number (key), e.g. IT0001. Convention: IT + 4 digits.
ITDESC20AItem description (written after XLATE partial upper-casing).
ITQOH7S,0Quantity on hand (integer).
ITPRC9S,2Unit price.
ITCLS1AItem class: R raw, F finished goods, S supplies (leftmost byte of the 3-char class code, via MOVEL truncation).

Seeded item set: IT0001 R/4/199.50, IT0002 R/500/12.75, IT0003 F/2/899.00, IT0004 F/60/145.25, IT0005 S/75/9.99.

INVTXN — Transaction log (record INVTXNR, key TXNO)

FieldType (DDS)Meaning
TXNO6S,0Transaction number (key) — also the posting order, since INVPOST reads in key order.
ITNO6AItem number the transaction applies to (matched into INVMAS by CHAIN).
TXTYP1AType: 1 receipt (add on-hand), 2 issue (subtract), 3 removal (delete item).
TXQTY5S,0Quantity moved (receipt/issue).
TXAMT9S,2Amount field (present in the record; the report's extended amount is computed as TXQTY×ITPRC).

Tested transaction set (7 rows, TXNO 1–7): (1) IT0001 receipt 2, (2) IT0002 issue 50, (3) IT0003 receipt 1, (4) IT0004 issue 10, (5) IT0005 removal, (6) IT9999 receipt 5 (unknown item → NO ITEM), (7) IT 007 receipt 1 (malformed key → BAD KEY).

INVCLSX — Program-described flat extract (cycle primary; RCDLEN 23)

A source physical file of raw fixed-column text, one record per class, pre-sorted by class so the L1 breaks land correctly. It is program-described because I-spec control levels (the L1 that drives the cycle) are a program-described-file feature — an externally-described file has no I-specs to carry an L1 entry. The RPG source I-spec nominally declares GRP at cols 13–15 and QOH at cols 19–23 (the proven convention); the data is deliberately laid out at the actual read offsets the engine uses (see RPG3-QA-04 in F.4).

FieldDeclared colsMeaning
GRP13–15 (L1)Class code (RAW / FIN / ...). The L1 control field.
QOH19–23Pre-summed on-hand total for that class.

Tested extract rows: RAW / 504 (4+500), FIN / 62 (2+60).

Relationships

E. Operations Runbook ↑ top

E.1 Run the flow end-to-end

The reference flow — exactly what test/inv_build.mjs drives — is: create the library and source, compile the three programs, seed, build the extract, report, load the transaction log, and post. In operator terms:

  1. Ensure the job's library list includes SIMPINV (CURLIB(SIMPINV)).
  2. Create the DDS files from source: CRTPF FILE(SIMPINV/INVMAS) SRCFILE(SIMPINV/QDDSSRC) SRCMBR(INVMAS) and the same for INVTXN.
  3. Compile each program: CRTRPGPGM PGM(SIMPINV/INVSEED) SRCFILE(SIMPINV/QRPGSRC) SRCMBR(INVSEED) (and INVPOST, INVCLSR). A clean compile leaves a *PGM object; a failure spools a listing to QPRINT.
  4. CALL SIMPINV/INVSEED — loads 5 items; check the four-line DSPLY trace.
  5. Build / refresh the INVCLSX extract (one pre-summed row per class), then CALL SIMPINV/INVCLSR — review the class-summary spool on QSYSPRT.
  6. Load the transaction log (7 rows) into INVTXN, then CALL SIMPINV/INVPOST — review the posting report on QPRINT and the DSPLY per-transaction trace.

Pre-checks: confirm all three *PGM objects exist; confirm INVMAS is seeded before INVPOST; confirm the job's library list resolves SIMPINV.

E.2 Verified figures (post-checks)

These are the exact figures the build/battle checks against a hand-derived oracle — use them to confirm a healthy run.

After INVSEED

After INVCLSR (class-summary report)

After INVPOST (posting)

E.3 Failure & re-run rules

SituationBehaviourAction
Compile failsNo *PGM object; a listing spools to QPRINT.Read the compile listing, fix the source member, re-run CRTRPGPGM. (The build driver prints the failing listing automatically.)
INVPOST run before INVSEEDEvery CHAIN misses → NO ITEM for all rows.Seed INVMAS first, then re-post.
Re-run INVSEED on a populated masterWRITEs collide with existing keys.Not idempotent — seed once into an empty master. The tested flow starts from a fresh CRTLIB(SIMPINV).
Re-run INVPOSTDestructive/cumulative: receipts/issues re-apply, a removed item stays gone.Not idempotent — re-run the whole flow from a fresh library to reproduce the verified figures.
Unknown item in a transactionCHAIN miss → DSPLY NO ITEM; no phantom row created; loop continues.Correct the transaction's ITNO; the bad row is simply skipped, not fatal.
Malformed item key (embedded blank)SCAN gate trips → DSPLY BAD KEY; CHAIN/UPDAT never reached.Fix the key format (IT+4 digits); the malformed row is skipped safely.
Two same-class rows in INVCLSXSpurious L1 break between consecutive equal keys (RPG3-QA-05).Feed the cycle report one pre-summed row per class, as the tested extract does (F.4).
Because INVSEED/INVPOST mutate INVMAS in place and the seed is not idempotent, the canonical way to reproduce the verified figures is a full clean run from a fresh library — exactly what test/inv_build.mjs does (it rebuilds IBMI_DATA from scratch each run and checks 30+ assertions against a hand-derived oracle).

F. Developer Reference ↑ top

SIMPINV/i is a language-reference application: each program is a vehicle for a cluster of classic RPG III / OPM RPG/400 features. This section maps each program to the exact features it demonstrates, cross- referenced to the rpg3.js deepening (commit fe8342b11) and grounded in the three RPG members plus sources.mjs (which holds the verified classic column-layout helpers: IC3 named constant, IDS3/ISF3 MODS, E3 extension spec, I3r/I3f program-described I-specs, C3 calc, OR3/ OAO3/OF3/O3c output).

F.1 INVSEED — features exercised

Named constants (I-spec col 43 'C')
SEEDMS (char 'SEEDED'), NITEMS (numeric 5), and the two XLATE map constants LO/UPP. A named-constant value sits in a 22-column classic I-spec window (cols 21–42); a longer quoted literal would truncate the closing quote and be refused by the unbalanced-quote guard, so literals are kept short.
Alternating compile-time array + LOKUP + comma index
CLSCD (class code, 3 chars) alternating with CLSDS (class description, 10 chars), declared PERRCD(1), riding one **CTDATA section (RAWRawMaterls, FINFinishedGd, SUPShopSupply). Looked up with LOKUP and read through comma refs like CLSDS,1 / CLSDS,IX. Each 10-char description is chosen to fill the whole 10 columns (never trailing-blank-padded) — see RPG3-QA-01 in F.4.
Multiple-occurrence data structure (MODS / OCCURS)
RECLOG OCCURS 3 with subfield RLITNO (cols 1–6), used as a real 3-slot ring buffer of the last item numbers written, positioned with OCUR. Item 4 explicitly wraps the position back to occurrence 1, overwriting IT0001 — the final DSPLY of occurrence 1 reads IT0004, proving program-controlled wrap (not a platform auto-wrap).
XLATE against named-constant FROM/TO strings
XLATE 'LO:UPP' ITDX ITDESC: factor 1 is the from:to pair, factor 2 the source, result the target. The 9-letter map (rawfinsupRAWFINSUP) upper-cases only those letters over the full description; the rest pass through. The second constant is UPP not UP deliberately (RPG3-QA-02, F.4).
MOVEL truncation into a 1-char field
MOVEL of a 3-char class literal ('RAW') into the 1-char ITCLS keeps only the leftmost byte (R) — exactly the 1-char class code INVPOST's conditioning expects.
Structured IFEQ/ELSE/END + DSPLY trace
The trace uses structured operations (no GOTO/TAG — an unproven surface, left alone), DSPLYing the banner, count, a LOKUP-matched description, and the ring-buffer value.

F.2 INVPOST — features exercised

Named constants (thresholds + banner + digit set)
LOWSTK (10), HIVAL (500), RPTHDR ('INVENTORY REPORT'), DIGITS ('0123456789' — carried as a named constant because a C-spec factor literal's 10-column window can't hold the quoted 10-digit string).
AND / OR multi-slot conditioning indicators
REORDER (indicator 30) = ITQOH < LOWSTK AND ITPRC > HIVAL (via IFLT/ANDGT); REVIEW (indicator 31) = ITCLS = 'R' OR ITCLS = 'F' (via IFEQ/OREQ) — real business rules.
Comma array reference (TXDSC,TXIX)
Transaction-type code → description through a PERRCD(1), 3×8 compile-time array (RECEIPT/ISSUE/REMOVE) indexed by a 1-based TXIX. TXIX is built with a structured IFEQ chain rather than MOVELing a character digit into a numeric field (RPG3-QA-03, F.4).
MHxZO zone-move family (MHLZO)
Packs a 2-char status code: MOVE ITCLS STAT then MHLZO SEV STAT folds the severity flag's zone nibble onto STAT's second byte — the classic space-saving status-byte technique, character operands throughout (a zoned-numeric source is refused by design).
XLATE / SCAN / CHECK / CHECKR item-number validation
SCAN ' ' ITNO (embedded blank), CHECK DIGITS ITNO (non-digit suffix), CHEKR ' ' ITNO (rightmost significant char). A malformed key gates out of the CHAIN/UPDAT body (BAD KEY) instead of an early GOTO.
Keyed ops through classic III spellings
CHAIN (random read of the item master by key), UPDAT (update), DELET (delete a record for a removal transaction). Sequential READ of the keyed INVTXN returns rows in key order.
USROPN printer file + O-spec exception output
QPRINT is UC (USROPN) with explicit OPEN/CLOSE. Output is exception (EXCPT HDR, EXCPT DETL); the estate uses EXCPT because this program does not run the RPG cycle (only 'E' records auto-fire outside the cycle). An edit word renders the extended amount (399.00, 1,452.50). A second DETL record under the same EXCPT name is AND-folded on indicators 30 and 31, printing the REORDER+REVIEW marker only when both are on.

F.3 INVCLSR — features exercised

Single-primary RPG cycle
INVCLSX is a P-designated primary file; the RPG cycle reads each record automatically and drives detail-time and total-time processing without an explicit read loop.
Program-described I-specs with a control level (L1)
I3r('INVCLSX','01') plus I3f lines declaring GRP (L1 control field) and QOH. A change in GRP fires the L1 level break. Control levels are a program-described-file feature — an externally-described file has no I-specs to carry L1.
Total-time (L1) calculations in a live cycle
C-specs carrying ctl=L1 run at total time: the break sets indicator 55; a structured IFxx/ANDxx/END block (also all L1) sets indicator 34 (ALERT) only when CLSTOT > CLSTHR (100) — a real field comparison, not a bare indicator group.
Detail-time accumulation gated on the L1 indicator
The class running total CLSTOT resets in detail time gated on *IN55, not in total time — because the cycle runs all total-time C-specs before the total-time output (RPG3-QA-06, F.4).
Total-time O-spec output, record-granularity AND-fold
Two total-time records (otype T): CLSLN (on 55) always prints CLASS: xxx QTY: nnn; CLSALR (on 55 AND 34) prints ALERT only on breaks over threshold — per-record conditioning, not per-field.

F.4 RPG III / engine caveats (RPG3-QA log)

The source documents a set of confirmed, logged accommodations — some genuine engine quirks in rpg3.js, some intentional app-side idioms. They are reproduced here so a maintainer reads the workarounds as deliberate, not accidental. Each is grounded in a source comment.

IDKindWhat / why
RPG3-QA-01Enginecvt3to4 right-trims every source line unconditionally, including **CTDATA data records — a blank-padded fixed-width data record silently loses its trailing bytes and desynchronizes later PERRCD/ALT chunk boundaries. Workaround: every 10-char class description fills all 10 columns (no trailing blanks).
RPG3-QA-02EngineA field or named constant literally named UP fails compile with a COBOL syntax error, because rpg.js's reserved-word mangling set (that suffixes -R onto RPG names colliding with COBOL keywords) is missing UP. Workaround: the XLATE target constant is named UPP.
RPG3-QA-03EngineA MOVE/MOVEL from a character digit field into a numeric result compiles to a bare COBOL COMPUTE of the alphanumeric field, which GnuCOBOL rejects ("not numeric") — confirmed with a 5-line repro, not RPG-III-specific. Workaround: TXIX is built with a structured IFEQ chain.
RPG3-QA-04EngineA program-described DISK file read through the materialized-source-member path ignores the declared I-spec from/to columns and always extracts from (declared_col − 12) — a 12-byte source-sequence-prefix width. Workaround: INVCLSX data is laid out at the actual read offsets (GRP cols 1–3, QOH cols 7–11) while the I-spec still declares the proven 13–15 / 19–23.
RPG3-QA-05EngineThe single-primary cycle's control-field comparison spuriously breaks between two consecutive records that share the same class code (independently reproduced). Workaround: feed the cycle one pre-summed row per class, so no two adjacent rows share a key.
RPG3-QA-06App idiomNot a platform bug: the cycle driver runs all total-time C-specs before the total-time O-spec output, so a total-time reset zeroes the total before it prints. Correct classic idiom used here: reset in detail time gated on *IN55.
Column-window limits recur throughout: named constants live in a 22-column I-spec window (cols 21–42) and C-spec factor literals in a 10-column window (cols 33–42). Literals that overflow either don't error — they silently shift later columns and corrupt the next field — so descriptions, the LO:UPP map, and banners are all kept short by design, and wider strings (the digit set) ride named constants.

G. Glossary ↑ top

RPG III / OPM RPG/400
Classic fixed-form RPG (H/F/I/E/C/O specification columns), the pre-ILE ("Original Program Model") generation. SIMPINV/i is written entirely in it and compiled through CRTRPGPGM.
RPG cycle
The implicit read-calculate-write loop RPG runs for a primary (P) file: it reads each record, performs detail-time and total-time processing, and drives level-break output automatically — used by INVCLSR.
Level break (L1)
A control-field change in a cycle program. When the L1 field (GRP) changes value, the cycle fires total-time processing for the group that just ended (here, per class).
Detail time / total time
The two phases of a cycle iteration: detail time processes the current record; total time runs at a level break, before the next record's detail. Total-time C-specs and O-specs carry ctl=L1.
Named constant
An I-spec constant (col 43 C) with a fixed value, e.g. LOWSTK=10 — the RPG III way to name a magic number or a literal.
Compile-time array (**CTDATA)
An array whose values are supplied as data records after the source, following a ** separator. TXDSC, and the alternating CLSCD/CLSDS, are compile-time arrays.
Alternating array
Two arrays whose elements interleave in one data record (main element then alternate element per entry) — here class code paired with class description, read via comma refs like CLSDS,1.
PERRCD
Per-record count — how many array elements occupy one compile-time data record. Both arrays here use PERRCD(1) (one logical entry per record).
MODS / OCCURS / OCUR
A multiple-occurrence data structure repeats a layout N times (OCCURS); OCUR positions to a given occurrence. RECLOG OCCURS 3 is used as a ring buffer.
Comma array reference
Indexing an array element with name,index syntax, e.g. TXDSC,TXIX or CLSDS,1.
CHAIN / UPDAT / DELET / READ
Classic RPG file ops: CHAIN randomly reads by key, UPDAT updates the current record, DELET deletes it, READ reads sequentially. INVPOST uses all four.
XLATE / SCAN / CHECK / CHECKR
Character op-codes: XLATE translates via a from/to map; SCAN finds a substring; CHECK/CHECKR verify a field against a character set (from left / from right). Used for upper-casing and item-number validation.
MHxZO (MHHZO/MHLZO/MLHZO/MLLZO)
Move-zone op-codes that copy the high/low zone or digit nibble between character fields — the classic way to pack a compact status byte. INVPOST uses MHLZO.
EXCPT / O-spec
Exception output: an EXCPT op-code fires named O-spec output records on demand. Outside the RPG cycle, only exception ('E') records auto-fire, which is why INVPOST uses EXCPT.
USROPN
User-controlled open (F-spec UC): the program opens and closes the file itself with OPEN/CLOSE rather than at program start/end. QPRINT is USROPN.
Program-described vs externally-described file
An externally-described file takes its record layout from DDS; a program-described file declares fields in I-specs in the program. INVMAS/INVTXN are externally described; INVCLSX is program described (so it can carry the L1 control level).
DSPLY
An RPG op-code that sends a low-level message (to the operator interactively, or the job log in batch). SIMPINV/i uses it for trace output, not as a screen.
CRTRPGPGM / rpg3.js / CVTRPGSRC
The compile path: CRTRPGPGM routes RPG III source through SteelFrame X's rpg3.js front end (a CVTRPGSRC-style RPG III → RPG IV conversion) and on to the standard build.