subroutine gfits_get(comm,argu,check,error,quiet,continue,comment,eof)
  use gfits_dependencies_interfaces
  use gfits_interfaces, except_this=>gfits_get
  use gfits_buf
  !---------------------------------------------------------------------
  ! @ public
  !  Retrieve the next line of the FITS header
  !---------------------------------------------------------------------
  character(len=*), intent(out)           :: comm      ! Returned FITS keyword
  character(len=*), intent(out)           :: argu      ! Returned keyword value
  logical,          intent(in)            :: check     ! Printout FITS card
  logical,          intent(out)           :: error     ! Logical error flag
  logical,          intent(in),  optional :: quiet     ! Verbosity flag
  logical,          intent(in),  optional :: continue  ! Merge CONTINUE'd lines?
  character(len=*), intent(out), optional :: comment   !
  logical,          intent(out), optional :: eof       !
  ! Local
  integer(kind=4) :: ll,iamp
  logical :: doquiet,docontinue,goteof
  character(len=8) :: nextkey
  character(len=70) :: contvalue
  !
  ! Arguments
  error = .false.
  doquiet = .false.
  if (present(quiet))  doquiet = quiet
  docontinue = .false.
  if (present(continue))  docontinue = continue
  goteof = .false.
  !
  ! Read keyword
  call get_keyword(comm,doquiet,goteof,error)
  if (goteof .or. error) then
    if (present(eof))  eof = goteof
    return
  endif
  !
  ! Read value
  call get_value(comm,argu,ll)
  !
  ! Strip or save any comments
  if (present(comment)) then
    call get_comment(argu,ll,comment)
  else
    call get_comment(argu,ll)
  endif
  !
  ! Put the pointer at end of current line / just before beginning of next line
  ib = ib+80
  !
  ! Support for CONTINUE'd lines, if requested
  if (docontinue .and. comm.ne.'END') then
    do  ! Infinite succession of CONTINUE
      call get_keyword(nextkey,doquiet,goteof,error)
      ! if (goteof) can this happen?
      ! if (error) ?
      if (nextkey.ne.'CONTINUE')  exit
      !
      iamp = index(argu,'&',.true.)
      if (iamp.eq.0)  exit
      !
      ! This is a valid CONTINUE'd pair of lines (else, leave them as is,
      ! CONTINUE'd lines should be considered as comments)
      call get_value(nextkey,contvalue,ll)
      !
      ! comm = unchanged
      ! comment =
      if (present(comment)) then
        call get_comment(contvalue,ll,comment)
      else
        call get_comment(contvalue,ll)
      endif
      ! argu =
      argu = argu(1:iamp-1)//contvalue(2:)
      !
      ib = ib+80
      !
    enddo
  endif
  !
contains
  subroutine get_keyword(key,doquiet,goteof,error)
    !-------------------------------------------------------------------
    ! Get the keyword at the current 'pointer' position, but do not
    ! change the cursor position. If pointer points to the end of
    ! current buffer, load the next buffer and set the pointer position
    ! so that its absolute position is unchanged.
    !-------------------------------------------------------------------
    character(len=*), intent(out)   :: key      !
    logical,          intent(in)    :: doquiet  !
    logical,          intent(inout) :: goteof   ! inout: may not be changed
    logical,          intent(inout) :: error    !
    ! Local
    character(len=76) :: chain
    !
    if (ib.ge.2880) then
      if (doquiet) then
        call fgetrecquiet(buffer,error,goteof)   ! This ERROR means EOF
        if (goteof)  return
        if (error)  return
      else
        call gfits_getrec(buffer,error)
      endif
      if (error) return
      ib = 0
    endif
    !
    if (check) then
      call bytoch(buffer(ib+1),chain,76)
      call gagout(chain)
    endif
    !
    key = ''  ! Blank the whole string first (beyond 8-th character)
    call bytoch(buffer(ib+1),key,8)
    call sic_upper(key)  ! Should not be necessary, but doesn't hurt...
    !
  end subroutine get_keyword
  !
  subroutine get_value(key,value,ll)
    !-------------------------------------------------------------------
    ! Read the value in current line. Limit is either the passed-length
    ! or the fact that the comment/value extends up to byte 80
    !-------------------------------------------------------------------
    character(len=*), intent(in)  :: key    ! Keyword
    character(len=*), intent(out) :: value  ! Value extracted
    integer(kind=4),  intent(out) :: ll     ! Length of value
    ! Local
    integer(kind=4) :: istart
    !
    select case (key)
    case ('COMMENT','HISTORY','')
      istart = 9
    case ('HIERARCH')
      istart = 10
    case default
      istart = 11
    end select
    !
    ll = min(len(value),80-istart+1)
    call bytoch(buffer(ib+istart),value,ll)  ! Assume 'ib' is at position 0 on line
    !
  end subroutine get_value
  !
  subroutine get_comment(value,ll,comment)
    character(len=*), intent(inout)         :: value
    integer(kind=4),  intent(in)            :: ll
    character(len=*), intent(out), optional :: comment
    ! Local
    logical :: string
    integer(kind=4) :: i
    !
    string = .false.
    if (present(comment))  comment = ''
    do i=1,ll
      if (value(i:i).eq.'''') then
        string = .not.string  ! Doesn't handle quotes within strings
      endif
      if (value(i:i).eq.'/' .and. .not.string) then  ! Comment, erase
        if (present(comment))  comment = value(i+1:)
        value(i:) = ' '
        exit
      endif
    enddo
  end subroutine get_comment
  !
end subroutine gfits_get
!
subroutine gfits_put(line,check,error)
  use gfits_interfaces, except_this=>gfits_put
  use gfits_buf
  !---------------------------------------------------------------------
  ! @ public
  !       Write a FITS line of the header
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! FITS card image
  logical,          intent(in)    :: check  ! Verbose flag
  logical,          intent(inout) :: error  ! Error flag
  ! Local
  integer :: i,j,k
  !
  if (check) write (*,'(A)') trim(line)
  k = min(len(line),80)
  do i=1,k
    buffer(ib+i) = ichar(line(i:i))
  enddo
  do j=k+1,80
    !           BUFFER(IB+J) = 0
    buffer(ib+j) = ichar(' ')
  enddo
  ib = ib+80
  if (ib.eq.2880) then
    call gfits_putrec(buffer,error)
    ib = 0
    if (error) return
  endif
end subroutine gfits_put
!
subroutine gfits_flush_data(error)
  use gfits_interfaces, except_this=>gfits_flush_data
  use gfits_buf
  !---------------------------------------------------------------------
  ! @ public
  ! Write current FITS buffer to disk. It the buffer is not full, DATA
  ! is padded with ZEROES (Wells et al, A&A Sup. Ser 44, P.364, line 47)
  !---------------------------------------------------------------------
  logical, intent(out) :: error                 ! Error flag
  ! Local
  integer :: i
  !
  if (read) then
    ! Mark current buffer as completely read
    ib = 2880
  else
    ! Pad buffer with zeroes and write it
    if (ib.eq.0) return
    do i=ib+1,2880
      buffer(i) = 0
    enddo
    error = .false.
    call gfits_putrec(buffer,error)
    ib = 0
    if (error) return
  endif
end subroutine gfits_flush_data
!
subroutine gfits_flush_header(error)
  use gfits_interfaces, except_this=>gfits_flush_header
  use gfits_buf
  !---------------------------------------------------------------------
  ! @ public
  ! Write current FITS buffer to disk. It the buffer is not full, HEADER
  ! is padded with BLANKS (Wells et al, A&A Sup. Ser 44, P.365, line 57)
  !---------------------------------------------------------------------
  logical, intent(out) :: error                 ! Error flag
  ! Local
  integer :: i
  !
  if (read) then
    ! Mark current buffer as completely read
    ib = 2880
  else
    ! Pad buffer with blanks (0x20=32d) and write it
    if (ib.eq.0) return
    do i=ib+1,2880
      buffer(i) = 32
    enddo
    error = .false.
    call gfits_putrec(buffer,error)
    ib = 0
    if (error) return
  endif
end subroutine gfits_flush_header
!
subroutine gfits_hierarch(key,value,error)
  use gbl_message
  use gfits_interfaces, except_this=>gfits_hierarch
  !---------------------------------------------------------------------
  ! @ public
  !  Decode the 'value' as 'key' + new 'value' if input 'key' is
  ! HIERARCH.
  ! ---
  !  HIERARCH keyword convention is described here:
  !    http://fits.gsfc.nasa.gov/registry/hierarch_keyword.html
  !  Note that this is only a convention.
  !---------------------------------------------------------------------
  character(len=*), intent(out)   :: key    ! Output key
  character(len=*), intent(inout) :: value  ! Input/Output value
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='FITS'
  integer(kind=4) :: isepar
  !
  isepar = index(value,'=')
  !
  if (isepar.le.0) then
    call gfits_message(seve%e,rname,'Not a valid HIERARCH keyword: '//value)
    error = .true.
    return
  endif
  !
  ! Key
  key = adjustl(value(1:isepar-1))  ! NB: key may be truncated if output
                                    ! variable is too short...
  !
  ! Value
  value = adjustl(value(isepar+1:))
  !
end subroutine gfits_hierarch
!
function gfits_unquote(value)
  !---------------------------------------------------------------------
  ! @ public
  !  Unquote the input string (if any quotes) and return the value.
  ! Useful in the context of FITS headers where the strings are often
  ! single-quoted.
  !---------------------------------------------------------------------
  character(len=80) :: gfits_unquote  ! Function value on return
  character(len=*), intent(in) :: value
  ! Local
  integer(kind=4) :: i1,i2,nc
  character(len=1), parameter :: quote=''''
  !
  if (value(1:1).eq.quote) then
    i1 = 2
  else
    i1 = 1
  endif
  !
  nc = len_trim(value)
  if (value(nc:nc).eq.quote) then
    i2 = nc-1
  else
    i2 = nc
  endif
  !
  gfits_unquote = value(i1:i2)
  !
  ! NB: this function would much better return a pointer on the substring
  ! This has both advantages 1) to avoid copies (waste of time) and 2) to
  ! avoid internal limits on the returned string (here max length is 80)
  ! Unfortunately, this is a F2003 syntax.
  !   function myfunc(value)
  !     character(len=:), pointer :: myfunc
  !     character(len=*), intent(in), target :: value
  !     myfunc => value(i1:i2)
  !   end function myfunc
  !
end function gfits_unquote
