subroutine open_procedure(line,error)
  use sic_interfaces, except_this=>open_procedure
  use gildas_def
  use sic_structures
  use sic_interactions
  use gbl_message
  use sic_dependencies_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   !
  logical,          intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='BEGIN'
  character(len=filename_length) :: file
  character(len=procname_length) :: name
  integer :: i,nc,ier
  !
  if (nproc.eq.maxpro) then
    call sic_message(seve%e,rname,'Too many procedures')
    error = .true.
    return
  endif
  !
  if (proced) then
    call sic_message(seve%e,rname,'Missing END command')
    error = .true.
    return
  endif
  !
  call sic_ch (line,0,2,name,nc,.true.,error)
  if (error) return
  if (nc.gt.procname_length) then
    call sic_message(seve%e,rname,'Procedure name too long')
    error = .true.
    return
  endif
  !
  call sic_parsef (name,file,'GAG_PROC:',sicext(1)(1:lext(1)))
  ier = sic_open(luntem,file,'UNKNOWN',.false.)
  if (ier.ne.0) then
    call sic_message(seve%e,rname,'Cannot open file for procedure')
    call putios('E-BEGIN,  ',ier)
    error = .true.
    return
  endif
  !
  proced = .true.
  if (sic_lire().eq.0) then
    ! Modify the prompt base to procedure name (without modifying the
    ! "master" prompt)
    gprompt_nlire_old = -10    ! Enforce next rebuild of the prompt
    call gprompt_base_set(name)
  endif
  !
  do i=1,nproc
    if (name.eq.proc_name(i)) then
      call sic_message(seve%d,rname,'Re-defining '//name)
      if (proc_file(i).ne.file) then
        call gag_filrm(proc_file(i))
        proc_file(i) = file
      endif
      iproc = i
      return
    endif
  enddo
  nproc = nproc+1
  proc_name(nproc) = name
  proc_file(nproc) = file
  iproc = nproc
  call sic_message(seve%d,rname,'Defining '//name)
  call sic_message(seve%d,rname,'on '//file)
end subroutine open_procedure
!
subroutine write_procedure(com,line,nline,error)
  use sic_interfaces, except_this=>write_procedure
  use sic_structures
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  character(len=*)                :: com    !
  character(len=*)                :: line   !
  integer                         :: nline  !
  logical,          intent(inout) :: error  !
  ! Local
  integer :: ier
  !
  ! Any command
  write(luntem,'(A)',iostat=ier) line(1:nline)
  if (ier.ne.0) error = .true.
end subroutine write_procedure
!
subroutine close_procedure(com,line,nline,error)
  use sic_interfaces, except_this=>close_procedure
  use sic_structures
  use sic_interactions
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  character(len=*)                :: com    !
  character(len=*)                :: line   !
  integer                         :: nline  !
  logical,          intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='END'
  character(len=procname_length) :: name
  integer :: nc
  !
  if (.not.proced) then
    call sic_message(seve%e,rname,'Missing BEGIN command')
    error = .true.
    return
  endif
  !
  ! Check consistency
  name = ' '
  call sic_ch (line,0,2,name,nc,.false.,error)
  if (error)  return
  if (name.ne.' ' .and. name.ne.proc_name(iproc)) then
    call sic_message(seve%e,rname,'Mismatched BEGIN / END PROCEDURE pair')
    call sic_message(seve%e,rname,'Expected "'//trim(proc_name(iproc))//  &
    '", typed "'//trim(name)//'"')
    error = .true.
    return
  endif
  !
  ! Close the procedure
  close(unit=luntem)
  proced = .false.
  if (sic_lire().eq.0) then
    ! Revert the prompt base to the "master" prompt
    gprompt_nlire_old = -10    ! Enforce next rebuild of the prompt
    call gprompt_base_set(gprompt_master)
  endif
  !
end subroutine close_procedure
!
subroutine end_procedure
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>end_procedure
  use gildas_def
  use sic_structures
  use gbl_message
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  ! Local
  character(len=filename_length) :: file
  integer :: i,ier
  !
  do i=1,nproc
    file = proc_file(i)
    call sic_message(seve%d,'SIC','Deleting '//file)
    call gag_filrm(file)
  enddo
  nproc = 0
  !
  ! Remove the directory
  file = 'GAG_PROC:'
  i = sic_getlog(file)
  if (file.eq.gag_proc) then
    ier = gag_rmdir(file)
    if (ier.ne.0)  &
      call sic_message(seve%w,'PROCEDURE','Error removing directory: '//file)
  else
    call sic_message(seve%e,'PROCEDURE','Unexpected change of GAG_PROC:')
    call sic_message(seve%e,'PROCEDURE','Expected '//gag_proc)
    call sic_message(seve%e,'PROCEDURE','Found    '//file)
  endif
end subroutine end_procedure
!
subroutine find_procedure(name,file,found)
  use gildas_def
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>find_procedure
  use sic_structures
  !---------------------------------------------------------------------
  ! @ private
  !  Compute the procedure file name (path+name+extension) given the
  ! input name ([path+]name[+extension])
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: name   ! Name to be resolved
  character(len=*), intent(out)   :: file   ! Path to the file
  logical,          intent(inout) :: found  ! Found a procedure or not?
  ! Local
  integer(kind=4) :: i,lastdot,lastsep
  character(len=1) :: insep,ousep,disep
  !
  found = .true.
  do i=1,nproc
    if (proc_name(i).eq.name) then
      !! Print *,'NAME ',trim(name),' File ',trim(file)
      file = proc_file(i)
      return
    endif
  enddo
  !
  call gag_separ(insep,ousep,disep)
  lastdot = index(name,'.',.true.)
  lastsep = index(name,disep,.true.)  ! Can be zero
  !
  if (lastdot.ne.0 .and. lastdot.gt.lastsep) then
    ! 'name' is something like "../a/./foo.bar" => an extension is provided,
    ! do not scan the extensions list
    if (find_procedure_ext(name,'',file))  return
  else
    ! No extension: loop on list of known extensions
    do i=1,maxext
      if (lext(i).eq.0) exit
      if (find_procedure_ext(name,sicext(i)(1:lext(i)),file))  return
    enddo
  endif
  !
  ! Macro not found
  found = .false.
  !
contains
  function find_procedure_ext(name,ext,file)
    use sic_dependencies_interfaces
    use sic_interfaces
    logical :: find_procedure_ext
    character(len=*), intent(in)  :: name
    character(len=*), intent(in)  :: ext
    character(len=*), intent(out) :: file
    ! Local
    logical :: exist
    !
    find_procedure_ext = .true.
    if (sic_query_file(name,'MACRO#DIR:',ext,file)) then
      ! Try first in MACRO#DIR:
      !! Print *,'Found File ',trim(name),' - ',trim(file)
      return
      !
    else
      ! If not found, try a normal path (absolute or relative)
      call sic_parse_file(name,' ',ext,file)
      inquire (file=file,exist=exist)
      if (exist) return
    endif
    find_procedure_ext = .false.
  end function find_procedure_ext
  !
end subroutine find_procedure
!
subroutine begin_area(line,error)
  use sic_interfaces, except_this=>begin_area
  use gildas_def
  use sic_structures
  use gbl_message
  use sic_dependencies_interfaces
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   !
  logical,          intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='BEGIN'
  character(len=filename_length) :: name,file
  character(len=256) :: string
  integer, parameter :: mvoc=3
  character(len=16) :: vocab(mvoc),keywor
  integer :: nc,ier,iunit,nkey
  logical :: ok
  data vocab/'PROCEDURE','HELP','DATA'/
  !
  call sic_ke (line,0,1,name,nc,.true.,error)
  if (error) return
  !
  call sic_ambigs('BEGIN',name,keywor,nkey,vocab,mvoc,error)
  if (error) return
  !
  ! New Procedure
  if (keywor.eq.'PROCEDURE') then
    call open_procedure(line,error)
    if (.not.error) sic_quiet = .true.
    !
    ! New help file
  elseif (keywor.eq.'HELP') then
    !
    ! Only valid within macro file
    if (mlire(nlire).le.0) then
      call sic_message(seve%e,rname,'Command only valid within macros')
      error = .true.
      return
    endif
    call sic_ch (line,0,2,name,nc,.true.,error)
    if (error) return
    ier = index(name(1:nc),'.')
    if (ier.ne.0) nc = ier-1
    if (nc.gt.len(proc_name(1))) then
      call sic_message(seve%e,rname,'Help file name too long')
      error = .true.
      return
    endif
    !
    call sic_parsef (name,file,'GAG_PROC:','.hlp')
    ier = sic_open(luntem,file,'UNKNOWN',.false.)
    if (ier.ne.0) then
      call sic_message(seve%e,rname,'Cannot open help file')
      call putios('E-BEGIN,  ',ier)
      error = .true.
      return
    endif
    ok = .true.
    string = '1 '//name
    call sic_upper(string)       ! ?
    do while (ok)
      write(luntem,'(A)') trim(string)
      read(lunmac(nmacro),'(A)',iostat=ier) string
      if (ier.ne.0) then
        ok = .false.
        call sic_message(seve%e,rname,'Missing END HELP keyword')
      elseif (sic_eqchain(string(1:8),'END HELP')) then
        ok = .false.
      endif
    enddo
    close(unit=luntem)
    !
    ! New data file
  else
    call sic_ch (line,0,2,name,nc,.true.,error)
    if (error) return
    call sic_parsef (name,file,' ','.dat')
    ier = sic_open(luntem,file,'NEW',.false.)
    if (ier.ne.0) then
      call sic_message(seve%e,rname,'Cannot open new data file')
      call putios('E-BEGIN,  ',ier)
      error = .true.
      return
    endif
    !
    if (mlire(nlire).eq.0) then   ! Read on keyboard (from STDIN or redirected with <)
      iunit = 5
    elseif (mlire(nlire).gt.0) then  ! Else read in macro file
      iunit = lunmac(nmacro)
    else
      call sic_message(seve%e,rname,'Command invalid in this context')
      error = .true.
      return
    endif
    !
    ok = .true.
    do while (ok)
      if (mlire(nlire).eq.0 .and. sic_inter_state(0)) then
        call sic_wprn('DATA> ',string,nc)
      else
        read(iunit,'(A)',iostat=ier) string
      endif
      if (ier.ne.0) then
        ok = .false.
        call sic_message(seve%e,rname,'Missing END DATA keyword')
      elseif (sic_eqchain(string(1:8),'END DATA')) then
        ok = .false.
      else
        write(luntem,'(A)') trim(string)
      endif
    enddo
    close(unit=luntem)
  endif
end subroutine begin_area
