subroutine greg_convert(line,error)
  use gildas_def
  use phys_const
  use gbl_format
  use gbl_message
  use gwcs_types
  use sic_types
  use greg_dependencies_interfaces, no_interface1=>equ_gal_1d,       &
                                    no_interface2=>gal_equ_1d,       &
                                    no_interface3=>equ_equ_1d,       &
                                    no_interface4=>rel_to_abs_1dn8,  &
                                    no_interface5=>abs_to_rel_1dn8
  use greg_interfaces, except_this=>greg_convert
  use greg_xyz
  use greg_wcs
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for command
  !    CONVERT RA0 DEC0 [ANGLE]
  !    1  [/TYPE P_TYPE]
  !    2  [/UNIT]
  !    3  [/SYSTEM EQUATORIAL|GALACTIC [Equinox]]
  !    4  [/VARIABLE A B]
  ! Converts from one projection system or absolute coordinates to the
  ! current projection system.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Global
  include 'gbl_memory.inc'
  ! Local
  character(len=*), parameter :: rname='CONVERT'
  integer(kind=4) :: nc,ier
  integer(kind=4), parameter :: msys=3
  character(len=13) :: keywor,argum,system(msys)
  character(len=32) :: chra,chdec
  real(kind=8) :: ra,dec,ang
  integer(kind=4) :: nkey,type,nsys
  integer(kind=size_length) :: nn
  integer(kind=address_length) :: ipx,ipy
  character(len=6) :: unit(4)
  character(len=13) :: projnam_array(0:mproj)
  real(kind=4) :: equinox
  character(len=message_length) :: mess
  ! Array support
  type(sic_descriptor_t) :: desc1,desc2
  integer(kind=index_length) :: npx,npy
  integer(kind=4) :: vtype
  character(len=80) :: chain
  logical :: found
  real(kind=8), allocatable :: bufx(:),bufy(:)
  type(projection_t) :: oldproj
  ! Data
  data system /'UNKNOWN','EQUATORIAL','GALACTIC'/
  data unit /'SECOND','MINUTE','DEGREE','RADIAN'/
  !
  if (sic_present(1,0)) then
    call sic_ke (line,1,1,argum,nc,.true.,error)
    if (error) return
    !
    call projnam_list(projnam_array)
    call sic_ambigs('CONVERT',argum,keywor,nkey,projnam_array,mproj+1,error)
    if (error) return
    type = nkey-1
  else
    type = p_none
  endif
  !
  ! Find input System
  if (sic_present(3,0)) then
    if (i_system.le.type_un) then
      call greg_message(seve%e,rname,'Cannot convert to UNKNOWN system')
      error = .true.
      return
    endif
    call sic_ke (line,3,1,argum,nc,.true.,error)
    if (error) return
    call sic_ambigs('CONVERT',argum,keywor,nsys,system,3,error)
    if (error) return
    if (nsys.le.type_un) then
      call greg_message(seve%e,rname,'Cannot convert from UNKNOWN system')
      error = .true.
      return
    endif
    if (nsys.eq.type_eq) then
      equinox = i_equinox_def
      call sic_r4(line,3,2,equinox,.false.,error)
      if (error)  return
    endif
  endif
  !
  ! Find input projection center
  if (type.ne.p_none) then
    ! Declination / latitude
    if (type.ne.p_aitoff) then
      call sic_ch(line,0,2,chdec,nc,.true.,error)
      if (error) return
      call sic_sexa(chdec,nc,dec,error)
      if (error)  return
      dec = dec*pi/180.0d0
    elseif (sic_present(0,2)) then
      call greg_message(seve%w,rname,'Declination ignored in AITOFF')
    endif
    ! Right ascension / longitude
    call sic_ch(line,0,1,chra,nc,.true.,error)
    if (error) return
    call sic_sexa(chra,nc,ra,error)
    if (error)  return
    if (nsys.eq.type_eq) then
      ra = ra*pi/12.0d0
    else
      ra = ra*pi/180.0d0
    endif
    ! Angle
    if (sic_present(0,3)) then
      if (type.eq.p_aitoff) then
        call greg_message(seve%w,rname,'Angle ignored in AITOFF')
      elseif (type.eq.p_radio) then
        call greg_message(seve%w,rname,'Angle ignored in RADIO')
      else
        call sic_r8(line,0,3,ang,.true.,error)
        if (error)  return
        ang = ang*pi/180.0d0
      endif
    else
      ang = 0.d0
    endif
  elseif (sic_present(0,1)) then
    call greg_message(seve%w,rname,'Projection center ignored in /TYPE NONE')
  endif
  !
  ! If option /VAR is present, take it, otherwise work on X and Y
  if (sic_present(4,0)) then
    call sic_ke (line,4,1,chain,nc,.true.,error)
    if (error) return
    found = .true.
    call sic_descriptor (chain,desc1,found)
    if (.not.found) then
      call greg_message(seve%e,rname,'Variable is Unknown')
      error = .true.
      return
    endif
    vtype = desc1%type
    if (desc1%readonly) then
      call greg_message(seve%e,rname,'Variable is Protected')
      error = .true.
      return
    endif
    if (vtype.ne.fmt_r8) then
      call greg_message(seve%e,rname,'Variable must be R*8')
      error = .true.
      return
    endif
    npx = desc_nelem(desc1)
    ipx = gag_pointer(desc1%addr,memory)
    !
    call sic_ke (line,4,2,chain,nc,.true.,error)
    if (error) return
    found = .true.
    call sic_descriptor (chain,desc2,found)
    if (.not.found) then
      call greg_message(seve%e,rname,'Variable is Unknown')
      error = .true.
      return
    endif
    vtype = desc2%type
    if (desc2%readonly) then
      call greg_message(seve%e,rname,'Variable is Protected')
      error = .true.
      return
    endif
    if (vtype.ne.fmt_r8) then
      call greg_message(seve%e,rname,'Variable must be R*8')
      error = .true.
      return
    endif
    npy = desc_nelem(desc2)
    if (npy.ne.npx) then
      call greg_message(seve%e,rname,'Inconsistent sizes')
      error = .true.
      return
    endif
    nn = npx
    ipy = gag_pointer(desc2%addr,memory)
  else
    ipx = gag_pointer(locwrd(column_x),memory)
    ipy = gag_pointer(locwrd(column_y),memory)
    nn=nxy
  endif
  if (nn.le.0) then
    call greg_message(seve%w,rname,'No data points, nothing done')
    return
  endif
  !
  ! Allocate working buffers
  allocate(bufx(nn),bufy(nn),stat=ier)
  if (failed_allocate(rname,'buffers',ier,error))  return
  !
  ! Convert angular unit
  if (sic_present(2,0)) then
    if (sic_present(2,1)) then
      call sic_ke (line,2,1,argum,nc,.false.,error)
      if (error)  goto 100
      call sic_ambigs('CONVERT',argum,keywor,nkey,unit,4,error)
      if (error)  goto 100
    else
      nkey = u_angle
    endif
    if (nkey.ne.u_radian) then
      call r8tor8_sl(memory(ipx),bufx,nn)
      call r8tor8_sl(memory(ipy),bufy,nn)
      call uni_to_rad(bufx,memory(ipx),nn,nkey)
      call uni_to_rad(bufy,memory(ipy),nn,nkey)
    endif
  endif
  !
  ! Convert to absolute coordinates
  if (type.ne.p_none) then
    oldproj = gproj
    call gwcs_projec(ra,dec,ang,type,gproj,error)
    call r8tor8_sl(memory(ipx),bufx,nn)
    call r8tor8_sl(memory(ipy),bufy,nn)
    call rel_to_abs_1dn8(gproj,bufx,bufy,memory(ipx),memory(ipy),nn)
    gproj = oldproj
  endif
  !
  ! Convert to current system
  if (sic_present(3,0)) then
    ! Work only if different systems, or different equinoxes for equatorial systems
    if (nsys.ne.i_system .or.  &
       (nsys.eq.type_eq.and.i_system.eq.type_eq.and.equinox.ne.i_equinox)) then
      !
      ! Sanity check for unimplemented ICRS
      if (i_system.eq.type_ic) then
        call greg_message(seve%e,rname,'Conversion to ICRS is not implemented')
        error = .true.
        return
      elseif (nsys.eq.type_ic) then
        call greg_message(seve%e,rname,'Conversion from ICRS is not implemented')
        error = .true.
        return
      endif
      ! Sanity check for unknown equinox
      if (i_system.eq.type_eq .and. i_equinox.eq.equinox_null) then
        call greg_message(seve%e,rname,  &
          'Can not convert to Equatorial system with unset equinox')
        error = .true.
        return
      elseif (nsys.eq.type_eq .and. equinox.eq.equinox_null) then
        call greg_message(seve%e,rname,  &
          'Can not convert from Equatorial system with unknown equinox')
        error = .true.
        return
      endif
      !
      if (nsys.eq.type_eq) then
        write(mess,'(A,1X,F0.1)') 'Converting from Equatorial',equinox
      else
        write(mess,'(A)')         'Converting from Galactic'
      endif
      nc = len_trim(mess)
      if (i_system.eq.type_eq) then
        write(mess(nc+2:),'(A,1X,F0.1)') 'to Equatorial',i_equinox
      else
        write(mess(nc+2:),'(A)')         'to Galactic'
      endif
      call greg_message(seve%i,rname,mess)
      !
      call r8tor8_sl(memory(ipx),bufx,nn)
      call r8tor8_sl(memory(ipy),bufy,nn)
      if (nsys.eq.type_eq) then
        ! From Nsys=Equatorial+Equinox...
        if (i_system.eq.type_eq) then
          ! ... to I_system=Equatorial+I_Equinox
          call equ_equ_1d(bufx,bufy,equinox,memory(ipx),memory(ipy),i_equinox,nn,error)
        else
          ! ... to I_system=Gal
          call equ_gal_1d(bufx,bufy,equinox,memory(ipx),memory(ipy),nn,error)
        endif
      else
        ! From Nsys=Gal to I_system=Equatorial+I_equinox
        call gal_equ_1d(bufx,bufy,memory(ipx),memory(ipy),i_equinox,nn,error)
      endif
      if (error)  return
    endif
  endif
  !
  ! Convert to offsets in current projection
  if (gproj%type.ne.p_none) then
    call r8tor8_sl(memory(ipx),bufx,nn)
    call r8tor8_sl(memory(ipy),bufy,nn)
    call abs_to_rel_1dn8(gproj,bufx,bufy,memory(ipx),memory(ipy),nn)
  endif
  !
100 continue
  deallocate(bufx,bufy)
end subroutine greg_convert
!
subroutine uni_to_rad(in,out,n,unit)
  use gildas_def
  use gbl_constant
  use phys_const
  use greg_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  !---------------------------------------------------------------------
  real(kind=8),              intent(in)  :: in(*)   !
  real(kind=8),              intent(out) :: out(*)  !
  integer(kind=size_length), intent(in)  :: n       !
  integer(kind=4),           intent(in)  :: unit    !
  ! Local
  real(kind=8) :: f
  integer(kind=size_length) :: i
  !
  if (unit.eq.u_second) then
    f = pi/3600.d0/180.d0
  elseif (unit.eq.u_minute) then
    f = pi/60.d0/180.d0
  elseif (unit.eq.u_degree) then
    f = pi/180.d0
  else
    return
  endif
  !
  do i=1,n
    out(i) = in(i)*f
  enddo
end subroutine uni_to_rad
!
subroutine find_blank4(y,bval,eval,nxy,is,ne,in)
  use gildas_def
  use greg_interfaces, except_this=>find_blank4
  !---------------------------------------------------------------------
  ! @ public
  !  Find the next non-blanked interval in array Y
  !---------------------------------------------------------------------
  integer(kind=size_length), intent(in)  :: nxy     ! Size of Y
  real(kind=4),              intent(in)  :: y(nxy)  ! Array to be checked against blanking
  real(kind=4),              intent(in)  :: bval    ! Blanking value
  real(kind=4),              intent(in)  :: eval    ! Tolerance
  integer(kind=size_length) :: is                   ! First element
  integer(kind=size_length) :: ne                   ! Number of elements
  integer(kind=size_length) :: in                   ! Start of next interval
  ! Local
  integer(kind=size_length) :: ie
  !
  if (nxy.lt.1) return
  ie = in
  is = in
  do while (.true.)
    !Protect against NaNs
    if (y(ie).eq.y(ie).and.abs(y(ie)-bval).gt.eval) then
      if (ie.eq.nxy) then
        in = 0
        ne = ie-is+1
        return
      endif
      ie = ie+1
    elseif (ie.eq.nxy) then
      in = 0
      ne = ie-is
      return
    elseif (ie.ne.1) then
      in = ie+1
      ne = ie-is
      do while (.not.(y(in).eq.y(in)) .or. abs(y(in)-bval).le.eval)
        if (in.eq.nxy) then
          in = 0
          return
        endif
        in = in+1
      enddo
      return
    else
      is = is+1
      if (nxy.eq.1) then
        in = 0
        ne = 0
        return
      endif
      do while(.not.(y(is).eq.y(is)) .or. abs(y(is)-bval).le.eval)
        if (is.eq.nxy) then
          ne = 0
          in = 0
          return
        endif
        is = is+1
      enddo
      ie = is
    endif
  enddo
end subroutine find_blank4
!
subroutine find_blank8(y,bval,eval,nxy,is,ne,in)
  use gildas_def
  use greg_interfaces, except_this=>find_blank8
  !---------------------------------------------------------------------
  ! @ public-mandatory
  !  Find the next non-blanked interval in array Y
  !---------------------------------------------------------------------
  integer(kind=size_length), intent(in) :: nxy     ! Size of Y
  real(kind=8),              intent(in) :: y(nxy)  ! Array to be checked against blanking
  real(kind=8),              intent(in) :: bval    ! Blanking value
  real(kind=8),              intent(in) :: eval    ! Tolerance
  integer(kind=size_length) :: is                  ! First element
  integer(kind=size_length) :: ne                  ! Number of elements
  integer(kind=size_length) :: in                  ! Start of next interval
  ! Local
  integer(kind=size_length) :: ie
  !
  if (nxy.lt.1) return
  ie = in
  is = in
  do while (.true.)
    !Protect against NaNs
    if (y(ie).eq.y(ie).and.abs(y(ie)-bval).gt.eval) then
      if (ie.eq.nxy) then
        in = 0
        ne = ie-is+1
        return
      endif
      ie = ie+1
    elseif (ie.eq.nxy) then
      in = 0
      ne = ie-is
      return
    elseif (ie.ne.1) then
      in = ie+1
      ne = ie-is
      do while(.not.(y(in).eq.y(in)) .or. abs(y(in)-bval).le.eval)
        if (in.eq.nxy) then
          in = 0
          return
        endif
        in = in+1
      enddo
      return
    else
      is = is+1
      if (nxy.eq.1) then
        in = 0
        ne = 0
        return
      endif
      do while(.not.(y(is).eq.y(is)) .or. abs(y(is)-bval).le.eval)
        if (is.eq.nxy) then
          ne = 0
          in = 0
          return
        endif
        is = is+1
      enddo
      ie = is
    endif
  enddo
end subroutine find_blank8
