Dump That File! – Solution

I’ve been coding hexdump utilities since the microcomputer era. They’re just so handy, especially when writing structures or other formatted data to a file. The dump assists with debugging, and it helps you figure out some undocumented data structures as well.

The good news is that most of the standard C library functions can easily lend themselves to writing a hexdump utility, which is the challenge for this month’s Exercise. For my solution, the code works as follows:

1. Check for command line arguments and open the file.

If the argument count is less than two, my code outputs an error message and quits. Otherwise, the command line argument is assumed to be a file and it’s opened for reading.

2. Main loop.

After opening the file, my solution wends its way into a while loop that repeats until the file pointer, fp, returns true for the end-of-file:

while( !feof(fp) )

3. Read a 16-byte chunk from the file.

The hexdump utility consumes file data 16-bytes at a time, so I use the fread() function to pull in a 16-byte chunk:

r = fread(buffer,sizeof(unsigned char),16,fp);
/* break on EOF */
if( r==0 )
    break;

Data read is stored in the unsigned char buffer. It must be unsigned or full hex values (0x80 to 0xff) aren’t read properly.

Variable r holds the number of bytes actually read, which comes into play when outputting the final row. Further, the value of r is tested for zero to catch a condition where the file has been fully read but the EOF isn’t caught in the while loop condition.

4. Generate output for the 16-byte row.

Output happens in three steps.

Variable offset is initialized to zero, then incremented for each iteration of the loop. But first, it’s output:

/* print offset */
printf("%04X ",offset);

In step two, hex values are output:

/* print hex values */
for( x=0; x<r; x++ )
{
    printf(" %02X",buffer[x]);
    if( x==7 )
        printf(" -");
}

See how variable r sets the repeat count for the loop? This is how the final row is set only as long as the number of bytes read from the file.

The if test sets the dash after the 8th hex byte is output.

If the value of variable r is less than 16, meaning the final line of data has been read from the file, a for loop fills the balance of the hex column with whitespace:

/* fill in the rest of a blank row */
if( r<16 )
{
    for( x=r; x<16; x++ )
    {
        printf("   ");
        if( x==7 )
            printf("  ");
    }
}

The third step is to output the ASCII column. An if test in the for loop generates the single dot output for unprintable characters that would otherwise mess up the display:

/* print ASCII */
printf("   ");
for( x=0; x<r; x++)
{
    if( buffer[x]<32 || buffer[x]>126 )
        putchar('.');
    else
        putchar(buffer[x]);
}
putchar('\n');
offset += r;

And, finally, the offset variable is increased by the value of r, as shown in the final statement above.

The loop continues until all bytes are read from the file.

5. Display the byte count total and close the file.

The code wraps up outputting the value of variable offset and closing the open file.

Click here to view the full code for my solution on GitHub. I hope you were able to devise a similar solution; writing the dump part isn’t really that difficult. No, the tough part is coding that final line so that the hex and ASCII columns line up evenly.

Leave a Reply