SUBROUTINE ADI2_FCOMIT( FID, STATUS )
*+
*  Name:
*     ADI2_FCOMIT

*  Purpose:
*     Commit buffer changes to a FITSfile object

*  Language:
*     Starlink Fortran

*  Invocation:
*     CALL ADI2_FCOMIT( FID, STATUS )

*  Description:
*     Commit any changes to keywords or data to the FITS file on disk. The
*     file is not closed.

*  Arguments:
*     FID = INTEGER (given)
*        ADI identifier of the FITSfile object
*     STATUS = INTEGER (given and returned)
*        The global status.

*  Examples:
*     {routine_example_text}
*        {routine_example_description}

*  Pitfalls:
*     {pitfall_description}...

*  Notes:
*     {routine_notes}...

*  Prior Requirements:
*     {routine_prior_requirements}...

*  Side Effects:
*     {routine_side_effects}...

*  Algorithm:
*     {algorithm_description}...

*  Accuracy:
*     {routine_accuracy}

*  Timing:
*     {routine_timing}

*  External Routines Used:
*     {name_of_facility_or_package}:
*        {routine_used}...

*  Implementation Deficiencies:
*     {routine_deficiencies}...

*  References:
*     ADI Subroutine Guide : http://www.sr.bham.ac.uk/asterix-docs/Programmer/Guides/adi.html

*  Keywords:
*     package:adi, usage:private

*  Copyright:
*     Copyright (C) University of Birmingham, 1995

*  Authors:
*     DJA: David J. Allan (Jet-X, University of Birmingham)
*     {enter_new_authors_here}

*  History:
*     2 Feb 1995 (DJA):
*        Original version.
*     {enter_changes_here}

*  Bugs:
*     {note_any_bugs_here}

*-
      
*  Type Definitions:
      IMPLICIT NONE              ! No implicit typing

*  Global Constants:
      INCLUDE 'SAE_PAR'          ! Standard SAE constants
      INCLUDE 'ADI_PAR'	

*  Arguments Given:
      INTEGER			FID

*  Status:
      INTEGER 			STATUS             	! Global status

*  External References:
      EXTERNAL			ADI2_MKIDX
        CHARACTER*8		ADI2_MKIDX
      EXTERNAL			CHR_LEN
        INTEGER			CHR_LEN

*  Local Variables:
      CHARACTER*8		IDXSTR			! Index string
      CHARACTER*6		MODE			! File access mode
      CHARACTER*200		THISFILE		! Current file name

      INTEGER			BSIZE			! Block size
      INTEGER			FSTAT			! FITSIO status
      INTEGER			HCID			! HDU container
      INTEGER			HDUID			! HDU identifier
      INTEGER			HDUTAB			! HDU table
      INTEGER			HDUTYPE			! FITSIO hdu type
      INTEGER			IHDU			! HDU loop variable
      INTEGER			ILUN			! Logical unit for i/p
      INTEGER			NHDU			! HDU count
      INTEGER			OIHDU			! O/p HDU counter
      INTEGER			OLUN			! Logical unit for o/p
      INTEGER			TLEN			! Length of THISFILE

      LOGICAL			SCANNEDALL		! Scanned all HDUs?
      LOGICAL			WRITE			! Write access?
*.

*  Check inherited global status.
      IF ( STATUS .NE. SAI__OK ) RETURN

*  Choose the file identifier for output. In write mode chose existing
*  opened file, but in update mode create new file
      CALL ADI_CGET0C( FID, 'MODE', MODE, STATUS )
      WRITE = ((MODE(1:1).EQ.'W') .OR. (MODE(1:1).EQ.'w'))
      IF ( WRITE ) THEN
        CALL ADI2_GETLUN( FID, OLUN, STATUS )

      ELSE

*    Extract input logical unit
        CALL ADI2_GETLUN( FID, ILUN, STATUS )

*    Create temporary file name
        INQUIRE( UNIT=ILUN, NAME=THISFILE, IOSTAT=FSTAT )
        TLEN = CHR_LEN(THISFILE)
        THISFILE(TLEN+1:) = '.tmp'

*    Get logical unit
        CALL FIO_GUNIT( OLUN, STATUS )

*    Try to open file
        FSTAT = 0
        CALL FTINIT( OLUN, THISFILE(:TLEN+4), 1, FSTAT )
        IF ( FSTAT .NE. 0 ) THEN
          CALL ADI2_FITERP( FSTAT, STATUS )
          CALL ERR_REP( ' ', 'Failed to create temporary file - '/
     :                /'FITS data not written to output', STATUS )
          GOTO 99
        END IF

      END IF

*  Locate the HDU container
      CALL ADI_FIND( FID, 'Hdus', HCID, STATUS )
      CALL ADI_FIND( HCID, 'HduTable', HDUTAB, STATUS )

*  Loop over HDU store, writing out stuff
      CALL ADI_CGET0I( HCID, 'HduCount', NHDU, STATUS )
      OIHDU = 0
      DO IHDU = 1, NHDU

*    Make the HDU index entry
        IDXSTR = ADI2_MKIDX( 'Obj_', IHDU )

*    Index the IHDU'th HDU
        CALL ADI_FIND( HDUTAB, IDXSTR, HDUID, STATUS )

*    Write the HDU
        CALL ADI2_FCOMIT_HDU( HDUID, WRITE, ILUN, IHDU, OLUN, OIHDU, 
     :                        STATUS )

*    Release the hdu
        CALL ADI_ERASE( HDUID, STATUS )

      END DO

*  Update mode?
      IF ( .NOT. WRITE ) THEN

*    Scanned all the HDU's
        CALL ADI_CGET0L( HCID, 'ScannedAll', SCANNEDALL, STATUS )
        IF ( .NOT. SCANNEDALL ) THEN

*      While more HDUs
          CALL ADI_CGET0I( HCID, 'MaxScan', IHDU, STATUS )
          FSTAT = 0
          DO WHILE ( FSTAT .EQ. 0 ) 

*        Move to next input HDU
            IHDU = IHDU + 1
            CALL FTMAHD( ILUN, IHDU, HDUTYPE, FSTAT )
 
*        Good HDU?
            IF ( FSTAT .EQ. 0 ) THEN

*          Create output HDU
              CALL FTCRHD( OLUN, FSTAT )
              OIHDU = OIHDU + 1
              CALL FTMAHD( OLUN, OIHDU, HDUTYPE, FSTAT )

*          Copy data from input
              CALL FTCOPY( ILUN, OLUN, 0, FSTAT )

            END IF

          END DO

        END IF

*    Close the temporary file and return its logical unit to the system
        FSTAT = 0
        CALL FTCLOS( OLUN, FSTAT )
        CALL FIO_PUNIT( OLUN, STATUS )

*    Close original file
        FSTAT = 0
        CALL FTCLOS( ILUN, FSTAT )

*    Rename the temporary file
        CALL UTIL_RENAME( THISFILE(:TLEN+4), THISFILE(:TLEN), STATUS )

*    Re-open the temp file so that it can be closed by the closure routine
        FSTAT = 0
        CALL FTOPEN( ILUN, THISFILE(:TLEN), 0, BSIZE, FSTAT )
        
      END IF

*  Release HDU container
      CALL ADI_ERASE( HDUTAB, STATUS )
      CALL ADI_ERASE( HCID, STATUS )

*  Report any errors
 99   IF ( STATUS .NE. SAI__OK ) CALL AST_REXIT( 'ADI2_FCOMIT', STATUS )

      END



      SUBROUTINE ADI2_FCOMIT_HDU( HDUID, WRITE, ILUN, IHDU, OLUN, 
     :                            OIHDU, STATUS )
*+
*  Name:
*     ADI2_FCOMIT_HDU

*  Purpose:
*     Commit buffer changes to a FITSfile object

*  Language:
*     Starlink Fortran

*  Invocation:
*     CALL ADI2_FCOMIT_HDU( HDUID, WRITE, ILUN, IHDU, OLUN, OIHDU, STATUS )

*  Description:
*     Commit any changes to keywords or data to the FITS file on disk. The
*     file is not closed.

*  Arguments:
*     FID = INTEGER (given)
*        ADI identifier of the FITSfile object
*     STATUS = INTEGER (given and returned)
*        The global status.

*  Examples:
*     {routine_example_text}
*        {routine_example_description}

*  Pitfalls:
*     {pitfall_description}...

*  Notes:
*     {routine_notes}...

*  Prior Requirements:
*     {routine_prior_requirements}...

*  Side Effects:
*     {routine_side_effects}...

*  Algorithm:
*     {algorithm_description}...

*  Accuracy:
*     {routine_accuracy}

*  Timing:
*     {routine_timing}

*  External Routines Used:
*     {name_of_facility_or_package}:
*        {routine_used}...

*  Implementation Deficiencies:
*     {routine_deficiencies}...

*  References:
*     ADI Subroutine Guide : http://www.sr.bham.ac.uk/asterix-docs/Programmer/Guides/adi.html

*  Keywords:
*     package:adi, usage:private

*  Copyright:
*     Copyright (C) University of Birmingham, 1995

*  Authors:
*     DJA: David J. Allan (Jet-X, University of Birmingham)
*     {enter_new_authors_here}

*  History:
*     2 Feb 1995 (DJA):
*        Original version.
*     {enter_changes_here}

*  Bugs:
*     {note_any_bugs_here}

*-
      
*  Type Definitions:
      IMPLICIT NONE              ! No implicit typing

*  Global Constants:
      INCLUDE 'SAE_PAR'          ! Standard SAE constants
      INCLUDE 'ADI_PAR'	

*  Arguments Given:
      INTEGER			HDUID, ILUN, IHDU, OLUN, OIHDU
      LOGICAL			WRITE

*  Status:
      INTEGER 			STATUS             	! Global status

*  External References:
      EXTERNAL			ADI2_MKIDX
        CHARACTER*8		ADI2_MKIDX
      EXTERNAL			CHR_LEN
        INTEGER			CHR_LEN

*  Local Variables:
      CHARACTER*1		AXC			! Axis # in char
      CHARACTER*72		CMNT			! Keyword comment
      CHARACTER*8		TYPE			! Basic data type

      INTEGER			BITPIX			! Bits per pixel
      INTEGER			FSTAT			! FITSIO status
      INTEGER			HDUTYPE			! FITSIO hdu type
      INTEGER			IAX			! Loop over axes
      INTEGER			IMID			! Image cache object
      INTEGER			IPTR			! Image data
      INTEGER			NDIG			! # digits
      INTEGER			NDIM,DIMS(ADI__MXDIM)	! Data shape
      INTEGER			NELM			! Total # elements
      INTEGER			PCOUNT, GCOUNT		! Group counters

      LOGICAL			EXTEND			! Dataset has extensions? 
      LOGICAL			ISTABLE			! Table HDU?
      LOGICAL			MODIFIED		! HDU is modified?
      LOGICAL			MRKDEL			! Object to be deleted?
      LOGICAL			SIMPLE			! HDU is standard?
*.

*  Check inherited global status.
      IF ( STATUS .NE. SAI__OK ) RETURN

*  HDU isn't marked for delete?
      CALL ADI2_ISDEL( HDUID, MRKDEL, STATUS )
      IF ( .NOT. MRKDEL ) THEN

*    Increment output HDU counter
        OIHDU = OIHDU + 1

*    Move to this hdu
        FSTAT = 0
        IF ( IHDU .GT. 1 ) THEN
          CALL FTCRHD( OLUN, FSTAT )
        END IF
        CALL FTMAHD( OLUN, OIHDU, HDUTYPE, FSTAT )

*    Modified?
        CALL ADI_CGET0L( HDUID, 'Modified', MODIFIED, STATUS )
 
*    Simple copy of input?
        IF ( .NOT. WRITE .AND. .NOT. MODIFIED ) THEN
          CALL FTMAHD( ILUN, IHDU, HDUTYPE, FSTAT )
          CALL FTCOPY( ILUN, OLUN, 0, FSTAT )
            
*    Full write required
        ELSE

*      Table or image?
          CALL ADI_CGET0L( HDUID, 'IsTable', ISTABLE, STATUS )
          IF ( ISTABLE ) THEN

*      Image HDU
          ELSE

*        Gather keywords for image extension
            CALL ADI2_IMGTSHP( HDUID, .TRUE., BITPIX, NDIM, DIMS, 
     :                         STATUS )

*        Simple HDU?
            CALL ADI2_HGKYL( HDUID, '>SIMPLE', SIMPLE, CMNT, STATUS )
            IF ( STATUS .NE. SAI__OK ) THEN
              CALL ERR_ANNUL( STATUS )
              SIMPLE = .TRUE.
            END IF

*        Get grouping values
            CALL ADI2_HGKYI( HDUID, '>PCOUNT', PCOUNT, CMNT, STATUS )
            IF ( STATUS .NE. SAI__OK ) THEN
              PCOUNT = 0
              CALL ERR_ANNUL( STATUS )
            END IF
            CALL ADI2_HGKYI( HDUID, '>GCOUNT', GCOUNT, CMNT, STATUS )
            IF ( STATUS .NE. SAI__OK ) THEN
              GCOUNT = 1
              CALL ERR_ANNUL( STATUS )
            END IF

*        Define the extension
            FSTAT = 0
            IF ( IHDU .EQ. 1 ) THEN
              IF ( SIMPLE ) THEN
                CMNT = 'file does conform to FITS standard'
              ELSE
                CMNT = 'file does not conform to FITS standard'
              END IF
              CALL FTPKYL( OLUN, 'SIMPLE', SIMPLE, CMNT, FSTAT )
            ELSE
              CALL FTPKYS( OLUN, 'XTENSION', 'IMAGE', 
     :                     'IMAGE extension', FSTAT )
            END IF

*        Write BITPIX
            CALL FTPKYJ( OLUN, 'BITPIX', BITPIX, 'bits per pixel', 
     :                   FSTAT )

*        Write shape info
            CALL FTPKYJ( OLUN, 'NAXIS', NDIM, 'number of data axes',
     :                   FSTAT )
            DO IAX = 1, NDIM
              CALL CHR_ITOC( IAX, AXC, NDIG )
              CALL FTPKYJ( OLUN, 'NAXIS'//AXC, DIMS(IAX), 
     :                     'length of data axis '//AXC, FSTAT )
            END DO

*        Write other stuff
            IF ( IHDU .EQ. 1 ) THEN

*          Extensions allowed?
              CALL ADI2_HGKYL( HDUID, '>EXTEND', EXTEND, CMNT, STATUS )
              IF ( STATUS .NE. SAI__OK ) THEN
                CALL ERR_ANNUL( STATUS )
                EXTEND = .TRUE.
              END IF
              IF ( EXTEND ) THEN
                CALL FTPKYL( OLUN, 'EXTEND', EXTEND,
     :                   'FITS dataset may contain extensions', FSTAT )
              END IF

*          Write the PCOUNT and GCOUNT values if nonstandard
              IF ( (PCOUNT .GT. 0) .OR. (GCOUNT .GT. 1) ) THEN
                CMNT = 'random group records are present'
                CALL FTPKYL( OLUN, 'GROUPS', .TRUE., CMNT, FSTAT )
                CMNT = 'number of random group parameters'
                CALL FTPKYJ( OLUN, 'PCOUNT', PCOUNT, CMNT, FSTAT )
                CMNT = 'number of random groups'
                CALL FTPKYJ( OLUN, 'GCOUNT', GCOUNT, CMNT, FSTAT )
              END IF

*        2nd or subsequent HDU
            ELSE
              CMNT = 'number of random group parameters'
              CALL FTPKYJ( OLUN, 'PCOUNT', PCOUNT, CMNT, FSTAT )
              CMNT = 'number of random groups'
              CALL FTPKYJ( OLUN, 'GCOUNT', GCOUNT, CMNT, FSTAT )

            END IF

*        Define the data size
            CALL FTPDEF( OLUN, BITPIX, NDIM, DIMS, PCOUNT, GCOUNT, 
     :                   FSTAT )

*        Write remaining header cards
            CALL ADI2_FCOMIT_CARDS( OLUN, HDUID, NDIM + 1, STATUS )

*        Non-zero extension size
            IF ( NDIM .GT. 0 ) THEN

*          Write the data
              CALL ADI_FIND( HDUID, 'Image', IMID, STATUS )

*          Has the data been modified?
              CALL ADI_CGET0L( IMID, 'Modified', MODIFIED, STATUS )
              IF ( .NOT. MODIFIED .AND. .NOT. WRITE ) THEN

*            Move to the input HDU
                CALL FTMAHD( ILUN, IHDU, HDUTYPE, FSTAT )
 
*            Copy the data
                CALL FTCPDT( ILUN, OLUN, FSTAT )

*          Write new data
              ELSE

*            Map the image value in its basic type
                CALL ADI_CTYPE( IMID, 'Value', TYPE, STATUS )
                CALL ADI_CMAP( IMID, 'Value', TYPE, 'READ', IPTR, 
     :                         STATUS )
 
*            Total number of elements
                CALL ARR_SUMDIM( NDIM, DIMS, NELM )

*            Copy data to FITS
                IF ( TYPE .EQ. 'DOUBLE' ) THEN
                  CALL FTPPRD( OLUN, 1, 1, NELM, %VAL(IPTR), FSTAT )
                ELSE IF ( TYPE .EQ. 'REAL' ) THEN
                  CALL FTPPRE( OLUN, 1, 1, NELM, %VAL(IPTR), FSTAT )
                ELSE IF ( TYPE .EQ. 'INTEGER' ) THEN
                  CALL FTPPRJ( OLUN, 1, 1, NELM, %VAL(IPTR), FSTAT )
                ELSE IF ( TYPE .EQ. 'WORD' ) THEN
                  CALL FTPPRI( OLUN, 1, 1, NELM, %VAL(IPTR), FSTAT )
                ELSE IF ( TYPE .EQ. 'BYTE' ) THEN
                  CALL FTPPRB( OLUN, 1, 1, NELM, %VAL(IPTR), FSTAT )
                END IF
     
*            Unmap data
                CALL ADI_CUNMAP( IMID, 'Value', IPTR, STATUS )

              END IF   

*          Release the data
              CALL ADI_ERASE( IMID, STATUS )

*        End of switch on image/table hdu
            END IF

*      End of switch on write/update mode
          END IF

*    End of modified test
        END IF

*  End of marked for delete test
      END IF

*  Report any errors
 99   IF ( STATUS .NE. SAI__OK ) THEN
        CALL AST_REXIT( 'ADI2_FCOMIT_HDU', STATUS )
      END IF

      END



      SUBROUTINE ADI2_FCOMIT_CARDS( LUN, HDUID, NDONE, STATUS )
*+
*  Name:
*     ADI2_FCOMIT_CARDS

*  Purpose:
*     Commit HDU cards to a FITS file

*  Language:
*     Starlink Fortran

*  Invocation:
*     CALL ADI2_FCOMIT_CARDS( LUN, HDUID, NDONE, STATUS )

*  Description:
*     Commit any changes to keywords or data to the FITS file on disk. The
*     file is not closed.

*  Arguments:
*     FID = INTEGER (given)
*        ADI identifier of the FITSfile object
*     STATUS = INTEGER (given and returned)
*        The global status.

*  Examples:
*     {routine_example_text}
*        {routine_example_description}

*  Pitfalls:
*     {pitfall_description}...

*  Notes:
*     {routine_notes}...

*  Prior Requirements:
*     {routine_prior_requirements}...

*  Side Effects:
*     {routine_side_effects}...

*  Algorithm:
*     {algorithm_description}...

*  Accuracy:
*     {routine_accuracy}

*  Timing:
*     {routine_timing}

*  External Routines Used:
*     {name_of_facility_or_package}:
*        {routine_used}...

*  Implementation Deficiencies:
*     {routine_deficiencies}...

*  References:
*     ADI Subroutine Guide : http://www.sr.bham.ac.uk/asterix-docs/Programmer/Guides/adi.html

*  Keywords:
*     package:adi, usage:private

*  Copyright:
*     Copyright (C) University of Birmingham, 1995

*  Authors:
*     DJA: David J. Allan (Jet-X, University of Birmingham)
*     {enter_new_authors_here}

*  History:
*     2 Feb 1995 (DJA):
*        Original version.
*     {enter_changes_here}

*  Bugs:
*     {note_any_bugs_here}

*-
      
*  Type Definitions:
      IMPLICIT NONE              ! No implicit typing

*  Global Constants:
      INCLUDE 'SAE_PAR'          ! Standard SAE constants
      INCLUDE 'ADI_PAR'	

*  Arguments Given:
      INTEGER			LUN, HDUID, NDONE

*  Status:
      INTEGER 			STATUS             	! Global status

*  External References:
      EXTERNAL			ADI2_MKIDX
        CHARACTER*8		ADI2_MKIDX
      EXTERNAL			CHR_LEN
        INTEGER			CHR_LEN

*  Local Variables:
      CHARACTER*72		CMNT			! Comment string
      CHARACTER*80		CVAL			! Keyword value
      CHARACTER*8		IDXSTR			! Index string
      CHARACTER*8		KEYWRD			! Keyword name
      CHARACTER*20		TYPE			! Basic data type
      CHARACTER*8		VTYPE			! Keyword value type

      DOUBLE PRECISION		DVAL			! Keyword value

      REAL			RVAL			! Keyword value

      INTEGER			CRDID			! Card cache object
      INTEGER			CRDTAB			! HDU table
      INTEGER			FSTAT			! FITSIO status
      INTEGER			ICARD			! Loop over cards
      INTEGER			IVAL			! Keyword value
      INTEGER			NCARD			! # cards in HDU
      INTEGER			NDEC			! # decimals used
      INTEGER			VID			! Value object
 
      LOGICAL			LVAL			! Keyword value
      LOGICAL			MRKDEL			! Object to be deleted?
      LOGICAL			SFMT			! Scientific notation?
      LOGICAL			THERE			! Object exists?
      LOGICAL			WRITTEN			! Already written?
*.

*  Check inherited global status.
      IF ( STATUS .NE. SAI__OK ) RETURN

*  How many cards in HDU
      CALL ADI_CGET0I( HDUID, 'CrdCount', NCARD, STATUS )

*  Allocate more space?
      IF ( NCARD .GT. NDONE ) THEN
        FSTAT = 0
        CALL FTHDEF( LUN, NCARD - NDONE, FSTAT )
      END IF

*  Locate card table
      CALL ADI_FIND( HDUID, 'CrdTable', CRDTAB, STATUS )

*  Loop over cards
      DO ICARD = 1, NCARD

*    Locate the ICARD'th card
        IDXSTR = ADI2_MKIDX( 'Obj_', ICARD )
        CALL ADI_FIND( CRDTAB, IDXSTR, CRDID, STATUS )

*    Card isn't already written?
        CALL ADI_CGET0L( CRDID, 'Written', WRITTEN, STATUS )
        IF ( .NOT. WRITTEN ) THEN

*      Marked for delete?
          CALL ADI2_ISDEL( CRDID, MRKDEL, STATUS )
          IF ( .NOT. MRKDEL ) THEN

*        What is the card object?
            CALL ADI_TYPE( CRDID, TYPE, STATUS )
            IF ( TYPE .EQ. 'FITSkeyCache' ) THEN

*          Get keyword name
              CALL ADI_CGET0C( CRDID, 'Name', KEYWRD, STATUS )

*          Locate keyword value
              CALL ADI_FIND( CRDID, 'Value', VID, STATUS )
              CALL ADI_TYPE( VID, VTYPE, STATUS )

*          Get keyword comment
              CALL ADI_THERE( CRDID, 'Comment', THERE, STATUS )
              IF ( THERE ) THEN
                CALL ADI_CGET0C( CRDID, 'Comment', CMNT, STATUS )
              ELSE
                CALL ADI2_STDCMT( KEYWRD, CMNT, STATUS )
              END IF

*          DOUBLE or REAL keyword
              FSTAT = 0
              IF ( (VTYPE .EQ. 'DOUBLE') .OR. (VTYPE.EQ.'REAL') ) THEN

*            Format control constants
                CALL ADI_THERE( VID, '.Scientific', THERE, STATUS )
                IF ( THERE ) THEN
                  CALL ADI_CGET0L( VID, '.Scientific', SFMT, STATUS )
                ELSE
                  SFMT = .FALSE.
                END IF
                CALL ADI_THERE( VID, '.Ndecimal', THERE, STATUS )
                IF ( THERE ) THEN
                  CALL ADI_CGET0I( VID, '.Ndecimal', NDEC, STATUS )
                ELSE IF ( VTYPE(1:1) .EQ. 'D' ) THEN
                  NDEC = 14
                ELSE
                  NDEC = 7
                END IF

*            Real value
                IF ( VTYPE(1:1) .EQ. 'R' ) THEN
                  CALL ADI_GET0R( VID, RVAL, STATUS )
                  IF ( SFMT ) THEN
                    CALL FTPKYE( LUN, KEYWRD, RVAL, NDEC, CMNT, FSTAT )
                  ELSE
                    CALL FTPKYF( LUN, KEYWRD, RVAL, NDEC, CMNT, FSTAT )
                  END IF

*            Double precision
                ELSE
                  CALL ADI_GET0D( VID, DVAL, STATUS )
                  IF ( SFMT ) THEN
                    CALL FTPKYD( LUN, KEYWRD, DVAL, NDEC, CMNT, FSTAT )
                  ELSE
                    CALL FTPKYG( LUN, KEYWRD, DVAL, NDEC, CMNT, FSTAT )
                  END IF

                END IF

*          CHAR keyword
              ELSE IF ( VTYPE .EQ. 'CHAR' ) THEN

*            Get and write value
                CALL ADI_GET0C( VID, CVAL, STATUS )
                CALL FTPKYS( LUN, KEYWRD, CVAL(:MAX(1,CHR_LEN(CVAL))), 
     :                       CMNT, FSTAT )

*          LOGICAL keyword
              ELSE IF ( VTYPE .EQ. 'LOGICAL' ) THEN

*            Get and write value
                CALL ADI_GET0L( VID, LVAL, STATUS )
                CALL FTPKYL( LUN, KEYWRD, LVAL, CMNT, FSTAT )

*          Treat everything else as INTEGER
              ELSE

*            Get and write value
                CALL ADI_GET0I( VID, IVAL, STATUS )
                CALL FTPKYJ( LUN, KEYWRD, IVAL, CMNT, FSTAT )

              END IF

*          Release keyword value
              CALL ADI_ERASE( VID, STATUS )

*        FITS comment card
            ELSE IF ( TYPE .EQ. 'FITScommCache' ) THEN

*          Get comment value
              CALL ADI_CGET0C( CRDID, 'Value', CMNT, STATUS )

*          Write it out
              CALL FTPCOM( LUN, CMNT(:MAX(1,CHR_LEN(CMNT))), FSTAT )

*        FITS history card
            ELSE IF ( TYPE .EQ. 'FITShistCache' ) THEN

*          Get history value
              CALL ADI_CGET0C( CRDID, 'Value', CMNT, STATUS )

*          Write it out
              CALL FTPHIS( LUN, CMNT(:MAX(1,CHR_LEN(CMNT))), FSTAT )

*        FITS crap card
            ELSE IF ( TYPE .EQ. 'FITScrapCache' ) THEN

*          Get crap
              CALL ADI_CGET0C( CRDID, 'Value', CMNT, STATUS )

*          Write raw low level card (yeuch)
              CALL FTPREC( LUN, CMNT(:MAX(1,CHR_LEN(CMNT))), FSTAT )
              
            END IF

          END IF

        END IF

*    Release the card
        CALL ADI_ERASE( CRDID, STATUS )

      END DO

*  Release HDU container
      CALL ADI_ERASE( CRDTAB, STATUS )
       
*  Report any errors
      IF ( STATUS .NE. SAI__OK ) THEN
        CALL AST_REXIT( 'ADI2_FCOMIT_CARDS', STATUS )
      END IF

      END