Synergex.FDLCleaner
1.0.26224.2028
dotnet tool install --global Synergex.FDLCleaner --version 1.0.26224.2028
dotnet new tool-manifest
dotnet tool install --local Synergex.FDLCleaner --version 1.0.26224.2028
#tool dotnet:?package=Synergex.FDLCleaner&version=1.0.26224.2028
nuke :add-package Synergex.FDLCleaner --version 1.0.26224.2028
FDLCleaner
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
.FDLextension; - 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:
- every existing
FILE NAMEattribute in theFILEsection is replaced; - if the FDL has a
FILEsection but noNAMEattribute, aNAMEattribute is inserted as the first property after the section header; - if the input base name is missing from the map, the fallback value is
<BASE>.ISM; and - 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:
- Normalize
KEY nheaders to one space and remove leading zeros from the key number; orderKEYsegment attributes by segment number, withSEGn_LENGTHbeforeSEGn_POSITION; suppress leading zeros on numeric values forRECORD SIZEandKEYSEGn_POSITIONandSEGn_LENGTHattributes; removeNULL_KEY NOproperties from allKEYsections; remove the one-lineIDENTsection and its following blank line when--remove-identis supplied; remove allAREAsections when--remove-areasis supplied and, when doing so, removeDATA_AREA,INDEX_AREA, andLEVEL1_INDEX_AREAfrom allKEYsections; remove the one-lineTITLEsection and its following blank line when--remove-titleis supplied; - Remove
ANALYSIS_OF_AREAandANALYSIS_OF_KEYsections unless--no-remove-analysisis supplied; - Remove the
SYSTEMsection when--remove-systemis supplied; - When
--remove-block-spanis supplied, removeBLOCK_SPANfrom theRECORDsection; - When
--remove-key-compression,--remove-record-compression, or--remove-index-compressionis supplied, remove the corresponding compression property from allKEYsections; - When
--remove-fillis supplied, removeDATA_FILLandINDEX_FILLfrom allKEYsections; - When
--remove-prologis supplied, removePROLOGfrom allKEYsections; - Remove
OWNERandPROTECTIONfrom theFILEsection, 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; - Unless
--remove-nameis supplied, clean existingFILE NAMEvalues; - Apply a file-name map, if supplied;
- Remove trailing whitespace from inside quoted property values;
- Check
KEY NAMEvalues and emit warnings when--check-key-namesis supplied; and - Render the document with normalized indentation unless
--no-reindentwas 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.Ycomes fromVERSION;YYis the two-digit UTC year;DDDis the three-digit UTC day of year (001through366);HHis the two-digit UTC hour (00through23); andMMis the two-digit UTC minute (00through59).
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, andnet10.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 | Versions 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. |
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 |