module gag_separators
  !---------------------------------------------------------------------
  ! SIC   Callable Routine
  !     Returns the characters used as Separators in path names.
  !     This allows multi-OS support where the directory names are separated
  !     by either / (Unix), \ (Windows), or : (MAC-OS)
  !---------------------------------------------------------------------
  character(len=1), parameter :: backsl=char(92)
  !
#if defined(WIN32)
  character(len=1), parameter :: insep='/'         !
  character(len=1), parameter :: ousep=backsl      !
  character(len=1), parameter :: disep=backsl      !
#elif defined(MAC)
  character(len=1), parameter :: insep=backsl      !
  character(len=1), parameter :: ousep=':'         !
  character(len=1), parameter :: disep=':'         !
#else
  character(len=1), parameter :: insep=backsl      !
  character(len=1), parameter :: ousep='/'         !
  character(len=1), parameter :: disep='/'         !
#endif
end module gag_separators
!
function sic_getlog_i4(chain,trans)
  use gbl_message
  use gsys_interfaces, except_this=>sic_getlog_i4
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated               ('trans' modified in return)
  !    1 if not found                          ('trans' not modified in return)
  !    2 if found but error during translation ('trans' not modified in return)
  ! ---
  !  I*4 version
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_i4  ! Function value on return
  character(len=*), intent(in)    :: chain  ! Logical name (e.g. 'SPACE_GILDAS')
  integer(kind=4),  intent(inout) :: trans  ! Output value
  ! Local
  character(len=*), parameter :: rname='GETLOG'
  integer(kind=8) :: i8
  integer(kind=4) :: i4
  logical :: error
  character(len=message_length) :: mess
  !
  i8 = trans
  sic_getlog_i4 = sic_getlog_i8(chain,i8)
  if (sic_getlog_i4.ne.0)  return
  !
  error = .false.
  call i8toi4_fini(i8,i4,1,error)
  if (error) then
    ! 'i8' does not fit in 'i4'. Error, let 'trans' unchanged.
    write(mess,'(A,A,A,I0)') 'Failed decoding ',trim(chain),', default to ',trans
    call gsys_message(seve%w,rname,mess)
    sic_getlog_i4 = 2
    return
  endif
  !
  trans = i4
  !
end function sic_getlog_i4
!
function sic_getlog_i8(chain,trans)
  use gbl_message
  use gsys_interfaces, except_this=>sic_getlog_i8
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated               ('trans' modified in return)
  !    1 if not found                          ('trans' not modified in return)
  !    2 if found but error during translation ('trans' not modified in return)
  ! ---
  !  I*8 version
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_i8  ! Function value on return
  character(len=*), intent(in)    :: chain  ! Logical name (e.g. 'SPACE_GILDAS')
  integer(kind=8),  intent(inout) :: trans  ! Output value
  ! Local
  character(len=*), parameter :: rname='GETLOG'
  integer(kind=8) :: i8
  real(kind=8) :: r8
  integer(kind=4) :: ier
  character(len=512) :: string
  character(len=message_length) :: mess
  !
  sic_getlog_i8 = sic_getlog_ch(chain,string)
  if (sic_getlog_i8.eq.1)  return  ! Not found
  !
  ! Try to decode as integer
  read(string,'(I20)',iostat=ier)  i8
  if (ier.eq.0) then  ! Success
    sic_getlog_i8 = 0
    trans = i8
    return
  endif
  !
  ! Try to decode as float, rounded
  read(string,*,iostat=ier)  r8
  if (ier.eq.0) then  ! Success
    sic_getlog_i8 = 0
    trans = nint(r8)
    return
  endif
  !
  write(mess,'(A,A,A,I0)') 'Failed decoding ',trim(chain),', default to ',trans
  call gsys_message(seve%w,rname,mess)
  sic_getlog_i8 = 2  ! Error during translation
  !
end function sic_getlog_i8
!
function sic_getlog_r4(chain,trans)
  use gbl_message
  use gsys_interfaces, except_this=>sic_getlog_r4
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated               ('trans' modified in return)
  !    1 if not found                          ('trans' not modified in return)
  !    2 if found but error during translation ('trans' not modified in return)
  ! ---
  !  R*4 version
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_r4  ! Function value on return
  character(len=*), intent(in)    :: chain  ! Logical name (e.g. 'SPACE_GILDAS')
  real(kind=4),     intent(inout) :: trans  ! Output value
  ! Local
  character(len=*), parameter :: rname='GETLOG'
  integer(kind=4) :: ier
  character(len=512) :: string
  real(kind=8) :: r4
  character(len=message_length) :: mess
  !
  sic_getlog_r4 = sic_getlog_ch(chain,string)
  if (sic_getlog_r4.eq.1)  return  ! Not found
  !
  ! Try to decode as float
  read(string,*,iostat=ier)  r4
  if (ier.eq.0) then  ! Success
    sic_getlog_r4 = 0
    trans = r4
    return
  endif
  !
  write(mess,'(A,A,A,1PG12.5)') 'Failed decoding ',trim(chain),', default to ',trans
  call gsys_message(seve%w,rname,mess)
  sic_getlog_r4 = 2  ! Error during translation
  !
end function sic_getlog_r4
!
function sic_getlog_r8(chain,trans)
  use gbl_message
  use gsys_interfaces, except_this=>sic_getlog_r8
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated               ('trans' modified in return)
  !    1 if not found                          ('trans' not modified in return)
  !    2 if found but error during translation ('trans' not modified in return)
  ! ---
  !  R*8 version
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_r8  ! Function value on return
  character(len=*), intent(in)    :: chain  ! Logical name (e.g. 'SPACE_GILDAS')
  real(kind=8),     intent(inout) :: trans  ! Output value
  ! Local
  character(len=*), parameter :: rname='GETLOG'
  integer(kind=4) :: ier
  character(len=512) :: string
  real(kind=8) :: r8
  character(len=message_length) :: mess
  !
  sic_getlog_r8 = sic_getlog_ch(chain,string)
  if (sic_getlog_r8.eq.1)  return  ! Not found
  !
  ! Try to decode as float
  read(string,*,iostat=ier)  r8
  if (ier.eq.0) then  ! Success
    sic_getlog_r8 = 0
    trans = r8
    return
  endif
  !
  write(mess,'(A,A,A,1PG12.5)') 'Failed decoding ',trim(chain),', default to ',trans
  call gsys_message(seve%w,rname,mess)
  sic_getlog_r8 = 2  ! Error during translation
  !
end function sic_getlog_r8
!
function sic_getlog_l(chain,trans)
  use gbl_message
  use gsys_interfaces, except_this=>sic_getlog_l
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated               ('trans' modified in return)
  !    1 if not found                          ('trans' not modified in return)
  !    2 if found but error during translation ('trans' not modified in return)
  ! ---
  !  Logical (boolean) version. Supported keywords are (case-
  ! insensitive): YES, Y, NO, N
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_l  ! Function value on return
  character(len=*), intent(in)    :: chain  ! Logical name (e.g. 'SPACE_GILDAS')
  logical,          intent(inout) :: trans  ! Output value
  ! Local
  character(len=*), parameter :: rname='GETLOG'
  integer(kind=4) :: nc
  character(len=512) :: string
  character(len=message_length) :: mess
  !
  sic_getlog_l = sic_getlog_ch(chain,string)
  if (sic_getlog_l.eq.1)  return  ! Not found
  !
  call sic_upper(string)
  nc = len_trim(string)
  if (string(1:nc).eq.'YES' .or. string(1:nc).eq.'Y') then
    sic_getlog_l = 0
    trans = .true.
  elseif (string(1:nc).eq.'NO' .or. string(1:nc).eq.'N') then
    sic_getlog_l = 0
    trans = .false.
  else
    write(mess,'(A,A,A,L)') 'Failed decoding ',trim(chain),', default to ',trans
    call gsys_message(seve%w,rname,mess)
    sic_getlog_l = 2  ! Error during translation
    ! 'trans' not modified
  endif
  !
end function sic_getlog_l
!
function sic_ramlog(chain,trans)
  use gbl_message
  use gsys_interfaces, except_this=>sic_ramlog
  !---------------------------------------------------------------------
  ! @ public
  !  Decode a Sic logical as a RAM space, computed in MiB. 3 syntaxes
  ! are allowed:
  !
  ! No unit: default MiB
  !   SPACE_GILDAS  256    ! [MiB] Absolute value
  !
  ! Explicit unit:
  !   SPACE_GILDAS  256MB  ! Supported units: TB GB MB kB TiB GiB MiB kiB
  !
  ! Percent of total RAM:
  !   SPACE_GILDAS  50%    ! [  ] Relative value in fraction of the total
  !                              RAM size
  !
  ! The value can be integer or floating point. The unit or percent can
  ! be separated from the value by 0 or more blanks.
  !
  ! Function value on return is:
  !    0 if found and translated               ('trans' modified in return)
  !    1 if not found                          ('trans' not modified in return)
  !    2 if found but error during translation ('trans' not modified in return)
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_ramlog  ! Function value on return
  character(len=*), intent(in)    :: chain  ! Logical name (e.g. 'SPACE_GILDAS')
  real(kind=4),     intent(inout) :: trans  ! Output value
  ! Local
  character(len=*), parameter :: rname='RAMLOG'
  integer(kind=4) :: ier,nc
  character(len=512) :: string
  real(kind=8) :: factor,value
  integer(kind=8) :: ram
  character(len=message_length) :: mess
  real(kind=8), parameter :: MiB=1048576.d0  ! Number of bytes in 1 MiB (1024**2)
  !
  sic_ramlog = sic_getlog_ch(chain,string)
  if (sic_ramlog.ne.0)  return  ! Not found
  !
  nc = len_trim(string)
  if (string(nc:nc).eq.'%') then
    call gag_ramsize(ram)
    if (ram.le.0) then
      write(mess,'(A,A,A,F0.2,A)')  &
        'Could not get RAM size for your OS, ',trim(chain),' defaults to ',trans,' MiB'
      call gsys_message(seve%w,rname,mess)
      sic_ramlog = 2
      return
    endif
    factor = ram/1d2
    nc = nc-1
    !
  elseif (len_trim(string).lt.3) then  ! Too small to store Value + Unit => No unit
    factor = 1.d0             ! Default MiB
    !
  elseif (string(nc-2:nc).eq.'TiB') then
    factor = 1.024d3*1.024d3  ! TiB to MiB
    nc = nc-3
  elseif (string(nc-2:nc).eq.'GiB') then
    factor = 1.024d3          ! GiB to MiB
    nc = nc-3
  elseif (string(nc-2:nc).eq.'MiB') then
    factor = 1.d0             ! MiB
    nc = nc-3
  elseif (string(nc-2:nc).eq.'kiB') then
    factor = 1.d0/1.024d3     ! kiB to MiB
    nc = nc-3
    !
  elseif (string(nc-1:nc).eq.'TB') then
    factor = 1.d12/MiB  ! TB to MiB
    nc = nc-2
  elseif (string(nc-1:nc).eq.'GB') then
    factor = 1.d9/MiB  ! GB to MiB
    nc = nc-2
  elseif (string(nc-1:nc).eq.'MB') then
    factor = 1.d6/MiB  ! MB to MiB
    nc = nc-2
  elseif (string(nc-1:nc).eq.'kB') then
    factor = 1.d3/MiB  ! kB to MiB
    nc = nc-2
    !
  else  ! No unit
    factor = 1.d0      ! Default MiB
  endif
  !
  ! Decode from int or float e.g. 123 or 123.456 or 1.23456E+02
  read(string(1:nc),*,iostat=ier)  value
  if (ier.ne.0) then
    write(mess,'(A,A,F0.2,A)')  &
      trim(chain),' not understood, defaults to ',trans,' MiB'
    call gsys_message(seve%w,rname,mess)
    sic_ramlog = 2
    return
  endif
  value = value*factor
  !
  ! Sanity check. We could also check if requesting more than the RAM,
  ! but RAM size is not fully portable and raise warnings if not.
  if (value.le.0.d0) then
    write(mess,'(A,A,F0.2,A)')  &
      trim(chain),' can not be negative, defaults to ',trans,' MiB'
    call gsys_message(seve%w,rname,mess)
    sic_ramlog = 2
    return
  endif
  !
  sic_ramlog = 0
  trans = value
  !
end function sic_ramlog
!
function sic_getlog_ch(name,trans)
  use gsys_interfaces, except_this=>sic_getlog_ch
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated ('trans' modified in return)
  !    1 if not found            ('trans' not modified in return)
  ! ---
  !  C*(*) version
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_ch  ! Function value on return
  character(len=*), intent(in)    :: name   ! Logical name
  character(len=*), intent(inout) :: trans  ! Output value
  ! Local
  character(len=path_length) :: string
  !
  string = name
  sic_getlog_ch = sic_getlog_inplace(string)
  if (sic_getlog_ch.eq.0)  trans = string
  !
end function sic_getlog_ch
!
function sic_getlog_inplace(name)
  use gsys_interfaces, except_this=>sic_getlog_inplace
  !---------------------------------------------------------------------
  ! @ public-generic sic_getlog
  !  Translate a logical value. Function value on return is:
  !    0 if found and translated ('name' modified in return)
  !    1 if not found            ('name' not modified in return)
  !  OBSOLESCENT, USE 2 ARGUMENTS INSTEAD  !!!
  ! ---
  !  C*(*) version, obsolescent calling sequence which replaces the
  ! value in place.
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_getlog_inplace
  character(len=*), intent(inout) :: name  ! Output value
  ! Local
  integer(kind=4) :: coderr
  !
  call sic_handlelog(name,' ',1,coderr)
  if (coderr.eq.1) then
    sic_getlog_inplace = 0
  else
    sic_getlog_inplace = 1
  endif
end function sic_getlog_inplace
!
function sic_setlog(name,trans)
  use gsys_interfaces, except_this=>sic_setlog
  !---------------------------------------------------------------------
  ! @ public
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_setlog
  character(len=*), intent(in) :: name   !
  character(len=*), intent(in) :: trans  !
  ! Local
  character(len=512) :: ident
  integer(kind=4) :: coderr
  !
  ident = name
  call sic_handlelog(ident,trans,0,coderr)
  sic_setlog = coderr
end function sic_setlog
!
subroutine sic_handlelog(name,trans,codeop,coderr)
  use gildas_def
  use gbl_message
  use gsys_interfaces, except_this=>sic_handlelog
  !---------------------------------------------------------------------
  ! @ private
  !
  !     Get or Set a log name according to Code Op
  !
  ! Simulates recursive translation of a VMS logical name by looking into
  ! a dictionary in the user's path. The calling list should probably be
  ! modified to include the string length.
  ! Three dictionaries are used: a global dictionary contains site independent
  ! definitions, a local one is defined at installation level and a user
  ! specific one can be used by any individual user to customize his
  ! definitions. Local definitions override more global definitions, so the
  ! user has the final say.
  !---------------------------------------------------------------------
  character(len=*), intent(inout) :: name     !
  character(len=*), intent(in)    :: trans    !
  integer(kind=4),  intent(in)    :: codeop   !
  integer(kind=4),  intent(out)   :: coderr   !
  character(len=*), intent(in)    :: pattern  ! For sic_listlog
  ! Local
  character(len=*), parameter :: rname='GTLGTR'
  integer(kind=4), parameter :: maxlog=500
  integer(kind=4), parameter :: tab=9
  integer(kind=4) :: ll,in,ier,ik,il
  logical :: first,nodict,found
  integer(kind=4) :: pflog(0:27)          ! Alphabetic pointers PF(27)=number of
  integer(kind=4) :: pnlog(maxlog)        ! Chained pointers
  character(len=512) :: ident             !
  character(len=512) :: diclog(maxlog)    ! Identifiers (logical names)
  character(len=512) :: translog(maxlog)  ! Translation for identifiers
  character(len=512) :: upattern
  character(len=1) :: psepar
  logical :: error
  logical :: ispath
  integer(kind=4) :: list(maxlog)
  !
  save                         ! Needed!
  ! Data
  data first /.true./
  data nodict /.false./
  data diclog /maxlog*' '/
  data translog /maxlog*' '/
  data pflog /28*0/
  data pnlog /maxlog*0/
  data psepar /';'/            ! Path separator in a list of paths
  !
  if (codeop.eq.1) then
    coderr = 0                 ! Default value
    !
    ! On first call, open the dictionary
    if (first) then
      error = .false.
      call load_dict(maxlog,pflog,pnlog,diclog,translog,error)
      if (error) nodict = .true.
      first  = .false.
    endif
    ier = sic_expenv (name)
    if (ier.eq.1) coderr = 1
    !
    ! Return if no dictionary could be found
    if (nodict) return
    !
    ! Look for translation
    ident = name
    call sic_upper(ident)
    ier = gag_hasfin(maxlog,pflog,pnlog,diclog,ident,in)
    if (mod(ier,2).ne.0) then
      name=translog(in)
      !
      ! With the original code ( NAME = TRANSLOG(IN) )
      !     GAG_HELP_SIC is replaced by
      !            GAG_HELP:SICHELP.HLP
      !     which in turn is converted by SIC_PARSEF into
      !            /users/gag/NOV95/help/sichelp.hlp
      coderr = 1
    endif
    ier = sic_expenv (name)
    if (ier.eq.1) coderr = 1
    ! Print *,'Log: ',sic_getlog,' ',trim(name)
    return
  else
    !
    ! Set a logical name
    ! On first call, open the dictionary
    if (first) then
      error = .false.
      call load_dict(maxlog,pflog,pnlog,diclog,translog,error)
      first  = .false.
    endif
    !
    ident = name
    ll = lenc(ident)
    call sic_upper(ident)
    coderr  = gag_hasins(maxlog,pflog,pnlog,diclog,ident,in)
    if (coderr.eq.0) then
      call gsys_message(seve%e,rname,'Invalid logical name '//ident)
    elseif (mod(coderr,2).eq.0) then
      call gsys_message(seve%w,rname,'Too many logical names: '//  &
      trim(ident)//' ignored')
    else
      ispath = ident(ll:ll).eq.':'
      call gag_setcleanlog (trans,translog(in),ispath)
      !
      nodict = .false.
      coderr = 1
      call gsys_message(seve%d,rname,'Set '//ident(:ll)//' to '//translog(in))
    endif
  endif
  return
  !
entry sic_listlog(pattern)
  !---------------------------------------------------------------------
  ! @ private
  !  Make a list of the LOGICAL symbols and their translations, using
  ! the input pattern. Use * to list all symbols
  !---------------------------------------------------------------------
  upattern = pattern
  call sic_upper(upattern)
  !
  ! Check if one is listing all variables
  found = .false.
  call gag_haslis(maxlog,pflog,pnlog,list,in)
  do il=1,in
    ik = list(il)
    !
    ! Check if name matches the pattern
    if (.not.match_string(diclog(ik),upattern))  cycle
    !
    write(*,'(A,T22,A,A)') trim(diclog(ik)),' = ',trim(translog(ik))
    found = .true.
  enddo
  !
  if (.not.found)  call gsys_message(seve%w,rname,'No logical name found')
  !
end subroutine sic_handlelog
!
function sic_get_npath(paths,sep)
  use gsys_interfaces, except_this=>sic_get_npath
  !---------------------------------------------------------------------
  ! @ private
  ! Return number of paths in a list of paths PATHS separated by SEP.
  ! Return 0 if input string is empty. Take care that PATHS may or may not
  ! end with a SEP.
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_get_npath  !
  character(len=*), intent(in) :: paths  ! Paths list
  character(len=*), intent(in) :: sep    ! Separator (assume len=1)
  ! Local
  integer(kind=4) :: pa,pr          ! Position absolute and relative
  integer(kind=4) :: pl
  !
  sic_get_npath = 0
  pl = lenc(paths)
  if (pl.eq.0) return
  !
  pa = 0
  do
    sic_get_npath = sic_get_npath+1
    pr = index(paths(pa+1:),sep)
    pa = pa+pr
    if (pr.eq.0 .or. pa.eq.pl) exit
    ! No more separators .OR. last separator is at EOL: stop incrementing
  enddo
  !
end function sic_get_npath
!
subroutine sic_get_path(paths,sep,n,istart,iend)
  use gsys_interfaces, except_this=>sic_get_path
  !---------------------------------------------------------------------
  ! @ private
  ! Return Nth path indices in a list of paths PATHS separated by SEP.
  ! Return indexes for an empty string if such a path does not exist.
  !---------------------------------------------------------------------
  character(len=*), intent(in)  :: paths   ! Paths list
  character(len=*), intent(in)  :: sep     ! Separator (assume len=1)
  integer(kind=4),  intent(in)  :: n       ! Position
  integer(kind=4),  intent(out) :: istart  ! Beginning of string
  integer(kind=4),  intent(out) :: iend    ! End of string
  ! Local
  integer(kind=4) :: i,s1,s2,pl
  !
  pl = lenc(paths)
  s1 = 0
  s2 = 0
  !
  do i=1,n
    s1 = s2
    s2 = s2+index(paths(s2+1:),sep)
    if (s2.eq.s1) s2=pl+1      ! No more SEP, stuck S2 just after EOL
  enddo
  !
  istart = s1+1
  iend   = s2-1
  ! We may have ISTART>IEND, which means there was two contiguous separators
  !
end subroutine sic_get_path
!
subroutine load_dict(maxlog,pflog,pnlog,diclog,translog,error)
  use gildas_def
  use gbl_message
  use gsys_interfaces, except_this=>load_dict
  !---------------------------------------------------------------------
  ! @ private
  !  Fills the internal dictionary, reading from the three possible
  ! configuration files.
  !---------------------------------------------------------------------
  integer(kind=4),    intent(in)    :: maxlog            !
  integer(kind=4),    intent(out)   :: pflog(0:27)       ! Alphabetic pointers PF(27)=number of
  integer(kind=4),    intent(out)   :: pnlog(maxlog)     ! Chained pointers
  character(len=512), intent(inout) :: diclog(maxlog)    ! Identifiers
  character(len=512), intent(inout) :: translog(maxlog)  ! Translation for identifiers
  logical,            intent(inout) :: error             !
  ! Local
  character(len=*), parameter :: rname='DICT'
  integer(kind=4) :: i,ier,in,iunit,l,ll,status,mdict,kk
  character(len=filename_length) :: filnam
  character(len=512) :: line,ident
  logical :: ispath
  !
  status = sic_getlun(iunit)
  if (mod(status,2).eq.0) then
    error = .true.
    return
  endif
  mdict = 3                    ! Have a User dictionary too...
  ! Initialize dictionary structure
  call gag_hasini(maxlog,pflog,pnlog)
  do i=1,mdict
    if (i.eq.1) then
      status = dictname('GLOBAL',filnam)
      if (mod(status,2).eq.0) then
        call gsys_message(seve%f,rname,'No global logical name table')
        call sysexi(fatale)
      endif
    elseif (i.eq.2) then
      status = dictname('LOCAL',filnam)
      if (mod(status,2).eq.0) then
        call gsys_message(seve%w,rname,'No local logical name table')
        goto 30
      endif
    elseif (i.eq.3) then
      status = dictname('USER',filnam)
      if (mod(status,2).ne.0) then
        call gsys_message(seve%d,rname,'Using user defined logical name '//  &
        'table '//filnam)
      else
        call gsys_message(seve%d,rname,'No user defined logical name table')
        goto 30
      endif
    endif
    status = sic_open(iunit,filnam,'OLD',.true.)
    if (status.ne.0) then
      call putios ('E-DICT,  ',status)
      call sic_frelun(iunit)
      error = .true.
      return
    endif
    !
    ! Read dictionary
80  continue
    read (iunit,'(A)',end=90) line
    in = lenc(line)
    call gtlblanc (line,in)
    if (in.eq.0) goto 80
    ll = index(line,' ')
    l  = lenc(line)
    if (ll.le.0.or.ll+1.gt.l) goto 80
    !
    ! Insert or replace in symbol dictionnary
    ident = line(1:ll)
    call sic_upper(ident)
    ier = gag_hasins(maxlog,pflog,pnlog,diclog,ident,in)
    if (ier.eq.0) then
      call gsys_message(seve%e,rname,'Invalid logical name '//ident)
    elseif (mod(ier,2).eq.0) then
      call gsys_message(seve%w,rname,'Too many logical names: '//   &
      trim(ident)//' ignored')
    else
      ! Put into symbol table
      kk = len_trim(ident)
      ispath = ident(kk:kk).eq.':'
      call gag_setcleanlog(line(ll+1:l),translog(in),ispath)
      !!print *,trim(ident)//' == '//trim(translog(in))
    endif
    goto 80
    !
90  close (iunit)
30  continue
  enddo
  call sic_frelun (iunit)
end subroutine load_dict
!
subroutine gtlblanc(c,n)
  use gsys_interfaces, except_this=>gtlblanc
  !---------------------------------------------------------------------
  ! @ private
  !  Reduce the character string C to the standard SIC internal syntax.
  !  Suppress all unecessary separators.
  !  Ignores and destroys comments.
  !---------------------------------------------------------------------
  character(len=*), intent(inout) :: c  ! Character string to be formatted
  integer(kind=4),  intent(inout) :: n  ! Length of C
  ! Local
  integer(kind=4) :: i,nl
  logical :: lo,li
  integer(kind=4), parameter :: tab=9
  !
  if (n.eq.0) return
  !
  lo = .true.
  nl = n
  n = 0
  i = 1
  !
  do while (i.le.nl)
    !
    ! Suppress redondant separators
    li=.false.
    if (c(i:i).ne.' ' .and. c(i:i).ne.char(tab)) goto 20
    ! Space separator
    li=.true.
    ! Not the first one
    if (lo)  go to 100
    ! First one
    c(i:i)=' '
    goto 30
    !
    ! Skip comment area
20  continue
    if (c(i:i).eq.'!') then
      goto 200
    endif
    !
    ! Reset input character string
30  n=n+1
    if (i.ne.n) c(n:n)=c(i:i)
    if (i.gt.n) c(i:i)=' '
100 lo=li
    !
    ! End of loop
    i = i+1
  enddo
  !
  ! Remove trailing separators if any
200 continue
  if (n.ne.0) then
    if (c(n:n).eq.' ') n=n-1
  endif
  ! Clean up end of line
  if (n.lt.len(c)) c(n+1:) = ' '
end subroutine gtlblanc
!
function dictname(dtype,file)
  use gsys_interfaces, except_this=>dictname
  use gildas_def
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public
  !
  ! This system dependent routine returns the full names (including
  ! path) of the (internal) logical name definition files.
  ! Known dictionary types as input are 'GLOBAL', 'LOCAL', or 'USER'.
  ! Any other kind raises an error.
  !
  ! This version for Unix.
  !---------------------------------------------------------------------
  integer(kind=4) :: dictname             !
  character(len=*), intent(in)  :: dtype  ! Dictionary type
  character(len=*), intent(out) :: file   ! Associated file
  ! Local
  character(len=*), parameter :: rname='DICTNAME'
  character(len=2048) :: chain  ! The path can be rather long...
  character(len=16) :: name
  character(len=1) :: psep
  integer(kind=4) :: i,j,l
  logical :: success
  integer(kind=4), parameter :: errcode=12
  !
  chain=' '
  !
#if defined(WIN32)
  psep = ';'
#else
  psep = ':'
#endif
  dictname = 1                 ! Success value
  !
  if (dtype.eq.'GLOBAL'.or.dtype.eq.'LOCAL') then
    ! First search for a GAG_PATH environment variable
    call sic_getenv('GAG_PATH',chain)
    l = lenc(chain)
    ! If GAG_PATH isn't set: fatale
    if (l.eq.0) then
      call gsys_message(seve%f,rname,'Environment variable $GAG_PATH is '//  &
      'not set')
      call sysexi(fatale)
    endif
    ! Look for dictionary file in GAG_PATH
    i = 1
    if (dtype.eq.'GLOBAL') then
      name = 'gag.dico.gbl'
    elseif (dtype.eq.'LOCAL') then
      name = 'gag.dico.lcl'
    endif
    do while (i.le.l)
      j = index(chain(i:l),psep)
      if (j.gt.0) then
        file = chain(i:i+j-2)//'/'//name
        i = i+j
      else
        file = chain(i:l)//'/'//name
        i = l+1
      endif
      inquire (file=file,exist=success)
      if (success) return
    enddo
    ! Nothing found. Generate an error and return.
    call gsys_message(seve%e,rname,'Did not found '//trim(name)//' in '//  &
    '$GAG_PATH')
    dictname = errcode
    file = ' '
  !
  elseif (dtype.eq.'USER') then
    call sic_getenv('HOME',chain)
    file = trim(chain)//'/'//'.gag.dico'
    inquire (file=file,exist=success)
    if (.not.success) dictname = errcode
  !
  else
    call gsys_message(seve%e,rname,'Internal error, no such dictionary '//  &
      dtype)
    dictname = errcode
    file = ' '
  endif
end function dictname
!
function sic_expenv(name)
  use gsys_interfaces, except_this=>sic_expenv
  !---------------------------------------------------------------------
  ! @ private
  !
  ! This Unix specific routine expands environment variables in file names.
  ! Environment variables begin with a $ sign. They are terminated by a /
  ! sign.
  !---------------------------------------------------------------------
  integer(kind=4) :: sic_expenv  !
  character(len=*), intent(inout) :: name  !
  ! Local
  character(len=path_length) :: line
  !
  call sic_resolve_env (name,line)
  if (name.eq.line) then
    sic_expenv = 0
  else
    sic_expenv = 1
  endif
  name = line
end function sic_expenv
!
subroutine sic_ctrans (name,nn,trans,np)
  use gsys_interfaces, except_this=>sic_ctrans
  use gildas_def
  !---------------------------------------------------------------------
  ! @ private
  !     Returns the translation (TRANS(1:NP)) of a Logical name (NAME(1:NN))
  !     NAME and TRANS are assumed to be C Strings, i.e. Byte arrays.
  !---------------------------------------------------------------------
  integer(kind=1), intent(in)    :: name(*)   !
  integer(kind=4), intent(in)    :: nn        !
  integer(kind=1), intent(out)   :: trans(*)  !
  integer(kind=4), intent(inout) :: np        !
  ! Global
  include 'gbl_memory.inc'
  ! Local
  character(len=512) :: tmp
  integer(kind=4) :: im,ier
  integer(kind=address_length) :: il,ip
  !
  il = locstr(tmp)
  ip = bytpnt(il,membyt)
  call bytoby(name,membyt(ip),nn)
  tmp(nn+1:) = ' '
  ier = sic_getlog(tmp)
  im = min(lenc(tmp),np)
  tmp(im+1:im+1) = char(0)
  call bytoby(membyt(ip),trans,im+1)
  np = im
end subroutine sic_ctrans
!
subroutine gag_separ(ins,ous,dis)
  use gag_separators
  !---------------------------------------------------------------------
  ! @ public
  !     Returns the characters used as Separators in path names.
  !     This allows multi-OS support where the directory names are separated
  !     by either / (Unix), \ (Windows), or : (MAC-OS)
  !---------------------------------------------------------------------
  character(len=1), intent(out) :: ins         !
  character(len=1), intent(out) :: ous         !
  character(len=1), intent(out) :: dis         !
  ! Local
  ins = insep
  ous = ousep
  dis = disep
end subroutine gag_separ
!
subroutine gag_release(ostring)
  use gsys_interfaces, except_this=>gag_release
  use gildas_def
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public
  !   Return a string with the release name, date, system, and branch.
  ! Read the string in GAG_VERSION symbol, and optionally replace the
  ! release date by the calling executable date if in HEAD version.
  !---------------------------------------------------------------------
  character(len=*), intent(out) :: ostring  ! Output string
  ! Local
  logical :: found
  character(len=filename_length) :: progname,fullname
  character(len=128) :: version,timestr,prefix,suffix
  integer(kind=4) :: filetime,p1,p2,ier
  !
  version = ''
  ier = sic_getlog('GAG_VERSION',version)
  !
  call getarg(0,progname)  ! NB: progname may be empty if Python master
  found = gag_which(progname,'$PATH',fullname)
  !
  ! Change version date to binary date if "dev":
  if (version(1:4).eq."dev " .and. found) then
    !
    ier = gag_mdate(fullname,filetime)
    !
    if (ier.eq.0) then
      call sic_c_datetime_from_raw(filetime,timestr)
      call sic_lower(timestr)
      !
      ! Split VERSION. May be:
      !     "dev (22oct07 09:27 cest) (pc-fedora6-ifort) source tree"
      ! OR
      !     "dev (pc-fedora6-ifort) source tree"
      !
      p1 = index(version,'(',.true.)   ! Backward search
      prefix = version(:p1-1)  ! = "dev (15oct07 10:41)" or "dev"
      suffix = version(p1:)    ! = "(pc-fedora6-ifort) source tree"
      !
      ! Search if PREFIX is "dev" or "dev (15oct07 10:41)"
      p1 = index(prefix,'(')
      p2 = index(prefix,')')
      if (p1.eq.0) then
        prefix = trim(prefix)//' ('//trim(timestr)//')'
      else
        prefix = prefix(:p1)//trim(timestr)//prefix(p2:)
      endif
      !
      version = trim(prefix)//' '//suffix
    endif
  endif
  !
  ! Echo the Gildas version
  ostring = 'IMAGER specific GILDAS Version: '//version
  !
end subroutine gag_release
!
subroutine gag_setcleanlog (input,output,ispath)
  use gsys_interfaces, except_this=>gag_setcleanlog
  use gag_separators
  !---------------------------------------------------------------------
  ! @ private
  ! Perform a good cleaning on the Logical name definitions to 
  ! use the appropriate system dependent separators.
  !
  ! A better job can be done using the code marked !!BETTER
  ! but that does not seem to be required.
  !---------------------------------------------------------------------
  character(len=*), intent(in)  :: input
  character(len=*), intent(out) :: output
  logical,          intent(in)  :: ispath
  ! Local
  character(len=1), parameter :: psepar=';'
  integer(kind=4) :: ier,i,j,itot,i1,i2,j1,j2,l
  character(len=512) :: path1, path2
  !
  output = input
  ier = sic_expenv(output)
  if (.not.ispath) return
  !
  !
  ! 1/ Perform some cleaning on paths separator, and
  !    add terminating path character.
  i = len_trim(output)
  ! Next line ensure not changing presence or absence of ';' at EOL
  if (output(i:i).ne.psepar) i=i+1
  do
     if (i.eq.0) then
        ! All done
        exit
     elseif (i.eq.1) then
        ! Remove ';' at beginning:
        output=output(2:)
     elseif (output(i-1:i-1).eq.psepar) then
        ! Remove duplicates ';'
        output(i-1:)=output(i:)
     elseif (output(i-1:i-1).eq.':') then
        ! A paths-list symbol: skip
     elseif (output(i-1:i-1).eq.insep) then
        ! Switch "\" into "/" (linux example)
        output(i-1:i-1) = ousep
     elseif (output(i-1:i-1).ne.ousep) then
        ! Add "/" at end if absent (linux example)
        output(i+1:) = output(i:)
        output(i:i)  = ousep
        i=i+1
     endif
     l = i-1
     i = index(output(:l),psepar,.true.)
     j = index(output(:l),insep,.true.) !BETTER
     if (j.gt.i) i = j+1                !BETTER
  enddo
  !
  ! 2/ Remove duplicate paths
  i = 1
  itot = sic_get_npath(output,psepar)
  do
     if (i.ge.itot) exit
     call sic_get_path(output,psepar,i,i1,i2)
     path1 = output(i1:i2)
     j = i+1
     do
        if (j.gt.itot) exit
        call sic_get_path(output,psepar,j,j1,j2)
        path2 = output(j1:j2)
        if (path1.eq.path2) then
           output(j1:)=output(j2+2:)
           itot = sic_get_npath(output,psepar)
           cycle
        endif
        j = j+1
     enddo
     i = i+1
  enddo
end subroutine gag_setcleanlog
