Class dc_url
In: dc_url.f90

Overview

このモジュールは gtool4 変数 URL の文字列解析 を行うための手続きを提供します。

gtool4 変数の書式に関しては, gtool4 netCDF 規約 の「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 等) を利用してください。

Methods

Included Modules

dc_types dc_string dc_trace

Public Instance methods

GT_ATMARK
Constant :
GT_ATMARK = "@" :character, public, parameter
: ファイル名と変数名の区切りに用いられます。
GT_CIRCUMFLEX
Constant :
GT_CIRCUMFLEX = "^" :character, public, parameter
: 座標の位置を値ではなく、 格子点番号で指定する時に用いられます。
GT_COLON
Constant :
GT_COLON = ":" :character, public, parameter
: 変数の属性を示す時に用いられます。
GT_COMMA
Constant :
GT_COMMA = "," :character, public, parameter
: 入出力範囲の限定に用いられます。
GT_EQUAL
Constant :
GT_EQUAL = "=" :character, public, parameter
: 入出力範囲の限定に用いられます。
GT_PLUS
Constant :
GT_PLUS = "+" :character, public, parameter
: 属性の行頭にこの文字がつく場合、大域属性を示します。
GT_QUESTION
Constant :
GT_QUESTION = "?" :character, public, parameter
: ファイル名と変数名の区切りに用いられます。
Function :
result :character(len = STRING)
file :character(len = *), intent(in)
var :character(len = *), intent(in)

ファイル名 file、変数名 var を結合して relsult として返します。

[Source]

  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 :
result :character(len = STRING)
file :character(len = *), intent(in)
var :character(len = *), intent(in)
attr :character(len = *), intent(in)
iorange :character(len = *), intent(in)

ファイル名 file、変数名 var、属性 attr、 入出力範囲 iorange を結合して relsult として返します。

[Source]

  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
Function :
result :character(len = STRING)
file :character(len = *), intent(in)
var :character(len = *), intent(in)
attr :character(len = *), intent(in)
iorange(:) :character(len = *), intent(in)

ファイル名 file、変数名 var、属性 attr、 入出力範囲 iorange を結合して relsult として返します。 iorange には文字型配列を与えます。文字型配列のそれぞれの要素は GT_COMMA で連結されてから結合されます。

[Source]

  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 :
result :character(len = STRING)
relative :character(len = *), intent(in)
base :character(len = *), intent(in)

relative で与えられる変数 URL が完全でない (ファイル名、 変数名、 属性名、入出力範囲指定のどれかが無い) 場合に、 base から補完します。

[Source]

  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
Function :
result :character(len = STRING)
fullname :character(len = *), intent(in)
dimvar :character(len = *), intent(in)

変数 URL fullname 内の, 次元 dimvar に関する 入出力範囲指定の値を取得します。

fullname には gtool4 変数全体または入出力範囲指定部分の値を与えます。 dimvar には入出力範囲指定部分に含まれる次元変数名を与えます。 dimvar に対応する次元変数が存在する場合、その値を返します。 dimvar に対応する次元変数が存在しない場合、空文字を返します。

[Source]

  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 :
fullname :character(len = *), intent(in)
file :character(len = *), intent(out), optional
var :character(len = *), intent(out), optional
attr :character(len = *), intent(out), optional
iorange :character(len = *), intent(out), optional

fullname で与えられる変数 URL を、ファイル名 file、 変数名 var、 属性名 attr、入出力範囲指定 iorange に分解して返します。 見つからない成分には空文字列が代入されます。

[Source]

  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 :
fullname :character(len = *), intent(in)
iorange :character(len = *), intent(out)
: 入出力範囲指定部分
remainder :character(len = *), intent(out)
: 残りの部分

fullname で与えられる変数 URL の入出力範囲指定部分と 残りの部分とを分離し、それぞれ iorange と remainder に返します。

[Source]

  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 :
result :logical
url_a :character(len = *), intent(in)
url_b :character(len = *), intent(in)

1 つ目の引数に与えられる変数 URL と 2 つ目の引数に与えられる 変数 URL とが同じファイルを指しているかどうか判定します。 もしも同じファイルであれば .true. を、 異なるファイルであれば .false. を返します。

[Source]

  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

[Validate]