Synergex.FDLCleaner 1.0.26224.2028

dotnet tool install --global Synergex.FDLCleaner --version 1.0.26224.2028
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Synergex.FDLCleaner --version 1.0.26224.2028
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Synergex.FDLCleaner&version=1.0.26224.2028
                    
nuke :add-package Synergex.FDLCleaner --version 1.0.26224.2028
                    

FDLCleaner

Windows x64 Linux x64 .NET 8 .NET 9 .NET 10 NuGet NuGet Downloads License: BSD-2-Clause

FDLCleaner is a .NET command-line tool for cleaning up and standardizing OpenVMS File Definition Language (FDL) files. It processes files in place, preserves their established text encoding and line-ending convention, and can optionally create backups before making changes.

The tool is intended for FDL files generated by OpenVMS RMS utilities. It performs a focused, text-preserving cleanup rather than attempting to be a complete FDL compiler or validator.

Platforms and Requirements

The tool targets .NET 8, .NET 9, and .NET 10. A compatible .NET runtime is required to run an installed tool; the .NET SDK is required to build or pack the project.

The tool can run on any operating system supported by the selected .NET runtime. File specifications that use OpenVMS-style logical names are mapped through the local process environment; the tool does not access an OpenVMS system or read synergy.ini. The update mode requires HTTPS access to nuget.org.

Installing the tool

Install the published package globally with the .NET CLI:

dotnet tool install --global Synergex.FDLCleaner

The installed command is fdlcleaner. Display command help with:

fdlcleaner help

Update an existing global installation:

dotnet tool update --global Synergex.FDLCleaner

Uninstall it with:

dotnet tool uninstall --global Synergex.FDLCleaner

If the command is not found immediately after installation on Windows, open a new terminal so that the updated .NET tools directory is available on PATH.

Command-line syntax

The first argument is either the input specification, the help mode, or the update mode:

fdlcleaner <input> [options]
fdlcleaner help
fdlcleaner update

If no arguments are supplied, FDLCleaner reports the missing input error and then displays the help information:

ERROR: An FDL file or wildcard, a list input file, or 'help' or 'update'.

Examples:

fdlcleaner CUSTOMER.FDL
fdlcleaner FDL:*.FDL --quiet --backup
fdlcleaner CUSTOMER.FDL --remove-areas
fdlcleaner fdl-files.lst --file-name-map file-name-map.txt
fdlcleaner help
fdlcleaner update

Paths containing spaces should be quoted according to the shell being used. Options are case-insensitive. Options that take a value can use either a separate argument or an equals sign, for example:

fdlcleaner CUSTOMER.FDL --file-name-map names.txt
fdlcleaner CUSTOMER.FDL --file-name-map=names.txt

Options

help mode

Displays the usage summary and exits successfully. It must be the first argument.

--quiet

Suppresses the Processing: <file> message for each FDL file and the completion statistics. By default, those messages are written to standard output. Errors and warnings continue to be written to standard error.

--backup

Copies each changed original file before overwriting it. Existing backup files are overwritten. The backup suffix follows the case of the input file name:

Input file name Backup file name
CUSTOMER.FDL CUSTOMER.FDL.BACKUP
Customer.FDL Customer.FDL.backup

Files that require no changes are not backed up.

--check-key-names

Enables warnings for KEY n NAME values. The check does not modify key names and is disabled unless this option is supplied. When enabled, it warns when a key name:

  • is empty;
  • does not begin with an ASCII letter;
  • contains characters other than ASCII letters, digits, or underscores;
  • exceeds 15 characters; or
  • conflicts with another key name after comparison at the 15-character limit.

The check is limited to KEY NAME attributes. It does not validate every FDL rule, key segment, or key-number ordering constraint.

--file-name-map <file>

Uses a mapping file to replace FILE NAME values. The map is described in the File-name maps section.

--indent-with-tabs

Uses 8-character tab-based indentation when the document is reindented. This option has no effect when --no-reindent is supplied.

--no-reindent

Preserves the existing section and attribute indentation as much as possible. Without this option, the renderer normalizes the layout by placing primary sections on separate formatted lines, indenting secondary attributes with spaces, placing property names at column 9 and values at column 33 when the property name fits, and inserting a blank line between primary sections.

Value replacements and removed statements are applied in either rendering mode.

--no-remove-analysis

Keeps ANALYSIS_OF_AREA and ANALYSIS_OF_KEY sections. By default, these sections and their secondary attributes are removed.

--no-remove-owner

Keeps OWNER attributes in the FILE section. By default, FILE OWNER is removed.

--no-remove-protection

Keeps PROTECTION attributes in the FILE section. By default, FILE PROTECTION is removed.

--no-file-name-clean

Disables the default cleanup of existing FILE NAME values. The default cleanup removes the device specification, bracketed directory portions, and file version from a VMS file specification.

For example, a value such as:

"DISK$DATA:[APPLICATION.DATA]CUSTOMER.DAT;3"

is cleaned to:

"CUSTOMER.DAT"

The original single- or double-quote style is retained when a value is rewritten. This option does not disable a file-name map. If both --no-file-name-clean and --file-name-map are supplied, the tool emits a warning and still applies the map.

--no-remove-comments

Preserves ! comments. Despite the option name, comments are removed by default and preserved when this option is supplied. This includes comment-only lines and comments attached to statements that are removed by a cleanup rule.

--remove-areas

Removes complete AREA n sections and their secondary attributes. When this option is supplied, the cleaner also removes DATA_AREA, INDEX_AREA, and LEVEL1_INDEX_AREA properties from all KEY sections. By default, AREA n sections and these properties are preserved.

--remove-block-span

Removes BLOCK_SPAN properties from the RECORD section. The property is retained unless this option is supplied.

--remove-contiguous

Removes CONTIGUOUS properties from the FILE section. The property is retained unless this option is supplied.

--remove-key-compression

Removes DATA_KEY_COMPRESSION properties from all KEY sections. The property is retained unless this option is supplied.

--remove-record-compression

Removes DATA_RECORD_COMPRESSION properties from all KEY sections. The property is retained unless this option is supplied.

--remove-deferred-write

Removes DEFERRED_WRITE properties from the FILE section. The property is retained unless this option is supplied.

--remove-file-allocation

Removes ALLOCATION properties from the FILE section. The property is retained unless this option is supplied.

--remove-file-bucket-size

Removes BUCKET_SIZE properties from the FILE section. The property is retained unless this option is supplied.

--remove-file-cluster-size

Removes CLUSTER_SIZE properties from the FILE section. The property is retained unless this option is supplied.

--remove-file-contiguous

Removes BEST_TRY_CONTIGUOUS properties from the FILE section. The property is retained unless this option is supplied.

--remove-file-extension

Removes EXTENSION properties from the FILE section. The property is retained unless this option is supplied.

--remove-file-monitoring

Removes FILE_MONITORING properties from the FILE section. The property is retained unless this option is supplied.

--remove-fill

Removes DATA_FILL and INDEX_FILL properties from all KEY sections. These properties are retained unless this option is supplied. This option is independent of AREA section removal.

--remove-global-buffers

Removes GLOBAL_BUFFER* and GLBUFF* properties from the FILE section. Any property whose name begins with either prefix is removed when this option is supplied.

--remove-ident

Removes the one-line IDENT section. If a blank line immediately follows the section, that blank line is removed as well.

--remove-index-compression

Removes INDEX_COMPRESSION properties from all KEY sections. The property is retained unless this option is supplied.

--remove-name

Removes all NAME properties from the FILE section. When this option is supplied, the normal FILE NAME cleanup is skipped. It cannot be combined with --file-name-map; supplying both options is an error.

--remove-prolog

Removes PROLOG properties from all KEY sections. The properties are retained unless this option is supplied.

--remove-system

Removes the entire SYSTEM section, including its secondary attributes, when this option is supplied.

--remove-title

Removes a one-line TITLE section. If a blank line immediately follows the section, that blank line is removed as well.

update mode

Checks nuget.org for the latest stable Synergex.FDLCleaner package. This is a standalone command and must be the first argument:

fdlcleaner update

When the installed version is current, the tool reports:

You have the latest version

When a newer version is available, it reports the installation command on the following line:

A new version is available, to install it run:
dotnet tool install --global Synergex.FDLCleaner --version <version>

The check requires network access to nuget.org. A failed network request or invalid package metadata returns exit code 1.

Selecting input files

The positional input specification can identify one FDL file, a wildcard, or a list file.

A single FDL file

An input file is recognized directly when its file name has a .FDL extension, regardless of case:

fdlcleaner CUSTOMER.FDL
fdlcleaner C:\Projects\Fdl\Customer.fdl

The tool rewrites the input file in place.

An FDL wildcard

Wildcards are supported in the file-name portion of an FDL specification. The supported wildcard characters are * and ?:

fdlcleaner C:\Projects\Fdl\*.FDL --backup
fdlcleaner FDL:CUST??.FDL --quiet

For a top-level wildcard input:

  • the wildcard must be in the file name, not a directory portion;
  • the specification must identify FDL files with a .FDL extension;
  • subdirectories are not searched;
  • matches are processed in sorted path order; and
  • duplicate paths are removed.

An input list file

If the positional input does not have a .FDL extension, it is treated as a list file. Each nonblank line identifies one input file or wildcard:

CUSTOMER.FDL
INVENTORY.FDL
FDL:ORDERS*.FDL

List files support blank lines, comments, and optional single or double quotes around a complete entry. A #, ;, or ! outside quotes begins a comment; everything after the first such character on that line is ignored. These characters remain part of an entry when they occur inside quotes. For example:

# Process the customer file.
CUSTOMER.FDL ; the comment begins here
"C:\Projects\Fdl\customer#archive.FDL" ! marker is inside the quoted path

Relative list entries are first resolved relative to the current working directory. If they are not found there, the tool tries the directory containing the list file. Wildcard entries use the same fallback behavior. Logical-name entries are resolved through the environment before the list-file fallback is considered.

Example list file:

"C:\Projects\Fdl\CUSTOMER.FDL"
DATA\INVENTORY.FDL
FDL:ORDERS*.FDL

Duplicate paths from a list are processed only once.

Logical-name paths

The tool supports a local environment-variable convention for VMS-style logical names. A specification such as:

FDL:*.FDL

uses the value of the local FDL environment variable as its directory. On PowerShell:

$env:FDL = 'C:\Projects\Fdl'
fdlcleaner FDL:*.FDL

On Windows Command Prompt:

set FDL=C:\Projects\Fdl
fdlcleaner FDL:*.FDL

If the environment variable is undefined or empty, the current working directory is used. This fallback makes examples such as FDL:*.FDL usable without configuration, but it can also cause an unexpected directory to be searched if a logical name was misspelled.

On Windows, logical names may contain letters, digits, underscores, dollar signs, and hyphens, subject to the first-character rule required by the tool. On Linux and macOS, logical names must use portable environment-variable characters: letters, digits, and underscores, with a letter or underscore as the first character. Use a portable logical name such as FDL_DATA when the same command must run across operating systems. A Windows drive path such as C:\Data\File.FDL is treated as a normal drive path, not as a logical name.

OpenVMS file values can still contain $, such as DISK$DATA:[ISAM]CUSTOMER.ISM; this restriction applies only to logical names resolved through the local environment.

The same resolution rules apply to --file-name-map paths.

File-name maps

A file-name map is a plain text file containing KEY=VALUE entries:

# Map the FDL input base name to the desired FILE NAME value.
CUSTOMER=DISK$DATA:[ISAM]CUSTOMER.ISM
INVENTORY=MDS$INVENTORY_FILE
ORDERS=DATA:ORDERS.ISM

Map rules are:

  • blank lines are ignored;
  • lines beginning with # or ; are ignored;
  • the first = separates the key from the value;
  • keys and values are trimmed;
  • keys are compared case-insensitively and normalized to uppercase;
  • a later duplicate key replaces the earlier value; and
  • malformed lines produce warnings and are ignored.

The lookup key is the uppercase base name of the input FDL file, not the existing FILE NAME value inside the FDL. For example, processing C:\Fdl\customer.FDL looks up CUSTOMER.

When a map is supplied:

  1. every existing FILE NAME attribute in the FILE section is replaced;
  2. if the FDL has a FILE section but no NAME attribute, a NAME attribute is inserted as the first property after the section header;
  3. if the input base name is missing from the map, the fallback value is <BASE>.ISM; and
  4. a warning is emitted when the fallback is used.

If the FDL contains no FILE section, there is no valid section in which to place a NAME attribute, so no mapped name is added.

Map values are used as supplied, subject to trimming and quote-style handling when an existing FDL value is replaced. A map is useful when the target file name differs from the FDL input file name or when a complete VMS file specification must be restored.

What the cleaner changes

The transformation order is:

  1. Normalize KEY n headers to one space and remove leading zeros from the key number; order KEY segment attributes by segment number, with SEGn_LENGTH before SEGn_POSITION; suppress leading zeros on numeric values for RECORD SIZE and KEY SEGn_POSITION and SEGn_LENGTH attributes; remove NULL_KEY NO properties from all KEY sections; remove the one-line IDENT section and its following blank line when --remove-ident is supplied; remove all AREA sections when --remove-areas is supplied and, when doing so, remove DATA_AREA, INDEX_AREA, and LEVEL1_INDEX_AREA from all KEY sections; remove the one-line TITLE section and its following blank line when --remove-title is supplied;
  2. Remove ANALYSIS_OF_AREA and ANALYSIS_OF_KEY sections unless --no-remove-analysis is supplied;
  3. Remove the SYSTEM section when --remove-system is supplied;
  4. When --remove-block-span is supplied, remove BLOCK_SPAN from the RECORD section;
  5. When --remove-key-compression, --remove-record-compression, or --remove-index-compression is supplied, remove the corresponding compression property from all KEY sections;
  6. When --remove-fill is supplied, remove DATA_FILL and INDEX_FILL from all KEY sections;
  7. When --remove-prolog is supplied, remove PROLOG from all KEY sections;
  8. Remove OWNER and PROTECTION from the FILE section, along with any properties selected by --remove-contiguous, --remove-deferred-write, --remove-file-allocation, --remove-file-bucket-size, --remove-file-cluster-size, --remove-file-contiguous, --remove-file-extension, --remove-file-monitoring, --remove-global-buffers, and --remove-name;
  9. Unless --remove-name is supplied, clean existing FILE NAME values;
  10. Apply a file-name map, if supplied;
  11. Remove trailing whitespace from inside quoted property values;
  12. Check KEY NAME values and emit warnings when --check-key-names is supplied; and
  13. Render the document with normalized indentation unless --no-reindent was supplied.

The transformations are text-oriented and are applied only to recognized sections and attributes. Unknown attributes are retained. The tool does not reorder sections, repair invalid FDL values, renumber keys, or rewrite the entire file into a canonical semantic representation.

The recognized primary sections are:

TITLE
IDENT
SYSTEM
FILE
DATE
RECORD
ACCESS
NETWORK
SHARING
CONNECT
AREA
KEY
ANALYSIS_OF_AREA
ANALYSIS_OF_KEY

These are the primary sections described by the VSI OpenVMS Record Management Utilities Reference Manual.

Comments and statement boundaries

FDL statements can share a source line and are separated by semicolons. An exclamation point begins a comment. The parser recognizes semicolons and exclamation points outside quoted text, so quoted values can safely contain those characters.

The tool does not accept every possible malformed FDL construct. In particular, an unquoted comment containing a semicolon is ambiguous under the FDL rules and should be corrected before processing.

Reindent behavior

With the default rendering mode, primary sections are emitted as headers and secondary attributes are emitted on indented lines. Property names begin at column 9, and values begin at column 33 when the property name is short enough; longer property names receive one separating space. A blank line is placed between primary sections. TITLE and IDENT content remains unindented.

Supplying --indent-with-tabs restores tab-based property indentation and tab-stop value alignment for compatibility with the previous formatter.

With --no-reindent, the original line and statement arrangement is retained as much as possible. Removed statements and replaced values still change the result, blank lines are emitted without whitespace, and the renderer may need to adjust semicolons when statements are removed from a line.

Encoding and line endings

When a file is read, FDLCleaner detects and preserves these encodings when it writes a changed file:

  • UTF-32 big-endian and little-endian with a BOM;
  • UTF-8 with a BOM;
  • UTF-16 little-endian and big-endian with a BOM;
  • BOM-less UTF-8 when the content is valid UTF-8; or
  • Latin-1 as a fallback for BOM-less content that is not valid UTF-8.

The original BOM is retained. The tool detects the dominant newline convention (CRLF, LF, or CR) and uses it for the rendered file. Every rendered file ends with exactly one blank line.

File processing and safety

FDLCleaner modifies input files in place. It does not provide a dry-run mode or an output-directory option. Use --backup when reviewing a new cleanup rule, and verify the input wildcard or list before processing a large set of files.

The tool skips writing a file when the transformed text is identical to the original text. A backup is therefore created only when a file actually changes.

Warnings, such as a missing map entry or an invalid key name when --check-key-names is enabled, do not by themselves stop processing. The process continues with the next file.

Exit codes and diagnostics

Exit code Meaning
0 Help or update completed successfully, or all selected files were processed successfully.
1 One or more selected files could not be processed, or an update check could not complete.
2 Command-line parsing, input resolution, or file-name-map loading failed before normal processing.

Errors and warnings are written to standard error. Processing messages and completion statistics are written to standard output unless --quiet is supplied. The completion statistics have this form:

Processed <count> files, altered: <count>

The processed count includes files successfully read and transformed. The altered count includes files whose transformed content was successfully saved.

Building the project

Restore and build the solution from the repository root:

dotnet restore FDLCleaner.slnx
dotnet build FDLCleaner.slnx --configuration Release

The project targets .NET 8, .NET 9, and .NET 10. A normal build generates assembly version metadata using the current UTC time and the major/minor prefix from the root VERSION file.

Versioning

The root VERSION file contains the major/minor prefix, for example:

1.0

Release versions use this format:

X.Y.YYDDD.HHMM

Where:

  • X.Y comes from VERSION;
  • YY is the two-digit UTC year;
  • DDD is the three-digit UTC day of year (001 through 366);
  • HH is the two-digit UTC hour (00 through 23); and
  • MM is the two-digit UTC minute (00 through 59).

For example, a build at 00:38 UTC on day 217 of 2026 has the full build stamp 1.0.26217.0038.

The full padded value is applied to the assembly file and informational version metadata. NuGet normalizes numeric package-version components by removing leading zeroes, so the corresponding package identity may be displayed as 1.0.26217.38. This is normal NuGet behavior; see the NuGet package version reference.

Creating a NuGet tool package

The project is configured as a .NET tool package with:

  • package ID Synergex.FDLCleaner;
  • command name fdlcleaner;
  • target frameworks net8.0, net9.0, and net10.0;
  • package README and BSD 2-Clause license metadata; and
  • a symbol package generated alongside the main package.

Use the repository packaging script so one UTC timestamp is used for the assembly and package version throughout the pack operation:

build\Pack.ps1

The script accepts these parameters:

build\Pack.ps1 -Configuration Debug
build\Pack.ps1 -Configuration Release -NoRestore

Packages are written to artifacts\nupkg:

artifacts\nupkg\Synergex.FDLCleaner.<version>.nupkg
artifacts\nupkg\Synergex.FDLCleaner.<version>.snupkg

Use -NoRestore only when the project has already been restored for the current dependency state.

Testing a locally built package

A package can be installed to an isolated tool directory without changing the global tool installation:

$packageDirectory = (Resolve-Path .\artifacts\nupkg).Path
$toolDirectory = Join-Path $PWD 'local-tool'

dotnet tool install `
    --tool-path $toolDirectory `
    --add-source $packageDirectory `
    Synergex.FDLCleaner

& (Join-Path $toolDirectory 'fdlcleaner.exe') help

For a global installation from a local package source, specify the package version explicitly when more than one package version is present:

dotnet tool install --global Synergex.FDLCleaner `
    --add-source .\artifacts\nupkg `
    --version <version>

Publishing to nuget.org

Publishing requires an account and a NuGet API key with permission to publish the Synergex.FDLCleaner package. Keep the API key out of source control and prefer an environment variable or a credential provider.

After reviewing and locally testing the package, publish the main package with:

$env:NUGET_API_KEY = '<your-api-key>'
$package = Get-ChildItem .\artifacts\nupkg\Synergex.FDLCleaner.*.nupkg |
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 1

dotnet nuget push $package.FullName `
    --api-key $env:NUGET_API_KEY `
    --source https://api.nuget.org/v3/index.json

Do not publish a version that already exists on nuget.org. Package versions are immutable once published; increment the VERSION prefix or generate a new UTC build version for a subsequent release.

License

This project is licensed under the BSD 2-Clause License. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.0.26224.2028 124 8/12/2026
1.0.26220.15 110 8/8/2026
1.0.26219.46 105 8/7/2026
1.0.26218.49 97 8/6/2026
1.0.26217.1936 104 8/5/2026