🚨 Oracle not porting Rdb to x86 and EOL on Itanium 12/2027 🚨
Technical Capabilities
Having trouble finding what you need?
Get in touch with us, so we can answer your specific questions directly.
Get In Touch

FMS$ - Forms Management System

Overview

VX/FMS$ is a native C reimplementation of OpenVMS FMS (Forms Management System) for x86 and ARM Linux. It exports the OpenVMS FDV$ Forms Driver callable interface, so applications that call FDV$LOAD, FDV$DISPW, FDV$GET and the rest of the 66-routine set link and run unchanged. Forms authored in the FMS form language compile to the same binary form format and load from the same form libraries.

The product ships as a static library (libfms.a) plus command-line utilities and a terminal form editor. Compiled forms render to VT, ANSI, and xterm terminals through an escape-sequence driver rather than a VMS terminal driver, and every FDV$ routine returns the same VMS-style condition codes, so forms-based applications keep their existing screen behaviour and error handling on Linux.

<!-- Webflow embed (min). Source: fms-api-page-technical/fms-tech-body-embed-dark.html → python3 website/embeds/minify_webflow_embed.py … --> <div class="s7-tech-embed" data-vxfmsd-body-embed="1" data-technical-mega-embed="1" lang="en"><h2 id="architecture">Architecture and dispatch</h2><p> VX/FMS$ is a linked library, not a daemon. An application links against <code>libfms.a</code> (or <code>libfmsx.a</code> in standalone mode) and calls the FDV$ Forms Driver routines directly. The whole product is a single portable source tree: the same files build for OpenVMS and for Linux, guarded by <code>__VMS</code> conditionals, so behaviour on Linux tracks the VMS original rather than forking from it. Three pieces make up the product: the FDV$ Forms Driver runtime, the FMS form language and binary form format, and a terminal driver that paints forms with escape sequences. </p><h6>Two-layer call dispatch</h6><p> Every FDV$ call passes through two layers. This is the single most important structural fact about the runtime. </p><div class="table-wrapper"><table><thead><tr><th>Layer</th><th>Symbol shape</th><th>Role</th></tr></thead><tbody><tr><td>Public entry (VMS ABI)</td><td><code>FDV_D_XXX</code>, aliased to <code>FDV$XXX</code> / <code>fdv$xxx</code></td><td>The ABI-facing thunk. On VMS it probes the caller's argument count and NULLs out omitted trailing arguments, then calls the implementation and normalises the return value.</td></tr><tr><td>Implementation</td><td><code>FCC_XXX</code></td><td>The actual work: validates arguments, checks the current terminal control area and cancel state, mutates the workspace, drives the terminal, and returns an <code>FDV__*</code> condition code.</td></tr></tbody></table></div><p> The dollar-sign name is bound to a dollar-free real symbol through an alias table, because <code>$</code> is legal in OpenVMS identifiers but not in a portable C symbol. The public thunk and its implementation look like this: </p> <pre><span class="cmt">/* public thunk: normalises the VMS ABI */</span> <span class="kw">U32</span> FDV_D_ADLVA(<span class="kw">S32</span> *video) { begin_FDV(); <span class="cmt">#ifdef __VMS</span> <span class="kw">int</span> prmcnt; va_count(prmcnt); <span class="kw">if</span>( prmcnt &lt; 1 ) video = <span class="kw">NULL</span>; <span class="cmt">/* default an omitted arg */</span> <span class="cmt">#endif</span> call_FDV( FCC_ADLVA( video ) ); end_FDV(); } __AliasF(FDV_D_ADLVA, FDV$ADLVA, fdv$adlva); <span class="cmt">/* export the VMS-visible name */</span> <span class="cmt">/* implementation: the real work + status ladder */</span> <span class="kw">U32</span> FCC_ADLVA(<span class="kw">S32</span> *video) { enter_FDV <span class="kw">if</span>( ! video ) return_FDV( FDV__ARG ) <span class="cmt">/* bad/omitted arg */</span> <span class="kw">if</span>( ! FMS_curr_tca ) return_FDV( FDV__TCA ) <span class="cmt">/* no terminal control area */</span> <span class="kw">if</span>( FMS_t_cancel(FMS_curr_tca) ) return_FDV( FDV__CAN ) <span class="cmt">/* ... do the work ... */</span> return_FDV( FDV__SUC ) <span class="cmt">/* 2719889 = success */</span> }</pre> <div class="callout"><strong>Consistent error ladder.</strong> Nearly every routine follows the same guard order: <code>FDV__ARG</code> (bad or omitted argument), then <code>FDV__TCA</code> (no terminal control area), then <code>FDV__CAN</code> (call cancelled), then the routine's own work, then <code>FDV__SUC</code>. The <code>enter_FDV</code> / <code>return_FDV</code> wrappers keep the last status current so <code>FDV$STAT</code> can report it afterwards. </div><h6>Core runtime state</h6><p>The runtime is organised around a small set of structures:</p><div class="table-wrapper"><table><thead><tr><th>Structure</th><th>Role</th></tr></thead><tbody><tr><td>Terminal Control Area (TCA)</td><td>Per-terminal context in a linked list, holding display state, the cancel flag, and the current workspace root. <code>FMS_curr_tca</code> is the active one, selected by <code>FDV$STERM</code>.</td></tr><tr><td>Workspace</td><td>Where a loaded form lives; attached with <code>FDV$AWKSP</code> and selected with <code>FDV$SWKSP</code>.</td></tr><tr><td>Form library</td><td>An open library file on a channel, holding compiled forms; opened with <code>FDV$LOPEN</code>.</td></tr><tr><td>Loaded form</td><td>An in-memory copy of a compiled form, brought in from the library by <code>FDV$LOAD</code>.</td></tr></tbody></table></div><h6>Call lifecycle</h6><style>.s7-tech-embed .fmsapi-flow {margin: 1.5rem 0;padding: 16px;border: 1px solid var(--s7t-border);border-radius: 10px;background: rgba(255, 255, 255, 0.01);}.s7-tech-embed .fmsapi-flow-stages {display: grid;grid-template-columns: repeat(4, minmax(0, 1fr));gap: 10px;}.s7-tech-embed .fmsapi-flow-card {min-width: 0;padding: 15px;border-top: 3px solid var(--s7t-accent);border-radius: 6px;background: var(--s7t-surface2);color: var(--s7t-text);}.s7-tech-embed .fmsapi-flow-card strong,.s7-tech-embed .fmsapi-flow-card span:last-child {display: block;}.s7-tech-embed .fmsapi-flow-card strong {margin-bottom: 4px;}.s7-tech-embed .fmsapi-flow-card span:last-child {color: var(--s7t-muted);font-size: 0.9em;line-height: 1.45;}.s7-tech-embed .fmsapi-flow-label {display: block;margin-bottom: 10px;font-family: var(--s7t-mono);color: var(--s7t-accent);font-size: 0.76em;font-weight: 700;letter-spacing: 0.08em;text-transform: uppercase;}.s7-tech-embed .fmsapi-flow-output {border: 1px solid var(--s7t-note-bd);border-top: 3px solid var(--s7t-accent);background: var(--s7t-note-bg);}@media (max-width: 960px) {.s7-tech-embed .fmsapi-flow-stages {grid-template-columns: repeat(2, minmax(0, 1fr));}}@media (max-width: 600px) {.s7-tech-embed .fmsapi-flow-stages {grid-template-columns: 1fr;}}</style><div class="fmsapi-flow" aria-label="VX/FMS API session lifecycle"><div class="fmsapi-flow-stages"><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">01</span><strong>Attach and select terminal</strong><span><code>FDV$ATERM</code> attaches the terminal and creates its TCA; <code>FDV$STERM</code> selects that TCA as current.</span></div><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">02</span><strong>Open form library</strong><span><code>FDV$LOPEN(file)</code> opens the library on a channel.</span></div><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">03</span><strong>Attach and select workspace</strong><span><code>FDV$AWKSP</code> attaches the workspace; <code>FDV$SWKSP</code> selects it as current.</span></div><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">04</span><strong>Load compiled form</strong><span><code>FDV$LOAD(name)</code> reads <code>form.fbn</code> into the workspace.</span></div><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">05</span><strong>Display and wait</strong><span><code>FDV$DISPW</code> paints the form to the terminal and waits until it is ready.</span></div><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">06</span><strong>Interact with fields</strong><span><code>FDV$PUT*</code> seeds values, then <code>FDV$GET*</code> or <code>FDV$PFT</code> reads them, then <code>FDV$RET*</code> harvests the result.</span></div><div class="fmsapi-flow-card"><span class="fmsapi-flow-label">07</span><strong>Close library</strong><span><code>FDV$LCLOS</code> releases the form library channel.</span></div><div class="fmsapi-flow-card fmsapi-flow-output"><span class="fmsapi-flow-label">08</span><strong>Detach terminal</strong><span><code>FDV$DTERM</code> ends the terminal session.</span></div></div></div><h2 id="fdv-routines">FDV$ callable routines</h2><p> VX/FMS$ exports the full OpenVMS FDV$ Forms Driver set: 66 callable routines, each backed by a real implementation body. On the VMS ABI every argument is passed by reference and trailing arguments are optional, defaulted to NULL by the public thunk. The routines are grouped below by function; every routine listed is <span class="ac-live">live</span>. </p><div class="callout"><strong>FDV$, not FDL$.</strong> These are the <em>Forms Driver</em> routines of OpenVMS FMS. They are not the RMS File Definition Language routines (FDL$), which are a separate product. This page documents FDV$ only. </div><h6>Terminal and workspace setup</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FDV$ATERM</code></td><td>Attach a terminal and create a terminal control area on a channel.</td></tr><tr><td><code>FDV$STERM</code></td><td>Select a terminal control area, making it current.</td></tr><tr><td><code>FDV$DTERM</code></td><td>Detach a terminal and tear down its terminal control area.</td></tr><tr><td><code>FDV$AWKSP</code></td><td>Attach (register) a workspace of a given size.</td></tr><tr><td><code>FDV$SWKSP</code></td><td>Select a workspace as the current one.</td></tr><tr><td><code>FDV$DWKSP</code></td><td>Detach (deregister) a workspace.</td></tr><tr><td><code>FDV$FIX_SCREEN</code></td><td>Repair and repaint the physical screen.</td></tr></tbody></table></div><h6>Form libraries and loading</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FDV$LOPEN</code></td><td>Open a form library file on a channel.</td></tr><tr><td><code>FDV$LCLOS</code></td><td>Close the current form library.</td></tr><tr><td><code>FDV$LOAD</code></td><td>Load a form by name from the library into the current workspace.</td></tr><tr><td><code>FDV$READ</code></td><td>Read a binary form image into caller-supplied memory.</td></tr><tr><td><code>FDV$DEL</code></td><td>Delete (undisplay) a named form from the workspace.</td></tr><tr><td><code>FDV$FCHAN</code></td><td>Return the form-library channel of the current terminal control area.</td></tr><tr><td><code>FDV$LCHAN</code></td><td>Return the current library channel.</td></tr><tr><td><code>FDV$TCHAN</code></td><td>Return the terminal channel of the current terminal control area.</td></tr></tbody></table></div><h6>Display and refresh</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FDV$DISP</code></td><td>Display a form without waiting.</td></tr><tr><td><code>FDV$DISPW</code></td><td>Display the current form and wait for the terminal to be ready.</td></tr><tr><td><code>FDV$NDISP</code></td><td>Display without clearing (overlay a new display).</td></tr><tr><td><code>FDV$CDISP</code></td><td>Continue or append the display of a form at an offset.</td></tr><tr><td><code>FDV$RFRSH</code></td><td>Refresh (repaint) the screen from the workspace.</td></tr><tr><td><code>FDV$USER_REFRESH</code></td><td>Register a user refresh callback.</td></tr><tr><td><code>FDV$CLEAR</code></td><td>Clear a count of screen lines from a starting line.</td></tr><tr><td><code>FDV$PUTL</code></td><td>Put a text string on a screen line.</td></tr><tr><td><code>FDV$PRINT_SCREEN</code></td><td>Print or dump the current screen to a file.</td></tr></tbody></table></div><h6>Field input and output</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FDV$GET</code></td><td>Read one field (value plus terminator key).</td></tr><tr><td><code>FDV$GETAF</code></td><td>Get all fields starting at a named field.</td></tr><tr><td><code>FDV$GETAL</code></td><td>Get all field values into a single buffer.</td></tr><tr><td><code>FDV$GETDL</code></td><td>Get a data line with a prompt on a screen line.</td></tr><tr><td><code>FDV$GETSC</code></td><td>Get a field from a scrolled area.</td></tr><tr><td><code>FDV$PFT</code></td><td>Put field and transmit; scroll or advance a scrolled area.</td></tr><tr><td><code>FDV$WAIT</code></td><td>Wait for a terminator key without reading a field.</td></tr><tr><td><code>FDV$PUT</code></td><td>Put a value into a field.</td></tr><tr><td><code>FDV$PUTAL</code></td><td>Put all field values from one buffer.</td></tr><tr><td><code>FDV$PUTD</code></td><td>Put the default value into a field.</td></tr><tr><td><code>FDV$PUTDA</code></td><td>Put defaults into all fields.</td></tr><tr><td><code>FDV$PUTSC</code></td><td>Put a value into a scrolled-area field.</td></tr></tbody></table></div><h6>Retrieving form context and status</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FDV$RET</code></td><td>Return (retrieve) a field's current value.</td></tr><tr><td><code>FDV$RETAL</code></td><td>Return all field values.</td></tr><tr><td><code>FDV$RETCX</code></td><td>Return full context: terminal control area, workspace, form, cursor position, terminator, insert/overstrike, and help state.</td></tr><tr><td><code>FDV$RETDI</code></td><td>Return named data by index.</td></tr><tr><td><code>FDV$RETDN</code></td><td>Return named data by name.</td></tr><tr><td><code>FDV$RETFL</code></td><td>Return a form line image.</td></tr><tr><td><code>FDV$RETFN</code></td><td>Return the current field's name.</td></tr><tr><td><code>FDV$RETFO</code></td><td>Return a field name by ordinal number.</td></tr><tr><td><code>FDV$RETLE</code></td><td>Return a field's length.</td></tr><tr><td><code>FDV$STAT</code></td><td>Return the last FMS status and I/O status.</td></tr><tr><td><code>FDV$SSRV</code></td><td>Set service: return the status and I/O status pair.</td></tr></tbody></table></div><h6>Attributes, keyboard, and control</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FDV$ADLVA</code></td><td>Set the down-line-loadable video attribute on the current terminal control area.</td></tr><tr><td><code>FDV$AFCX</code></td><td>Access field context (insert/overstrike, cursor position, field).</td></tr><tr><td><code>FDV$AFVA</code></td><td>Alter field video attributes.</td></tr><tr><td><code>FDV$CLEAR_VA</code></td><td>Clear video-attribute state.</td></tr><tr><td><code>FDV$DPCOM</code></td><td>Set the display or data-path communication mode.</td></tr><tr><td><code>FDV$SPADA</code></td><td>Set the pad or scrolled-area display mode.</td></tr><tr><td><code>FDV$SPON</code></td><td>Turn supervisor mode on.</td></tr><tr><td><code>FDV$SPOFF</code></td><td>Turn supervisor mode off.</td></tr><tr><td><code>FDV$DFKBD</code></td><td>Define the keyboard (key to function mapping).</td></tr><tr><td><code>FDV$BELL</code></td><td>Sound the terminal bell and reset video and LEDs.</td></tr><tr><td><code>FDV$LEDON</code></td><td>Turn a keyboard LED on.</td></tr><tr><td><code>FDV$LEDOF</code></td><td>Turn a keyboard LED off.</td></tr><tr><td><code>FDV$ILTRM</code></td><td>Set the illegal-terminator handling mode.</td></tr><tr><td><code>FDV$SSIGQ</code></td><td>Set the signal-queue mode.</td></tr><tr><td><code>FDV$SIGOP</code></td><td>Signal the operator and drive the message line.</td></tr><tr><td><code>FDV$STIME</code></td><td>Set the GET or WAIT timeout period.</td></tr><tr><td><code>FDV$CANCL</code></td><td>Cancel the pending GET or WAIT on the current terminal control area.</td></tr><tr><td><code>FDV$SCR_LENGTH</code></td><td>Return the screen length in rows.</td></tr><tr><td><code>FDV$SCR_WIDTH</code></td><td>Return the screen width in columns.</td></tr></tbody></table></div><p> One further name, <code>FDV$RESETTERMINAL</code>, appears in the public header but is not part of the exported 66-routine set; treat it as internal-only. </p><h2 id="status-codes">Status and terminator codes</h2><p> FDV$ routines return VMS-style condition codes: an odd value is success, an even value is failure, and callers test the low bit. There are 73 <code>FDV__*</code> codes in total, numbered contiguously from <code>2719889</code> (<code>FDV__SUC</code>, normal completion). The table lists the load-bearing codes an application is most likely to test or log. </p><div class="table-wrapper"><table><thead><tr><th>Code</th><th>Value</th><th>Meaning</th></tr></thead><tbody><tr><td><code>FDV__SUC</code></td><td>2719889</td><td>Normal completion (success).</td></tr><tr><td><code>FDV__INC</code></td><td>2719897</td><td>Form incomplete after a PFT call.</td></tr><tr><td><code>FDV__MOD</code></td><td>2719905</td><td>Input successful; a field may have changed.</td></tr><tr><td><code>FDV__IMP</code></td><td>2719922</td><td>Workspace too small.</td></tr><tr><td><code>FDV__FSP</code></td><td>2719930</td><td>Illegal file spec in a LOPEN call.</td></tr><tr><td><code>FDV__IOL</code></td><td>2719938</td><td>Error opening the form library.</td></tr><tr><td><code>FDV__FLB</code></td><td>2719946</td><td>Specified file is not a form library.</td></tr><tr><td><code>FDV__ICH</code></td><td>2719954</td><td>Invalid channel number specified.</td></tr><tr><td><code>FDV__FRM</code></td><td>2719970</td><td>Invalid binary form.</td></tr><tr><td><code>FDV__FNM</code></td><td>2719978</td><td>Specified form does not exist.</td></tr><tr><td><code>FDV__FLD</code></td><td>2719994</td><td>Invalid field specification.</td></tr><tr><td><code>FDV__DSP</code></td><td>2720010</td><td>GET-type call is illegal for a display-only field.</td></tr><tr><td><code>FDV__UTR</code></td><td>2720042</td><td>Undefined field terminator.</td></tr><tr><td><code>FDV__ARG</code></td><td>2720066</td><td>Wrong number of arguments for the call.</td></tr><tr><td><code>FDV__INI</code></td><td>2720074</td><td>Workspace not attached.</td></tr><tr><td><code>FDV__IVM</code></td><td>2720090</td><td>Insufficient virtual memory.</td></tr><tr><td><code>FDV__ITT</code></td><td>2720106</td><td>Invalid terminal type.</td></tr><tr><td><code>FDV__TCA</code></td><td>2720114</td><td>Terminal Control Area invalid or undefined.</td></tr><tr><td><code>FDV__WID</code></td><td>2720130</td><td>Form too wide for the terminal or context.</td></tr><tr><td><code>FDV__NFL</code></td><td>2720138</td><td>No form loaded into the specified workspace.</td></tr><tr><td><code>FDV__NDS</code></td><td>2720154</td><td>GET-type call to an undisplayed form.</td></tr><tr><td><code>FDV__CAN</code></td><td>2720194</td><td>Call was cancelled.</td></tr><tr><td><code>FDV__TMO</code></td><td>2720234</td><td>Timeout exceeded on a GET-type call or WAIT.</td></tr><tr><td><code>FDV__VAL</code></td><td>2720250</td><td>Value of a parameter out of range.</td></tr><tr><td><code>FDV__SYS</code></td><td>2720266</td><td>FDV encountered a system error response.</td></tr></tbody></table></div><p> A further block of field-attribute codes (for example <code>FDV__ALPHA</code>, <code>FDV__NUMERC</code>, <code>FDV__MUSTFILL</code>, <code>FDV__NOHELP</code>) describes field validation classes and is what a User Action Routine inspects. </p><h6>Field terminator codes</h6><p> The terminator out-parameter of <code>FDV$GET</code>, <code>FDV$GETSC</code>, <code>FDV$PFT</code> and <code>FDV$WAIT</code> carries the key that ended input. There are 17 terminator values; the common ones are: </p><div class="table-wrapper"><table><thead><tr><th>Constant</th><th>Value</th><th>Meaning</th></tr></thead><tbody><tr><td><code>FDV_K_FT_NTR</code></td><td>0</td><td>Enter (end of GETs).</td></tr><tr><td><code>FDV_K_FT_NXT</code></td><td>1</td><td>Next field.</td></tr><tr><td><code>FDV_K_FT_PRV</code></td><td>2</td><td>Previous field.</td></tr><tr><td><code>FDV_K_FT_ATB</code></td><td>3</td><td>Auto-tab to the next field.</td></tr><tr><td><code>FDV_K_FT_XBK</code></td><td>4</td><td>Exit scrolled area backward.</td></tr><tr><td><code>FDV_K_FT_XFW</code></td><td>5</td><td>Exit scrolled area forward.</td></tr><tr><td><code>FDV_K_FT_SNX</code></td><td>6</td><td>Scroll forward to the next field.</td></tr><tr><td><code>FDV_K_FT_SPR</code></td><td>7</td><td>Scroll backward to the previous field.</td></tr><tr><td><code>FDV_K_FT_SFW</code></td><td>8</td><td>Scroll forward.</td></tr><tr><td><code>FDV_K_FT_SBK</code></td><td>9</td><td>Scroll backward.</td></tr></tbody></table></div><h2 id="form-language">The FMS form language and binary forms</h2><p> A form is authored as a text <code>.flg</code> file, compiled to a binary <code>.fbn</code> form, and grouped with other forms into a form library. At run time <code>FDV$LOPEN</code> opens the library on a channel and <code>FDV$LOAD</code> locates a form by appending <code>.fbn</code> to its name. The form language and binary format match the OpenVMS originals, so existing form sources compile unchanged. </p><h6>Statement types</h6><p>The top-level statements in a <code>.flg</code> form description:</p><div class="table-wrapper"><table><thead><tr><th>Statement</th><th>Purpose</th></tr></thead><tbody><tr><td><code>FORM</code></td><td>Begin a form; must be the first statement.</td></tr><tr><td><code>ATTRIBUTE_DEFAULTS</code></td><td>Set default attributes for the form.</td></tr><tr><td><code>TEXT</code></td><td>Literal screen text.</td></tr><tr><td><code>FIELD</code></td><td>Define an input or output field.</td></tr><tr><td><code>DRAW</code></td><td>Line-drawing block.</td></tr><tr><td><code>VIDEO</code></td><td>Video-attribute block.</td></tr><tr><td><code>SCROLL</code></td><td>Define a scrolled area.</td></tr><tr><td><code>ORDER</code></td><td>Field ordering.</td></tr><tr><td><code>NAMED_DATA</code></td><td>Attach named constant data to the form.</td></tr><tr><td><code>END_OF_FORM</code></td><td>Terminate a form.</td></tr></tbody></table></div><h6>Item keywords</h6><p> Clauses within a statement select field behaviour, validation, and video attributes. The full keyword set includes: </p><div class="kw-grid"><div>ACTION_ROUTINE</div><div>AREA_TO_CLEAR</div><div>BACKGROUND</div><div>CHARACTER_SET</div><div>CLEAR_CHARACTER</div><div>DATA</div><div>DATE_FIELD</div><div>DEFAULT</div><div>HELP</div><div>HELP_FORM</div><div>HIGHLIGHT</div><div>INDEX</div><div>INDEXED</div><div>NAME</div><div>PICTURE</div><div>TIME_FIELD</div><div>WIDTH</div><div>AUTOTAB</div><div>BLANK_FILL</div><div>BLINKING</div><div>BOLD</div><div>DISPLAY_ONLY</div><div>ECHO</div><div>FIXED_DECIMAL</div><div>LEFT_JUSTIFIED</div><div>MUST_FILL</div><div>RESPONSE_REQUIRED</div><div>REVERSE</div><div>RIGHT_JUSTIFIED</div><div>SUPERVISOR_ONLY</div><div>SUPPRESS</div><div>UNDERLINE</div><div>UPPERCASE</div><div>ZERO_FILL</div></div><p> Date pictures (<code>MDY</code>, <code>DDMMMYY</code>, <code>MMDDYY</code>, <code>DDMMYY</code>) and time pictures (<code>HHMMSS</code>, <code>HHMMAMPM</code>) are built in, and the compiler enforces that <code>FORM</code> is the first statement before writing the binary form. </p><h6>Example form source</h6> <pre><span class="kw">FORM</span> NAME=<span class="str">'ACCOUNT_INQUIRY'</span> AREA_TO_CLEAR=1:23 WIDTH=80 BACKGROUND=CURRENT HIGHLIGHT=BOLD:UNDERLINE FUNCTION_KEY_ACTION_ROUTINE=<span class="str">'FILTER_UAR'</span> ; <span class="kw">TEXT</span> (5,10) <span class="str">'Account Number :'</span> ; <span class="kw">FIELD</span> ACCT_NO (5,27) PICTURE=<span class="str">'NNNNNNNNNN'</span> RESPONSE_REQUIRED UPPERCASE ;</pre> <p> Positions are given as <code>(row,col)</code>, an ampersand continues a string across lines, and each statement ends with a semicolon. </p><h6>Linux form editor</h6><p> VX/FMS$ ships <code>fmsedit</code>, a Linux reimplementation of the VMS form editor that reads and writes the same <code>.flg</code> format and renders to an ANSI or VT terminal. It follows the VMS Gold-key idiom (PF1 as Gold) and also builds a headless render tool and a round-trip regression tool for validating form files in a build pipeline. </p><h2 id="terminal-rendering">Terminal rendering</h2><p> Forms are painted by emitting escape sequences directly, not through curses. A dedicated terminal layer handles cursor addressing, line erasing, video attributes, and output flushing. Video attributes map to standard CSI sequences: </p> <pre><span class="cmt">/* video attribute sequences */</span> BST_SEQ_VID_BEG <span class="str">"\033["</span> <span class="cmt">/* CSI */</span> BST_SEQ_BOLD <span class="str">"1"</span> BST_SEQ_UNDERLINE <span class="str">"4"</span> BST_SEQ_REVERSE <span class="str">"7"</span> BST_SEQ_VID_END <span class="str">"m"</span></pre> <p> Terminal type is auto-detected from the <code>$TERM</code> environment variable at startup. An X-window terminal resolves to <code>XTERM</code>; otherwise a prefix match selects <code>ANSI</code>, <code>HFT</code>, or <code>VT</code>, and anything unmatched falls back to <code>VT</code>. This is the main Linux divergence point: the OpenVMS original drove real VT-series hardware through the VMS terminal driver, while VX/FMS$ renders the same forms to a Linux pseudo-terminal using ANSI and VT escape sequences. </p><div class="callout"><strong>Same forms, portable output.</strong> Because rendering is driven entirely by <code>$TERM</code>, a form built for a VT terminal displays correctly under xterm and other ANSI-compatible terminals without any change to the form source. </div><h2 id="call-path">End-to-end call path</h2><p> A migrated program links against <code>libfms.a</code> and calls the FDV$ routines exactly as it did on OpenVMS. The success test is the same: the low bit of the returned status is set on success (<code>status &amp; 1</code>). The example below loads and displays a form, then reads fields from a scrolled area, checking status after each call. </p> <pre><span class="cmt">/* fail fast: report the FMS message and exit on any error */</span> <span class="cmt">#define CHECK if( !(fmsstat &amp; 1) ) { \</span> <span class="cmt"> fprintf(stderr, "FMS error %d [%s] at line %d\r\n", \</span> <span class="cmt"> fmsstat, FMS_disp_deb_mess_1(fmsstat), __LINE__); exit(0); }</span> <span class="cmt">/* simple form: select workspace, load, display, wait */</span> fmsstat = fdv$swksp( &amp;acct_wksp ); CHECK fmsstat = fdv$load ( _DESCR(<span class="str">"ACCOUNT_INQUIRY"</span>) ); CHECK fmsstat = fdv$dispw( 0 ); CHECK fmsstat = fdv$wait ( 0 ); CHECK <span class="cmt">/* scrolled area: read fields until the terminator says stop */</span> fmsstat = fdv$swksp( &amp;txn_wksp ); CHECK fmsstat = fdv$load ( _DESCR(<span class="str">"TXN_HISTORY"</span>) ); CHECK fmsstat = fdv$dispw( 0 ); CHECK fmsstat = fdv$getsc( _DESCR(<span class="str">"TXN_LINE"</span>), &amp;val, &amp;trm ); CHECK <span class="kw">while</span>( 1 ) { <span class="kw">switch</span>( trm ) { <span class="cmt">/* trm is an FDV_K_FT_* code */</span> <span class="kw">case</span> FDV_K_FT_NXT: <span class="kw">case</span> FDV_K_FT_ATB: <span class="kw">case</span> FDV_K_FT_SFW: <span class="kw">case</span> FDV_K_FT_SNX: fmsstat = fdv$pft( &amp;trm, _DESCR(<span class="str">"TXN_LINE"</span>), _DESCR(line_buf), 0, 0 ); CHECK <span class="kw">break</span>; <span class="cmt">/* ... handle other terminators ... */</span> } }</pre> <p> Note the trailing <code>0, 0</code> passed to <code>fdv$pft</code>: on Linux the optional arguments a VMS caller could omit are passed explicitly as NULL, because the argument-count probe used on VMS is not available. </p><p> The complete ordered sequence, including terminal and workspace selection, library and form loading, interaction, and teardown, is shown in <a href="#architecture">Architecture and dispatch: Call lifecycle</a>. </p><p><code>FDV$STAT</code> can report the last condition value at any point in this sequence. </p><h2 id="compatibility">Compatibility and divergences</h2><p> The table summarises what is implemented. The core forms driver, the form language, the binary form format, terminal rendering, scrolled areas, and User Action Routines are all present and exercised. </p><div class="table-wrapper"><table><thead><tr><th>Capability</th><th>Status</th></tr></thead><tbody><tr><td>66 FDV$ Forms Driver routines (each with an implementation body)</td><td><span class="ac-live">live</span></td></tr><tr><td>FDV$ condition codes and message text</td><td><span class="ac-live">live</span></td></tr><tr><td>Field terminator and validation-class codes</td><td><span class="ac-live">live</span></td></tr><tr><td>FMS form language and statement / keyword set</td><td><span class="ac-live">live</span></td></tr><tr><td>Binary form load (<code>FDV$LOAD</code> / <code>FDV$READ</code>)</td><td><span class="ac-live">live</span></td></tr><tr><td>Form libraries (<code>FDV$LOPEN</code> / <code>FDV$LCLOS</code>)</td><td><span class="ac-live">live</span></td></tr><tr><td>VT, ANSI, xterm, and HFT terminal rendering</td><td><span class="ac-live">live</span></td></tr><tr><td>Scrolled areas (<code>FDV$GETSC</code> / <code>FDV$PFT</code> / <code>FDV$SPADA</code>)</td><td><span class="ac-live">live</span></td></tr><tr><td>User Action Routines and the UAR generator utility</td><td><span class="ac-live">live</span></td></tr><tr><td><code>fmsedit</code> Linux form editor (read, write, render <code>.flg</code>)</td><td><span class="ac-live">live</span></td></tr><tr><td><code>FDV$RESETTERMINAL</code> public export</td><td><span class="ac-no">not exposed</span></td></tr></tbody></table></div><h6>Divergences from OpenVMS FMS</h6><div class="table-wrapper"><table><thead><tr><th>Divergence</th><th>Reason</th></tr></thead><tbody><tr><td>Each routine is exported twice: a dollar-free real symbol (<code>FDV_D_XXX</code>) plus a <code>FDV$XXX</code> alias.</td><td>A dollar sign is legal in OpenVMS identifiers but not in a portable C symbol; the alias reproduces the VMS-visible name so existing object references resolve.</td></tr><tr><td>Optional trailing arguments must be passed explicitly as NULL on Linux.</td><td>The VMS argument-count probe is not available on Linux, so callers pass omitted arguments as NULL or zero.</td></tr><tr><td>Rendering uses ANSI and VT escape strings, driven by <code>$TERM</code>.</td><td>There is no VMS terminal driver or real VT hardware on Linux.</td></tr><tr><td>A form binary is located by concatenating the form name with <code>.fbn</code> in a library directory.</td><td>Maps OpenVMS form-library semantics onto a Linux directory and file layout.</td></tr><tr><td>A standalone build (<code>libfmsx.a</code>) is available alongside the default <code>libfms.a</code>.</td><td>The standalone build decouples FMS from the rest of the VX/RT runtime.</td></tr></tbody></table></div><h2 id="quick-reference">Quick reference</h2><h6>Linking</h6><p> Link with <code>-lfms</code> (or <code>-lfmsx</code> for the standalone build) from <code>libfms.a</code>; include the FDV$ routine prototypes and pull in the FMS standard header. </p><h6>Minimal call flow</h6><p> Use the ordered card flow in <a href="#architecture">Architecture and dispatch: Call lifecycle</a> for the complete session sequence. The minimal path selects the terminal, opens the library, selects the workspace, loads and displays the form, reads and returns field values, then closes the library. </p><h6>Common status codes</h6><div class="kw-grid"><div>FDV__SUC = 2719889</div><div>FDV__ARG (bad args)</div><div>FDV__TCA (no terminal)</div><div>FDV__CAN (cancelled)</div><div>FDV__FNM (form not found)</div><div>FDV__FRM (bad binary form)</div><div>FDV__NFL (no form loaded)</div><div>FDV__TMO (timeout)</div></div><p>Success test: <code>status &amp; 1</code> true means success.</p><h6>File extensions</h6><div class="kw-grid"><div>.flg (form source)</div><div>.fbn (binary form)</div><div>form library on a channel</div></div><h6>Common terminators</h6><div class="kw-grid"><div>FDV_K_FT_NTR = 0 (Enter)</div><div>FDV_K_FT_NXT = 1</div><div>FDV_K_FT_PRV = 2</div><div>FDV_K_FT_ATB = 3</div></div><h6>Environment</h6><p><code>$TERM</code> selects XTERM, ANSI, HFT, or VT rendering at startup.</p></div>

Frequently Asked Questions

Curious about how Sector7 can facilitate your application migration? Explore our FAQs for expert insights.

What is VX/FMS and how does it help with OpenVMS migration?

VX/FMS provides a native call-compatible implementation of OpenVMS Forms Management System for Linux platforms. It enables OpenVMS applications to define, generate, and manage native FMS Forms on both x86 and ARM Linux systems.

This solution allows organizations to preserve their existing OpenVMS forms-based applications while migrating to modern Linux infrastructure. To discuss how VX/FMS can support your specific migration requirements, contact our team.

What key features does VX/FMS provide for forms management?

VX/FMS offers full compatibility with OpenVMS FDL$ APIs, supports file structure definition and parsing, and maintains OpenVMS file structure semantics on Linux.

Does VX/FMS support all OpenVMS FDV$ API functions?

Yes, VX/FMS provides comprehensive support for FDV$ APIs including display operations, terminal handling, file management, and workspace allocation functions.

What are the main benefits of migrating forms with VX/FMS?

VX/FMS preserves OpenVMS capability while enabling direct porting of applications without major modifications, minimizing development costs and preserving productivity.

What technical platforms does VX/FMS support?

VX/FMS supports both x86 and ARM Linux architectures, providing flexible deployment options for modern infrastructure requirements.

How does VX/FMS handle OpenVMS forms processing workflows?

VX/FMS maintains the complete OpenVMS forms workflow including structure generation, parsing, display operations, and user interaction handling. The solution preserves terminal management functions, screen operations, and file channel management exactly as they work in OpenVMS.

This comprehensive approach ensures that complex forms-based applications continue to operate with identical behavior on Linux platforms.

What results can organizations expect from VX/FMS implementation?

VX/FMS delivers seamless migration of forms-based applications with preserved functionality and consistent behavior. Organizations eliminate vendor lock-in while modernizing their infrastructure to Linux platforms.

The solution reduces development costs by avoiding application rewrites and maintains productivity through familiar forms management capabilities. Companies like Shaw Industries have successfully modernized their manufacturing systems using similar migration strategies.

Ready to explore how VX/FMS can modernize your forms-based applications? Contact us to discuss your specific requirements.

What is VX/FMS$?

VX/FMS$ is a native reimplementation of the OpenVMS Forms Management System (FMS) for x86 and ARM Linux. It exports the FDV$ Forms Driver callable interface, so OpenVMS applications can define, display, and manage FMS forms on Linux without changing their forms logic.

Which CPU architectures and platforms does VX/FMS$ run on?

VX/FMS$ runs on both x86 and ARM Linux. It is delivered as part of the VX/RT runtime that brings OpenVMS compatibility to those platforms.

Do I have to rewrite my application to use VX/FMS$?

No. Applications that call the OpenVMS FDV$ Forms Driver routines link and run without major modifications, which preserves productivity and minimizes development cost.

Which FDV$ routines does VX/FMS$ provide?

VX/FMS$ provides the full set of 66 FDV$ callable routines. They span form loading and display (FDV$LOAD, FDV$DISP, FDV$DISPW), field input and output (FDV$GET, FDV$GETSC, FDV$PFT, FDV$PUT), terminal and screen management (FDV$STERM, FDV$SCR_WIDTH, FDV$SCR_LENGTH), workspace handling (FDV$AWKSP, FDV$SWKSP, FDV$DWKSP), and library and channel control (FDV$LOPEN, FDV$LCHAN, FDV$TCHAN). The full routine table is on the page.

How does VX/FMS$ handle terminal display and user interaction?

Through its FDV$ routines. For example FDV$DISP and FDV$DISPW display data, FDV$READ and FDV$GET handle input, FDV$BELL sounds the terminal alert, FDV$LEDON and FDV$LEDOF control terminal LEDs, and FDV$STERM sets terminal characteristics. Behaviour matches OpenVMS FMS, and forms are rendered to VT, ANSI, and xterm terminals using escape sequences.

How does VX/FMS$ fit with the rest of the Sector7 migration stack?

VX/FMS$ integrates into the VX/RT ecosystem, which provides OpenVMS compatibility on x86 and ARM Linux. FMS forms handling is delivered as part of that broader OpenVMS-on-Linux runtime rather than as a standalone island.

Does VX/FMS$ preserve the same forms workflows as OpenVMS?

Yes. VX/FMS$ preserves OpenVMS FMS capability and supports the same forms workflows: loading and displaying compiled forms, reading and transmitting fields, and managing the terminal, so forms-based applications can be ported directly.

How is an FMS form defined and displayed?

A form is authored in the FMS form language as a .flg source file with statements such as FORM, TEXT, and FIELD, then compiled to a binary .fbn form. At run time an application selects a workspace with FDV$SWKSP, loads the form with FDV$LOAD, displays it with FDV$DISPW, and reads user input with FDV$GET or FDV$GETSC.

Transform Your Legacy Software Today!

Get In Touch
Unlock the potential of your legacy software with our expert migration services.