#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define BUFLEN 16384
char buf[BUFLEN+2];
char rcl[4];
char rc2[4];

unsigned long packit( char x[4] ) {
        return (x[0] & 0x00ff) | 
            ((x[1] << 8) & 0xff00) |
            ((x[2] << 16) & 0xff0000) |
            ((x[3] << 24) & 0xff000000);
}

int read_record( char buf[], unsigned int buf_size, FILE *fd ) {
    int n;
    char tbuf1[4];
    char tbuf2[4];
    int reclen1;
    int reclen2;

    n = fread( tbuf1, sizeof(char), 4, fd );
    if( n == 0 ) {
        return -1;
    }
    if( n < 4 ) {
        fprintf( stderr, "Bad read length %d\n", n );
        exit(1);
    }
    reclen1 = packit( tbuf1 );
    if( reclen1 == 0 ) {
        return 0;
    }
    if( reclen1 > buf_size) {
        fprintf( stderr, "ERROR: tape record too big: %d   max is %s\n",
                 reclen1, buf_size );
        exit(1);
    }
    n = fread( buf, sizeof(char), reclen1, fd );
    if( n != reclen1 ) {
        fprintf( stderr, "ERROR: short read\n" );
        exit(1);
    }
    /*
    ** check end count
    */
    n = fread( tbuf2, sizeof(char), 4, fd );
    if( n != 4 ) {
        fprintf( stderr, "ERROR: end length missing\n" );
        exit(1);
    }
    reclen2 = packit( tbuf2 );
    if( reclen1 != reclen2 ) {
        fprintf( stderr, "ERROR: record lengths do not match [%d,%d]\n",
                 reclen1, reclen2 );
        exit(1);
    }
    return reclen1;
}

void dump_buf( char buf[], int buf_len ) {
    int i,j;

    for( i = 0; i < buf_len; i += 16 ) {
        printf( "   " );
        for( j = 0; j < 16; j++ ) {
            if( (i+j) >= buf_len )
                printf( "-- " );
            else
                printf( "%02x ", (buf[i+j] & 0xff) );
        }
        printf( "   [" );
        for( j = 0; j < 16; j++ ) {
            if( (i + j) >= buf_len )
                printf( " " );
            else if( (buf[i+j] < 32) || ((buf[i+j] & 0xff) >= 127) )
                printf( " " );
            else
                printf( "%c", buf[i+j] );
        }
        printf( "]\n" );
    }
}

int main( int argc, char *argv[] ) {
    unsigned int reclen;
    unsigned int reccnt;
    unsigned long byte_cnt;
    FILE *tp;
    
    reccnt = 0;
    byte_cnt = 0;

    if( argc < 2 ) {
        fprintf( stderr, "Usage: dumpit tape\n" );
        exit(1);
    }

    if( (tp = fopen(argv[1],"r")) == NULL ) {
        fprintf( stderr, "FATAL: Can't open %s\n", argv[1] );
        exit(1);
    }

    while( 1 ) {
        reclen = read_record( buf, BUFLEN, tp );
        if( reclen < 0 ) {
            printf( "**** End of Tape\n" );
            break;
        } else if( reclen == 0 ) {
            printf( "**** File Mark\n" );
            continue;
        }
        byte_cnt += reclen;
        reccnt++;
        printf( "**** record %d  size %d  total size %ld\n",
                reccnt+1, reclen, byte_cnt );
        dump_buf( buf, reclen );
    }

    fclose(tp);
    return 0;
}
