!> Author: Jabir Ali Ouassou !> Category: System !> !> This file renames the ISO input/output units to the standard UNIX names, !> defines the ANSI escape codes for colored output, and defines a number of !> auxiliary subroutines for e.g. writing out error and warning messages. module stdio_m use, intrinsic :: iso_fortran_env public ! Declare standard input/output units integer :: stdin = input_unit integer :: stdout = output_unit integer :: stderr = error_unit ! Define escape codes for terminal colors character(*), parameter :: color_none = '[00m' character(*), parameter :: color_red = '[31m' character(*), parameter :: color_green = '[32m' character(*), parameter :: color_yellow = '[33m' character(*), parameter :: color_blue = '[34m' character(*), parameter :: color_purple = '[35m' character(*), parameter :: color_cyan = '[36m' character(*), parameter :: color_white = '[37m' ! Declare public interfaces interface dump !! Public interface for functions that dump results to files module procedure dump_arrays, dump_scalar end interface contains impure subroutine message(msg) !! This subroutine provides a way to report a status message. character(*), intent(in) :: msg write(stderr,'(a)') color_green // ' >> INFO: ' // color_none // msg flush(stderr) end subroutine impure subroutine warning(msg) !! This subroutine provides a way to report a warning message. character(*), intent(in) :: msg write(stderr,'(a)') color_yellow // ' >> WARNING: ' // color_none // msg flush(stderr) end subroutine impure subroutine error(msg) !! This subroutine provides a way to report an error message and halt the program. character(*), intent(in) :: msg write(stderr,'(a)') color_red // ' >> ERROR: ' // color_none // msg flush(stderr) stop end subroutine impure subroutine status_head(title) !! This subroutine is used to write boxed status messages to standard out; !! in particular, this routine writes out a boxed title with a timestamp. character(len=*), intent(in) :: title character(len=33) :: title_ real :: time integer :: hh, mm, ss ! Calculate the current time call cpu_time(time) hh = int(time/3600.0) mm = int(mod(time,3600.0)/60.0) ss = int(mod(time,60.0)) ! adjust the provided title title_ = '' title_((len(title_)-len(title)+1)/2:) = title ! Write out the boxed header write(stdout,*) write(stdout,'(a)') & '╒═══════════════════════════════════╕' write(stdout,'(a)') & '│ ' // title_ // ' │' write(stdout,'(a)') & '├───────────────────────────────────┤' write(stdout,'(a,3x,a,7x,i3.2,a,i2.2,a,i2.2,3x,a)') & '│', 'Elapsed time:', hh, ':', mm, ':', ss, '│' end subroutine impure subroutine status_body(title, value) !! This subroutine is used to write boxed status messages to standard out; !! in particular, this routine writes out the name and value of a variable. character(len=*), intent(in) :: title character(len=20) :: title_ class(*), intent(in) :: value ! Adjust the provided title title_ = trim(title) // ':' ! Print out the title and value select type(value) type is (integer) write(stdout,'(a,3x,a,i10 ,2x,a)') '│', title_, value, '│' type is (real) write(stdout,'(a,3x,a,f10.8,2x,a)') '│', title_, value, '│' type is (double precision) write(stdout,'(a,3x,a,f10.8,2x,a)') '│', title_, value, '│' end select end subroutine impure subroutine status_foot() !! This subroutine is used to write boxed status messages to standard out; !! in particular, this routine writes out the bottom edge of such a box. ! Write out the boxed footer write(stdout,'(a)') & '╘═══════════════════════════════════╛' ! Flush the information to standard out flush(unit=stdout) end subroutine impure subroutine status_box(title) !! This subroutine is used to write boxed status messages to standard out. character(len=*), intent(in) :: title character(len=33) :: title_ ! adjust the provided title title_ = '' title_((len(title_)-len(title)+1)/2:) = title ! Write out the boxed message write(stdout,*) write(stdout,'(a)') & '╒═══════════════════════════════════╕' write(stdout,'(a)') & '│ ' // title_ // ' │' write(stdout,'(a)') & '╘═══════════════════════════════════╛' end subroutine impure function input(file) result(unit) !! This function is used to open an input file for reading. character(len=*), intent(in) :: file integer :: iostat integer :: unit ! Open the output file open(newunit = unit, file = file, iostat = iostat, action = 'read', status = 'old') if (iostat /= 0) then call error('Failed to open input file "' // file // '"!') end if end function impure function output(file) result(unit) !! This function is used to open an output file for writing. character(len=*), intent(in) :: file integer :: iostat integer :: unit ! Open the output file open(newunit = unit, file = file, iostat = iostat, action = 'write', status = 'replace') if (iostat /= 0) then call error('Failed to open output file "' // file // '"!') end if end function impure subroutine dump_arrays(filename, arrays, header) !! This subroutine is used to dump numerical arrays to an output file. use :: iso_fortran_env character(len=*), intent(in) :: filename real(real64), dimension(:), intent(in) :: arrays character(len=*), dimension(:), intent(in) :: header real(real64), dimension(size(arrays)/size(header),size(header)) :: matrix integer :: unit integer :: n ! Reshape the data matrix = reshape(arrays, shape(matrix)) ! Open the output file unit = output(filename) ! Write the header line write(unit,'(*(a20,:," "))') '# ' // header(1), header(2:) ! Loop over the matrix rows do n=1,size(matrix,1) ! Write the matrix column to file write(unit,'(*(es20.12e3,:," "))') matrix(n,:) end do ! Close the output file close(unit = unit) end subroutine impure subroutine dump_scalar(filename, scalar) !! This subroutine is used to dump a numerical result to an output file. use :: iso_fortran_env character(len=*), intent(in) :: filename real(real64), intent(in) :: scalar character(len=2048) :: str integer :: unit integer :: n ! Open the output file unit = output(filename) ! Write out command-line arguments do n=1,command_argument_count() call get_command_argument(n, str) write(unit,'(a," ")',advance='no') trim(str) end do ! Write the scalar value to file write(unit,'(*(es20.12e3,:," "))') scalar ! Close the output file close(unit = unit) end subroutine end module