# Ideas for command module

**URL:** <https://fortran-lang.discourse.group/t/ideas-for-command-module/439>\
**Category:** Uncategorized\
**Created:** [November 22, 2020, 8:39pm UTC](https://fortran-lang.discourse.group/t/ideas-for-command-module/439 "2020-11-22T20:39:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [November 22, 2020, 8:39pm UTC](https://fortran-lang.discourse.group/t/ideas-for-command-module/439/1 "2020-11-22T20:39:56Z")

</div>

I am working on implementing a module similar to [std::process](https://doc.rust-lang.org/std/process/index.html) in Rust. This module would contain tools to spawn and interact with child processes.

Here is what I have so far:

```auto
module process_module

  use iso_varying_string ! See https://gitlab.com/everythingfunctional/iso_varying_string

  use, intrinsic :: iso_fortran_env, only: output_unit, input_unit, error_unit
  implicit none

  type :: command
    type(varying_string) :: program
    type(varying_string), allocatable :: args(:)
    integer :: stderr_ = error_unit
    integer :: stdin_ = input_unit
    integer :: stdout_ = output_unit
  contains
    procedure :: new
    procedure :: arg => set_arg
    procedure :: stdin
    procedure :: stderr
    procedure :: stdout
    procedure :: get_program
    procedure :: get_args
    procedure :: status
  end type

contains

  subroutine new(self,prog)
    class(command), intent(out) :: self
    character(len=*), intent(in) :: prog
    if (allocated(self%args)) deallocate(self%args)
    self%program = trim(prog)
  end subroutine

  function get_program(self) result(p)
    class(command), intent(in) :: self
    type(varying_string) :: p
    p = self%program
  end function

  function get_args(self) result(args)
    class(command), intent(in) :: self
    type(varying_string), allocatable :: args(:)
    allocate(args,source=self%args)
  end function

  subroutine set_arg(self,arg)
    class(command), intent(inout) :: self
    character(len=*), intent(in) :: arg

    type(varying_string) :: vs

    vs = arg
    if (allocated(self%args)) then
      self%args = [self%args, vs]
    else
      allocate(self%args(1))
      self%args(1) = arg
    end if
  end subroutine

  subroutine stdin(self,unit)
    class(command), intent(inout) :: self
    integer, intent(in) :: unit
    self%stdin_ = unit
  end subroutine

  subroutine stderr(self,unit)
    class(command), intent(inout) :: self
    integer, intent(in) :: unit
    self%stderr_ = unit
  end subroutine

    subroutine stdout(self,unit)
    class(command), intent(inout) :: self
    integer, intent(in) :: unit
    self%stdout_ = unit
  end subroutine

  subroutine status(self,success,code)
    class(command), intent(inout) :: self
    logical, intent(out), optional :: success
    integer, intent(out), optional :: code

    integer :: exitstat, cmdstat
    character(len=1000) :: cmdmsg

    character(len=1000) :: command
    integer :: i

    cmdmsg = ""

    command = self%program
    if (allocated(self%args)) then
      do i = 1, size(self%args)
        command = trim(command)//" "//trim(self%args(i))
      end do
    end if

    call execute_command_line(command,wait=.true., &
      exitstat=exitstat, &
      cmdstat=cmdstat, &
      cmdmsg=cmdmsg)
    print *, trim(cmdmsg)

    if (present(success)) then
      if (cmdstat == 0) then
        success = .true.
      else
        success = .false.
      end if
    end if

    if (present(code)) code = exitstat
  end subroutine

end module

program main

  use iso_varying_string
  use process_module
  implicit none

  type(command) :: cmd
  logical :: succ
  integer :: code

  call cmd%new("gfortran")
  call cmd%arg("hello_world.f90") ! contains "print *, "Hello from child!"; end
  call cmd%arg("-o")
  call cmd%arg("hello_world")
  call cmd%status(success=succ,code=code)
  print *, succ, code

  call cmd%new("./hello_world")
  call cmd%status(success=s,code=code)
  print *, succ, code
  print *, "Hello from caller."
end program

```

The Rust API provides three ways to run a command with slightly different roles:

- `status` will run the command as a child process, wait for it to finish and collect it’s exit status;
- `output` will run the command as a child process, wait for it to finish and collect it’s exit status and output (stderr, and, stdout);
- `spawn` will run the command and return a handle to the process (the PID presumably).

Is it possible to replicate this functionality purely in Fortran?

If possible, can it be used in a parallel setting? For example if one image spawns a child process, and communicate the child id, can the second image check the status.

I would also appreciate learning any other ideas related to the functionality of such a process module.

---

<div class="post-metadata">

**Author:** ![lkedward](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/lkedward/32/72_2.png) [@lkedward](https://fortran-lang.discourse.group/u/lkedward)\
**Post date:** [November 24, 2020, 10:23am UTC](https://fortran-lang.discourse.group/t/ideas-for-command-module/439/3 "2020-11-24T10:23:58Z")

</div>

This is a nice API, certainly something I would make use of. The third command method `spawn` would be particularly useful, especially if it is able to return a handle which I can later `wait` upon and retrieve output.

Unfortunately I don’t know the specifics of how this could be implemented for single- or cross-platform, but I don’t think pure Fortran is possible - maybe with some platform-specific `c` code?

Some other process features that I’ve needed to implement when working with MATLAB:

- Modify or set environment variables before launching the process
- Reading from `stdout` and `stderr` buffers while the process is running.
- Set a process timeout
- Procedure to kill spawned process

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [November 24, 2020, 11:37am UTC](https://fortran-lang.discourse.group/t/ideas-for-command-module/439/4 "2020-11-24T11:37:48Z")

</div>

I have found part of functionality I want to replicate in some of the modules distributed with the [NAG Fortran Compiler](https://www.nag.com/content/nag-fortran-compiler-documentation).

> **[f90\_unix\_proc: UNIX Process Primitives Module](https://www.nag.com/nagware/np/r70_doc/f90_unix_proc.html)**

It is essentially an interface to POSIX. This would be a good candidate for inclusion into `stdlib` (not the NAG one, but a community developed version).

* * *

Intel Fortran comes with its own interface:

> **[POSIX\* Library Procedures](https://software.intel.com/content/www/us/en/develop/documentation/fortran-compiler-developer-guide-and-reference/top/language-reference/a-to-z-reference/language-summary-tables/posix-library-procedures.html)**
>
> Developer guide and reference for users of the 19.1 Intel® Fortran Compiler

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [November 24, 2020, 3:23pm UTC](https://fortran-lang.discourse.group/t/ideas-for-command-module/439/5 "2020-11-24T15:23:53Z")

</div>

It turns out, it was done several times already…

> <https://github.com/fortran-lang/stdlib/issues/22#issuecomment-733021530>
>
> stdlib may include a module which provides an interface to the POSIX I/O calls in the C standard library. Such a...

---

<div class="post-metadata">

**Author:** ![urbanjost](https://avatars.discourse-cdn.com/v4/letter/u/0ea827/32.png) [@urbanjost](https://fortran-lang.discourse.group/u/urbanjost)\
**Post date:** [November 24, 2020, 3:28pm UTC](https://fortran-lang.discourse.group/t/ideas-for-command-module/439/6 "2020-11-24T15:28:35Z")

</div>

A rather long post I thought I made on this topic seems to have not made it. It cannot be done with standard Fortran. Fortran does not even have a concept of a PID, for example. If you look at the M\_process, M\_system, and M\_io modules in GPF (General Purpose Fortran) there are components for interfacing via the ISO\_C\_BINDING interface to many of the most common POSIX routines on platforms that support it, and an interface to popen(3c) and family that might be useful. A similiar interface to the exec(3c) routines would be needed to implement all the features. Relatively straight-forward on a POSIX platform; but would have to be a custom solution for anything else; albeit several vendors support proprietary interfaces so the work has been done in that mostly it can be done with compiler-specific calls behind a wrapper library. See[for the M\_system, M\_io, and M\_process modules](https://github.com/urbanjost). You can get something similiar to some of the functionality by using Fortran’s many parallel packages for making a more event-driven interface with threads/processes waiting for events and so on.
