Command Line Subcommands in Fortran

Here’s the translation of the Go code to Fortran, with explanations in Markdown format suitable for Hugo:

Our program demonstrates the use of command-line subcommands, each with its own set of flags. This is similar to how tools like git have different subcommands (e.g., git commit, git push) with their own specific options.

program main
    use, intrinsic :: iso_fortran_env, only: error_unit
    implicit none
    
    integer :: num_args
    character(len=32) :: arg
    
    ! Variables for 'foo' subcommand
    logical :: foo_enable = .false.
    character(len=32) :: foo_name = ""
    
    ! Variables for 'bar' subcommand
    integer :: bar_level = 0
    
    num_args = command_argument_count()
    
    if (num_args < 1) then
        write(error_unit, *) "expected 'foo' or 'bar' subcommands"
        stop 1
    end if
    
    call get_command_argument(1, arg)
    
    select case (arg)
    case ("foo")
        call parse_foo_args()
        print *, "subcommand 'foo'"
        print *, "  enable:", foo_enable
        print *, "  name:", trim(foo_name)
        call print_remaining_args(3)
    case ("bar")
        call parse_bar_args()
        print *, "subcommand 'bar'"
        print *, "  level:", bar_level
        call print_remaining_args(3)
    case default
        write(error_unit, *) "expected 'foo' or 'bar' subcommands"
        stop 1
    end select
    
contains

    subroutine parse_foo_args()
        integer :: i
        character(len=32) :: arg_value
        
        do i = 2, num_args
            call get_command_argument(i, arg)
            if (arg == "--enable") then
                foo_enable = .true.
            else if (arg(1:7) == "--name=") then
                foo_name = arg(8:)
            end if
        end do
    end subroutine parse_foo_args
    
    subroutine parse_bar_args()
        integer :: i
        character(len=32) :: arg_value
        
        do i = 2, num_args
            call get_command_argument(i, arg)
            if (arg(1:8) == "--level=") then
                read(arg(9:), *) bar_level
            end if
        end do
    end subroutine parse_bar_args
    
    subroutine print_remaining_args(start_index)
        integer, intent(in) :: start_index
        integer :: i
        
        print *, "  tail:"
        do i = start_index, num_args
            call get_command_argument(i, arg)
            print *, "    ", trim(arg)
        end do
    end subroutine print_remaining_args

end program main

To compile and run the program:

$ gfortran -o command_line_subcommands command_line_subcommands.f90

First, invoke the foo subcommand:

$ ./command_line_subcommands foo --enable --name=joe a1 a2
subcommand 'foo'
  enable: T
  name: joe
  tail:
    a1
    a2

Now try bar:

$ ./command_line_subcommands bar --level=8 a1
subcommand 'bar'
  level: 8
  tail:
    a1

But bar won’t accept foo’s flags:

$ ./command_line_subcommands bar --enable a1
subcommand 'bar'
  level: 0
  tail:
    --enable
    a1

Note that Fortran doesn’t have built-in flag parsing like Go’s flag package. This example implements a simple custom parsing logic. For more complex command-line argument parsing in Fortran, you might want to use external libraries or implement a more robust parsing system.

Next, we’ll look at environment variables, another common way to parameterize programs.