🚨 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

FOR$ - FORTRAN Support Routines

Overview

FOR$ is a call-compatible re-implementation of the OpenVMS FORTRAN run-time support library for x86 and ARM Linux. It provides the FOR$ entry points that DEC and VSI FORTRAN object code calls at run time, so migrated applications link and execute while preserving language features, execution behaviour, and system interactions. It is the runtime the compiled or translated object links against, not the compiler and not the source translator.

Two concerns dominate the library: numeric-to-text conversion through the FOR$CVT family, and record access through FOR$RAB over Sector7's RMS layer. FOR$ ships inside VX/RT and integrates with the rest of the OpenVMS run-time services on Linux, so FORTRAN applications that depend on FOR$ routines can be ported directly and keep their original behaviour.

<!-- Webflow embed (min). Source: for-api-page-technical/for-tech-body-embed-dark.html → python3 website/embeds/minify_webflow_embed.py … --> <div class="s7-tech-embed" data-vxford-body-embed="1" data-technical-mega-embed="1" lang="en"><h2 id="architecture">Architecture and components</h2><p> FOR$ is a linked run-time library, not a server process. There is nothing to administer: the FOR$ entry points are archived into <code>libvxrt.a</code> and linked directly into the migrated FORTRAN application. At run time the library owns a per-unit channel table, hands out RMS Record Access Blocks, and formats numeric values into edited character strings. The table maps each OpenVMS FORTRAN run-time concept to its Linux implementation. </p><div class="table-wrapper"><table><thead><tr><th>OpenVMS concept</th><th>FOR$ implementation</th><th>Role</th><th>Status</th></tr></thead><tbody><tr><td><code>FOR$CVT_D_TE</code> (D_float to text)</td><td>Base numeric converter</td><td>Formats a double into an edited output string; the shared converter behind the CVT family.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>FOR$CVT_G_TE</code> / <code>FOR$CVT_H_TE</code></td><td>G_float and H_float converters</td><td>Format G_float and H_float values to text through the shared conversion path.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>FOR$RAB</code> (unit to RAB)</td><td>Record Access Block accessor</td><td>Validates a FORTRAN unit and returns its RMS Record Access Block.</td><td><span class="ac-live">live</span></td></tr><tr><td>FORTRAN unit to RMS channel table</td><td>Per-unit channel list</td><td>Per-unit channel table sized to the maximum unit count, allocated once at initialisation.</td><td><span class="ac-live">live</span></td></tr><tr><td>OPEN / CLOSE</td><td>Record-I/O runtime</td><td>Opens and closes units, builds the FAB and RAB, and honours KEEP, DELETE, PRINT, and SUBMIT dispositions.</td><td><span class="ac-live">live</span></td></tr><tr><td>READ / WRITE / REWRITE / DELETE</td><td>Record-I/O runtime</td><td>Record read, write, update-in-place, and delete over the RMS and ISAM layer.</td><td><span class="ac-live">live</span></td></tr><tr><td>BACKSPACE / REWIND / ENDFILE / INQUIRE</td><td>Record-I/O runtime</td><td>Positioning, truncation, and INQUIRE-by-unit or by-file.</td><td><span class="ac-live">live</span></td></tr><tr><td>ERRSNS</td><td>Error-state accessor</td><td>Returns the last I/O, system, status, unit, and condition information, then clears it.</td><td><span class="ac-live">live</span></td></tr><tr><td>VMS to Unix filename translation</td><td>Filename translator</td><td>Converts a VMS file specification to a Unix path when a unit is opened.</td><td><span class="ac-live">live</span></td></tr></tbody></table></div><div class="callout"><strong>No daemon to run.</strong> FOR$ is delivered as a static library inside VX/RT. The application links it directly, so there is no separate runtime service to install or manage on the Linux host. </div><h6>Call lifecycle (record access path)</h6><p> Translated FORTRAN object, or a FOR$ helper, reaches a unit's Record Access Block through the validated lookup below. The channel table is allocated once at initialisation: </p><style>.s7-tech-embed[data-vxford-body-embed] .guard-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[data-vxford-body-embed] .guard-endpoint {display: grid;grid-template-columns: 82px minmax(0, 1fr);gap: 14px;align-items: center;padding: 14px 16px;border-radius: 8px;background: var(--s7t-surface);}.s7-tech-embed[data-vxford-body-embed] .guard-success {border: 1px solid var(--s7t-note-bd);background: var(--s7t-note-bg);}.s7-tech-embed[data-vxford-body-embed] .guard-label,.s7-tech-embed[data-vxford-body-embed] .guard-number,.s7-tech-embed[data-vxford-body-embed] .guard-pass,.s7-tech-embed[data-vxford-body-embed] .guard-fail {font-family: var(--s7t-mono);font-size: 0.76em;font-weight: 700;letter-spacing: 0.08em;text-transform: uppercase;}.s7-tech-embed[data-vxford-body-embed] .guard-label,.s7-tech-embed[data-vxford-body-embed] .guard-number,.s7-tech-embed[data-vxford-body-embed] .guard-pass {color: var(--s7t-accent);}.s7-tech-embed[data-vxford-body-embed] .guard-fail {color: #ffd84a;}.s7-tech-embed[data-vxford-body-embed] .guard-checks {display: grid;grid-template-columns: repeat(3, minmax(0, 1fr));gap: 10px;margin: 10px 0;padding: 0;list-style: none;}.s7-tech-embed[data-vxford-body-embed] .guard-check {min-width: 0;padding: 15px;border-top: 3px solid var(--s7t-accent);border-radius: 6px;background: var(--s7t-surface2);}.s7-tech-embed[data-vxford-body-embed] .guard-check .guard-number {display: block;margin-bottom: 10px;}.s7-tech-embed[data-vxford-body-embed] .guard-check strong,.s7-tech-embed[data-vxford-body-embed] .guard-check > span {display: block;}.s7-tech-embed[data-vxford-body-embed] .guard-check strong {margin-bottom: 8px;color: var(--s7t-text);}.s7-tech-embed[data-vxford-body-embed] .guard-outcome {margin-top: 6px;color: var(--s7t-muted);font-size: 0.9em;line-height: 1.45;}.s7-tech-embed[data-vxford-body-embed] .guard-endpoint strong,.s7-tech-embed[data-vxford-body-embed] .guard-endpoint span:last-child {display: block;}.s7-tech-embed[data-vxford-body-embed] .guard-endpoint strong {margin-bottom: 4px;}.s7-tech-embed[data-vxford-body-embed] .guard-endpoint span:last-child {color: var(--s7t-muted);font-size: 0.9em;}@media (max-width: 800px) {.s7-tech-embed[data-vxford-body-embed] .guard-checks,.s7-tech-embed[data-vxford-body-embed] .guard-endpoint {grid-template-columns: 1fr;}.s7-tech-embed[data-vxford-body-embed] .guard-endpoint {gap: 5px;}}</style><div class="guard-flow" role="group" aria-label="Guarded FOR$RAB record access lifecycle"><div class="guard-endpoint"><span class="guard-label">Request</span><div><strong>FORTRAN object calls <code>FOR$RAB(unit)</code></strong><span>The accessor evaluates each guard in order.</span></div></div><ol class="guard-checks"><li class="guard-check"><span class="guard-number">Guard 01</span><strong>Unit in range?</strong><div class="guard-outcome"><span class="guard-fail">No</span> Set channel-out-of-range error state and return <code>NULL</code>.</div><div class="guard-outcome"><span class="guard-pass">Yes</span> Look up <code>channel table[unit]</code>.</div></li><li class="guard-check"><span class="guard-number">Guard 02</span><strong>Unit open?</strong><div class="guard-outcome"><span class="guard-fail">No</span> Set unit-not-open error state and return <code>NULL</code>.</div><div class="guard-outcome"><span class="guard-pass">Yes</span> Continue to the channel's RAB.</div></li><li class="guard-check"><span class="guard-number">Guard 03</span><strong>RAB present?</strong><div class="guard-outcome"><span class="guard-fail">No</span> Set error state and return <code>NULL</code>.</div><div class="guard-outcome"><span class="guard-pass">Yes</span> Complete the validated lookup.</div></li></ol><div class="guard-endpoint guard-success"><span class="guard-label">All pass</span><div><strong>Return <code>RABDEF*</code></strong><span>The pointer identifies the unit's RMS Record Access Block.</span></div></div></div><p> The FORTRAN I/O statements (OPEN, READ, WRITE, and the rest) sit on the same per-unit channel table and delegate record storage to Sector7's RMS and ISAM layer, so record organisation and access order match the original OpenVMS behaviour. </p><h2 id="routines">Callable FOR$ routines</h2><p> FOR$ exports four public entry points. Each ships in two layers in the same source module: a C-callable core, and a FORTRAN-callable wrapper that receives string arguments as a hidden VMS-style descriptor and then calls the core. The public <code>FOR$</code> name is attached by an alias mechanism, so existing OpenVMS object references resolve unchanged and the FORTRAN calling convention (a trailing hidden length argument) is preserved. </p><div class="table-wrapper"><table><thead><tr><th>FORTRAN name</th><th>Purpose</th><th>Status</th></tr></thead><tbody><tr><td><code>FOR$CVT_D_TE</code></td><td>D_float to edited text; the base numeric converter.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>FOR$CVT_G_TE</code></td><td>G_float to text.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>FOR$CVT_H_TE</code></td><td>H_float (128-bit floating) to text.</td><td><span class="ac-live">live</span></td></tr><tr><td><code>FOR$RAB</code></td><td>Return the RMS Record Access Block for an open FORTRAN unit.</td><td><span class="ac-live">live</span></td></tr></tbody></table></div><h6>Numeric conversion (the CVT family)</h6><p> The three <code>FOR$CVT</code> routines share a single call shape and a common formatting core. They format a floating value into an edited character string, apply the OpenVMS field-overflow convention (a truncated output field is filled with asterisks), and return a condition value: </p> <pre>U32 FOR$CVT_x_TE( double *inValue, &lt;descriptor&gt; outStr, long digInFrac, <span class="cmt">; digits in the fractional part</span> long scale, <span class="cmt">; scale factor on the integer part</span> long digInInt, <span class="cmt">; digits in the integer part</span> long digInExp, <span class="cmt">; digits in the exponent</span> long flags ); <span class="cmt">; conversion options</span></pre> <p> A successful call returns a normal status. If the edited value does not fit the caller's output descriptor, the routine overwrites the field with asterisks and returns an output-conversion error, matching the OpenVMS edit-descriptor behaviour rather than silently corrupting the buffer. <code>FOR$CVT_G_TE</code> and <code>FOR$CVT_H_TE</code> currently reach text through the same shared D_float formatting path. </p><h6>Record access (FOR$RAB)</h6><p><code>FOR$RAB</code> returns a pointer to the RMS Record Access Block for an open FORTRAN unit, or a null pointer on error with the condition recorded in the run-time error state. It runs a fixed validation ladder before returning: </p> <pre>RABDEF *FOR$RAB( int *for_unit );</pre> <div class="table-wrapper"><table><thead><tr><th>Check</th><th>On failure</th></tr></thead><tbody><tr><td>Unit number within the valid range</td><td>Record a channel-out-of-range condition; return NULL.</td></tr><tr><td>Unit is open (channel table slot allocated)</td><td>Record an illegal-channel-number condition; return NULL.</td></tr><tr><td>A Record Access Block exists for the unit</td><td>Record a no-RAB condition; return NULL.</td></tr><tr><td>All checks pass</td><td>Return the unit's Record Access Block.</td></tr></tbody></table></div><p> The maximum FORTRAN unit number is 1024. Because <code>FOR$RAB</code> returns a null pointer and stashes the condition rather than returning the status directly, calling code checks the error state through <code>ERRSNS</code> (see below) when the pointer comes back null. </p><h6>Real call path (banking example)</h6><p> A migrated program opens a keyed account file and takes the unit's Record Access Block to drive a keyed lookup, then reads the error state if the accessor returns null: </p> <pre><span class="cmt">C open the account master and fetch its Record Access Block</span> OPEN (UNIT=ACCT_UNIT, FILE=<span class="str">'BANKING$DATA:ACCOUNT_MASTER.DAT'</span>, + ORGANIZATION=<span class="str">'INDEXED'</span>, ACCESS=<span class="str">'KEYED'</span>, STATUS=<span class="str">'OLD'</span>) RAB = FOR$RAB (ACCT_UNIT) IF (RAB .EQ. 0) THEN CALL ERRSNS (IOERR, SYSERR, STAT, UNIT, COND) <span class="cmt">C ... handle the recorded condition ...</span> END IF READ (UNIT=ACCT_UNIT, KEY=CUST_ID) ACCT_RECORD</pre> <h2 id="record-io">Record access and file I/O</h2><p><code>FOR$RAB</code> is the public window onto a larger record-I/O runtime. The FORTRAN OPEN, READ, WRITE, REWRITE, DELETE, BACKSPACE, REWIND, ENDFILE, and INQUIRE statements are all implemented over the same per-unit channel table and delegate record storage to Sector7's RMS and ISAM layer. The table lists the record-I/O surface behind the four public entry points. </p><div class="table-wrapper"><table><thead><tr><th>FORTRAN statement</th><th>Runtime role</th><th>Status</th></tr></thead><tbody><tr><td>OPEN</td><td>Open a unit, build the FAB and RAB, and translate the VMS filename to a Unix path.</td><td><span class="ac-live">live</span></td></tr><tr><td>CLOSE</td><td>Close a unit with KEEP, DELETE, PRINT, or SUBMIT disposition.</td><td><span class="ac-live">live</span></td></tr><tr><td>READ</td><td>Record read via the RMS and ISAM layer.</td><td><span class="ac-live">live</span></td></tr><tr><td>WRITE</td><td>Record write, including the formatted-write helpers.</td><td><span class="ac-live">live</span></td></tr><tr><td>REWRITE</td><td>Update a record in place.</td><td><span class="ac-live">live</span></td></tr><tr><td>DELETE</td><td>Delete the current or a keyed record.</td><td><span class="ac-live">live</span></td></tr><tr><td>BACKSPACE / REWIND</td><td>Reposition one record back, or to the start of the file.</td><td><span class="ac-live">live</span></td></tr><tr><td>ENDFILE</td><td>Truncate the file and mark end of file.</td><td><span class="ac-live">live</span></td></tr><tr><td>INQUIRE</td><td>INQUIRE by unit or by file.</td><td><span class="ac-live">live</span></td></tr><tr><td>UNLOCK</td><td>Release a record lock held on a unit.</td><td><span class="ac-live">live</span></td></tr></tbody></table></div><h6>The per-unit channel</h6><p> Each open unit has a channel record in a table allocated once at initialisation, sized to the maximum unit count plus one. The channel carries everything the runtime needs to service the unit, including the fields most relevant to record access: </p><div class="table-wrapper"><table><thead><tr><th>Field</th><th>Meaning</th></tr></thead><tbody><tr><td><code>rab</code></td><td>RMS Record Access Block, the pointer <code>FOR$RAB</code> returns.</td></tr><tr><td><code>fab</code></td><td>RMS File Access Block.</td></tr><tr><td><code>vmsname</code></td><td>Original VMS file name for the unit.</td></tr><tr><td><code>location</code></td><td>Current record number or file position.</td></tr><tr><td><code>org</code></td><td>RMS organisation (sequential, relative, or indexed).</td></tr><tr><td><code>locking</code></td><td>Locking mode: automatic, manual, or exclusive.</td></tr><tr><td><code>rec_len</code> / <code>blksiz</code></td><td>Record length and buffer size.</td></tr><tr><td><code>magic</code></td><td>Integrity check confirming the slot is a live channel.</td></tr></tbody></table></div><div class="callout"><strong>Record buffers stay compatible.</strong> The runtime reads and writes fields at the byte offsets the application's FORTRAN record declares, so record-oriented programs keep the same on-disk layout and access semantics they had under OpenVMS. </div><h2 id="errors">Error handling and status codes</h2><p> FOR$ preserves OpenVMS FORTRAN error semantics. The conversion routines return standard status codes, the record-access routines validate the unit and open state before returning, and <code>ERRSNS</code> exposes the last error condition to the application exactly as it did under OpenVMS. Error state is held per thread, so a multi-threaded Linux process keeps each thread's last-error information separate. </p><h6>The ERRSNS path</h6><p><code>ERRSNS</code> returns the last I/O, system, status, unit, and condition values, then clears the saved condition so the next call reflects only new errors. The I/O status is the RMS status mapped to a FORTRAN IOSTAT value; the system and status values come from the unit's Record Access Block: </p> <pre><span class="cmt">/* FORTRAN: ERRSNS([IO_ERR][,SYS_ERR][,STAT][,UNIT][,COND]) */</span> void Vxf_Errsns(U32 *io_err, U32 *sys_err, U32 *stat, U32 *unit, U32 *cond) { if (io_err) *io_err = Vxf_rms_equiv(Vxf_VMS_STATUS); <span class="cmt">/* RMS to IOSTAT */</span> if (sys_err) *sys_err = Vxf_RmsStatus(Vxf_VMS_UNIT, Value); <span class="cmt">/* RAB/FAB STV */</span> if (stat) *stat = Vxf_RmsStatus(Vxf_VMS_UNIT, Status);<span class="cmt">/* RAB STS */</span> if (unit) *unit = Vxf_VMS_UNIT; if (cond) *cond = Vxf_VMS_STATUS; Vxf_VMS_STATUS = 0; <span class="cmt">/* reset saved information after each ERRSNS call */</span> }</pre> <h6>Run-time error codes</h6><p>The FORTRAN run-time layer reports record-access failures with a small, stable set of codes:</p><div class="table-wrapper"><table><thead><tr><th>Condition</th><th>Value</th><th>Meaning</th></tr></thead><tbody><tr><td>no error</td><td>0</td><td>No error.</td></tr><tr><td>channel out of range</td><td>1002</td><td>Unit number outside the valid range.</td></tr><tr><td>file not open</td><td>1004</td><td>Unit is not open.</td></tr><tr><td>no RAB</td><td>1006</td><td>No Record Access Block for the unit.</td></tr><tr><td>no FAB</td><td>1008</td><td>No File Access Block for the unit.</td></tr><tr><td>illegal channel number</td><td>1010</td><td>Channel table slot is not a live channel.</td></tr><tr><td>invalid record</td><td>1012</td><td>Record is not valid for the operation.</td></tr><tr><td>record overflow</td><td>1014</td><td>Record exceeds the buffer.</td></tr><tr><td>illegal filename</td><td>1016</td><td>File specification could not be translated.</td></tr></tbody></table></div><div class="callout"><strong>IOSTAT is preserved.</strong> FOR$ ships the full DEC and VSI FORTRAN IOSTAT table so that <code>READ</code> and <code>WRITE</code> error handling driven by IOSTAT values, including end-of-record and end-of-file, behaves the same on Linux as it did under OpenVMS. </div><h2 id="compatibility">Compatibility and divergences</h2><p> FOR$ is built to let OpenVMS FORTRAN applications run on Linux without source changes. A few behaviours differ from the original VMS runtime by design, because the target platform differs; each divergence keeps application-visible behaviour intact while adapting to Linux. </p><div class="table-wrapper"><table><thead><tr><th>Divergence</th><th>Reason</th></tr></thead><tbody><tr><td>Error state is held per thread rather than per image.</td><td>The Linux runtime can be multi-threaded, so last-error information is kept separate for each thread.</td></tr><tr><td><code>FOR$RAB</code> returns a null pointer and records the condition separately, rather than returning the status directly.</td><td>The Linux port returns the pointer type; callers consult the error state through <code>ERRSNS</code> when the pointer is null.</td></tr><tr><td>H_float conversion is carried on the shared double-precision path.</td><td>Linux on x86 has no native 128-bit H_float type, so H_float folds onto the shared formatter.</td></tr><tr><td>Filenames pass through VMS-to-Unix translation at OPEN time.</td><td>VMS file specifications are mapped to Unix paths, which RMS handled natively on OpenVMS.</td></tr><tr><td>Open files are closed by a registered exit handler.</td><td>Reproduces OpenVMS image-rundown file cleanup on Linux through a process exit handler.</td></tr></tbody></table></div><div class="callout"><strong>Ships inside VX/RT.</strong> FOR$ is delivered as part of the VX/RT run-time, so a FORTRAN application picks up FOR$ conversion and record-access services alongside the rest of the OpenVMS run-time surface on x86 and ARM Linux. </div><h2 id="quickref">Quick reference</h2><h6>Public FOR$ entry points</h6><div class="kw-grid"><div>FOR$CVT_D_TE</div><div>FOR$CVT_G_TE</div><div>FOR$CVT_H_TE</div><div>FOR$RAB</div></div><h6>Record-I/O statements serviced</h6><div class="kw-grid"><div>OPEN</div><div>CLOSE</div><div>READ</div><div>WRITE</div><div>REWRITE</div><div>DELETE</div><div>BACKSPACE</div><div>REWIND</div><div>ENDFILE</div><div>INQUIRE</div><div>UNLOCK</div><div>ERRSNS</div></div><h6>RMS file organizations</h6><div class="kw-grid"><div>sequential</div><div>relative</div><div>indexed</div></div><h6>Call shapes</h6><div class="table-wrapper"><table><thead><tr><th>Routine</th><th>Contract</th></tr></thead><tbody><tr><td><code>FOR$CVT_x_TE</code></td><td>Format a floating value to edited text; return normal status, or an output-conversion error with the field filled with asterisks on overflow.</td></tr><tr><td><code>FOR$RAB</code></td><td>Return the unit's Record Access Block, or NULL with the condition recorded for <code>ERRSNS</code>.</td></tr></tbody></table></div><h6>Key facts</h6><div class="table-wrapper"><table><thead><tr><th>Item</th><th>Value</th></tr></thead><tbody><tr><td>Maximum FORTRAN unit number</td><td>1024</td></tr><tr><td>Delivered in</td><td>VX/RT run-time, archived into <code>libvxrt.a</code></td></tr><tr><td>Target platforms</td><td>x86 and ARM Linux</td></tr><tr><td>Error state scope</td><td>Per thread</td></tr></tbody></table></div></div>

Frequently Asked Questions

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

What is VX/FOR$ and how does it help with FORTRAN migration?

VX/FOR$ provides a call-compatible implementation of OpenVMS Fortran runtime APIs for x86 and ARM Linux. It ensures that OpenVMS Fortran applications can execute seamlessly while preserving language features, execution behavior, and system interactions.

This tool eliminates the need to rewrite complex Fortran runtime dependencies, allowing organizations to migrate legacy applications efficiently. For migration planning and implementation support, contact our team.

What specific features does VX/FOR$ support?

VX/FOR$ supports data format conversion, record access management, runtime execution, and maintains OpenVMS Fortran execution semantics to ensure consistent behavior on Linux.

Which FOR$ API functions are supported?

VX/FOR$ supports key APIs including FOR$CVT_D_TE for decimal to text conversion, FOR$CVT_G_TE for floating-point G format conversion, FOR$CVT_H_TE for hexadecimal to text conversion, and FOR$RAB for Record Access Block operations.

How does VX/FOR$ integrate with other migration tools?

VX/FOR$ seamlessly integrates with VX/RT to provide full OpenVMS Fortran runtime capabilities on x86 and ARM Linux systems.

Can VX/FOR$ handle complex record access operations?

Yes, VX/FOR$ includes full support for Record Access Block (RAB) operations, which are essential for OpenVMS applications that perform complex file I/O and data management tasks. The tool preserves the original OpenVMS behavior for these operations on Linux.

Organizations like BNY Mellon have successfully migrated complex Fortran applications with similar record management requirements.

Does VX/FOR$ require code modifications during migration?

VX/FOR$ is designed to minimize code modifications by providing call-compatible implementations of OpenVMS FOR$ APIs, allowing direct porting of applications.

How does VX/FOR$ maintain OpenVMS compatibility?

VX/FOR$ maintains full compatibility with OpenVMS FOR$ runtime functions and preserves OpenVMS Fortran execution logic. This ensures that migrated applications behave identically to their original OpenVMS counterparts, reducing testing requirements and migration risks.

What are the benefits of using VX/FOR$ for Fortran migration?

VX/FOR$ delivers significant cost and time savings by preserving existing OpenVMS Fortran execution logic and enabling direct porting without major modifications. Organizations can maintain productivity while modernizing their infrastructure.

The tool supports key OpenVMS Fortran operations including data conversion and record access, ensuring comprehensive compatibility. Companies like Amprion GmbH have successfully leveraged similar runtime preservation strategies for complex Fortran applications.

VX/FOR$ minimizes development costs and accelerates migration timelines. To explore how VX/FOR$ can streamline your Fortran migration project, contact us for a consultation.

Which Fortran features are not supported by the new host compiler?

These are language constructs which are supported by VMS for which there are no simple syntactic translations to modern Fortran. The code must be re-structured. Usually, sub-programs must be called to supply the missing features.

Again, the VMS code will simply not compile or run without modification. The important issues are:

  • VMS File Names in OPEN and INQUIRE: VMS file names may contain device directory and version specifications. When these are specified in I/O statements they must be translated at run-time on the new host. This is done by calling sub-programs in Sector7's VXRMS library.
  • ISAM Files: Indexed Sequential Access Method files are files which contain linkage pointers from fields within their records to related records. Under VMS the OPEN, READ, WRITE and INQUIRE keywords are extended to support them. These extension are not supported under Linux, Unix or Windows. fpt handles ISAM files by replacing the OPEN, CLOSE, INQUIRE, READ and WRITE statements by calls to sub-programs in Sector7' VXRMS library.
  • Variables and Expressions in FORMAT Statements: Under VMS, variables and run-time expressions may be written inside FORMAT statements or in embedded format strings. The variables or expressions are written within < > delimiters. This construct is translated to standard Fortran using run-time format strings.
What is FOR$?

FOR$ is a call-compatible re-implementation of the OpenVMS FORTRAN run-time support (FOR$) routines for x86 and ARM Linux. It lets OpenVMS FORTRAN applications run on Linux while preserving language features, execution behaviour, and system interactions.

Which platforms does FOR$ run on?

FOR$ runs on x86 and ARM Linux. It brings the OpenVMS FORTRAN run-time support routines to both architectures, so FOR$-dependent applications execute with consistent behaviour on Linux.

Which FOR$ routines does the library provide?

The library documents four public callable routines: FOR$CVT_D_TE (D_float to text), FOR$CVT_G_TE (G_float to text), FOR$CVT_H_TE (H_float to text), and FOR$RAB, which returns the RMS Record Access Block for an open FORTRAN unit.

Do I have to rewrite my FORTRAN application to use FOR$?

No major modifications are required. FOR$ is call-compatible with the OpenVMS FOR$ routines, so applications that rely on them can be ported directly and keep their original execution logic.

How does FOR$ relate to VX/RT?

FOR$ is delivered inside VX/RT. It integrates with the VX/RT run-time to provide the OpenVMS FORTRAN run-time support services on x86 and ARM Linux alongside the rest of the OpenVMS run-time surface.

Does FOR$ handle record access (RAB) operations?

Yes. FOR$RAB validates a FORTRAN unit and returns its RMS Record Access Block, and the run-time supports the full record-I/O surface (OPEN, READ, WRITE, REWRITE, DELETE, and more) while preserving OpenVMS record access behaviour on Linux.

What kinds of numeric conversion does FOR$ support?

FOR$ provides the FOR$CVT family of numeric-to-text conversion routines, formatting D_float, G_float, and H_float values into edited character strings. A field that does not fit its output is filled with asterisks and reported as an output-conversion error, matching the OpenVMS edit-descriptor convention.

Will my application behave the same after migrating with FOR$?

That is the goal. FOR$ preserves OpenVMS FORTRAN execution semantics, including IOSTAT error handling and record access behaviour, so applications run as they did under OpenVMS while executing on x86 and ARM Linux.

Transform Your Legacy Software Today!

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