/*  Simple file "hexadecimal dump" (hd) program.  Shows printable text also.
**
**  Written 1995/06/07 by Craig Bruce
*/

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

typedef unsigned char uchar;
typedef unsigned long ulong;
typedef int bool;
#define TRUE 1
#define FALSE 0

int     main( int argc, char *argv[] );
void    HexDumpFile( FILE *fin );
void    HexPut( char outline[], int linepos, int hexDigits, ulong value );
int     GetChunk( FILE *fin, uchar buf[], int len );

/****************************************************************************/
int main(int argc, char *argv[])
{
    FILE   *fin, *fout;
    int     ifile;

    if (argc < 2) {
        HexDumpFile( stdin );
    } else {
        for( ifile=1; ifile<argc; ifile++ ) {
            fin = fopen( argv[ifile], "rb" );
            if (fin == NULL) {
                fprintf(stderr, "%s: Error opening file \"%s\".\n", argv[0],
                    argv[ifile]);
                exit( 1 );
            } else {
                HexDumpFile( fin );
                fclose( fin );
            }
        }
    }
    return( 0 );
}

/****************************************************************************/
void HexDumpFile( FILE *fin )
{
    uchar   chunk[16];
    uchar   outline[81];
    uchar   str[20];
    int     bytes, i;
    ulong   filepos;
    int     linepos;
    uchar   c;

    strcpy( outline, "00000000: 00 11 22 33, 44 55 66 77, " );
    strcat( outline, "88 99 aa bb, cc dd ee ff ;0123456789abcdef");
    filepos = 0;

    while( TRUE ) {
        bytes = GetChunk( fin, chunk, 16 );
        if (bytes <= 0) break;
        /* put in address */
        HexPut( outline, 0, 8, filepos );
        /* put in hexadecimal values */
        for (i=0; i<16; i++) {
            linepos = 10 + i*3 + i/4;
            if (i < bytes) {
                HexPut( outline, linepos, 2, chunk[i] );
            } else {
                outline[linepos+0] = ' ';
                outline[linepos+1] = ' ';
                if (i%4 == 0) {
                    outline[linepos-2] = ' ';  /*zap lead comma*/
                }
            }
        }
        /* put in character values */
        for (i=0; i<16; i++) {
            c = chunk[i];
            if ( (c>=0x20 && c<=0x7e) || (c>=0xa0) ) {
                outline[62+i] = c;
            } else {
                outline[62+i] = '.';
            }
        }
        /* remove excess character values */
        outline[62+bytes] = '\0';
        /* print */
        printf("%s\n", outline);
        filepos += bytes;
    }
}

/****************************************************************************/
void HexPut( char outline[], int linepos, int hexDigits, ulong value )
{
    char    str[20];
    char    fmt[20];
    int     i;

    sprintf(fmt, "%%0%dx", hexDigits);
    sprintf(str, fmt, value);
    for (i=0; i<hexDigits; i++) {
        outline[linepos+i] = str[i];
    }
}

/****************************************************************************/
int GetChunk( FILE *fin, uchar buf[], int len )
{
    int     i, c;

    for (i=0; i<len; i++) {
        c = getc(fin);
        if (c==EOF) return( i );
        buf[i] = c;
    }
    return( len );
}
