Degenerate Conic

Algorithms • Modern Fortran Programming • Orbital Mechanics

Feb 17, 2018

Command Line Arguments

prompt

A standard way to access a program's command line arguments wasn't added to Fortran until 2003. Command line arguments were one of those things (like environment variables, the file system, and the operating system shell) that the Fortran standards committee pretended didn't exist or wasn't important. Of course, that was and is ridiculous. So for decades, all Fortran compilers provided a non-standard way to get the command line arguments (for example, GETARG in gfortran). Currently, the standards committee still pretends that the file system doesn't exist (for example, there's no standard way to change an application's working directory, or list the files in a directory, or even to check for the existence of directories). But I digress.

The two routines you need to know are COMMAND_ARGUMENT_COUNT and GET_COMMAND_ARGUMENT. Frequently in examples on the internet (even the gfortran example) you will see people just declare a really long string and use GET_COMMAND_ARGUMENT to get the command line argument and hope for the best. That's terrible of course, since this routine does have the ability to return the actual length of the argument, so you should use that to allocate a string with the correct size to hold it.

Consider the following example:

module command_line_module

    implicit none

    private

    type,public :: string
        !! a variable-length string type
        character(len=:),allocatable :: str
    end type

    public :: get_command_arguments

contains

subroutine get_command_arguments(nargs, args)

    !! return all the command line arguments.
    !! (each one is the correct size)

    implicit none

    integer,intent(out) :: nargs !! number of arguments
    type(string),dimension(:),allocatable,intent(out) :: args

    integer :: i, ilen

    nargs = command_argument_count()
    allocate(args(0:nargs))

    do i = 0, nargs
        call get_command_argument(i,length=ilen)
        allocate(character(len=ilen) :: args(i)%str)
        call get_command_argument(i,value=args(i)%str)
    end do

end subroutine get_command_arguments

end module command_line_module

Here we have to define our own string type (string), so we can create an array of deferred-length strings (since a useful varying-length string type is another thing Fortran pretends is not important). See StringiFor for a full-featured variable-string type, but for our purposes here the simple one is fine. The procedure in the get_command_arguments() routine is to check for the size of each argument, allocate a string large enough to hold it, and then retrieve the value. It returns an array of string variables containing the command line arguments. With a wrapper module like this, getting command line arguments is effortless, and there is no reason anymore to use the old non-standard routines.