IOFILE.f90 Source File


Files dependent on this one

sourcefile~~iofile.f90~~AfferentGraph sourcefile~iofile.f90 IOFILE.f90 sourcefile~ioplot.f90 IOPLOT.f90 sourcefile~ioplot.f90->sourcefile~iofile.f90 sourcefile~ioread.f90 IOREAD.f90 sourcefile~ioread.f90->sourcefile~iofile.f90 sourcefile~sf_iotools.f90 SF_IOTOOLS.f90 sourcefile~sf_iotools.f90->sourcefile~iofile.f90 sourcefile~sf_iotools.f90->sourcefile~ioplot.f90 sourcefile~sf_iotools.f90->sourcefile~ioread.f90 sourcefile~scifor.f90 SCIFOR.f90 sourcefile~scifor.f90->sourcefile~sf_iotools.f90 sourcefile~sf_stat.f90 SF_STAT.f90 sourcefile~scifor.f90->sourcefile~sf_stat.f90 sourcefile~sf_stat.f90->sourcefile~sf_iotools.f90

Source Code

module IOFILE
  implicit none
  private

  !file size to be stored automagically (in Kb)
  integer,save :: store_size=2048

  interface str
     module procedure str_i_to_ch
     module procedure str_i_to_ch_pad
     module procedure str_r_to_ch
     module procedure str_c_to_ch
     module procedure str_l_to_ch
     module procedure str_ch_to_ch
  end interface str

  interface txtfy
     module procedure str_i_to_ch
     module procedure str_i_to_ch_pad
     module procedure str_r_to_ch
     module procedure str_c_to_ch
     module procedure str_l_to_ch
     module procedure str_ch_to_ch
  end interface txtfy

  interface reg
     module procedure reg_filename
  end interface reg

  interface create_dir
     module procedure create_data_dir
  end interface create_dir

  interface newunit
     module procedure free_unit
  end interface newunit

  interface print_matrix
     module procedure print_array_d
     module procedure print_array_c
  end interface print_matrix


  public :: set_store_size
  !
  public :: str
  public :: txtfy !obsolete
  public :: reg
  public :: to_lower
  public :: to_upper
  !
  public :: file_size
  public :: file_length
  public :: file_info
  public :: file_gzip           !data_store
  public :: file_gunzip         !data_open
  public :: file_targz
  public :: file_untargz
  !
  public :: newunit
  public :: free_unit
  public :: free_units
  !
  public :: create_dir
  !
  public :: get_filename
  public :: get_filepath
  !
  public :: print_matrix

contains




  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  function reg_filename(file) result(reg)
    character(len=*)                                   :: file    
    character(len=len_trim(trim(adjustl(trim(file))))) :: reg
    reg=trim(adjustl(trim(file)))
  end function reg_filename

  function get_filename(string) result(fname)
    character(len=*) :: string
    ! character(len=len_trim(string)) :: fname
    character(len=:),allocatable :: fname
    integer :: i,slen
    slen=len_trim(string)
    do i=slen,1,-1
       if(string(i:i)== '/')exit
    enddo
    fname=trim(adjustl(trim(string(i+1:slen))))
  end function get_filename

  function get_filepath(string) result(pname)
    character(len=*) :: string
    ! character(len=len_trim(string)) :: pname
    character(len=:),allocatable :: pname
    integer :: i,slen
    slen=len_trim(string)
    do i=slen,1,-1
       if(string(i:i)== '/')exit
    enddo
    pname=trim(adjustl(trim(string(1:i))))
  end function get_filepath


  function free_unit(n) result(unit_)
    integer,optional :: n
    integer          :: unit_,ios
    logical          :: opened
    unit_=100
    do 
       unit_=unit_+1
       INQUIRE(unit=unit_,OPENED=opened,iostat=ios)
       if(.not.opened.AND.ios==0)exit 
       if(unit_>900) stop "ERROR free_unit: no unit free smaller than 900. Possible BUG"
    enddo
    if(present(n))n=unit_
  end function free_unit

  function free_units(n) result(unit)
    integer :: n
    integer :: unit(n)
    integer :: i,unit_,ios
    logical :: is_it_opened
    unit_=100
    do i=1,n
       search: do 
          unit_=unit_+1
          inquire(unit=unit_,OPENED=is_it_opened,iostat=ios)
          if(.not.is_it_opened.AND.ios==0)exit search
          if(unit_>900) stop "ERROR free_unit: no unit free smaller than 900. Possible BUG"
       enddo search
       unit(i)=unit_
    enddo
  end function free_units




  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  function file_size(file,printf) result(size)
    integer               :: size,status
    character(len=*)      :: file
    integer,dimension(13) :: buff
    logical,optional      :: printf
    logical               :: control,printf_
    printf_=.false.;if(present(printf))printf_=printf
    inquire(file=reg(file),exist=control)
    if(.not.control)then
       write(*,*) 'Cannot read '//reg(file)//'. Skip file_size'
       return
    endif
    open(10,file=reg(file))
    call fstat(10,buff,status)
    size=nint(dble(buff(8))/dble(1024))
    if(printf_)write(*,"(A,A,A,f9.6,A)")"file: **",reg(file),"** is ",size," Kb"
  end function file_size



  !******************************************************************
  !******************************************************************
  !******************************************************************



  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  function file_info(file)
    integer               :: file_info
    character(len=*)      :: file
    integer,dimension(13) :: buff
    integer               :: status,ifile
    logical               :: IOfile
    inquire(file=reg(file),exist=IOfile)
    if(.not.IOfile)then
       print*,'Cannot read ',reg(file),': skip file_size'
       file_info=0
       return
    endif
    open(10,file=reg(file))
    call fstat(10,buff,status)
    if(status == 0)then
       WRITE (*, FMT="('Device ID:',               T30, I19)") buff(1)
       WRITE (*, FMT="('Inode number:',            T30, I19)") buff(2)
       WRITE (*, FMT="('File mode (octal):',       T30, O19)") buff(3)
       WRITE (*, FMT="('Number of links:',         T30, I19)") buff(4)
       WRITE (*, FMT="('Owner''s uid:',            T30, I19)") buff(5)
       WRITE (*, FMT="('Owner''s gid:',            T30, I19)") buff(6)
       WRITE (*, FMT="('Device where located:',    T30, I19)") buff(7)
       WRITE (*, FMT="('File size:',               T30, I19)") buff(8)
       WRITE (*, FMT="('Last access time:',        T30, A19)") buff(9)
       WRITE (*, FMT="('Last modification time',   T30, A19)") buff(10)
       WRITE (*, FMT="('Last status change time:', T30, A19)") buff(11)
       WRITE (*, FMT="('Preferred block size:',    T30, I19)") buff(12)
       WRITE (*, FMT="('No. of blocks allocated:', T30, I19)") buff(13)
    endif
    close(10)
  end function file_info



  !******************************************************************
  !******************************************************************
  !******************************************************************



  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  function file_length(file) result(lines)
    integer           :: lines
    character(len=*)  :: file
    integer           :: ifile,ierr,pos
    logical           :: IOfile,bool,bool1,bool2
    character(len=256)::buffer
    inquire(file=reg(file),exist=IOfile)
    if(.not.IOfile)then
       inquire(file=reg(file)//".gz",exist=IOfile)
       if(IOfile)call file_gunzip(reg(file))
    endif
    lines=0
    if(.not.IOfile)then
       write(*,*) 'Cannot read +'//reg(file)//'. Skip file_size'
       return
    endif
    open(99,file=reg(file))
    ierr=0
    do while(ierr==0)
       lines=lines+1
       read(99,*,iostat=ierr)buffer
       bool1=scan(buffer,"#").ne.0
       bool2=len_trim(buffer).eq.0       
       if(bool1 .OR. bool2)lines=lines-1
    enddo
    lines=lines-1
    write(*,'(A,I9,A)') 'there are', lines,' lines in +'//reg(file)
    rewind(99)
    close(99)
  end function file_length



  !******************************************************************
  !******************************************************************
  !******************************************************************







  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  subroutine set_store_size(size)
    integer :: size
    store_size=size
    write(*,"(A)")"store size ="//trim(txtfy(size))//"Kb"
  end subroutine set_store_size




  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  subroutine file_gzip(file,size)
    character(len=*)  :: file
    integer,optional  :: size
    logical           :: control
    character(len=9)  :: csize 
    integer           :: cstatus,fsize,unit,len
    fsize=store_size;if(present(size))fsize=size
    write(*,"(A)") "Storing "//file
    inquire(file=reg(file),exist=control)
    if(control)then
       len=file_size(reg(file))
       if(len>fsize)call system("gzip -fv "//reg(file))
    endif
    inquire(file=reg(file),opened=control,number=unit)
    if(control)close(unit)
  end subroutine file_gzip





  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  subroutine file_gunzip(filename)
    character(len=*)             :: filename
    character(len=3),parameter   :: type='.gz'
    logical                      :: iexist,iopen
    integer                      :: unit
    !
    inquire(file=reg(filename),exist=iexist)
    if(iexist)return           !nothing to be done:
    !
    inquire(file=reg(filename)//type,exist=iexist)
    if(.not.iexist)then
       write(*,"(A)")"file "//reg(filename)//" not found, not even with .gz extension"
       stop
    endif
    write(*,"(A)")"deflate "//reg(filename)//type
    call system("gunzip "//reg(filename)//type)
    inquire(file=reg(filename),opened=iopen,number=unit)
    if(iopen)close(unit)
  end subroutine file_gunzip




  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  subroutine file_targz(tarball,pattern,size)
    character(len=*)           :: tarball
    character(len=*)           :: pattern
    integer,optional           :: size
    character(len=4),parameter :: type='.tgz'
    integer                    :: control,fsize
    character(len=100)         :: cmsg
    fsize=store_size;if(present(size))fsize=size
    write(*,"(A)") "Store "//str(pattern)//" in "//str(tarball)//type
    call execute_command_line("tar -czf "//str(tarball)//type//" "//str(pattern),CMDSTAT=control,CMDMSG=cmsg)
    if(control>0)then
       write(*,"(A)")"Command tar -czf failed with error: "//str(cmsg)
    elseif(control<0)then
       write(*,"(A)")"Command tar -czf not supported"
    else
       call execute_command_line("rm -f "//str(pattern))
    endif
  end subroutine file_targz


  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  subroutine file_untargz(tarball)
    character(len=*)           :: tarball
    integer                    :: control
    logical                    :: iexist,iopen
    integer                    :: unit
    character(len=4),parameter :: type='.tgz'
    character(len=100)         :: cmsg
    inquire(file=reg(tarball)//type,exist=iexist)
    if(.not.iexist)then
       write(*,"(A)")"Tarball "//str(tarball)//type//" not present: skip"
       return           !nothing to be done:
    endif
    write(*,"(A)")"deflate "//reg(tarball)//type
    call execute_command_line("tar -xzf "//str(tarball)//type//" ",CMDSTAT=control,CMDMSG=cmsg)
    if(control>0)then
       write(*,"(A)")"Command tar -xzf failed with error: "//str(cmsg)
    elseif(control<0)then
       write(*,"(A)")"Command tar -xzf not supported"
    else
       call execute_command_line("rm -f "//str(tarball)//type)
    endif

  end subroutine file_untargz






  !******************************************************************
  !******************************************************************
  !******************************************************************




  !+-----------------------------------------------------------------+
  !PURPOSE  : 
  !+-----------------------------------------------------------------+
  subroutine create_data_dir(dir_name)
    character(len=*) :: dir_name
    logical          :: control
    call system("mkdir -v "//reg(dir_name))
  end subroutine create_data_dir


  !******************************************************************
  !******************************************************************
  !******************************************************************



  function to_upper(StrIn) result(StrOut)
    character(len=*), intent(in) :: strIn
    character(len=len(strIn))    :: strOut
    integer :: i
    do i = 1,len(StrIn)
       select case(StrIn(i:i))
       case("a":"z")
          StrOut(i:i) = achar(iachar(StrIn(i:i))-32)
       case default
          StrOut(i:i) = StrIn(i:i)
       end select
    end do
  end function to_upper

  function to_lower(StrIn) result(StrOut)
    character(len=*), intent(in) :: strIn
    character(len=len(strIn))    :: strOut
    integer :: i
    do i = 1,len(StrIn)
       select case(StrIn(i:i))
       case("A":"Z")
          StrOut(i:i) = achar(iachar(StrIn(i:i))+32)
       case default
          StrOut(i:i) = StrIn(i:i)
       end select
    end do
  end function to_lower




  ! function i_to_ch(i4) result(string)
  !   character(len=32) :: string
  !   integer           :: i4
  !   call i4_to_s_left(i4,string)
  ! end function i_to_ch
  ! function i_to_ch_pad(i4,Npad) result(string)
  !   integer             :: Npad
  !   character(len=Npad) :: string
  !   integer             :: i4
  !   call i4_to_s_zero(i4,string)
  ! end function i_to_ch_pad
  ! function r_to_ch(r8) result(string)
  !   character(len=32) :: string
  !   character(len=16) :: string_
  !   real(8)           :: r8
  !   call r8_to_s_left(r8,string_)
  !   string=adjustl(string_)
  ! end function r_to_ch
  ! function c_to_ch(c) result(string)
  !   character(len=32+3) :: string
  !   character(len=16) :: sre,sim
  !   complex(8)        :: c
  !   real(8)           :: re,im
  !   re=real(c,8);im=aimag(c)
  !   call r8_to_s_left(re,sre)
  !   call r8_to_s_left(im,sim)
  !   string="("//trim(sre)//","//trim(sim)//")"
  ! end function c_to_ch
  ! function l_to_ch(bool) result(string)
  !   logical :: bool
  !   character(len=1) :: string
  !   string='F'
  !   if(bool)string='T'
  ! end function l_to_ch
  ! function ch_to_ch(txt) result(string)
  !   character(len=*)              :: txt
  !   character(len=len(trim(txt))) :: string
  !   string=trim(txt)
  ! end function ch_to_ch



  function str_i_to_ch(i4) result(string)
    integer                      :: i4
    character(len=:),allocatable :: string
    character(len=16)            :: string_
    call i4_to_s_left(i4,string_)
    string=trim(adjustl(trim(string_)))
  end function str_i_to_ch

  function str_i_to_ch_pad(i4,Npad) result(string)
    integer                      :: i4
    integer                      :: Npad
    character(len=:),allocatable :: string
    character(len=Npad)          :: string_pad
    call i4_to_s_zero(i4,string_pad)
    string=trim(adjustl(trim(string_pad)))
  end function str_i_to_ch_pad

  function str_r_to_ch(r8,d,lead) result(string)
    real(8)                      :: r8
    integer,optional             :: d,lead
    integer                      :: w_,d_,lead_
    character(len=:),allocatable :: string
    character(len=:),allocatable :: string_
    d_    =6 ;if(present(d))d_=d
    lead_ =1 ;if(present(lead))lead_=lead
    w_ = get_w_(r8,d_,lead_)
    allocate(character(len=w_) :: string_)
    call r8_to_s_left(r8,string_,d_,lead_)
    string=trim(adjustl(trim(string_)))
  end function str_r_to_ch


  function str_c_to_ch(c,d,lead) result(string)
    complex(8)                   :: c
    integer,optional             :: d,lead
    integer                      :: w_,d_,lead_
    character(len=:),allocatable :: string
    character(len=:),allocatable :: sre,sim
    real(8)                      :: re,im
    d_    =6 ;if(present(d))d_=d
    lead_ =1 ;if(present(lead))lead_=lead
    re=dreal(c)
    w_ = get_w_(re,d_,lead_)
    allocate(character(len=w_) :: sre)
    call r8_to_s_left(re,sre,d_,lead_)
    !
    im=dimag(c)
    w_ = get_w_(im,d_,lead_)
    allocate(character(len=w_) :: sim)
    call r8_to_s_left(im,sim,d_,lead_)
    string="("//trim(adjustl(trim(sre)))//","//trim(adjustl(trim(sim)))//")"
  end function str_c_to_ch


  function str_l_to_ch(bool) result(string)
    logical          :: bool
    character(len=1) :: string
    string='F'
    if(bool)string='T'
  end function str_l_to_ch

  function str_ch_to_ch(txt) result(string)
    character(len=*)                             :: txt
    character(len=:),allocatable :: string
    string=trim(adjustl(trim(txt)))
  end function str_ch_to_ch


  function get_w_(r8,d,lead) result(w)
    real(8) :: r8
    integer :: d,lead
    integer :: w
    if(r8==0d0)then
       w=d+4
    else
       w=floor(log10(abs(r8)))
       if(w < -lead)then
          w = d + 4 + 4
       else
          w = abs(w) + d + 4 + lead
       endif
    endif
  end function get_w_




  !******************************************************************
  !******************************************************************
  !******************************************************************

  subroutine i4_to_s_left ( i4, s )
    !! I4_TO_S_LEFT converts an I4 to a left-justified string.
    !  Example:
    !    Assume that S is 6 characters long:
    !        I4  S
    !         1  1
    !        -1  -1
    !         0  0
    !      1952  1952
    !    123456  123456
    !   1234567  ******  <-- Not enough room!
    !  Parameters:
    !    Input, integer ( kind = 4 ) I4, an integer to be converted.
    !    Output, character ( len = * ) S, the representation of the integer.
    !    The integer will be left-justified.  If there is not enough space,
    !    the string will be filled with stars.
    character :: c
    integer   :: i
    integer   :: i4
    integer   :: idig
    integer   :: ihi
    integer   :: ilo
    integer   :: ipos
    integer   :: ival
    character(len=*) ::  s
    s = ' '
    ilo = 1
    ihi = len ( s )
    if ( ihi <= 0 ) then
       return
    end if
    !  Make a copy of the integer.
    ival = i4
    !  Handle the negative sign.
    if ( ival < 0 ) then
       if ( ihi <= 1 ) then
          s(1:1) = '*'
          return
       end if
       ival = -ival
       s(1:1) = '-'
       ilo = 2
    end if
    !  The absolute value of the integer goes into S(ILO:IHI).
    ipos = ihi
    !  Find the last digit of IVAL, strip it off, and stick it into the string.
    do
       idig = mod ( ival, 10 )
       ival = ival / 10
       if ( ipos < ilo ) then
          do i = 1, ihi
             s(i:i) = '*'
          end do
          return
       end if
       call digit_to_ch ( idig, c )
       s(ipos:ipos) = c
       ipos = ipos - 1
       if ( ival == 0 ) then
          exit
       end if
    end do
    !  Shift the string to the left.
    s(ilo:ilo+ihi-ipos-1) = s(ipos+1:ihi)
    s(ilo+ihi-ipos:ihi) = ' '
  end subroutine i4_to_s_left


  subroutine r8_to_s_left( r8, s, digits, lead)
    !! R8_TO_S_LEFT writes an R8 into a left justified string.
    !    An R8 is a real ( kind = 8 ) value.
    !    A 'F<len(s)>.DIGITS' format is used with a WRITE statement.
    character(len=12)   :: fmt
    integer             :: i
    real(8)             :: r8
    character(len=*)    :: s
    integer             :: s_length,w_
    integer             :: digits,lead
    s_length = len ( s )
    write(fmt,"(A2,I0,A1,I0,A1)")"(F",s_length,".",digits,")"
    if(r8/=0d0)then
       w_=floor(log10(abs(r8)))
       if(w_<-lead)then
          write(fmt,"(A3,I0,A1,I0,A1)")"(ES",s_length,".",digits,")"
       else
          write(fmt,"(A2,I0,A1,I0,A1)")"(F",s_length,".",digits+lead,")"
       endif
    endif
    write ( s, fmt ) r8
    s = trim(adjustl(trim( s )))
  end subroutine r8_to_s_left


  subroutine digit_to_ch(digit,ch)
    !! DIGIT_TO_CH returns the character representation of a decimal digit.
    !    Instead of CHAR, we now use the ACHAR function, which
    !    guarantees the ASCII collating sequence.
    !  Example:
    !    DIGIT   CH
    !    -----  ---
    !      0    '0'
    !      1    '1'
    !    ...    ...
    !      9    '9'
    !     17    '*'
    !  Parameters:
    !    Input, integer ( kind = 4 ) DIGIT, the digit value between 0 and 9.
    !    Output, character CH, the corresponding character.
    character :: ch
    integer   :: digit
    if ( 0 <= digit .and. digit <= 9 ) then
       ch = achar ( digit + 48 )
    else
       ch = '*'
    end if
  end subroutine digit_to_ch


  subroutine i4_to_s_zero ( intval, s )
    !! I4_TO_S_ZERO converts an I4 to a string, with zero padding.
    !    An I4 is an integer ( kind = 4 ).
    !  Example:
    !    Assume that S is 6 characters long:
    !    INTVAL  S
    !         1  000001
    !        -1  -00001
    !         0  000000
    !      1952  001952
    !    123456  123456
    !   1234567  ******  <-- Not enough room!
    !  Parameters:
    !    Input, integer ( kind = 4 ) INTVAL, an integer to be converted.
    !    Output, character ( len = * ) S, the representation of the integer.
    !    The integer will be right justified, and zero padded.
    !    If there is not enough space, the string will be filled with stars.
    implicit none
    character c
    integer ( kind = 4 ) i
    integer ( kind = 4 ) idig
    integer ( kind = 4 ) ihi
    integer ( kind = 4 ) ilo
    integer ( kind = 4 ) intval
    integer ( kind = 4 ) ipos
    integer ( kind = 4 ) ival
    character ( len = * ) s
    s = ' '
    ilo = 1
    ihi = len ( s )
    if ( ihi <= 0 ) then
       return
    end if
    !
    !  Make a copy of the integer.
    !
    ival = intval
    !
    !  Handle the negative sign.
    !
    if ( ival < 0 ) then
       if ( ihi <= 1 ) then
          s(1:1) = '*'
          return
       end if
       ival = -ival
       s(1:1) = '-'
       ilo = 2
    end if
    !
    !  Working from right to left, strip off the digits of the integer
    !  and place them into S(ILO:IHI).
    !
    ipos = ihi
    do while ( ival /= 0 .or. ipos == ihi )
       idig = mod ( ival, 10 )
       ival = ival / 10
       if ( ipos < ilo ) then
          do i = 1, ihi
             s(i:i) = '*'
          end do
          return
       end if
       call digit_to_ch ( idig, c )
       s(ipos:ipos) = c
       ipos = ipos - 1
    end do
    !
    !  Fill the empties with zeroes.
    !
    do i = ilo, ipos
       s(i:i) = '0'
    end do
    return
  end subroutine i4_to_s_zero






  subroutine print_array_d(M,file,w,d)
    real(8),dimension(:,:)    :: M
    character(len=*),optional :: file
    integer,optional          :: w,d
    integer                   :: w_,d_
    integer                   :: i,j
    integer                   :: unit
    character(len=128)        :: fmt
    unit=6
    if(present(file))open(free_unit(unit),file=reg(file))
    w_=5;if(present(w))w_=w
    d_=2;if(present(d))d_=d
    write(fmt,"(A1,I0,A2,I0,A1,I0,A5)")"(",size(M,2),"(F",w_,".",d_,",1x))"
    do i=1,size(M,1)
       write(unit,fmt)(M(i,j),j=1,size(M,2))
    enddo
  end subroutine print_array_d

  subroutine print_array_c(M,file,w,d)
    complex(8),dimension(:,:) :: M
    character(len=*),optional :: file
    integer,optional          :: w,d
    integer                   :: w_,d_
    integer                   :: i,j
    integer                   :: unit
    character(len=128)        :: fmt
    unit=6
    if(present(file))open(free_unit(unit),file=reg(file))
    w_=5;if(present(w))w_=w
    d_=2;if(present(d))d_=d
    write(fmt,"(A1,I0,A5,I0,A1,I0,A5,I0,A1,I0,A7)")"(",size(M,2),"(A1,F",w_,".",d_,",A1,F",w_,".",d_,"A1,1x))"
    do i=1,size(M,1)
       write(unit,fmt)("(",dreal(M(i,j)),",",dimag(M(i,j)),")",j=1,size(M,2))
    enddo
  end subroutine print_array_c


end module IOFILE