/* identification */
#define VERSION		"1.3"			/* version number 	*/
#define PROGRAM		"LFITS"			/* program name 	*/
#define NDEBUG		0 			/* assert debug mode	*/

/* lfits.c

                            COPYRIGHT (c) 1991
            Kapteyn Astronomical Institute - University of Groningen
                P.O. Box 800, 9700 AV Groningen, The Netherlands

#>            lfits.dc1

Program:      lfits

Purpose:      List FITS files on a tape

Category:     FITS, TAPES, UTILITY

File:         lfits.c

Author:       P.R. Roelfsema (M. Vogelaar)

Keywords:

     TAPE=    Name of input (disk-)tape [ none ]


 ** FILES=    Give file numbers to list [ all files on TAPE ]
    
  ** FULL=    Give listing of entire FITS header? [ N ]
 
** OUTPUT=    Name of file where listings are saved [ none ]

Description:

                LFITS lists files found on a FITS tape. For each file
              it gives a one-line description of its contents.
              
                It is also possible to get the full header (this can give 
              A LOT of output!) by specifying FULL=Y.
 

Updates:      Mar 28, 1991: PRR, Document created.
              Apr  3, 1991: PRR, added OUTPUT= keyword.
              May 15, 1992: VOG, New call to mtopen
#<

*/


#include "gipsyc.h"
#include "assert.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "cmain.h"
#include "init.h"
#include "finis.h"
#include "nelc.h"
#include "status.h"
#include "anyout.h"
#include "error.h"
#include "cancel.h"
#include "usertext.h"
#include "userint.h"
#include "userlog.h"
#include "mtopen.h"
#include "mtclose.h"
#include "mtrew.h"
#include "mtfsf.h"
#include "mtbsf.h"
#include "mtweof.h"
#include "fts_skipfil.h"
#include "ftsd_geth.h"
#include "ftsd_puth.h"
#include "ftsi_geti.h"
#include "ftsi_puti.h"
#include "ftsd_rint.h"
#include "ftsd_rchar.h"
#include "ftsd_find.h"
#include "ircc_rate.h"

#define finit( fc , len ) { fc.a = malloc( ( len + 1 ) * sizeof( char ) ) ;  \
                            fc.l = len ; }


/* definitions for error levels */

/*static  fint            error_level_fatal      =   4;
#define FATAL_ERROR     ( &error_level_fatal   )
static  fint            error_level_serious    =   3;
#define SERIOUS_ERROR   ( &error_level_serious )
static  fint            error_level_minor      =   2;
#define MINOR_ERROR     ( &error_level_minor   )*/
static  fint            error_level_warning    =   1;
#define WARNING         ( &error_level_warning )

/* definitions for anyout levels */

static  fint            anyout_level_default   =  0 ;
#define ANYOUT_DEF      ( &anyout_level_default   )
/*static  fint            anyout_level_terminal  =  1 ;
#define ANYOUT_TERM     ( &anyout_level_terminal  )
static  fint            anyout_level_logfile   =  2 ;
#define ANYOUT_LOG      ( &anyout_level_logfile   )
static  fint            anyout_level_dumb_user =  8 ;
#define ANYOUT_NOEXP    ( &anyout_level_dumb_user )*/
static  fint            anyout_level_test      = 16 ;
#define ANYOUT_TST      ( &anyout_level_test      )

/* definitions for default levels */

/*static  fint            default_no_default     =  0 ;
#define DFLT_NONE       ( &default_no_default  )*/
static  fint            default_has_default    =  1 ;
#define DFLT_DEF	( &default_has_default )
static  fint            default_hidden_key     =  2 ;
#define DFLT_HIDD       ( &default_hidden_key  )
/*static  fint            default_exact_number   =  4 ;
#define DFLT_EXACT      ( &default_exact_number)*/


/* keywords and USER*** message strings */
#define	TAPE_KEY	tofchar( "TAPE=" )
#define	TAPE_MES	tofchar( "Name of input (disk-)tape [ none ]" )

#define	FILES_KEY	tofchar( "FILES=" )
#define	FILES_MES	tofchar( "Give file numbers to list [ all files on TAPE ]" )

#define	FULL_KEY	tofchar( "FULL=" ) 
#define	FULL_MES	tofchar( "Give listing of entire FITS header? [ N ]" ) 

#define	LIST_KEY	tofchar( "OUTPUT=" ) 
#define	LIST_MES	tofchar( "Name of file where listings are saved [ none ]" ) 

/* miscellaneous definitions */
#define true              1
#define false             0
#define MAXTXTLEN       160			/* length of textlines 	*/

#define	OK		    0			/* OK			*/
#define STOP            -1000                   /* stop code            */
#define OPEN_ERROR      -1001                   /* tape open error code */
#define BAD_SKIP        -1002                   /* bad skip count       */
#define BAD_HEADER      -1003                   /* bad header           */
#define END_OF_TAPE     -1006                   /* found EOT            */
#define HEADER_ERROR    -1007                   /* error in process hed */

#define	FTS_EOT		-13			/* fts_io EOT definition*/
#define TAPE_LABEL	-12			/* fts_io tape label	*/

#define	MAXFILES	 250			/* max. nr. of files	*/
#define	FTSBLOCK	2880			/* fits block size	*/
#define FTS_RECLEN	  80			/* fits record size	*/
#define HEDLEN		30*FTSBLOCK		/* fits header size	*/

/*
      The routine OpenTape tries to open a tape unit 
*/
       fint OpenTape( fchar tapename ,		/* open tapename	*/
                      fint  *deflev ,		/* default level	*/
                      fchar key ,		/* the keyword		*/
                      fchar mess )		/* the message		*/

{
   fint		mtid ;				/* tape id		*/	
   fint		error ;				/* error retrun code	*/
   
   char 	line[ MAXTXTLEN ] ;		/* text line		*/

   anyout_c( ANYOUT_TST , tofchar( "LFITS - OpenTape" ) ) ;
/*   nret = usertext_c( tapename ,*/		/* get tape name	*/
/*                      deflev ,	  */		/* has a default	*/
/*                      key ,	  */		/* keyword		*/
/*                      mess ) ;	  */		/* message		*/
/*   cancel_c( key ) ;		*/		/* cancel the keyword	*/
/*   if ( nret == 0 ) return( STOP ) ; */		/* CR -> exit		*/
/*   mtid = mtopen_c( tapename ) ; */		/* try to open tape	*/
   mtid = mtopen_c( tofchar( "?TAPE=Name of tape device [list of all tape devices]" ) );
   
   if ( mtid < 0 ) {				/* cannot open tape	*/
      sprintf( line , "Cannot open tape %.*s, try another" ,
                       nelc_c( tapename ) ,
                       tapename.a ) ;
      error_c( WARNING , tofchar( line ) ) ;	/* issue warning	*/
      sprintf( line , "MTOPEN error nr %d" , mtid ) ;
      anyout_c( ANYOUT_TST , tofchar( line ) ) ;	/* inform user	*/
      return( OPEN_ERROR ) ;			/* return error		*/
   }

   sprintf( line , "Will rewind tape %.*s" ,
                    nelc_c( tapename ) ,
                    tapename.a ) ;
   status_c( tofchar( line ) ) ;		/* inform user		*/
   if ( ( error = mtrew_c( &mtid ) ) < 0 ) {	/* try to rewind	*/
      sprintf( line , "Cannot rewind tape %.*s, try another" ,
                       nelc_c( tapename ) ,
                       tapename.a ) ;
      error_c( WARNING , tofchar( line ) ) ;	/* issue warning	*/
      sprintf( line , "MTREW error nr %d on mtid %d" , error , mtid ) ;
      anyout_c( ANYOUT_TST , tofchar( line ) ) ;	/* inform user	*/
      return( OPEN_ERROR ) ;			/* return error		*/
   }

   sprintf( line , "Opened tape %.*s on mtid %d" ,
                    nelc_c( tapename ) ,
                    tapename.a ,
                    mtid ) ;
   anyout_c( ANYOUT_TST , tofchar( line ) ) ;	/* inform user		*/

   return( mtid ) ;				/* give the mtid back 	*/
}						/* end OpenTape		*/

/*
       CloseTape closes a tape unit and issues a warning in case of trouble
*/
void CloseTape( fint  *mtid , 			/* close mtid		*/
                fchar tapename ) 		/* called tapename	*/
{
   char		line[ MAXTXTLEN ] ;		/* text line		*/

   fint		error ;				/* error retrun code	*/
   
   anyout_c( ANYOUT_TST , tofchar( "LFITS - CloseTape" ) ) ;
   sprintf( line , "Will rewind tape %.*s" ,
                    nelc_c( tapename ) ,
                    tapename.a ) ;
   status_c( tofchar( line ) ) ;		/* inform user		*/
   if ( ( error = mtrew_c( mtid ) ) < 0 ) {	/* try to rewind	*/
      sprintf( line , "Cannot rewind tape %.*s" ,
                       nelc_c( tapename ) ,
                       tapename.a ) ;
      error_c( WARNING , tofchar( line ) ) ;	/* issue warning	*/
      sprintf( line , "MTREW error nr %d on mtid %d" , error , *mtid ) ;
      anyout_c( ANYOUT_TST , tofchar( line ) ) ;/* inform user		*/
   }

   error = mtclose_c( mtid ) ;			/* try to close mtid	*/
   if( error < 0 ) {
      sprintf( line , "Cannot close tape %.*s, state of tape is unknown" ,
                       nelc_c( tapename ) ,
                       tapename.a ) ;
      error_c( WARNING , tofchar( line ) ) ;	/* issue warning	*/
      sprintf( line , "MTCLOSE error nr %d on mtid %d" , error , *mtid ) ;
      anyout_c( ANYOUT_TST , tofchar( line ) ) ;	/* inform user	*/
      return ;
   }

   sprintf( line , "Closed tape %.*s on mtid %d" ,
                    nelc_c( tapename ) ,
                    tapename.a ,
                    *mtid ) ;
   anyout_c( ANYOUT_TST , tofchar( line ) ) ;	/* inform user		*/
}

/*
     MakeHeading opens (on user request an output file, and writes the 
  header for the tape listing on that output file.
*/
static FILE *MakeHeading( fchar tape     ,	/* header for tape	*/
                          fchar listing	 )	/* name of listfile	*/
{
   bool		done = false ;			/* got a filename ?	*/

   FILE		*listfile = NULL ;		/* file handle		*/

   char		line[ MAXTXTLEN ] ;		/* text line		*/
   char		filename[ MAXTXTLEN ] ;		/* filename buffer	*/
   
   fint		nret ;				/* return from usertext	*/
   fint		*deflev ;			/* default level	*/

   if ( !listfile ) {				/* no listfile yet	*/
      deflev = DFLT_HIDD ;			/* start as hidden key	*/
      do {
         nret = usertext_c( listing ,		/* get a listfile name	*/
                            deflev ,		/* default level	*/
                            LIST_KEY ,		/* keyword		*/
                            LIST_MES ) ;	/* message		*/
         if ( nret > 0 ) {			/* user typed something	*/
            (void) strncpy( filename , listing.a , nelc_c( listing ) ) ;
            listfile = fopen( filename , "a" ) ;/* append to file	*/
            done = ( listfile != NULL ) ;	/* done if file is open	*/
            if ( !listfile ) {			/* file open error	*/
               sprintf( line , "Could not open file %.*s, try again" ,
                                nelc_c( listing ) , listing.a ) ;
               error_c( WARNING , tofchar( line ) ) ;	/* warn user	*/
               cancel_c( LIST_KEY ) ;		/* cancel the key	*/
            }
         } else {
            break ;				/* CR -> no file	*/
         }
      } while ( !done ) ;			/* stop until OK	*/
   }

   if ( listfile ) {
      fprintf( listfile , "\n\n  Listing of tape %.*s:\n\n" , nelc_c( tape ) , tape.a ) ;
      fprintf( listfile , "file | object           | instrument |bpix| size(s)  ...   comment\n" ) ;
      fprintf( listfile , "-----|------------------|------------|----|-----------------------------------\n") ;
   } else {
      sprintf( line , "  Listing of tape %.*s:" , nelc_c( tape ) , tape.a ) ;
      anyout_c( ANYOUT_DEF , tofchar( line ) ) ;
      anyout_c( ANYOUT_DEF , tofchar( "" ) ) ;
      sprintf( line , "file | object           | instrument |bpix| size(s)  ...   comment" ) ;
      anyout_c( ANYOUT_DEF , tofchar( line ) ) ;
      sprintf( line , "-----|------------------|------------|----|-----------------------------------") ;
      anyout_c( ANYOUT_DEF , tofchar( line ) ) ;
   }

   return( listfile ) ;				/* give the handle	*/
}						/* MakeHeading		*/

/*
      SkipInFiles skips files on the input tape
*/
       fint SkipInFiles( fint  *mtid ,		/* input tape id	*/
                         fchar tape ,		/* name of input tape	*/
                         fint  *files ,		/* list of files	*/
                         fint  file ,		/* current seq.file nr.	*/
                         bool  all_files ) 	/* do all files ?	*/
{
   char		line[ MAXTXTLEN ] ;		/* text line		*/

   fint		nskip ;				/* nr. of files to skip	*/
   fint		error = 0 ;			/* error return code	*/
         
   anyout_c( ANYOUT_TST , tofchar( "LFITS - SkipInFiles" ) ) ;
   if ( file == 0 ) {				/* first file ?		*/
      nskip = files[ file ] - 1 ;		/* yes-> skip is fileno	*/
   } else {
      nskip = files[ file ] - 
              files[ file - 1 ] - 1 ;		/* no-> skip from last	*/
   }
   sprintf( line , "Sequential file %d is file %d, try to skip %d files" ,
                    file , files[ file ] , nskip ) ;
   anyout_c( ANYOUT_TST , tofchar( line ) ) ;
   error = fts_skipfil_c( mtid  , &nskip ) ;	/* skip forward		*/
   sprintf( line , "FTS_SKIPFIL returns %d trying to skip %d files on tape %.*s" ,
                    error , nskip , nelc_c( tape ) , tape.a ) ;
   anyout_c( ANYOUT_TST , tofchar( line ) ) ;
   if ( error == FTS_EOT )  {			/* got End Of Tape?	*/
      if ( file == 0 ) {			/* first input file ?	*/
         sprintf( line , "Input tape %.*s is empty, try new tape" ,
                          nelc_c( tape ) , tape.a ) ;
         error_c( WARNING , tofchar( line ) ) ;
      } else {					/* EOT, not first file	*/
         if ( !all_files ) {			/* not all? -> warning	*/
            sprintf( line , "Reached end of input tape %.*s before file %d!" ,
                             nelc_c( tape ) , tape.a ,
                             files[ file ] ) ;
            error_c( WARNING , tofchar( line ) ) ;
         }
      }
      return( BAD_SKIP ) ;			/* exit loop on files	*/
   } else if ( error < 0 ) {
      sprintf( line , "Error %d skipping %d files on input tape %.*s, try new tape" ,
                       error , nskip ,
                       nelc_c( tape ) , tape.a ) ;
      error_c( WARNING , tofchar( line ) ) ;
      return( BAD_SKIP ) ;			/* exit loop on files	*/
   }
   
   return( OK ) ;         			/* no problems 		*/
}						/* end SkipInFiles	*/

/*
      ClearHeader sets an entire  header to balnk spaces
*/
       void ClearHeader( char *header , 	/* clear header		*/
                         fint  nel )		/* number of items to do*/
{
   fint		n ;
   
   anyout_c( ANYOUT_TST , tofchar( "LFITS - ClearHeader" ) ) ;
   for ( n = 0 ; n < nel ; n++ ) {		/* loop on header array	*/
      header[ n ] = ' ' ;			/* set element to space	*/
   }
}						/* end ClearHeader	*/

/*
      ProcessHeaders reads the input header and creates an output header
*/
       int ProcessHeaders( fint  *mtid  ,	/* input mtid		*/
                           fchar tape ,		/* input tape		*/
                           fchar header  ,	/* input header		*/
                           fint  file )		/* current file number	*/
{
   char		line[ MAXTXTLEN ] ;		/* text line		*/

   fint		one = 1 ;
   fint		tid  ;				/* tid of input tape	*/
   fint		error ;				/* retrun code		*/
   
   anyout_c( ANYOUT_TST , tofchar( "LFITS - ProcessHeaders" ) ) ;
   ClearHeader( header.a , header.l ) ;	/* fill header with ' '	*/
   error  = TAPE_LABEL ;			
   while ( error == TAPE_LABEL ) {		/* skip label		*/
      tid  = 0 ;				/* initialise tid	*/
      error = ftsd_geth_c( mtid  ,		/* get tape		*/
                           header  ,		/* header of tape	*/
                           &tid  ) ;		/* input tid		*/
      sprintf( line , "Read %d character (max %d) header (tid %d) from mtid %d (tape %.*s)" ,
                       error , header.l , tid  , *mtid  , nelc_c( tape ) , tape.a ) ;
      anyout_c( ANYOUT_TST , tofchar(line ) ) ;
   }
   if ( error == FTS_EOT ) {			/* found end of tape	*/
      sprintf( line , "End of input tape %.*s" ,
                       nelc_c( tape ) , tape.a ) ;
      status_c( tofchar( line ) ) ;		/* tell user	*/
      return( END_OF_TAPE ) ;			/* exit loop on files	*/
   } else if ( error < 0 ) {			/* error reading header	*/
      sprintf( line , "Error %d reading header of file %d on input tape %.*s, try next file" ,
                       error, file , nelc_c( tape ) , tape.a ) ;
      error_c( WARNING , tofchar( line ) ) ;	/* tell user	*/
      sprintf( line , "Error %d reading header of file %d on mtid %d (tape %.*s)" ,
                       error , file , *mtid  ,
                       nelc_c( tape ) , tape.a ) ;
      anyout_c( ANYOUT_TST , tofchar( line ) ) ;
      return( HEADER_ERROR ) ;			/* exit loop on files	*/
   }

   error = mtfsf_c( mtid , &one ) ;
   if ( error != one ) {
      sprintf( line , "Error skipping file %d on input tape %.*s, try next file" ,
                       file , nelc_c( tape ) , tape.a ) ;
      error_c( WARNING , tofchar( line ) ) ;	/* tell user	*/
      sprintf( line , "Error %d skipping to next file on mtid %d (tape %.*s)" ,
                       error , file , *mtid  ,
                       nelc_c( tape ) , tape.a ) ;
      return( HEADER_ERROR ) ;			/* exit loop on files	*/
   }

   return( OK ) ;				/* no problems		*/
}						/* end ProcessHeaders	*/

/*
      ListFile lists the current file in the desired format
*/      
static void ListFile( fint file ,		/* current file number	*/
                      fchar header ,  		/* FITS header 		*/
                      FILE *listfile ) 		/* list on list-file	*/
{
   bool		full = false ;			/* list full header?	*/
   
   char		line[ MAXTXTLEN ] ;		/* character line 	*/
   char		line2[ MAXTXTLEN ] ;		/* character line too 	*/
   char		key[ MAXTXTLEN ] ;		/* keyword	 	*/
   
   fint		n , one = 1 ;
   fint		naxis ;				/* nr. of axes		*/
   fint		bitpix ;			/* nr. of bits per pix.	*/ 
   fint		npix ;				/* nr. pixels on axis	*/
   fint		nrecs ;				/* nr. of FITS records	*/
   fint		sop = 0 , att = 0 ;		/* sop/att: IRAS	*/ 
  
   fchar	object ;			/* object name		*/
   fchar	instrument ;			/* instrument name	*/
   fchar	comment ;			/* comment record	*/
   
   anyout_c( ANYOUT_TST , tofchar( "LFITS - ListFile" ) ) ;
   finit( object        , MAXTXTLEN ) ;		/* initialise fchars	*/ 
   finit( instrument    , MAXTXTLEN ) ;
   finit( comment       , MAXTXTLEN ) ;
  
   (void) ftsd_rint_c(  header , 		/* read from header	*/
                        tofchar( "NAXIS" ) , 	/* NAXIS key		*/
                        &naxis ) ;		/* gives naxis		*/
   (void) ftsd_rint_c(  header , 		/* read from header	*/
                        tofchar( "BITPIX" ) , 	/* BITPIX key		*/
                        &bitpix ) ;		/* gives bitpix		*/
   if ( ftsd_rchar_c( header , 			/* read from header	*/
                      tofchar( "OBJECT" ) ,  	/* OBJECT key		*/
                      object ) < 0 ) {		/* gives object		*/
      (void) strncpy( object.a , "object unknown    " , 18 ) ;
      if ( ftsd_rint_c( header ,		/* read from header	*/
                        tofchar( "SOP" ) ,  	/* SOP key		*/
                        &sop ) >= 0 ) {		/* gives sop		*/
         (void) ftsd_rint_c( header ,		/* read from header	*/
                             tofchar( "ATT" ) ,	/* ATT key		*/
                             &att ) ;		/* gives att		*/
         sprintf( object.a , "sop/att %03d/%03d   " , sop ,att ) ;
      }
   }
   if ( ftsd_rchar_c( header , 			/* read from header	*/
                      tofchar( "INSTRUME" ) , 	/* INSTRUME key		*/
                      instrument ) < 0 ) {	/* gives instrument	*/
      if ( sop != 0 ) {				/* IRAS => BPHF		*/
         (void) strncpy( instrument.a , "IRAS BPHF  " , 10 ) ;         
      } else {
         (void) strncpy( instrument.a , "unknown    " , 10 ) ;
      }
   }
   sprintf( line , "%4d | %16.16s | %10.10s | %2d | " ,
                    file ,			/* file number		*/
                    object.a ,			/* object name		*/
                    instrument.a ,		/* instrument name	*/
                    bitpix ) ;			/* nr. of bits per pix.	*/

   for ( n = 1 ; n <= naxis ; n++ ) {		/* loop on axes		*/
      sprintf( key , "NAXIS%d" , n ) ;		/* make NAXIS% key	*/
      ftsd_rint_c(  header , 			/* read from header	*/
                    tofchar( key ) , 		/* NAXIS% key		*/
                    &npix ) ;			/* gives npix		*/
      if ( n < naxis ) {			/* not last axis yet	*/
         sprintf( line2 , "%5d *" , npix ) ;
      } else {					/* last axis 		*/
         sprintf( line2 , "%5d | " , npix ) ;
      }
      (void) strcat( line , line2 ) ;		/* add to line		*/
   }
   if ( ftsd_find_c( header , 			/* read from header	*/
                     tofchar( "COMMENT" ) , 	/* COMMENT key		*/
                     comment ) > 0 ) {		/* gives comment	*/
      (void) strncat( line , &comment.a[ 7 ] , nelc_c( comment ) - 7 ) ;
   }
   if ( listfile ) {				/* listing to file ?	*/
      fprintf( listfile , "%s\n" , line ) ;	/* print to file	*/
   } else {					/* no listfile		*/
      anyout_c( ANYOUT_DEF , tofchar( line ) ) ;/* print to screen	*/
   }
   
   n       = userlog_c( &full ,			/* full header?		*/
                        &one ,			/* only one logical	*/
                        DFLT_HIDD ,		/* hidden keyword	*/
                        FULL_KEY ,		/* keyword		*/
                        FULL_MES ) ;		/* message		*/
   if ( full ) {				/* user wants full	*/
      nrecs = nelc_c( header ) / FTS_RECLEN + 1 ;	/* nr. records	*/
      for ( n = 0 ; n < nrecs ; n++ ) {		/* loop on all records	*/
         sprintf( line , "%.*s" ,		/* put record in buffer	*/
                         FTS_RECLEN ,		/* one FITS record	*/
                         &header.a[ n * FTS_RECLEN ] ) ;
         if ( listfile ) {			/* listing to file ?	*/
            fprintf( listfile , "%s\n" , line ) ;	/* to file	*/
         } else {				/* no listfile		*/
            anyout_c( ANYOUT_DEF , tofchar( line ) ) ;	/* to screen	*/
         }
      }
   }
   

}						/* ListFile		*/

MAIN_PROGRAM_ENTRY
{
   FILE		*listfile = NULL ;		/* list-file handle	*/

   bool		all_files ;			/* all files ?		*/
   bool		done ;				
   
   char 	line[ MAXTXTLEN ] ;		/* text line		*/

   fchar	tape ;				/* name of input tape	*/
   fchar	header  ;			/* input fits header 	*/
   fchar	listing  ;			/* name of list-file 	*/
   
   fint		error = 0 ;			/* error return code	*/
   fint		*files ;			/* filenumbers to read	*/
   fint		nfiles ;			/* nr. of files to read	*/
   fint         maxfiles = MAXFILES ;		/* max. nr. of files	*/
   fint		file ;				/* file number		*/
   fint		mtid  ;				/* input tape id	*/

   init_c( ); 					/* hello HERMES 	*/
   IDENTIFICATION( PROGRAM , VERSION ) ;
   finit( tape       , MAXTXTLEN ) ;		/* initialise fchars	*/
   finit( header     , HEDLEN    ) ;
   finit( listing    , MAXTXTLEN ) ;
   files = (fint *) malloc( MAXFILES * sizeof( fint ) ) ;


   done = false ;
   while( !done ){				/* stop after one tape 	*/
      done = true ;

      mtid   = OpenTape( tape ,			/* get tape name	*/
                         DFLT_DEF ,		/* has a default	*/
                         TAPE_KEY ,		/* keyword		*/
                         TAPE_MES ) ;		/* message		*/
      if( mtid  == OPEN_ERROR ) continue ;	/* open error -> retry	*/
      if( mtid  == STOP ) break ;		/* CR -> exit 		*/
      
      nfiles  = userint_c( files ,		/* ask file numbers	*/
                           &maxfiles ,		/* max. nr. of files	*/
                           DFLT_HIDD ,		/* hidden keyword	*/
                           FILES_KEY ,		/* keyword		*/
                           FILES_MES ) ;	/* message		*/
      all_files = ( nfiles == 0 ) ;		/* read all files ?	*/
      if ( all_files ) {			/* set nfiles for all	*/
         nfiles = 1 ;
      }
            

      listfile = MakeHeading( tape     ,	/* header for tape	*/
                              listing  ) ;	/* name of listfile	*/

      sprintf( line , "Listing tape %s" , tape.a ) ;
      status_c( tofchar( line ) ) ;		/* inform user		*/
      for ( file = 0 ; file < nfiles ; file++ ) {/* loop on the files	*/
         if ( all_files ) {
            if ( nfiles > maxfiles ) {		/* to many files 	*/
               maxfiles = maxfiles + MAXFILES ;	/* add buffer space	*/
               files = (fint *)realloc( (char *)files , maxfiles * sizeof( fint ) ) ;
            }
            files[ file ] = file + 1 ;		/* set files		*/
            nfiles = nfiles + 1 ;		/* add a file		*/
         }

         error = SkipInFiles( &mtid  ,		/* input tape id	*/
                              tape ,		/* name of input tape	*/
                              files ,		/* list of files	*/
                              file ,		/* current seq.file nr.	*/
                              all_files ) ;	/* do all files ?	*/
         if ( error < 0 ) break ;		/* problem -> next tape	*/

         error = ProcessHeaders( &mtid  ,	/* input mtid		*/
                                 tape ,		/* input tape		*/
                                 header  ,	/* input header		*/
                                 files[ file ] ); /* current file nr.	*/
         if ( error == END_OF_TAPE ) {		/* EOT -> done		*/
            break ;
         } else if ( error < 0 ) {		/* problem -> next file	*/
            continue ;
         }
         
         ListFile( files[ file ] ,		/* current file number	*/
                   header , 			/* FITS header 		*/
                   listfile ) ;			/* on list-file		*/
         
      }						/* end loop on files	*/

      CloseTape( &mtid  , tape  ) ;		/* close tape		*/
      
      if ( listfile ) {				/* output file used	*/
         sprintf( line , "Listing of tape %.*s written to file %.*s" ,
                          nelc_c( tape )    , tape.a ,
                          nelc_c( listing ) , listing.a ) ;
         anyout_c( ANYOUT_DEF , tofchar( line ) ) ;	/* tell user 	*/
         (void) fclose( listfile ) ;		/* close listfile	*/
         listfile = NULL ;			/* no listfile		*/
      }
      
                 
   }						/* end endless loop	*/

   finis_c( );					/* bye, bye HERMES 	*/
   return( 0 ) ;
}



