!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubetools_option
  use cubetools_parameters
  use cubesyntax_messaging
  use cubetools_primitive_arg
  use cubetools_terminal_tool
  use cubetools_list
  !
  public :: option_t,narg_k,narg_max,strg_quest
  public :: cubetools_option_ptr
  !
  private
  !
  integer(kind=code_k), parameter :: help_src_unkn=0  ! Unknown
  integer(kind=code_k), parameter :: help_src_none=1  ! No help => look at abstract
  integer(kind=code_k), parameter :: help_src_strg=2  ! From string
  integer(kind=code_k), parameter :: help_src_file=3  ! From file
  !
  integer(kind=4), parameter :: opti_k = 4
  integer(kind=4), parameter :: opti_l = 16
  integer(kind=4), parameter :: abst_l = 80
  integer(kind=4), parameter :: synt_l = 60
  integer(kind=4), parameter :: narg_max = 10
  !
  character(len=*), parameter :: strg_quest = '?' ! Short help
  !
  type, extends(tools_object_t) :: option_t
     integer(kind=opti_k)          :: inum     = code_abs  ! Option number in command
     character(len=opti_l)         :: name     = strg_unk
     character(len=synt_l)         :: syntax   = strg_emp
     character(len=abst_l)         :: abstract = strg_emp  ! One-line abstract help
     integer(kind=code_k)          :: help_src = help_src_unkn
     character(len=:), allocatable :: help_strg            ! Long/multiline help OR
     character(len=file_l)         :: help_file            ! File name for help
     integer(kind=narg_k)          :: nargmin  = code_abs
     integer(kind=narg_k)          :: nargmax  = code_abs
     type(tools_list_t)            :: arg                  ! List of arguments to the option
   contains
     ! Parsing
     procedure :: getnarg      => cubetools_option_getnarg
     procedure :: present      => cubetools_option_present
     procedure, private :: traphelp  => cubetools_option_traphelp
     procedure, private :: getarg_i4 => cubetools_option_getarg_i4
     procedure, private :: getarg_i8 => cubetools_option_getarg_i8
     procedure, private :: getarg_r4 => cubetools_option_getarg_r4
     procedure, private :: getarg_r8 => cubetools_option_getarg_r8
     procedure, private :: getarg_st => cubetools_option_getarg_st
     generic   :: getarg       => getarg_i4, getarg_i8, getarg_r4, getarg_r8, getarg_st
     !
     ! General
     procedure :: check        => cubetools_option_check_execute
     procedure :: init         => cubetools_option_init
     procedure :: final        => cubetools_option_final
     procedure :: free         => cubetools_option_free
     !
     ! Registering
     procedure :: put          => cubetools_option_put
     !
     ! Listing and Help
     procedure :: print_abstract => cubetools_option_print_abstract
     procedure :: list           => cubetools_option_list
     procedure :: help           => cubetools_option_help
     procedure :: summary        => cubetools_option_summary
     procedure :: show_syntax    => cubetools_option_show_syntax
     procedure :: help_iterate   => cubetools_option_help_iterate
     procedure, private :: print_syntax    => cubetools_option_print_syntax
     procedure, private :: print_help_strg => cubetools_option_print_help_strg
     procedure, private :: print_help_file => cubetools_option_print_help_file
  end type option_t
  !
contains
  !
  !---Parsing-utilities--------------------------------------------------
  !
  function cubetools_option_getnarg(opt)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Returns number of arguments given to option
    !-------------------------------------------------------------------
    integer(kind=narg_k)       :: cubetools_option_getnarg
    class(option_t),intent(in) :: opt
    !
    cubetools_option_getnarg = sic_narg(opt%inum)
  end function cubetools_option_getnarg
  !
  subroutine cubetools_option_present(opt,line,present,error)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Returns if option is present.
    ! If the option has a question mark (?) argument, show the either
    ! the option or the argument help.
    !-------------------------------------------------------------------
    class(option_t),  intent(in)    :: opt
    character(len=*), intent(in)    :: line
    logical,          intent(out)   :: present
    logical,          intent(inout) :: error
    !
    integer(kind=4) :: nc,narg
    character(len=1) :: arg1
    character(len=argu_l) :: arg
    character(len=*), parameter :: rname='OPTION>PRESENT'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    present = sic_present(opt%inum,icomm)
    if (.not.present)  return
    !
    ! Trap ? on last argument
    narg = opt%getnarg()
    if (narg.le.0)  return  ! No argument present
    !
    if (sic_len(opt%inum,narg).ne.1)  return  ! Argument can not be ?
    !
    call sic_ch(line,opt%inum,narg,arg1,nc,mandatory,error)
    if (error) return
    if (arg1.ne.strg_quest)  return  ! Not a question mark
    !
    if (narg.eq.1) then
      ! Question mark follows the option: show help summary
      call opt%summary(error)
      if (error) return
    else
      ! Question mark follows an argument: show its full summary
      call sic_ke(line,opt%inum,narg-1,arg,nc,mandatory,error)
      if (error) return
      call cubetools_option_help_onearg(opt,arg(1:nc),error)
      if (error) return
    endif
    !
    ! Raise error to ensure the whole calling cascade is exited.
    error = .true.
    return
  end subroutine cubetools_option_present
  !
  subroutine cubetools_option_traphelp(opt,line,iarg,argum,nc,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    ! Get the iarg-th argument (as a string) of the option from the command
    ! line. If the argument is a question mark (?), show the option help.
    !----------------------------------------------------------------------
    class(option_t),      intent(in)    :: opt
    character(len=*),     intent(in)    :: line
    integer(kind=argu_k), intent(in)    :: iarg
    character(len=*),     intent(out)   :: argum
    integer(kind=4),      intent(out)   :: nc
    logical,              intent(inout) :: error
    !
    logical :: obligatory
    type(primitive_arg_t), pointer :: parg
    character(len=*), parameter :: rname='GET>ARG>TRAP>HELP'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    parg => cubetools_primitive_arg_ptr(opt%arg%list(iarg)%p,error)
    obligatory = parg%mandatory.eq.code_arg_mandatory.or.parg%mandatory.eq.code_arg_optional
    call sic_ch(line,opt%inum,iarg,argum,nc,obligatory,error)
    if (error) return
    if (argum.eq.strg_quest) then
       call opt%summary(error)
       if (error) return
       error = .true.
       return
    endif
  end subroutine cubetools_option_traphelp
  !
  subroutine cubetools_option_getarg_i4(opt,line,iarg,value,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t),      intent(in)    :: opt
    character(len=*),     intent(in)    :: line
    integer(kind=argu_k), intent(in)    :: iarg
    integer(kind=4),      intent(inout) :: value
    logical,              intent(inout) :: error
    !
    character(len=base_l) :: argum
    integer(kind=4) :: nc
    character(len=*), parameter :: rname='GET>ARG>I4'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%traphelp(line,iarg,argum,nc,error)
    if (error) return
    call sic_math_inte(argum,nc,value,error)
    if (error) then
       error = .false.
       call opt%show_syntax(error)
       error = .true.
       return
    endif
  end subroutine cubetools_option_getarg_i4
  !
  subroutine cubetools_option_getarg_i8(opt,line,iarg,value,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t),      intent(in)    :: opt
    character(len=*),     intent(in)    :: line
    integer(kind=argu_k), intent(in)    :: iarg
    integer(kind=8),      intent(inout) :: value
    logical,              intent(inout) :: error
    !
    character(len=base_l) :: argum
    integer(kind=4) :: nc
    character(len=*), parameter :: rname='GET>ARG>I8'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%traphelp(line,iarg,argum,nc,error)
    if (error) return
    call sic_math_long(argum,nc,value,error)
    if (error) then
       error = .false.
       call opt%show_syntax(error)
       error = .true.
       return
    endif
  end subroutine cubetools_option_getarg_i8
  !
  subroutine cubetools_option_getarg_r4(opt,line,iarg,value,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t),      intent(in)    :: opt
    character(len=*),     intent(in)    :: line
    integer(kind=argu_k), intent(in)    :: iarg
    real(kind=4),         intent(inout) :: value
    logical,              intent(inout) :: error
    !
    character(len=base_l) :: argum
    integer(kind=4) :: nc
    character(len=*), parameter :: rname='GET>ARG>I8'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%traphelp(line,iarg,argum,nc,error)
    if (error) return
    call sic_math_real(argum,nc,value,error)
    if (error) then
       error = .false.
       call opt%show_syntax(error)
       error = .true.
       return
    endif
  end subroutine cubetools_option_getarg_r4
  !
  subroutine cubetools_option_getarg_r8(opt,line,iarg,value,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t),      intent(in)    :: opt
    character(len=*),     intent(in)    :: line
    integer(kind=argu_k), intent(in)    :: iarg
    real(kind=8),         intent(inout) :: value
    logical,              intent(inout) :: error
    !
    character(len=base_l) :: argum
    integer(kind=4) :: nc
    character(len=*), parameter :: rname='GET>ARG>I8'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%traphelp(line,iarg,argum,nc,error)
    if (error) return
    call sic_math_dble(argum,nc,value,error)
    if (error) then
       error = .false.
       call opt%show_syntax(error)
       error = .true.
       return
    endif
  end subroutine cubetools_option_getarg_r8
  !
  subroutine cubetools_option_getarg_st(opt,line,iarg,value,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t),      intent(in)    :: opt
    character(len=*),     intent(in)    :: line
    integer(kind=argu_k), intent(in)    :: iarg
    character(len=*),     intent(inout) :: value
    logical,              intent(inout) :: error
    !
    integer(kind=4) :: nc
    character(len=*), parameter :: rname='GET>ARG>ST'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%traphelp(line,iarg,value,nc,error)
    if (error) return
  end subroutine cubetools_option_getarg_st
  !
  !---General-routines-----------------------------------------------------
  !
  subroutine cubetools_option_init(opt,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t), intent(out)   :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>INIT'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
  end subroutine cubetools_option_init
  !
  subroutine cubetools_option_final(opt,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t), intent(out)   :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>FINAL'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call cubetools_option_free(opt,error)
    if (error) return
  end subroutine cubetools_option_final
  !
  function cubetools_option_ptr(tot,error)
    !-------------------------------------------------------------------
    ! Check if the input class is of type(option_t), and return
    ! a pointer to it if relevant.
    !-------------------------------------------------------------------
    type(option_t), pointer :: cubetools_option_ptr  ! Function value on return
    class(tools_object_t), pointer       :: tot
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>PTR'
    !
    select type(tot)
    type is (option_t)
      cubetools_option_ptr => tot
    class default
      cubetools_option_ptr => null()
      call cubesyntax_message(seve%e,rname,  &
        'Internal error: object is not a option_t type')
      error = .true.
      return
    end select
  end function cubetools_option_ptr
  !
  subroutine cubetools_option_check_execute(opt,command,line,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    ! When a command is executed, check if the option is present. If yes,
    ! check if the number of arguments are within the expected range
    ! EXCEPT if the first argument is ?, which shows the help.
    !----------------------------------------------------------------------
    class(option_t),  intent(in)    :: opt
    character(len=*), intent(in)    :: command  ! Command name (for proper feedback)
    character(len=*), intent(in)    :: line
    logical,          intent(inout) :: error
    !
    integer(kind=narg_k) :: narg
    character(len=mess_l) :: mess
    character(len=128) :: prefix
    logical :: present
    character(len=*), parameter :: rname='OPTION>CHECK>EXECUTE'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    ! Check if present and trap ? as first argument to the option:
    call opt%present(line,present,error)
    if (error) return
    if (.not.present)  return
    !
    narg = opt%getnarg()
    !
    if (opt%inum.eq.0) then
      prefix = 'Command '//opt%name
    else
      prefix = 'Key /'//opt%name
    endif
    !
    if (narg.lt.opt%nargmin) then
      write(mess,'(a,3(a,i0))')  trim(prefix),  &
        ' takes at least ',opt%nargmin,' argument(s) (',narg,' given)'
      call cubesyntax_message(seve%e,rname,mess)
      error = .true.
      return
    endif
    !
    if (narg.gt.opt%nargmax) then
      if (opt%nargmax.eq.0) then
        write(mess,'(a,2(a,i0))')  trim(prefix),  &
          ' takes no argument (',narg,' given)'
      else
        write(mess,'(a,3(a,i0))')  trim(prefix),  &
          ' takes at most ',opt%nargmax,' argument(s) (',narg,' given)'
      endif
      call cubesyntax_message(seve%e,rname,mess)
      error = .true.
      return
    endif
  end subroutine cubetools_option_check_execute
  !
  subroutine cubetools_option_free(opt,error)
    !----------------------------------------------------------------------
    ! Free the contents of an 'option_t'
    !----------------------------------------------------------------------
    class(option_t), intent(inout) :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>FREE'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%arg%free(error)
    if (error) return
  end subroutine cubetools_option_free
  !
  !---Registering----------------------------------------------------------
  !
  subroutine cubetools_option_put(opt,inum,name,syntax,abstract,help,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t),      intent(inout) :: opt
    integer(kind=opti_k), intent(in)    :: inum
    character(len=*),     intent(in)    :: name
    character(len=*),     intent(in)    :: syntax
    character(len=*),     intent(in)    :: abstract
    character(len=*),     intent(in)    :: help
    logical,              intent(inout) :: error
    !
    character(len=file_l) :: filename
    character(len=*), parameter :: rname='OPTION>PUT'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call cubetools_option_final(opt,error)
    if (error) return
    call cubetools_option_init(opt,error)
    if (error) return
    !
    opt%inum     = inum
    opt%name     = name
    opt%syntax   = syntax
    opt%abstract = abstract
    if (help.eq.strg_id) then
      opt%help_src = help_src_none
    else
      call sic_parse_file(help,'','',filename)
      if (gag_inquire(filename,len_trim(filename)).eq.0) then
         opt%help_src = help_src_file
         opt%help_file = filename
      else
         opt%help_src = help_src_strg
         opt%help_strg = help
      endif
    endif
    opt%nargmin  = 0
    opt%nargmax  = 0
  end subroutine cubetools_option_put
  !
  !---Listing-and-Help---------------------------------------------------
  !
  subroutine cubetools_option_print_syntax(opt,error)
    use cubetools_format
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    integer(kind=4) :: width,nmess,noptsyntax
    character(len=mess_l) :: mess,key
    character(len=synt_l) :: optsyntax
    character(len=opti_l) :: optname
    character(len=*), parameter :: rname='OPTION>PRINT>SYNTAX'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    mess = ''
    nmess = 0
    width = terminal%width()
    key = 'Syntax'
    optname = '/'//trim(opt%name)
    if (len_trim(opt%syntax).eq.0) then
       optsyntax = cubetools_format_bold(optname)
    else
       optsyntax = trim(cubetools_format_bold(optname))//' '//trim(opt%syntax)
    endif
    noptsyntax = len_trim(optsyntax)
    width = width+bold_l
    mess = '  '//cubetools_format_stdkey_stdval(key,optsyntax,width)
    call cubesyntax_message(syntaxseve%help,rname,mess)
  end subroutine cubetools_option_print_syntax
  !
  subroutine cubetools_option_print_abstract(opt,error)
    use cubetools_format
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=mess_l) :: mess
    character(len=*), parameter :: rname='OPTION>PRINT>ABSTRACT'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    mess = '  /'//cubetools_format_stdkey_boldval(opt%name,opt%abstract,terminal%width()-1)
    call cubesyntax_message(syntaxseve%help,rname,mess)
  end subroutine cubetools_option_print_abstract
  !
  subroutine cubetools_option_list(opt,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=mess_l) :: mess
    integer(kind=narg_k) :: iarg
    class(primitive_arg_t), pointer :: arg
    character(len=*), parameter :: rname='OPTION>LIST'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    if (opt%arg%n.le.0) return
    !
    call cubesyntax_message(syntaxseve%help,rname,terminal%dash_strg())
    write(mess,'(a)') '  Arguments'
    call cubesyntax_message(syntaxseve%help,rname,mess)
    do iarg=1,opt%arg%n
       arg => cubetools_primitive_arg_ptr(opt%arg%list(iarg)%p,error)
       if (error) return
       call arg%print_abstract(iarg,error)
       if (error) return
    enddo !iarg
  end subroutine cubetools_option_list
  !
  subroutine cubetools_option_help(opt,error)
    !-------------------------------------------------------------------
    ! Print option help
    !-------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>HELP'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    select case (opt%help_src)
    case (help_src_none)
      ! Only abstract is available
      return
    case (help_src_strg)
      call opt%print_help_strg(error)
      if (error) return
    case (help_src_file)
      call opt%print_help_file(error)
      if (error) return
    case default
      call cubesyntax_message(seve%e,rname,'Unexpected help source')
      error = .true.
      return
    end select
    !
  end subroutine cubetools_option_help
  !
  subroutine cubetools_option_print_help_strg(opt,error)
    !-------------------------------------------------------------------
    ! Print option help from opt%help_strg
    !-------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>PRINT>HELP>STRG'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call cubesyntax_message(syntaxseve%help,rname,blankstr)
    call terminal%print_strg(opt%help_strg,error)
    if (error) return
  end subroutine cubetools_option_print_help_strg
  !
  subroutine cubetools_option_print_help_file(opt,error)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Print option help from file opt%help_file
    !-------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>PRINT>HELP>FILE'
    character(len=256) :: line
    integer(kind=4) :: ier,ilun
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call cubesyntax_message(syntaxseve%help,rname,blankstr)
    !
    ier = sic_getlun(ilun)
    if (ier.ne.1) then
      call cubesyntax_message(seve%e,rname,'No logical unit left')
      error = .true.
      return
    endif
    ier = sic_open(ilun,opt%help_file,'OLD',.true.)
    if (ier.ne.0) then
      call cubesyntax_message(seve%e,rname,'Cannot open '//opt%help_file)
      call putios('E-OPTION>HELP>FILE,  ',ier)
      error = .true.
      return
    endif
    do while (.true.)
      read(ilun,'(A)',end=40,err=50) line
      if (line.eq.'ENDOFHELP')  goto 40
      call cubesyntax_message(syntaxseve%help,rname,line)
    enddo
    !
    ! Error
50  call cubesyntax_message(seve%e,rname,'Error reading '//opt%help_file)
    error = .true.
    !
    ! Error and success
40  ier = sic_close(ilun)
    call sic_frelun(ilun)
  end subroutine cubetools_option_print_help_file
  !
  subroutine cubetools_option_summary(opt,error)
    !-------------------------------------------------------------------
    ! Short option summary
    !-------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>SUMMARY'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%print_syntax(error)
    if (error) return
    call cubesyntax_message(syntaxseve%help,rname,terminal%dash_strg())
    call opt%print_abstract(error)
    if (error) return
    call opt%help(error)
    if (error) return
    call opt%list(error)
    if (error) return
    call cubesyntax_message(syntaxseve%help,rname,blankstr)
  end subroutine cubetools_option_summary
  !
  subroutine cubetools_option_show_syntax(opt,error)
    !-------------------------------------------------------------------
    ! Short option syntax reminder
    !-------------------------------------------------------------------
    class(option_t), intent(in)    :: opt
    logical,         intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>SHOW>SYNTAX'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    call opt%print_syntax(error)
    call opt%list(error)
    call cubesyntax_message(syntaxseve%help,rname,'')
  end subroutine cubetools_option_show_syntax
  !
  subroutine cubetools_option_help_onearg(opt,arg,error)
    use cubetools_disambiguate
    !-------------------------------------------------------------------
    ! Disambiguate and show the help for one argument of the option
    ! (among all the other arguments). Might show the option help as
    ! fallback.
    !-------------------------------------------------------------------
    class(option_t),  intent(in)    :: opt
    character(len=*), intent(in)    :: arg
    logical,          intent(inout) :: error
    !
    integer(kind=4) :: iarg,ikey
    character(len=argu_l) :: solved
    class(primitive_arg_t), pointer :: parg
    character(len=argu_l), allocatable :: arglist(:)
    character(len=*), parameter :: rname='OPTION>PRESENT'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    ! Build the list of argument names
    allocate(arglist(opt%arg%n))
    do iarg=1,opt%arg%n
      parg => cubetools_primitive_arg_ptr(opt%arg%list(iarg)%p,error)
      if (error) return
      arglist(iarg) = parg%name
    enddo
    !
    ! Identify and show help
    call cubetools_disambiguate_flexible(arg,arglist,ikey,solved,error)
    if (error) return
    if (ikey.eq.code_unresolved) then
      ! Not a known argument
      call cubesyntax_message(seve%w,rname,  &
        'Unrecognized argument '//arg//'. Possible arguments are:')
      call opt%list(error)
      if (error) return
    else
      ! Show argument help summary
      parg => cubetools_primitive_arg_ptr(opt%arg%list(ikey)%p,error)
      call parg%summary(error)
      if (error) return
    endif
  end subroutine cubetools_option_help_onearg
  !
  subroutine cubetools_option_help_iterate(opt,langname,commname,error)
    !-------------------------------------------------------------------
    !
    !-------------------------------------------------------------------
    class(option_t),  intent(in)    :: opt
    character(len=*), intent(in)    :: langname
    character(len=*), intent(in)    :: commname
    logical,          intent(inout) :: error
    !
    character(len=*), parameter :: rname='OPTION>HELP>ITERATE'
    !
    call cubesyntax_message(syntaxseve%help,rname,'\subsubsection{'//trim(commname)//' /'//trim(opt%name)//'}')
    call cubesyntax_message(syntaxseve%help,rname,'\label{sec:'//trim(langname)//':'//trim(commname)//&
         ':'//trim(opt%name)//':help}')
    call cubesyntax_message(syntaxseve%help,rname,'\index{'//trim(langname)//' '//trim(commname)//&
         ' /'//trim(opt%name)//' option}')
    !
    call cubesyntax_message(syntaxseve%help,rname,'\begin{PlusVerbatim}')
    call opt%summary(error)
    if (error) return
    call cubesyntax_message(syntaxseve%help,rname,'\end{PlusVerbatim}')
  end subroutine cubetools_option_help_iterate
  !
end module cubetools_option
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
