Portable CLI Argument Parsing in Fortran 2003
A guide to portable CLI argument parsing in Fortran 2003+ using command_argument_count and deferred-length strings for robust input validation and error recovery.
03 Apr 2026, 19:12 UTC

The Problem: Predictable Input Validation in Fortran
Fortran programs integrated into automated pipelines must handle command-line arguments reliably. A common failure point is the use of fixed-length character buffers that silently truncate long file paths or the lack of explicit validation before attempting file I/O. When a program fails due to missing or malformed arguments, it must provide a clear diagnostic to stderr and return a nonzero exit status to signal the calling shell or script.
The Fortran 2003 standard introduced command_argument_count and get_command_argument, which provide a portable way to handle these tasks without relying on nonstandard compiler extensions.
Desired Outcome
A portable Fortran program that accepts a required input path and an optional integer repeat count, validates both, and terminates with a specific error code if the input is invalid, ensuring no files are opened until all arguments are verified.
Prerequisites
- A Fortran 2003 or later compliant compiler (e.g., gfortran, ifort).
- Source code written in free-form format (recommended for modern standards).
- Compilation with standards conformance flags (e.g.,
-std=f2008) to ensure portability.
Implementation Procedure
1. Querying Argument Count
Use command_argument_count() to determine how many arguments were passed. Note that unlike C's argc, this intrinsic does not count the program name itself; index 1 refers to the first user-supplied argument.
program task_runner
implicit none
character(len=:), allocatable :: path_arg, repeat_arg
integer :: nargs, repeat_count, status
nargs = command_argument_count()
if (nargs < 1) then
write(*, '(A)') 'Usage: task_runner <input_path> [repeat_count]'
stop 1
end if
2. Retrieving Arguments with Deferred Length
To prevent truncation of long directory paths, use allocatable character strings with deferred-length len=:. This allows the compiler to allocate exactly the amount of memory needed for the argument string.
! Retrieve the required input path
call get_command_argument(1, path_arg)
! Set default for optional repeat count
repeat_count = 1
if (nargs >= 2) then
call get_command_argument(2, repeat_arg)
! Convert string to integer using internal read
read(repeat_arg, *, iostat=status) repeat_count
if (status /= 0) then
write(*, '(A, A)') 'Error: repeat_count must be an integer: ', trim(repeat_arg)
stop 2
end if
if (repeat_count <= 0) then
write(*, '(A)') 'Error: repeat_count must be a positive integer'
stop 3
end if
end if
3. Safe File Access
Only attempt to open the file after all arguments are validated. Use the iostat and iomsg parameters to capture system-level errors without crashing the program.
integer :: unit_num, ios
character(len=256) :: msg
open(newunit=unit_num, file=path_arg, status='old', action='read', iostat=ios, iomsg=msg)
if (ios /= 0) then
write(*, '(A, A)') 'Error opening file: ', trim(msg)
if (allocated(path_arg)) deallocate(path_arg)
if (allocated(repeat_arg)) deallocate(repeat_arg)
stop 4
end if
! ... perform task ...
close(unit_num)
end program task_runner
Expected Checks and Validation
| Test Case | Expected Result | Exit Code |
|---|---|---|
| No arguments | Usage message printed | 1 |
| Path provided, repeat is "abc" | Integer conversion error | 2 |
| Path provided, repeat is "-5" | Positive range error | 3 |
| Path does not exist | iomsg error from open() | 4 |
| Valid path and integer | Successful execution | 0 |
Recovery and Rollback
Because this operation changes the state of the system by opening a file unit, failure recovery must ensure resources are released. If open() fails, the newunit is not associated, but any previously allocated strings should be explicitly deallocated if the program is part of a larger module. Using the stop [integer] statement is the standard way to terminate and return a status code to the operating system.
Limitations
- Memory: While deferred-length strings prevent truncation, they rely on the compiler's implementation of
get_command_argumentto handle allocation. - OS Differences: The exact string returned by
iomsgvaries between compilers (e.g., GNU vs Intel) and operating systems. - Indexing: Always remember that
command_argument_countexcludes the executable path; starting at index 0 will result in a runtime error.
Practical Verification
Compile the program using a standard-compliant command:
gfortran -std=f2008 -Wall -o task_runner task_runner.f90
To verify the exit status on Linux or macOS, run a failing case and check the special variable $?:
./task_runner non_existent_file.txt -1
echo $?
The output should be 3, indicating the range validation failed before the program even attempted to check if the file existed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.