/********************************************************************* * Program Name : SNIFF - Search Numerically Indexed FITS File * Version : See below * Author : Dan Wilkinson * Date Written : August 18, 1992 * Date Updated : March 8, 1993 * Function : Put the FITS Binary Table Files to the TEST. * Reads the header and copies the selected portion * of data to a file as ASCII. * * This program consists of a collection of C functions * designed to read and interpret the contents of the * GOES data files written in the FITS Binary Table * Extention format. The intent is for this code to * be transportable between various computer systems * and compilers. So far, it has been successfully * tested on a PC with Microsoft C and Borland C, a SUN * with the GNU C compiler, and a DEC Workstation. * version .002 version .003 Allow for excess header records., i.e. blank records after END that exceed FITS requirement. Display warning, but find data start OK. version .004 Increase the data output format to show 4 digits. Change all console I/O to gets(). Show input and output files at end of processing. version .005 Restrict IndexSize to 2-1000 instead of 1-1000. This avoids a divide by zero in dcwCreateIndex. version .006 After compiling with Borland C++ 3.1, several warning were given. Minor changes were made to eliminate them. version .007 The search IndexSize is set to 100 instead of being user selectable. The function dcwCopyData() was modified to return a count of the records output. The library function strnset() was changed to the more common memset() in function dcwCopyHeader(). main() was changed to show the date and time after doing a search. version .008 If a user requests a seek for day < 1, the program now forces the day to 1 in main(). dcwMakeDate() returns GOOD and sets date to day 1 when when it is sent a negative seconds of the month. Some GOES data files start on previous month which can make seconds of the month negative! version .009 Modified to handle HEPAD data. A search for the string HEPAD will show all instances of modification. version 1.00 Modified to handle corrections made to the FITS files: NAXIS2 set to the actual data record count. TZEROn keywords changed to SUBZEROn. Files padded to n*2880 bytes. EXTVER key value set to 2. version 1.1 Make minor changes to eliminate some compilation errors using RISC C compiler on Ultrix 4.2. All #ifdef and #endif were moved to column #1 and (float) is used instead of F. version 1.2 Take out the != 0L in the while statement in dcwCopyData() and dcwCopyDatax(). version 1.3 This version of sniff will work on either the version 1 or version 2 data files. This is accomplished by adding dcwParseTZERO() and dcwSetNAXIS2 functions. version 1.4 dcwCopyDatax() modified to copy data even when the flagword goes to zero (which is shouldn't do but does). version 1.5 The if statement controling the dcwSetNAXIS2 function usage had a = instead of a == in the main module. *********************************************************************/ #define VERSION 1.5 #include #include #include #include #include #include #include /***** The binary integers used in FITS formatted data files are two's complement with the bytes in decreasing order of significance (Big Endian). The following table lists how this compares to some popular computer prcessors. If your computer does not default to the FITS integer representation, you will have to swap bytes accordingly. This list was prepared from word-of-mouth only! If you have additions or corrections please call me: Dan Wilkinson (303) 497-6137 dcw@mail.ngdc.noaa.gov INTEGER BYTE ORDER 16-BIT 32-BIT -------------------------------- FITS B1 B0 B3 B2 B1 B0 MOTOROLA B1 B0 B3 B2 B1 B0 DATA GENERAL B1 B0 B3 B2 B1 B0 MACINTOSH B1 B0 B3 B2 B1 B0 APOLLO B1 B0 B3 B2 B1 B0 SPARC B1 B0 B3 B2 B1 B0 SUN B1 B0 B3 B2 B1 B0 IBM 360/370 B1 B0 B3 B2 B1 B0 INTEL B0 B1 B0 B1 B2 B3 Must Swap IBM PC B0 B1 B0 B1 B2 B3 Must Swap VAX B0 B1 B0 B1 B2 B3 Must Swap DEC STATION B0 B1 B0 B1 B2 B3 Must Swap PDP B0 B1 B2 B3 B0 B1 On your own : -------------------------------- This program will swap bytes when SWAPBYTES is defined. Remove "#define SWAPBYTES" when swapping is not necessary. *****/ #define SWAPBYTES /***** Define DEBUG and DEBUG_OPEN to print useful process information to DebugStream *****/ #define xDEBUG #define xDEBUG_OPEN #define SEEK_SET 0 /* Used in fseek to seek from file top */ #define SEEK_CUR 1 /* Used in fseek to seek current position */ #define SEEK_END 2 /* Used in fseek to seek from file end */ #define YES 1 #define NO 0 #define GOOD 1 #define BAD 0 #define PRIMARY_HEADER 1 #define EXTEND_HEADER 2 #define DATA_TOP 3 #define DATA_BOTTOM 4 #define TYPE_SHORT 1 #define TYPE_LONG 2 #define TYPE_CHAR 3 #define TYPE_FLOAT 4 #define TYPE_STRING 5 #define HEADER_RECORD 80 #define HEADER_BLOCK 2880 #define TIME 0 #define OFFSET 1 #define TWO_BYTES 2 #define FOUR_BYTES 4 #define MAG 10 #define XRAY 11 #define PART 12 #define HEPAD 13 #define HP 0 #define HE 1 #define HN 2 #define XS 0 #define XL 1 #define MPX2 0 #define MPX4 1 #define MPX8 2 short DataType; short RC; char HeaderRecord[HEADER_RECORD]; /* structure with basic header info */ typedef struct { char XTENSION[15]; short BITPIX; short NAXIS; long NAXIS1; long NAXIS2; short PCOUNT; short GCOUNT; char OBSERVER[10]; char INSTRUME[15]; char DATE[10]; char DATEOBS[10]; short TFIELDS; short EXTVER; char AUTHOR[15]; char TFORM[6]; char TTYPE[6][10]; long TNULL[6]; long SUBZERO[6]; float LONG[32]; } BASIC_HEADER; BASIC_HEADER BasicHeader; typedef struct { short Year; short Month; short Day; short Hour; short Minute; short Second; long SecMonth; } DATE; DATE Creation; DATE Observation; DATE Date; typedef struct { long SecMonth; long FlagWord; short Raw[3]; float Data[3]; } DATA_RECORD; DATA_RECORD DataRecord; #define MAX_ROW 1000 #define MAX_COL 2 long DataIndex[MAX_ROW][MAX_COL]; short IndexSize; FILE *InputStream, *OutputStream, *DebugStream; char InFile[40], OutFile[40], DebugFile[40]; char DebugFile[40] = "sniff.dbg"; void dcwIntro( void ); short dcwOpenFiles( short argc, char **argv, FILE **InputStream, FILE **OutputStream ); short dcwSeek( FILE *InputStream, short Boundary ); short dcwSeekBlockEnd( FILE *InputStream ); short dcwCopyHeader( FILE *InputStream, FILE *OutputStream, short Boundary ); short dcwShowHeader( FILE *InputStream, short LinesPerScreen, short Boundary ); short dcwParseHeader( FILE *InputStream, BASIC_HEADER *BasicHeader, short Boundary ); short dcwParseTZERO( FILE *InputStream, BASIC_HEADER *BasicHeader, short Boundary ); short dcwSetNAXIS2( FILE *InputStream, BASIC_HEADER *BasicHeader ); short dcwGetKeyWord( FILE *InputStream, char *KeyWord, void *KeyValue, short DataType, short Boundary ); short dcwParseDate( BASIC_HEADER BasicHeader, DATE *Creation, DATE *Observation ); short dcwMakeDate( long SecMonth, DATE *Observation ); short dcwParseType( BASIC_HEADER BasicHeader, short *DataType ); short dcwCreateIndex( FILE *InputStream, long DataIndex[MAX_ROW][MAX_COL], short IndexSize ); short dcwSwapBytes( char *in, short Bytes ); short dcwCopyData( FILE *InputStream, FILE *OutputStream, long DeltaSeconds, long *RecordCount ); short dcwCopyDatax( FILE *InputStream, FILE *OutputStream, long DeltaSeconds, long *RecordCount ); short dcwUnpack( DATA_RECORD *DataRecord, short DataType ); short dcwIndexSeek( FILE *InputStream, short SeekDay, short SeekHour, short SeekMin, short IndexSize ); float x_float ( int x_flux ); float h_float ( int h_flux ); float p_float ( int p_flux ); int main( short argc, char **argv ) { char Response[60]; short Hours; short SeekDay, SeekHour, SeekMin; long RecordCount, DeltaSeconds; dcwIntro(); /***** O P E N ******/ if ( dcwOpenFiles( argc, argv, &InputStream, &OutputStream ) == BAD ) return(0); RC = dcwShowHeader( InputStream, 17, EXTEND_HEADER ); /***** H E A D E R *****/ printf( "\nCopy header to output? (Y/N): " ); gets( Response ); if( Response[0] == 'y' || Response[0] == 'Y'){ RC = dcwCopyHeader( InputStream, OutputStream, PRIMARY_HEADER ); RC = dcwCopyHeader( InputStream, OutputStream, EXTEND_HEADER ); } printf( "\nParsing header information.\n" ); RC = dcwParseHeader( InputStream, &BasicHeader, EXTEND_HEADER ); /***** If BasicHeader.EXTVER is set to 1, the incoming file is the original version that was created on the CYBER. Calling the following function will get the SUBZEROn info from the TZEROn keyword. See comments for version 1.0 above. *****/ if( BasicHeader.EXTVER == 1 ){ RC = dcwParseTZERO( InputStream, &BasicHeader, EXTEND_HEADER ); RC = dcwSetNAXIS2( InputStream, &BasicHeader ); } if( RC == GOOD ){ RC = dcwParseDate( BasicHeader, &Creation, &Observation ); RC = dcwParseType( BasicHeader, &DataType ); } else{ printf( "Could not read the header properly, good-bye.\n" ); return(0); } /***** I N D E X *****/ /***** The index created below is a two dimensional array -- one column for file offset and one for seconds of month at that offset. An index array of 1000 elements will allow very fast time searches, but, takes a long time to create. An index array of 100 elements is a good choice for most cases because is is created quickly and searches reasonably fast. *****/ do{ /**** The IndexSize is soft wired here to be 100. *****/ /* printf( "\nEnter the index size (2-1000): " ); gets( Response ); sscanf( Response, "%d", &IndexSize ); */ IndexSize = 100; } while( IndexSize < 2 || IndexSize > MAX_ROW ); printf( "\nCreating a %hd-address search index.\n", IndexSize ); RC = dcwCreateIndex( InputStream, DataIndex, IndexSize ); /***** S E E K *****/ printf( "\nEnter location to seek (day,hour,min): " ); gets( Response ); sscanf( Response, "%hd,%hd,%hd", &SeekDay, &SeekHour, &SeekMin ); if( SeekDay <= 0L ){ SeekDay = 1; } printf( "\nSeeking day %hd hour %hd minute %hd.\n", SeekDay, SeekHour, SeekMin ); RC = dcwIndexSeek( InputStream, SeekDay, SeekHour, SeekMin, IndexSize ); RC = dcwMakeDate( DataRecord.SecMonth, &Observation ); printf( "File pointer points to: Date %2hd/%2hd/%2hd\n" " Time %2hd:%2hd:%2hd\n", Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second ); /***** C O P Y *****/ if( RC == GOOD ){ printf( "\nEnter number of hours to copy: " ); gets( Response ); sscanf( Response, "%hd", &Hours ); printf( "\nCopying data records to file...\n" ); DeltaSeconds = Hours * 60L * 60L; RC = dcwCopyDatax( InputStream, OutputStream, DeltaSeconds, &RecordCount ); printf( "\nYour range ideally encompasses %ld data records,\n" "%ld records were output.\n", (long)Hours * 60L * 20L, RecordCount ); } printf("\nInput file Name : %s\n" "Output file Name : %s\n", InFile, OutFile ); printf( "\nDone!\n" ); fclose( InputStream ); fclose( OutputStream ); #ifdef DEBUG fclose( DebugStream ); #endif return(0); } /******************************************************************** * Function Name: dcwIntro * Author : Dan Wilkinson * Date : October 30, 1992 * Function : Print a program introduction to screen. *********************************************************************/ void dcwIntro( void ) { printf( "\nS N I F F version(%5.3f)\n", VERSION ); } /******************************************************************** * Function Name: dcwMakeDate * Author : Dan Wilkinson * Date : August 27, 1992 * Function : Convert seconds of month to day, hour, minute, second. *********************************************************************/ short dcwMakeDate( long SecMonth, DATE *Date ) { long SecDay; if( SecMonth < 0 ){ Date->Day = 1; Date->Hour = 0; Date->Minute = 0; Date->Second = 0; Date->SecMonth = SecMonth; return( GOOD ); } /***** Days in SecMonth *****/ Date->Day = (short) ( ( SecMonth / (24L*60L*60L) ) + 1L ); /***** Seconds remaining on last day *****/ SecDay = (long) ( SecMonth - ( ( (long)Date->Day - 1L ) * 24L*60L*60L ) ); Date->Hour = (short) ( SecDay / (60L*60L) ); Date->Minute = (short) ( ( SecDay - (60L*60L*(long)Date->Hour) ) / 60L ); Date->Second = (short) ( SecDay - (60L*60L*(long)Date->Hour) - (60L*(long)Date->Minute) ); Date->SecMonth = SecMonth; return(GOOD); } /******************************************************************** * Function Name: dcwIndexSeek * Author : Dan Wilkinson * Date : August 24, 1992 * Function : Use an array of offset vs. time for indexed searches *********************************************************************/ short dcwIndexSeek( FILE *InputStream, short SeekDay, short SeekHour, short SeekMin, short IndexSize ) { long SeekSec, BytesBack; short Index; SeekSec = ( ( (long)SeekDay - 1L ) * 24L * 60L * 60L ) + ( (long)SeekHour * 60L * 60L ) + ( (long)SeekMin * 60L ); if( SeekSec < DataIndex[0][TIME] ){ RC = fseek( InputStream, DataIndex[0][OFFSET], SEEK_SET ); RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); RC = fseek( InputStream, -1*BasicHeader.NAXIS1, SEEK_CUR ); dcwSwapBytes( (char *) &(DataRecord.SecMonth), FOUR_BYTES ); #ifdef DEBUG fprintf( DebugStream, "dcwIndexSeek(): SeekSec= %ld - underflow!\n", SeekSec ); #endif return( GOOD ); } if( SeekSec > DataIndex[IndexSize-1][TIME] ){ RC = fseek( InputStream, DataIndex[IndexSize-1][OFFSET], SEEK_SET ); RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); RC = fseek( InputStream, -1*BasicHeader.NAXIS1, SEEK_CUR ); dcwSwapBytes( (char *) &(DataRecord.SecMonth), FOUR_BYTES ); #ifdef DEBUG fprintf( DebugStream, "dcwIndexSeek(): SeekSec= %ld - overflow!\n", SeekSec ); #endif return( GOOD ); } /***** Find the nearest index that has time < searched for time *****/ for( Index = IndexSize-1; Index >= 0; --Index ){ #ifdef DEBUG fprintf( DebugStream, " SeekSec=%ld" " DataIndex[%hd][OFFSET]=%8ld, DataIndex[%hd][TIME]=%8ld\n", SeekSec, Index, DataIndex[Index][OFFSET], Index, DataIndex[Index][TIME] ); #endif if( SeekSec >= DataIndex[Index][TIME] ){ break; } } RC = fseek( InputStream, DataIndex[Index][OFFSET], SEEK_SET ); RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); RC = fseek( InputStream, -1*BasicHeader.NAXIS1, SEEK_CUR ); dcwSwapBytes( (char *) &(DataRecord.SecMonth), FOUR_BYTES ); #ifdef DEBUG fprintf( DebugStream, "dcwIndexSeek(): SeekSec=%ld DataIndex[%hd][TIME]=%ld\n", SeekSec, Index, DataIndex[Index][TIME] ); #endif BytesBack = BasicHeader.NAXIS1; while( BytesBack == BasicHeader.NAXIS1 ){ RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); dcwSwapBytes( (char *) &(DataRecord.SecMonth), FOUR_BYTES ); if( SeekSec < DataRecord.SecMonth ){ RC = fseek( InputStream, -2*BasicHeader.NAXIS1, SEEK_CUR ); BytesBack = (long)fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); RC = fseek( InputStream, -1*BasicHeader.NAXIS1, SEEK_CUR ); dcwSwapBytes( (char *) &(DataRecord.SecMonth), FOUR_BYTES ); #ifdef DEBUG fprintf( DebugStream, "dcwIndexSeek(): \n" " SeekDay = %hd, SeekHour = %hd, SeekMin = %hd\n" " SeekSec = %ld, DataRecord.SecMonth = %ld\n" " DataIndex[%hd][TIME] = %ld, DataIndex[%hd][OFFSET] = %ld\n", SeekDay, SeekHour, SeekMin, SeekSec, DataRecord.SecMonth, Index, DataIndex[Index][TIME], Index, DataIndex[Index][OFFSET] ); #endif return( GOOD ); } } return( BAD ); } /******************************************************************** * Function Name: dcwCopyDatax * Author : Dan Wilkinson * Date : August 24, 1992 * Function : Copy data to file. *********************************************************************/ short dcwCopyDatax( FILE *InputStream, FILE *OutputStream, long DeltaSeconds, long *RecordCount ) { long MaxSeconds; *RecordCount = 0L; /* The dcwIndexSeek function left the data structure loaded with the contents of the current data record */ MaxSeconds = DataRecord.SecMonth + DeltaSeconds + 3L; fprintf( OutputStream, "%s\n", BasicHeader.OBSERVER ); /* while( DataRecord.SecMonth <= MaxSeconds && DataRecord.FlagWord != 0L ){ */ while( DataRecord.SecMonth <= MaxSeconds ){ RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); if( RC != (short)BasicHeader.NAXIS1 ){ break; } ++*RecordCount; dcwUnpack( &DataRecord, DataType ); dcwMakeDate( DataRecord.SecMonth, &Observation ); switch( DataType ){ case MAG: fprintf( OutputStream, "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%10ld %11.3e %11.3e %11.3e\n", Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.FlagWord, DataRecord.Data[HP], DataRecord.Data[HE], DataRecord.Data[HN] ); break; case XRAY: fprintf( OutputStream, "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%10ld %11.3e %11.3e\n", Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.FlagWord, DataRecord.Data[XS], DataRecord.Data[XL] ); break; case PART: fprintf( OutputStream, "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%10ld %11.3e %11.3e %11.3e\n", Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.FlagWord, DataRecord.Data[MPX2], DataRecord.Data[MPX4], DataRecord.Data[MPX8] ); break; case HEPAD: fprintf( OutputStream, "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%10ld %11.3e %11.3e\n", Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.FlagWord, DataRecord.Data[MPX2], DataRecord.Data[MPX4] ); break; } } return( GOOD ); } /******************************************************************** * Function Name: dcwCopyData * Author : Dan Wilkinson * Date : August 24, 1992 * Function : Copy data to file. *********************************************************************/ short dcwCopyData( FILE *InputStream, FILE *OutputStream, long DeltaSeconds, long *RecordCount ) { long FileOffset, MaxSeconds; char Head1[100], Head2[100]; *RecordCount = 0L; /* The dcwIndexSeek function left the data structure loaded with the contents of the current data record */ MaxSeconds = DataRecord.SecMonth + DeltaSeconds + 3L; switch( DataType ){ case MAG: strcpy( Head1,"Rec # Offset Sec Mo FLAGWORD HP HE HN YY/MM/DD:HH:MM:SS Raw->" ); strcpy( Head2,"---------------------------------------------------------------------" ); /* 99999 99999999 9999999 9999999999 999.9 999.9 999.9 99/99/99:99:99:99 */ break; case XRAY: strcpy( Head1,"Rec # Offset Sec Mo FLAGWORD XS XL YY/MM/DD:HH:MM:SS Raw->" ); strcpy( Head2,"-----------------------------------------------------------------------" ); /* 99999 99999999 9999999 9999999999 9.99E+999 9.99E+999 */ break; case PART: strcpy( Head1,"Rec # Offset Sec Mo FLAGWORD MPX2 MPX4 MPX8 YY/MM/DD:HH:MM:SS Raw->" ); strcpy( Head2,"---------------------------------------------------------------------------------" ); /* 99999 99999999 9999999 9999999999 9.99E+999 9.99E+999 9.99E+999*/ break; case HEPAD: strcpy( Head1,"Rec # Offset Sec Mo FLAGWORD MPX4 MPX[4] YY/MM/DD:HH:MM:SS Raw->" ); strcpy( Head2,"---------------------------------------------------------------------------------" ); /* 99999 99999999 9999999 9999999999 9.99E+999 9.99E+999 */ break; } fprintf( OutputStream, "\n%s\n%s\n", Head1, Head2 ); while( DataRecord.SecMonth <= MaxSeconds && DataRecord.FlagWord != 0L ){ FileOffset= ftell( InputStream ); RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); if( RC != (short)BasicHeader.NAXIS1 ){ break; } ++*RecordCount; dcwUnpack( &DataRecord, DataType ); dcwMakeDate( DataRecord.SecMonth, &Observation ); switch( DataType ){ case MAG: fprintf( OutputStream, "%5ld %8ld %7ld %10ld %5.1f %5.1f %5.1f " "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%5hd %5hd %5hd\n", *RecordCount, FileOffset, DataRecord.SecMonth, DataRecord.FlagWord, DataRecord.Data[HP], DataRecord.Data[HE], DataRecord.Data[HN], Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.Raw[HP], DataRecord.Raw[HE], DataRecord.Raw[HN] ); break; case XRAY: fprintf( OutputStream, "%5ld %8ld %7ld %10ld %9.2e %9.2e " "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%5hd %5hd\n", *RecordCount, FileOffset, DataRecord.SecMonth, DataRecord.FlagWord, DataRecord.Data[XS], DataRecord.Data[XL], Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.Raw[XS], DataRecord.Raw[XL] ); break; case PART: fprintf( OutputStream, "%5ld %8ld %7ld %10ld %9.2e %9.2e %9.2e " "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%5hd %5hd %5hd\n", *RecordCount, FileOffset, DataRecord.SecMonth, DataRecord.FlagWord, DataRecord.Data[MPX2], DataRecord.Data[MPX4], DataRecord.Data[MPX8], Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.Raw[MPX2], DataRecord.Raw[MPX4], DataRecord.Raw[MPX8] ); break; case HEPAD: fprintf( OutputStream, "%5ld %8ld %7ld %10ld %9.2e %9.2e " "%2hd/%2hd/%2hd:%2hd:%2hd:%2hd " "%5hd %5hd\n", *RecordCount, FileOffset, DataRecord.SecMonth, DataRecord.FlagWord, DataRecord.Data[MPX2], DataRecord.Data[MPX4], Observation.Year, Observation.Month, Observation.Day, Observation.Hour, Observation.Minute, Observation.Second, DataRecord.Raw[MPX2], DataRecord.Raw[MPX4] ); break; } /* End of Switch */ } /* End of While */ fprintf( OutputStream, "%s\n%s\n\n", Head2, Head1 ); return( GOOD ); } /******************************************************************** * Function Name: dcwUnpack * Author : Grigoriy Ushomirskiy * Date : August 25, 1992 * Function : Change Raw numbers into data. *********************************************************************/ short dcwUnpack( DATA_RECORD *DataRecord, short DataType ) { dcwSwapBytes( (char *) &(DataRecord->SecMonth), FOUR_BYTES ); dcwSwapBytes( (char *) &(DataRecord->FlagWord), FOUR_BYTES ); switch( DataType ){ case MAG: dcwSwapBytes( (char *) &(DataRecord->Raw[HP]), TWO_BYTES ); dcwSwapBytes( (char *) &(DataRecord->Raw[HE]), TWO_BYTES ); dcwSwapBytes( (char *) &(DataRecord->Raw[HN]), TWO_BYTES ); DataRecord->Data[HP] = h_float( DataRecord->Raw[HP] ); DataRecord->Data[HE] = h_float( DataRecord->Raw[HE] ); DataRecord->Data[HN] = h_float( DataRecord->Raw[HN] ); break; case XRAY: dcwSwapBytes( (char *) &(DataRecord->Raw[XS]), TWO_BYTES ); dcwSwapBytes( (char *) &(DataRecord->Raw[XL]), TWO_BYTES ); DataRecord->Data[XS] = x_float( DataRecord->Raw[XS] ); DataRecord->Data[XL] = x_float( DataRecord->Raw[XL] ); break; case PART: dcwSwapBytes( (char *) &(DataRecord->Raw[MPX2]), TWO_BYTES ); dcwSwapBytes( (char *) &(DataRecord->Raw[MPX4]), TWO_BYTES ); dcwSwapBytes( (char *) &(DataRecord->Raw[MPX8]), TWO_BYTES ); DataRecord->Data[MPX2] = p_float( DataRecord->Raw[MPX2] ); DataRecord->Data[MPX4] = p_float( DataRecord->Raw[MPX4] ); DataRecord->Data[MPX8] = p_float( DataRecord->Raw[MPX8] ); break; case HEPAD: dcwSwapBytes( (char *) &(DataRecord->Raw[MPX2]), TWO_BYTES ); dcwSwapBytes( (char *) &(DataRecord->Raw[MPX4]), TWO_BYTES ); DataRecord->Data[MPX2] = p_float( DataRecord->Raw[MPX2] ); DataRecord->Data[MPX4] = p_float( DataRecord->Raw[MPX4] ); break; default: return( BAD ); } return( GOOD ); } /******************************************************************** * Function Name: dcwSwapBytes * Author : Dan Wilkinson & Grigoriy Ushomirskiy * Date : August 24, 1992 * Function : Swap byte order of a 16-bit or 32-bit integer. *********************************************************************/ short dcwSwapBytes( char *in, short Bytes ) { char c; #ifdef SWAPBYTES switch( Bytes ){ case TWO_BYTES: c=*in; *in=*(in+1); *(in+1)=c; return( GOOD); case FOUR_BYTES: c=*in; *in=*(in+3); *(in+3)=c; c=*(in+1); *(in+1)=*(in+2); *(in+2)=c; return( GOOD ); } return( BAD ); #else return( GOOD ); #endif } /******************************************************************** * Function Name: dcwCreateIndex * Author : Dan Wilkinson * Date : August 24, 1992 * Function : Create an array of offset vs. time for indexed searches *********************************************************************/ short dcwCreateIndex( FILE *InputStream, long DataIndex[MAX_ROW][MAX_COL], short IndexSize ) { long DataOffsetTop, DataOffsetBottom, BottomTime; long IndexSpanRecords, IndexSpanBytes; short Index; if( IndexSize > MAX_ROW ){ printf( "Index size cannot exceed %hd! Function aborted.\n", MAX_ROW ); return( BAD ); } /***** Locate Data TOP *****/ RC = dcwSeek( InputStream, DATA_TOP ); if( RC == BAD ){ printf( "dcwCreateIndex(): Seek failed! Aborting this function.\n" ); return( BAD ); } DataOffsetTop = ftell( InputStream ); /***** Locate Data BOTTOM *****/ RC = dcwSeek( InputStream, DATA_TOP ); if( RC == BAD ){ printf( "dcwCopyData(): Seek failed! Aborting this function.\n" ); return( BAD ); } /***** Seek to last data record. *****/ RC = fseek( InputStream, BasicHeader.NAXIS1*(BasicHeader.NAXIS2-1), SEEK_CUR ); DataOffsetBottom = ftell( InputStream ); RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); dcwSwapBytes( (char *) &(DataRecord.SecMonth), FOUR_BYTES ); BottomTime = DataRecord.SecMonth; #ifdef DEBUG fprintf( DebugStream, "dcwCreateIndex(): DataRecord.Secmonth=%ld, DataOffsetBottom=%ld\n", DataRecord.SecMonth, DataOffsetBottom ); #endif IndexSpanRecords = BasicHeader.NAXIS2 / ( IndexSize-1 ); IndexSpanBytes = IndexSpanRecords * BasicHeader.NAXIS1; #ifdef DEBUG fprintf( DebugStream, "\ndcwCreateIndex()\n" "IndexSize : %hd\n" "DataOffsetTop : %ld\n" "DataOffsetBottom: %ld\n" "DataRecords : %ld\n" "IndexSpanRecords: %ld\n" "IndexSpanBytes : %ld\n", IndexSize, DataOffsetTop, DataOffsetBottom, BasicHeader.NAXIS2, IndexSpanRecords, IndexSpanBytes ); #endif /***** Go to TOP again And print the entire index with *****/ RC = fseek( InputStream, DataOffsetTop, SEEK_SET ); for( Index=0; Index < (IndexSize-1); ++Index ){ if( Index !=0 ){ RC = fseek( InputStream, IndexSpanBytes, SEEK_CUR ); } RC = fread( &DataRecord, 1, (short)BasicHeader.NAXIS1, InputStream ); RC = fseek( InputStream, -BasicHeader.NAXIS1, SEEK_CUR ); DataIndex[Index][TIME] = DataRecord.SecMonth; DataIndex[Index][OFFSET] = ftell( InputStream ); dcwSwapBytes( (char *) &DataIndex[Index][TIME], FOUR_BYTES ); #ifdef DEBUG fprintf( DebugStream, "DataIndex[%3hd][OFFSET] : %8ld " "DataIndex[%3hd][TIME]: %8ld\n", Index, DataIndex[Index][OFFSET], Index, DataIndex[Index][TIME] ); #endif }; DataIndex[IndexSize-1][TIME] = BottomTime; DataIndex[IndexSize-1][OFFSET] = DataOffsetBottom; #ifdef DEBUG fprintf( DebugStream, "DataIndex[%3hd][OFFSET] : %8ld " "DataIndex[%3hd][TIME]: %8ld\n", IndexSize-1, DataIndex[IndexSize-1][OFFSET], IndexSize-1, DataIndex[IndexSize-1][TIME] ); #endif return( GOOD ); } /******************************************************************** * Function Name: dcwParseType * Author : Dan Wilkinson * Date : August 25, 1992 * Function : Determine the data type from the header structure. *********************************************************************/ short dcwParseType( BASIC_HEADER BasicHeader, short *DataType ) { if( BasicHeader.INSTRUME[0] == 'M' ){ *DataType = MAG; #ifdef DEBUG fprintf( DebugStream, "dcwParseType(): Type is MAG = %hd\n", *DataType ); #endif return( GOOD ); } if( BasicHeader.INSTRUME[0] == 'X' ){ *DataType = XRAY; #ifdef DEBUG fprintf( DebugStream, "dcwParseType(): Type is XRAY = %hd\n", *DataType ); #endif return( GOOD ); } if( BasicHeader.INSTRUME[0] == 'P' ){ *DataType = PART; #ifdef DEBUG fprintf( DebugStream, "dcwParseType(): Type is PART = %hd\n", *DataType ); #endif return( GOOD ); } if( BasicHeader.INSTRUME[0] == 'H' ){ *DataType = HEPAD; #ifdef DEBUG fprintf( DebugStream, "dcwParseType(): Type is HEPAD = %hd\n", *DataType ); #endif return( GOOD ); } DataType = BAD; return( BAD ); } /******************************************************************** * Function Name: dcwParseDate * Author : Dan Wilkinson * Date : August 20, 1992 * Function : Decode the DATE key words. *********************************************************************/ short dcwParseDate( BASIC_HEADER BasicHeader, DATE *Creation, DATE *Observation ) { sscanf( BasicHeader.DATE, "%2hd/%2hd/%2hd", &Creation->Day, &Creation->Month, &Creation->Year ); #ifdef DEBUG fprintf( DebugStream, "dcwParseDate(): Creation Date dd/mm/yy %2hd/%2hd/%2hd\n", Creation->Day, Creation->Month, Creation->Year ); #endif sscanf( BasicHeader.DATEOBS, "%2hd/%2hd/%2hd", &Observation->Day, &Observation->Month, &Observation->Year ); #ifdef DEBUG fprintf( DebugStream, "dcwParseDate(): Observation Date dd/mm/yy %2hd/%2hd/%2hd\n", Observation->Day, Observation->Month, Observation->Year ); #endif return( GOOD ); } /******************************************************************** * Function Name: dcwParseHeader * Author : Dan Wilkinson * Date : August 20, 1992 * Function : Decode key word values in header. *********************************************************************/ short dcwParseHeader( FILE *InputStream, BASIC_HEADER *BasicHeader, short Boundary ) { char KeyString[20]; short i; RC = dcwSeek( InputStream, EXTEND_HEADER ); if( RC == BAD ){ printf( "dcwParseHeader(): Seek failed! Aborting this function.\n" ); return( BAD ); } RC = dcwGetKeyWord( InputStream, "XTENSION", BasicHeader->XTENSION, TYPE_STRING, Boundary ); RC = dcwGetKeyWord( InputStream, "BITPIX", &BasicHeader->BITPIX, TYPE_SHORT, Boundary ); RC = dcwGetKeyWord( InputStream, "NAXIS ", &BasicHeader->NAXIS, TYPE_SHORT, Boundary ); RC = dcwGetKeyWord( InputStream, "NAXIS1", &BasicHeader->NAXIS1, TYPE_LONG, Boundary ); RC = dcwGetKeyWord( InputStream, "NAXIS2", &BasicHeader->NAXIS2, TYPE_LONG, Boundary ); RC = dcwGetKeyWord( InputStream, "PCOUNT", &BasicHeader->PCOUNT, TYPE_SHORT, Boundary ); RC = dcwGetKeyWord( InputStream, "GCOUNT", &BasicHeader->GCOUNT, TYPE_SHORT, Boundary ); RC = dcwGetKeyWord( InputStream, "OBSERVER", BasicHeader->OBSERVER, TYPE_STRING, Boundary ); RC = dcwGetKeyWord( InputStream, "INSTRUME", BasicHeader->INSTRUME, TYPE_STRING, Boundary ); RC = dcwGetKeyWord( InputStream, "DATE ", BasicHeader->DATE, TYPE_STRING, Boundary ); RC = dcwGetKeyWord( InputStream, "DATE-OBS", BasicHeader->DATEOBS, TYPE_STRING, Boundary ); RC = dcwGetKeyWord( InputStream, "TFIELDS", &BasicHeader->TFIELDS, TYPE_SHORT, Boundary ); RC = dcwGetKeyWord( InputStream, "EXTVER", &BasicHeader->EXTVER, TYPE_SHORT, Boundary ); RC = dcwGetKeyWord( InputStream, "AUTHOR", BasicHeader->AUTHOR, TYPE_STRING, Boundary ); for( i=1; i<=5; ++i ){ sprintf( KeyString, "TFORM%hd", i ); RC = dcwGetKeyWord( InputStream, KeyString, &BasicHeader->TFORM[i], TYPE_CHAR, Boundary ); } for( i=1; i<=5; ++i ){ sprintf( KeyString, "TTYPE%hd", i ); RC = dcwGetKeyWord( InputStream, KeyString, &BasicHeader->TTYPE[i], TYPE_STRING, Boundary ); } for( i=1; i<=5; ++i ){ sprintf( KeyString, "TNULL%hd", i ); RC = dcwGetKeyWord( InputStream, KeyString, &BasicHeader->TNULL[i], TYPE_LONG, Boundary ); } for( i=1; i<=5; ++i ){ sprintf( KeyString, "SUBZERO%hd", i ); RC = dcwGetKeyWord( InputStream, KeyString, &BasicHeader->SUBZERO[i], TYPE_LONG, Boundary ); } for( i=1; i<=31; ++i ){ sprintf( KeyString, "LONG%2.2hd", i ); RC = dcwGetKeyWord( InputStream, KeyString, &BasicHeader->LONG[i], TYPE_FLOAT, Boundary ); } return( GOOD ); } /******************************************************************** * Function Name: dcwParseTZERO * Author : Dan Wilkinson * Date : August 20, 1992 * Function : Decode key word values in header. * This time read TZEROn into SUBZEROn from version 1 *********************************************************************/ short dcwParseTZERO( FILE *InputStream, BASIC_HEADER *BasicHeader, short Boundary ) { char KeyString[20]; short i; RC = dcwSeek( InputStream, EXTEND_HEADER ); if( RC == BAD ){ printf( "dcwParseHeader(): Seek failed! Aborting this function.\n" ); return( BAD ); } for( i=1; i<=5; ++i ){ sprintf( KeyString, "TZERO%hd", i ); RC = dcwGetKeyWord( InputStream, KeyString, &BasicHeader->SUBZERO[i], TYPE_LONG, Boundary ); } return( GOOD ); } /******************************************************************** * Function Name: dcwSetNAXIS2 * Author : Dan Wilkinson * Date : November 12, 1993 * Function : Set the NAXIS2 value in version 1 tables. *********************************************************************/ short dcwSetNAXIS2( FILE *InputStream, BASIC_HEADER *BasicHeader ) { long RecordCount=0; long DataOffsetTop, DataOffsetBottom; /***** Locate Data TOP *****/ RC = dcwSeek( InputStream, DATA_TOP ); if( RC == BAD ){ printf( "dcwSetNAXIS2(): Seek failed! Aborting this function.\n" ); return( BAD ); } DataOffsetTop = ftell( InputStream ); /***** Locate Data BOTTOM *****/ RC = dcwSeek( InputStream, DATA_BOTTOM ); if( RC == BAD ){ printf( "dcwSetNAXIS2(): Seek failed! Aborting this function.\n" ); return( BAD ); } /***** Read backwards to find non-zero data *****/ while( DataRecord.SecMonth == 0L ){ RC = fseek( InputStream, -BasicHeader->NAXIS1, SEEK_CUR ); RC = fread( &DataRecord, 1, (short)BasicHeader->NAXIS1, InputStream ); RC = fseek( InputStream, -BasicHeader->NAXIS1, SEEK_CUR ); } DataOffsetBottom = ftell( InputStream ); RecordCount = ( DataOffsetBottom - DataOffsetTop ) / (long)BasicHeader->NAXIS1; ++RecordCount; BasicHeader->NAXIS2 = RecordCount; #ifdef DEBUG printf( "dcwSetNAXIS2(): Top= %ld Bottom= %ld\n", DataOffsetTop, DataOffsetBottom ); printf( "dcwSetNAXIS2(): RecordCount= %ld BasicHeader->NAXIS2= %ld \n", RecordCount, BasicHeader->NAXIS2 ); #endif return( GOOD ); } /******************************************************************** * Function Name: dcwGetKeyWord * Author : Dan Wilkinson * Date : August 20, 1992 * Function : Get a key value using a void pointer. *********************************************************************/ short dcwGetKeyWord( FILE *InputStream, char *KeyWord, void *KeyValue, short DataType, short Boundary ) { /***** Locate Header *****/ RC = dcwSeek( InputStream, Boundary ); if( RC == BAD ){ printf( "dcwGetKeyWord(): Seek failed! Aborting this function.\n" ); return( BAD ); } /***** Read to 'END' of the Header *****/ do { RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( RC != HEADER_RECORD ){ printf( "dcwCopyHeader(): Error Reading To End of Header\n" ); return( BAD ); } if( strncmp( HeaderRecord, KeyWord, strlen(KeyWord) ) == 0 ){ switch(DataType){ case TYPE_SHORT: sscanf( HeaderRecord+11, " %hd", (short *)KeyValue ); #ifdef DEBUG fprintf( DebugStream, "dcwGetKeyWord(): KeyWord: %s, KeyValue: %hd\nRecord: %80.80s\n\n", KeyWord, *(short *)KeyValue, HeaderRecord ); #endif break; case TYPE_LONG: sscanf( HeaderRecord+11, " %ld", (long *)KeyValue ); #ifdef DEBUG fprintf( DebugStream, "dcwGetKeyWord(): KeyWord: %s, KeyValue: %ld\nRecord: %80.80s\n\n", KeyWord, *(long *)KeyValue, HeaderRecord ); #endif break; case TYPE_CHAR: sscanf( HeaderRecord+11, "%c", (char *)KeyValue ); #ifdef DEBUG fprintf( DebugStream, "dcwGetKeyWord(): KeyWord: %s, KeyValue: %c\nRecord: %80.80s\n\n", KeyWord, *(char *)KeyValue, HeaderRecord ); #endif break; case TYPE_FLOAT: sscanf( HeaderRecord+11, " %f", (float *)KeyValue ); #ifdef DEBUG fprintf( DebugStream, "dcwGetKeyWord(): KeyWord: %s, KeyValue: %f\nRecord: %80.80s\n\n", KeyWord, *(float *)KeyValue, HeaderRecord ); #endif break; case TYPE_STRING: sscanf( HeaderRecord+11, "%[^']", (char *)KeyValue ); #ifdef DEBUG fprintf( DebugStream, "dcwGetKeyWord(): KeyWord: %s, KeyValue: %s\nRecord: %80.80s\n\n", KeyWord, (char *)KeyValue, HeaderRecord ); #endif break; } } } while( strncmp( HeaderRecord, "END", 3 ) != 0 ); return( BAD ); } /******************************************************************** * Function Name: dcwShowHeader * Author : Dan Wilkinson * Date : August 20, 1992 * Function : Show a header on screen. *********************************************************************/ short dcwShowHeader( FILE *InputStream, short LinesPerScreen, short Boundary ) { short i=0; /***** Locate Header *****/ RC = dcwSeek( InputStream, Boundary ); if( RC == BAD ){ printf( "dcwShowHeader(): Seek failed! Aborting this function.\n" ); return( BAD ); } /***** Read first LinesPerScreen header records *****/ for( i=1; i<=LinesPerScreen; ++i ) { RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( RC != HEADER_RECORD ){ printf( "dcwCopyHeader(): Error Reading To End of Header\n" ); return( BAD ); } printf( "%79.79s\n", HeaderRecord ); } printf( "\n" ); return( GOOD ); } /******************************************************************** * Function Name: dcwCopyHeader * Author : Dan Wilkinson * Date : August 20, 1992 * Function : Copy a header to file. *********************************************************************/ short dcwCopyHeader( FILE *InputStream, FILE *OutputStream, short Boundary ) { short RecordCount=0, i=0; long FileOffset, DeltaOffset; /***** Locate Header *****/ RC = dcwSeek( InputStream, Boundary ); if( RC == BAD ){ printf( "dcwCopyHeader(): Seek failed! Aborting this function.\n" ); return( BAD ); } /***** Copy to 'END' of the Header *****/ while( strncmp( HeaderRecord, "END", 3 ) != 0 ){ RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( RC != HEADER_RECORD ){ printf( "dcwCopyHeader(): Error Reading To End of Header\n" ); return( BAD ); } fprintf( OutputStream, "%3hd:%80.80s:\n", ++RecordCount, HeaderRecord ); } /***** Determine the blank line count and write blanks to file *****/ FileOffset = ftell( InputStream ); RC = dcwSeekBlockEnd( InputStream ); DeltaOffset = ftell( InputStream ) - FileOffset; memset( HeaderRecord, ' ', HEADER_RECORD ); for( i=0; i < (short)DeltaOffset/HEADER_RECORD; ++i ){ fprintf( OutputStream, "%3hd:%80.80s:\n", ++RecordCount, HeaderRecord ); } return( GOOD ); } /******************************************************************** * Function Name: dcwOpenFiles * Author : Dan Wilkinson * Date : August 19, 1992 * Function : Open input and output files. * The user can pass the file names via command line * parameters. Otherwise the program will prompt for * the names. *********************************************************************/ short dcwOpenFiles( short argc, char **argv, FILE **InputStream, FILE **OutputStream ) { if( argc >= 2 ){ /***** parameter 2 will be input file name *****/ sprintf( InFile, "%s", *(argv+1) ); /***** parameter 3 will be drive letter, i.e., A: *****/ if( argc == 3 ){ sprintf( OutFile, "%s", *(argv+2) ); } printf("\nInput file Name : %s\n" "Output file Name : %s\n\n", InFile, OutFile ); *InputStream = fopen( InFile,"rb"); if( *InputStream == NULL ) { printf("\n***** Error Opening Input.\n"); return( BAD ); } *OutputStream = fopen( OutFile,"wt"); if( *OutputStream == NULL ) { printf("\n***** Error Opening Output.\n"); return( BAD ); } } else{ /* Talk to the user about the data being converted */ printf("\nEnter the input file name : " ); gets( InFile ); *InputStream = fopen( InFile,"rb"); if( *InputStream == NULL ) { printf("*** Error Opening Input\n"); return( BAD ); } printf("Enter the output file name: " ); gets( OutFile ); *OutputStream = fopen(OutFile,"wt"); if( *OutputStream == NULL ) { printf("*** Error Opening Output\n"); return( BAD ); } } #ifdef DEBUG_OPEN DebugStream = fopen( DebugFile, "wt" ); #endif return( GOOD ); } /******************************************************************** * Function Name: dcwSeek * Author : Dan Wilkinson * Date : August 19, 1992 * Function : Seek a header or data boundary. *********************************************************************/ short dcwSeek( FILE *InputStream, short Boundary ) { /***** Find First Record of Standard Header. *****/ RC = fseek( InputStream, 0L, SEEK_SET ); RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( strncmp( HeaderRecord, "SIMPLE ", 8 ) != 0 ){ printf( "dcwSEEK(): First Keyword in Standard Header Is Not 'SIMPLE'!\n"); return( BAD ); } if( Boundary == PRIMARY_HEADER ){ RC = fseek( InputStream, -HEADER_RECORD, SEEK_CUR ); return( GOOD ); } /***** Find the 'END' of the Standard Header *****/ while( strncmp( HeaderRecord, "END", 3 ) != 0 ){ RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( RC != HEADER_RECORD ){ printf( "dcwSEEK(): Error Reading To End of Standard Header\n" ); return( BAD ); } } RC = dcwSeekBlockEnd( InputStream ); RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( strncmp( HeaderRecord, "XTENSION", 8 ) != 0 ){ printf( "dcwSEEK(): First Keyword in Extend Header Is Not 'XTENSION'!\n"); return( BAD ); } if( Boundary == EXTEND_HEADER ){ RC = fseek( InputStream, -HEADER_RECORD, SEEK_CUR ); return( GOOD ); } /***** Find the 'END' of the Extend Header *****/ while( strncmp( HeaderRecord, "END", 3 ) != 0 ){ RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( RC != HEADER_RECORD ){ printf( "dcwSEEK(): Error Reading To End of Extend Header\n" ); return( BAD ); } } RC = dcwSeekBlockEnd( InputStream ); /***** version .003 modification: The pointer should be at DATA_TOP, however, in cases where excess blank header records have been padded to a header it will be necessary to look for non blank data. *****/ RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); while( strncmp( HeaderRecord, " ", 8 ) == 0 ) { fprintf( OutputStream, " Error, Header too long ... Blank header record found instead of data.\n" ); RC = fread ( HeaderRecord, 1, HEADER_RECORD, InputStream ); if( RC != HEADER_RECORD ){ printf( "dcwSEEK(): Error Reading To Start of Data\n" ); return( BAD ); } } /***** Backup one header record *****/ RC = fseek( InputStream, -HEADER_RECORD, SEEK_CUR ); /***** End of version .003 modification *****/ if( Boundary == DATA_TOP ){ return( GOOD ); } RC = fseek( InputStream, 0L, SEEK_END ); if( Boundary == DATA_BOTTOM ){ return( GOOD ); } return( BAD ); } /******************************************************************** * Function Name: dcwSeekBlockEnd * Author : Dan Wilkinson * Date : August 19, 1992 * Function : Seek next 2880 byte boundary. *********************************************************************/ short dcwSeekBlockEnd( FILE *InputStream ) { long FileOffset, DeltaOffset; /***** Locate the next logical record boundary. *****/ FileOffset = ftell( InputStream ); if( FileOffset%(long)HEADER_BLOCK != 0 ){ DeltaOffset = (long)HEADER_BLOCK - ( FileOffset%(long)HEADER_BLOCK ); } else{ DeltaOffset = 0L; } /***** Position at the boundary. *****/ if( DeltaOffset > 0 ){ RC = fseek( InputStream, DeltaOffset, SEEK_CUR ); if( RC != 0 ){ printf( "dcwSeekBlockEnd(): fseek() failed!" ); return( BAD ); } } return( GOOD ); } /******************************************************************** * Function Name: x_float * * Author : Dan Wilkinson * * Date : December 7, 1990 * Function : Uncompress a x-ray word. * *********************************************************************/ float x_float ( int x_flux ) { if ( x_flux == (int) BasicHeader.TNULL[3] ) return ( (float) BasicHeader.TNULL[3] ); if ( x_flux == (int) BasicHeader.SUBZERO[3] ) return ( (float)0.0 ); return ( (float) pow ( (double) 10, (double) x_flux / 1000 ) ); } /******************************************************************** * Function Name: h_float * * Author : Dan Wilkinson * * Date : December 7, 1990 * Function : Uncompress a magnetometer word. * *********************************************************************/ float h_float ( int h_flux ) { if ( h_flux == (int) BasicHeader.TNULL[3] ) return ( (float) BasicHeader.TNULL[3] ); if ( h_flux == (int) BasicHeader.SUBZERO[3] ) return ( (float) 0.0 ); return ( (float) ( (float) h_flux / (float)10.0 ) ); } /******************************************************************** * Function Name: p_float * * Author : Dan Wilkinson * * Date : December 7, 1990 * Function : Uncompress a particle word. * *********************************************************************/ float p_float ( int p_flux ) { if ( p_flux == (int) BasicHeader.TNULL[3] ) return ( (float) BasicHeader.TNULL[3] ); if ( p_flux == (int) BasicHeader.SUBZERO[3] ) return ( (float)0.0 ); return ( (float) pow ( (double) 10, (double) p_flux / 1000 ) ); }