dc_url.f90
Go to the documentation of this file.
1 !== dc_url.f90 - 変数 URL の文字列解析
2 !
3 ! Authors:: Yasuhiro MORIKAWA, Eizi TOYODA
4 ! Version:: $Id: dc_url.f90,v 1.1 2009-03-20 09:09:52 morikawa Exp $
5 ! Tag Name:: $Name: $
6 ! Copyright:: Copyright (C) GFD Dennou Club, 2000-2005. All rights reserved.
7 ! License:: See COPYRIGHT[link:../../COPYRIGHT]
8 !
9 ! This file provides dc_url
10 !
11 
12 module dc_url
13  !
14  !== Overview
15  !
16  ! このモジュールは gtool4 変数 URL の文字列解析
17  ! を行うための手続きを提供します。
18  !
19  ! gtool4 変数の書式に関しては,
20  ! {gtool4 netCDF 規約}[link:../xref.htm#label-6]
21  ! の「5. 各種の文字列書式」を参照ください。
22  !
23  !== Procedures Summary
24  !
25  ! 手続き群の要約
26  !
27  ! UrlSplit :: 変数 URL を分解しファイル名、変数名、
28  ! 属性名および入出力範囲指定を取り出す
29  ! UrlMerge :: ファイル名、変数名、属性名および入出力範囲指定
30  ! を連結して変数 URL を作成
31  ! UrlResolve :: 変数 URL の補完
32  ! Url_Chop_IOrange :: 変数 URL から iorange を除去
33  ! UrlSearchIORange :: 変数 URL 内の iorange うち, ある次元に関する
34  ! 入出力範囲指定の値を取得
35  ! dc_url#operator(.OnTheSameFile.) :: 2 つの変数 URL
36  ! が同じファイルを指すかどうか判定
37  !
38  ! このモジュールは gtool4 変数において特別な役割を果たす
39  ! 文字のニーモニックを提供します。gtool4 変数解析の際には、
40  ! 直接文字を用いるのではなく、ここで提供する変数群
41  ! (GT_ATMARK 等) を利用してください。
42  !
43 
44 
45  implicit none
46  private
47 
48  public:: url_chop_iorange
49  public:: operator(.onthesamefile.)
50 
51  public:: urlmerge
52  interface urlmerge
53 ! module procedure url_merge_v_vvv
54  module procedure url_merge_cc
55  module procedure url_merge_cccc
56  module procedure url_merge_cccca
57  end interface
58 
59  public:: urlsplit
60  interface urlsplit
61 ! module procedure url_split_v
62  module procedure url_split_c
63  end interface
64 
65  public:: urlresolve
66  interface urlresolve
67  module procedure url_resolve_c
68  end interface
69 
70  public:: urlsearchiorange
71  interface urlsearchiorange
72  module procedure url_search_iorange
73  end interface
74 
75  interface operator(.onthesamefile.)
76  module procedure urlonthesamefile
77  end interface
78 
79  character, public, parameter:: gt_atmark = "@"
80  ! ファイル名と変数名の区切りに用いられます。
81  character, public, parameter:: gt_question = "?"
82  ! ファイル名と変数名の区切りに用いられます。
83  character, public, parameter:: gt_colon = ":"
84  ! 変数の属性を示す時に用いられます。
85  character, public, parameter:: gt_comma = ","
86  ! 入出力範囲の限定に用いられます。
87  character, public, parameter:: gt_equal = "="
88  ! 入出力範囲の限定に用いられます。
89  character, public, parameter:: gt_circumflex = "^"
90  ! 座標の位置を値ではなく、
91  ! 格子点番号で指定する時に用いられます。
92  character, public, parameter:: gt_plus = "+"
93  ! 属性の行頭にこの文字がつく場合、大域属性を示します。
94 
95 contains
96 
97  ! ANUrlMerge - 変数 URL の合成
98  ! 空文字列の成分はないとみなされる。
99 
100 ! type(VSTRING) function &
101 ! & url_merge_v_vvv(file, var, attr, iorange) result(result) !:nodoc:
102 ! use dcstring_base, only: VSTRING, operator(.cat.), operator(/=), &
103 ! & extract, operator(==) !:nodoc:
104 ! implicit none
105 ! type(VSTRING), intent(in):: file
106 ! type(VSTRING), intent(in), optional:: var
107 ! type(VSTRING), intent(in), optional:: attr
108 ! type(VSTRING), intent(in), optional:: iorange
109 ! result = file .cat. GT_ATMARK
110 ! if (present(var)) result = result .cat. var
111 ! if (present(attr)) then
112 ! if (attr /= "") result = result .cat. GT_COLON .cat. attr
113 ! endif
114 ! if (present(iorange)) then
115 ! if (extract(iorange, 1, 1) == GT_COMMA) then
116 ! result = result .cat. iorange
117 ! else if (iorange /= "") then
118 ! result = result .cat. GT_COMMA .cat. iorange
119 ! endif
120 ! endif
121 ! end function
122 
123  function url_merge_cc(file, var) result(result)
124  !
125  ! ファイル名 file、変数名 var を結合して relsult として返します。
126  !
127  use dc_types, only: string
128  character(len = STRING):: result
129  character(len = *), intent(in):: file
130  character(len = *), intent(in):: var
131  continue
132  result = url_merge_cccc(file, var, "", "")
133  end function url_merge_cc
134 
135  function url_merge_cccca(file, var, attr, iorange) result(result)
136  !
137  ! ファイル名 file、変数名 var、属性 attr、
138  ! 入出力範囲 iorange を結合して relsult として返します。
139  ! iorange には文字型配列を与えます。文字型配列のそれぞれの要素は
140  ! GT_COMMA で連結されてから結合されます。
141  !
142  use dc_types, only: string
143  character(len = STRING):: result
144  character(len = *), intent(in):: file
145  character(len = *), intent(in):: var
146  character(len = *), intent(in):: attr
147  character(len = *), intent(in):: iorange(:)
148  integer:: i
149  continue
150  if (file /= "") then
151  result = trim(file) // gt_atmark
152  else
153  result = gt_atmark
154  endif
155  if (var /= "") result = trim(result) // var
156  if (attr /= "") then
157  result = trim(result) // gt_colon // attr
158  endif
159  do i = 1, size(iorange)
160  if (iorange(i) /= "") then
161  if (iorange(i)(1:1) == gt_comma) then
162  result = trim(result) // trim(iorange(i))
163  else
164  result = trim(result) // gt_comma // trim(iorange(i))
165  endif
166  endif
167  end do
168  end function url_merge_cccca
169 
170  function url_merge_cccc(file, var, attr, iorange) result(result)
171  !
172  ! ファイル名 file、変数名 var、属性 attr、
173  ! 入出力範囲 iorange を結合して relsult として返します。
174  !
175  use dc_types, only: string
176  character(len = STRING):: result
177  character(len = *), intent(in):: file
178  character(len = *), intent(in):: var
179  character(len = *), intent(in):: attr
180  character(len = *), intent(in):: iorange
181  continue
182  if (trim(file) /= "") then
183  result = trim(file) // gt_atmark
184  else
185  result = gt_atmark
186  endif
187  if (trim(var) /= "") result = trim(result) // var
188  if (trim(attr) /= "") then
189  result = trim(result) // gt_colon // attr
190  endif
191  if (trim(iorange) /= "") then
192  if (iorange(1:1) == gt_comma) then
193  result = trim(result) // iorange
194  else
195  result = trim(result) // gt_comma // iorange
196  endif
197  endif
198  end function url_merge_cccc
199 
200  subroutine url_chop_iorange(fullname, iorange, remainder)
201  !
202  ! fullname で与えられる変数 URL の入出力範囲指定部分と
203  ! 残りの部分とを分離し、それぞれ iorange と remainder に返します。
204  !
205  use dc_types, only: string
206  character(len = *), intent(in):: fullname
207  character(len = *), intent(out):: iorange ! 入出力範囲指定部分
208  character(len = *), intent(out):: remainder ! 残りの部分
209  character(STRING):: file, var, attr
210  call urlsplit(fullname, file=file, var=var, attr=attr, iorange=iorange)
211  remainder = url_merge_cccc(file=file, var=var, attr=attr, iorange="")
212  end subroutine url_chop_iorange
213 
214  function url_search_iorange(fullname, dimvar) result(result)
215  !
216  ! 変数 URL *fullname* 内の, 次元 *dimvar* に関する
217  ! 入出力範囲指定の値を取得します。
218  !
219  ! fullname には gtool4 変数全体または入出力範囲指定部分の値を与えます。
220  ! dimvar には入出力範囲指定部分に含まれる次元変数名を与えます。
221  ! dimvar に対応する次元変数が存在する場合、その値を返します。
222  ! dimvar に対応する次元変数が存在しない場合、空文字を返します。
223  !
224  use dc_types, only: string
225  use dc_string, only: split
226  character(len = *), intent(in):: fullname
227  character(len = *), intent(in):: dimvar
228  character(len = STRING):: result
229  character(STRING):: file, var, attr, iorange
230  character(STRING), pointer :: ioranges_slice(:) => null()
231  integer :: i, eqpos, atmark
232  continue
233  result = ""
234  ! @ または ? が含まれているなら urlsplit で分離
235  atmark = index(fullname, gt_question)
236  if (atmark == 0) atmark = index(fullname, gt_atmark)
237  if (atmark /= 0) then
238  call urlsplit(fullname, file=file, var=var, attr=attr, iorange=iorange)
239  else
240  iorange = fullname
241  end if
242  call split(iorange, ioranges_slice, gt_comma)
243  do i = 1, size(ioranges_slice)
244  eqpos = index(ioranges_slice(i), gt_equal)
245  if (ioranges_slice(i)(1:eqpos-1) == trim(dimvar)) then
246  result = trim(ioranges_slice(i)(eqpos+1:))
247  exit
248  end if
249  end do
250  deallocate(ioranges_slice)
251  end function url_search_iorange
252 
253  subroutine url_split_c(fullname, file, var, attr, iorange)
254  !
255  ! fullname で与えられる変数 URL を、ファイル名 file、 変数名 var、
256  ! 属性名 attr、入出力範囲指定 iorange に分解して返します。
257  ! 見つからない成分には空文字列が代入されます。
258  !
259  use dc_types, only: string
260  character(len = *), intent(in):: fullname
261  character(len = *), intent(out), optional:: file, var, attr, iorange
262  character(len = STRING):: varpart
263  integer:: atmark, colon, comma
264  character(len = *), parameter:: VARNAME_SET &
265  = "0123456789eEdD+-=^,.:_" &
266  // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" &
267  // "abcdefghijklmnopqrstuvwxyz"
268  continue
269  ! まず URL と変数属性指定 (? または @ 以降) を分離する。
270  ! URL は @ を含みうるため、最後の @ 以降に対して変数属性
271  ! として許されない文字(典型的には '/')が含まれていたら
272  ! 当該 @ は URL の一部とみなす。
273  atmark = index(fullname, gt_question)
274  if (atmark == 0) then
275  atmark = index(fullname, gt_atmark, back=.true.)
276  if (atmark /= 0) then
277  if (verify(trim(fullname(atmark+1: )), varname_set) /= 0) then
278  atmark = 0
279  endif
280  endif
281  endif
282  if (atmark == 0) then
283  ! 変数属性指定はなかった。
284  if (present(file)) file = fullname
285  if (present(var)) var = ''
286  if (present(attr)) attr = ''
287  if (present(iorange)) iorange = ''
288  return
289  endif
290  varpart = fullname(atmark+1: )
291  ! 変数属性指定があった。
292  if (present(file)) file = fullname(1: atmark - 1)
293  ! 範囲指定を探索する。
294  comma = index(varpart, gt_comma)
295  if (comma /= 0) then
296  ! 範囲指定がみつかった。
297  if (present(var)) var = varpart(1: comma - 1)
298  if (present(attr)) attr = ''
299  if (present(iorange)) iorange = varpart(comma + 1: )
300  return
301  endif
302  if (present(iorange)) iorange = ''
303  ! 範囲指定がなかったので、属性名の検索をする。
304  colon = index(varpart, gt_colon)
305  if (colon == 0) then
306  if (present(var)) var = varpart
307  if (present(attr)) attr = ''
308  varpart = ''
309  return
310  endif
311  if (present(var)) var = varpart(1: colon - 1)
312  if (present(attr)) attr = varpart(colon + 1: )
313  varpart = ''
314  end subroutine url_split_c
315 
316 ! subroutine url_split_v(fullname, file, var, attr, iorange) !:nodoc:
317 ! use dcstring_base, only: VSTRING, operator(.cat.), operator(/=), &
318 ! & extract, operator(==) !:nodoc:
319 ! use dc_string
320 ! implicit none
321 ! type(VSTRING), intent(in):: fullname
322 ! type(VSTRING), intent(out), optional:: file, var, attr, iorange
323 ! type(VSTRING):: varpart
324 ! integer:: atmark, colon, comma
325 ! character(len = *), parameter:: VARNAME_SET &
326 ! = "0123456789eEdD+-=^,.:_" &
327 ! // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" &
328 ! // "abcdefghijklmnopqrstuvwxyz"
329 ! continue
330 ! ! まず URL と変数属性指定 (? または @ 以降) を分離する。
331 ! ! URL は @ を含みうるため、最後の @ 以降に対して変数属性
332 ! ! として許されない文字(典型的には '/')が含まれていたら
333 ! ! 当該 @ は URL の一部とみなす。
334 ! atmark = vindex(fullname, GT_QUESTION)
335 ! if (atmark == 0) then
336 ! atmark = vindex(fullname, GT_ATMARK, .TRUE.)
337 ! if (atmark /= 0) then
338 ! varpart = extract(fullname, atmark + 1)
339 ! if (vverify(varpart, VARNAME_SET) /= 0) then
340 ! atmark = 0
341 ! endif
342 ! endif
343 ! endif
344 ! if (atmark == 0) then
345 ! ! 変数属性指定はなかった。
346 ! if (present(file)) file = fullname
347 ! if (present(var)) var = ''
348 ! if (present(attr)) attr = ''
349 ! if (present(iorange)) iorange = ''
350 ! return
351 ! endif
352 ! varpart = extract(fullname, atmark + 1)
353 ! ! 変数属性指定があった。
354 ! if (present(file)) file = extract(fullname, 1, atmark - 1)
355 ! ! 範囲指定を探索する。
356 ! comma = vindex(varpart, GT_COMMA)
357 ! if (comma /= 0) then
358 ! ! 範囲指定がみつかった。
359 ! if (present(var)) var = extract(varpart, 1, comma - 1)
360 ! if (present(attr)) attr = ''
361 ! if (present(iorange)) iorange = extract(varpart, comma + 1)
362 ! return
363 ! endif
364 ! if (present(iorange)) iorange = ''
365 ! ! 範囲指定がなかったので、属性名の検索をする。
366 ! colon = vindex(varpart, GT_COLON)
367 ! if (colon == 0) then
368 ! if (present(var)) var = varpart
369 ! if (present(attr)) attr = ''
370 ! varpart = ''
371 ! return
372 ! endif
373 ! if (present(var)) var = extract(varpart, 1, colon - 1)
374 ! if (present(attr)) attr = extract(varpart, colon + 1)
375 ! varpart = ''
376 ! end subroutine url_split_v
377 
378  !
379  ! === 同じファイルに載っているかどうか判定 ===
380  !
381 
382  logical function urlonthesamefile(url_a, url_b) result(result)
383  !
384  ! 1 つ目の引数に与えられる変数 URL と 2 つ目の引数に与えられる
385  ! 変数 URL とが同じファイルを指しているかどうか判定します。
386  ! もしも同じファイルであれば <b><tt>.true.</tt></b> を、
387  ! 異なるファイルであれば <b><tt>.false.</tt></b> を返します。
388  !
389  use dc_string
390  use dc_types, only: string
391  character(len = *), intent(in) :: url_a
392  character(len = *), intent(in) :: url_b
393  character(len = STRING) :: filepart_a
394  character(len = STRING) :: filepart_b
395  call urlsplit(url_a, file=filepart_a)
396  call urlsplit(url_b, file=filepart_b)
397  result = (filepart_a == filepart_b)
398  end function urlonthesamefile
399 
400  !
401  ! === 相対リンクを解決 ===
402  !
403 
404  function url_resolve_c(relative, base) result(result)
405  !
406  ! relative で与えられる変数 URL が完全でない (ファイル名、 変数名、
407  ! 属性名、入出力範囲指定のどれかが無い) 場合に、 base
408  ! から補完します。
409  !
410  use dc_string, only: strhead
411  use dc_types, only: string
412  use dc_trace, only: beginsub, endsub, dbgmessage
413  implicit none
414  character(len = *), intent(in):: relative
415  character(len = *), intent(in):: base
416  character(len = STRING):: result
417  integer, parameter:: FILE = 1, var = 2, attr = 3, ior = 4
418  character(len = STRING):: rel(file:ior), bas(file:ior)
419  character(3), parameter:: PATHDELIM = "/:" // achar(94)
420  integer:: idir_r, idir_b
421  continue
422  call beginsub('urlresolve', 'rel=<%c> base=<%c>', c1=relative, c2=base)
423  call urlsplit(trim(relative), file=rel(file), var=rel(var), &
424  & attr=rel(attr), iorange=rel(ior))
425  call dbgmessage('rel -> file=<%c> var=<%c> attr=<%c>', &
426  & c1=trim(rel(file)), c2=trim(rel(var)), &
427  & c3=(trim(rel(attr)) // '> ior=<' // trim(rel(ior))))
428  call urlsplit(base, file=bas(file), var=bas(var), &
429  & attr=bas(attr), iorange=bas(ior))
430  call dbgmessage('base -> file=<%s> var=<%s> attr=<%s> ior=<%s>', &
431  & c1=trim(bas(file)), c2=trim(bas(var)), &
432  & c3=(trim(bas(attr)) // '> ior=<' // trim(bas(ior))))
433  ! --- ファイル名を欠くばあいは単に補う ---
434  if (rel(file) == "") then
435  rel(file) = bas(file)
436  if (rel(var) == "") &
437  & rel(var) = bas(var)
438  result = urlmerge(file=rel(file), var=rel(var), &
439  & attr=rel(attr), iorange=rel(ior))
440  call endsub('urlresolve', '1 result=%c', c1=trim(result))
441  return
442  endif
443  ! --- 絶対パス (と見られる) ファイル名はそのまま使用 ---
444  if (strhead(rel(file), "file:") &
445  & .OR. strhead(rel(file), "http:") &
446  & .OR. strhead(rel(file), "ftp:") &
447  & .OR. strhead(rel(file), "news:") &
448  & .OR. strhead(rel(file), "www") &
449  & .OR. strhead(rel(file), "/") &
450  & .OR. strhead(rel(file), achar(94)) &
451  & .OR. rel(file)(2:2) == ":" &
452  ) then
453  result = relative
454  call endsub('urlresolve', '2 result=%c', c1=trim(result))
455  return
456  endif
457  ! ディレクトリ名の取り出し
458  idir_b = scan(bas(file), pathdelim, back=.true.)
459  if (idir_b == 0) then
460  ! が、できなければ、(エラーとすべきかもしれぬが)
461  ! 相対パスをそのまま使用
462  result = relative
463  call endsub('urlresolve', '3 result=%c', c1=trim(result))
464  return
465  endif
466  ! 相対パスのほうのディレクトリ名の取り出し
467  idir_r = scan(rel(file), pathdelim, back=.true.)
468  if (idir_r == 0) then
469  ! ができなければ全体を使用
470  idir_r = 1
471  endif
472  result = base(1: idir_b) // relative(idir_r: )
473  call endsub('urlresolve', '4 result=%c', c1=trim(result))
474  end function url_resolve_c
475 
476 end module
character, parameter, public gt_comma
Definition: dc_url.f90:85
logical function urlonthesamefile(url_a, url_b)
Definition: dc_url.f90:383
character, parameter, public gt_equal
Definition: dc_url.f90:87
character, parameter, public gt_plus
Definition: dc_url.f90:92
character(len=string) function url_resolve_c(relative, base)
Definition: dc_url.f90:405
character(len=string) function url_merge_cc(file, var)
Definition: dc_url.f90:124
character(len=string) function url_merge_cccc(file, var, attr, iorange)
Definition: dc_url.f90:171
character, parameter, public gt_atmark
Definition: dc_url.f90:79
character(len=string) function url_merge_cccca(file, var, attr, iorange)
Definition: dc_url.f90:136
subroutine url_split_c(fullname, file, var, attr, iorange)
Definition: dc_url.f90:254
subroutine, public url_chop_iorange(fullname, iorange, remainder)
Definition: dc_url.f90:201
subroutine, public dbgmessage(fmt, i, r, d, L, n, c1, c2, c3, ca)
Definition: dc_trace.f90:509
subroutine, public beginsub(name, fmt, i, r, d, L, n, c1, c2, c3, ca, version)
Definition: dc_trace.f90:351
character, parameter, public gt_circumflex
Definition: dc_url.f90:89
character, parameter, public gt_colon
Definition: dc_url.f90:83
文字型変数の操作.
Definition: dc_string.f90:24
種別型パラメタを提供します。
Definition: dc_types.f90:49
character, parameter, public gt_question
Definition: dc_url.f90:81
character(len=string) function url_search_iorange(fullname, dimvar)
Definition: dc_url.f90:215
subroutine, public endsub(name, fmt, i, r, d, L, n, c1, c2, c3, ca)
Definition: dc_trace.f90:446
integer, parameter, public string
文字列を保持する 文字型変数の種別型パラメタ
Definition: dc_types.f90:118