1/*
2  This file contains a simple hex dump routine.
3
4  THIS CODE COPYRIGHT DOMINIC GIAMPAOLO.  NO WARRANTY IS EXPRESSED
5  OR IMPLIED.  YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
6  NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
7
8  FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
9
10  Dominic Giampaolo
11  dbg@be.com
12*/
13#include <stdio.h>
14#include <ctype.h>
15
16#include "compat.h"
17
18/*
19 * This routine is a simple memory dumper.  It's nice and simple, and works
20 * well.
21 *
22 * The bad things about it are that it assumes roughly an 80 column output
23 * device and that output is fixed at BYTES_PER_LINE/2 columns (separated
24 * every two bytes).
25 *
26 * Obviously the bad things are fixable, but I don't need the extra
27 * flexibility at the moment, so I don't feel like doing it.
28 *
29 *   Dominic Giampaolo
30 *   (dbg@be.com)
31 */
32
33#define BYTES_PER_LINE 16  /* a reasonable power of two */
34
35
36void hexdump(void *address, int size)
37{
38  int i;
39  int offset, num_spaces;
40  unsigned char *mem, *tmp;
41
42
43  offset = 0;
44  mem = (unsigned char *)address;
45
46  /*
47   * Each line contains BYTES_PER_LINE bytes of data (presently 16).  I
48   * chose 16 because it is a nice power of two and makes reading the
49   * hex offset column much easier.  I used to use a value of 18 to fit
50   * more info on the screen, and 20 is also doable but much too crowded.
51   * Ideally it should be an argument or settable parameter...
52   *
53   * The data is formatted into BYTES_PER_LINE/2 (8) columns of 2 bytes
54   * each (printed in hex).
55   *
56   * The offset is formatted as a 4 byte hex number (i.e. 8 characters).
57   */
58  while(offset < size)
59    {
60      printf("%.8x: ", offset);
61
62      for(i=0,tmp=mem; i < BYTES_PER_LINE && (offset+i) < size; i++,tmp++)
63       {
64     printf("%.2x", *tmp);
65     if (((i+1) % 4) == 0)
66       printf(" ");
67       }
68
69      /*
70       * This formula for the number of spaces to print is as follows:
71       *   10 is the number of characters printed at the beginning of
72       *      the line (8 hex digits, the colon and a space).
73       *   i*2 is the number of characters of data we dumped in hex.
74       *   i/2 is the number of blanks we printed between columns.
75       *   i is the number of bytes we will print in ascii.
76       *
77       * Then we subtract all that from 74 (the width of the output
78       * device) to decide how many spaces we need to push the ascii
79       * column as far to the right as possible.
80       *
81       * The number 58 is the column where we start we start printing
82       * the ascii dump.  We subtract how many characters we've already
83       * printed and that gets us to where we need to be to start the
84       * ascii portion of the dump.
85       *
86       */
87      num_spaces = 58 - (12 + i*2 + i/4);
88      for(i=0; i < num_spaces; i++)
89    printf(" ");
90
91      for(i=0,tmp=mem; i < BYTES_PER_LINE && (offset+i) < size; i++, tmp++)
92    if (isprint(*tmp))
93      printf("%c", *tmp);
94    else
95      printf(".");
96
97      printf("\n");
98
99      offset += BYTES_PER_LINE;
100      mem = tmp;
101    }
102}
103
104
105
106#ifdef TEST
107
108
109char buff[] = "!blah, blah blah blah blah asldfj lkasjdf lka lkjasdflasdlj"
110              "asdj lasdfj lasdjf lasdjf lkasjdfl kjasdlf jasldfj lasdfj l"
111              "asdjflkasjdflk;ja sdfljasdfjk asjkfl;kasjfl;asjdfl;azzzzzzz";
112
113main(int argc, char **argv)
114{
115  int i,j,k;
116  FILE *fp;
117
118  hexdump(buff, 171);
119
120  printf("---------\n");
121
122  hexdump(main, 57);
123}
124
125#endif /* TEST */
126