Architecture and components
FDL is a small text description language for RMS file structure. An .FDL file is a
sequence of primary sections (FILE, RECORD, KEY,
AREA and others) whose indented attribute lines describe a file's organization,
record format, sizes, and index keys. VX/FDL is the callable library that reads and writes that
description: it parses an FDL text into RMS control blocks (a FAB plus a RAB), creates an RMS
file from an FDL, and generates an FDL text back from an existing RMS file.
VX/FDL is a library plus a DCL command surface, not a long-running service. The
routines compile into the shared VX/RT runtime archive (libvxrt.a) that a migrated
application links directly, and two VX/DCL commands provide the operator front end. There is no
daemon to administer and no separate binary to deploy.
| Translation unit | Public entry point | Role | Status |
|---|
FDL_CRE | FDL$CREATE | Read an FDL, build and SYS$CREATE the matching RMS file. | live |
FDL_GEN | FDL$GENERATE | Open an RMS file and emit an FDL text describing it. | live |
FDL_PAR | FDL$PARSE | Parse an FDL into freshly allocated FAB and RAB blocks. | live |
FDL_REL | FDL$RELEASE | Free the FAB and RAB (and their FNA and XAB) that FDL$PARSE allocated. | live |
No server to administer. VX/FDL adds no process to the runtime. The four
FDL$ routines are entry points inside libvxrt.a, and the DCL commands
call them in-process. The only surface is the four routines plus CREATE/FDL,
ANALYZE/RMS_FILE, and CONVERT/FDL.
Call lifecycle
The three operations share one internal flow: parse an FDL description into control blocks, act
on those blocks (create a file, or the reverse: read a file and emit its description), then
release any blocks that were allocated.
Parse and release control blocks
.FDL textFile structure description
FDL$PARSEAllocates FAB and RAB control blocks
FDL$RELEASEFrees the FAB, RAB, FNA, and XAB blocks
.FDL textOrganization, format, size, and keys
FDL$CREATEParses the description and calls SYS$CREATE
New RMS fileBuilt from the parsed control blocks
Generate an FDL description
RMS fileExisting file and attributes
FDL$GENERATEReads the file's FAB and RAB values
.FDL textOrganization, format, size, and keys
The FDL$ routine API
VX/FDL exports the four public OpenVMS FDL$ routines. Each is defined under an internal
name and aliased to the VMS spelling, so both FDL$CREATE and lowercase
fdl$create resolve to the same symbol and existing object references link unchanged.
| Routine | Signature | Purpose | Status |
|---|
FDL$CREATE | FDL$CREATE(fdl, fname) | Create an RMS file as defined by an FDL specification. | live |
FDL$GENERATE | FDL$GENERATE(flags, fab, rab, fdl) | Open the file named in fab and write an FDL description to fdl (a file spec) or, if empty, to the terminal. | live |
FDL$PARSE | FDL$PARSE(fdl, fab, rab, flags, def, stmt) | Parse an FDL, from a file or from a string, into newly allocated FAB and RAB blocks. | live |
FDL$RELEASE | FDL$RELEASE(pfab, prab, flags, badblk) | Free the FAB and RAB allocated by FDL$PARSE; nulls the caller's pointers. | live |
Every routine follows the VMS condition-value convention: the function result is returned by
value, an odd value means success and an even value means failure, so callers test
ODD(status).
FORTRAN-callable jackets
FDL$CREATE, FDL$GENERATE, and FDL$PARSE also expose
FORTRAN-callable jackets (the F4_* variants). These accept FORTRAN string
descriptors, unpack them, and call the C entry point, so mixed COBOL, FORTRAN, and C application
code links against the same library. FDL$RELEASE has no FORTRAN jacket.
Flag bits
Four public flag bits gate the string-versus-file behaviour of FDL$PARSE and
FDL$GENERATE:
| Symbol | Value | Meaning |
|---|
FDL$M_SIGNAL | 0x1 | Signal errors rather than return them. Reserved for source compatibility; not acted on in this release. |
FDL$M_FDL_STRING | 0x2 | The fdl argument is an in-memory FDL string, not a file spec. |
FDL$M_DEFAULT_STRING | 0x4 | The def argument is a defaults string, not a file spec. |
FDL$M_FULL_OUTPUT | 0x8 | Emit the full, non-abbreviated FDL on generate. Reserved for source compatibility; not acted on in this release. |
Status reporting
The FDL facility defines 33 FDL$_ message codes for source compatibility, tested with
the usual (status & 1) success convention. The shipping library emits
FDL$_OPENFDL when a CREATE/FDL input file is not found, and otherwise
returns the generic RMS and system status codes (RMS$_NORMAL, RMS$_FNF
for file not found, SS$_NORMAL, and related values). FDL-facility status reporting is
therefore thinner than the OpenVMS original; see the status matrix below.
Call lifecycle
The routines cooperate through the RMS control blocks. FDL$PARSE allocates and fills
a FAB and RAB from an FDL text; FDL$CREATE parses internally and materialises a file;
FDL$GENERATE reads a file and emits a text; FDL$RELEASE frees whatever
FDL$PARSE allocated.
Create path
FDL$CREATE seeds RMS defaults into a FAB and RAB, parses the FDL text into that FAB,
resolves the output file name (from the routine argument or the FDL's DEFAULT_NAME),
then runs SYS$PARSE and SYS$SEARCH to compute the next version and
SYS$CREATE to materialise the structure, followed by SYS$CONNECT,
SYS$DISCONNECT, and SYS$CLOSE. It supports three creation modes: the
legacy in-place create, an erase-then-create-in-place mode, and a build-into-a-temporary-file mode
used by CONVERT/FDL.
Parse path
FDL$PARSE allocates a fresh FAB and RAB, seeds RMS type, length, and organization
defaults, and cross-links the RAB to the FAB. If a defaults source is supplied it is read first
(from a string when FDL$M_DEFAULT_STRING is set, otherwise from a file), then the main
FDL source is read and overlaid on top (from a string when FDL$M_FDL_STRING is set,
otherwise from a file). File resolution tries the VMS-to-unix name, then retries with a
.FDL type appended, then retries lowercased, returning RMS$_FNF only after
all three miss. The stmt single-statement parameter is accepted for source
compatibility but not used in this release.
Release path
FDL$RELEASE takes the address of the FAB and RAB pointers, frees the file-name string
and any extended attribute block, then the FAB and the RAB, and nulls the caller's pointers to
avoid dangling references. The flags and badblk arguments are accepted
but unused.
End-to-end C example
The canonical setup, call, check, and cleanup path for a C caller parsing an FDL file into control
blocks. Note the ODD() status test and the address-of-pointer passed to
FDL$RELEASE:
/* string descriptor for the FDL spec */
VMS_DESCR fdl;
FABDEF *fab = 0;
RABDEF *rab = 0;
U32 flags = 0; /* 0 means fdl_path is a FILE spec */
U32 status;
vxrt_dsc64t(&fdl, (U16)strlen(fdl_path), (char *)fdl_path);
/* parse the FDL file into freshly allocated FAB / RAB */
status = FDL$PARSE(&fdl, &fab, &rab, &flags, /*def*/ 0, /*stmt*/ 0);
if (!ODD(status)) /* e.g. RMS$_FNF if the .FDL is absent */
return status;
/* ... use fab / rab: SYS$CREATE, SYS$OPEN, inspect organization ... */
/* free exactly what FDL$PARSE allocated; fab and rab become NULL */
FDL$RELEASE(&fab, &rab, /*flags*/ 0, /*badblk*/ 0);
return SS$_NORMAL;
To parse an in-memory FDL string instead of a file, set flags = FDL$M_FDL_STRING and
point the descriptor at the text.
VX/DCL command surface
Two VX/DCL commands are the operator front end to the library, and a third also consumes an FDL.
They live in VX/DCL and their syntax matches the OpenVMS originals, so existing
.COM procedures and build scripts run with minimal change.
| Command | Calls | Behaviour |
|---|
CREATE/FDL=fdl-file [out-file] | FDL$CREATE | Build the output spec, defaulting a missing type on the FDL to .FDL, verify the FDL file exists, then create the RMS file. The /FDL= value is required and non-negatable. Emits an open error and a file-not-found status if the FDL is missing. |
ANALYZE/RMS_FILE [/OUTPUT=x.FDL] file | FDL$GENERATE | Scan each file spec, default a missing type to .DAT, verify the file exists, build the output FDL spec, then generate the FDL. A missing output name or type defaults to the input name with a .FDL type. |
CONVERT/FDL=fdl-file in... out | FDL$CREATE | Create the output from the FDL into a temporary file, copy records with SYS$GET and SYS$PUT, then rename to the target. Accepts up to 20 input files; /FDL is required unless /APPEND is given. |
CREATE/FDL
The /FDL= value is required and non-negatable; the optional trailing parameter is the
output file name. The handler runs a file scan over the FDL spec to fill in device, directory, and
name, and supplies .FDL when no type is given. /LOG prints a line
reporting whether the file was created.
! FDL to RMS file (FDL$CREATE)
$ CREATE /FDL=CUSTOMER.FDL CUSTOMER.DAT
ANALYZE/RMS_FILE
The ANALYZE/RMS_FILE sub-syntax parses /CHECK, /FDL,
/INTERACTIVE, /RU_JOURNAL, /STATISTICS, /SUMMARY,
and /OUTPUT, but the handler acts only on /OUTPUT in this release: it
writes the generated FDL to the named file. The other analysis qualifiers are accepted by the
parser and not yet acted on. Use /OUTPUT=name.FDL to capture the FDL description.
! RMS file to FDL (FDL$GENERATE)
$ ANALYZE /RMS_FILE /OUTPUT=CUSTOMER.FDL CUSTOMER.DAT
CONVERT/FDL
! load records into an FDL-defined output file
$ CONVERT /FDL=CUSTOMER.FDL CUSTOMER.SEQ CUSTOMER.IDX
What FDL$GENERATE emits
FDL$GENERATE (the routine behind ANALYZE/RMS_FILE /OUTPUT) opens the file
named in the FAB and writes an FDL text describing it. If the file was created outside RMS and
lacks VMS attributes it retries as a variable-format file rather than failing. Output goes to the
FDL descriptor when non-empty, otherwise to the terminal.
The generated FDL is written in a fixed order and covers:
| Emitted section | Source |
|---|
IDENT | File creation time. |
SYSTEM SOURCE | The host identity from uname. |
FILE NAME | The resolved file specification. |
ORGANIZATION | One of sequential, relative, or indexed. |
RECORD FORMAT | One of fixed, stream, variable, or undefined. |
SIZE | The maximum record size. |
KEY blocks | For indexed files only, one block per key, pulled from the runtime key descriptors. |
Scope of the generated FDL. The generator reproduces organization, record
format, size, and keys. It does not reconstruct AREA allocations, bucket sizes,
ACCESS, SHARING, or CONNECT sections, protections, or the
ANALYSIS_OF_* statistics that a native VMS ANALYZE/RMS_FILE would
produce. This is the main difference in fidelity from the OpenVMS original, and is enough to
recreate a working file structure through CREATE/FDL.
The SYSTEM SOURCE line reflects the Linux or Windows host the generator runs on rather
than a VMS node identity, because there is no VMS node lookup on the target platform.
Compatibility and status
VX/FDL covers the create, parse, generate, and release path end to end for all three RMS file
organizations. The table records what is live and what is intentionally out of scope in this
release.
| Capability | Status |
|---|
FDL$CREATE: build an RMS file from an FDL | live |
FDL$PARSE: FDL text to FAB and RAB, from a file or a string | live |
FDL$RELEASE: free parsed blocks | live |
FDL$GENERATE: RMS file to FDL (organization, format, size, keys) | live |
| FORTRAN-callable jackets for CREATE, GENERATE, and PARSE | live |
| Indexed, Relative, and Sequential organizations | live |
| Record formats fixed, variable, stream, and undefined | live |
CREATE/FDL, ANALYZE/RMS_FILE /OUTPUT, and CONVERT/FDL DCL commands | live |
Generation of AREA, ACCESS, SHARING, CONNECT, and ANALYSIS sections | out of scope |
ANALYZE/RMS_FILE qualifiers other than /OUTPUT (/CHECK, /STATISTICS, /SUMMARY and others) | parsed, not acted on |
Full FDL$_ message-facility reporting (33 codes) | partial: codes defined, generic RMS status returned |
FDL$PARSE single-statement (stmt) parameter | accepted, not used |
Divergences from OpenVMS FDL
FDL$GENERATE emits organization, record format, size, and key sections, not the
AREA, ACCESS, SHARING, CONNECT, or
ANALYSIS statistics blocks. The host RMS layer exposes those attributes through the
FAB and key descriptors only.- The
SYSTEM SOURCE line comes from the Linux or Windows host name rather than a
VMS node, because there is no VMS node identity on the target platform. - FDL-facility status reporting is reduced to a small set of codes; most work returns the
generic RMS and system status values. The full set of
FDL$_ symbols exists for
source compatibility. ANALYZE/RMS_FILE honours /OUTPUT; the other analysis qualifiers are
accepted but inert in this release, which implements the FDL-generation path rather than the full
ANALYZE utility family.
Quick reference
Public routines
FDL$CREATE (fdl, fname) // create RMS file from FDL
FDL$GENERATE (flags, fab, rab, fdl) // RMS file to FDL text
FDL$PARSE (fdl, fab, rab, flags, def, stmt) // FDL to FAB / RAB
FDL$RELEASE (pfab, prab, flags, badblk) // free parsed FAB / RAB
Return convention: odd means success, even means failure; test ODD(status).
VX/DCL commands
$ CREATE /FDL=CUSTOMER.FDL CUSTOMER.DAT ! FDL to RMS file (FDL$CREATE)
$ ANALYZE /RMS_FILE /OUTPUT=CUSTOMER.FDL CUSTOMER.DAT ! RMS file to FDL (FDL$GENERATE)
$ CONVERT /FDL=CUSTOMER.FDL CUSTOMER.SEQ CUSTOMER.IDX ! load records into FDL-defined file
Flag bits
FDL$M_SIGNAL 0x1
FDL$M_FDL_STRING 0x2
FDL$M_DEFAULT_STRING 0x4
FDL$M_FULL_OUTPUT 0x8
FDL primary sections
TITLE
IDENT
SYSTEM
FILE
DATE
RECORD
ACCESS
SHARING
CONNECT
AREA
KEY
ANALYSIS_OF_AREA
ANALYSIS_OF_KEY
KEY data types
BIN2
BIN4
BIN8
DBIN2
DBIN4
DBIN8
INT2
INT4
INT8
DINT2
DINT4
DINT8
DECIMAL
DDECIMAL
STRING
DSTRING