strings.F90 Source File


Files dependent on this one

sourcefile~~strings.f90~~AfferentGraph sourcefile~strings.f90 strings.F90 sourcefile~apply_basis.f90 apply_basis.F90 sourcefile~apply_basis.f90->sourcefile~strings.f90 sourcefile~atomic_structure.f90 atomic_structure.F90 sourcefile~apply_basis.f90->sourcefile~atomic_structure.f90 sourcefile~c_interop.f90 c_interop.F90 sourcefile~apply_basis.f90->sourcefile~c_interop.f90 sourcefile~types.f90 types.F90 sourcefile~apply_basis.f90->sourcefile~types.f90 sourcefile~atomic_structure.f90->sourcefile~strings.f90 sourcefile~basis_library.f90 basis_library.F90 sourcefile~basis_library.f90->sourcefile~strings.f90 sourcefile~elements.f90 elements.F90 sourcefile~basis_library.f90->sourcefile~elements.f90 sourcefile~c_interop.f90->sourcefile~strings.f90 sourcefile~basis_tools.f90 basis_tools.F90 sourcefile~c_interop.f90->sourcefile~basis_tools.f90 sourcefile~c_interop.f90->sourcefile~types.f90 sourcefile~dft.f90 dft.F90 sourcefile~dft.f90->sourcefile~strings.f90 sourcefile~dft.f90->sourcefile~basis_tools.f90 sourcefile~dft_fuzzycell.f90 dft_fuzzycell.F90 sourcefile~dft.f90->sourcefile~dft_fuzzycell.f90 sourcefile~dft.f90->sourcefile~types.f90 sourcefile~dft_gridint_energy.f90 dft_gridint_energy.F90 sourcefile~dft.f90->sourcefile~dft_gridint_energy.f90 sourcefile~dft_gridint_grad.f90 dft_gridint_grad.F90 sourcefile~dft.f90->sourcefile~dft_gridint_grad.f90 sourcefile~libxc.f90 libxc.F90 sourcefile~dft.f90->sourcefile~libxc.f90 sourcefile~electric_moments.f90 electric_moments.F90 sourcefile~electric_moments.f90->sourcefile~strings.f90 sourcefile~electric_moments.f90->sourcefile~c_interop.f90 sourcefile~electric_moments.f90->sourcefile~basis_tools.f90 sourcefile~electric_moments.f90->sourcefile~types.f90 sourcefile~int1.f90 int1.F90 sourcefile~electric_moments.f90->sourcefile~int1.f90 sourcefile~elements.f90->sourcefile~strings.f90 sourcefile~get_basis_overlap.f90 get_basis_overlap.F90 sourcefile~get_basis_overlap.f90->sourcefile~strings.f90 sourcefile~get_basis_overlap.f90->sourcefile~atomic_structure.f90 sourcefile~get_basis_overlap.f90->sourcefile~c_interop.f90 sourcefile~get_basis_overlap.f90->sourcefile~basis_tools.f90 sourcefile~get_basis_overlap.f90->sourcefile~types.f90 sourcefile~get_basis_overlap.f90->sourcefile~int1.f90 sourcefile~get_states_overlap.f90 get_states_overlap.F90 sourcefile~get_states_overlap.f90->sourcefile~strings.f90 sourcefile~get_states_overlap.f90->sourcefile~atomic_structure.f90 sourcefile~get_states_overlap.f90->sourcefile~c_interop.f90 sourcefile~get_states_overlap.f90->sourcefile~basis_tools.f90 sourcefile~get_states_overlap.f90->sourcefile~types.f90 sourcefile~tdhf_mrsf_lib.f90 tdhf_mrsf_lib.F90 sourcefile~get_states_overlap.f90->sourcefile~tdhf_mrsf_lib.f90 sourcefile~guess_hcore.f90 guess_hcore.F90 sourcefile~guess_hcore.f90->sourcefile~strings.f90 sourcefile~guess_hcore.f90->sourcefile~c_interop.f90 sourcefile~guess_hcore.f90->sourcefile~basis_tools.f90 sourcefile~guess_hcore.f90->sourcefile~types.f90 sourcefile~guess.f90 guess.F90 sourcefile~guess_hcore.f90->sourcefile~guess.f90 sourcefile~printing.f90 printing.F90 sourcefile~guess_hcore.f90->sourcefile~printing.f90 sourcefile~guess_huckel.f90 guess_huckel.F90 sourcefile~guess_huckel.f90->sourcefile~strings.f90 sourcefile~guess_huckel.f90->sourcefile~c_interop.f90 sourcefile~guess_huckel.f90->sourcefile~basis_tools.f90 sourcefile~huckel.f90 huckel.F90 sourcefile~guess_huckel.f90->sourcefile~huckel.f90 sourcefile~guess_huckel.f90->sourcefile~types.f90 sourcefile~guess_huckel.f90->sourcefile~guess.f90 sourcefile~guess_huckel.f90->sourcefile~printing.f90 sourcefile~hf_energy.f90 hf_energy.f90 sourcefile~hf_energy.f90->sourcefile~strings.f90 sourcefile~hf_energy.f90->sourcefile~c_interop.f90 sourcefile~hf_energy.f90->sourcefile~dft.f90 sourcefile~hf_energy.f90->sourcefile~basis_tools.f90 sourcefile~scf.f90 scf.F90 sourcefile~hf_energy.f90->sourcefile~scf.f90 sourcefile~hf_energy.f90->sourcefile~types.f90 sourcefile~hf_energy.f90->sourcefile~printing.f90 sourcefile~hf_gradient.f90 hf_gradient.F90 sourcefile~hf_gradient.f90->sourcefile~strings.f90 sourcefile~hf_gradient.f90->sourcefile~c_interop.f90 sourcefile~hf_gradient.f90->sourcefile~dft.f90 sourcefile~hf_gradient.f90->sourcefile~basis_tools.f90 sourcefile~grd1.f90 grd1.F90 sourcefile~hf_gradient.f90->sourcefile~grd1.f90 sourcefile~hf_gradient.f90->sourcefile~types.f90 sourcefile~grd2.f90 grd2.F90 sourcefile~hf_gradient.f90->sourcefile~grd2.f90 sourcefile~hf_gradient.f90->sourcefile~printing.f90 sourcefile~int1e.f90 int1e.F90 sourcefile~int1e.f90->sourcefile~strings.f90 sourcefile~int1e.f90->sourcefile~c_interop.f90 sourcefile~int1e.f90->sourcefile~basis_tools.f90 sourcefile~int1e.f90->sourcefile~types.f90 sourcefile~int1e.f90->sourcefile~int1.f90 sourcefile~int1e.f90->sourcefile~printing.f90 sourcefile~population_analysis.f90 population_analysis.F90 sourcefile~population_analysis.f90->sourcefile~strings.f90 sourcefile~population_analysis.f90->sourcefile~c_interop.f90 sourcefile~population_analysis.f90->sourcefile~elements.f90 sourcefile~population_analysis.f90->sourcefile~basis_tools.f90 sourcefile~population_analysis.f90->sourcefile~types.f90 sourcefile~resp.f90 resp.F90 sourcefile~resp.f90->sourcefile~strings.f90 sourcefile~resp.f90->sourcefile~c_interop.f90 sourcefile~resp.f90->sourcefile~elements.f90 sourcefile~resp.f90->sourcefile~basis_tools.f90 sourcefile~resp.f90->sourcefile~types.f90 sourcefile~resp.f90->sourcefile~int1.f90 sourcefile~tdhf_energy.f90 tdhf_energy.F90 sourcefile~tdhf_energy.f90->sourcefile~strings.f90 sourcefile~tdhf_energy.f90->sourcefile~c_interop.f90 sourcefile~tdhf_energy.f90->sourcefile~dft.f90 sourcefile~tdhf_energy.f90->sourcefile~basis_tools.f90 sourcefile~int2.f90 int2.F90 sourcefile~tdhf_energy.f90->sourcefile~int2.f90 sourcefile~tdhf_energy.f90->sourcefile~types.f90 sourcefile~dft_gridint_fxc.f90 dft_gridint_fxc.F90 sourcefile~tdhf_energy.f90->sourcefile~dft_gridint_fxc.f90 sourcefile~tdhf_energy.f90->sourcefile~int1.f90 sourcefile~tdhf_energy.f90->sourcefile~printing.f90 sourcefile~tdhf_lib.f90 tdhf_lib.F90 sourcefile~tdhf_energy.f90->sourcefile~tdhf_lib.f90 sourcefile~tdhf_gradient.f90 tdhf_gradient.F90 sourcefile~tdhf_gradient.f90->sourcefile~strings.f90 sourcefile~tdhf_gradient.f90->sourcefile~c_interop.f90 sourcefile~tdhf_gradient.f90->sourcefile~dft.f90 sourcefile~tdhf_gradient.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_gradient.f90->sourcefile~grd1.f90 sourcefile~tdhf_gradient.f90->sourcefile~types.f90 sourcefile~dft_gridint_tdxc_grad.f90 dft_gridint_tdxc_grad.F90 sourcefile~tdhf_gradient.f90->sourcefile~dft_gridint_tdxc_grad.f90 sourcefile~tdhf_gradient.f90->sourcefile~grd2.f90 sourcefile~tdhf_gradient.f90->sourcefile~printing.f90 sourcefile~tdhf_gradient.f90->sourcefile~tdhf_lib.f90 sourcefile~tdhf_mrsf_energy.f90 tdhf_mrsf_energy.F90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~strings.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~c_interop.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~int2.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~types.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~printing.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~tdhf_lib.f90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~tdhf_mrsf_lib.f90 sourcefile~tdhf_sf_lib.f90 tdhf_sf_lib.F90 sourcefile~tdhf_mrsf_energy.f90->sourcefile~tdhf_sf_lib.f90 sourcefile~tdhf_sf_energy.f90 tdhf_sf_energy.F90 sourcefile~tdhf_sf_energy.f90->sourcefile~strings.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~c_interop.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~int2.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~types.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~printing.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~tdhf_lib.f90 sourcefile~tdhf_sf_energy.f90->sourcefile~tdhf_sf_lib.f90 sourcefile~tdhf_z_vector.f90 tdhf_z_vector.F90 sourcefile~tdhf_z_vector.f90->sourcefile~strings.f90 sourcefile~tdhf_z_vector.f90->sourcefile~c_interop.f90 sourcefile~tdhf_z_vector.f90->sourcefile~dft.f90 sourcefile~tdhf_z_vector.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_z_vector.f90->sourcefile~int2.f90 sourcefile~tdhf_z_vector.f90->sourcefile~types.f90 sourcefile~tdhf_z_vector.f90->sourcefile~dft_gridint_fxc.f90 sourcefile~dft_gridint_gxc.f90 dft_gridint_gxc.F90 sourcefile~tdhf_z_vector.f90->sourcefile~dft_gridint_gxc.f90 sourcefile~tdhf_z_vector.f90->sourcefile~printing.f90 sourcefile~tdhf_z_vector.f90->sourcefile~tdhf_lib.f90 sourcefile~tdhf_z_vector.f90->sourcefile~tdhf_sf_lib.f90 sourcefile~basis_tools.f90->sourcefile~atomic_structure.f90 sourcefile~basis_tools.f90->sourcefile~basis_library.f90 sourcefile~basis_tools.f90->sourcefile~elements.f90 sourcefile~dft_fuzzycell.f90->sourcefile~atomic_structure.f90 sourcefile~dft_fuzzycell.f90->sourcefile~basis_tools.f90 sourcefile~grd1.f90->sourcefile~atomic_structure.f90 sourcefile~grd1.f90->sourcefile~basis_tools.f90 sourcefile~grd1.f90->sourcefile~types.f90 sourcefile~ecp.f90 ecp.F90 sourcefile~grd1.f90->sourcefile~ecp.f90 sourcefile~mod_shell_tools.f90 mod_shell_tools.F90 sourcefile~grd1.f90->sourcefile~mod_shell_tools.f90 sourcefile~mod_1e_primitives.f90 mod_1e_primitives.F90 sourcefile~grd1.f90->sourcefile~mod_1e_primitives.f90 sourcefile~guess_json.f90 guess_json.F90 sourcefile~guess_json.f90->sourcefile~c_interop.f90 sourcefile~guess_json.f90->sourcefile~basis_tools.f90 sourcefile~guess_json.f90->sourcefile~types.f90 sourcefile~guess_json.f90->sourcefile~guess.f90 sourcefile~guess_json.f90->sourcefile~printing.f90 sourcefile~huckel.f90->sourcefile~atomic_structure.f90 sourcefile~huckel.f90->sourcefile~basis_tools.f90 sourcefile~huckel.f90->sourcefile~types.f90 sourcefile~huckel.f90->sourcefile~guess.f90 sourcefile~huckel.f90->sourcefile~int1.f90 sourcefile~int2.f90->sourcefile~atomic_structure.f90 sourcefile~int2.f90->sourcefile~basis_tools.f90 sourcefile~int2.f90->sourcefile~types.f90 sourcefile~int2_pairs.f90 int2_pairs.F90 sourcefile~int2.f90->sourcefile~int2_pairs.f90 sourcefile~int_libint.f90 int_libint.F90 sourcefile~int2.f90->sourcefile~int_libint.f90 sourcefile~int_rotaxis.f90 int_rotaxis.F90 sourcefile~int2.f90->sourcefile~int_rotaxis.f90 sourcefile~int_rys.f90 int_rys.F90 sourcefile~int2.f90->sourcefile~int_rys.f90 sourcefile~oqp_banner.f90 oqp_banner.F90 sourcefile~oqp_banner.f90->sourcefile~c_interop.f90 sourcefile~oqp_banner.f90->sourcefile~types.f90 sourcefile~scf.f90->sourcefile~dft.f90 sourcefile~scf.f90->sourcefile~basis_tools.f90 sourcefile~scf.f90->sourcefile~int2.f90 sourcefile~scf.f90->sourcefile~types.f90 sourcefile~scf.f90->sourcefile~guess.f90 sourcefile~scf.f90->sourcefile~printing.f90 sourcefile~scf_converger.f90 scf_converger.F90 sourcefile~scf.f90->sourcefile~scf_converger.f90 sourcefile~types.f90->sourcefile~atomic_structure.f90 sourcefile~types.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint.f90 dft_gridint.F90 sourcefile~dft_gridint.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_energy.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_energy.f90->sourcefile~types.f90 sourcefile~dft_gridint_energy.f90->sourcefile~dft_gridint.f90 sourcefile~dft_gridint_fxc.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_fxc.f90->sourcefile~types.f90 sourcefile~dft_gridint_fxc.f90->sourcefile~dft_gridint.f90 sourcefile~dft_gridint_grad.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_grad.f90->sourcefile~types.f90 sourcefile~dft_gridint_grad.f90->sourcefile~dft_gridint.f90 sourcefile~dft_gridint_gxc.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_gxc.f90->sourcefile~types.f90 sourcefile~dft_gridint_gxc.f90->sourcefile~dft_gridint.f90 sourcefile~dft_gridint_gxc.f90->sourcefile~dft_gridint_fxc.f90 sourcefile~dft_gridint_tdxc_grad.f90->sourcefile~basis_tools.f90 sourcefile~dft_gridint_tdxc_grad.f90->sourcefile~types.f90 sourcefile~dft_gridint_tdxc_grad.f90->sourcefile~dft_gridint.f90 sourcefile~ecp.f90->sourcefile~basis_tools.f90 sourcefile~grd2.f90->sourcefile~basis_tools.f90 sourcefile~grd2.f90->sourcefile~int2.f90 sourcefile~grd2.f90->sourcefile~types.f90 sourcefile~grd2_rys.f90 grd2_rys.F90 sourcefile~grd2.f90->sourcefile~grd2_rys.f90 sourcefile~grd2.f90->sourcefile~int2_pairs.f90 sourcefile~grd2_rys.f90->sourcefile~basis_tools.f90 sourcefile~grd2_rys.f90->sourcefile~int2_pairs.f90 sourcefile~guess.f90->sourcefile~basis_tools.f90 sourcefile~guess.f90->sourcefile~types.f90 sourcefile~int1.f90->sourcefile~basis_tools.f90 sourcefile~int1.f90->sourcefile~ecp.f90 sourcefile~int1.f90->sourcefile~mod_shell_tools.f90 sourcefile~int1.f90->sourcefile~printing.f90 sourcefile~int1.f90->sourcefile~mod_1e_primitives.f90 sourcefile~int2_pairs.f90->sourcefile~basis_tools.f90 sourcefile~int_libint.f90->sourcefile~basis_tools.f90 sourcefile~int_libint.f90->sourcefile~int2_pairs.f90 sourcefile~int_rotaxis.f90->sourcefile~basis_tools.f90 sourcefile~int_rotaxis.f90->sourcefile~int2_pairs.f90 sourcefile~int_rys.f90->sourcefile~basis_tools.f90 sourcefile~int_rys.f90->sourcefile~int2_pairs.f90 sourcefile~libxc.f90->sourcefile~types.f90 sourcefile~mod_shell_tools.f90->sourcefile~basis_tools.f90 sourcefile~printing.f90->sourcefile~basis_tools.f90 sourcefile~printing.f90->sourcefile~types.f90 sourcefile~tdhf_lib.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_lib.f90->sourcefile~int2.f90 sourcefile~tdhf_lib.f90->sourcefile~types.f90 sourcefile~tdhf_mrsf_lib.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_mrsf_lib.f90->sourcefile~int2.f90 sourcefile~tdhf_mrsf_lib.f90->sourcefile~types.f90 sourcefile~tdhf_sf_lib.f90->sourcefile~basis_tools.f90 sourcefile~tdhf_sf_lib.f90->sourcefile~types.f90 sourcefile~tdhf_sf_lib.f90->sourcefile~int1.f90 sourcefile~tdhf_sf_lib.f90->sourcefile~tdhf_lib.f90 sourcefile~mod_1e_primitives.f90->sourcefile~mod_shell_tools.f90 sourcefile~scf_converger.f90->sourcefile~printing.f90

Source Code

module strings
  use, intrinsic :: iso_c_binding, only: c_ptr, c_int64_t
  implicit none
  private
  character(*), parameter, public :: &
    ALPHANUM = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' &
    , AN_DASH = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'
  integer, parameter :: &
    A_LOWER = iachar('a'), &
    Z_LOWER = iachar('z'), &
    A_UPPER = iachar('A'), &
    Z_UPPER = iachar('Z'), &
    UPPER_TO_LOWER = A_LOWER-A_UPPER
  public :: to_upper, to_lower, count_substring, remove_spaces, index_ith, fstring
  public :: f_c_char
  public :: c_f_char
  character, target :: char_empty = ''

  type, public :: tokenizer_t
    character(:), pointer :: str => null()
    character(:), pointer :: delims => null()
  contains
    procedure :: get => next_token
  end type

  type, public, bind(C) :: Cstring
    integer(c_int64_t) :: length
    type(c_ptr) :: string
  end type Cstring

contains

!> @brief  Split string on tokens, delimiting by specified set of symbols
!> @author Vladimir Mironov
!> @date   Sept, 2021
!> @param  this   [inout] `tokenizer_t` instance
!> @param  str    [in]    optional, input string
!> @param  delim  [in]    optional, string containing delimiter symbols, default=''
!> @param  result         pointer to the next token
!> @note   Delimiter instance saves its state after `str` and `delim` has been set up.
!>         At each successfull call user can redefine `delim` string
!>         The behavior is similar to C `strtok` function.
!>         Returns null pointer when line ends and resets `tokenizer_t` internal state.
!>         Example usage:
!>         ```fortran
!>         type(tokenizer_t) :: tokz
!>         character(:), pointer :: ptr
!>         ptr => tokz%get(str, ' ;,')
!>         do while (associated(ptr))
!>           print *, ptr
!>           ptr => tokz%get()
!>         end do
!>         ```
!> @note   Do not use for csv reading!
  function next_token(this, str, delim) result(res)
    class(tokenizer_t) :: this
    character(*), target, intent(in), optional :: str
    character(*), target, intent(in), optional :: delim
    character(:), pointer :: res
    integer :: pos_start, res_len, pos_end
    character(:), pointer :: temp_str

    res => null()

    if (present(str)) then
      nullify (this%str)
      this%str => str
    end if

    if (present(delim)) then
      if (len(delim) /= 0) then
        this%delims => delim
      end if
    end if

    if (len(this%str) == 0) then
      nullify (this%str)
      this%delims => char_empty
      return
    end if

    if (.not. associated(this%str)) return
    if (.not. associated(this%delims)) then
      this%delims => char_empty
    end if

    pos_start = verify(this%str, this%delims)

    if (pos_start == 0) then
      nullify (this%str)
      this%delims => char_empty
      return
    end if

    res_len = scan(this%str(pos_start:), this%delims)-1
    temp_str => this%str(pos_start:)
    if (res_len < 0) res_len = len(temp_str)
    nullify(temp_str)

    pos_end = pos_start+res_len

    res => this%str(pos_start:pos_end-1)

    this%str => this%str(pos_end+1:)

  end function next_token

  !> @brief  return string in upper case
  !> @author Igor S. Gerasimov
  !> @date   Sep, 2019 --Initial release--
  !> @date   May, 2021 Moved to strings
  !> @date   Sep, 2021 subroutine -> function
  !> @param  line - (in)
  pure function to_upper(input_string) result(output_string)
    character(*), intent(in) :: input_string
    character(:), allocatable :: output_string
    integer :: i, ic
    output_string = input_string
    do i = 1, len(output_string)
      ic = iachar(output_string(i:i))
      if (ic <= Z_LOWER .and. ic >= A_LOWER) then
        output_string(i:i) = achar(ic-UPPER_TO_LOWER)
      end if
    end do
  end function to_upper
  !> @brief  return string in lower case
  !> @author Igor S. Gerasimov
  !> @date   Sep, 2021 --Initial release--
  !> @param  line - (inout)
  pure function to_lower(input_string) result(output_string)
    character(*), intent(in) :: input_string
    character(:), allocatable :: output_string
    integer :: i, ic
    output_string = input_string
    do i = 1, len(output_string)
      ic = iachar(output_string(i:i))
      if (ic <= Z_UPPER .and. ic >= A_UPPER) then
        output_string(i:i) = achar(ic+UPPER_TO_LOWER)
      end if
    end do
  end function to_lower
  !> @brief  This function return count of substring in string
  !> @author Igor S. Gerasimov
  !> @date   Sep, 2019 --Initial release--
  !> @date   May, 2021 Moved to strings
  !> @param  substring - (in)
  !> @param  string    - (in)
  pure integer function count_substring(substring, string) result(res)
    character(len=*), intent(in) :: substring, string
    ! internal variables
    character(len=:), allocatable :: tmp_string
    res = 0
    tmp_string = string
    do
      if (index(tmp_string, substring) == 0) exit
      res = res+1
      tmp_string = tmp_string(index(tmp_string, substring)+1:)
    end do
    return
  end function count_substring
  !> @brief  This routine remove not needed spaces from section line
  !> @detail This routine used revert reading of lines.
  !>         Example, that this routine do:
  !>       > DFTTYP = PBE0 BASNAM=APC4 , ACC5
  !>       < DFTTYP=PBE0 BASNAM=APC4,ACC5
  !> @author Igor S. Gerasimov
  !> @date   Sep, 2019 --Initial release--
  !> @date   May, 2021 Moved to strings
  !> @param  line - (inout) worked line
  pure subroutine remove_spaces(line)
    character(len=:), allocatable, intent(inout) :: line
    ! internal variables
    character(len=:), allocatable :: tmp_line, res_line
    integer :: i, ind, ind_end
    logical :: skip, first
    tmp_line = line
    line = ""
    do
      res_line = ""
      ind_end = index(tmp_line, "=")
      first = .true.
      skip = .false.
      ind = ind_end
      if (ind == 0) ind = len(tmp_line)
      do i = ind, 1, -1
        if (tmp_line(i:i) /= " ") then
          res_line = tmp_line(i:i)//res_line
          if (tmp_line(i:i) /= "=" .and. first .and. ind_end /= 0) then
            skip = .true.
            first = .false.
          end if
        else if (skip) then
          res_line = " "//res_line
          skip = .false.
        end if
      end do
      line = line//trim(adjustl(res_line))
      if (ind_end == 0) exit
      tmp_line = tmp_line(ind+1:)
    end do
  end subroutine remove_spaces
  !> @brief   This function return index of i'th substring in string
  !> @details if ind is negative, backward search will be
  !>          result is equal 0 if search was failed
  !> @author  Igor S. Gerasimov
  !> @date    May, 2021 --Initial release--
  !> @param   substring - (in)
  !> @param   string    - (in)
  !> @param   ith       - (in) index of needed substring
  pure integer function index_ith(substring, string, ith) result(res)
    character(len=*), intent(in) :: substring, string
    integer, intent(in) :: ith
    ! internal variables
    character(len=:), allocatable :: tmp_string
    integer :: i, diff
    res = 0
    tmp_string = string
    if (ith > 0) then
      do i = 1, ith
        diff = index(tmp_string, substring)
        res = res+diff
        if (diff == 0) then
          res = 0
          exit
        end if
        tmp_string = tmp_string(index(tmp_string, substring)+1:)
      end do
    else if (ith < 0) then
      do i = -1, ith, -1
        res = index(tmp_string, substring, back=.true.)
        if (res == 0) exit
        tmp_string = tmp_string(:index(tmp_string, substring, back=.true.)-1)
      end do
    else
      res = 0
    end if
  end function index_ith
  !> @brief   This function return fortran allocatable string
  !> @author  Igor S. Gerasimov
  !> @date    April, 2022 --Initial release--
  !> @param   string    - (in) C-like string
  function fstring(string) result(res)
    use, intrinsic :: iso_c_binding, only: c_f_pointer, c_char
    type(Cstring), intent(in) :: string
    character(len=:), allocatable :: res
    character(len=1,kind=c_char), pointer :: fpstring(:)
    ! internal variables
    integer :: i
    allocate(character(len=string%length) :: res)
    call c_f_pointer(string%string, fpstring, shape=[string%length])
    do i = 1, string%length
      res(i:i) = fpstring(i)
    end do
  end function fstring

!> @brief Convert Fortran string to a raw null-terminated C-string
!> @note No real boundary checks for c-string are performed, use at your own risk!
!> @note C-string should be already allocated
!> @param[in]   from    fortran string
!> @param[out]  to      null-terminated c-string, len(to) should be at least numchar+1
!> @param[in]   numchar maximum number of characters to pass from fortran to c-string
  subroutine f_c_char(from, to, numchar)
    use, intrinsic :: iso_c_binding, only: c_char, c_null_char
    character(len=*), intent(in) :: from
    character(kind=c_char, len=1) :: to(*)
    integer, intent(in) :: numchar
    integer :: i
    do i = 1, min(len(from), numchar)
      to(i) = from(i:i)
    end do
    to(i) = c_null_char
  end subroutine f_c_char

!> @brief Convert raw null-terminated C-string to Fortran string
!> @note No boundary checks for c-string are performed, use at your own risk!
  function c_f_char(cchar) result(fstr)
    use, intrinsic :: iso_c_binding, only: c_char, c_null_char
    character(kind=c_char), intent(in) :: cchar(*)
    character(:), allocatable :: fstr
    integer :: i, strlen

    strlen = 0
    do
        if (cchar(strlen+1) == c_null_char) exit
        strlen = strlen + 1
    end do

    allocate(character(strlen) :: fstr)

    do i = 1, strlen
        fstr(i:i) = cchar(i)
    end do
  end function c_f_char
end module strings