!== dc_url.f90 - å¤‰æ•° URL ã®æ–‡å—åˆ—è§£æž
!
! Authors::   Yasuhiro MORIKAWA, Eizi TOYODA
! Version::   $Id: dc_url.f90,v 1.1 2009-03-20 09:09:52 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]
!
! This file provides dc_url
!

module dc_url
  !
  !== Overview
  !
  ! ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ gtool4 å¤‰æ•° URL ã®æ–‡å—åˆ—è§£æž
  ! ã‚’è¡Œã†ãŸã‚ã®æ‰‹ç¶šãã‚’æä¾›ã—ã¾ã™ã€‚
  !
  ! gtool4 å¤‰æ•°ã®æ›¸å¼ã«é–¢ã—ã¦ã¯,
  ! {gtool4 netCDF è¦ç´„}[link:../xref.htm#label-6]
  ! ã®ã€Œ5. å„ç¨®ã®æ–‡å—åˆ—æ›¸å¼ã€ã‚’å‚ç…§ãã ã•ã„ã€‚
  !
  !== Procedures Summary
  !
  ! æ‰‹ç¶šãç¾¤ã®è¦ç´„
  !
  ! UrlSplit         :: å¤‰æ•° URL ã‚’åˆ†è§£ã—ãƒ•ã‚¡ã‚¤ãƒ«åã€å¤‰æ•°åã€
  !                     å±žæ€§åãŠã‚ˆã³å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šã‚’å–ã‚Šå‡ºã™
  ! UrlMerge         :: ãƒ•ã‚¡ã‚¤ãƒ«åã€å¤‰æ•°åã€å±žæ€§åãŠã‚ˆã³å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®š
  !                     ã‚’é€£çµã—ã¦å¤‰æ•° URL ã‚’ä½œæˆ
  ! UrlResolve       :: å¤‰æ•° URL ã®è£œå®Œ
  ! Url_Chop_IOrange :: å¤‰æ•° URL ã‹ã‚‰ iorange ã‚’é™¤åŽ»
  ! UrlSearchIORange :: å¤‰æ•° URL å†…ã® iorange ã†ã¡, ã‚ã‚‹æ¬¡å…ƒã«é–¢ã™ã‚‹
  !                     å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šã®å€¤ã‚’å–å¾—
  ! dc_url#operator(.OnTheSameFile.) :: 2 ã¤ã®å¤‰æ•° URL
  !                                     ãŒåŒã˜ãƒ•ã‚¡ã‚¤ãƒ«ã‚’æŒ‡ã™ã‹ã©ã†ã‹åˆ¤å®š
  !
  ! ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ gtool4 å¤‰æ•°ã«ãŠã„ã¦ç‰¹åˆ¥ãªå½¹å‰²ã‚’æžœãŸã™
  ! æ–‡å—ã®ãƒ‹ãƒ¼ãƒ¢ãƒ‹ãƒƒã‚¯ã‚’æä¾›ã—ã¾ã™ã€‚gtool4 å¤‰æ•°è§£æžã®éš›ã«ã¯ã€
  ! ç›´æŽ¥æ–‡å—ã‚’ç”¨ã„ã‚‹ã®ã§ã¯ãªãã€ã“ã“ã§æä¾›ã™ã‚‹å¤‰æ•°ç¾¤
  ! (GT_ATMARK ç‰) ã‚’åˆ©ç”¨ã—ã¦ãã ã•ã„ã€‚
  !

  implicit none
  private

  public:: Url_Chop_IOrange
  public:: operator(.OnTheSameFile.)

  public:: UrlMerge
  interface UrlMerge
!    module procedure url_merge_v_vvv
    module procedure url_merge_cc
    module procedure url_merge_cccc
    module procedure url_merge_cccca
  end interface

  public:: UrlSplit
  interface UrlSplit
!    module procedure url_split_v
    module procedure url_split_c
  end interface

  public:: UrlResolve
  interface UrlResolve
    module procedure url_resolve_c
  end interface

  public:: UrlSearchIORange
  interface UrlSearchIORange
    module procedure url_search_iorange
  end interface

  interface operator(.OnTheSameFile.)
    module procedure UrlOnTheSameFile
  end interface

  character, public, parameter:: GT_ATMARK = "@"
                                 ! ãƒ•ã‚¡ã‚¤ãƒ«åã¨å¤‰æ•°åã®åŒºåˆ‡ã‚Šã«ç”¨ã„ã‚‰ã‚Œã¾ã™ã€‚
  character, public, parameter:: GT_QUESTION = "?"
                                 ! ãƒ•ã‚¡ã‚¤ãƒ«åã¨å¤‰æ•°åã®åŒºåˆ‡ã‚Šã«ç”¨ã„ã‚‰ã‚Œã¾ã™ã€‚
  character, public, parameter:: GT_COLON = ":"
                                 ! å¤‰æ•°ã®å±žæ€§ã‚’ç¤ºã™æ™‚ã«ç”¨ã„ã‚‰ã‚Œã¾ã™ã€‚
  character, public, parameter:: GT_COMMA = ","
                                 ! å…¥å‡ºåŠ›ç¯„å›²ã®é™å®šã«ç”¨ã„ã‚‰ã‚Œã¾ã™ã€‚
  character, public, parameter:: GT_EQUAL = "="
                                 ! å…¥å‡ºåŠ›ç¯„å›²ã®é™å®šã«ç”¨ã„ã‚‰ã‚Œã¾ã™ã€‚
  character, public, parameter:: GT_CIRCUMFLEX = "^"
                                 ! åº§æ¨™ã®ä½ç½®ã‚’å€¤ã§ã¯ãªãã€
                                 ! æ ¼åç‚¹ç•ªå·ã§æŒ‡å®šã™ã‚‹æ™‚ã«ç”¨ã„ã‚‰ã‚Œã¾ã™ã€‚
  character, public, parameter:: GT_PLUS = "+"
                                 ! å±žæ€§ã®è¡Œé ã«ã“ã®æ–‡å—ãŒã¤ãå ´åˆã€å¤§åŸŸå±žæ€§ã‚’ç¤ºã—ã¾ã™ã€‚

contains

  ! ANUrlMerge - å¤‰æ•° URL ã®åˆæˆ
  ! ç©ºæ–‡å—åˆ—ã®æˆåˆ†ã¯ãªã„ã¨ã¿ãªã•ã‚Œã‚‹ã€‚

!  type(VSTRING) function &
!    & url_merge_v_vvv(file, var, attr, iorange) result(result) !:nodoc:
!    use dcstring_base, only: VSTRING, operator(.cat.), operator(/=), &
!      & extract, operator(==) !:nodoc:
!    implicit none
!    type(VSTRING), intent(in):: file
!    type(VSTRING), intent(in), optional:: var
!    type(VSTRING), intent(in), optional:: attr
!    type(VSTRING), intent(in), optional:: iorange
!    result = file .cat. GT_ATMARK
!    if (present(var)) result = result .cat. var
!    if (present(attr)) then
!      if (attr /= "") result = result .cat. GT_COLON .cat. attr
!    endif
!    if (present(iorange)) then
!      if (extract(iorange, 1, 1) == GT_COMMA) then
!        result = result .cat. iorange
!      else if (iorange /= "") then
!        result = result .cat. GT_COMMA .cat. iorange
!      endif
!    endif
!  end function

  function url_merge_cc(file, var) result(result)
    !
    ! ãƒ•ã‚¡ã‚¤ãƒ«å fileã€å¤‰æ•°å var ã‚’çµåˆã—ã¦ relsult ã¨ã—ã¦è¿”ã—ã¾ã™ã€‚
    !
    use dc_types, only: STRING
    character(len = STRING):: result
    character(len = *), intent(in):: file
    character(len = *), intent(in):: var
  continue
    result = url_merge_cccc(file, var, "", "")
  end function url_merge_cc

  function url_merge_cccca(file, var, attr, iorange) result(result)
    !
    ! ãƒ•ã‚¡ã‚¤ãƒ«å fileã€å¤‰æ•°å varã€å±žæ€§ attrã€
    ! å…¥å‡ºåŠ›ç¯„å›² iorange ã‚’çµåˆã—ã¦ relsult ã¨ã—ã¦è¿”ã—ã¾ã™ã€‚
    ! iorange ã«ã¯æ–‡å—åž‹é…åˆ—ã‚’ä¸Žãˆã¾ã™ã€‚æ–‡å—åž‹é…åˆ—ã®ãã‚Œãžã‚Œã®è¦ç´ ã¯
    ! GT_COMMA ã§é€£çµã•ã‚Œã¦ã‹ã‚‰çµåˆã•ã‚Œã¾ã™ã€‚
    !
    use dc_types, only: STRING
    character(len = STRING):: result
    character(len = *), intent(in):: file
    character(len = *), intent(in):: var
    character(len = *), intent(in):: attr
    character(len = *), intent(in):: iorange(:)
    integer:: i
  continue
    if (file /= "") then
      result = trim(file) // gt_atmark
    else
      result = gt_atmark
    endif
    if (var /= "") result = trim(result) // var
    if (attr /= "") then
      result = trim(result) // gt_colon // attr
    endif
    do i = 1, size(iorange)
      if (iorange(i) /= "") then
        if (iorange(i)(1:1) == gt_comma) then
          result = trim(result) // trim(iorange(i))
        else
          result = trim(result) // gt_comma // trim(iorange(i))
        endif
      endif
    end do
  end function url_merge_cccca

  function url_merge_cccc(file, var, attr, iorange) result(result)
    !
    ! ãƒ•ã‚¡ã‚¤ãƒ«å fileã€å¤‰æ•°å varã€å±žæ€§ attrã€
    ! å…¥å‡ºåŠ›ç¯„å›² iorange ã‚’çµåˆã—ã¦ relsult ã¨ã—ã¦è¿”ã—ã¾ã™ã€‚
    !
    use dc_types, only: STRING
    character(len = STRING):: result
    character(len = *), intent(in):: file
    character(len = *), intent(in):: var
    character(len = *), intent(in):: attr
    character(len = *), intent(in):: iorange
  continue
    if (trim(file) /= "") then
      result = trim(file) // gt_atmark
    else
      result = gt_atmark
    endif
    if (trim(var) /= "") result = trim(result) // var
    if (trim(attr) /= "") then
      result = trim(result) // gt_colon // attr
    endif
    if (trim(iorange) /= "") then
      if (iorange(1:1) == gt_comma) then
        result = trim(result) // iorange
      else
        result = trim(result) // gt_comma // iorange
      endif
    endif
  end function url_merge_cccc

  subroutine Url_Chop_IOrange(fullname, iorange, remainder)
    !
    ! fullname ã§ä¸Žãˆã‚‰ã‚Œã‚‹å¤‰æ•° URL ã®å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šéƒ¨åˆ†ã¨
    ! æ®‹ã‚Šã®éƒ¨åˆ†ã¨ã‚’åˆ†é›¢ã—ã€ãã‚Œãžã‚Œ iorange ã¨ remainder ã«è¿”ã—ã¾ã™ã€‚
    !
    use dc_types, only: STRING
    character(len = *), intent(in):: fullname
    character(len = *), intent(out):: iorange   ! å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šéƒ¨åˆ†
    character(len = *), intent(out):: remainder ! æ®‹ã‚Šã®éƒ¨åˆ†
    character(STRING):: file, var, attr
    call urlsplit(fullname, file=file, var=var, attr=attr, iorange=iorange)
    remainder = url_merge_cccc(file=file, var=var, attr=attr, iorange="")
  end subroutine url_chop_iorange

  function url_search_iorange(fullname, dimvar) result(result)
    !
    ! å¤‰æ•° URL *fullname* å†…ã®, æ¬¡å…ƒ *dimvar* ã«é–¢ã™ã‚‹
    ! å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šã®å€¤ã‚’å–å¾—ã—ã¾ã™ã€‚
    !
    ! fullname ã«ã¯ gtool4 å¤‰æ•°å…¨ä½“ã¾ãŸã¯å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šéƒ¨åˆ†ã®å€¤ã‚’ä¸Žãˆã¾ã™ã€‚
    ! dimvar ã«ã¯å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šéƒ¨åˆ†ã«å«ã¾ã‚Œã‚‹æ¬¡å…ƒå¤‰æ•°åã‚’ä¸Žãˆã¾ã™ã€‚
    ! dimvar ã«å¯¾å¿œã™ã‚‹æ¬¡å…ƒå¤‰æ•°ãŒå˜åœ¨ã™ã‚‹å ´åˆã€ãã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚
    ! dimvar ã«å¯¾å¿œã™ã‚‹æ¬¡å…ƒå¤‰æ•°ãŒå˜åœ¨ã—ãªã„å ´åˆã€ç©ºæ–‡å—ã‚’è¿”ã—ã¾ã™ã€‚
    !
    use dc_types, only: STRING
    use dc_string, only: Split
    character(len = *), intent(in):: fullname
    character(len = *), intent(in):: dimvar
    character(len = STRING):: result
    character(STRING):: file, var, attr, iorange
    character(STRING), pointer :: ioranges_slice(:) => null()
    integer :: i, eqpos, atmark
  continue
    result = ""
    ! @ ã¾ãŸã¯ ? ãŒå«ã¾ã‚Œã¦ã„ã‚‹ãªã‚‰ urlsplit ã§åˆ†é›¢
    atmark = index(fullname, GT_QUESTION)
    if (atmark == 0) atmark = index(fullname, GT_ATMARK)
    if (atmark /= 0) then
      call urlsplit(fullname, file=file, var=var, attr=attr, iorange=iorange)
    else
      iorange = fullname
    end if
    call Split(iorange, ioranges_slice, GT_COMMA)
    do i = 1, size(ioranges_slice)
      eqpos = index(ioranges_slice(i), GT_EQUAL)
      if (ioranges_slice(i)(1:eqpos-1) == trim(dimvar)) then
        result = trim(ioranges_slice(i)(eqpos+1:))
        exit
      end if
    end do
    deallocate(ioranges_slice)
  end function url_search_iorange

  subroutine url_split_c(fullname, file, var, attr, iorange)
    !
    ! fullname ã§ä¸Žãˆã‚‰ã‚Œã‚‹å¤‰æ•° URL ã‚’ã€ãƒ•ã‚¡ã‚¤ãƒ«å fileã€ å¤‰æ•°å varã€
    ! å±žæ€§å attrã€å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®š iorange ã«åˆ†è§£ã—ã¦è¿”ã—ã¾ã™ã€‚
    ! è¦‹ã¤ã‹ã‚‰ãªã„æˆåˆ†ã«ã¯ç©ºæ–‡å—åˆ—ãŒä»£å…¥ã•ã‚Œã¾ã™ã€‚
    !
    use dc_types, only: STRING
    character(len = *), intent(in):: fullname
    character(len = *), intent(out), optional:: file, var, attr, iorange
    character(len = STRING):: varpart
    integer:: atmark, colon, comma
    character(len = *), parameter:: VARNAME_SET &
      = "0123456789eEdD+-=^,.:_" &
      // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" &
      // "abcdefghijklmnopqrstuvwxyz"
  continue
    ! ã¾ãš URL ã¨å¤‰æ•°å±žæ€§æŒ‡å®š (? ã¾ãŸã¯ @ ä»¥é™) ã‚’åˆ†é›¢ã™ã‚‹ã€‚
    ! URL ã¯ @ ã‚’å«ã¿ã†ã‚‹ãŸã‚ã€æœ€å¾Œã® @ ä»¥é™ã«å¯¾ã—ã¦å¤‰æ•°å±žæ€§
    ! ã¨ã—ã¦è¨±ã•ã‚Œãªã„æ–‡å—ï¼ˆå…¸åž‹çš„ã«ã¯ '/'ï¼‰ãŒå«ã¾ã‚Œã¦ã„ãŸã‚‰
    ! å½“è©² @ ã¯ URL ã®ä¸€éƒ¨ã¨ã¿ãªã™ã€‚
    atmark = index(fullname, GT_QUESTION)
    if (atmark == 0) then
      atmark = index(fullname, GT_ATMARK, back=.TRUE.)
      if (atmark /= 0) then
        if (verify(trim(fullname(atmark+1: )), VARNAME_SET) /= 0) then
          atmark = 0
        endif
      endif
    endif
    if (atmark == 0) then
      ! å¤‰æ•°å±žæ€§æŒ‡å®šã¯ãªã‹ã£ãŸã€‚
      if (present(file)) file = fullname
      if (present(var)) var = ''
      if (present(attr)) attr = ''
      if (present(iorange)) iorange = ''
      return
    endif
    varpart = fullname(atmark+1: )
    ! å¤‰æ•°å±žæ€§æŒ‡å®šãŒã‚ã£ãŸã€‚
    if (present(file)) file = fullname(1: atmark - 1)
    ! ç¯„å›²æŒ‡å®šã‚’æŽ¢ç´¢ã™ã‚‹ã€‚
    comma = index(varpart, GT_COMMA)
    if (comma /= 0) then
      ! ç¯„å›²æŒ‡å®šãŒã¿ã¤ã‹ã£ãŸã€‚
      if (present(var)) var = varpart(1: comma - 1)
      if (present(attr)) attr = ''
      if (present(iorange)) iorange = varpart(comma + 1: )
      return
    endif
    if (present(iorange)) iorange = ''
    ! ç¯„å›²æŒ‡å®šãŒãªã‹ã£ãŸã®ã§ã€å±žæ€§åã®æ¤œç´¢ã‚’ã™ã‚‹ã€‚
    colon = index(varpart, GT_COLON)
    if (colon == 0) then
      if (present(var)) var = varpart
      if (present(attr)) attr = ''
      varpart = ''
      return
    endif
    if (present(var)) var = varpart(1: colon - 1)
    if (present(attr)) attr = varpart(colon + 1: )
    varpart = ''
  end subroutine url_split_c

!  subroutine url_split_v(fullname, file, var, attr, iorange) !:nodoc:
!    use dcstring_base, only: VSTRING, operator(.cat.), operator(/=), &
!      & extract, operator(==) !:nodoc:
!    use dc_string
!    implicit none
!    type(VSTRING), intent(in):: fullname
!    type(VSTRING), intent(out), optional::        file, var, attr, iorange
!    type(VSTRING):: varpart
!    integer:: atmark, colon, comma
!    character(len = *), parameter:: VARNAME_SET &
!      = "0123456789eEdD+-=^,.:_" &
!      // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" &
!      // "abcdefghijklmnopqrstuvwxyz"
!  continue
!    ! ã¾ãš URL ã¨å¤‰æ•°å±žæ€§æŒ‡å®š (? ã¾ãŸã¯ @ ä»¥é™) ã‚’åˆ†é›¢ã™ã‚‹ã€‚
!    ! URL ã¯ @ ã‚’å«ã¿ã†ã‚‹ãŸã‚ã€æœ€å¾Œã® @ ä»¥é™ã«å¯¾ã—ã¦å¤‰æ•°å±žæ€§
!    ! ã¨ã—ã¦è¨±ã•ã‚Œãªã„æ–‡å—ï¼ˆå…¸åž‹çš„ã«ã¯ '/'ï¼‰ãŒå«ã¾ã‚Œã¦ã„ãŸã‚‰
!    ! å½“è©² @ ã¯ URL ã®ä¸€éƒ¨ã¨ã¿ãªã™ã€‚
!    atmark = vindex(fullname, GT_QUESTION)
!    if (atmark == 0) then
!      atmark = vindex(fullname, GT_ATMARK, .TRUE.)
!      if (atmark /= 0) then
!        varpart = extract(fullname, atmark + 1)
!        if (vverify(varpart, VARNAME_SET) /= 0) then
!          atmark = 0
!        endif
!      endif
!    endif
!    if (atmark == 0) then
!      ! å¤‰æ•°å±žæ€§æŒ‡å®šã¯ãªã‹ã£ãŸã€‚
!      if (present(file)) file = fullname
!      if (present(var)) var = ''
!      if (present(attr)) attr = ''
!      if (present(iorange)) iorange = ''
!      return
!    endif
!    varpart = extract(fullname, atmark + 1)
!    ! å¤‰æ•°å±žæ€§æŒ‡å®šãŒã‚ã£ãŸã€‚
!    if (present(file)) file = extract(fullname, 1, atmark - 1)
!    ! ç¯„å›²æŒ‡å®šã‚’æŽ¢ç´¢ã™ã‚‹ã€‚
!    comma = vindex(varpart, GT_COMMA)
!    if (comma /= 0) then
!      ! ç¯„å›²æŒ‡å®šãŒã¿ã¤ã‹ã£ãŸã€‚
!      if (present(var)) var = extract(varpart, 1, comma - 1)
!      if (present(attr)) attr = ''
!      if (present(iorange)) iorange = extract(varpart, comma + 1)
!      return
!    endif
!    if (present(iorange)) iorange = ''
!    ! ç¯„å›²æŒ‡å®šãŒãªã‹ã£ãŸã®ã§ã€å±žæ€§åã®æ¤œç´¢ã‚’ã™ã‚‹ã€‚
!    colon = vindex(varpart, GT_COLON)
!    if (colon == 0) then
!      if (present(var)) var = varpart
!      if (present(attr)) attr = ''
!      varpart = ''
!      return
!    endif
!    if (present(var)) var = extract(varpart, 1, colon - 1)
!    if (present(attr)) attr = extract(varpart, colon + 1)
!    varpart = ''
!  end subroutine url_split_v

  !
  ! === åŒã˜ãƒ•ã‚¡ã‚¤ãƒ«ã«è¼‰ã£ã¦ã„ã‚‹ã‹ã©ã†ã‹åˆ¤å®š ===
  !

  logical function UrlOnTheSameFile(url_a, url_b) result(result)
    !
    ! 1 ã¤ç›®ã®å¼•æ•°ã«ä¸Žãˆã‚‰ã‚Œã‚‹å¤‰æ•° URL ã¨ 2 ã¤ç›®ã®å¼•æ•°ã«ä¸Žãˆã‚‰ã‚Œã‚‹
    ! å¤‰æ•° URL ã¨ãŒåŒã˜ãƒ•ã‚¡ã‚¤ãƒ«ã‚’æŒ‡ã—ã¦ã„ã‚‹ã‹ã©ã†ã‹åˆ¤å®šã—ã¾ã™ã€‚
    ! ã‚‚ã—ã‚‚åŒã˜ãƒ•ã‚¡ã‚¤ãƒ«ã§ã‚ã‚Œã° <b><tt>.true.</tt></b> ã‚’ã€
    ! ç•°ãªã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã§ã‚ã‚Œã° <b><tt>.false.</tt></b> ã‚’è¿”ã—ã¾ã™ã€‚
    !
    use dc_string
    use dc_types, only: STRING
    character(len = *), intent(in) :: url_a
    character(len = *), intent(in) :: url_b
    character(len = STRING)        :: filepart_a
    character(len = STRING)        :: filepart_b
    call UrlSplit(url_a, file=filepart_a)
    call UrlSplit(url_b, file=filepart_b)
    result = (filepart_a == filepart_b)
  end function UrlOnTheSameFile

  !
  ! === ç›¸å¯¾ãƒªãƒ³ã‚¯ã‚’è§£æ±º ===
  !

  function url_resolve_c(relative, base) result(result)
    !
    ! relative ã§ä¸Žãˆã‚‰ã‚Œã‚‹å¤‰æ•° URL ãŒå®Œå…¨ã§ãªã„ (ãƒ•ã‚¡ã‚¤ãƒ«åã€ å¤‰æ•°åã€
    ! å±žæ€§åã€å…¥å‡ºåŠ›ç¯„å›²æŒ‡å®šã®ã©ã‚Œã‹ãŒç„¡ã„) å ´åˆã«ã€ base
    ! ã‹ã‚‰è£œå®Œã—ã¾ã™ã€‚
    !
    use dc_string, only: StrHead
    use dc_types, only: STRING
    use dc_trace, only: BeginSub, EndSub, DbgMessage
    implicit none
    character(len = *), intent(in):: relative
    character(len = *), intent(in):: base
    character(len = STRING):: result
    integer, parameter:: FILE = 1, VAR = 2, ATTR = 3, IOR = 4
    character(len = STRING):: rel(FILE:IOR), bas(FILE:IOR)
    character(3), parameter:: PATHDELIM = "/:" // achar(94)
    integer:: idir_r, idir_b
  continue
    call BeginSub('urlresolve', 'rel=<%c> base=<%c>', c1=relative, c2=base)
    call UrlSplit(trim(relative), file=rel(FILE), var=rel(VAR), &
      & attr=rel(ATTR), iorange=rel(IOR))
    call DbgMessage('rel -> file=<%c> var=<%c> attr=<%c>', &
      & c1=trim(rel(FILE)), c2=trim(rel(VAR)), &
      & c3=(trim(rel(ATTR)) // '> ior=<' // trim(rel(IOR))))
    call UrlSplit(base, file=bas(FILE), var=bas(VAR), &
      & attr=bas(ATTR), iorange=bas(IOR))
    call DbgMessage('base -> file=<%s> var=<%s> attr=<%s> ior=<%s>', &
      & c1=trim(bas(FILE)), c2=trim(bas(VAR)), &
      & c3=(trim(bas(ATTR)) // '> ior=<' // trim(bas(IOR))))
    ! --- ãƒ•ã‚¡ã‚¤ãƒ«åã‚’æ¬ ãã°ã‚ã„ã¯å˜ã«è£œã† ---
    if (rel(FILE) == "") then
      rel(FILE) = bas(FILE)
      if (rel(VAR) == "") &
        & rel(VAR) = bas(VAR)
      result = UrlMerge(file=rel(FILE), var=rel(VAR), &
        & attr=rel(ATTR), iorange=rel(IOR))
      call EndSub('urlresolve', '1 result=%c', c1=trim(result))
      return
    endif
    ! --- çµ¶å¯¾ãƒ‘ã‚¹ (ã¨è¦‹ã‚‰ã‚Œã‚‹) ãƒ•ã‚¡ã‚¤ãƒ«åã¯ãã®ã¾ã¾ä½¿ç”¨ ---
    if (StrHead(rel(FILE), "file:") &
      & .OR. StrHead(rel(FILE), "http:") &
      & .OR. StrHead(rel(FILE), "ftp:") &
      & .OR. StrHead(rel(FILE), "news:") &
      & .OR. StrHead(rel(FILE), "www") &
      & .OR. StrHead(rel(FILE), "/") &
      & .OR. StrHead(rel(FILE), achar(94)) &
      & .OR. rel(FILE)(2:2) == ":" &
      ) then
      result = relative
      call EndSub('urlresolve', '2 result=%c', c1=trim(result))
      return
    endif
    ! ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªåã®å–ã‚Šå‡ºã—
    idir_b = scan(bas(FILE), PATHDELIM, back=.TRUE.)
    if (idir_b == 0) then
      ! ãŒã€ã§ããªã‘ã‚Œã°ã€ï¼ˆã‚¨ãƒ©ãƒ¼ã¨ã™ã¹ãã‹ã‚‚ã—ã‚Œã¬ãŒï¼‰
      ! ç›¸å¯¾ãƒ‘ã‚¹ã‚’ãã®ã¾ã¾ä½¿ç”¨
      result = relative
      call EndSub('urlresolve', '3 result=%c', c1=trim(result))
      return
    endif
    ! ç›¸å¯¾ãƒ‘ã‚¹ã®ã»ã†ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªåã®å–ã‚Šå‡ºã—
    idir_r = scan(rel(FILE), PATHDELIM, back=.TRUE.)
    if (idir_r == 0) then
      ! ãŒã§ããªã‘ã‚Œã°å…¨ä½“ã‚’ä½¿ç”¨
      idir_r = 1
    endif
    result = base(1: idir_b) // relative(idir_r: )
    call EndSub('urlresolve', '4 result=%c', c1=trim(result))
  end function url_resolve_c

end module