!
!---------------------------  FILOPN  ----------------------------------
!
! 1- program statistics:
!     name     : FILOPN, FILCLS, FILUNIT, FILKDI
!     use      : allocate and release file units associated to a given
!                file name. Word addressable (KDI), sequential (formatted
!                or not) and direct access (DA) files are permitted.
!                These functions are Ganlib wrappers for the KDROPN
!                and KDIOP utilities.
!     modified : 2009-06-08
!     author   : A. Hebert
!
! 2- routine parameters:
!
! - function FILOPN(cuname,iactio,iutype,lrda)
!
!   open file and allocate unit number. Allocate a unit number to file
!   name. If unit is already opened, returns its address.
!
!   input
!     cuname   : filename                                     c*(*)
!                if cuname=' ', use a default name
!     iactio   : action on file                               i
!                =0 to allocate a new file
!                =1 to access and modify an existing file
!                =2 to access an existing file in
!                   read-only mode
!                =3 unknown
!     iutype   : file type                                    i
!                =1  KDI word addressable file
!                =2  sequential unformatted
!                =3  sequential formatted
!                =4  direct access (DA) unformatted file
!     ldra     : number of words in DA a record               i
!                required for  iutype = 4 only
!   output
!     FILOPN   : address of file (successful allocation)      type(c_ptr)
!                == NULL  allocation failure
!
!---------------------------  FILOPN  ----------------------------------
!
function FILOPN(cuname,iactio,iutype,lrda)
   use, intrinsic :: iso_c_binding
   type(c_ptr) FILOPN
!----
!   subroutine arguments
!----
   character(len=*) :: cuname
   integer :: iactio,iutype,lrda
!----
!   local variables
!----
   type FIL_file
      integer :: unit
      type(c_ptr) :: kdi_file
   end type FIL_file
   type(FIL_file), pointer :: my_file
   type(c_ptr) :: my_kdi_file
   type(c_ptr),external :: KDIOP
   integer,external :: KDROPN
   integer :: ret_val
!----
!  kdi (word addressable) file open
!----
   if(iutype == 1) then
      my_kdi_file=KDIOP(crdnam,iactio)
      if(.not.c_associated(my_kdi_file)) go to 6000
      allocate(my_file)
      my_file%kdi_file=my_kdi_file
      my_file%unit=0
   else
!----
!  Fortran file open
!----
      ret_val=KDROPN(cuname,iactio,iutype,lrda)
      if(ret_val <= 0) go to 6000
      allocate(my_file)
      my_file%kdi_file=c_null_ptr
      my_file%unit=ret_val
   endif
   FILOPN=c_loc(my_file)
   return
!----
!  Error
!----
   6000 FILOPN=c_null_ptr
   return
end function FILOPN
!
!-------------------------- FILCLS -------------------------------------
!
! - function FILCLS(my_file,iactio)
!
!   close file and release unit number.
!
!   input
!     my_file  : address of file                              type(c_ptr)
!     iactio   : action on file                               i
!                = 1    to keep the file;
!                = 2    to delete the file.
!   output
!     FILCLS   : error status                                 i
!                =  0  unit closed
!                = -1  error on close of kdi file
!                = -2  error on close of Fortran file
!                = -3  unknown file at close
!
!-------------------------- FILCLS -------------------------------------
!
integer function FILCLS(file_pt,iactio)
   use, intrinsic :: iso_c_binding
!----
!   subroutine arguments
!----
   type(c_ptr), target :: file_pt
   integer :: iactio
!----
!   local variables
!----
   type FIL_file
      integer :: unit
      type(c_ptr) :: kdi_file
   end type FIL_file
   integer, parameter :: ndummy=4
   type(FIL_file), pointer :: my_file
   type(c_ptr) :: my_kdi_file
   integer,external :: KDICL,KDRCLS
   integer :: ret_val
!
   call c_f_pointer(file_pt,my_file)
   itapno=my_file%unit
   my_kdi_file=my_file%kdi_file
!----
!  kdi (word addressable) file open
!----
   if((itapno == 0).and.c_associated(my_kdi_file)) then
      iercod=KDICL(my_kdi_file,iactio)
      ret_val=-1
      if(iercod /= 0) go to 7000
   else if((itapno > 0).and..not.c_associated(my_kdi_file)) then
      ret_val=-2
      iercod=KDRCLS(itapno,iactio)
      if(iercod /= 0) go to 7000
   else
      ret_val=-3
      go to 7000
   endif
   deallocate(my_file)
   FILCLS=0
   return
   7000 FILCLS=ret_val
   return
end function FILCLS
!
!-------------------------- FILUNIT ------------------------------------
!
! - function FILUNIT(file_pt)
!
!   recover Fortran file unit number.
!
!   input
!     file_pt    = address of file                            type(c_ptr)
!
!   output
!     FILUNIT    = Fortran file unit number                   i
!
!-------------------------- FILUNIT ------------------------------------
!
integer function FILUNIT(file_pt)
   use, intrinsic :: iso_c_binding
!----
!   subroutine arguments
!----
   type(c_ptr), intent(in), target :: file_pt
!----
!   local variables
!----
   type FIL_file
      integer :: unit
      type(c_ptr) :: kdi_file
   end type FIL_file
   type(FIL_file), pointer :: my_file
!
   call c_f_pointer(file_pt,my_file)
   if(c_associated(my_file%kdi_file)) then
      FILUNIT = -1
      return
   endif
   FILUNIT=my_file%unit
   return
end function FILUNIT
!
!-------------------------- FILKDI -------------------------------------
!
! - function FILKDI(file_pt)
!
!   recover KDI file c_ptr.
!
!   input
!     file_pt    = address of file                            type(c_ptr)
!
!   output
!     FILKDI     = KDI file c_ptr                             type(c_ptr)
!
!-------------------------- FILKDI -------------------------------------
!
function FILKDI(file_pt)
   use, intrinsic :: iso_c_binding
   type(c_ptr) FILKDI
!----
!   subroutine arguments
!----
   type(c_ptr), intent(in), target :: file_pt
!----
!   local variables
!----
   type FIL_file
      integer :: unit
      type(c_ptr) :: kdi_file
   end type FIL_file
   type(FIL_file), pointer :: my_file
!
   call c_f_pointer(file_pt,my_file)
   if(my_file%unit > 0) then
      FILKDI=c_null_ptr
      return
   endif
   FILKDI=my_file%kdi_file
   return
end function FILKDI
