3
votes

I want to wrap the fortran write-statement in a custom subroutine or function which includes some additional debug-logic.

But I'm currently stuck with defining the prototype of the function/subroutine. Is this possible? If yes, how?

3
are you trying to modify the behavior of the write statement without modifying the write statement syntax by wrapping it in your own function call? Short answer you cant do that. Maybe some preprocessor tricks will get you there but i think it would be a mess.agentp
Ah, that sounds not good. I simply wanted to put a short-circuit in front of the write (if (flag .neqv. .true.) then return end if) to globally control if output happens or not. Beside that, the function should simply delegate to write.Joachim Rosskopf

3 Answers

3
votes

The title of your question exhibits a misunderstanding, though the text suggests you know better. Nevertheless, for the record, write is a Fortran statement, it is neither a subroutine nor a function.

I think you have a number of options. One, which I have used occasionally, would be to write a function which returns a string. Perhaps

function error_message(error)
    character(len=*), intent(in) :: error
    character(len=:), allocatable :: error_message
    error_message = 'ERROR: '//trim(error)
end function error_message

which you can then use like this

write(*,*) error_message('Oh s**t')

You could certainly write a subroutine or a function with side effects which include writing to an ouput channel, but if you adopt this approach you have to be careful to observe the rules for recursive i/o.

EDIT

after OP's comment.

If you want to switch off debug messages another option you have is to direct them to a null device or file, eg /dev/null on Linux or NUL on Windows. Something like

integer, parameter :: debug_channel = 99
logical, parameter :: debugging = .false.
...
if (debugging) then
   open(debug_channel, file='NUL')
else
   open(debug_channel, file='debuglog'
end if

and then

write(debug_channel,*) 'message'
2
votes

a relatively simple way to accomplish most of what you want is to simply put the if inline in front of every write that is subject to debug control:

    if(debug)write(..,..).. 

where debug is a global logical value, or even:

    if(debugf(level))write(..,..).. 

where the logical function debugf determines whether to write based on some argument.

1
votes

In addition to the other answers, you may be able to avoid using if (debug) write... with derived type IO.

I say "may", as it is quite silly unless you already have a suitable structure, and compiler support is currently rare.

However, as an example, compiled with ifort 14.0.1:

module errormod

  type error_t
     character(len=:), allocatable :: message
   contains
     procedure write_error
     generic :: write(formatted) => write_error
  end type error_t

  logical debug_verbose

contains

  subroutine write_error(err, unit, iotype, v_list, iostat, iomsg)
    class(error_t), intent(in)  :: err
    integer, intent(in)  :: unit
    character(len=*), intent(in)  :: iotype
    integer, intent(in), dimension(:)  :: v_list
    integer, intent(out)  :: iostat
    character(len=*), intent(inout)  :: iomsg

    if (debug_verbose) then
       write(unit, '("Error: ", A)', iostat=iostat, iomsg=iomsg) err%message
    else
       write(unit, '()', advance='no')
    end if

  end subroutine write_error

end module errormod


program test

  use errormod

  implicit none

  type(error_t) error

  debug_verbose = .TRUE.
  error%message = "This error will be reported."
  write(*, '(dt)') error

  debug_verbose = .FALSE.
  error%message = "This error will not be reported."
  write(*, '(dt)') error

  debug_verbose = .TRUE.
  error%message = "This final error will also be reported."
  write(*, '(dt)') error

end program test

The first and third messages will appear, but not the second.