!= ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®è§£æž
!= Command line arguments parser
!
! Authors::   Yasuhiro MORIKAWA
! Version::   $Id: dc_args.f90,v 1.2 2009-08-09 06:53:11 morikawa Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2005. All rights reserved.
! License::   See COPYRIGHT[link:../../COPYRIGHT]
!

module dc_args
  !
  != ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®è§£æž
  != Command line arguments parser
  !
  ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®è§£æžã‚’è¡Œã„ã¾ã™.
  !
  ! åŠ ãˆã¦, ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®è¡¨ç¤ºã«é–¢ã—ã¦ä¾¿åˆ©ãªã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚‚
  ! ç”¨æ„ã—ã¦ã„ã¾ã™.
  !
  !== Tutorial
  !
  ! * gtool5 ã‚ªãƒ•ã‚£ã‚·ãƒ£ãƒ«ãƒãƒ¥ãƒ¼ãƒˆãƒªã‚¢ãƒ«:
  !   {ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®è§£æž}[link:../tutorial/dc_args.htm]
  !
  !== Procedures list
  !
  ! DCArgsOpen     :: æ§‹é€ åž‹ ARGS å¤‰æ•°ã®åˆæœŸåŒ–
  ! DCArgsClose    :: æ§‹é€ åž‹ ARGS å¤‰æ•°ã®çµ‚äº†å‡¦ç†
  ! DCArgsGet      :: ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®å–å¾—
  ! DCArgsNumber   :: ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®æ•°ã‚’è¿”ã™
  ! DCArgsOption   :: ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’å–å¾—ã™ã‚‹ãŸã‚ã®è¨å®š
  ! DCArgsDebug    :: ãƒ‡ãƒãƒƒã‚°ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®è‡ªå‹•è¨å®š
  ! DCArgsHelp     :: ãƒ˜ãƒ«ãƒ—ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®è‡ªå‹•è¨å®š
  ! DCArgsHelpMsg  :: ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®è¨å®š
  ! DCArgsStrict   :: ç„¡åŠ¹ãªã‚ªãƒ—ã‚·ãƒ§ãƒ³ãŒæŒ‡å®šã•ã‚ŒãŸæ™‚ã«è¦å‘Šã‚’è¡¨ç¤ºã™ã‚‹ã‚ˆã†è¨å®š
  ! DCArgsPutLine  :: æ§‹é€ åž‹ ARGS å¤‰æ•°ã®å†…å®¹ã‚’å°å—
  !
  !
  !== Usage
  !
  ! æ§‹é€ åž‹ ARGS ã®å¤‰æ•°ã‚’å®šç¾©ã—, Open, Get ã‚’åˆ©ç”¨ã™ã‚‹ã“ã¨ã§
  ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã‚’å–å¾—ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™.
  !
  !     program dc_args_sample1
  !       use dc_types
  !       use dc_string, only: StoA
  !       use dc_args
  !       implicit none
  !       type(ARGS) :: arg
  !       character(STRING), pointer :: argv(:) => null()
  !       integer :: i
  !
  !       call DCArgsOpen( arg = arg )   ! (out)
  !       call DCArgsDebug( arg = arg )  ! (inout)
  !       call DCArgsHelp( arg = arg )   ! (inout)
  !       call DCArgsStrict( arg = arg ) ! (inout)
  !       call DCArgsGet( arg = arg, &   ! (inout)
  !         & argv = argv )              ! (out)
  !       do i = 1, size( argv )
  !         write(*,*) argv(i)
  !       end do
  !       deallocate( argv )
  !       call DCArgsClose( arg = arg )  ! (inout)
  !     end program dc_args_sample1
  !
  ! å¼•æ•°ã«ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’æŒ‡å®šã—ãŸã„å ´åˆã«ã¯, DCArgsOption ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’
  ! åˆ©ç”¨ã—ã¦ãã ã•ã„. ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®æ›¸å¼ã«é–¢ã—ã¦ã¯ DCArgsOption ã®
  ! ã€Œã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®æ›¸å¼ã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„.
  !
  !     program dc_args_sample2
  !       use dc_types
  !       use dc_string, only: StoA
  !       use dc_args
  !       implicit none
  !       type(ARGS) :: arg
  !       logical :: OPT_size
  !       logical :: OPT_namelist
  !       character(STRING) :: VAL_namelist
  !
  !       call DCArgsOpen( arg = arg )              ! (out)
  !       call DCArgsOption( arg = arg, &           ! (inout)
  !         & options = StoA('-s', '--size'), &     ! (in)
  !         & flag = OPT_size, &                    ! (out)
  !         & help = "Return number of arguments")  ! (in)
  !       call DCArgsOption( arg = arg, &           ! (inout)
  !         & options = StoA('-N', '--namelist'), & ! (in)
  !         & flag = OPT_namelist, &                ! (out)
  !         & value = VAL_namelist, &               ! (out)
  !         & help = "Namelist filename")           ! (in)
  !
  !       call DCArgsDebug( arg = arg )  ! (inout)
  !       call DCArgsHelp( arg = arg )   ! (inout)
  !       call DCArgsStrict( arg = arg ) ! (inout)
  !
  !       if (OPT_size) then
  !         write(*,*) 'number of arguments :: ', DCArgsNumber(arg)
  !       end if
  !       if (OPT_namelist) then
  !         write(*,*) '--namelist=', trim(VAL_namelist)
  !       else
  !         write(*,*) '--namelist is not found'
  !       end if
  !       call DCArgsClose( arg = arg ) ! (inout)
  !     end program dc_args_sample2
  !
  ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã« '-h', '-H', '--help' ã®ã„ã¥ã‚Œã‹ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’
  ! æŒ‡å®šã™ã‚‹ã“ã¨ã§, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®ä¸€è¦§ãŒæ¨™æº–å‡ºåŠ›ã«è¡¨ç¤ºã•ã‚Œã¾ã™.
  !
  ! ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®å†…å®¹ã‚’å……å®Ÿã•ã›ãŸã„å ´åˆã«ã¯ DCArgsHelpMsg ã‚’
  ! å‚ç…§ã—ã¦ãã ã•ã„.
  !
  !
  !== Note
  !
  !=== å¾Œæ–¹äº’æ›
  !
  ! ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 20071009 ä»¥å‰ã«åˆ©ç”¨å¯èƒ½ã ã£ãŸä»¥ä¸‹ã®æ‰‹ç¶šãã¯,
  ! å¾Œæ–¹äº’æ›ã®ãŸã‚, ã—ã°ã‚‰ãã¯åˆ©ç”¨å¯èƒ½ã§ã™.
  !
  ! * Open, Close, Option, PutLine, Debug, Help, HelpMsg, Strict, Get
  !   Number
  !
  !=== dc_args ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’ä½œæˆã—ãŸç†ç”±ã«ã¤ã„ã¦
  !
  ! Fortran ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ã®ã»ã¨ã‚“ã©ã«ã¯ IARGC, GETARG ã¨ã„ã£ãŸ
  ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°å–å¾—ã®ãŸã‚ã®å‰¯ãƒ—ãƒã‚°ãƒ©ãƒ ãŒç”¨æ„ã•ã‚Œã¦ã„ã‚‹.
  ! ã“ã‚Œã‚‰ã®å‰¯ãƒ—ãƒã‚°ãƒ©ãƒ ã®åˆ©ç”¨ã«ã‚ˆã£ã¦, ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã®å¼•æ•°ã‚’
  ! å˜ã«å–å¾—ã™ã‚‹ã“ã¨ã¯ç°¡å˜ã§ã‚ã‚‹.
  !
  ! ã—ã‹ã—ã“ã® IARGC, GETARG ã®ä½¿ç”¨ã«éš›ã—, 2 ã¤ã»ã©é¢å€’ãªç‚¹ãŒã‚ã‚‹.
  !
  ! 1 ã¤ã¯ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ä¾å˜ã«ã‚ˆã‚‹ IARGC, GETARG ã®ä»•æ§˜ã®é•ã„ã§ã‚ã‚‹.
  ! ã“ã‚Œã‚‰ã®å‰¯ãƒ—ãƒã‚°ãƒ©ãƒ ã¯ Fortran è¦æ ¼ã«å«ã¾ã‚Œãªã„ã‚µãƒ¼ãƒ“ã‚¹ãƒ«ãƒ¼ãƒãƒ³
  ! ã§ã‚ã‚‹ãŸã‚, ãŸã„ã¦ã„ã®ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ã«ã¯ã“ã®å‰¯ãƒ—ãƒã‚°ãƒ©ãƒ ã¯
  ! å˜åœ¨ã™ã‚‹ã‚‚ã®ã®, ä»•æ§˜ãŒå¾®å¦™ã«ç•°ãªã‚‹å ´åˆãŒã‚ã‚‹. (å¤§æŠµã®ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ã¯
  ! GETARG ã®ç¬¬ä¸€å¼•æ•°ã‚’ 1 ã«ã™ã‚‹ã¨ä¸€ã¤ç›®ã®å¼•æ•°ã‚’å–å¾—ã™ã‚‹ãŒ,
  ! å¤ã„ HITACHI ã®ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ã¯ç¬¬ä¸€å¼•æ•°ã‚’ 2 ã«ã—ãªã„ã¨ä¸€ã¤ç›®ã®
  ! å¼•æ•°ã‚’å–å¾—ã§ããªã„, ãªã©). ãã“ã§ gtool5 ãƒ©ã‚¤ãƒ–ãƒ©ãƒªã§ã¯
  ! ã“ã‚Œã‚‰ã®ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ä¾å˜æ€§ã‚’å¸åŽã™ã‚‹è¨è¨ˆã‚’è¡Œã£ã¦ã„ã‚‹.
  ! dc_args ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’ä½¿ç”¨ã™ã‚‹éš›ã«ã¯, ã“ã‚Œã‚‰ã®ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ä¾å˜ã¯
  ! æ°—ã«ã—ãªãã¦ã‚ˆã„. (ãªãŠ, ã‚³ãƒ³ãƒ‘ã‚¤ãƒ©ä¾å˜æ€§ã‚’å®Ÿéš›ã«
  ! å¸åŽã—ã¦ã„ã‚‹ã®ã¯ sysdep ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã§ã‚ã‚‹).
  !
  ! 2 ã¤ç›®ã¯, ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã«ãŠã‘ã‚‹ã‚ªãƒ—ã‚·ãƒ§ãƒ³å¼•æ•°
  ! (-h ã‚„ --version ãªã©) ã®å–ã‚Šæ‰±ã„ã®ä¸ä¾¿ã•ã§ã‚ã‚‹.
  ! IARGC ã‚„ GETARG ã¯å˜ã«å¼•æ•°ã‚’å–å¾—ã™ã‚‹ãŸã‚ã®å‰¯ãƒ—ãƒã‚°ãƒ©ãƒ ã§ã‚ã‚Š,
  ! Perl ã‚„ Ruby ãªã©ã®ã‚¤ãƒ³ã‚¿ãƒ—ãƒªã‚¿è¨€èªžã®ã‚ˆã†ã«,
  ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã«ã‚ªãƒ—ã‚·ãƒ§ãƒ³å¼•æ•°ã‚’å‡¦ç†ã™ã‚‹ãŸã‚ã®
  ! ãƒ©ã‚¤ãƒ–ãƒ©ãƒª (Getopt ã‚„ OptionParser ãªã©) ãŒç”¨æ„ã•ã‚Œã¦ã„ãªã„.
  ! dc_args ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯, Fortran ãƒ—ãƒã‚°ãƒ©ãƒ ã§ã‚‚ã‚ªãƒ—ã‚·ãƒ§ãƒ³å¼•æ•°ã‚’
  ! æ‰‹è»½ã«æ‰±ãˆã‚‹ã‚ˆã†, ã‚ªãƒ—ã‚·ãƒ§ãƒ³å¼•æ•°å‡¦ç†ã®
  ! ãŸã‚ã®ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã‚’ã§ãã‚‹ã ã‘ç°¡ç´ ã«ã™ã‚‹ã¹ãæ•´å‚™ã—ãŸãƒ—ãƒã‚°ãƒ©ãƒ ã§ã‚ã‚‹.
  !
  ! è¨è¨ˆæ€æƒ³ã¯, {ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆæŒ‡å‘ã‚¹ã‚¯ãƒªãƒ—ãƒˆè¨€èªž Ruby}[http://www.ruby-lang.org/]
  ! ã® OptionParser[http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=OptionParser]
  ! ã‚’çœŸä¼¼ã¦ãŠã‚Š, OptionParser ã‚¯ãƒ©ã‚¹ã®ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã‚’
  ! æ§‹é€ åž‹ ARGS ã«, new (initialize) ãƒ¡ã‚½ãƒƒãƒ‰ã‚’ DCArgsOpen ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã«,
  ! on ãƒ¡ã‚½ãƒƒãƒ‰ã‚’ DCArgsOption ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã«, parse ãƒ¡ã‚½ãƒƒãƒ‰ã‚’ DCArgsGet
  ! ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã«è¦‹ç«‹ã¦ã¦ã„ã‚‹. è¨€èªžä»•æ§˜ã®é•ã„ã«ã‚ˆã‚Šå®Ÿè£…ã‚„ä»•æ§˜ã¯
  ! ãã‚Œãªã‚Šã«ç•°ãªã‚‹ãŒ, æ§‹é€ åž‹ ARGS ã®å¤‰æ•°ã‚’ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã«è¦‹ç«‹ã¦,
  ! ã“ã®å¤‰æ•°ã«å¯¾ã—ã¦ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’ä½œç”¨ã•ã›ã‚‹ã“ã¨ã«ã‚ˆã£ã¦
  ! ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã¸ã®æ“ä½œã‚„ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã‹ã‚‰ã®å¼•æ•°æƒ…å ±ã®å–å¾—ã‚’è¡Œã†ã¨ã„ã†ç‚¹ã§ã¯
  ! OptionParser ã¨åŒæ§˜ã§ã‚ã‚‹.
  !
  ! ãŠã¾ã‘çš„æ©Ÿèƒ½ã§ã‚ã‚‹ãŒ, dc_trace ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¨ã®é€£æºã‚‚å›³ã‚‰ã‚Œã¦ãŠã‚Š,
  ! Debug ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’ä½¿ç”¨ã™ã‚‹ã“ã¨ã«ã‚ˆã‚Š (ä½¿ç”¨æ³•ã¯ä¸Šè¨˜å‚ç…§), å†ã‚³ãƒ³
  ! ãƒ‘ã‚¤ãƒ«ã™ã‚‹ã“ã¨ãªã, ãƒ—ãƒã‚°ãƒ©ãƒ ã®å®Ÿè¡Œã®éš›ã« "-D" ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’ã¤ã‘ã‚‹
  ! ã“ã¨ã§ãƒ‡ãƒãƒƒã‚°ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’è¡¨ç¤ºã™ã‚‹ãƒ¢ãƒ¼ãƒ‰ã«å¤‰æ›´ã™ã‚‹ã“ã¨ã‚‚ã§ãã‚‹.
  !

  use dc_types, only : STRING
  use dc_hash, only: HASH
  implicit none
  private

  public:: ARGS
  public:: DCArgsOpen, DCArgsClose, DCArgsOption
  public:: DCArgsPutLine, DCArgsDebug, DCArgsHelp
  public:: DCArgsHelpMsg, DCArgsStrict, DCArgsGet
  public:: DCArgsNumber

  !-----------------------------------------------
  ! å¾Œæ–¹äº’æ›ç”¨
  ! For backward compatibility
  public:: Open, Close, Option, PutLine, Debug, Help, HelpMsg, Strict, Get
  public:: Number

  type ARGS
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°è§£æžç”¨ã®æ§‹é€ ä½“ã§ã™.
    ! åˆæœŸåŒ–ã«ã¯ DCArgsOpen ã‚’, çµ‚äº†å‡¦ç†ã«ã¯ DCArgsClose ã‚’ç”¨ã„ã¾ã™.
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã«ä¸Žãˆã‚‰ã‚Œã‚‹å¼•æ•°ã‚„, ãƒ—ãƒã‚°ãƒ©ãƒ å†…ã§
    ! DCArgsOption, DCArgsHelpMsg ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã«ã‚ˆã£ã¦ä¸Žãˆã‚‰ã‚ŒãŸæƒ…å ±ã‚’
    ! æ ¼ç´ã—ã¾ã™.
    !
    ! è©³ã—ã„ä½¿ã„æ–¹ã¯ dc_args ã® Usage ã‚’å‚ç…§ãã ã•ã„.
    !
    private
    type(OPT_ENTRY), pointer :: opt_table(:) => null()
                              ! DCArgsOption ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã§æŒ‡å®šã•ã‚Œã‚‹
                              ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®ãƒªã‚¹ãƒˆ
    logical :: initialized = .false.
    type(CMD_OPTS_INTERNAL), pointer :: cmd_opts_list(:) => null()
                              ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã†ã¡, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨
                              ! ã—ã¦è˜åˆ¥ã•ã‚Œã‚‹ã‚‚ã®ã®ã®ãƒªã‚¹ãƒˆ.
    type(HASH) :: helpmsg
  end type ARGS

  type OPT_ENTRY
    character(STRING), pointer:: options(:) => null()
                              ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³åãƒªã‚¹ãƒˆ
    character(STRING) :: help_message
                              ! ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸
    logical :: optvalue_flag
                              ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®å€¤ã®æœ‰ç„¡
  end type OPT_ENTRY

  type CMD_OPTS_INTERNAL
    character(STRING) :: name  ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³å
    character(STRING) :: value ! å€¤
    logical:: flag_called = .false.
                              ! ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³åãŒ DCArgsOption ã§å‘¼ã°ã‚ŒãŸã‚‚ã®
                              ! ã‹ã©ã†ã‹ã‚’åˆ¤åˆ¥ã™ã‚‹ãƒ•ãƒ©ã‚°
  end type CMD_OPTS_INTERNAL

  interface DCArgsOpen
    module procedure DCArgsOpen0
  end interface

  interface DCArgsClose
    module procedure DCArgsClose0
  end interface

  interface DCArgsOption
    module procedure DCArgsOption0
  end interface

  interface DCArgsPutLine
    module procedure DCArgsPutLine0
  end interface

  interface DCArgsDebug
    module procedure DCArgsDebug0
  end interface

  interface DCArgsHelp
    module procedure DCArgsHelp0
  end interface

  interface DCArgsHelpMsg
    module procedure DCArgsHelpMsg0
  end interface

  interface DCArgsStrict
    module procedure DCArgsStrict0
  end interface

  interface DCArgsGet
    module procedure DCArgsGet0
  end interface

  interface DCArgsNumber
    module procedure DCArgsNumber0
  end interface

  !-----------------------------------------------
  ! å¾Œæ–¹äº’æ›ç”¨
  ! For backward compatibility
  interface Open
    module procedure DCArgsOpen0
  end interface

  interface Close
    module procedure DCArgsClose0
  end interface

  interface Option
    module procedure DCArgsOption0
  end interface

  interface PutLine
    module procedure DCArgsPutLine0
  end interface

  interface Debug
    module procedure DCArgsDebug0
  end interface

  interface Help
    module procedure DCArgsHelp0
  end interface

  interface HelpMsg
    module procedure DCArgsHelpMsg0
  end interface

  interface Strict
    module procedure DCArgsStrict0
  end interface

  interface Get
    module procedure DCArgsGet0
  end interface

  interface Number
    module procedure DCArgsNumber0
  end interface

  !-------------------------------------
  ! BuildArgTable ã§è¨å®šã•ã‚Œã‚‹å¤‰æ•°
  character(STRING), allocatable, save:: argstr_table(:)
                              ! å…¨å¼•æ•°ã®å†…å®¹. (ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‹ã©ã†ã‹ãªã©
                              ! ã®åˆ¤åˆ¥ã¯è¡Œã£ã¦ã„ãªã„). BuildArgTable
                              ! ã§è¨å®šã•ã‚Œã‚‹.

  integer, save:: argind_count = -1
                              ! å…¨å¼•æ•°ã®æ•°. BuildArgTable ã§
                              ! è¨å®šã•ã‚Œã‚‹.

  !-------------------------------------
  ! SortArgTable ã§è¨å®šã•ã‚Œã‚‹å¤‰æ•°
  type(CMD_OPTS_INTERNAL), allocatable, save :: cmd_opts_list(:)
                              ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã†ã¡, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨
                              ! ã—ã¦è˜åˆ¥ã•ã‚Œã‚‹ã‚‚ã®ã®ã®ãƒªã‚¹
                              ! ãƒˆ. SortArgTable ã§è¨å®šã•ã‚Œã‚‹.

  character(STRING), allocatable, save:: cmd_argv_list(:)
                              ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã†ã¡, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã§
                              ! ã¯ãªã„å¼•æ•°ã®ãƒªã‚¹ãƒˆ. SortArgTable ã§è¨
                              ! å®šã•ã‚Œã‚‹.

contains

  subroutine DCArgsOpen0(arg)
    !
    ! ARGS åž‹ã®å¤‰æ•°ã‚’åˆæœŸè¨å®šã—ã¾ã™.
    !
    ! ARGS åž‹ã®å¤‰æ•°ã‚’åˆ©ç”¨ã™ã‚‹éš›ã«ã¯ã¾ãšã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã«ã‚ˆã£ã¦
    ! åˆæœŸè¨å®šã‚’è¡Œã£ã¦ãã ã•ã„.
    !
    ! ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã¯, ã‚ˆã‚Šä¸‹å±¤ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³å†…ã§ IARGC ã‚„ GETARG
    ! ã‚’ç”¨ã„ã¦å¾—ã‚‰ã‚ŒãŸã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®æƒ…å ±ã‚’å¼•æ•° *arg*
    ! ã¸ã¨æ ¼ç´ã—ã¾ã™.
    !
    use dc_message, only: MessageNotify
    use dc_types, only: STRING
    implicit none
    type(ARGS), intent(out) :: arg
    integer:: cmd_opts_max
    character(len = *), parameter :: subname = 'DCArgsOpen'
  continue
    if (arg % initialized) then
      call MessageNotify('W', subname, 'This argument (type ARGS) is already opend.')
      return
    end if
    call BuildArgTable
    call SortArgTable
    cmd_opts_max = size(cmd_opts_list)
    allocate(arg % cmd_opts_list(cmd_opts_max))
    arg % cmd_opts_list = cmd_opts_list
    nullify( arg % opt_table )
    arg % initialized = .true.
  end subroutine DCArgsOpen0

  subroutine DCArgsClose0(arg)
    !
    ! ARGS åž‹ã®å¤‰æ•°ã®çµ‚äº†å‡¦ç†ã‚’è¡Œã„ã¾ã™.
    !
    use dc_hash, only: DCHashDelete
    implicit none
    type(ARGS), intent(inout) :: arg
    integer :: i
  continue
    if (arg % initialized) then
      if ( associated( arg % opt_table ) ) then
        do i = 1, size(arg % opt_table)
          deallocate(arg % opt_table(i) % options)
        end do

        deallocate(arg % opt_table)
      end if

      deallocate(arg % cmd_opts_list)
      deallocate(argstr_table)
      deallocate(cmd_argv_list)
      deallocate(cmd_opts_list)

      call DCHashDelete(arg % helpmsg)
    end if
  end subroutine DCArgsClose0

  subroutine DCArgsOption0(arg, options, flag, value, help)
    !
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³æƒ…å ±ã®ç™»éŒ²ã¨å–å¾—ã‚’è¡Œã„ã¾ã™.
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã†ã¡, *options* ã«ä¸Žãˆã‚‹ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã«é–¢ã™ã‚‹æƒ…
    ! å ±ã‚’ *flag* ã¨ *value* ã«å–å¾—ã—ã¾ã™. *options* ãŒã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³
    ! å¼•æ•°ã«ä¸Žãˆã‚‰ã‚Œã¦ã„ã‚Œã° *flag* ã« .true. ãŒ, ãã†ã§ãªã„å ´åˆã¯
    ! .false. ãŒè¿”ã‚Šã¾ã™. ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã«å€¤ãŒæŒ‡å®šã•ã‚Œã‚‹å ´åˆã¯ *value* ã«
    ! ãã®å€¤ãŒè¿”ã‚Šã¾ã™. ã‚ªãƒ—ã‚·ãƒ§ãƒ³è‡ªä½“ãŒä¸Žãˆã‚‰ã‚Œã¦ã„ãªã„å ´åˆã«ã¯
    ! *value* ã«ã¯ç©ºæ–‡å—ãŒè¿”ã‚Šã¾ã™.
    !
    ! *help* ã«ã¯ *options* ã«é–¢ã™ã‚‹ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’ *arg* ã«
    ! ç™»éŒ²ã—ã¾ã™. ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ DCArgsHelp ã‚’
    ! ç”¨ã„ãŸéš›ã«, ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒå‡ºåŠ›ã•ã‚Œã¾ã™.
    ! *value* ã‚’ä¸Žãˆã¦ã„ã‚‹ã‹ã©ã†ã‹ã§ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã¯å¤‰åŒ–ã—ã¾ã™.
    !
    !=== ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®æ›¸å¼
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã†ã¡, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨åˆ¤å®šã•ã‚Œã‚‹ã®ã¯ä»¥ä¸‹ã®å ´åˆã§ã™.
    !
    ! * 1 æ–‡å—ç›®ãŒ '-' ã®å ´åˆ. ã“ã®å ´åˆã¯çŸã„ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ãªã‚Š, '-'
    !   ã®æ¬¡ã®ä¸€æ–‡å—ã®ã¿ãŒã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ã—ã¦æœ‰åŠ¹ã«ãªã‚Šã¾ã™.
    !
    ! * 1-2æ–‡å—ç›®ãŒ '--' (ãƒã‚¤ãƒ•ãƒ³ 2 æ–‡å—) ã®å ´åˆ.
    !   ã“ã®å ´åˆã¯é•·ã„ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ãªã‚Š,
    !   '--' ä»¥é™ã®æ–‡å—åˆ—ãŒã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ã—ã¦æœ‰åŠ¹ã«ãªã‚Šã¾ã™.
    !
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®å€¤ã¯, "=" ã‚ˆã‚Šã‚‚å¾Œã‚ã®æ–‡å—åˆ—ã«ãªã‚Šã¾ã™.
    !
    ! ä¾‹
    !
    ! <b>ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°</b>  :: <b>ã‚ªãƒ—ã‚·ãƒ§ãƒ³å, å€¤      </b>
    ! -h                         ::    -h,           ç„¡ã—
    ! --help                     ::    --help,       ç„¡ã—
    ! -D=6                       ::    -D,            6
    ! -debug=                    ::    -d,           ç„¡ã—
    ! --include=/usr             ::    --include,    /usr
    !

    use dc_message, only: MessageNotify
    implicit none
    type(ARGS), intent(inout) :: arg
    character(len = *), intent(in) :: options(:)
    logical, intent(out) :: flag
    character(len = *), intent(out), optional :: value
    character(len = *), intent(in), optional :: help
    integer :: i, j, options_size, table_size
    type(OPT_ENTRY), allocatable :: local_tables(:)
    character(len = STRING) :: opt_name, opt_value, opt_full
    character(len = *), parameter  :: subname = 'DCArgsOption'
  continue
    flag = .false.
    if (present(value)) value = ''
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Option in dc_args.')
      call DCArgsOpen(arg)
    end if
    options_size = size(options)
    if (options_size < 1) then
      return
    end if

    !-----------------------------------
    ! æ§‹é€ ä½“ ARGS ã¸ã®ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ç”¨ã®æƒ…å ±ç™»éŒ²
    ! * ã¾ãšã¯ãƒ†ãƒ¼ãƒ–ãƒ« arg % opt_table ã‚’ä¸€ã¤åºƒã’ã‚‹.
    !-----------------------------------
    if ( .not. associated( arg % opt_table ) ) then
      ! 1 ã¤ã‚ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³æŒ‡å®š
      !
      table_size = 0
      allocate(arg % opt_table(table_size + 1))
    else
      ! 2 ã¤ã‚ä»¥é™ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³æŒ‡å®š
      !
      table_size = size(arg % opt_table)
      allocate(local_tables(table_size))
      local_tables(1:table_size) = arg % opt_table(1:table_size)
      deallocate(arg % opt_table)
      allocate(arg % opt_table(table_size + 1))
      arg % opt_table(1:table_size) = local_tables(1:table_size)
      deallocate(local_tables)
    end if

    !----- å€¤ã®ä»£å…¥ -----
    allocate(arg % opt_table(table_size + 1) % options(options_size))
    arg % opt_table(table_size + 1) % options = options
    arg % opt_table(table_size + 1) % help_message = ''
    if (present(help)) then
      arg % opt_table(table_size + 1) % help_message = help
    end if
    arg % opt_table(table_size + 1) % optvalue_flag = present(value)

    !----- options ã®æ£è¦åŒ– -----
    do i = 1, options_size
      opt_full = arg % opt_table(table_size + 1) % options(i)
      if (DCOptionFormC(opt_full, opt_name, opt_value)) then
        arg % opt_table(table_size + 1) % options(i) = opt_name
      else
        if (len(trim(adjustl(opt_full))) < 2) then
          arg % opt_table(table_size + 1) % options(i) = &
            & '-' // trim(adjustl(opt_full))
        else
          arg % opt_table(table_size + 1) % options(i) = &
            & '--' // trim(adjustl(opt_full))
        end if
      end if
    end do

    ! arg % cmd_opts_list å†…ã®æŽ¢æŸ»ã¨ flag, value ã¸ã®ä»£å…¥
    ! å‘¼ã°ã‚ŒãŸã‚‚ã®ã«é–¢ã—ã¦ã¯ arg % cmd_opts_list % flag_called ã‚’
    ! .true. ã«
    do i = 1, options_size
      do j = 1, size(arg % cmd_opts_list)
        if (trim(arg % opt_table(table_size + 1) % options(i)) &
          &             == trim(arg % cmd_opts_list(j) % name)) then
          flag = .true.
          if (present(value)) then
            value = arg % cmd_opts_list(j) % value
          end if
          arg % cmd_opts_list(j) % flag_called = .true.
        end if
      end do
    end do
  end subroutine DCArgsOption0

  subroutine DCArgsDebug0(arg)
    !
    ! ãƒ‡ãƒãƒƒã‚°ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®è‡ªå‹•è¨å®šã‚’è¡Œã„ã¾ã™.
    !
    ! -D ã‚‚ã—ãã¯ --debug ãŒæŒ‡å®šã•ã‚ŒãŸéš›, è‡ªå‹•çš„ã«
    ! dc_trace#SetDebug ã‚’å‘¼ã³å‡ºã™ã‚ˆã† *arg* ã‚’è¨å®šã—ã¾ã™.
    !
    use dc_types, only: STRING
    use dc_string, only: StoA, StoI
    use dc_trace, only: SetDebug
    use dc_message, only: MessageNotify
    implicit none
    type(ARGS), intent(inout) :: arg
    logical :: OPT_debug
    character(STRING) :: VAL_debug
    character(len = *), parameter  :: subname = 'DCArgsDebug'
  continue
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Debug in dc_args.')
      call DCArgsOpen(arg)
    end if
    call Option(arg, StoA('-D', '--debug'), OPT_debug, VAL_debug, &
      & help="call dc_trace#SetDebug (display a lot of messages for debug). " // &
      & "VAL is unit number (default is standard output)")
    if (OPT_debug) then
      if (trim(VAL_debug) == '') then
        call SetDebug
      else
        call SetDebug(StoI(VAL_debug))
      end if
    end if
    return
  end subroutine DCArgsDebug0

  subroutine DCArgsHelp0(arg, force)
    !
    ! ãƒ˜ãƒ«ãƒ—ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®è‡ªå‹•è¨å®šã‚’è¡Œã„ã¾ã™.
    !
    ! -h, -H, --help ã®ã„ã¥ã‚Œã‹ãŒæŒ‡å®šã•ã‚ŒãŸéš›, è‡ªå‹•çš„ã« *arg* å†…ã«è¨å®šã•ã‚ŒãŸ
    ! æƒ…å ±ã‚’ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã¨ã—ã¦è¡¨ç¤ºã—ãŸå¾Œ, ãƒ—ãƒã‚°ãƒ©ãƒ ã‚’çµ‚äº†ã•ã›ã¾ã™.
    ! åŽŸå‰‡çš„ã«, ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚ˆã‚Šã‚‚å‰ã« DCArgsOption, DCArgsDebug
    ! ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’å‘¼ã‚“ã§ä¸‹ã•ã„.
    !
    ! *force* ã« .true. ãŒæŒ‡å®šã•ã‚Œã‚‹å ´åˆ, -H, --help ã‚ªãƒ—ã‚·ãƒ§ãƒ³ãŒä¸Žãˆ
    ! ã‚‰ã‚Œãªã„å ´åˆã§ã‚‚ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’è¡¨ç¤ºã—ãŸå¾Œ, ãƒ—ãƒã‚°ãƒ©ãƒ ã‚’çµ‚äº†ã•
    ! ã›ã¾ã™.
    !
    ! ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã«è¡¨ç¤ºã•ã‚Œã‚‹æƒ…å ±ã¯, DCArgsOption, DCArgsHelpMsg
    ! ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã«ã‚ˆã£ã¦ä»˜åŠ ã™ã‚‹ã“ã¨ãŒå¯èƒ½ã§ã™.
    !
    use dc_types, only: STRING, STDOUT
    use dc_string, only: StoA, StoI, Printf, Concat, JoinChar, UChar, LChar
    use dc_present, only: present_and_true
    use dc_message, only: MessageNotify
    use dc_hash, only: DCHashGet, DCHashDelete, DCHashRewind, DCHashNext
    implicit none
    type(ARGS), intent(inout) :: arg
    logical, intent(in), optional :: force
    logical :: OPT_help, found, end
    character(STRING) :: VAL_help, options_msg, help_msg, category
    character(STRING), pointer :: localopts(:) => null()
    integer :: unit, i
    character(len = *), parameter  :: subname = 'DCArgsHelp'
  continue
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Help in dc_args.')
      call DCArgsOpen(arg)
    end if
    call DCArgsOption(arg, StoA('-h', '-H', '--help'), OPT_help, VAL_help, &
      & help="display this help and exit. " // &
      & "VAL is unit number (default is standard output)")
    if (.not. OPT_help .and. .not. present_and_true(force)) then
      return
    end if
    if (trim(VAL_help) == '') then
      unit = STDOUT
    else
      unit = StoI(VAL_help)
    end if

    call Printf(unit, '')

    call DCHashGet(arg % helpmsg, 'TITLE', help_msg, found)
    if (found) then
      call Printf(unit, '%c', c1=trim(help_msg))
      call Printf(unit, '')
      call DCHashDelete(arg % helpmsg, 'TITLE')
    end if

    call DCHashGet(arg % helpmsg, 'OVERVIEW', help_msg, found)
    if (found) then
      call Printf(unit, 'Overview::')
      call PrintAutoLinefeed(unit, help_msg, indent='     ')
      call Printf(unit, '')
      call DCHashDelete(arg % helpmsg, 'OVERVIEW')
    end if

    call DCHashGet(arg % helpmsg, 'USAGE', help_msg, found)
    if (found) then
      call Printf(unit, 'Usage::')
      call PrintAutoLinefeed(unit, help_msg, indent='     ')
      call Printf(unit, '')
      call DCHashDelete(arg % helpmsg, 'USAGE')
    end if

    call Printf(unit, 'Options::')
    if ( associated(arg % opt_table) ) then
      do i = 1, size(arg % opt_table)
        options_msg = ' '
        if (arg % opt_table(i) % optvalue_flag) then
          call Concat(arg % opt_table(i) % options, '=VAL', localopts)
        else
          allocate(localopts(size(arg % opt_table(i) % options)))
          localopts = arg % opt_table(i) % options
        end if
        options_msg = trim(options_msg) // trim(JoinChar(localopts))
        deallocate(localopts)
        call Printf(unit, ' %c', c1=trim(options_msg))
        call PrintAutoLinefeed(unit, &
          & arg % opt_table(i) % help_message, indent='     ')
        call Printf(unit, '')
      end do
    end if

    call DCHashRewind(arg % helpmsg)
    do
      call DCHashNext(arg % helpmsg, category, help_msg, end)
      if (end) exit

      call Printf(unit, '%c%c::', &
        & c1=trim(UChar(category(1:1))), c2=trim(LChar(category(2:))))
      call PrintAutoLinefeed(unit, help_msg, indent='     ')
      call Printf(unit, '')

    enddo

    call DCArgsClose(arg)

    stop
  end subroutine DCArgsHelp0

  subroutine DCArgsHelpMsg0(arg, category, msg)
    !
    ! ãƒ˜ãƒ«ãƒ—ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’è¿½åŠ ã—ã¾ã™.
    !
    ! ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ DCArgsHelp ã‚’ä½¿ç”¨ã—ãŸéš›ã«å‡ºåŠ›ã•ã‚Œã‚‹ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’
    ! ä»˜åŠ ã—ã¾ã™. *category* ã« +Title+, +Overview+, +Usage+ ãŒ
    ! æŒ‡å®šã•ã‚ŒãŸã‚‚ã®ã¯ +Options+ ã‚ˆã‚Šã‚‚ä¸Šéƒ¨ã«,
    ! ãã‚Œä»¥å¤–ã®ã‚‚ã®ã¯ä¸‹éƒ¨ã«è¡¨ç¤ºã•ã‚Œã¾ã™.
    ! *msg* ã«ã¯ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’ä¸Žãˆã¦ãã ã•ã„.
    !
    !=== ä¾‹
    !
    !     program dc_args_sample3
    !       use dc_types
    !       use dc_string, only: StoA
    !       use dc_args
    !       implicit none
    !       type(ARGS) :: arg
    !       logical :: OPT_namelist
    !       character(STRING) :: VAL_namelist
    !       character(STRING), pointer :: argv(:) => null()
    !       integer :: i
    !
    !       call DCArgsOpen( arg = arg )   ! (out)
    !       call DCArgsHelpMsg( arg = arg, &              ! (inout)
    !         & category = 'Title', &                     ! (in)
    !         & msg = 'dcargs $Revision: 1.2 $ ' // &
    !         &       ':: Test program of dc_args' )      ! (in)
    !       call DCArgsHelpMsg( arg = arg, &              ! (inout)
    !         & category = 'Usage', &                     ! (in)
    !         & msg = 'dcargs [Options] arg1, arg2, ...') ! (in)
    !       call DCArgsOption( arg = arg, &           ! (inout)
    !         & options = StoA('-N', '--namelist'), & ! (in)
    !         & flag = OPT_namelist, &                ! (out)
    !         & value = VAL_namelist, &               ! (out)
    !         & help = "Namelist filename")           ! (in)
    !       call DCArgsHelpMsg( arg = arg, &          ! (inout)
    !         & category = 'DESCRIPTION', &           ! (in)
    !         & msg = '(1) Define type "HASH". ' // &
    !         &       '(2) Open the variable. ' // &
    !         &       '(3) set HelpMsg. ' // &
    !         &       '(4) set Options. ' // &
    !         &       '(5) call Debug. ' // &
    !         &       '(6) call Help. ' // &
    !         &       '(7) call Strict.')             ! (in)
    !       call DCArgsHelpMsg( arg = arg, &                         ! (inout)
    !         & category = 'Copyright', &                            ! (in)
    !         & msg = 'Copyright (C) ' // &
    !         &       'GFD Dennou Club, 2008. All rights reserved.') ! (in)
    !       call DCArgsDebug( arg = arg )  ! (inout)
    !       call DCArgsHelp( arg = arg )   ! (inout)
    !       call DCArgsStrict( arg = arg ) ! (inout)
    !       call DCArgsGet( arg = arg, &   ! (inout)
    !         & argv = argv )              ! (out)
    !       write(*,*) '--namelist=', trim( VAL_namelist )
    !       do i = 1, size(argv)
    !         write(*,*) argv(i)
    !       end do
    !       deallocate( argv )
    !       call DCArgsClose( arg = arg )  ! (inout)
    !     program dc_args_sample3
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã« '-h', '-H', '--help' ã®ã„ã¥ã‚Œã‹ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³
    ! ã‚’æŒ‡å®šã™ã‚‹ã“ã¨ã§, HelpMsg ã§ä¸ŽãˆãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã¨, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®ä¸€è¦§
    ! ãŒæ¨™æº–å‡ºåŠ›ã«è¡¨ç¤ºã•ã‚Œã¾ã™.
    !
    use dc_hash, only: DCHashPut
    use dc_string, only: UChar
    use dc_message, only: MessageNotify
    implicit none
    type(ARGS), intent(inout) :: arg
    character(*), intent(in) :: category
    character(*), intent(in) :: msg
    character(len = *), parameter  :: subname = 'DCArgsHelpMsg'
  continue
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Help in dc_args.')
      call DCArgsOpen(arg)
    end if
    call DCHashPut(arg % helpmsg, key=UChar(category), value=msg)
  end subroutine DCArgsHelpMsg0

  subroutine DCArgsStrict0(arg, severe)
    !
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ãƒã‚§ãƒƒã‚¯ã‚’è¡Œã„ã¾ã™.
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ã—ã¦æŒ‡å®šã•ã‚ŒãŸã‚‚ã®ã®å†…,
    ! DCArgsOption ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã§è¨å®šã•ã‚Œã¦ã„ãªã„ã‚‚ã®ãŒå˜åœ¨ã™ã‚‹
    ! å ´åˆã«ã¯è¦å‘Šã‚’è¿”ã—ã¾ã™. *severe* ã« .true. ã‚’æŒ‡å®šã™ã‚‹ã¨
    ! ã‚¨ãƒ©ãƒ¼ã‚’è¿”ã—ã¦çµ‚äº†ã—ã¾ã™.
    ! ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’å‘¼ã¶å‰ã«, DCArgsOption, DCArgsDebug,
    ! DCArgsHelp ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’å‘¼ã‚“ã§ãã ã•ã„.
    !
    ! æ§‹é€ ä½“ ARGS ã®å¤‰æ•°ã«å¯¾ã—ã¦ã“ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã‚’é©ç”¨ã—ã¦ãŠã
    ! ã“ã¨ã§, ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã¨ã—ã¦ä¸ŽãˆãŸã‚ªãƒ—ã‚·ãƒ§ãƒ³ãŒæ£ã—ã
    ! ãƒ—ãƒã‚°ãƒ©ãƒ ãŒèªè˜ã—ã¦ã„ã‚‹ã‹ã©ã†ã‹ã‚’ãƒã‚§ãƒƒã‚¯ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™.
    !
    !
    use dc_types, only: STRING
    use dc_present, only: present_and_true
    use dc_message, only: MessageNotify
    implicit none
    type(ARGS), intent(inout) :: arg
    logical, intent(in), optional :: severe
    character(STRING) :: err_mess
    integer :: i
    character(len = *), parameter  :: subname = 'DCArgsStrict'
  continue
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Help in dc_args.')
      call DCArgsOpen(arg)
    end if
    do i = 1, size(arg % cmd_opts_list)
      err_mess = trim(arg % cmd_opts_list(i) % name) // ' is invalid option.'
      if (.not. arg % cmd_opts_list(i) % flag_called) then
        if (present_and_true(severe)) then
          call MessageNotify('E', subname, err_mess)
        else
          call MessageNotify('W', subname, err_mess)
        end if
      end if
    end do
  end subroutine DCArgsStrict0

  subroutine DCArgsGet0(arg, argv)
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã®ã†ã¡, ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã§ã¯ãªã„ã‚‚ã®ã‚’
    ! *argv* ã«è¿”ã—ã¾ã™.
    !
    ! *argv* ã¯æ–‡å—åž‹é…åˆ—ã®ãƒã‚¤ãƒ³ã‚¿ã§ã™.
    ! å¼•æ•°ã¨ã—ã¦ä¸Žãˆã‚‹å ´åˆã«ã¯å¿…ãšç©ºçŠ¶æ…‹ã—ã¦ä¸Žãˆã¦ãã ã•ã„.
    !
    use dc_types, only: STRING
    use dc_string, only: StoA, StoI, Printf, Concat, JoinChar
    use dc_present, only: present_and_true
    use dc_message, only: MessageNotify
    implicit none
    type(ARGS), intent(inout) :: arg
    character(*), pointer :: argv(:) !(out)
    integer :: i, cmd_argv_max
    character(len = *), parameter  :: subname = 'DCArgsGet'
  continue
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Help in dc_args.')
      call DCArgsOpen(arg)
    end if
    cmd_argv_max = size(cmd_argv_list)
    allocate(argv(cmd_argv_max))
    do i = 1, cmd_argv_max
      argv(i) = cmd_argv_list(i)
    end do
  end subroutine DCArgsGet0

  function DCArgsNumber0(arg) result(result)
    !
    ! ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°ã¨ã—ã¦ä¸Žãˆã‚‰ã‚ŒãŸå¼•æ•°ã®æ•°ã‚’è¿”ã—ã¾ã™.
    !
    use dc_message, only: MessageNotify
    implicit none
    type(ARGS), intent(inout) :: arg
    integer :: result
    character(len = *), parameter  :: subname = 'DCArgsNumber'
  continue
    if (.not. arg % initialized) then
      call MessageNotify('W', subname, 'Call Open before Help in dc_args.')
      call DCArgsOpen(arg)
    end if
    result = size(cmd_argv_list)
  end function DCArgsNumber0

  subroutine DCArgsPutLine0(arg)
    !
    ! *arg* ã«é–¢ã™ã‚‹æƒ…å ±ã‚’æ¨™æº–å‡ºåŠ›ã«è¡¨ç¤ºã—ã¾ã™.
    !
    use dc_types, only: STDOUT
    use dc_string, only: Printf, JoinChar
    implicit none
    type(ARGS), intent(in) :: arg
    integer :: i
  continue
    if (.not. arg % initialized) then
      call Printf(STDOUT, '#<ARGS:: @initialized=%y>', l=(/arg % initialized/))
      return
    end if
    call Printf(STDOUT, '#<ARGS:: @initialized=%y,', l=(/arg % initialized/))
    call Printf(STDOUT, '  @opt_table(:)=')
    if ( associated(arg % opt_table) ) then
      do i = 1, size(arg % opt_table)
        call Printf(STDOUT, '    #<OPT_ENTRY:: ')
        call Printf(STDOUT, '      @options=%c, @help_message=%c, @optvalue_flag=%y', &
          & c1=trim(JoinChar(arg % opt_table(i) % options)), &
          & c2=trim(arg % opt_table(i) % help_message), &
          & l=(/arg % opt_table(i) % optvalue_flag/))
        call Printf(STDOUT, '    >')
      end do
    end if
    call Printf(STDOUT, '  ,')
    call Printf(STDOUT, '  @cmd_opts_list(:)=')
    do i = 1, size(arg % cmd_opts_list)
      call Printf(STDOUT, '    #<CMD_OPTS_INTERNAL:: ')
      call Printf(STDOUT, '      @name=%c, @value=%c, @flag_called=%y', &
        & c1=trim(arg % cmd_opts_list(i) % name), &
        & c2=trim(arg % cmd_opts_list(i) % value), &
        & l=(/arg % cmd_opts_list(i) % flag_called/))
      call Printf(STDOUT, '    >')
    end do
    call Printf(STDOUT, '  ,')
    call Printf(STDOUT, '  @cmd_argv_list(:)=%c', &
      & c1=trim(JoinChar(cmd_argv_list)))
    call Printf(STDOUT, '>')

  end subroutine DCArgsPutLine0

  subroutine PrintAutoLinefeed(unit, fmt, length, indent)
    !
    ! æ–‡å—åˆ—ã‚’è‡ªå‹•æ”¹è¡Œã—ã¦å‡ºåŠ›ã—ã¾ã™.
    ! ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«å†…éƒ¨ã§ç”¨ã„ã‚‹ãŸã‚ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã§ã™.
    !
    ! *fmt* ã«ä¸Žãˆã‚‰ã‚ŒãŸæ–‡ç« ã‚’æ–‡å—æ•° *length* (æŒ‡å®šã•ã‚Œãªã„å ´åˆ 70)
    ! ä»¥å†…ã«æ”¹è¡Œã—, å‡ºåŠ›ã—ã¾ã™. å‡ºåŠ›ã®éš›, *indent* ãŒæŒ‡å®šã•ã‚Œã¦ã„ã‚‹ã¨
    ! ãã®æ–‡å—åˆ—ã‚’è¡Œé ã«æŒ¿å…¥ã—ã¦å‡ºåŠ›ã‚’è¡Œã„ã¾ã™.
    ! å‡ºåŠ›å…ˆã¯ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã¯æ¨™æº–å‡ºåŠ›ã¨ãªã‚Šã¾ã™. *unit* ã«å‡ºåŠ›è£…ç½®ç•ªå·
    ! ã‚’è¨å®šã™ã‚‹ã“ã¨ã§å‡ºåŠ›å…ˆã‚’å¤‰æ›´ã§ãã¾ã™.
    !
    use dc_types, only: STRING, STDOUT
    use dc_string, only: Split
    implicit none
    character(*), intent(in) :: fmt
    integer,      intent(in), optional :: length ! ä¸€è¡Œã®é•·ã•
    character(*), intent(in), optional :: indent ! å—ä¸‹ã’æ–‡å—åˆ—
    integer,      intent(in), optional :: unit   ! å‡ºåŠ›è£…ç½®
    character(STRING), pointer :: carray_tmp(:) => null()
    character(STRING) :: store_str
    integer, parameter :: default_len = 70
    integer :: i, split_len, indent_len, unit_num
    logical :: new_line_flag
  continue
    if (present(unit)) then
      unit_num = unit
    else
      unit_num = STDOUT
    end if

    if (present(indent)) then
      indent_len = len(indent)
    else
      indent_len = 0
    end if

    if (present(length)) then
      split_len = length - indent_len
    else
      split_len = default_len - indent_len
    end if

    nullify(carray_tmp)
    call Split(fmt, carray_tmp, '')
    store_str = ''
    new_line_flag = .true.
    i = 1
    do
      if (i > size(carray_tmp)) then
        write(unit_num, '(A)') trim(store_str)
        exit
      end if

      if (len(trim(store_str)) + len(trim(carray_tmp(i))) > split_len) then
        if (new_line_flag) then
          write(unit_num, '(A)') trim(carray_tmp(i))
          i = i + 1
        else
          write(unit_num, '(A)') trim(store_str)
          store_str = ''
          new_line_flag = .true.
        end if
        cycle
      end if

      if (new_line_flag .and. present(indent)) then
        store_str = indent // trim(carray_tmp(i))
      else
        store_str = trim(store_str) // ' ' // trim(carray_tmp(i))
      end if
      new_line_flag = .false.
      i = i + 1
    end do

  end subroutine PrintAutoLinefeed

  subroutine SortArgTable
    !
    ! å†…éƒ¨å‘ã‘ã®å¼•æ•°æŒ¯ã‚Šåˆ†ã‘ã®ãŸã‚ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã§ã™.
    !
    ! BuildArgTable ã§è¨å®šã•ã‚ŒãŸ argind_count, argstr_table ã‚’
    ! ç”¨ã„, cmd_argv_list, cmd_opts_list ã‚’è¨å®šã—ã¾ã™.
    !
    ! æ—¢ã«ä¸€åº¦ã§ã‚‚å‘¼ã°ã‚Œã¦ã„ã‚‹å ´åˆ, ä½•ã‚‚ã›ãšã«çµ‚äº†ã—ã¾ã™.
    !
    use dc_types, only: STRING
    implicit none
    character(STRING):: raw_arg, name, value
    integer:: i, cmd_argv_count, cmd_opts_count, cmd_argv_max, cmd_opts_max
  continue
    if (allocated(cmd_opts_list)) return
    cmd_argv_count = 0
    cmd_opts_count = 0
    check_count: do, i = 1, argind_count
      raw_arg = argstr_table(i)
      if (DCOptionFormC(raw_arg, name, value)) then
        cmd_opts_count = cmd_opts_count + 1
      else
        cmd_argv_count = cmd_argv_count + 1
      end if
    end do check_count

    cmd_argv_max = cmd_argv_count
    cmd_opts_max = cmd_opts_count

    allocate(cmd_argv_list(cmd_argv_max))
    allocate(cmd_opts_list(cmd_opts_max))

    cmd_argv_count = 0
    cmd_opts_count = 0
    arg_get : do, i = 1, argind_count
      raw_arg = argstr_table(i)
      if (DCOptionFormC(raw_arg, name, value)) then
        cmd_opts_count = cmd_opts_count + 1
        cmd_opts_list(cmd_opts_count) % name = name
        cmd_opts_list(cmd_opts_count) % value = value
        cmd_opts_list(cmd_opts_count) % flag_called = .false.
      else
        cmd_argv_count = cmd_argv_count + 1
        cmd_argv_list(cmd_argv_count) = raw_arg
      end if
    end do arg_get
  end subroutine SortArgTable

  subroutine BuildArgTable
    !
    ! å†…éƒ¨å‘ã‘ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°å‡¦ç†ã®ã‚µãƒ–ãƒ«ãƒ¼ãƒãƒ³ã§ã™.
    !
    ! ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ« sysdep ã® sysdep#SysdepArgCount, sysdep#ArgGet
    ! ã‚’å‘¼ã³å‡ºã—, ãã®å†…å®¹ã‚’ argind_count ã¨ argstr_table ã«æ ¼ç´ã—ã¾ã™.
    !
    ! æ—¢ã«ä¸€åº¦ã§ã‚‚å‘¼ã°ã‚Œã¦ã„ã‚‹å ´åˆ, ä½•ã‚‚ã›ãšã«çµ‚äº†ã—ã¾ã™.
    !
    use sysdep, only: SysdepArgCount, SysdepArgGet
    use dc_types, only: STRING
    implicit none
    integer:: i, narg, nargmax
    character(len = STRING):: value
    character(len = STRING), allocatable:: localtab(:)
  continue
    if (argind_count >= 0) return
    nargmax = SysdepArgCount()
    allocate(localtab(nargmax))
    narg = 0
    do, i = 1, nargmax
      call SysdepArgGet(i, value)
      narg = narg + 1
      localtab(narg) = value
    enddo
    argind_count = narg
    allocate(argstr_table(narg))
    argstr_table(1: narg) = localtab(1: narg)
    deallocate(localtab)
  end subroutine BuildArgTable

  function DCOptionFormC(argument, name, value) result(result)
    !
    ! å¼•æ•°ã¨ã—ã¦ã§å¾—ã‚‰ã‚ŒãŸæ–‡å—åˆ—ã‚’ *argument* ã«æ¸¡ã™ã“ã¨ã§,
    ! ãã‚ŒãŒã‚ªãƒ—ã‚·ãƒ§ãƒ³ãªã®ã‹ãã†ã§ãªã„ã®ã‹ã‚’åˆ¤åˆ¥ã—, ã‚‚ã—ã‚‚
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨åˆ¤åˆ¥ã—ãŸå ´åˆã«ã¯æˆ»ã‚Šå€¤ã« .true. ã‚’è¿”ã—,
    ! name ã«ã‚ªãƒ—ã‚·ãƒ§ãƒ³å, *value* ã«ãã®å€¤ã‚’è¿”ã™.
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã«å€¤ãŒä»˜åŠ ã•ã‚Œãªã„å ´åˆã¯ *value* ã«ã¯ç©ºç™½ã‚’è¿”ã™.
    !
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã§ã¯ãªã„å ´åˆã¯æˆ»ã‚Šå€¤ã« .false. ã‚’è¿”ã—,
    ! *name*, *value* ã«ã¯ç©ºç™½ã‚’è¿”ã™.
    !
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨åˆ¤å®šã•ã‚Œã‚‹ã®ã¯ä»¥ä¸‹ã®å ´åˆã§ã™.
    !
    ! * ä¸€æ–‡å—ç›®ãŒ '-' ã®å ´åˆ. ã“ã®å ´åˆã¯çŸã„ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ãªã‚Š, '-'
    !   ã®æ¬¡ã®ä¸€æ–‡å—ã®ã¿ãŒã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ã—ã¦æœ‰åŠ¹ã«ãªã‚Šã¾ã™.
    !
    ! * 1-2æ–‡å—ç›®ãŒ '--' ã®å ´åˆ. ã“ã®å ´åˆã¯é•·ã„ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ãªã‚Š,
    !   '--' ä»¥é™ã®æ–‡å—åˆ—ãŒã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¨ã—ã¦æœ‰åŠ¹ã«ãªã‚Šã¾ã™.
    !
    ! ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®å€¤ã¯, "=" ã‚ˆã‚Šã‚‚å¾Œã‚ã®æ–‡å—åˆ—ã«ãªã‚Šã¾ã™.
    !
    !=== ä¾‹
    !
    ! *argument*    :: <b>name,      value, è¿”ã‚Šå€¤</b>
    ! arg           ::    ç©ºç™½,      ç©ºç™½,  .false.
    ! -O            ::    -O,        ç©ºç™½,  .true.
    ! -debug        ::    -d,        ç©ºç™½,  .true.
    ! --debug       ::    --debug,   ç©ºç™½,  .true.
    ! -I=/usr       ::    -I,        /usr,  .true.
    ! --include=/usr::    --include, /usr,  .true.
    !
    implicit none
    character(len = *), intent(in):: argument
    character(len = *), intent(out):: name, value
    logical :: result
    integer:: equal
  continue
    equal = index(argument, '=')
    if (argument(1:1) == '-' .and. argument(2:2) /= '-') then
      ! Short Option
      if (equal == 0) then
        name = argument(1:2)
        value = ""
      else
        name = argument(1:2)
        value = argument(equal+1: )
      endif
      result = .true.
    elseif (argument(1:2) == '--') then
      ! Long Option
      if (equal == 0) then
        name = argument
        value = ""
      else
        name = argument(1:equal-1)
        value = argument(equal+1: )
      endif
      result = .true.
!    elseif (equal == 0 .and. &
!      &     verify(argument(1:equal-1), WORDCHARS) == 0) then
!      ! ???
!      name = argument(1:equal-1)
!      value = argument(equal+1: )
!      result = .true.
    else
      ! No Option (normal arguments)
      name = ""
      value = ""
      result = .false.
    endif
  end function DCOptionFormC

end module dc_args