!====================================================================== ! ! Program: UnfSeq (Unformatted Sequential File Converter) ! ! Fortran PowerStation reads and writes unformatted sequential files ! in a particular way, which can be different from unformatted sequential ! files on other platforms. This can cause problems when trying to move ! data files from other platforms to Windows, or vice versa. ! ! This program will help convert these files, from one format to the other. ! ! Usage ! ===== ! From the command line: ! unfseq { -toms | -fromms } [ -bigendian ] source [ destination ] ! where: ! -toms specifies that the source file is to be converted to ! Microsoft unformatted sequential format. ! -fromms specifies that the source file is to be converted from ! Microsoft unformatted sequential format. ! -bigendian The other platform is a bigendian platform. The lengths ! associated with each record will be read/written in ! bigendian form. See the note below about the endian of ! data if you must use this switch. The default is little ! endian. ! source The file to be converted. ! destination If specified, names the file to write the converted file to. ! If not specified, the source file is replaced with ! the converted file. ! ! File Structures ! =============== ! The structure of Fortran PowerStation unformatted sequential files ! is documented in the Programmer's Guide. ! ! The typical structure on other platforms is somewhat simpler: for each ! record, the length of the record appears before and after the record, ! as a 4-byte integer quantity. Note that these lengths can either be in ! little or big endian format (see the -bigendian switch above). ! There is no begin or end bytes, as there is in Fortran PowerStation. ! ! Endian of Data ! ============== ! Note that this program will adjust the structure of the file appropriately, ! but cannot change the data itself. This can cause problems if the source ! platform is big endian and the destination is little endian, since any ! numeric variables will have their bytes reversed in the data file. ! This program can be augmented to properly translate the data, for a ! specific data file format, while it is translating the file structure. ! program UnformattedSequentialConverter use msflib implicit none character*2 ConvertType integer*2 StatusC, StatusS, StatusD character*($MAXPATH) SrcFile, DestFile logical BigEndian integer*4 i4 logical error, ConvertToMS, ConvertFromMS ! Read arguments, display usage information if there is a problem ! call getarg( int2(1), ConvertType, StatusC ) call getarg( int2(2), SrcFile, StatusS ) if( StatusC < 0 .or. StatusS < 0 ) ConvertType = '***' if( (SrcFile(1:1) == '/' .or. SrcFile(1:1) == '-') .and. & (SrcFile(2:2) == 'b' .or. SrcFile(2:2) == 'B') ) then BigEndian = .true. call getarg( int2(3), SrcFile, StatusS ) call getarg( int2(4), DestFile, StatusD ) else BigEndian = .false. call getarg( int2(3), DestFile, StatusD ) endif if( StatusD < 0 ) DestFile = '$$unfseq.tmp' select case( ConvertType ) case( '-t', '-T', '/t', '/T' ) error = .not. ConvertToMS( SrcFile, DestFile, BigEndian ) case( '-f', '-F', '/f', '/F' ) error = .not. ConvertFromMS( SrcFile, DestFile, BigEndian ) case default print *,'usage: unfseq { -toms | -fromms } & &[ -bigendian ] source [ destination ]' error = .true. end select ! If the destination was not specified, replace the source ! if( .not. error .and. StatusD < 0 ) then i4 = DelFilesQQ( SrcFile ) i4 = RenameFileQQ( DestFile, SrcFile ) endif end program !---------------------------------------------------------------------- logical function ConvertFromMS( from, to, bigendian ) implicit none character*(*) from, to logical bigendian character buff1 character*(65536) record integer start, len logical first open( unit=1, file=from, access='sequential', blocksize=65535, & err=10, form='binary', mode='read', status='old' ) open( unit=2, file=to, access='sequential', blocksize=65535, & err=20, form='binary', mode='write', status='new' ) ! Check BOF Flag read( 1, err=10 ) buff1 if( ichar(buff1) /= 75 ) then print *,'ERROR: ',from(:len_trim(from)),& ' is not a Microsoft unformmatted sequential file' ConvertFromMS = .false. return endif ! Read Record, Write to output file do read( 1, err=10 ) buff1; len = ichar(buff1) if( len .eq. 130 ) exit ! EOF Flag = 130 decimal start = 1 first = .true. do while( first .or. (len > 128) ) if( len == 129 ) len = len-1 read( 1, err=10 ) record(start:start+len-1) start = start + len read( 1, err=10 ) buff1; len = ichar(buff1) first = .false. end do if( .not. writelen( len ) ) goto 20 write( 2, err=20 ) record(1:start-1) if( .not. writelen( len ) ) goto 20 end do close( 1, err=10 ) close( 2, err=20 ) ConvertFromMS = .true. return 10 print *,"ERROR: File open or read error on file '",from(:len_trim(from)),"'" ConvertFromMS = .false. return 20 print *,"ERROR: File open or write error on file '",to(:len_trim(to)),"'" ConvertFromMS = .false. return contains logical function writelen( len ) integer(4) len if( bigendian ) then write( 2, err=30 ) int1(ishft(len,-24)), int1(ishft(len,-16)),& int1(ishft(len,-8)), int1(len) else write( 2, err=30 ) len endif writelen = .true. return 30 writelen = .false. return end function writelen end function ConvertFromMS !---------------------------------------------------------------------- logical function ConvertToMS( from, to, bigendian ) character*(*) from, to logical bigendian character*(65536) record integer start, len, len_end open( unit=1, file=from, access='sequential', blocksize=65535, & err=10, form='binary', mode='read', status='old' ) open( unit=2, file=to, access='sequential', blocksize=65535, & err=20, form='binary', mode='write', status='new' ) ! write BOF write( 2, err=20 ) char(75) do while( .not. eof( 1 ) ) if( .not. readlen( len ) ) goto 10 read( 1, err=10 ) record( 1:len ) if( .not. readlen( len_end ) ) goto 10 if( len_end /= len ) then print *,'ERROR: Record start/end length mismatch' ConvertToMS = .false. return endif start = 1 do while( (len-start+1) > 128 ) write( 2, err=20 ) int1( 129 ) write( 2, err=20 ) record( start:start+128 ) write( 2, err=20 ) int1( 129 ) start = start + 128 end do if( (len-start) > 0 ) then write( 2, err=20 ) int1(len-start+1) write( 2, err=20 ) record( start:len ) write( 2, err=20 ) int1(len-start+1) end if end do write( 2, err=20 ) char(130) close( 1, err=10 ) close( 2, err=20 ) ConvertToMS = .true. return 10 print *,"ERROR: File open or read error on file '",from(:len_trim(from)),"'" ConvertToMS = .false. return 20 print *,"ERROR: File open or write error on file '",to(:len_trim(to)),"'" ConvertToMS = .false. return contains logical function readlen( len ) character*4 lench if( bigendian ) then read( 1, err=30 ) lench len = ishft(ichar(lench(1:1)),24) .or. & ishft(ichar(lench(2:2)),16) .or. & ishft(ichar(lench(3:3)),8) .or. ichar(lench(4:4)) else read( 1, err=30 ) len endif readlen = .true. return 30 readlen = .false. return end function readlen end function ConvertToMS !======================================================================