subroutine GDNcFileOpen(fileid, filename, writable, overwrite, stat, err)
  use gtdata_netcdf_file_types, only: GD_NC_FILE_ID_ENTRY
  use gtdata_netcdf_file_internal, only: id_head, id_used
  use netcdf, only: &
    & NF90_WRITE, &
    & NF90_NOWRITE, &
    & NF90_ENOTNC4, &
    & NF90_NOERR, &
    & NF90_NOCLOBBER, &
    & NF90_CLOBBER, &
    & NF90_OPEN, &
    & NF90_CREATE
  use dc_message, only: MessageNotify
  use dc_error, only: StoreError
  use dc_types, only: STRING
  use dc_trace, only: BeginSub, EndSub
  implicit none
  integer, intent(out):: fileid
  character(len = *), intent(in):: filename
  logical, intent(in), optional:: writable
                                        ! .TRUE. 縺ｯ譖ｸ縺崎ｾｼ縺ｿ繝｢繝ｼ繝峨�
                                        ! .FALSE. 縺ｯ隱ｭ霎ｼ繝｢繝ｼ繝峨�
                                        ! 隱ｭ霎ｼ繝｢繝ｼ繝峨�髫帙↓繝輔ぃ繧､繝ｫ縺�
                                        ! 繝輔ぃ繧､繝ｫ縺悟ｭ伜惠縺励↑縺�→
                                        ! 繧ｨ繝ｩ繝ｼ縺ｫ縺ｪ繧九�
                                        ! 繝�ヵ繧ｩ繝ｫ繝医�隱ｭ縺ｿ霎ｼ縺ｿ繝｢繝ｼ繝�
  logical, intent(in), optional:: overwrite
                                        ! writable 縺� .TRUE. 縺ｮ
                                        ! 蝣ｴ蜷医�縺ｿ譛牙柑縲�
                                        ! .TRUE. 縺ｪ繧峨�荳頑嶌縺阪Δ繝ｼ繝�
                                        ! .FALSE. 縺ｮ蝣ｴ蜷医∵里蟄倥�
                                        ! 繝輔ぃ繧､繝ｫ縺悟ｭ伜惠縺吶ｋ縺ｨ
                                        ! 繧ｨ繝ｩ繝ｼ縺ｫ縺ｪ繧�
  logical, intent(out), optional:: err
  integer, intent(out), optional:: stat
  logical:: writable_required
  logical:: overwrite_required
  type(GD_NC_FILE_ID_ENTRY), pointer:: identptr, prev
  integer:: mystat, mode
  character(len = 256):: real_filename
  character(len = STRING):: cause_c
  character(*), parameter:: subname = "GDNcFileOpen"
continue
  fileid = -1
  !
  ! 繧ｪ繝励す繝ｧ繝ｳ縺ｮ隗｣驥�
  !
  writable_required = .FALSE.
  overwrite_required = .FALSE.
  if (present(writable)) writable_required = writable
  if (present(overwrite)) overwrite_required = overwrite
  call BeginSub(subname, 'writable=%y overwrite=%y file=%c', &
    & L=(/writable_required, overwrite_required/), c1=trim(filename))
  !
  ! 蜷後§蜷榊燕縺ｧ譖ｸ霎ｼ縺ｿ蜿ｯ閭ｽ諤ｧ繧る←蜷医＠縺ｦ縺�ｌ縺ｰ nf90_open 縺励↑縺�〒貂医∪縺帙ｋ
  !
  if (id_used) then
    identptr => id_head
    nullify(prev)
    do
      if ((identptr % filename == filename) &
        & .and. (identptr % writable .or. .not. writable_required)) then
        fileid = identptr % id
        identptr % count = identptr % count + 1
        if (present(err)) err = .FALSE.
        if (present(stat)) stat = NF90_NOERR
        mystat = NF90_NOERR
        goto 999
      endif
      prev => identptr
      identptr => identptr % next
      if (.not. associated(identptr)) exit
    enddo
    allocate(identptr)
    prev%next => identptr
  else
    nullify(prev)
    allocate(id_head)
    identptr => id_head
    id_used = .TRUE.
  endif
  nullify(identptr % next)
  identptr % filename = filename
  identptr % writable = writable_required
  identptr % count = 1
  !
  ! URL 縺ｮ驛ｨ蛻�噪繧ｵ繝昴�繝�
  !
  real_filename = filename
  if (real_filename(1:8) == 'file:///') then
    real_filename = real_filename(8: )
  else if (real_filename(1:5) == 'file:' .AND. real_filename(6:6) /= '/') then
    real_filename = real_filename(6: )
  endif
  !
  ! 縺�＊ nf90_open
  !
  mode = NF90_NOWRITE
  if (writable_required) mode = ior(mode, NF90_WRITE)
  ! 譌｢縺ｫ nc 繝輔ぃ繧､繝ｫ縺後≠繧九→諤昴▲縺ｦ髢九￠縺ｦ縺ｿ繧�
  mystat = NF90_OPEN(real_filename, mode, identptr % id)
  !
  ! 繝輔ぃ繧､繝ｫ縺梧里縺ｫ蟄伜惠縺吶ｋ蝣ｴ蜷�
  !
  if (mystat == NF90_NOERR) then
    ! 譖ｸ縺崎ｾｼ縺ｿ繝｢繝ｼ繝峨�蝣ｴ蜷�
    if (writable_required) then
      if (overwrite_required) then
        ! 荳頑嶌縺阪Δ繝ｼ繝峨�蝣ｴ蜷�
        mode = NF90_CLOBBER
        call MessageNotify('M', subname, &
          & '"%c" is overwritten.', c1=trim(filename), rank_mpi = -1)
      else
        ! 荳頑嶌縺咲ｦ∵ｭ｢繝｢繝ｼ繝峨�蝣ｴ蜷�
        mode = NF90_NOCLOBBER
        call MessageNotify('W', subname, &
          & '"%c" is opened in write-protect mode.', c1=trim(filename), rank_mpi = -1)
      end if
      mystat = NF90_CREATE(real_filename, mode, identptr % id)
      if (mystat /= NF90_NOERR) then
        cause_c=filename
        if (present(stat)) stat = mystat
        goto 999
      end if
    endif
    ! 隱ｭ縺ｿ霎ｼ縺ｿ繝｢繝ｼ繝峨�蝣ｴ蜷医�菴輔ｂ縺励↑縺�
  else
    !
    ! 繝輔ぃ繧､繝ｫ縺檎┌縺九▲縺溷�ｴ蜷�
    !
    if (.not. writable_required) then
      ! 隱ｭ縺ｿ霎ｼ縺ｿ繝｢繝ｼ繝峨�蝣ｴ蜷�
      !
      ! 縲檎┌縺�ｈ縲阪→繧ｨ繝ｩ繝ｼ繧貞瑞縺�※邨ゆｺ�
      if (mystat /= NF90_NOERR) then
        cause_c=filename
        if (present(stat)) stat = mystat
        goto 999
      end if
    else
      ! 譖ｸ縺崎ｾｼ縺ｿ繝｢繝ｼ繝峨�蝣ｴ蜷�
      mode = NF90_CLOBBER
      ! 繝輔ぃ繧､繝ｫ繧剃ｽ懈�縺吶ｋ
      mystat = NF90_CREATE(real_filename, mode, identptr % id)
      if (mystat /= NF90_NOERR) then
        cause_c=filename
        if (present(stat)) stat = mystat
        goto 999
      end if
    endif
  endif

  fileid = identptr % id

  ! 螟ｱ謨励＠縺溘ｉ豸医＠縺ｦ縺翫￥
  if (mystat /= NF90_NOERR) then
    if (associated(prev)) then
      prev%next => identptr % next
    else
      id_head => identptr % next
      if (.not. associated(id_head)) id_used = .FALSE.
    endif
    deallocate(identptr)
    fileid = -1
  endif

  if (present(stat)) then
    stat = mystat
    if (present(err)) err = (stat /= NF90_NOERR)
  else
    cause_c=filename
    goto 999
  endif
999 continue
  call StoreError(mystat, subname, err, cause_c)
  call EndSub(subname, 'id=%d stat=%d', i=(/fileid, mystat/))
end subroutine GDNcFileOpen