subroutine sic_r4 (line,iopt,iarg,rel,present,error)
  use sic_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  !  Retrieves the IARG-th argument of the IOPT-th option
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  real(kind=4),     intent(inout) :: rel      ! Argument value
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,oreal=rel)
end subroutine sic_r4
!
subroutine sic_r8 (line,iopt,iarg,dbl,present,error)
  use sic_interfaces, except_this=>sic_r8
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieves the IARG-th argument of the IOPT-th option
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  real(kind=8),     intent(inout) :: dbl      ! Argument value
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,odble=dbl)
end subroutine sic_r8
!
subroutine sic_i8 (line,iopt,iarg,long,present,error)
  use sic_interfaces, except_this=>sic_i8
  !---------------------------------------------------------------------
  ! @ public-generic sic_i0
  !  Retrieves the IARG-th argument of the IOPT-th option
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  integer(kind=8),  intent(inout) :: long     ! Argument value
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,olong=long)
end subroutine sic_i8
!
subroutine sic_i4 (line,iopt,iarg,inte,present,error)
  use sic_interfaces, except_this=>sic_i4
  !---------------------------------------------------------------------
  ! @ public-generic sic_i0
  !  Retrieves the IARG-th argument of the IOPT-th option
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  integer(kind=4),  intent(inout) :: inte     ! Argument value
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,ointe=inte)
end subroutine sic_i4
!
subroutine sic_i2 (line,iopt,iarg,short,present,error)
  use sic_interfaces, except_this=>sic_i2
  !---------------------------------------------------------------------
  ! @ public-generic sic_i0
  !  Retrieves the IARG-th argument of the IOPT-th option
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  integer(kind=2),  intent(inout) :: short    ! Argument value
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,oshort=short)
end subroutine sic_i2
!
subroutine sic_l4 (line,iopt,iarg,logi,present,error)
  use sic_interfaces, except_this=>sic_l4
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieves the IARG-th argument of the IOPT-th option
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  logical,          intent(inout) :: logi     ! Argument value
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,ologi=logi)
end subroutine sic_l4
!
subroutine sic_ch (line,iopt,iarg,argum,length,present,error)
  use sic_interfaces, except_this=>sic_ch
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieves the IARG-th argument of the IOPT-th option
  !  Character string. Length returned.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  character(len=*), intent(inout) :: argum    ! Argument value
  integer(kind=4),  intent(out)   :: length   !
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  ! Local
  integer(kind=4) :: chtyp
  !
  chtyp = 0
  length = 0  ! Must be initialised if no argument present
  call sic_argument(line,iopt,iarg,present,error,  &
    chtyp=chtyp,ostring=argum,olen=length)
end subroutine sic_ch
!
subroutine sic_st (line,iopt,iarg,argum,length,present,error)
  use sic_interfaces, except_this=>sic_st
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieves the IARG-th argument of the IOPT-th option
  !  Character string, with no formatting.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  character(len=*), intent(inout) :: argum    ! Argument value
  integer(kind=4),  intent(out)   :: length   !
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  ! Local
  integer(kind=4) :: chtyp
  !
  chtyp = 1
  length = 0  ! Must be initialised if no argument present
  call sic_argument(line,iopt,iarg,present,error,  &
    chtyp=chtyp,ostring=argum,olen=length)
end subroutine sic_st
!
subroutine sic_ke (line,iopt,iarg,argum,length,present,error)
  use sic_interfaces, except_this=>sic_ke
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieves the IARG-th argument of the IOPT-th option
  !  Keyword: Expansion, Uppercase conversion
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line     ! Command line
  integer(kind=4),  intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),  intent(in)    :: iarg     ! Argument number (0=command)
  character(len=*), intent(inout) :: argum    ! Argument value
  integer(kind=4),  intent(out)   :: length   !
  logical,          intent(in)    :: present  ! Must the argument be present ?
  logical,          intent(inout) :: error    ! Error flag
  ! Local
  integer(kind=4) :: chtyp
  !
  chtyp = -1
  length = 0  ! Must be initialised if no argument present
  call sic_argument(line,iopt,iarg,present,error,  &
    chtyp=chtyp,ostring=argum,olen=length)
end subroutine sic_ke
!
subroutine sic_de(line,iopt,iarg,desc,present,error)
  use sic_interfaces, except_this=>sic_de
  use sic_types
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieves the descriptor of the IARG-th argument of the IOPT-th
  ! option.
  !
  !  - If argum is a variable name, return its descriptor
  !  - If argum is a variable non-contiguous subset, return the
  !    descriptor of its materialization
  !  - If argum is a scalar value (numeric, logical, or character),
  !    return the descriptor of its incarnation
  !
  ! IT IS THE RESPONSIBILITY OF THE CALLER TO FREE SCRATCH VARIABLES
  ! CREATED HERE: call sic_volatile(desc)
  !---------------------------------------------------------------------
  character(len=*),       intent(in)    :: line     ! Command line
  integer(kind=4),        intent(in)    :: iopt     ! Option number (0=command)
  integer(kind=4),        intent(in)    :: iarg     ! Argument number (0=command)
  type(sic_descriptor_t), intent(inout) :: desc     !
  logical,                intent(in)    :: present  ! Must the argument be present ?
  logical,                intent(inout) :: error    ! Error flag
  !
  call sic_argument(line,iopt,iarg,present,error,odesc=desc)
end subroutine sic_de
!
subroutine sic_argument(line,iopt,iarg,presen,error,  &
    oreal,odble,olong,ointe,oshort,ologi,chtyp,ostring,olen,odesc)
  use gildas_def
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_argument
  use sic_interactions
  use sic_dictionaries
  use sic_structures
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  !  Retrieves the IARG-th argument of the IOPT-th option
  !  The type and kind of the output argument is ruled by the present
  ! argument.
  !---------------------------------------------------------------------
  character(len=*),       intent(in)              :: line    ! Command line
  integer(kind=4),        intent(in)              :: iopt    ! Option number (0=command)
  integer(kind=4),        intent(in)              :: iarg    ! Argument number (0=command)
  logical,                intent(in)              :: presen  ! Must the argument be present ?
  logical,                intent(out)             :: error   ! Error flag
  ! One of these output arguments will be filled. Unchanged if absent.
  ! Numerics or logical
  real(kind=4),           intent(inout), optional :: oreal   !
  real(kind=8),           intent(inout), optional :: odble   !
  integer(kind=8),        intent(inout), optional :: olong   !
  integer(kind=4),        intent(inout), optional :: ointe   !
  integer(kind=2),        intent(inout), optional :: oshort  !
  logical,                intent(inout), optional :: ologi   !
  ! Characters
  integer(kind=4),        intent(in),    optional :: chtyp   ! Which kind of character parsing?
  character(len=*),       intent(inout), optional :: ostring !
  integer(kind=4),        intent(inout), optional :: olen    !
  ! Descriptor
  type(sic_descriptor_t), intent(inout), optional :: odesc   !
  ! Local
  character(len=*), parameter :: rname='DECODE'
  integer(kind=4) :: ifirst,ilast,parg
  logical :: l
  real(kind=4) :: r4
  real(kind=8) :: r8
  integer(kind=4) :: i4
  integer(kind=8) :: i8
  character(len=argument_length) :: expr
  character(len=message_length) :: mess
  !
  ! Check if argument is present
  error = .true.
  if (iopt.gt.maxopt .or. iopt.lt.0 .or. iarg.lt.0) then
    write(mess,104) iopt,iarg
    call sic_message(seve%e,rname,mess)
    return
  endif
  if (locstr(line).ne.ccomm%aline) then
    call sic_message(seve%e,rname,'You have overwritten the command line pointers')
    return
  endif
  if (iarg.le.ccomm%narg(iopt)) then
    ! Requested argument is present
    parg = ccomm%popt(iopt)+iarg
    if (parg.gt.mword) then
      write(mess,104) iopt,iarg
      call sic_message(seve%e,rname,mess)
      return
    endif
    ifirst = ccomm%ibeg(parg)
    ilast  = ccomm%iend(parg)
  else
    ! Requested argument is absent
    if (presen) then
      ! It was mandatory
      if (iopt.eq.0) then
        write(mess,101) iarg,trim(ccomm%lang),vocab(ccomm%icom)(2:)
      else
        write(mess,102) iarg,vocab(ccomm%icom+iopt)(2:)
      endif
      call sic_message(seve%e,rname,mess)
    else
      ! It was optional
      error = .false.
      if (present(ostring))  olen = len_trim(ostring)  ! Reuse input string
    endif
    return
  endif
  error = .false.
  !
  ! True values: remove outer quotes
  ! if (chtyp.eq.2) then
  !    if (line(ifirst:ifirst).eq.quote .and. line(ilast:ilast).eq.quote) then
  !       ifirst = ifirst+1
  !       ilast  = ilast-1
  !    endif
  ! endif
  !
  if (present(odesc)) then
    call sic_argument_desc(line(ifirst:ilast),ilast-ifirst+1,odesc,error)
    if (error)  return
    !
  elseif (present(ostring)) then  ! Characters
    if (chtyp.gt.0) then
      call sic_shape(ostring,line,ifirst,ilast,parg,error)
    elseif (chtyp.eq.0) then
      call sic_expand(ostring,line,ifirst,ilast,parg,error)
      olen = parg   ! Even if error...
    else
      call sic_keyw(ostring,line,ifirst,ilast,parg,error)
    endif
    if (error) return
    olen = parg
    !
  else    ! Numerics or logicals
    call sic_shape(expr,line,ifirst,ilast,parg,error)
    !
    if (present(ologi)) then
      call sic_math_logi (expr,parg,l,error)
      if (error) return
      ologi = l
    elseif (present(oreal)) then
      call sic_math_real (expr,parg,r4,error)
      if (error) return
      oreal = r4
    elseif (present(odble)) then
      call sic_math_dble (expr,parg,r8,error)
      if (error) return
      odble = r8
    elseif (present(ointe)) then
      call sic_math_inte (expr,parg,i4,error)
      if (error) return
      ointe = i4
    elseif (present(olong)) then
      call sic_math_long (expr,parg,i8,error)
      if (error) return
      olong = i8
    elseif (present(oshort)) then
      call sic_math_inte (expr,parg,i4,error)
      if (error) return
      oshort = i4
    endif
  endif
  !
101 format('Missing argument number ',i3,' of Command ',a,'\',a)
102 format('Missing argument number ',i3,' of Option ',a)
104 format('Option ',i3,' or argument ',i3,' out of bounds')
end subroutine sic_argument
!
subroutine sic_argument_desc(argum,larg,odesc,error)
  use sic_interfaces, except_this=>sic_argument_desc
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  ! Produce a valid descriptor describing the argument
  !---------------------------------------------------------------------
  character(len=*),       intent(in)    :: argum  !
  integer(kind=4),        intent(in)    :: larg   ! Length of argum
  type(sic_descriptor_t), intent(out)   :: odesc
  logical,                intent(inout) :: error
  ! Local
  logical :: found
  integer(kind=4) :: ier,lexpr
  character(len=argument_length) :: expr
  real(kind=8) :: r8
  integer(kind=8) :: i8
  !
  found = .false.  ! Not verbose
  call sic_materialize(argum,odesc,found)
  if (found)  return
  !
  ! Not found, this MUST be an explicit scalar value:
  !   Floats: 1.23E9
  !   Integer: 123
  !   Logicals: .true. or .false.  (YES and NO are variables, not values)
  !   Characters: "Hello"          (Hello without double quotes is rejected)
  ! Any other form would be a variable name catched above.
  !
  ! I would like to distinguish clearly between strings, logicals, integers,
  ! and "the others" (floats obviously). For now the code below is not perfect.
  ! Check what is done with build_tree+evaluate_tree in the sic_math_*
  ! routines.
  if (argum(1:1).eq.'"' .or. argum(larg:larg).eq.'"') then
    ! Assume a character string, e.g. "Hello" or 'myvar'"-suffix"
    call sic_expand(expr,argum,1,larg,lexpr,error)
    if (error)  return
    call sic_incarnate(expr(1:lexpr),odesc,error)
    if (error)  return
  else
    ! Try to read as integer, else compute as float
    read(argum,'(I20)',iostat=ier) i8
    if (ier.eq.0) then
      ! Successfully read into 'i8'
      call sic_incarnate(i8,odesc,error)
      if (error)  return
    else
      ! Asumme a scalar floating point, e.g. 1.23, 12E+3, 1+23, 1+pi
      call sic_math_dble(argum,larg,r8,error)
      if (error)  return
      call sic_incarnate(r8,odesc,error)
      if (error)  return
    endif
  endif
  !
end subroutine sic_argument_desc
!
function sic_present(iopt,iarg)
  use sic_structures
  !---------------------------------------------------------------------
  ! @ public
  !  Is argument IARG of option IOPT present ?
  !---------------------------------------------------------------------
  logical :: sic_present  ! Function value on return
  integer(kind=4), intent(in) :: iopt  ! Option number (0=command)
  integer(kind=4), intent(in) :: iarg  ! Argument number (0=option)
  !
  sic_present=.false.
  if (iopt.gt.maxopt .or. iopt.lt.0 .or. iarg.lt.0) return
  if (iarg.gt.ccomm%narg(iopt)) return
  sic_present = ccomm%ibeg(ccomm%popt(iopt)+iarg).ne.0
end function sic_present
!
function sic_len(iopt,iarg)
  use sic_structures
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public
  ! Length (number of characters) of argument IARG of option IOPT
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_len  ! Function value on return
  integer(kind=4), intent(in) :: iopt  ! Argument number (0=option)
  integer(kind=4), intent(in) :: iarg  ! Option number (0=command
  ! Local
  integer(kind=4) :: parg
  !
  sic_len = 0
  if (iopt.gt.maxopt .or. iopt.lt.0 .or. iarg.lt.0) return
  if (iarg.gt.ccomm%narg(iopt)) return
  parg = ccomm%popt(iopt)+iarg
  sic_len = ccomm%iend(parg) - ccomm%ibeg(parg) + 1
end function sic_len
!
function sic_start(iopt,iarg)
  use sic_structures
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public
  !  Return the position (first character) of argument IARG of option
  ! IOPT
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_start  ! Function value on return
  integer(kind=4), intent(in) :: iopt  ! Argument number (0=option)
  integer(kind=4), intent(in) :: iarg  ! Option number (0=command)
  !
  sic_start = 0
  if (iopt.gt.maxopt .or. iopt.lt.0 .or. iarg.lt.0) return
  if (iarg.gt.ccomm%narg(iopt)) return
  sic_start = ccomm%ibeg(ccomm%popt(iopt)+iarg)
end function sic_start
!
function sic_end(iopt,iarg)
  use sic_structures
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public
  !  Return the position (last character) of argument IARG of option
  ! IOPT
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_end  ! Function value on return
  integer(kind=4), intent(in) :: iopt  ! Argument number (0=option)
  integer(kind=4), intent(in) :: iarg  ! Option number (0=command)
  !
  sic_end = 0
  if (iopt.gt.maxopt .or. iopt.lt.0 .or. iarg.lt.0) return
  if (iarg.gt.ccomm%narg(iopt)) return
  sic_end = ccomm%iend(ccomm%popt(iopt)+iarg)
end function sic_end
!
function sic_narg(iopt)
  use sic_structures
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public
  ! Return the number of arguments passed to the Ith option (0 ==
  ! command)
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_narg  ! Function value on return
  integer(kind=4), intent(in) :: iopt  !
  !
  sic_narg = 0
  if (iopt.lt.0 .or. iopt.gt.maxopt) return
  sic_narg = ccomm%narg(iopt)
end function sic_narg
!
function sic_nopt(dummy)
  use sic_structures
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_nopt  ! Function value on return
  integer(kind=4) :: dummy     !
  !
  sic_nopt = nopt(ccomm%icom)
end function sic_nopt
!
function sic_lire()
  use sic_structures
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public
  ! To be checked and documented
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_lire  ! Function value on return
  !
  if (library_mode) then
    sic_lire = -10
  elseif (nlire.gt.0) then
    sic_lire = mlire(nlire)
  else
    sic_lire = -10
  endif
end function sic_lire
!
subroutine sic_expand(argum,line,ifirst,ilast,length,error)
  use sic_interfaces, except_this=>sic_expand
  use sic_structures
  use sic_interactions
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !   Format an argument by expanding the variables, etc...
  !---------------------------------------------------------------------
  character(len=*), intent(out)   :: argum   ! Returned argument
  character(len=*), intent(in)    :: line    ! Command line
  integer(kind=4),  intent(in)    :: ifirst  ! Pointer to start
  integer(kind=4),  intent(in)    :: ilast   ! Pointer to end
  integer(kind=4),  intent(out)   :: length  ! Argument length
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SIC_CHAR'
  logical :: quiet,apos,found
  integer(kind=4) :: kstart,kapost
  integer(kind=4) :: iquote,jquote,kquote,kend
  character(len=1), parameter :: quote=''''
  character(len=1), parameter :: apost='"'
  real(kind=8) :: d
  logical :: dlogi
  equivalence (d,dlogi)
  !
  kend = len(argum)
  iquote = ifirst
  kquote = index(line(ifirst:ilast),quote)
  kapost = index(line(ifirst:ilast),apost)
  !
  if (kquote.eq.0) then
    apos = .true.
  elseif (kapost.ne.0) then
    apos = kquote.gt.kapost
  else
    apos = .false.
  endif
  if (apos) kquote = kapost
  kstart = 1
  quiet = sic_quiet
  sic_quiet = .true.
  !
  ! Loop on quoted expressions in command line
  do while (kquote.ne.0)
    if (kquote.gt.1) then
      argum(kstart:) = line(iquote:iquote+kquote-2)
      kstart = kstart+kquote-1
      if (kstart.gt.kend) goto 20
    endif
    kquote = kquote+iquote
    !
    ! Plain string within "double-quotes"
    if (apos) then
      jquote = index(line(kquote:ilast),apost)
      if (jquote.ne.0) then
        !
        ! Check double ""
        jquote = jquote+kquote-2
        if (line(jquote+2:jquote+2).eq.apost) then
          jquote = jquote+1
          argum(kstart:) = line(kquote:jquote)
          kstart = kstart+jquote-kquote+1
          jquote = jquote-1
        else
          argum(kstart:) = line(kquote:jquote)
          kstart = kstart+jquote-kquote+1
        endif
        ! End check
      else
        call sic_message(seve%e,rname,'No closing "')
        error = .true.
        !! goto 20 
        sic_quiet = quiet 
        length = 0
        return 
      endif
      iquote = jquote+2
      kquote = index(line(iquote:ilast),quote)
      kapost = index(line(iquote:ilast),apost)
    else
      jquote = index(line(kquote:ilast),quote)
      if (jquote.ne.0) then
        jquote = jquote+kquote-2
        call sic_expand_variable(line(kquote:jquote),argum(kstart:),found,error)
        if (error)  goto 20
        if (found) then
          kstart = kstart+len_trim(argum(kstart:))
        else
          ! Nothing valid, just 'sometext'
          !
          !   Either  return this text with the quotes
          ! argum(kstart:) = line(kquote-1:jquote+1)
          ! kstart = kstart+jquote-kquote+3         
          !   or without the quotes ?...
          ! argum(kstart:) = line(kquote:jquote)
          ! kstart = kstart+jquote-kquote+1
          !
          !   and proceed ?
          ! continue
          !
          ! or abort with an error.
          ! user can place the invalid text between double quote if needed
          error = .true.
          sic_quiet = quiet 
          length = 0
          return 
          !
          ! The initial code was just this: no error, nothing done...
          ! goto 20
        endif
        !
        ! Return error status ?
        iquote = jquote+2
        if (kstart.gt.kend) goto 20
        if (iquote.gt.ilast) then
          kquote = 0
          kapost = 0
        else
          kquote = index(line(iquote:ilast),quote)
          kapost = index(line(iquote:ilast),apost)
        endif
      else
        ! No closing quote: stop processing here
        call sic_message(seve%e,rname,'No closing ''')
        error = .true.
!!      goto 20
        sic_quiet = quiet 
        length = 0
        return 
      endif
      !
    endif
    !
    if (kquote.eq.0) then
      apos = .true.
    elseif (kapost.ne.0) then
      apos = kquote.gt.kapost
    else
      apos = .false.
    endif
    if (apos) kquote = kapost
  enddo
  !
  ! Trailing arguments if any
  if (kstart.gt.kend) goto 20
  argum(kstart:) = line(iquote:ilast)
  !
  ! Restore quiet status and return
20 sic_quiet = quiet
  length = kstart+ilast-iquote
  if (length.gt.kend) then
    length = kend 
    call sic_message(seve%e,rname,  &
      'String '''//line(iquote:ilast)//''' too long for argument')
    error = .true.
  endif
end subroutine sic_expand
!
subroutine sic_real_to_string(num,string)
  use gbl_format
  use sic_dependencies_interfaces
  use sic_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  ! Format a single-precision float according to current SIC PRECISION
  !---------------------------------------------------------------------
  real(kind=4),     intent(in)  :: num     !
  character(len=*), intent(out) :: string  !
  !
  call sic_float_to_string(real(num,kind=8),fmt_r4,string)
  !
end subroutine sic_real_to_string
!
subroutine sic_dble_to_string(num,string)
  use gbl_format
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_dble_to_string
  !---------------------------------------------------------------------
  ! @ private
  ! Format a double-precision float according to current SIC PRECISION
  !---------------------------------------------------------------------
  real(kind=8),     intent(in)  :: num     !
  character(len=*), intent(out) :: string  !
  !
  call sic_float_to_string(num,fmt_r8,string)
  !
end subroutine sic_dble_to_string
!
subroutine sic_float_to_string(num,itype,string)
  use gbl_format
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_float_to_string
  use sic_interactions
  !---------------------------------------------------------------------
  ! @ private
  ! Format a float (single or double) according to current SIC
  ! PRECISION. This subroutine always receives a double-precision
  ! float as input, but its input type is taken into account.
  !---------------------------------------------------------------------
  real(kind=8),     intent(in)  :: num     !
  integer(kind=4),  intent(in)  :: itype   !
  character(len=*), intent(out) :: string  !
  ! Local
  integer(kind=4) :: nf,ndec,ndigit,larg
  integer(kind=4) :: i4
  integer(kind=8) :: i8
  real(kind=4) :: r4
  real(kind=8), parameter :: maxi4=2147483647.d0
  real(kind=8), parameter :: maxi8=9223372036854775807.d0
  !
  if (sicprecis.eq.fmt_r8 .or. (itype.eq.fmt_r8.and.sicprecis.eq.0)) then
    if (abs(num).gt.maxi4) then
      ndec = 2
    else
      i4 = int(num)
      if (dble(i4).eq.num) then
        ndec = 16
      else
        ndec = 2
      endif
    endif
    ndigit = 16
    !
  elseif (sicprecis.eq.fmt_r4 .or. (itype.eq.fmt_r4.and.sicprecis.eq.0)) then
    if (abs(num).gt.maxi4) then
      ndec = 2
    else
      r4 = num
      i4 = int(r4)
      if (float(i4).eq.r4) then
        ndec = 7
      else
        ndec = 2
      endif
    endif
    ndigit = 7
    !
  elseif (sicprecis.eq.fmt_i8) then
    if (abs(num).gt.maxi8) then
      ndec = 2
    else
      i8 = int(num,8)
      if (dble(i8).eq.num) then
        ndec = 20
      else
        ndec = 2
      endif
    endif
    ndigit = 20
  endif
  !
  call sic_spanum(string,num,0,nf,larg,0.d0,ndigit,ndec)
  string(larg+1:) = ''
end subroutine sic_float_to_string
!
subroutine sic_long_to_string(i8,string)
  use gbl_message
  use sic_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  !   Does the same as 'sic_dble_to_string', but avoid rounding to
  ! a double precision float, which is not precise enough for (really)
  ! long integers.
  !---------------------------------------------------------------------
  integer(kind=8),  intent(in)  :: i8      !
  character(len=*), intent(out) :: string  !
  ! Local
  character(len=128) :: string2
  !
  ! 1) Get the value. Do this in a local copy since it is a fatal error
  !    in Fortran to write a value if the output string is too small.
  !    NB: subroutine sic_spanum also reads the value in a local buffer.
  write(string2,'(I0)') i8
  !
  ! 2) Copy the value.
  !    NB: subroutine sic_spanum can truncate the value and warns the
  !    user if so. Note that truncation can return incorrect values,
  !    both here and in sic_spanum
  if (len_trim(string2).gt.len(string)) then
    call sic_message(seve%w,'SPANUM',  &
      'String too short. Integer number has been truncated.')
  endif
  string = string2
  !
end subroutine sic_long_to_string
!
subroutine sic_logi_to_string(l,string)
  use sic_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  !---------------------------------------------------------------------
  logical :: l                      !
  character(len=*) :: string        !
  !
  if (l) then
    string = 'YES'
  else
    string = 'NO'
  endif
end subroutine sic_logi_to_string
!
subroutine sic_var_to_string(var,string)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_var_to_string
  use gildas_def
  use gbl_format
  use gbl_message
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  !
  !---------------------------------------------------------------------
  type(sic_descriptor_t) :: var     !
  character(len=*)       :: string  !
  ! Global
  include 'gbl_memory.inc'
  ! Local
  integer(kind=4) :: i,nc,ntype,narg
  integer(kind=address_length) :: ipnt
  real(kind=8) :: args(16)
  !
  narg = min(desc_nelem(var),16)
  ipnt = bytpnt(var%addr,membyt)
  !
  ntype = var%type
  if (ntype.eq.fmt_l) then
    ! Logical
    call l_type_to_string(narg,membyt(ipnt),string)
  elseif (ntype.gt.0) then
    ! Characters
    call destoc(var%type,var%addr,string)
  else
    if (ntype.eq.fmt_c4) then
      ! Complex
      ! call c4_type_to_string(narg,membyt(ipnt),string)
      call sic_message(seve%e,'LET','Complex not supported')
      string = '********'
    else
      ! Numeric values
      if (ntype.eq.fmt_r8) then
        call r8tor8(membyt(ipnt),args,narg)
      elseif (ntype.eq.fmt_r4) then
        call r4tor8(membyt(ipnt),args,narg)
      elseif (ntype.eq.fmt_i8) then
        call i8tor8(membyt(ipnt),args,narg)
      elseif (ntype.eq.fmt_i4) then
        call i4tor8(membyt(ipnt),args,narg)
      else
        narg = 0
        string = '<UNKNOWN TYPE>'
      endif
      nc = 1
      do i = 1,narg
        call sic_dble_to_string(args(i),string(nc:))
        nc = nc + len_trim(string(nc:))+ 1
      enddo
    endif
  endif
  nc = len_trim(string)+1
  string(nc:nc) = char(0)
end subroutine sic_var_to_string
!
subroutine sic_expand_variable(line,argum,found,error)
  use sic_interfaces, except_this=>sic_expand_variable
  use gbl_format
  !---------------------------------------------------------------------
  ! @ private
  !   Replace a variable name by its value
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Command line
  character(len=*), intent(out)   :: argum  ! Returned argument
  logical,          intent(out)   :: found  ! Variable has been resolved
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  integer(kind=4) :: larg
  integer(kind=4) :: icode
  real(kind=8) :: d  ! 2 words buffer for any kind of result
  !
  ! Try a character variable
  found = .true.
  call sic_get_char(line,argum,larg,error)
  if (.not.error)  return
  !
  ! Must be a mathematical expression. Try to decode, and then format.
  error = .false.
  call sic_math_auto (line,len_trim(line),d,icode,error)
  if (error)  return
  if (icode.eq.fmt_r8) then  ! Float expression
    call sic_dble_to_string(d,argum)
    !
  elseif (icode.eq.fmt_r4) then  ! Float expression
    call sic_real_to_string(d,argum)
    !
  elseif (icode.eq.fmt_i8) then  ! Integer expression
    call sic_long_to_string(d,argum)
    !
  elseif (icode.eq.fmt_l) then  ! Logical expression
    call sic_logi_to_string(d,argum)
    !
  else ! Nothing valid, just 'sometext'
    found = .false.
  endif
  !
end subroutine sic_expand_variable
!
subroutine sic_shape(argum,line,ifirst,ilast,length,error)
  use sic_interfaces, except_this=>sic_shape
  use sic_structures
  use sic_interactions
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !  Format an argument
  !  Similar to SIC_EXPAND, but does not suppress double quotes
  !---------------------------------------------------------------------
  character(len=*), intent(out)   :: argum   ! Returned argument
  character(len=*), intent(in)    :: line    ! Command line
  integer(kind=4),  intent(in)    :: ifirst  ! Pointer to start
  integer(kind=4),  intent(in)    :: ilast   ! Pointer to end
  integer(kind=4),  intent(out)   :: length  ! Argument length
  logical,          intent(inout) :: error   ! Error flag
  ! Local
  character(len=*), parameter :: rname='SIC_CHAR'
  logical :: quiet,apos,found
  integer(kind=4) :: kstart,kapost
  integer(kind=4) :: iquote,jquote,kquote,kend
  character(len=1), parameter :: quote=''''
  character(len=1), parameter :: apost='"'
  real(kind=8) :: d
  logical :: dlogi
  equivalence (d,dlogi)
  !
  kend = len(argum)
  iquote = ifirst
  kquote = index(line(ifirst:ilast),quote)
  kapost = index(line(ifirst:ilast),apost)
  !
  if (kquote.eq.0) then
    apos = .true.
  elseif (kapost.ne.0) then
    apos = kquote.gt.kapost
  else
    apos = .false.
  endif
  if (apos) kquote = kapost
  kstart = 1
  quiet = sic_quiet
  sic_quiet = .true.
  !
  ! Loop on quoted expressions in command line
  do while (kquote.ne.0)
    if (kquote.gt.1) then
      argum(kstart:) = line(iquote:iquote+kquote-2)
      kstart = kstart+kquote-1
      if (kstart.gt.kend) goto 20
    endif
    kquote = kquote+iquote
    !
    ! Plain string within "double-quotes"
    if (apos) then
      jquote = index(line(kquote:ilast),apost)
      if (jquote.ne.0) then
        jquote = jquote+kquote
        argum(kstart:) = line(kquote-1:jquote)
        kstart = kstart+jquote-kquote+1
      else
        call sic_message(seve%e,rname,'No closing "')
        error = .true.
        goto 20
      endif
      iquote = jquote
      kquote = index(line(iquote:ilast),quote)
      kapost = index(line(iquote:ilast),apost)
    else
      jquote = index(line(kquote:ilast),quote)
      if (jquote.ne.0) then
        jquote = jquote+kquote-2
        call sic_expand_variable(line(kquote:jquote),argum(kstart:),found,error)
        if (error)  goto 20
        if (found) then
          kstart = kstart+len_trim(argum(kstart:))
        else
          ! Nothing valid, just 'sometext'
          argum(kstart:) = line(kquote-1:jquote+1)
          kstart = kstart+jquote-kquote+3
          if (kstart.gt.kend) goto 20
        endif
        !
        ! Return error status ?
        iquote = jquote+2
        if (kstart.gt.kend) goto 20
        if (iquote.gt.ilast) then
          kquote = 0
          kapost = 0
        else
          kquote = index(line(iquote:ilast),quote)
          kapost = index(line(iquote:ilast),apost)
        endif
      else
        ! No closing quote: stop processing here
        call sic_message(seve%e,rname,'No closing ''')
        error = .true.
        goto 20
      endif
      !
    endif
    !
    if (kquote.eq.0) then
      apos = .true.
    elseif (kapost.ne.0) then
      apos = kquote.gt.kapost
    else
      apos = .false.
    endif
    if (apos) kquote = kapost
  enddo
  !
  ! Trailing arguments if any
  if (kstart.gt.kend) goto 20
  argum(kstart:) = line(iquote:ilast)
  !
  ! Restore quiet status and return
20 sic_quiet = quiet
  length = min(kend,kstart+ilast-iquote)
end subroutine sic_shape
!
subroutine sic_keyw(argum,line,ifirst,ilast,length,error)
  use sic_interfaces, except_this=>sic_keyw
  use sic_structures
  use sic_interactions
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !  Format an argument
  !  Similar to SIC_EXPAND and SIC_SHAPE but check on syntax
  !---------------------------------------------------------------------
  character(len=*), intent(out)   :: argum   ! Returned argument
  character(len=*), intent(in)    :: line    ! Command line
  integer(kind=4),  intent(in)    :: ifirst  ! Pointer to start
  integer(kind=4),  intent(in)    :: ilast   ! Pointer to end
  integer(kind=4),  intent(out)   :: length  ! Argument length
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  logical :: quiet,apos,found
  integer(kind=4) :: kstart,kapost
  integer(kind=4) :: iquote,jquote,kquote,kend,i
  character(len=1), parameter :: quote=''''
  character(len=1), parameter :: apost='"'
  real(kind=8) :: d
  logical :: dlogi
  equivalence (d,dlogi)
  !
  kend = len(argum)
  iquote = ifirst
  kquote = index(line(ifirst:ilast),quote)
  kapost = index(line(ifirst:ilast),apost)
  !
  if (kquote.eq.0) then
    apos = .true.
  elseif (kapost.ne.0) then
    apos = kquote.gt.kapost
  else
    apos = .false.
  endif
  if (apos) kquote = kapost
  kstart = 1
  quiet = sic_quiet
  sic_quiet = .true.
  !
  ! Loop on quoted expressions in command line
  do while (kquote.ne.0)
    if (kquote.gt.1) then
      argum(kstart:) = line(iquote:iquote+kquote-2)
      kstart = kstart+kquote-1
      if (kstart.gt.kend) goto 20
    endif
    kquote = kquote+iquote
    !
    ! Plain string within "double-quotes"
    if (apos) then
      jquote = index(line(kquote:ilast),apost)
      if (jquote.ne.0) then
        jquote = jquote+kquote
        argum(kstart:) = line(kquote-1:jquote)
        kstart = kstart+jquote-kquote+1
      else
        call sic_message(seve%e,'SIC_CHAR','No closing "')
        error = .true.
        goto 20
      endif
      iquote = jquote
      kquote = index(line(iquote:ilast),quote)
      kapost = index(line(iquote:ilast),apost)
    else
      jquote = index(line(kquote:ilast),quote)
      if (jquote.ne.0) then
        jquote = jquote+kquote-2
        call sic_expand_variable(line(kquote:jquote),argum(kstart:),found,error)
        if (error)  goto 20
        if (found) then
          kstart = kstart+len_trim(argum(kstart:))
        else
          ! Nothing valid, just 'sometext'
          goto 20
        endif
        !
        ! Return error status ?
        iquote = jquote+2
        if (kstart.gt.kend) goto 20
        if (iquote.gt.ilast) then
          kquote = 0
          kapost = 0
        else
          kquote = index(line(iquote:ilast),quote)
          kapost = index(line(iquote:ilast),apost)
        endif
      else
        ! No closing quote: stop processing here
        call sic_message(seve%e,'SIC_CHAR','No closing ''')
        error = .true.
        goto 20
      endif
      !
    endif
    !
    if (kquote.eq.0) then
      apos = .true.
    elseif (kapost.ne.0) then
      apos = kquote.gt.kapost
    else
      apos = .false.
    endif
    if (apos) kquote = kapost
  enddo
  !
  ! Trailing arguments if any
  if (kstart.gt.kend) goto 20
  argum(kstart:) = line(iquote:ilast)
  !
  ! Restore quiet status and return
20 sic_quiet = quiet
  length = kstart+ilast-iquote
  !
  ! Bad programming in several areas MAY prevent this test to be used
  !!
  !! if (length.gt.kend) then
  !!  call sic_message(seve%e,'SIC_KE','Argument too long for keyword '//trim(argum))
  !!  error = .true.
  !!  return
  !! endif
  !
  do i=1,min(kend,length)
    if ( ichar(argum(i:i)).ge.ichar('a') .and.  &
         ichar(argum(i:i)).le.ichar('z') ) then
      argum(i:i) = char(ichar(argum(i:i))+ichar('A')-ichar('a'))
    endif
  enddo
end subroutine sic_keyw
!
subroutine sic_spanum(string,anum,nfx,nf,ndg,range,digit,ndc)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_spanum
  !---------------------------------------------------------------------
  ! @ public
  !   This routine is called for numbering. It translates a number into
  ! a character string.
  !
  !   Maximum number of significant digits is MXDIG0 or DIGIT if non
  ! zero. If your computer has a lower accuracy, you should accordingly
  ! decrease the value of MXDIG0 in order to get rid of round-off
  ! troubles.
  !
  !   NDC is the range in which fixed format is used.
  !---------------------------------------------------------------------
  character(len=*), intent(out) :: string  ! Formatted result
  real(kind=8),     intent(in)  :: anum    ! Number to be formatted
  integer(kind=4),  intent(in)  :: nfx     ! Desired format
  integer(kind=4),  intent(out) :: nf      ! Used format 1 fixed, 0 Integer, -1 Float
  integer(kind=4),  intent(out) :: ndg     ! Number of characters in STRING
  real(kind=8),     intent(in)  :: range   ! Reduce number of digits for smaller numbers
  integer(kind=4),  intent(in)  :: digit   ! Max number of digits
  integer(kind=4),  intent(in)  :: ndc     ! Max number of decimals
  ! Local
  integer(kind=4), parameter :: mxexp=3
#if defined(VAX)
  integer(kind=4), parameter :: mxdig0=16     ! Maximum number of significant digits
#else
  integer(kind=4), parameter :: mxdig0=14     ! Maximum number of significant digits
#endif
  integer(kind=4) :: mantis(mxdig0+1)         ! Allow one digit for round off
  integer(kind=4) :: itab  (mxdig0+5+mxexp)   !
  real(kind=8) :: sn,p10,tmp
  integer(kind=4) :: jtab,in(10),im,ip,ipnt,ie
  integer(kind=4) :: maxdig,lose,ip10,i,j,lgmant,m1,m2,imot,i1,j1,k1
  !
  !      data in/'0','1','2','3','4','5','6','7','8','9'/
  !      data im,ip,ipnt,ie /'-','+','.','E'/
  ! Standard syntax, in ASCII
  data in/48,49,50,51,52,53,54,55,56,57/
  data im,ip,ipnt,ie /45,43,46,69/
  !
  ! First check for IEEE special cases (NaN, +INF, -INF)
  call gag_infini (anum,string,ndg)
  if (ndg.ne.0) return
  !
  ! Compute MAXDIG = max. number of significant digits
  ! Compute mantissa in the range 0.1 thru 1.
  sn=dabs(anum)
  if (sn.eq.0.d0) goto 100
  maxdig=mxdig0
  if (digit.ne.0) maxdig = min(maxdig,digit)
  if (range.gt.0.d0) then
    tmp =sn/range
    tmp =dlog10(tmp)+0.5d0
    lose=floor(tmp)
    maxdig=min(maxdig,maxdig+lose)
    if (maxdig.le.0) goto 100
  endif
  p10=dlog10(sn)
  !
  ! Version to avoid overflows in the range MinReal, MaxReal
  ip10 = floor(p10)
  sn=sn/(10.d0**ip10)
  sn=sn/10.d0
  ip10 = ip10+1
  !
  mantis(1)=0
  do i=2,maxdig
    sn=10.d0*sn
    mantis(i)=floor(sn)
    sn=sn-dble(mantis(i))
  enddo
  tmp=10.d0*sn+0.5d0
  mantis(maxdig+1)=floor(tmp)
  !
  ! Propagate round-off digit
  ! Drop away right-hand zeros
  !
  j=maxdig+1
  m2=1
  do i=1,maxdig
    if (mantis(j).lt.10) then
      if (mantis(j).gt.0) m2=max(m2,j)
    else
      mantis(j)=0
      mantis(j-1)=mantis(j-1)+1
    endif
    j=j-1
  enddo
  ip10=ip10+mantis(1)
  m1=1
  if (mantis(1).eq.0 .and. m2.gt.1) m1=2
  !
  ! Convert array MANTIS to a character string of length LGMANT
  ! Truncate to MAXDIG digits
  j=0
  do i=m1,m2
    j=j+1
    mantis(j)=in(mantis(i)+1)
  enddo
  lgmant = min(j,maxdig)
  !
  ! Check for sign of ANUM
  if (anum.lt.0.d0) then
    ndg=1
    itab(1)=im
  endif
  !
  ! Select the format for output
200 continue
  if (nfx.lt.0 .or. ip10.lt.(1-ndc) .or. ip10.gt.(1+ndc)) then
    !
    ! Floating format
    ndg=ndg+2
    itab(ndg-1)=mantis(1)
    itab(ndg)=ipnt
    do i=2,lgmant
      ndg=ndg+1
      itab(ndg)=mantis(i)
    enddo
    !
    ! Compute and store exponent
    ip10=ip10-1
    !
    ! Store power of 10
    imot=ip
    if (ip10.lt.0) imot=im
    i1 = iabs(ip10)
    if (i1.lt.100) then
      ndg=ndg+4
      itab(ndg-3)=ie
      itab(ndg-2)=imot
      j1=i1/10
      k1=i1-j1*10
      itab(ndg-1)=in(j1+1)
      itab(ndg)  =in(k1+1)
    else
      ndg=ndg+5
      itab(ndg-4)=ie
      itab(ndg-3)=imot
      j1 = i1/100
      itab(ndg-2) = in(j1+1)
      k1 = i1-j1*100
      i1 = k1/10
      itab(ndg-1) = in(i1+1)
      j1 = k1-i1*10
      itab(ndg) = in(j1+1)
    endif
    nf=-1
    !
    ! Fixed format ( 1-NDC <= IP10 <=1+NDC )
    !
  elseif (ip10.le.0) then
    !
    ! Negative or null exponent: add zeroes to the left
    ndg=ndg+2
    itab(ndg-1)=in(1)
    itab(ndg)=ipnt
    if (ip10.ne.0) then
      ip10=-ip10
      do i=1,ip10
        ndg=ndg+1
        itab(ndg)=in(1)
      enddo
    endif
    !
    ! Copy mantissa
    do i=1,lgmant
      ndg=ndg+1
      itab(ndg)=mantis(i)
    enddo
    nf=1
    !
    ! Positive exponent : Store integer part
  else
    do i=1,ip10
      ndg=ndg+1
      itab(ndg)=in(1)
      if (i.le.lgmant) itab(ndg)=mantis(i)
    enddo
    !
    ! Non-integer: store point and fractional part
    if (ip10.lt.lgmant) then
      ndg=ndg+1
      itab(ndg)=ipnt
      do i=ip10+1,lgmant
        ndg=ndg+1
        itab(ndg)=mantis(i)
      enddo
      nf=1
      !
      ! Integer number: add optional decimal point and return.
    elseif (nfx.gt.0) then
      ndg=ndg+1
      itab(ndg)=ipnt
      nf=1
    else
      nf=0
    endif
  endif
  !
  ! Check for access violation
  if (ndg.gt.len(string)) then
    call sic_message(seve%w,'SPANUM',  &
      'String too short. Number has been truncated.')
    ndg = len(string)
  endif
  !
  ! Fill in the buffer STRING
  do i=1,ndg
    jtab = itab(i)
    string(i:i) = char(jtab)
  enddo
  return
  !
100 mantis(1) = in(1)
  lgmant=1
  ip10=1
  ndg=0
  goto 200
end subroutine sic_spanum
