module spglib_f08

   use iso_c_binding, only: c_char, c_int, c_double, c_ptr, c_null_char, c_f_pointer, c_associated

   implicit none

   private

   enum, bind(C)
      enumerator ::  SPGLIB_SUCCESS = 0
      enumerator ::  SPGERR_SPACEGROUP_SEARCH_FAILED
      enumerator ::  SPGERR_CELL_STANDARDIZATION_FAILED
      enumerator ::  SPGERR_SYMMETRY_OPERATION_SEARCH_FAILED
      enumerator ::  SPGERR_ATOMS_TOO_CLOSE
      enumerator ::  SPGERR_POINTGROUP_NOT_FOUND
      enumerator ::  SPGERR_NIGGLI_FAILED
      enumerator ::  SPGERR_DELAUNAY_FAILED
      enumerator ::  SPGERR_ARRAY_SIZE_SHORTAGE
      enumerator ::  SPGERR_NONE
   end enum

   type :: SpglibSpacegroupType
      integer(c_int) :: number
      character(len=11) :: international_short
      character(len=20) :: international_full
      character(len=32) :: international
      character(len=7) :: schoenflies
      integer(c_int) :: hall_number
      character(len=17) :: hall_symbol
      character(len=6) :: choice
      character(len=6) :: pointgroup_international
      character(len=4) :: pointgroup_schoenflies
      integer(c_int) :: arithmetic_crystal_class_number
      character(len=7) :: arithmetic_crystal_class_symbol
   end type SpglibSpacegroupType

   type :: SpglibDataset
      integer(c_int) :: spacegroup_number
      integer(c_int) :: hall_number
      character(len=11) :: international_symbol
      character(len=17) :: hall_symbol
      character(len=6) :: choice
      real(c_double)  :: transformation_matrix(3, 3)
      real(c_double)  :: origin_shift(3)
      integer(c_int) :: n_operations
      integer(c_int), allocatable :: rotations(:, :, :)
      real(c_double), allocatable :: translations(:, :)
      integer(c_int) :: n_atoms
      integer(c_int), allocatable :: wyckoffs(:)
      character(len=7), allocatable :: site_symmetry_symbols(:)
      integer(c_int), allocatable :: equivalent_atoms(:) !Beware mapping refers to positions starting at 0
      integer(c_int), allocatable :: crystallographic_orbits(:) !Beware mapping refers to positions starting at 0
      real(c_double) :: primitive_lattice(3, 3)
      integer(c_int), allocatable :: mapping_to_primitive(:) !Beware mapping refers to positions starting at 0
      integer(c_int) :: n_std_atoms
      real(c_double) :: std_lattice(3, 3)
      integer(c_int), allocatable :: std_types(:)
      real(c_double), allocatable :: std_positions(:, :)
      real(c_double)  :: std_rotation_matrix(3, 3)
      integer(c_int), allocatable :: std_mapping_to_primitive(:) !Beware mapping refers to positions starting at 0
      character(len=6) :: pointgroup_symbol
      integer(kind(SPGLIB_SUCCESS)) :: spglib_error
   end type SpglibDataset

   interface

      function spg_get_symmetry(rotation, translation, max_size, lattice, &
           & position, types, num_atom, symprec) bind(c)
         import c_int, c_double
         integer(c_int), intent(out) :: rotation(3, 3, *)
         real(c_double), intent(out) :: translation(3, *)
         integer(c_int), intent(in), value :: max_size
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_symmetry
      end function spg_get_symmetry

      function spgat_get_symmetry(rotation, translation, max_size, lattice, &
           & position, types, num_atom, symprec, angle_tolerance) bind(c)
         import c_int, c_double
         integer(c_int), intent(out) :: rotation(3, 3, *)
         real(c_double), intent(out) :: translation(3, *)
         integer(c_int), intent(in), value :: max_size
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_get_symmetry
      end function spgat_get_symmetry

      function spg_get_symmetry_with_collinear_spin(rotation, translation, &
           & equivalent_atoms, max_size, lattice, position, types, spins, &
           & num_atom, symprec) bind(c)
         import c_int, c_double
         integer(c_int), intent(out) :: rotation(3, 3, *)
         real(c_double), intent(out) :: translation(3, *)
         integer(c_int), intent(out) :: equivalent_atoms(*)
         integer(c_int), intent(in), value :: max_size
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         real(c_double), intent(in) :: spins(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_symmetry_with_collinear_spin
      end function spg_get_symmetry_with_collinear_spin

      function spgat_get_symmetry_with_collinear_spin(rotation, translation, &
           & equivalent_atoms, max_size, lattice, position, types, spins, &
           & num_atom, symprec, angle_tolerance) bind(c)
         import c_int, c_double
         integer(c_int), intent(out) :: rotation(3, 3, *)
         real(c_double), intent(out) :: translation(3, *)
         integer(c_int), intent(out) :: equivalent_atoms(*)
         integer(c_int), intent(in), value :: max_size
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         real(c_double), intent(in) :: spins(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_get_symmetry_with_collinear_spin
      end function spgat_get_symmetry_with_collinear_spin

      function spg_get_symmetry_with_site_tensors(rotation, translation, &
           & equivalent_atoms, primitive_lattice, spin_flips, max_size, lattice, &
           & position, types, tensors, tensor_rank, num_atom, with_time_reversal, &
           & is_axial, symprec) bind(c)
         import c_int, c_double
         integer(c_int), intent(out) :: rotation(3, 3, *)
         real(c_double), intent(out) :: translation(3, *)
         integer(c_int), intent(out) :: equivalent_atoms(*)
         real(c_double), intent(out) :: primitive_lattice(3, 3)
         integer(c_int), intent(out) :: spin_flips(*)
         integer(c_int), intent(in), value :: max_size
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         real(c_double), intent(in) :: tensors(*)
         integer(c_int), intent(in), value :: tensor_rank
         integer(c_int), intent(in), value :: num_atom
         integer(c_int), intent(in), value :: with_time_reversal
         integer(c_int), intent(in), value :: is_axial
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_symmetry_with_site_tensors
      end function spg_get_symmetry_with_site_tensors

      function spgat_get_symmetry_with_site_tensors(rotation, translation, &
           & equivalent_atoms, primitive_lattice, spin_flips, max_size, lattice, &
           & position, types, tensors, tensor_rank, num_atom, with_time_reversal, &
           & is_axial, symprec, angle_tolerance) bind(c)
         import c_int, c_double
         integer(c_int), intent(out) :: rotation(3, 3, *)
         real(c_double), intent(out) :: translation(3, *)
         integer(c_int), intent(out) :: equivalent_atoms(*)
         real(c_double), intent(out) :: primitive_lattice(3, 3)
         integer(c_int), intent(out) :: spin_flips(*)
         integer(c_int), intent(in), value :: max_size
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         real(c_double), intent(in) :: tensors(*)
         integer(c_int), intent(in), value :: tensor_rank
         integer(c_int), intent(in), value :: num_atom
         integer(c_int), intent(in), value :: with_time_reversal
         integer(c_int), intent(in), value :: is_axial
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_get_symmetry_with_site_tensors
      end function spgat_get_symmetry_with_site_tensors

      function spg_get_multiplicity(lattice, position, types, num_atom, &
           & symprec) bind(c)
         import c_int, c_double
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_multiplicity
      end function spg_get_multiplicity

      function spgat_get_multiplicity(lattice, position, types, num_atom, &
           & symprec, angle_tolerance) bind(c)
         import c_int, c_double
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_get_multiplicity
      end function spgat_get_multiplicity

      function spg_delaunay_reduce(lattice, symprec) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3)
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_delaunay_reduce
      end function spg_delaunay_reduce

      function spg_niggli_reduce(lattice, symprec) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3)
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_niggli_reduce
      end function spg_niggli_reduce

      function spg_find_primitive(lattice, position, types, num_atom, symprec) &
        & bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(inout) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_find_primitive
      end function spg_find_primitive

      function spgat_find_primitive(lattice, position, types, num_atom, symprec, &
           & angle_tolerance) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(inout) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_find_primitive
      end function spgat_find_primitive

      function spg_get_international(symbol, lattice, position, types, num_atom, &
           & symprec) bind(c)
         import c_char, c_int, c_double
         character(kind=c_char), intent(out) :: symbol(11)
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_international ! the number corresponding to 'symbol'. 0 on failure
      end function spg_get_international

      function spgat_get_international(symbol, lattice, position, types, num_atom, &
           & symprec, angle_tolerance) bind(c)
         import c_char, c_int, c_double
         character(kind=c_char), intent(out) :: symbol(11)
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_get_international ! the number corresponding to 'symbol'. 0 on failure
      end function spgat_get_international

      function spg_get_schoenflies(symbol, lattice, position, types, num_atom, &
           & symprec) bind(c)
         import c_char, c_int, c_double
         character(kind=c_char), intent(out) :: symbol(7)
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_schoenflies ! the number corresponding to 'symbol'. 0 on failure
      end function spg_get_schoenflies

      function spgat_get_schoenflies(symbol, lattice, position, types, num_atom, &
           & symprec, angle_tolerance) bind(c)
         import c_char, c_int, c_double
         character(kind=c_char), intent(out) :: symbol(7)
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_get_schoenflies ! the number corresponding to 'symbol'. 0 on failure
      end function spgat_get_schoenflies

      function spg_get_pointgroup(symbol, trans_mat, rotations, num_rotations) &
           & bind(c)
         import c_char, c_int, c_double
         character(kind=c_char) :: symbol(6)
         integer(c_int), intent(out) :: trans_mat(3, 3)
         integer(c_int), intent(in) :: rotations(3, 3, *)
         integer(c_int), intent(in), value :: num_rotations
         integer(c_int) :: spg_get_pointgroup
      end function spg_get_pointgroup

      function spg_refine_cell(lattice, position, types, num_atom, symprec) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(inout) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_refine_cell
      end function spg_refine_cell

      function spgat_refine_cell(lattice, position, types, num_atom, symprec, &
           & angle_tolerance) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(inout) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_refine_cell
      end function spgat_refine_cell

      function spg_standardize_cell(lattice, position, types, num_atom, &
           & to_primitive, no_idealize, symprec) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(inout) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         integer(c_int), intent(in), value :: to_primitive, no_idealize
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_standardize_cell
      end function spg_standardize_cell

      function spgat_standardize_cell(lattice, position, types, num_atom, &
           & to_primitive, no_idealize, symprec, angle_tolerance) bind(c)
         import c_int, c_double
         real(c_double), intent(inout) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(inout) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         integer(c_int), intent(in), value :: to_primitive, no_idealize
         real(c_double), intent(in), value :: symprec, angle_tolerance
         integer(c_int) :: spgat_standardize_cell
      end function spgat_standardize_cell

      function spg_get_ir_reciprocal_mesh(grid_point, map, mesh, is_shift, &
           & is_time_reversal, lattice, position, types, num_atom, symprec) bind(c)
         import c_int, c_double
         !   Beware the map refers to positions starting at 0
         integer(c_int), intent(out) :: grid_point(3, *), map(*) ! size is product(mesh)
         integer(c_int), intent(in) :: mesh(3), is_shift(3)
         integer(c_int), intent(in), value :: is_time_reversal
         real(c_double), intent(in) :: lattice(3, 3), position(3, *)
         integer(c_int), intent(in) :: types(*)
         integer(c_int), intent(in), value :: num_atom
         real(c_double), intent(in), value :: symprec
         integer(c_int) :: spg_get_ir_reciprocal_mesh ! the number of points in the reduced mesh
      end function spg_get_ir_reciprocal_mesh

      function spg_get_stabilized_reciprocal_mesh(grid_point, map, mesh, is_shift, &
           & is_time_reversal, lattice, num_rot, rotations, num_q, qpoints) bind(c)
         import c_int, c_double
         !   Beware the map refers to positions starting at 0
         integer(c_int), intent(out) :: grid_point(3, *), map(*)
         integer(c_int), intent(in) :: mesh(3)
         integer(c_int), intent(in) :: is_shift(3)
         integer(c_int), intent(in), value :: is_time_reversal
         real(c_double), intent(in) :: lattice(3, 3)
         integer(c_int), intent(in), value :: num_rot
         integer(c_int), intent(in) :: rotations(3, 3, *)
         integer(c_int), intent(in), value :: num_q
         real(c_double), intent(in) :: qpoints(3, *)
         integer(c_int) :: spg_get_stabilized_reciprocal_mesh
      end function spg_get_stabilized_reciprocal_mesh

      function spg_get_error_code() bind(c, name='spg_get_error_code')
         import SPGLIB_SUCCESS
         integer(kind(SPGLIB_SUCCESS)) :: spg_get_error_code
      end function spg_get_error_code

   end interface

   public :: SpglibDataset, spg_get_dataset, &
        & spg_get_symmetry, spgat_get_symmetry, &
        & spg_get_symmetry_with_collinear_spin, &
        & spgat_get_symmetry_with_collinear_spin, &
        & spg_get_symmetry_with_site_tensors, &
        & spgat_get_symmetry_with_site_tensors, &
        & spg_get_multiplicity, spgat_get_multiplicity, &
        & spg_delaunay_reduce, spg_niggli_reduce, &
        & spg_find_primitive, spgat_find_primitive, &
        & spg_get_international, spgat_get_international, &
        & spg_get_schoenflies, spgat_get_schoenflies, &
        & spg_get_pointgroup, spg_refine_cell, spgat_refine_cell, &
        & spg_standardize_cell, spgat_standardize_cell, &
        & spg_get_ir_reciprocal_mesh, &
        & spg_get_stabilized_reciprocal_mesh, &
        & spg_get_error_code, spg_get_error_message, &
        & SpglibSpacegroupType, spg_get_spacegroup_type

contains

   function spg_get_error_message(spglib_error)
      integer(kind(SPGLIB_SUCCESS)) :: spglib_error
      character(len=32) :: spg_get_error_message

      character, pointer, dimension(:) :: message
      type(c_ptr) :: message_ptr

      integer :: i

      interface

         function spg_get_error_message_c(spglib_error) &
              & bind(c, name='spg_get_error_message')
            import c_ptr, SPGLIB_SUCCESS

            integer(kind(SPGLIB_SUCCESS)), value :: spglib_error
            type(c_ptr) :: spg_get_error_message_c

         end function spg_get_error_message_c

      end interface

      message_ptr = spg_get_error_message_c(spglib_error)
      call c_f_pointer(message_ptr, message, [len(spg_get_error_message)])

      spg_get_error_message = ' '
      do i = 1, len(spg_get_error_message)
         if (message(i) == C_NULL_CHAR) exit
         spg_get_error_message(i:i) = message(i)
      end do

   end function spg_get_error_message

   function spg_get_spacegroup_type(hall_number) result(spgtype)
      integer(c_int), intent(in) :: hall_number
      type(SpglibSpacegroupType) :: spgtype

      type, bind(c) :: SpglibSpacegroupType_c
         integer(c_int) :: number
         character(kind=c_char) :: international_short(11)
         character(kind=c_char) :: international_full(20)
         character(kind=c_char) :: international(32)
         character(kind=c_char) :: schoenflies(7)
         integer(c_int) :: hall_number
         character(kind=c_char) :: hall_symbol(17)
         character(kind=c_char) :: choice(6)
         character(kind=c_char) :: pointgroup_international(6)
         character(kind=c_char) :: pointgroup_schoenflies(4)
         integer(c_int) :: arithmetic_crystal_class_number
         character(kind=c_char) :: arithmetic_crystal_class_symbol(7)
      end type SpglibSpacegroupType_c

      interface

         function spg_get_spacegroup_type_c(hall_number) &
              & bind(c, name='spg_get_spacegroup_type')
            import c_int, SpglibSpacegroupType_c
            integer(c_int), intent(in), value :: hall_number
            type(SpglibSpacegroupType_c) :: spg_get_spacegroup_type_c
         end function spg_get_spacegroup_type_c

      end interface

      type(SpglibSpacegroupType_c):: spgtype_c
      integer :: i

      spgtype_c = spg_get_spacegroup_type_c(hall_number)

      spgtype%number = spgtype_c%number
      spgtype%hall_number = spgtype_c%hall_number
      spgtype%arithmetic_crystal_class_number = &
           & spgtype_c%arithmetic_crystal_class_number

      do i = 1, size(spgtype_c%international_short)
         if (spgtype_c%international_short(i) == C_NULL_CHAR) then
            spgtype%international_short(i:) = ' '
            exit
         end if
         spgtype%international_short(i:i) = spgtype_c%international_short(i)
      end do

      do i = 1, size(spgtype_c%international_full)
         if (spgtype_c%international_full(i) == C_NULL_CHAR) then
            spgtype%international_full(i:) = ' '
            exit
         end if
         spgtype%international_full(i:i) = spgtype_c%international_full(i)
      end do

      do i = 1, size(spgtype_c%international)
         if (spgtype_c%international(i) == C_NULL_CHAR) then
            spgtype%international(i:) = ' '
            exit
         end if
         spgtype%international(i:i) = spgtype_c%international(i)
      end do

      do i = 1, size(spgtype_c%schoenflies)
         if (spgtype_c%schoenflies(i) == C_NULL_CHAR) then
            spgtype%schoenflies(i:) = ' '
            exit
         end if
         spgtype%schoenflies(i:i) = spgtype_c%schoenflies(i)
      end do

      do i = 1, size(spgtype_c%hall_symbol)
         if (spgtype_c%hall_symbol(i) == C_NULL_CHAR) then
            spgtype%hall_symbol(i:) = ' '
            exit
         end if
         spgtype%hall_symbol(i:i) = spgtype_c%hall_symbol(i)
      end do

      do i = 1, size(spgtype_c%choice)
         if (spgtype_c%choice(i) == C_NULL_CHAR) then
            spgtype%choice(i:) = ' '
            exit
         end if
         spgtype%choice(i:i) = spgtype_c%choice(i)
      end do

      do i = 1, size(spgtype_c%pointgroup_international)
         if (spgtype_c%pointgroup_international(i) == C_NULL_CHAR) then
            spgtype%pointgroup_international(i:) = ' '
            exit
         end if
         spgtype%pointgroup_international(i:i) = &
              & spgtype_c%pointgroup_international(i)
      end do

      do i = 1, size(spgtype_c%pointgroup_schoenflies)
         if (spgtype_c%pointgroup_schoenflies(i) == C_NULL_CHAR) then
            spgtype%pointgroup_schoenflies(i:) = ' '
            exit
         end if
         spgtype%pointgroup_schoenflies(i:i) = &
              & spgtype_c%pointgroup_schoenflies(i)
      end do

      do i = 1, size(spgtype_c%arithmetic_crystal_class_symbol)
         if (spgtype_c%arithmetic_crystal_class_symbol(i) == C_NULL_CHAR) then
            spgtype%arithmetic_crystal_class_symbol(i:) = ' '
            exit
         end if
         spgtype%arithmetic_crystal_class_symbol(i:i) = &
              & spgtype_c%arithmetic_crystal_class_symbol(i)
      end do

   end function spg_get_spacegroup_type

   function spg_get_dataset(lattice, position, types, num_atom, symprec) result(dset)

      real(c_double), intent(in) :: lattice(3, 3)
      real(c_double), intent(in) :: position(3, *)
      integer(c_int), intent(in) :: types(*)
      integer(c_int), intent(in), value :: num_atom
      real(c_double), intent(in), value :: symprec
      type(SpglibDataset) :: dset

      type, bind(c) :: SpglibDataset_c
         integer(c_int) :: spacegroup_number
         integer(c_int) :: hall_number
         character(kind=c_char) :: international_symbol(11)
         character(kind=c_char) :: hall_symbol(17)
         character(kind=c_char) :: choice(6)
         real(c_double) :: transformation_matrix(3, 3)
         real(c_double) :: origin_shift(3)
         integer(c_int) :: n_operations
         type(c_ptr) :: rotations
         type(c_ptr) :: translations
         integer(c_int) :: n_atoms
         type(c_ptr) :: wyckoffs
         type(c_ptr) :: site_symmetry_symbols
         type(c_ptr) :: equivalent_atoms
         type(c_ptr) :: crystallographic_orbits
         real(c_double) :: primitive_lattice(3, 3)
         type(c_ptr) :: mapping_to_primitive
         integer(c_int) :: n_std_atoms
         real(c_double) :: std_lattice(3, 3)
         type(c_ptr) :: std_types
         type(c_ptr) :: std_positions
         real(c_double)  :: std_rotation_matrix(3, 3)
         type(c_ptr) :: std_mapping_to_primitive
         character(kind=c_char) :: pointgroup_symbol(6)
      end type SpglibDataset_c

      interface
         function spg_get_dataset_c(lattice, position, types, num_atom, symprec) &
              & bind(c, name='spg_get_dataset')
            import c_int, c_double, c_ptr
            real(c_double), intent(in) :: lattice(3, 3)
            real(c_double), intent(in) :: position(3, *)
            integer(c_int), intent(in) :: types(*)
            integer(c_int), intent(in), value :: num_atom
            real(c_double), intent(in), value :: symprec
            type(c_ptr) :: spg_get_dataset_c
         end function spg_get_dataset_c

         subroutine spg_free_dataset_c(dataset) bind(c, name='spg_free_dataset')
            import SpglibDataset_c
            type(SpglibDataset_c), intent(inout) :: dataset
         end subroutine spg_free_dataset_c

      end interface

      type(SpglibDataset_c), pointer :: dset_c
      type(c_ptr) :: dataset_ptr_c
      integer(c_int) :: n_operations, n_atoms, n_std_atoms
      integer :: i
      integer(kind(SPGLIB_SUCCESS)) :: SpglibErrcode
      real(c_double), pointer :: translations(:, :), std_positions(:, :)
      integer(c_int), pointer :: rotations(:, :, :), wyckoffs(:), equivalent_atoms(:)
      integer(c_int), pointer :: crystallographic_orbits(:), std_types(:)

      dataset_ptr_c = spg_get_dataset_c(lattice, position, types, num_atom, symprec)

      if (c_associated(dataset_ptr_c)) then

         dset%spglib_error = SPGLIB_SUCCESS

         call c_f_pointer(dataset_ptr_c, dset_c)

         dset%spacegroup_number = dset_c%spacegroup_number
         dset%hall_number = dset_c%hall_number
         dset%transformation_matrix = dset_c%transformation_matrix
         dset%origin_shift = dset_c%origin_shift
         dset%n_operations = dset_c%n_operations
         dset%n_atoms = dset_c%n_atoms
         dset%n_std_atoms = dset_c%n_std_atoms
         dset%std_lattice = dset_c%std_lattice
         dset%std_rotation_matrix = dset_c%std_rotation_matrix
         dset%primitive_lattice = dset_c%primitive_lattice

         ! Copy C strings to Fortran characters, converting C NULL to Fortran space padded strings
         do i = 1, size(dset_c%international_symbol)
            if (dset_c%international_symbol(i) == C_NULL_CHAR) then
               dset%international_symbol(i:) = ' '
               exit
            end if
            dset%international_symbol(i:i) = dset_c%international_symbol(i)
         end do

         do i = 1, size(dset_c%hall_symbol)
            if (dset_c%hall_symbol(i) == C_NULL_CHAR) then
               dset%hall_symbol(i:) = ' '
               exit
            end if
            dset%hall_symbol(i:i) = dset_c%hall_symbol(i)
         end do

         do i = 1, size(dset_c%choice)
            if (dset_c%choice(i) == C_NULL_CHAR) then
               dset%choice(i:) = ' '
               exit
            end if
            dset%choice(i:i) = dset_c%choice(i)
         end do

         do i = 1, size(dset_c%pointgroup_symbol)
            if (dset_c%pointgroup_symbol(i) == C_NULL_CHAR) then
               dset%pointgroup_symbol(i:) = ' '
               exit
            end if
            dset%pointgroup_symbol(i:i) = dset_c%pointgroup_symbol(i)
         end do

         n_operations = dset_c%n_operations
         n_atoms = dset_c%n_atoms
         n_std_atoms = dset_c%n_std_atoms

         call c_f_pointer(dset_c%rotations, rotations, shape=[3, 3, n_operations])
         call c_f_pointer(dset_c%translations, translations, shape=[3, n_operations])
         call c_f_pointer(dset_c%wyckoffs, wyckoffs, shape=[n_atoms])
         call c_f_pointer(dset_c%equivalent_atoms, equivalent_atoms, shape=[n_atoms])
         call c_f_pointer(dset_c%crystallographic_orbits, crystallographic_orbits, shape=[n_atoms])
         call c_f_pointer(dset_c%std_types, std_types, shape=[n_std_atoms])
         call c_f_pointer(dset_c%std_positions, std_positions, shape=[3, n_std_atoms])

         allocate (dset%rotations(3, 3, n_operations))
         allocate (dset%translations(3, n_operations))
         allocate (dset%wyckoffs(n_atoms))
         allocate (dset%equivalent_atoms(n_atoms))
         allocate (dset%crystallographic_orbits(n_atoms))
         allocate (dset%std_types(n_std_atoms))
         allocate (dset%std_positions(3, n_std_atoms))

         dset%rotations = rotations
         dset%translations = translations
         dset%wyckoffs = wyckoffs
         dset%equivalent_atoms = equivalent_atoms
         dset%crystallographic_orbits = crystallographic_orbits
         dset%std_types = std_types
         dset%std_positions = std_positions

         call spg_free_dataset_c(dset_c)

      else

         dset%spglib_error = spg_get_error_code()

         dset%spacegroup_number = 0
         dset%hall_number = 0
         dset%international_symbol = ' '
         dset%hall_symbol = ' '
         dset%choice = ' '
         dset%transformation_matrix = 0.0_c_double
         dset%origin_shift = 0.0_c_double
         dset%n_operations = 0
         dset%n_atoms = 0
         dset%n_std_atoms = 0
         dset%std_lattice = 0.0_c_double
         dset%primitive_lattice = 0.0_c_double
         dset%pointgroup_symbol = ' '

      end if

   end function spg_get_dataset

end module spglib_f08
