subroutine class_set_command(set,line,r,error)
  use phys_const
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces
  use class_index
  use class_types
  use plot_formula
  !---------------------------------------------------------------------
  ! @ no-interface (intent IN/INOUT problems)
  ! SET Something [value1, value2, ...] [/NOCURSOR] [/DEFAULT] [/POLYGON]
  !
  !     ACTION      I[ndex]     O[bservation]
  !     ALIGN       V[elocity]  C[omposite]
  !                 F[requency] I[ntersect]
  !                 C[hannel]
  !                 P[osition]
  !     ANGLE       DEG[re]
  !                 MIN[ute]
  !                 SEC[ond]
  !                 MAS[econd]
  !                 RAD[ian]
  !     BAD         A[nd]
  !                 O[r]
  !     BASE        degree
  !                 S[inus]
  !     BOX         L[andscape]
  !                 P[ortrait]
  !                 S[quare]
  !                 Xmin Xmax Ymin Ymax
  !     CALIBRATION Tolerance
  !     CHARACTER   size                    **
  !     CHASE_NAN   ON|OFF
  !     [NO]CHECK   [SOURCE|POSITION|OFFSET|LINE|SPECTROSCOPY|CALIBRATION|SWITCHING]
  !     DEFAULT     [Filename]
  !     DROP        LowEnd  HighEnd
  !     ENTRY       First Last
  !     EXTENSION   chain
  !     FIND        UPDATE | NOUPDATE
  !     FITS        BITS | MODE  Value
  !     FONT        S[implex]               **
  !                 D[uplex]
  !     FORMAT      L[ong]
  !                 B[rief]
  !                 F[ull]
  !     FREQUENCY   Value1 [Value2] [SIGNAL|IMAGE]
  !     LEVEL       level  (OBSOLETE, SB 02-jun-2008)
  !     LINE        NAME
  !     MASK        N[one]
  !                 Vmin1,Vmax1,Vmin2,Vmax2,....
  !     [NO]MATCH   tolerance
  !     MODE        X | Y | Z | BOTH [ T[otal] | A[uto] ] AMIN,AMAX
  !     NUMBER      MIN,MAX
  !     OBSERVATORY Observatory [Longitude Latitude Altitude]
  !     OBSERVED    OMIN,OMAX
  !     OFFSET      OFF1,OFF2
  !     PAGE        L[andscape]
  !                 P[ortrait]
  !                 S[quare]
  !                 Xmin Xmax Ymin Ymax
  !     POSANGLE    Amin Amax
  !     PLOT        N[ormal]  H[istogram]  P[oint]
  !     RANGE       W[est] E[ast] S[outh] N[orth]
  !     REDUCED     RMIN,RMAX
  !     SCALE       *|Code
  !     SCAN        scan1 scan2
  !     SUBSCAN     sub1 sub2
  !     SIZE        X LENGTH
  !                 Y LENGTH
  !     SORT        keywords
  !     SOURCE      NAME
  !     SYSTEM      E[quatorial] [Equinox]
  !                 G[alactic]
  !                 A[uto]
  !     TELESCOPE   NAME
  !     TICK        size
  !     TYPE        Continuum
  !                 Spectroscopy
  !     UNIQUENESS  YES|NO
  !     UNIT        Xlow Xup
  !                (C[hannel] V[elocity] F[requency] I[mage] A[ngle])
  !     VARIABLE    Section [READ|WRITE|OFF]
  !     VELOCITY    L[sr]
  !                 H[eliocentric]
  !                 A[utomatic]
  !     WEIGHT      T[emps]
  !                 S[igma]
  !                 E[qual]
  !     WINDOW      N[one]
  !                 A[uto]
  !                 Vmin1,Vmax1,Vmin2,Vmax2,....
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set    !
  character(len=*),    intent(inout) :: line   ! Input command line
  type(observation),   intent(inout) :: r      !
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: proc='SET'
  character(len=256) :: line2
  character(len=*), parameter :: backslash=char(92)
  integer(kind=4), parameter :: mini2=-32768
  integer(kind=4), parameter :: maxi2=32767
  real(kind=4), parameter :: epsr4=1e-7
  logical :: found
  integer(kind=4) :: dummy,i,nkey,nl,long,na,n1,n2,nc
  real(kind=4) :: xx,any,dummyr4
  real(kind=8) :: dummyr8,lonlat(2)
  character(len=40) :: argum,argum1,argum2
  character(len=12) :: keyword
  character(len=80) :: mess
  ! Command line
  integer(kind=4), parameter :: optnocur=1
  integer(kind=4), parameter :: optdefau=2
  integer(kind=4), parameter :: optpolyg=3
  integer(kind=4), parameter :: optvaria=4
  integer(kind=4), parameter :: optassoc=5
  logical :: dodefault,dopolygon,dovariable,doassoc
  ! Data
  integer(kind=4), parameter :: mvocab=55  ! Size of SET vocabulary
  integer(kind=4), parameter :: ntype=6    ! Size of TYPE vocabulary
  character(len=12) :: vocab(mvocab),vocab_type(ntype)
  character(len=3) :: vocab_yesno(2)
  data vocab / &
    'ACTION',      'ALIGN',      'ANGLE',     'BAD',        'BASELINE',  &
    'BOX_LOCATION','CALIBRATION','CHARACTER', 'CHASE_NAN',  'CHECK',     &
    'DEFAULT',     'DROP',       'ENTRY',     'EXTENSION',  'FIND',      &
    'FITS',        'FONT',       'FORMAT',    'FREQUENCY',  'LEVEL',     &
    'LINE',        'MAP',        'MASK',      'MATCH',      'MODE',      &
    'NOCHECK',     'NOMATCH',    'NUMBER',    'OBSERVATORY','OBSERVED',  &
    'OFFSET',      'ORIENTATION','PAGE',      'PLOT',       'POSANGLE',  &
    'QUALITY',     'RANGE',      'REDUCED',   'SCALE',      'SCAN',      &
    'SORT',        'SOURCE',     'SUBSCAN',   'SYSTEM',     'TELESCOPE', &
    'TICKSIZE',    'TYPE',       'UNIQUENESS','UNIT',       'VARIABLE',  &
    'VELOCITY',    'VERBOSE',    'VIRTUAL',   'WEIGHT',     'WINDOW'/
  data vocab_type /'ANY','CONTINUUM','LINE','ONOFF','SPECTROSCOPY','SKYDIP'/
  data vocab_yesno / 'YES','NO' /
  character(len=9), parameter :: data_plot(3) =   &
    (/ 'NORMAL   ','HISTOGRAM','POINT    ' /)
  !
  ! Decode command line
  !
  call chtoby('ANY ',any,4)
  dodefault  = sic_present(optdefau,0)
  dopolygon  = sic_present(optpolyg,0)
  dovariable = sic_present(optvaria,0)
  doassoc    = sic_present(optassoc,0)
  if (dopolygon.and.dovariable .or.  &
      dopolygon.and.doassoc    .or.  &
      doassoc.and.dovariable) then
     call class_message(seve%e,proc,'/POLYGON, /VARIABLE and /ASSOCIATED are incompatible')
     error = .true.
     return
  endif
  !
  call sic_ke (line,0,1,argum,nc,.true.,error)
  if (error) return
  i = 1
  found = .false.
  do while(.not.found)
     if (argum(1:nc).eq.vocab(i)(1:nc)) then
        found = .true.
     elseif (i.eq.mvocab.and..not.found) then
        ! Search a GREG command
        nc = index(line,'SET')
        ! command line sent to GreG
        call gr_exec1(line(nc:))
        error = gr_error()
        return
     endif
     i = i+1
     if (i.gt.mvocab) found = .true.
  enddo
  nc = index(line,'SET')
  call sic_ambigs('SET',argum,keyword,nkey,vocab,mvocab,error)
  if (error) return
  !
  select case (keyword)
  case('ALIGN')
     set%align = 'C'
     call sic_ke (line,0,2,set%align,nc,.false.,error)
     if (error) return
     set%alig2 = 'I'
     call sic_ke (line,0,3,set%alig2,nc,.false.,error)
     if (error) return
     if (set%kind.eq.kind_spec) then
       error = set%align.ne.'C' .and. set%align.ne.'F' .and.  &
               set%align.ne.'V'
     elseif (set%kind.eq.kind_cont) then
       error = set%align.ne.'C'.and.set%align.ne.'P'
     else
       call class_message(seve%e,'SET ALIGN','Unsupported kind of data')
       error = .true.
       return
     endif
     error = error .or. set%alig2.ne.'I'.and.set%alig2.ne.'C'
     if (error) then
        mess = 'Invalid align type '//set%align//' '//set%alig2
        call class_message(seve%w,proc,mess)
        set%align = 'C'
        set%alig2 = 'I'
     endif
     !
  case('ANGLE')
     argum1 = 'SEC'
     call sic_ke(line,0,2,argum1,nc,.false.,error)
     if (error) return
     call set_angle_factor('SET ANGLE',argum1,set%angle,set%fangle,error)
     if (error)  return
     call set_angle(set,r%head)  ! Apply new conversion factor where needed
     !
  case('BASELINE')
     argum1 = '1'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:1).eq.'S') then
        set%base  = -1
     else
        call sic_i4 (line,0,2,set%base,.false.,error)
        if (error) return
        set%base=max(0,min(set%base,30))
     endif
     !
  case('SYSTEM')
     argum1 = 'A'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:1).eq.'A') then
        set%coord = 0
     elseif (argum1(1:1).eq.'E') then
        set%coord = type_eq
        call sic_r4(line,0,3,set%equinox,.false.,error)
        if (error) then
          call class_message(seve%e,proc,'Invalid equinox')
          return
        endif
     elseif (argum1(1:1).eq.'G') then
        set%coord = type_ga
     else
        mess = 'Invalid system '//argum1
        call class_message(seve%w,proc,mess)
        set%coord = 0
     endif
     if (r%head%xnum.ne.0) then
       ! Convert current R spectrum, if any
       call convert_pos(set,r%head,error)
       if (error)  return
     endif
     !
  case('DEFAULT')
     call las_setdef(set,error)
     !
  case('ENTRY')
     call parse_minmax8(line,set%entr1,set%entr2,error)
     if (error)  return
     !
  case('FORMAT')
     call setfor(set,line,error)
     !
  case('FREQUENCY')
     call setfrequency('SET FREQUENCY',line,0,2,set%freqmin,set%freqmax,  &
       set%freqsig,error)
     !
  case('LINE')
     set%line = '*'
     call sic_ch(line,0,2,set%line,nc,.false.,error)
     if (error) return
     call sic_upper(set%line)
     !
  case('MASK')
     set%nmask = 0
     argum1 = ' '
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:1).ne.'N') then
       call setregion(set,line,mmask1,set%nmask,set%mask1,set%mask2,'MASK',error)
       if (error)  return
     endif
     !
  case('MATCH')  ! SET MATCH [Tol [Unit]]
     argum1 = ' '
     call sic_ch(line,0,2,argum1,nc,.false.,error)
     if (error) return
     argum2 = ' '  ! Default current angle unit
     call sic_ke(line,0,3,argum2,nc,.false.,error)
     if (error)  return
     !
     if (argum1.eq.' ') then
       set%tole = 2.e0*rad_per_sec  ! Same as in 'setdef'
     else
       call coffse(set,'SET MATCH',argum1,argum2,set%tole,error)
       set%tole = abs(set%tole)
     endif
     set%match = .true.
     cx%cons%off%done = .false.  ! Reset Offset consistency of index
     !
  case('MODE')
     call setmod(set,line,r,error)
     return
     !
  case('NOMATCH')
     set%match = .false.
     cx%cons%off%done = .false.  ! Reset Offset consistency of index
     !
  case('NUMBER')
     call parse_minmax8(line,set%nume1,set%nume2,error)
     if (error)  return
     !
  case('OBSERVATORY')
     call sic_ke(line,0,2,set%obs_name,nc,.true.,error)
     if (error)  return
     if (set%obs_name.eq.'*') then
       set%obs_long = 0.d0  ! Unused if name is *
       set%obs_lati = 0.d0  ! Unused if name is *
       set%obs_alti = 0.d0  ! Unused if name is *
     elseif (sic_present(0,3)) then
       ! Explicit lon-lat-alti values
       call sic_ch(line,0,3,argum1,nc,.true.,error)
       if (error)  return
       call sic_sexa(argum1,nc,set%obs_long,error)
       if (error)  return
       call sic_ch(line,0,4,argum2,nc,.true.,error)
       if (error)  return
       call sic_sexa(argum2,nc,set%obs_lati,error)
       if (error)  return
       call sic_r8(line,0,5,set%obs_alti,.true.,error)
       if (error)  return
     else
       ! Implicit lon-lat-alti values taken from observatories known by Gildas
       call gwcs_observatory(set%obs_name,lonlat,set%obs_alti,dummyr8,dummyr4,error)
       if (error)  return
       set%obs_long = lonlat(1)
       set%obs_lati = lonlat(2)
     endif
     !
  case('OBSERVED')
     argum1 = '*'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     argum2 = '*'
     call sic_ke (line,0,3,argum2,nc,.false.,error)
     if (error) return
     set%obse1 = mini2
     call gag_fromdate(argum1,set%obse1,error)
     set%obse2 = maxi2
     call gag_fromdate(argum2,set%obse2,error)
     !
  case('OFFSET')
     argum1  = '*'
     call sic_ch(line,0,2,argum1,n1,.false.,error)
     if (error) return
     argum2 = '*'
     call sic_ch(line,0,3,argum2,n2,.false.,error)
     if (error) return
     argum = ' '  ! Default current angle unit
     call sic_ke(line,0,4,argum,nc,.false.,error)
     if (error)  return
     !
     set%offs1 = any
     call coffse(set,'SET OFFSET',argum1(1:n1),argum,set%offs1,error)
     set%offl1  = set%offs1
     set%offs2 = any
     call coffse(set,'SET OFFSET',argum2(1:n2),argum,set%offs2,error)
     set%offl2  = set%offs2
     !
  case('PLOT')
     argum = 'NORMAL'  ! Default
     call sic_ke(line,0,2,argum,nc,.false.,error)
     if (error) return
     call sic_ambigs('SET PLOT',argum,keyword,nkey,data_plot,3,error)
     if (error)  return
     set%plot = keyword
     !
  case('RANGE')
     argum = ' '  ! Default current angle unit
     call sic_ke(line,0,6,argum,nc,.false.,error)
     if (error)  return
     !
     argum1 = '*'
     call sic_ch(line,0,2,argum1,n1,.false.,error)
     if (error) return
     set%offs1=any
     call coffse(set,'SET RANGE',argum1,argum,set%offs1,error)
     if (error)  return
     !
     argum2 = '*'
     call sic_ch(line,0,3,argum2,n2,.false.,error)
     if (error) return
     set%offl1=any
     call coffse(set,'SET RANGE',argum2,argum,set%offl1,error)
     if (error)  return
     !
     argum1 = '*'
     call sic_ch(line,0,4,argum1,n1,.false.,error)
     if (error) return
     set%offs2=any
     call coffse(set,'SET RANGE',argum1,argum,set%offs2,error)
     if (error)  return
     !
     argum2 = '*'
     call sic_ch(line,0,5,argum2,n2,.false.,error)
     if (error) return
     set%offl2=any
     call coffse(set,'SET RANGE',argum2,argum,set%offl2,error)
     if (error)  return
     !
  case('REDUCED')
     argum1  = '*'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     argum2 = '*'
     call sic_ke (line,0,3,argum2,nc,.false.,error)
     if (error) return
     set%redu1 = mini2
     call gag_fromdate(argum1,set%redu1,error)
     set%redu2 = maxi2
     call gag_fromdate(argum2,set%redu2,error)
     !
  case('SOURCE')
     set%sourc = '*'
     call sic_ch(line,0,2,set%sourc,nc,.false.,error)
     if (error) return
     call sic_upper(set%sourc)
     !
  case('TELESCOPE')
     set%teles = '*'
     call sic_ch(line,0,2,set%teles,nc,.false.,error)
     if (error) return
     call sic_upper(set%teles)
     !
  case('UNIQUENESS')
     if (sic_present(0,2)) then
        call sic_ke(line,0,2,argum,nc,.true.,error)
        if (error) return
        call sic_ambigs(proc,argum,keyword,nkey,vocab_yesno,2,error)
        if (error) return
        set%uniqueness = keyword.eq.'YES'
        if (set%uniqueness) then
          call optimize_sort_set_dtt(ox,error)
          if (error)  return
        endif
     endif
     if (set%uniqueness) then
        call class_message(seve%i,proc,'UNIQUENESS is YES')
     else
        call class_message(seve%i,proc,'UNIQUENESS is NO')
     endif
     !
  case('UNIT')
     argum1 = 'V'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1.ne.'C' .and. argum1.ne.'V' .and. argum1.ne.'F' .and.  &
         argum1.ne.'I' .and. argum1.ne.'A' .and. argum1.ne.'T') then
        mess = 'Invalid X unit '//trim(argum1)//' reset to '//set%unitx(1)
        call class_message(seve%w,proc,mess)
        argum1 = set%unitx(1)
     endif
     argum2 = set%unitx(1)
     call sic_ke (line,0,3,argum2,nc,.false.,error)
     if (error) return
     if (argum2.ne.'C' .and. argum2.ne.'V' .and. argum2.ne.'F' .and.  &
         argum2.ne.'I' .and. argum2.ne.'A' .and. argum2.ne.'T') then
        mess = 'Invalid upper X unit '//trim(argum2)//  &
                   ' reset to '//set%unitx(1)
        call class_message(seve%w,proc,mess)
        argum2 = set%unitx(1)
     endif
     call seunitx(set,r,argum1,argum2,error)
     if (error)  return
     call gelimx(dummyr8,gux1,gux2,gux,set%unitx(1))
     !
  case('WEIGHT')
    call setweight('SET WEIGHT',line,0,2,set%weigh,error)
    if (error)  return
     !
  case('WINDOW')
     set%nwind = setnwind_default
     set%wind1(:) = 0.
     set%wind2(:) = 0.
     argum1 = ' '
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (dodefault) then  ! /DEFAULT
       set%nwind = setnwind_default
     elseif (argum1(1:1).eq.'N') then  ! NONE
       set%nwind = 0  ! 0 windows is valid for baselining
     elseif (argum1(1:1).eq.'A') then  ! AUTO
       set%nwind = setnwind_auto
     elseif (doassoc) then
       set%nwind = setnwind_assoc
     elseif (dopolygon) then
       call setwindow_polygon(set,line,error)
       if (error)  return
       set%nwind = setnwind_polygon
     else
       call setregion(set,line,mwind1,set%nwind,set%wind1,set%wind2,'WINDOW',error)
       if (error)  return
     endif
     !
  case('BAD')
     set%bad = 'O'
     call sic_ke (line,0,2,set%bad,nc,.false.,error)
     if (error) return
     if (set%bad.ne.'O'.and.set%bad.ne.'A') then
        mess = 'Invalid bad channel checking '//set%bad
        call class_message(seve%w,proc,mess)
        set%bad = 'O'
     endif
     !
  case('DROP')
     set%drop(:) = 0
     call sic_i4 (line,0,2,set%drop(1),.false.,error)
     if (error)  return
     call sic_i4 (line,0,3,set%drop(2),.false.,error)
     if (error)  return
     if (set%drop(1).lt.0) set%drop(1) = 0
     if (set%drop(2).lt.0) set%drop(2) = 0
     write(mess,'(A,I4,I4)') 'Dropped channels ',set%drop(1),set%drop(2)
     call class_message(seve%i,proc,mess)
     !
     if (r%head%xnum.ne.0) then  ! Convert current R spectrum, if any
       call convert_drop(set,r,error)
       if (error)  return
     endif
     !
  case('EXTENSION')
     argum1 = '.30m'
     call sic_ch (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:1).ne.'.') then
        set%defext = '.'//argum1
     else
        set%defext = argum1
     endif
     mess = 'Default file extension set to '//set%defext
     call class_message(seve%i,proc,mess)
     !
  case('LEVEL')
     call class_message(seve%e,proc,"SET LEVEL is obsolete. See HELP for details.")
     error = .true.
     !
  case('PAGE','CHARACTER','FONT','TICKSIZE','ORIENTATION')
     ! command line sent to GreG
     call gr_exec1(line(nc:))
     error = gr_error()
     return
     !
  case('BOX_LOCATION')
     if (dodefault) then
        set%box = "D"
     else
        if (sic_narg(0).gt.1) then
           call sic_ke(line,0,2,set%box,nc,.true.,error)
        else
           call class_message(seve%e,proc,'Wrong number of parameters')
           error = .true.
           return
        endif
        call setbox(set,error)
        return
     endif
     !
  case('CALIBRATION')
     ! CALIBRATION OFF or CALIBRATION [Beam_Tolerance [Gain_Tolerance]]
     if (sic_present(0,2)) then
        call sic_ke (line,0,2,argum1,nc,.true.,error)
        if (error) return
        if (argum1(1:2).eq.'OF') then
           set%beamt = 0.0
           set%gaint = 0.0
        else
           call sic_r4 (line,0,2,set%beamt,.true.,error)
           if (error) return
           call sic_r4 (line,0,3,set%gaint,.true.,error)
           if (error) return
        endif
     else
        set%beamt = 0.01
        set%gaint = 0
     endif
     cx%cons%cal%done = .false.  ! Reset Calibration consistency of index
     !
  case('TYPE')
     ! SET TYPE Any|Continum|Spectroscopy|Line|Skydip|Onoff
     call sic_ke (line,0,2,argum1,nc,.true.,error)
     if (error) return
     call sic_ambigs('SET TYPE',argum1,argum2,nkey,vocab_type,ntype,error)
     if (error) return
     if (argum2.eq.'ANY') then
        set%kind = kind_any
        call gprompt_set('AAS')
        ! set%method   => leave unchanged
        ! set%align    => leave unchanged
        ! set%unitx(:) => leave unchanged
     elseif (argum2.eq.'CONTINUUM') then
        set%kind = kind_cont
        call gprompt_set('CAS')
        if (set%method.ne.'GAUSS' .and. set%method.ne.'CONTINUUM') then
           call class_message(seve%w,proc,'METHOD reset to CONTINUUM')
           set%method = 'CONTINUUM'
        endif
        if (set%align.ne.'C' .and. set%align.ne.'P') then
           call class_message(seve%w,proc,'ALIGN reset to Position')
           set%align = 'P'
        endif
        set%unitx(:) = 'A'
     elseif (argum2.eq.'SPECTROSCOPY'.or.argum2.eq.'LINE') then
        set%kind = kind_spec
        call gprompt_set('LAS')
        if (set%method.eq.'CONTINUUM') then
           call class_message(seve%w,proc,'METHOD reset to GAUSS')
           set%method = 'GAUSS'
        endif
        if (set%align.eq.'P') then
           call class_message(seve%w,proc,'ALIGN reset to Velocity')
           set%align = 'V'
        endif
        set%unitx(:) = 'V'
     elseif (argum2.eq.'SKYDIP') then
        set%kind = kind_sky
        call gprompt_set('SAS')
     elseif (argum2.eq.'ONOFF') then
        set%kind = kind_onoff
        call gprompt_set('OAS')
     else
        call class_message(seve%e,proc,'Invalid Type '//argum1)
        error = .true.
        return
     endif
     !
  case('QUALITY')
     if (sic_present(0,3)) then   ! Quality range
        call sic_i4 (line,0,2,long,.false.,error)
        if (error) return
        if (long.ge.0 .and. long.le.9) then
           set%qual1 = long
        else
           call class_message(seve%w,proc,'Quality flag out of range 0-9')
        endif
        call sic_i4 (line,0,3,long,.false.,error)
        if (error) return
        if (long.ge.0 .and. long.le.9) then
           set%qual2 = long
        else
           call class_message(seve%w,proc,'Quality flag out of range 0-9')
        endif
     else
        long = set%qual2
        call sic_i4 (line,0,2,long,.false.,error)
        if (error) return
        if (long.ge.0 .and. long.le.9) then
           set%qual2 = long
        else
           call class_message(seve%w,proc,'Quality flag out of range 0-9')
        endif
     endif
     !
  case('VELOCITY')
     argum1 = 'A'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:1).eq.'A') then
        set%veloc = vel_aut
     elseif (argum1(1:1).eq.'L') then
        set%veloc = vel_lsr
     elseif (argum1(1:1).eq.'H') then
        set%veloc = vel_hel
     else
        mess = 'Invalid system '//argum1
        call class_message(seve%w,proc,mess)
        error = .true.
        return
     endif
     if (r%head%xnum.ne.0) then
       ! Convert current R spectrum, if any
       call convert_vtype(set,r%head,error)
       call newdat(set,r,error)
     endif
     !
  case('SCAN')
     call parse_minmax8(line,set%scan1,set%scan2,error)
     if (error)  return
     !
  case('SUBSCAN')
     call parse_minmax4(line,set%sub1,set%sub2,error)
     if (error)  return
     !
  case('VARIABLE')
     call las_setvar(set,line,r,error)
     !
  case('POSANGLE')
     if (sic_present(0,3)) then
        call sic_ke (line,0,2,argum1,nc,.false.,error)
        if (error) return
        if (argum1(1:1).eq.'*') then
           set%posa1=-1e7
        else
           call sic_r4 (line,0,2,set%posa1,.false.,error)
           if (error) return
        endif
        call sic_ke (line,0,3,argum2,nc,.false.,error)
        if (error) return
        if (argum2(1:1).eq.'*') then
           set%posa2=+1e7
        else
           call sic_r4 (line,0,3,set%posa2,.false.,error)
           if (error) return
        endif
     else
        argum1 = '*'
        call sic_ke (line,0,2,argum1,nc,.false.,error)
        if (error) return
        if (argum1(1:1).eq.'*') then
           set%posa1=-1e7
           set%posa2=+1e7
        else
           call sic_r4 (line,0,2,xx,.false.,error)
           if (error) return
           set%posa1=xx-epsr4
           set%posa2=xx+epsr4
        endif
     endif
     !
  case('FIND')
     call sic_ke (line,0,2,argum1,nc,.true.,error)
     if (error) return
     if (argum1(1:1).eq.'U') then
        set%fupda = .true.
     elseif (argum1(1:1).eq.'N') then
        set%fupda = .false.
     else
        mess = 'Invalid FIND mode  '//argum1
        call class_message(seve%w,proc,mess)
        error = .true.
     endif
     !
  case('MAP')
     call sic_ke (line,0,2,argum1,nc,.true.,error)
     if (error) return
     if (argum1(1:1).eq.'C') then
        set%mapcl = .true.
     elseif (argum1(1:1).eq.'N') then
        set%mapcl = .false.
     else
        mess = 'Invalid MAP mode  '//argum1
        call class_message(seve%w,proc,mess)
        error = .true.
     endif
     !
  case('SORT')
     call set_sort(set,line,error)
     !
  case('FITS')
     call fits_select(line,error)
     !
  case('VERBOSE')
     argum1='ON'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:2).eq.'OF') then
        set%verbose = .false.
     elseif (argum1(1:2).eq.'ON') then
        if (sic_inter_state(dummy)) then
           set%verbose = .true.
        else
           set%verbose = .false.
        endif
     else
        mess = 'VERBOSE must be ON or OFF, no change made'
        call class_message(seve%w,proc,mess)
     endif
     !
  case('ACTION')
     set%action = 'O'
     call sic_ke(line,0,2,set%action,nc,.false.,error)
     if (error) return
     !
  case('VIRTUAL')
     call class_message(seve%e,proc,'SET VIRTUAL is obsolete')
     error = .true.
     return
     !
  case('CHASE_NAN')
     argum1='OFF'
     call sic_ke (line,0,2,argum1,nc,.false.,error)
     if (error) return
     if (argum1(1:2).eq.'OF') then      ! OFF
        set%chase_nan = .false.
     elseif (argum1.eq.'ON') then  ! ON
        set%chase_nan = .true.
     endif
     !
  case('CHECK','NOCHECK')
     call setcheck(set,line,keyword.eq.'CHECK',error)
     if (error)  return
     !
  case('SCALE')
    call sic_ch(line,0,2,argum,nc,.true.,error)
    if (error)  return
    call sic_upper(argum)
    call sic_ambigs(proc,argum,argum1,i,yunit_keys,1+myunit,error)
    if (error) return
    set%scale = i-1  ! Because yunit_keys(:) numbering starts at 0
    if (r%head%xnum.ne.0) then  ! Convert current R spectrum
      call convert_scale(set,r,.true.,error)
    endif
    !
  case default
     mess = keyword//' not implemented'
     call class_message(seve%e,proc,mess)
     error = .true.
     return
  end select
  !
  nl=sic_start(0,2)
  keyword=vocab(nkey)
  na=lenc(keyword)
  if (nl.gt.0) then
     line2 = 'LAS'//backslash//'SET '//keyword(1:na)//' '//line(nl:)
  else
     line2 = 'LAS'//backslash//'SET '//keyword(1:na)
  endif
  line=line2
  !
contains
  subroutine parse_minmax4(line,vmin,vmax,error)
    !-------------------------------------------------------------------
    ! Parse arguments for command
    !   SET SOMETHING Min Max
    ! I*4 version
    !-------------------------------------------------------------------
    character(len=*), intent(in)    :: line
    integer(kind=4),  intent(out)   :: vmin,vmax
    logical,          intent(inout) :: error
    ! Local
    integer(kind=4), parameter :: maxi4=2147483647_4
    character(len=40) :: argum
    integer(kind=4) :: nc
    !
    argum = '*'
    call sic_ke(line,0,2,argum,nc,.false.,error)
    if (error) return
    if (argum(1:2).eq.'*') then
      vmin = 0
    else
      call sic_i4(line,0,2,vmin,.false.,error)
      if (error) return
    endif
    !
    argum = '*'
    call sic_ke(line,0,3,argum,nc,.false.,error)
    if (error) return
    if (argum(1:2).eq.'*') then
      vmax = maxi4
    else
      call sic_i4(line,0,3,vmax,.false.,error)
      if (error) return
    endif
  end subroutine parse_minmax4
  !
  subroutine parse_minmax8(line,vmin,vmax,error)
    !-------------------------------------------------------------------
    ! Parse arguments for command
    !   SET SOMETHING Min Max
    ! I*8 version
    !-------------------------------------------------------------------
    character(len=*), intent(in)    :: line
    integer(kind=8),  intent(out)   :: vmin,vmax
    logical,          intent(inout) :: error
    ! Local
    integer(kind=8), parameter :: maxi8=9223372036854775807_8
    character(len=40) :: argum
    integer(kind=4) :: nc
    !
    argum = '*'
    call sic_ke(line,0,2,argum,nc,.false.,error)
    if (error) return
    if (argum(1:2).eq.'*') then
      vmin = 0
    else
      call sic_i8(line,0,2,vmin,.false.,error)
      if (error) return
    endif
    !
    argum = '*'
    call sic_ke(line,0,3,argum,nc,.false.,error)
    if (error) return
    if (argum(1:2).eq.'*') then
      vmax = maxi8
    else
      call sic_i8(line,0,3,vmax,.false.,error)
      if (error) return
    endif
  end subroutine parse_minmax8
  !
end subroutine class_set_command
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine setwindow_polygon(set,line,error)
  use gildas_def
  use gbl_message
  use gkernel_types
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>setwindow_polygon
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for command
  !  SET WINDOW /POLYGON [N] [filename1...filenameN]
  ! Define the windows from 1 or several polygons.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set    !
  character(len=*),    intent(in)    :: line   ! Input command line
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SET WINDOW'
  integer(kind=4), parameter :: optpolygon=3
  character(len=filename_length) :: filename
  integer(kind=4) :: i,nc,npoly
  character(len=message_length) :: mess
  character(len=40) :: argum,argum1
  type(polygon_t) :: poly
  character(len=filename_length) :: winpol_name(mwind1)
  !
  ! Number of polygon(s)
  npoly = 1  ! Default is 1 polygon if no argument
  call sic_i4 (line,optpolygon,1,npoly,.false.,error)
  if (error) return
  if (npoly.gt.mwind1) then
    write(mess,'(a,i0)') 'Too many polygons. Max number is ',mwind1
    call class_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
  if (sic_narg(optpolygon).le.1) then
    ! No filename(s): Define the polygon(s) with cursor
    if (gtg_curs()) then
      do i=1,npoly
        write(mess,'(A,I0,A,I0)') 'Draw polygon #',i,'/',npoly
        call class_message(seve%i,rname,mess)
        call greg_poly_cursor(rname,poly,error)
        if (error)  return
        write(argum,'(a,i0)') 'window-',i
        call sic_parse_file(adjustl(argum),'','.pol',winpol_name(i))
        call greg_poly_write(rname,poly,winpol_name(i),error)
        if (error)  return
      enddo
    else
      call class_message(seve%e,rname,'No cursor available')
      error = .true.
      return
    endif
  else if (sic_narg(optpolygon)-1.ne.npoly) then
    ! Some but not all filenames given
    call class_message(seve%e,rname,'Please enter ALL filenames')
    error = .true.
    return
  else
    ! All polygons from filenames
    do i=1,npoly
      call sic_ch (line,optpolygon,i+1,argum1,nc,.false.,error)
      if (error) return
      call sic_parse_file(argum1,' ','.pol',filename)
      winpol_name(i) = filename
      if (.not.sic_findfile(winpol_name(i),winpol_name(i),'','.pol')) then
        call class_message(seve%e,rname,'No such file '//winpol_name(i))
        error = .true.
        return
      endif
      write(mess,'(A,I0,A,A)') 'Read polygon #',i,' from file ',trim(filename)
      call class_message(seve%i,rname,mess)
    enddo
  endif
  !
  call polygon2window(set,winpol_name,npoly,error)
  if (error)  return
  !
end subroutine setwindow_polygon
!
subroutine polygon2window(set,file,nfile,error)
  use gildas_def
  use gbl_message
  use gbl_constant
  use gbl_format
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>polygon2window
  use class_data
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set          !
  integer(kind=4),     intent(in)    :: nfile        ! Number of polygon files
  character(len=*),    intent(in)    :: file(nfile)  ! Polygon files
  logical,             intent(inout) :: error        !
  ! Local
  character(len=*), parameter :: rname='POLYGON2WINDOW'
  integer(kind=4) :: box(4),ier,i1,iwind,nwind,maxwind,ichan
  integer(kind=entry_length) :: iobs
  integer(kind=index_length) :: dim(4)
  real(kind=4) :: dummy
  logical, allocatable :: m2d(:,:)
  !
  ! Check index
  if (cx%next.le.1) then
     call class_message(seve%e,rname,'Index is empty')
     error = .true.
     return
  endif
  ! Check if any 2D image loaded
  if (.not.associated(p%data2)) then
     call class_message(seve%e,rname,'No index loaded')
     error = .true.
     return
  endif
  !
  ! Compute the mask from polygon
  allocate(m2d(p%head%spe%nchan,p%head%des%ndump),stat=ier)
  if (failed_allocate(rname,'m2d',ier,error))  return
  call polygon2mask(file,nfile,m2d,box,p%head%spe%nchan,p%head%des%ndump,error)
  if (error) return
  !
  ! Count the maximum number of windows (i.e. a single polygon can result
  ! in several windows for one record). This is a simplified duplicate of the
  ! main loop.
  maxwind = 0
  do iobs=1,cx%next-1
    i1 = max(2,box(1))
    nwind = 0
    ! Left boundary condition
    if (box(1).eq.1 .and. m2d(1,iobs))  nwind = 1  ! Open the first window
    ! Middle channels
    do ichan=i1,box(3)
      if (m2d(ichan,iobs).and.(.not.m2d(ichan-1,iobs)))  nwind = nwind + 1
    enddo
    maxwind = max(maxwind,nwind)
  enddo
  if (maxwind.le.0) then
    ! Only a warning: since we allow 0 windows for some, we should allow 0
    ! windows for all...
    call class_message(seve%w,rname,  &
      'Polygons are completely off the index: 0 window defined')
  endif
  !
  dim(:) = (/p%head%des%ndump,1+2*maxwind,0,0/)
  if (allocated(set%window_polygon)) deallocate(set%window_polygon)
  allocate(set%window_polygon(dim(1),dim(2)),stat=ier)
  if (failed_allocate('BASE','window_polygon',ier,error))  return
  !
  ! Loop on observations
  do iobs=1,cx%next-1
     i1 = max(2,box(1))
     nwind = 0
     set%window_polygon(iobs,:) = 0.0
     ! Left boundary condition
     if (box(1).eq.1 .and. m2d(1,iobs)) then
        ! Open the first window
        nwind = 1
        set%window_polygon(iobs,2*nwind) = p%datax(1)
     endif
     ! Middle channels
     do ichan=i1,box(3)
        if (m2d(ichan,iobs).and.(.not.m2d(ichan-1,iobs))) then
           nwind = nwind + 1
           if (nwind.gt.maxwind) then
              call class_message(seve%e,rname,'Internal problem on number of windows (1)')
              error = .true.
              return
           endif
           set%window_polygon(iobs,2*nwind) = p%datax(ichan)
        else if (m2d(ichan-1,iobs).and.(.not.m2d(ichan,iobs))) then
           set%window_polygon(iobs,2*nwind+1) = p%datax(ichan-1)
        endif
     enddo
     ! Right boundary condition
     if (box(3).eq.p%head%spe%nchan .and. m2d(p%head%spe%nchan,iobs)) then
       ! Close the last window
       set%window_polygon(iobs,2*nwind+1) = p%datax(p%head%spe%nchan)
     endif
     ! Number of windows for this observation
     set%window_polygon(iobs,1) = real(nwind)
  enddo
  !
  ! Put window velocities in increasing order if needed
  if (p%datax(p%head%spe%nchan).lt.p%datax(1)) then
     do iwind=1,maxwind
        do iobs=1,cx%next-1
           dummy = set%window_polygon(iobs,2*iwind+1)
           set%window_polygon(iobs,2*iwind+1) = set%window_polygon(iobs,2*iwind)
           set%window_polygon(iobs,2*iwind)   = dummy
        enddo
     enddo
  endif
  !
  ! Define the GLOBAL variable WINDOW with the right number of spectral windows
  !
  dim(3) = maxval(set%window_polygon(:,1))
  if (dim(3).ne.maxwind) then
     call class_message(seve%e,rname,'Internal problem on number of windows (2)')
     error = .true.
     return
  endif
  if (.not.sic_varexist('SET')) then
     call sic_defstructure('SET%',.true.,error)
     if (error)  return
  else
     call sic_delvariable('SET%WINDOW',.false.,error)
     if (error)  return
  endif
  call sic_def_real('SET%WINDOW',set%window_polygon,2,dim,.true.,error)
  if (error)  return
  !
  ! Clean
  deallocate(m2d)
end subroutine polygon2window
!
subroutine polygon2mask(file,nfile,m2d,poly_lim,nx,ny,error)
  use gbl_message
  use gkernel_types
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>polygon2mask
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  !   Defines a logical mask from a list of polygon files
  !---------------------------------------------------------------------
  integer(kind=4),  intent(in)    :: nfile        ! Number of polygon files
  character(len=*), intent(in)    :: file(nfile)  ! Polygon files
  integer(kind=4),  intent(in)    :: nx,ny        ! Dimensions of 2D array
  logical,          intent(out)   :: m2d(nx,ny)   ! Resulting logical mask
  integer(kind=4),  intent(out)   :: poly_lim(4)  ! Polygon limit (for fast search)
  logical,          intent(inout) :: error        ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='POLYGON2MASK'
  real(kind=8) :: xconv(3),yconv(3)
  integer(kind=4) :: i,box(4),ier
  logical, allocatable :: w2d(:,:)
  type(polygon_t) :: poly
  !
  ! Get conversion formula
  xconv(1) = gcx1
  xconv(2) = gux1
  xconv(3) = (gux2-gux1)/(gcx2-gcx1)
  yconv(1) = 0
  yconv(2) = 0
  yconv(3) = 1
  ! blc
  box(1) = gcx1
  box(2) = 1
  ! trc
  box(3) = gcx2
  box(4) = ny
  !
  ! Allocating and building the mask
  allocate(w2d(nx,ny),stat=ier)
  if (failed_allocate(rname,'w2d',ier,error)) return
  m2d(:,:) = .false.
  w2d(:,:) = .false.
  !
  ! Builds the mask from the current polygon(s)
  poly_lim = (/nx,ny,1,1/)
  do i=1,nfile
     !
     call greg_poly_load(rname,.true.,file(i),poly,error)
     if (error)  return
     !
     call gr8_glmsk(poly,w2d,nx,ny,xconv,yconv,box)
     m2d = m2d.or.w2d
     ! Avoid exploring all the Map by storing imin,imax,jmin,jmax
     poly_lim(1) = min(poly_lim(1),box(1),box(3))
     poly_lim(3) = max(poly_lim(3),box(1),box(3))
     poly_lim(2) = min(poly_lim(2),box(2))
     poly_lim(4) = max(poly_lim(4),box(4))
  enddo
  deallocate(w2d)
end subroutine polygon2mask
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine setbox(set,error)
  use classcore_dependencies_interfaces
  use class_types
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  ! LAS support routine for command
  ! SET BOX L[andscape] P[ortrait]
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set    !
  logical,             intent(inout) :: error  ! Error flag
  !
  select case(set%box)
  case("L")
     call gr_exec1('SET PLOT LANDSCAPE')
     call gr_exec1('SET VIEW 0.1 0.9 0.15 0.70')
  case("P")
     call gr_exec1('SET PLOT PORTRAIT')
     call gr_exec1('SET VIEWPORT 0.15 0.85 0.10 0.80')
  case default
     gx1 = 3.
     gx2 = 28.0
     gy1 = 2.5
     gy2 = 15.5
     call gr_exec1('SET PLOT LANDSCAPE')
     call gr_exec1('SET VIEWPORT 0.10 0.90 0.10 0.70')
  end select
  error = gr_error()
end subroutine setbox
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine setregion(set,line,mw,nw,w1,w2,wtype,error)
  use gildas_def
  use gbl_constant
  use gbl_format
  use gbl_message
  use gkernel_types
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>setregion
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Support routine for SET WINDOW|MASK [/VARIABLE]
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set     !
  character(len=*),    intent(inout) :: line    ! Command line
  integer(kind=4),     intent(in)    :: mw      ! Maximum number of regions
  integer(kind=4),     intent(out)   :: nw      ! Actual number of regions
  real(kind=4),        intent(out)   :: w1(mw)  ! Lower bounds of regions
  real(kind=4),        intent(out)   :: w2(mw)  ! Upper bounds of regions
  character(len=*),    intent(in)    :: wtype   ! Type of regions (Window or Mask)
  logical,             intent(inout) :: error   ! Logical error flag
  ! Local
  integer(kind=4), parameter :: optnocursor=1
  integer(kind=4), parameter :: optvariable=4
  character(len=12) :: rname
  type(sic_descriptor_t) :: desc,inca
  integer(kind=address_length) :: ipi
  integer(kind=4) :: memory(1),form,i,nl,nc
  real(kind=4) :: window_array(1+2*mw)
  logical :: docursor,found
  character(len=40) :: argum
  character(len=message_length) :: mess
  !
  rname = 'SET '//wtype
  docursor = .not.sic_present(optnocursor,0)
  !
  if (.not.sic_present(optvariable,0)) then
    ! Not from a variable array
    if (sic_narg(0).ge.2) then
      if ((sic_narg(0)-1).gt.2*mw) then
        write(mess,*) 'Too many values, truncated to ',mw,' pairs'
        call class_message(seve%w,rname,mess)
        nw = mw
      else
        nw = int((sic_narg(0)-1)/2)  ! Truncate
      endif
      do i=1,nw
        call sic_r4(line,0,2*i,w1(i),.false.,error)
        if (error) return
        call sic_r4(line,0,2*i+1,w2(i),.false.,error)
        if (error) return
      enddo
      !
    elseif (docursor) then
      if (gtg_curs()) then
        call wincur(set,mw,nw,w1,w2,wtype)
      else
        call class_message(seve%e,rname,'No cursor available')
        error = .true.
        return
      endif
      !
    else
      call class_message(seve%e,rname,  &
        'Missing values or cursor not enabled')
      error = .true.
      return
    endif
    !
    if (set%kind.eq.kind_cont) then
      do i=1,nw
        w1(i) = w1(i)/set%fangle
        w2(i) = w2(i)/set%fangle
      enddo
    endif
    !
    ! Update the command line
    nl = index(line,' ')+1
    line(nl:) = trim(wtype)//' '
    nl = nl+7
    do i=1,nw
      write(line(nl:),'(1PG11.4)') w1(i)
      nl = nl+12
      write(line(nl:),'(1PG11.4)') w2(i)
      nl = nl+12
    enddo
    !
  else
    ! From a variable array
    window_array = 0.
    call sic_ch(line,optvariable,1,argum,nc,.true.,error)
    if (error) return
    !
    call sic_descriptor(argum,desc,found)
    if (.not.found) then
      call class_message(seve%e,rname,'No such variable')
      error = .true.
      return
    endif
    !
    form = fmt_r4
    call sic_incarnate(form,desc,inca,error)
    if (error) return
    !
    ! Check the variable is a rank-1 array.
    if (inca%ndim.ne.1) then
      call class_message(seve%e,rname,'Invalid number of dimensions')
      error = .true.
      return
    endif
    !
    if (mod(inca%dims(1),2_address_length).eq.0) then
      call class_message(seve%e,rname,'Invalid dimension 1')
      error = .true.
      return
    endif
    ipi = gag_pointer(inca%addr,memory)
    call r4tor4(memory(ipi),window_array,inca%dims(1))
    !
    ! Check if the number of boundaries declared matches the number
    ! of boundaries provided by the array
    if (window_array(1).gt.((inca%dims(1)-1.)/2.)) then
      call class_message(seve%e,rname,  &
        'First element does not match the number of pairs found')
      error = .true.
      return
    else
      nw = window_array(1)
    endif
    !
    if (nw.gt.mw) then
      write(mess,*) 'Too many values, truncated to ',mw,' pairs'
      call class_message(seve%w,rname,mess)
      nw = mw
    endif
    !
    do i=1,nw
      w1(i) = window_array(2*i)
      w2(i) = window_array(2*i+1)
    enddo
    !
    if (set%kind.eq.kind_cont) then
      do i=1,nw
        w1(i) = w1(i)/set%fangle
        w2(i) = w2(i)/set%fangle
      enddo
    endif
  endif
  !
end subroutine setregion
!
subroutine setfrequency(rname,line,optnum,argnum,freqmin,freqmax,freqsig,error)
  use gkernel_interfaces
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for commands:
  !   SET FREQUENCY Freq1 [Freq2] [SIGNAL|IMAGE]
  ! and
  !   FIND /FREQUENCY Freq1 [Freq2] [SIGNAL|IMAGE]
  !   Parse the command line to set the frequency values which will be
  ! used for the later FIND selection.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: rname    ! Calling routine name
  character(len=*), intent(in)    :: line     ! Command line
  integer,          intent(in)    :: optnum   ! Option number for command line parsing
  integer,          intent(in)    :: argnum   ! First argument number in the option
  real(kind=8),     intent(out)   :: freqmin  ! Minimum value found
  real(kind=8),     intent(out)   :: freqmax  ! Maximum value found
  logical,          intent(out)   :: freqsig  ! Signal or image frequency?
  logical,          intent(inout) :: error    ! Logical error flag
  ! Local
  character(len=40) :: argum1,argum2,argum3,keyword
  integer :: nc,nkey
  integer, parameter :: nfreq=2
  character(len=*), parameter :: vocab_freq(nfreq) = (/ 'SIGNAL','IMAGE ' /)
  !
  ! First argument: must be first value
  argum1 = '*'
  call sic_ke(line,optnum,argnum,argum1,nc,.true.,error)
  if (error) return
  if (argum1(1:1).eq.'*') then
    freqmin = -1.d0
  else
    call sic_r8(line,optnum,argnum,freqmin,.true.,error)
    if (error) return
  endif
  !
  ! Second argument: can be a value or a keyword
  argum2 = argum1  ! Default is same as argum1
  freqmax = freqmin  ! Default is same as freqmin
  call sic_ke(line,optnum,argnum+1,argum2,nc,.false.,error)
  if (error) return
  !
  if (sic_narg(optnum).eq.argnum+1) then
    ! Argument is the last of the option
    call sic_upper(argum2)
    if (argum2(1:nc).eq.vocab_freq(1)(1:nc)) then
      freqsig = .true.
      return
    elseif (argum2(1:nc).eq.vocab_freq(2)(1:nc)) then
      freqsig = .false.
      return
    endif
  endif
  !
  if (argum2(1:1).eq.'*') then
    freqmax = -1.d0
  else
    call sic_r8(line,optnum,argnum+1,freqmax,.false.,error)
    if (error) return
  endif
  !
  ! Third argument: can be the frequency kind
  freqsig = .true.
  if (sic_present(optnum,argnum+2)) then
    call sic_ke(line,optnum,argnum+2,argum3,nc,.false.,error)
    if (error) return
    !
    call sic_ambigs(rname,argum3,keyword,nkey,vocab_freq,nfreq,error)
    if (error)  return
    !
    if (keyword.eq.'IMAGE')  freqsig = .false.
  endif
  !
end subroutine setfrequency
!
subroutine setfor(set,line,error)
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>setfor
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! CLASS support routine for command
  ! SET FORMAT
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set    !
  character(len=*),    intent(in)    :: line   !
  logical,             intent(inout) :: error  !
  ! Local
  integer(kind=4), parameter :: mvoc=10
  integer(kind=4) :: nkey,nc
  character(len=12) :: argum,keywor,vocab(mvoc)
  character(len=80) :: mess
  logical :: lflag
  ! Data
  data vocab/'BRIEF','LONG','FULL','POSITION','QUALITY','SPECTRAL',  &
             'CALIBRATION','ATMOSPHERE','ORIGIN','CONTINUUM'/
  ! Code
  call sic_ke (line,0,2,argum,nc,.true.,error)
  if (error) return
  call sic_ambigs('SET FORMAT',argum,keywor,nkey,vocab,mvoc,error)
  if (error) return
  !
  select case (keywor)
  !
  case ('BRIEF')
     set%heade = 'B'
  case ('LONG')
     set%heade = 'L'
     set%title%origin = set%origin
  case ('FULL')
     set%heade = 'F'
     set%title%origin = .true.
  case default
     argum = 'ON'
     call sic_ke (line,0,3,argum,nc,.false.,error)
     if (error) return
     if (argum.eq.'ON') then
        lflag = .true.
     elseif (argum.eq.'OFF') then
        lflag = .false.
     else
        mess = 'Invalid argument '//argum
        call class_message(seve%e,'SET FORMAT',mess)
        error = .true.
        return
     endif
     !
     select case (keywor)
     case ('POSITION')
        set%title%position = lflag
     case ('QUALITY')
        set%title%quality = lflag
     case ('SPECTRAL')
        set%title%spectral = lflag
     case ('CALIBRATION')
        set%title%calibration = lflag
     case ('ATMOSPHERE')
        set%title%atmosphere = lflag
     case ('ORIGIN')
        set%title%origin = lflag
        set%origin = lflag
     case ('CONTINUUM')
        set%title%continuum = lflag
     end select
  end select
end subroutine setfor
!
subroutine setcheck(set,line,check,error)
  use classcore_dependencies_interfaces
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Support routine for command
  !   SET  [NO]CHECK  [SOURCE|POSITION|OFFSET|LINE|SPECTROSCOPY|CALIBRATION|SWITCHING]
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set    !
  character(len=*),    intent(in)    :: line   !
  logical,             intent(in)    :: check  !
  logical,             intent(inout) :: error  !
  ! Local
  character(len=7) :: rname
  integer(kind=4) :: iarg,nc,ikey
  character(len=13) :: argum,key
  integer(kind=4), parameter :: nkey=7
  character(len=*), parameter :: keys(nkey) = (/                  &
    'SOURCE      ','POSITION    ','OFFSET      ','LINE        ',  &
    'SPECTROSCOPY','CALIBRATION ','SWITCHING   ' /)
  !
  if (check) then
    rname = 'CHECK'
  else
    rname = 'NOCHECK'
  endif
  !
  if (sic_narg(0).eq.1) then
    ! No argument: (de)activate everything and return
    set%check%sou = check
    set%check%pos = check
    set%check%off = check
    set%check%lin = check
    set%check%spe = check
    set%check%cal = check
    set%check%swi = check
    return
  endif
  !
  do iarg=2,sic_narg(0)
    call sic_ke(line,0,iarg,argum,nc,.true.,error)
    if (error)  return
    call sic_ambigs(rname,argum,key,ikey,keys,nkey,error)
    if (error)  return
    select case (key)
    case ('SOURCE')
      set%check%sou = check
    case ('POSITION')
      set%check%pos = check
    case ('OFFSET')
      set%check%off = check
    case ('LINE')
      set%check%lin = check
    case ('SPECTROSCOPY')
      set%check%spe = check
    case ('CALIBRATION')
      set%check%cal = check
    case ('SWITCHING')
      set%check%swi = check
    end select
  enddo
  !
end subroutine setcheck
!
subroutine setweight(rname,line,iopt,iarg,weight,error)
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>setweight
  !---------------------------------------------------------------------
  ! @ private
  !  Parse command line for TIME|SIGMA|EQUAL, and return value in a
  ! 1-character string.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: rname   ! Calling routine name
  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
  character(len=*), intent(inout) :: weight  ! Value, unchanged in case of error
  logical,          intent(inout) :: error   ! Logical error flag
  ! Local
  character(len=16) :: argum
  integer(kind=4) :: nc,ikey
  character(len=5) :: key
  ! Data
  integer(kind=4), parameter :: mw=4
  character(len=5), parameter :: cw(mw) = (/ 'TIME ','SIGMA','EQUAL','ASSOC' /)
  !
  call sic_ke(line,iopt,iarg,argum,nc,.true.,error)
  if (error) return
  !
  call sic_ambigs(rname,argum,key,ikey,cw,mw,error)
  if (error)  return
  !
  weight = key(1:1)
  !
end subroutine setweight
!
subroutine set_angle_factor(rname,argum,angle,fangle,error)
  use phys_const
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>set_angle_factor
  !---------------------------------------------------------------------
  ! @ private
  ! Compute the angle conversion factor between 'unit' and radians.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: rname   ! Caller name
  character(len=*), intent(in)    :: argum   ! Argument to be resolved
  character(len=*), intent(inout) :: angle   ! Resolved angle
  real(kind=8),     intent(inout) :: fangle  ! Conversion factor
  logical,          intent(inout) :: error   !
  ! Local
  integer(kind=4), parameter :: nangle=5   ! Size of ANGLE vocabulary
  character(len=3) :: vocab_angle(nangle) = (/ 'RAD','DEG','MIN','SEC','MAS' /)
  character(len=3) :: key
  integer(kind=4) :: ikey
  !
  call sic_ambigs(rname,argum,key,ikey,vocab_angle,nangle,error)
  if (error) return  ! Nothing modified in case of error
  !
  angle = key
  select case (ikey)
  case (1)
    fangle = 1.d0
  case (2)
    fangle = 180.d0/pi
  case (3)
    fangle = 180.d0*60.d0/pi
  case (4)
    fangle = 180.d0*60.d0*60.d0/pi
  case (5)
    fangle = 180.d0*60.d0*60.d0*1.d3/pi
  end select
  !
end subroutine set_angle_factor
