subroutine sic_help(line,error)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_help
  use sic_interactions
  !---------------------------------------------------------------------
  ! @ private
  !   Read the help file from a sequential text file where command texts
  ! start with the command name and additional text start with a TAB or
  ! a SPACE.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Input command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=80) :: topic,subtopic,utopic
  integer(kind=4) :: nt,ns
  character(len=24), parameter :: syntax='SYNTAX'
  character(len=24), parameter :: functio='FUNCTION'
  character(len=1), parameter :: backslash=char(92)
  !
  ! Get TOPIC and SUBTOPIC arguments
  if (.not.sic_present(0,1)) then
    topic = ' '
    nt = 0
  else
    subtopic = ' '
    call sic_ch (line,0,2,subtopic,ns,.false.,error)
    if (error) return
    call sic_ch (line,0,1,topic,nt,.false.,error)
    if (error) return
    utopic = topic
    call sic_upper(utopic)
  endif
  !
  if (nt.eq.0) then
    ! No TOPIC => General Help
    call help_general(error)
    !
  elseif (utopic(nt:nt).eq.backslash .and.  &
          utopic(1:nt-1).eq.syntax(1:nt-1)) then
    ! HELP SYNTAX\ (with backslash)
    call help_syntax
    !
  elseif (topic(nt:nt).eq.backslash) then
    ! HELP Language\ (with backslash)
    call help_language(topic,error)
    !
  elseif (utopic.eq.'TASK') then
    ! HELP TASK [Group]
    call help_task(subtopic,error)
    !
  elseif (utopic(1:nt).eq.functio(1:nt) .and. nt.ge.3) then  ! Accept FUN, FUNC, ...
    ! HELP FUNCTION [Name]
    call help_function(subtopic,error)
    !
  elseif (utopic.eq.'RUN' .and. subtopic.ne.'') then
    ! HELP RUN TaskName [VarName]
    topic = subtopic
    subtopic = ' '
    call sic_ch (line,0,3,subtopic,ns,.false.,error)
    if (error) return
    call help_run(topic,subtopic,1,error)
    if (error)  &
      call sic_message(seve%e,rname,'No such task '//topic)
    !
  elseif (utopic.eq.'GO' .and. subtopic.ne.'') then
    ! HELP GO Procedure [Subtopic]
    topic = subtopic
    subtopic = ' '
    call sic_ch (line,0,3,subtopic,ns,.false.,error)
    if (error) return
    call help_procedure(topic,subtopic,error)
    !
  else
    ! HELP Command [Subtopic]
    call help_command(topic,subtopic,error)
    !
  endif
  !
end subroutine sic_help
!
subroutine help_general(error)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_general
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! General help
  !---------------------------------------------------------------------
  logical, intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=1), parameter :: backslash=char(92)
  integer(kind=4) :: ilang,jcom,ncom,mcom,lcom,nc
  integer(kind=4), allocatable :: ikeys(:)
  character(len=:), allocatable :: langlist(:)
  !
  ! First double-loop: find the best column width so that all
  ! the sub-loops are aligned. Find also the maximum number of
  ! commands per language
  nc = 0    ! Best column width
  mcom = 0  ! Maximum number of commands per language
  do ilang=1,nlang
    jcom = mbuilt(ilang-1)  ! Index of command-or-option
    lcom = mbuilt(ilang)    ! Last command-or-option in language
    ncom = 0                ! Number of commands found in language
    do
      jcom = jcom+1
      ncom = ncom+1
      nc = max(nc,len_trim(vocab(jcom)))
      jcom = jcom+nopt(jcom)  ! Index of last option before next command
      if (jcom.ge.lcom)  exit
    enddo
    mcom = max(mcom,ncom)
  enddo
  !
  ! Second double-loop: list commands for each language
  call sic_message(seve%r,rname,  &
    'HELP should be available on the following commands:')
  allocate(ikeys(mcom))
  do ilang=1,nlang
    jcom = mbuilt(ilang-1)
    lcom = mbuilt(ilang)
    ncom = 0  ! Number of commands found
    do
      jcom = jcom+1
      ncom = ncom+1
      ikeys(ncom) = jcom
      jcom = jcom+nopt(jcom)
      if (jcom.ge.lcom)  exit
    enddo
    call sic_ambigs_list(rname,seve%r,trim(languages(ilang)%name)//backslash,  &
      vocab,ikeys(1:ncom),2,nc)
  enddo
  deallocate(ikeys)
  !
  ! List of languages:
  call help_language_list(langlist,error)
  if (error)  return
  call sic_ambigs_list(rname,seve%r,  &
    'Additional help available (eg summaries):',langlist)
  deallocate(langlist)
  !
end subroutine help_general
!
subroutine help_syntax
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_syntax
  use gildas_def
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! Special case: syntax
  !---------------------------------------------------------------------
  ! Local
  character(len=filename_length) :: filename
  logical :: ok
  character(len=*), parameter :: syntax='SYNTAX'
  !
  if (help_mode.eq.help_html) then
    ok = html_help(syntax,' ',1)  ! 1: SIC language
    if (ok) return
  endif
  call sic_parse_file(languages(1)%help,' ','.hlp',filename)
  ok = sichelp(puthelp,syntax,' ',filename,.true.,.false.)
  !
end subroutine help_syntax
!
subroutine help_language(lname,error)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_language
  use gildas_def
  use gbl_message
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! Topic is a language
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: lname  ! Language name
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=filename_length) :: filename,chain
  character(len=36) :: fullcommand
  character(len=24) :: topic,subtopic,resolved
  integer(kind=4) :: jlang,nt,i
  logical :: ok
  character(len=message_length) :: mess
  character(len=:), allocatable :: langlist(:)
  character(len=1), parameter :: backslash=char(92)
  !
  topic = lname
  call sic_upper(topic)
  nt = len_trim(topic)-1  ! Drop the trailing backslash
  subtopic = ' '
  !
  ! Search the language
  call help_language_list(langlist,error)
  if (error)  return
  call sic_ambigs(rname,topic(1:nt),resolved,jlang,langlist,nlang,error)
  if (error)  return
  deallocate(langlist)
  !
  ! Library mode?
  if (languages(jlang)%libmod) then
    write(mess,1010) trim(languages(jlang)%name),backslash
    call sic_message(seve%w,rname,mess)
  endif
  !
  ! HTML help
  if (help_mode.eq.help_html) then
    ok = html_help('Language',subtopic,jlang)
    if (ok) return
  endif
  !
  ! ASCII help
  if (languages(jlang)%help.ne.' ') then
    ! Display ASCII help
    call sic_parse_file(languages(jlang)%help,' ','.hlp',filename)
    ok = sichelp(puthelp,topic,subtopic,filename,.true.,.true.)
    if (.not.ok) ok = sichelp(puthelp,'Language',subtopic,filename,.true.,.false.)
    !
  elseif (languages(jlang)%user) then
    ! List symbol translations for the language
    do i=mbuilt(jlang-1)+1,mbuilt(jlang)
      fullcommand = trim(languages(jlang)%name)//backslash//vocab(i)(2:)
      call sic_symdict_get(languages(jlang)%usym,vocab(i)(2:),chain,error)
      write(6,1001) fullcommand,' = "',trim(chain),'"'
    enddo
  endif
  !
1001 format(a24,3a)
1010 format('Language ',a,a,' is in library only mode')
end subroutine help_language
!
subroutine help_language_list(llist,error)
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! Build the list of languages
  !---------------------------------------------------------------------
  character(len=:), allocatable   :: llist(:)
  logical,          intent(inout) :: error
  ! Local
  integer(kind=4) :: ilang
  character(len=1), parameter :: backslash=char(92)
  !
  allocate(character(len=language_length+1)::llist(nlang))
  do ilang=1,nlang
    llist(ilang) = trim(languages(ilang)%name)//backslash
  enddo
  !
end subroutine help_language_list
!
subroutine help_command(cname,cnamesub,error)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_command
  use gildas_def
  use gbl_message
  use sic_dictionaries
  !--------------------------------------------------------------------
  ! @ private
  ! Topic is a command. Try to find associated language
  !--------------------------------------------------------------------
  character(len=*), intent(in)    :: cname     ! Command name
  character(len=*), intent(in)    :: cnamesub  ! Subtopic name
  logical,          intent(inout) :: error     ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=filename_length) :: filename,chain
  character(len=24) :: topic,subtopic
  character(len=36) :: fullcommand
  integer(kind=4) :: iquiet,ilang,icom,ocode,nt
  logical :: ok
  character(len=message_length) :: mess
  character(len=1), parameter :: backslash=char(92)
  !
  iquiet = 2
  ! if (help_mode.eq.help_html) then
  !    if (sic_present(0,1)) then
  !       call html_help(line,error)
  !       iquiet = 1
  !       if (.not.error) return
  !    endif
  ! elseif ((help_mode.ne.help_scroll).and.  &
  !         (help_mode.ne.help_page)) then
  !    help_mode = help_page
  ! endif
  !
  topic = cname
  call sic_upper(topic)
  nt = len_trim(topic)
  subtopic = cnamesub ! No UpperCase here: more subtle code in sichelp
  !
  ! Get translation of symbols: a valid command may be overloaded by
  ! something else => behave like SIC does.
  call sic_getsymbol(topic,chain,error)
  if (error) then
    ! Not a known symbol => not an error
    error = .false.
  else
    ! Found a symbol => feedback and replace
    write(*,1000) trim(topic),' is a symbol for "',trim(chain),'"'
    ! TO BE DONE: split topic and subtopic e.g. CD = "GTVL\CHANGE DIRECTORY"
    topic = chain
    nt = len_trim(topic)
    call sic_upper(topic)
  endif
  call sic_parse_command(topic,nt,iquiet,.true.,ilang,icom,ocode,error)
  if (error) then
    ! Something wrong when resolving the command name. Try a task name.
    if (ocode.eq.3) then
      ! Found several fully ambiguous commands. Check also for a fully
      ! ambiguous task.
      call help_run(cname,' ',2,error)  ! Use case-sensitive name
    else
      call help_run(cname,cnamesub,1,error)  ! Use case-sensitive name
      if (error)  &
        call sic_message(seve%e,rname,'No such command or task '//topic(1:nt))
    endif
    return
  endif
  !
  ! Command language found. Process the command help
  topic = vocab(icom)(2:)
  nt = len_trim(topic)
  if (languages(ilang)%user) then    ! Only ASCII help
    ! Print translation
    fullcommand = trim(languages(ilang)%name)//backslash//topic
    call sic_symdict_get(languages(ilang)%usym,topic,chain,error)
    write(*,1000) trim(fullcommand),' = "',trim(chain),'"'
    ! Print help file
    call sic_parse_file (help_text(icom),' ','.hlp',filename)
    ok = sichelp(puthelp,topic,subtopic,filename,.true.,.false.)
  else                       ! Either HTML or ASCII help
    if (languages(ilang)%libmod) then
      write(mess,1010) trim(languages(ilang)%name),backslash
      call sic_message(seve%w,rname,mess)
    endif
    if (help_mode.eq.help_html) then
      ok = html_help(topic,subtopic,ilang)
      if (ok) return
    endif
    call sic_parse_file (languages(ilang)%help,' ','.hlp',filename)
    ok = sichelp(puthelp,topic,subtopic,filename,.true.,.false.)
  endif
  !
  ! Try a Task even if command is found. Use case-sensitive name.
  call help_run (cname,' ',2,error)
  error = .false.
  !
1000 format(20(a))
1010 format('Language ',a,a,' is in library only mode')
end subroutine help_command
!
subroutine help_button(hlpfile,varname,buffer)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_button
  use sic_structures
  !---------------------------------------------------------------------
  ! @ public-mandatory (used by ggui, symbol is used elsewhere)
  !  Fill the help lines into the output buffer. This is suited
  ! only for the guis.
  !---------------------------------------------------------------------
  character(len=*), intent(in)  :: hlpfile
  character(len=*), intent(in)  :: varname
  character(len=*), intent(out) :: buffer
  ! Local
  integer(kind=4) :: ier,nbuf
  character(len=1024) :: line
  logical :: found
  !
  buffer = ""
  nbuf = 0
  !
  ! Open help file
  ier = sic_open(luntem,hlpfile,'OLD',.true.)
  if (ier.ne.0) then
    buffer = 'Help file is not yet available: '//trim(hlpfile)
    return
  endif
  !
  if (varname.eq.'') then
    ! Search for the topic in help file (assume only one is declared)
    found = .false.
    do
      read(luntem,'(A)',end=20) line
      if (line(1:1).eq.'1') then
        found = .true.
        exit
      endif
    enddo
    if (.not.found) goto 20
    line = trim(line(3:))//':'
    call append_line(line)
    !
    ! All possible variables are requested
    do
      read(luntem,'(A)',end=20) line
      if (line(1:1).eq.'1') then
        exit
      elseif (line(1:1).eq.'2') then
        call append_line("")  ! Blank line
        call append_varname(line(3:))
      else
        call append_line(line)
      endif
    enddo
    !
  else
    ! A single variable is requested
    call append_varname(varname)
    found = .false.
    do
      read(luntem,'(A)',end=20) line
      if (line(1:1).eq.'1') then
        if (found)  exit
      elseif (line(1:1).eq.'2') then
        if (found)  exit  ! Already found, this is another variable
        found = line(3:).eq.varname
      elseif (found) then
        call append_line(line)
      endif
    enddo
  endif
  !
20 continue
  ! Close help file
  ier = sic_close(luntem)
  if (.not.found)  call append_line('Help is not yet available')
  !
contains
  subroutine append_varname(varname)
    character(len=*), intent(in) :: varname
    ! Local
    character(len=64) :: strtype
    logical :: error
    !
    error = .false.
    call sic_examine_strtype_byname(varname,.true.,.false.,strtype,error)
    if (error) then  ! Probably no such variable
      ! e.g. "Variable TOTO:"
      call append_line(  &
        'Variable '//trim(varname)//':')
    else
      ! e.g. "Variable TOTO (REAL[2,3]):"
      call append_line(  &
        'Variable '//trim(varname)//' ('//trim(strtype)//'):')
    endif
    !
  end subroutine append_varname
  !
  subroutine append_line(line)
    character(len=*), intent(in) :: line
    ! Local
    integer(kind=4) :: nl
    !
    nl = len_trim(line)
    buffer(nbuf+1:) = line(1:nl)
    nbuf = nbuf+nl+1
    buffer(nbuf:nbuf) = char(13)  ! Carriage return
  end subroutine append_line
end subroutine help_button
!
function sichelp(phelp,topic,subtopic,file,reset,quiet)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sichelp
  use sic_structures
  use sic_interactions
  use gbl_ansicodes
  !---------------------------------------------------------------------
  ! @ private
  !  Output help from a SIC Standard Help File
  !  Returns an error status
  !---------------------------------------------------------------------
  logical :: sichelp                        ! Function value on return
  external                     :: phelp     ! Subroutine to output text
  character(len=*), intent(in) :: topic     ! Help topic (case sensitive)
  character(len=*), intent(in) :: subtopic  ! Help subtopic (case sensitive)
  character(len=*), intent(in) :: file      ! Help file name
  logical,          intent(in) :: reset     ! Reset the line counter?
  logical,          intent(in) :: quiet     ! No error message if (sub)topic not found?
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=1), parameter :: backslash=char(92)
  character(len=256) :: line,chain
  character(len=32) :: uptopic,list(20)
  character(len=message_length) :: message
  integer(kind=4) :: n,status,ns,nch,lt,nfound
  logical :: found,more
  integer :: space
  !
  space = 12
  !
  sichelp = .false.
  found = .false.
  lt = len_trim(topic)
  ns = 0
  !
  ! Avoid empty file name
  if (file.eq.'.hlp') goto 20
  ! Open help file
  status = sic_open (luntem,file,'OLD',.true.)
  if (status.ne.0) then
    message = 'Error opening '//file
    call sic_message(seve%e,rname,message)
    call putios('E-HELP,  ',status)
    return
  endif
  ! Initialize
  if (reset)  call phelp(char(0))
  ! Search for TOPIC in help file
  call goto_topic(found)
  if (.not.found) goto 20
  !
  ! Search for SUBTOPIC
  more = .true.
  ns = len_trim(subtopic)
  uptopic = subtopic
  call sic_upper(uptopic)
  nch = 0
  !
  if (ns.eq.0) then
    ! No particular SUBTOPIC requested
    do while (more)
      read(luntem,'(A)',end=40) line
      n = len_trim(line)
      if (n.eq.0.and.found) then
        call phelp(' ')
      elseif (line(1:1).eq.'1') then
        more = .false.
      elseif (line(1:1).eq.'2') then
        if (nch.eq.0) then
          call phelp(' ')
          call phelp('Additional Help Available: ')
          nch = 1
        elseif (nch.ge.72) then
          call phelp (chain)
          nch = 1
        endif
        ! Locate if there is a semi-colon at end of next word
        ! if so, force a line break.
        if (line(n:n).eq.':') then
          space = 16              ! Variable names are often long
          call phelp(chain(1:nch)//c_clear)
          if (line.eq.'2 Variables:') then
            ! Automatic Syntax coloring of Variables:
            call phelp(c_blue//line(2:n))
          else
            call phelp(line(2:n))
          endif
          chain =  ' '
          nch = 1
        else
          chain(nch:) = line(2:n)  ! Keep a blank before subtopic name (2nd char is a blank)
          nch = nch+1+space        ! Space + 1 characters-wide columns (blanks included)
        endif
        found = .false.
      elseif (found) then
        call phelp(line)
      endif
    enddo
40  continue
    if (nch.gt.1) call phelp(chain(1:nch)//c_clear)   ! Reset color 
    found = .true.
    !
  elseif (subtopic(1:ns).ne.'*') then
    ! A particular SUBTOPIC is requested
    ! This is done in 2 steps:
    ! 1) check possible ambiguities for subtopics
    ! 2) actually display the help if there is no ambiguity
    !
    ! 1) Ambiguities
    found = .false.
    nfound = 0
    do
      read(luntem,'(A)',end=20) line
      n = len_trim(line)
      if (line(1:1).eq.'1')  exit  ! This is another topic
      if (line(1:1).eq.'2') then
        if (line(3:min(n,ns+2)).eq.subtopic(1:ns) .or.  &
            line(3:min(n,ns+2)).eq.uptopic(1:ns)) then
          ! Found a matching subtopic
          nfound = nfound+1
          list(nfound) = line(3:n)
        endif
      endif
    enddo
    if (nfound.eq.0) then
      goto 20
    elseif (nfound.gt.1) then
      call sic_ambigs_list(rname,seve%w,'Ambiguous subtopic can be:',list(1:nfound))
      goto 20
    endif
    !
    ! 2) Actual help
    call goto_topic(found)
    found = .false.
    do
      read(luntem,'(A)',end=20) line
      n = len_trim(line)
      if (line(1:1).eq.'1')  exit  ! This is another topic
      if (n.eq.0 .and. found) then
        call phelp(' ')
      elseif (line(1:1).eq.'2') then
        if (found)  exit  ! This is another subtopic
        if (line(3:min(n,ns+2)).eq.subtopic(1:ns) .or.  &
            line(3:min(n,ns+2)).eq.uptopic(1:ns)) then
          found = .true.
          chain = trim(topic)//line(2:n)
          call phelp(chain)
        endif
      elseif (found) then
        call phelp(line)
      endif
    enddo
    !
  else
    ! All possible SUBTOPICS are requested
    found = .false.
    do while (more)
      read(luntem,'(A)',end=20) line
      n = len_trim(line)
      if (n.eq.0.and.found) then
        call phelp(' ')
      elseif (line(1:1).eq.'1') then
        more = .false.
      elseif (line(1:1).eq.'2') then
        chain = trim(topic)//line(2:n)
        call phelp(chain)
        found = .true.
      elseif (found) then
        call phelp(line)
      endif
    enddo
  endif
  !
20 continue
  ! Close help file
  close(unit=luntem)
  !
  ! Analyze search results
  if (.not.found) then         ! Reach EOF without finding the expected help
    if (quiet)  return
    if (ns.eq.0) then  ! No subtopic
      line = 'No help for '//topic(1:lt)
    else
      line = 'No such subtopic '//subtopic(1:ns)//' for HELP '//topic(1:lt)
    endif
    call sic_message(seve%w,rname,line)
  else                         ! Help has been correctly found
    sichelp = .true.
  endif
  ! Output something (is this needed?)
  call phelp(char(1))
  !
contains
  subroutine goto_topic(found)
    !-------------------------------------------------------------------
    ! Move the logical unit to the beginning of the desired topic. i.e.
    ! line starting with:
    !  1 TOPIC
    !-------------------------------------------------------------------
    logical, intent(out) :: found
    ! Local
    integer(kind=4) :: ier
    !
    rewind(luntem)
    found = .false.
    do while (.not.found)
      read(luntem,'(A)',iostat=ier) line
      if (ier.ne.0)  exit
      if (line(1:1).eq.'1') then
        ! We check 1 more character in line, which should be blank
        ! for correct match
        found = line(3:3+lt).eq.topic(1:lt)
      endif
    enddo
  end subroutine goto_topic
end function sichelp
!
subroutine puthelp(line)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>puthelp
  use sic_structures
  use sic_dictionaries
  use sic_interactions
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  !  Output a line on the current terminal taking into account the
  ! output mode (SCROLL or PAGE)
  !---------------------------------------------------------------------
  character(len=*), intent(in) :: line  !
  ! Local
  integer :: nl,kl,tt_lines
  logical :: print
  save nl,print
  !
  if (ichar(line(1:1)).eq.0) then
    nl = 0
    print = .true.
  elseif (.not.print) then
    return
  elseif (ichar(line(1:1)).eq.1) then
    return
  else
    tt_lines = sic_ttynlin()
    if (help_mode.eq.help_page .and. nl.ge.tt_lines-2) then
      if (hlp_more().ne.0) then
        print = .false.
        return
      endif
      nl = 0
    endif
    kl = len_trim(line)
    if (kl.eq.0) kl = 1
    write (*,'(A)') line(1:kl)
    nl = nl+1
  endif
end subroutine puthelp
!
function html_help(topic,subtopic,jlang)
  use gildas_def
  use sic_structures
  use sic_dictionaries
  use sic_interactions
  use gbl_message
  use sic_dependencies_interfaces
  !---------------------------------------------------------------------
  ! @ private
  ! SIC   Internal routine
  !       Read the help from html files starting with:
  !       GAG_HTML_program:node1.html
  !---------------------------------------------------------------------
  logical :: html_help                      ! Function value on return
  character(len=*), intent(in) :: topic     ! Help topic
  character(len=*), intent(in) :: subtopic  ! Help subtopic
  integer,          intent(in) :: jlang     ! Language number
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=filename_length) :: filename
  character(len=256) :: chain,string,root,home
  character(len=1024) :: netscape
  character(len=64) :: chain_1,chain_2,chain_0,navigator,uchain,lchain
  character(len=20) :: prefix
  character(len=4) :: post
  integer :: status
  integer :: ki,li,ni,lis,nc0,nc1,nc2
  integer :: ier,nl,nr
  character(len=1) :: dir_sep,ousep,insep, cprevious
  logical :: is_http, exist
  !
  call gag_separ(insep,ousep,dir_sep)
  html_help = .true.
  !
  ! Define html toc file and open it
  root = 'GAG_HTML_'//languages(jlang)%name
  nr = len_trim(root)+1
  root(nr:nr) = ':'
  ier = sic_getlog(root)
  if (ier.ne.0) then
    call sic_message(seve%w,rname,'Did not find translation of '//root(1:nr))
    call sic_message(seve%w,rname,'Fall back to terminal help')
    html_help = .false.
    return
  endif
  !
  ! Full (recursive) translation of ROOT only obtained through sic_parse_file
  call sic_parse_file (root,' ',' ',filename)
  root = filename
  !
  nr = len_trim(root)
  nl= nr+1
  filename = root
  !
  ! Remote Site case:
  is_http = (filename(1:4).eq.'http')
  !
  if (is_http) then
    home = '$HOME'
    ier = sic_getlog(home)
    filename = trim(home)//'/.gag/'//trim(languages(jlang)%name)//'-node1.html'
    inquire(file=filename,exist=exist)
    if (.not.exist) ier = gag_system &        
      & ('curl -s -o '//trim(filename)//' '//trim(root)//'node1.html')
    
  else
    !
    ! Unfortunately  TOPIC /SUBTOPIC not in this Table of Content
    ! even by specifying $TOC_DEPTH=4  in Latex2html
    filename(nl:) = 'node1.html'
    !
    ! and this only works for SIC (language names are not Doc names) 
    !! filename(nl:) = trim(languages(jlang)%name)//'.html'
  endif
  !
  nl = len_trim(filename)
  filename(nl+1:) = ' '
  !
  close(unit=luntem)
  !
  status = sic_open(luntem,filename,'OLD',.true.)
  if (status.ne.0) then
    call sic_message(seve%e,rname,'Error opening HTML Table of Contents')
    call sic_message(seve%e,rname,filename(1:nl)//'!')
    call putios('E-HELP,  ',status)
    call sic_message(seve%w,rname,'Fall back to terminal help')
    html_help = .false.
    return
  endif
  !
  ! A trick is to figure out the "previous" node, which tells you
  ! the overall Doc name, where all levels are included, so
  ! TOPIC /Subtopic can be found
  ki = 0
  do while (ki.eq.0)
    read(luntem,'(A)',iostat=ier) chain
    if (ier.lt.0) exit
    ki = index(chain,'previous') 
  enddo
  !
  if (ki.ne.0) then
    close(unit=luntem)
    !!Print *,'CHAIN '//trim(chain)
    ! <LINK REL="previous" HREF="sic.html">
    ki = index(chain,'HREF=') + 6
    string = chain(ki:)
    !!Print *,'STRING '//trim(string)
    ki = index(string,'"')-1
    !
    if (is_http) then
      filename = trim(home)//'/.gag/'//trim(languages(jlang)%name)//'-'//string(1:ki)
      inquire(file=filename,exist=exist)
      if (.not.exist) ier = gag_system &
        & ('curl -s -o '//trim(filename)//' '//trim(root)//string(1:ki))
    else
      filename = trim(root)//string(1:ki) 
    endif
    !!Print *,'FILENAME '//trim(filename)
    status = sic_open(luntem,filename,'OLD',.true.)
    !!Print *,status,' Open STATUS of '//trim(filename)
    if (status.ne.0) then
      call sic_message(seve%e,rname,'Error opening HTML main file')
      call sic_message(seve%e,rname,filename)
      call putios('E-HELP,  ',status)
      call sic_message(seve%w,rname,'Fall back to terminal help')
      html_help = .false.
      return
    endif
  endif
  !  
  !!Print *,'TOPIC '//topic
  !!Print *,'SUBTOPIC '//subtopic
  !
  ! HTML syntax to find help corresponding to "SIC> help sic help" command:
  !
  !<LI><A NAME="tex2html1938"
  !  HREF="node120.html">SIC HELP</A>
  !
  ! Look for "LANG Language Internal Help" and then for "TOPIC SUBTOPIC"
  !
  post = '</A'
  chain_1 = trim(topic)//post
  nc1 = len_trim(chain_1)
  if (subtopic.ne.' ') then
    !
    ! Up case conversion unless Mixed case or /Option
    uchain = subtopic
    call sic_upper(uchain)
    if (uchain(1:1).eq.'/') then
      chain_2 = uchain
    else
      lchain = uchain
      call sic_lower(lchain)
      if ((uchain.eq.subtopic)  .or. (lchain.eq.subtopic)) then
        chain_2 = uchain ! trim(topic)//' '//uchain
      else
        chain_2 = subtopic ! trim(topic)//' '//subtopic
      endif
    endif
    nc2 = len_trim(chain_2)
  else
    chain_2 = topic
    nc2 = 0
  endif
  !
  ! First look for "LANG Language Internal Help"
  chain_0 = trim(languages(jlang)%name)//' Language Internal Help'
  nc0 = len_trim(chain_0)
  ki = 0
  do while (ki.eq.0)
    read(luntem,'(A)',iostat=ier) chain
    if (ier.lt.0) exit
    ki = index(chain,chain_0(1:nc0))
  enddo
  !
  ! LANG not found, re-start from beginning (in case .hlp file was not
  ! fully compliant)
  if (ki.eq.0) rewind(unit=luntem)
  !
  ! Now look for "TOPIC SUBTOPIC"
  !
  ! Move to start of list
  ki = 0
  li = 0
  lis = 0
  do while (ki.eq.0)
    read(luntem,'(A)',iostat=ier) chain
    if (ier.lt.0) exit
    ki = index(chain,'<UL>')
  enddo
  !
  ! Explore list if it exists
  if (ier.eq.0) then
    do while (lis.eq.0)
      read(luntem,'(A)',iostat=ier) chain
      if (ier.lt.0) exit
      if (nc2.ne.0 .and. lis.eq.0) then
        ki = index(chain,chain_2(1:nc2))
        if (ki.eq.0) ki = index(chain,chain_2(1:nc2))
        if (ki.ne.0) then
          lis = index(chain,'HREF=')+5
          if (lis.ne.0) then
            ni = index(chain(li:),'>')+li-2
            li = lis
            if (chain(li:li).eq.'"') then
              li = li+1
              ni = ni-1
            endif
            string = chain
            !!Print *,'Located subtopic at '//trim(STRING)//' LIS ',lis
          endif
        endif
      endif
      if (li.eq.0) then
        ki = index(chain,chain_1(1:nc1))
        if (ki.ne.0) then
          ! Verify that this is not by accident a sub-topic with the same name as a Topic...
          if (chain(ki-1:ki-1).eq.' ') then
            cprevious = chain(ki-2:ki-2)
            if (cprevious.eq.'>') then
              continue
            else if (index('012356789',cprevious).ne.0) then
              continue
            else
              ki = 0
            endif
          else if (chain(ki-1:ki-1).ne.'>') then
            ki = 0
          endif
          !! if (ki.eq.0)  Print *,'Ignored false topic at '//trim(chain)
        endif
        if (ki.ne.0) then
          li = index(chain,'HREF=')+5
          if (li.ne.0) then
            ni = index(chain(li:),'>')+li-2
            if (chain(li:li).eq.'"') then
              li = li+1
              ni = ni-1
            endif
            string = chain
            if (nc2.eq.0) lis = li
            !!Print *,'Located topic in '//trim(STRING)//' LIS ',lis
          endif
        endif
      endif
    enddo
  endif
  close (unit=luntem)
  !
  ! Fallback to terminal help if needed
  if (li.eq.0) then
    call sic_message(seve%w,rname,'No documentation for '//  &
    chain_1(1:nc1-len_trim(post)))
    call sic_message(seve%w,rname,'Fall back to terminal help')
    html_help = .false.
    return
  endif
  !
  ! Calling the Browser is OS-dependent, but "gag_os" (in gys/sysfor.f90) 
  ! only returns LINUX or WIN32, not DARWIN
  !
  ! Use pre-processor directive so far - using gag_os would be better
#if defined(WIN32)
  ! WINDOWS, not Cygwin ...
  netscape = 'START "%SystemDrive%/progra~1/intern~1/iexplore.exe" '//  &
              root(1:nr)//string(li:ni)
#elif defined(DARWIN)
  ! Mac OS/X 
  navigator = ''
  ier = sic_getlog('GAG_BROWSER',navigator)
  if (navigator.eq.'OPEN'.or.navigator.eq.' ') then
    ! OS-X default
    netscape = 'open '//root(1:nr)//string(li:ni)    
  else if (navigator.eq.'SAFARI') then
    ! SAFARI display in the last active tab
    if (is_http) then
      netscape = "osascript -e 'tell application "//'"Safari"'  // &
        &  " to set URL of current tab of front window to "//'"' &
        & //root(1:nr) // string(li:ni)//'"'//"'"     
    else
      netscape = "osascript -e 'tell application "//'"Safari"'  // &
        &  " to set URL of current tab of front window to "//'"file://' &
        & //root(1:nr) // string(li:ni)//'"'//"'" 
    endif
  else if (navigator.ne.' ') then
    netscape = trim(navigator)//' '//root(1:nr)//  &
                 string(li:ni) //' &'
    !!        netscape = 'UNKNOWN '//root(1:Nr)//string(li:ni)
  endif
#else  
  ! Any Linux flavor, including Cygwin which has a special structure
  !
  navigator = ''
  ier = sic_getlog('GAG_BROWSER',navigator)
  if (is_http) then
    prefix = ' '
  else
    prefix = 'file://localhost/'
  endif
  if (navigator.eq.'NETSCAPE') then
    netscape = 'netscape -remote ''openURL('//trim(prefix)//root(1:nr)//  &
               string(li:ni)//')'''
  elseif  (navigator.eq.'IE') then
    if (root(1:10).eq.'/cygdrive/') then
      root = 'file:///'//root(11:11)//':'//root(12:nr)
      nr = len_trim(root)
      netscape = 'c:/progra~1/intern~1/iexplore.exe '//root(1:nr)//  &
                 string(li:ni) //' &'
    else
      html_help = .false.
    endif
  elseif  (navigator.eq.'FIREFOX') then
    if (root(1:10).eq.'/cygdrive/') then
      root = 'file:///'//root(11:11)//':'//root(12:nr)
      nr = len_trim(root)
      netscape = 'c:/progra~1/mozill~1/firefox.exe '//root(1:nr)//  &
                 string(li:ni) //' &'
    else
      netscape = 'firefox -url '//trim(prefix)//root(1:nr)//  &
               string(li:ni)
    endif
  else
    html_help = .false.
  endif
  if (.not.html_help) then
    call sic_message(seve%w,rname,'Unrecognized or unsupported browser '//navigator)
    call sic_message(seve%w,rname,'Fall back to terminal help')
    return
  endif
#endif
  ier = gag_system(netscape)
  !
  ! There is no guarantee that IER # 0 in case of failure, so no guarantee of fallback
  if (ier.ne.0) then
    call sic_message(seve%w,rname,trim(netscape)//' FAILED')
    call sic_message(seve%w,rname,'Fall back to terminal help')
    html_help = .false.
  endif
end function html_help
!
subroutine help_run(tname,vname,icode,error)
  use gildas_def
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_run
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  !  Display task help.
  !  Meaning of icode:
  !   1: normal mode i.e. search for the task and display its help
  !   2: Just check for tasks with the same name and warn about them
  !      (help not displayed)
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: tname  ! Task name
  character(len=*), intent(in)    :: vname  ! Variable name
  integer(kind=4),  intent(in)    :: icode  ! Printout code (HELP, or HELP TASK)
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=80) :: topic,subtopic
  character(len=filename_length) :: file
  integer(kind=4) :: nf
  logical :: ok
  character(len=message_length) :: mess
  !
  topic = tname
  subtopic = vname
  ! Beware! No upcasing here: task name (i.e. file name) may be case-sensitive!
  !
  ! HTML mode if specified and existing
  if (help_mode.eq.help_html) then
    if (sic_present(0,1)) then
      call sic_parse_file (topic,'GAG_TASK_HTML:','.html',file)
      inquire(file=file,exist=ok)
    else
      ok = .true.
    endif
    if (ok) then
      call help_run_html(topic,subtopic,error)
      return
    endif
  endif
  !
  ! Fall back on PAGE mode in other cases
  !  call sic_parsef (topic,file,'GILDAS_HELP:','.hlp')
  ok = sic_findfile(topic,file,'TASK#DIR:','.hlp')
  nf = len_trim(file)
  !  inquire(file=file,exist=ok)
  error = .true.
  if (.not.ok) then
    ! topic.hlp file not found in TASK#DIR:
    if (icode.eq.1) then
      call sic_parse_file (topic,'GAG_PROC:','.hlp',file)
      inquire(file=file,exist=ok)
      if (.not.ok) return
      write(mess,102) trim(topic),trim(topic)
      call sic_message(seve%i,rname,mess)
    else
      call sic_parse_file (topic,'GILDAS_RUN:','.exe',file)
      inquire(file=file,exist=ok)
      if (icode.eq.1) then
        if (.not.ok) then
          call sic_message(seve%e,rname,'No such task '//topic)
        else
          call sic_message(seve%e,rname,'No help for '//topic)
        endif
      endif
      return
    endif
  else
    if (icode.eq.1) then
      if (file(nf-3:nf).eq.'.hlp') then
        write(mess,101) trim(topic),trim(topic)
        call sic_message(seve%i,rname,mess)
      else
        write(mess,102) trim(topic),trim(topic)
        call sic_message(seve%i,rname,mess)
      endif
      call sic_upper(topic)     ! Topic is upcased in hlp file
    elseif (icode.eq.2) then
      write(mess,103) trim(topic),trim(topic)
      call sic_message(seve%i,rname,mess)
      return
    endif
  endif
  !
  ! Put the help
  error = .false.
  ok = sichelp(puthelp,topic,subtopic,file,.true.,.false.)
  !
101 format('"',a,'" is a task, use command "RUN ',a,'" to activate it')
102 format('"',a,'" is a procedure, use command @ ',a,' to execute it')
103 format('There is also a task named "',a,'", use "HELP RUN ',a,'" for help on it')
end subroutine help_run
!
subroutine help_task(group,error)
  use gildas_def
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_task
  use sic_structures
  !---------------------------------------------------------------------
  ! @ private
  !  Display a summary of all the available tasks
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: group  ! Group name (blank for all)
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=filename_length), allocatable :: filelist(:)
  character(len=filename_length) :: dirstring,hlpfile
  character(len=*), parameter :: logstring='gag_task:'
  character(len=*), parameter :: filestring='*-task-list.hlp'
  integer(kind=4) :: ifile,nfile,first,last
  integer(kind=4), allocatable :: it(:)
  character(len=30) :: topic  ! len=30 for nicer "HELP TASK ?", beware of truncation
  character(len=30), allocatable :: topics(:)
  logical :: ok
  !
  ! Find files *-task-list.hlp
  call sic_parse_file(logstring,'','',dirstring)  ! Translate Sic logicals and others
  call gag_directory(dirstring,filestring,filelist,nfile,error)
  if (error) return
  ! Sort by alphabetical order
  allocate(it(nfile),topics(nfile))
  call gch_trie(filelist,it,nfile,filename_length,error)
  if (error)  return
  do ifile=1,nfile
    ! Strip "-task-list.hlp" from the file name
    topics(ifile) = filelist(ifile)(:index(filelist(ifile),'-task-list.hlp')-1)
  enddo
  !
  if (group.eq.'') then
    first = 1
    last = nfile
  else
    call sic_ambigs(rname,group,topic,ifile,topics,nfile,error)
    if (error)  return
    first = ifile
    last = ifile
  endif
  !
  ! Initialize
  call puthelp(char(0))  ! Initialize the line counter
  do ifile=first,last
    hlpfile = trim(dirstring)//filelist(ifile)
    topic = topics(ifile)
    call puthelp(topic)
    ok = sichelp(puthelp,topic,'',hlpfile,.false.,.false.)
  enddo
  !
end subroutine help_task
!
subroutine help_function(fname,error)
  use gildas_def
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_function
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  !  Display a summary of all the available functions
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: fname  ! Function name (blank for all)
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=32) :: uname
  character(len=filename_length) :: hlpfile
  integer(kind=4) :: fcode,narg(2),ier,in
  logical :: ok
  !
  if (fname.eq.'') then
    ! List all available functions
    !
    ! Intrinsic functions (native support in SIC)
    call sic_ambigs_list(rname,seve%i,'Intrinsic functions are:',name_function)
    !
    ! Program-defined functions (added by the programs)
    call sic_list_func()
    !
    ! User-defined functions (added by the user)
    call sic_list_expr('',0,error)
    if (error)  return
    !
  else
    ! Help for the given function. NB: functions can not be abbreviated
    ! this would be non-sense.
    !
    ! Check if the function exists
    uname = fname
    call sic_upper(uname)
    fcode = sic_get_expr(uname,len_trim(uname))
    if (fcode.ne.0) then
      ! Found a user-defined function. No detailed help available for now,
      ! just give the translation:
      call sic_list_expr(uname,len_trim(uname),error)
      return  ! Always
    endif
    !
    ! Try a SIC intrinsic or a program-defined
    call get_funcode(uname,fcode,narg,error)
    if (error)  return
    !
    if (fcode.le.max_code_func) then
      ! Intrinsic function: help is in SIC logical gag_help_func_sic
      call sic_parse_file('gag_help_func_sic',' ','.hlp',hlpfile)
    elseif (fcode.eq.code_pyfunc) then
      call sic_message(seve%i,rname,trim(fname)//' is a Python function, check help in Python')
      return
    else
      ! Program-defined function: help is available per function
      ier = gag_hasfin(maxfun,pffun,pnfun,namfun,uname,in)
      call sic_parse_file(descfun(in)%help,' ','.hlp',hlpfile)
    endif
    !
    ! Type its help
    call puthelp(char(0))  ! Initialize the line counter
    ok = sichelp(puthelp,uname,'',hlpfile,.false.,.false.)
  endif
  !
end subroutine help_function
!
subroutine help_procedure(procname,subname,error)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_procedure
  !---------------------------------------------------------------------
  ! @ private
  !  Display procedure help (HELP GO ProcName)
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: procname  ! Procedure name
  character(len=*), intent(in)    :: subname   ! Subtopic name
  logical,          intent(inout) :: error     ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='HELP'
  character(len=80) :: chain,topic,subtopic
  character(len=filename_length) :: file
  logical :: ok,found
  !
  ! Beware! No upcasing here: procedure name (i.e. file name) are case-sensitive!
  chain = 'p_'//procname
  call find_procedure(chain,file,found)
  if (.not.found) then
    ! procname.* not found in MACRO#DIR:
    call sic_message(seve%e,rname,'No such procedure GO '//procname)
    error = .true.
    return
  endif
  !
  ok = sic_query_file(chain,'MACRO#DIR:','.hlp',file)
  if (.not.ok) then
    ! procname.hlp file not found in MACRO#DIR:
    call sic_message(seve%e,rname,'No help for procedure GO '//procname)
    error = .true.
    return
  endif
  !
  topic = procname
  call sic_upper(topic)     ! Topic is upcased in hlp file
  subtopic = subname
  ok = sichelp(puthelp,topic,subtopic,file,.true.,.false.)
  !
end subroutine help_procedure
!
subroutine tkeys(task,key)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>tkeys
  use gildas_def
  !---------------------------------------------------------------------
  ! @ private
  !---------------------------------------------------------------------
  character(len=*) :: task             !
  character(len=*), intent(in) :: key  !
  ! Local
  character(len=filename_length) :: file
  integer :: n
  logical :: ok
  !
  call sic_parse_file (task,'GILDAS_HELP:','.hlp',file)
  n = len_trim(task)
  call sic_upper (task(1:n))
  ok = sichelp(puthelp,task,key,file,.true.,.false.)
end subroutine tkeys
!
subroutine help_run_html(task,argu,error)
  use gildas_def
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>help_run_html
  !---------------------------------------------------------------------
  ! @ private
  ! Read the help file with the following structures :
  !   - HTML files in GAG_HTML: or GAG_HTML_language:
  !   - plus taskname.html in same area
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: task   ! Task name
  character(len=*), intent(in)    :: argu   ! Subtopic name
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=filename_length) :: html_file
  character(len=1024) :: netscape
  integer(kind=4) :: na,ier
  !
  na = len_trim(argu)
  !
  call sic_parse_file(task,'GAG_TASK_HTML:','.html',html_file)
  !
  ! Syntaxe HTML dans la liste
  ! <LI> <A NAME=BACKGROUND HREF=background.html#Main> BACKGROUND</A>
  !
  ! et dans les fichiers
  ! <LI> <A NAME=IN$> IN$</A>
  !
#if defined(WIN32)
  if (na.ne.0) then
    netscape = 'START %SystemDrive%\progra~1\intern~1\iexplore.exe '//  &
    trim(html_file)//'#'//argu
  else
    netscape = 'START %SystemDrive%\progra~1\intern~1\iexplore.exe '//  &
    trim(html_file)
  endif
#else
  if (na.ne.0) then
    netscape = 'netscape -remote ''openURL(file://localhost/'//  &
    trim(html_file)//'#'//trim(argu)//')'''
  else
    netscape = 'netscape -remote ''openURL(file://localhost/'//  &
    trim(html_file)//')'''
  endif
#endif
  ier = gag_system(netscape)
end subroutine help_run_html
