1 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 2 // 3 // Copyright (c) 2001-2003, Haiku 4 // 5 // This software is part of the Haiku distribution and is covered 6 // by the MIT License. 7 // 8 // 9 // File: hd.c 10 // Author: Daniel Reinhold (danielre@users.sf.net) 11 // Description: hex dump utility 12 // 13 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 14 15 #include <OS.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <ctype.h> 20 #include <errno.h> 21 #include <sys/stat.h> 22 23 24 void display (uint32, uint8 *); 25 void do_hd (char *); 26 void dump_file (FILE *); 27 char *hexbytes (uint8 *); 28 char *printable (uint8 *); 29 void usage (void); 30 31 32 static int BytesBetweenSpace = 1; 33 34 35 void 36 usage () 37 { 38 printf ("Usage:\thd [-n N] [file]\n"); 39 printf("\t-n expects a number between 1 and 16 and specifies\n"); 40 printf("\tthe number of bytes between spaces.\n"); 41 printf("\n\tIf no file is specified, input is read from stdin\n"); 42 } 43 44 45 int 46 main(int argc, char *argv[]) 47 { 48 char *arg = NULL; 49 50 if (argc == 1) 51 dump_file(stdin); 52 53 else { 54 char *first = *++argv; 55 56 if (strcmp(first, "--help") == 0) { 57 usage(); 58 return 0; 59 } 60 61 if (strcmp(first, "-n") == 0) { 62 if (--argc > 1) { 63 char *num = *++argv; 64 65 if (!isdigit(*num)) 66 printf("-n option needs a numeric argument\n"); 67 else { 68 int b = atoi(num); 69 70 if (b < 1) b = 1; 71 if (b > 16) b = 16; 72 BytesBetweenSpace = b; 73 74 if (--argc > 1) 75 arg = *++argv; 76 else 77 printf("no file specified\n"); 78 } 79 } 80 else 81 printf("-n option needs a numeric argument\n"); 82 } 83 else 84 arg = first; 85 86 if (arg) 87 do_hd(arg); 88 } 89 90 putchar('\n'); 91 return 0; 92 } 93 94 95 void 96 do_hd(char *fname) 97 { 98 struct stat e; 99 100 if (stat(fname, &e) == -1) { 101 fprintf(stderr, "'%s': no such file or directory\n", fname); 102 return; 103 } 104 105 if (S_ISDIR(e.st_mode)) 106 fprintf(stderr, "'%s' is a directory\n", fname); 107 else { 108 FILE *fp = fopen(fname, "rb"); 109 if (fp) { 110 dump_file(fp); 111 fclose(fp); 112 } 113 else 114 fprintf(stderr, "'%s': %s\n", fname, strerror(errno)); 115 } 116 } 117 118 119 void 120 dump_file(FILE *fp) 121 { 122 size_t got; 123 uint32 offset = 0; 124 uint8 data[16]; 125 126 while ((got = fread(data, 1, 16, fp)) == 16) { 127 display(offset, data); 128 offset += 16; 129 } 130 131 if (got > 0) { 132 memset(data+got, ' ', 16-got); 133 display(offset, data); 134 } 135 } 136 137 138 void 139 display(uint32 offset, uint8 *data) 140 { 141 printf("%08" B_PRIx32 " ", offset); 142 printf(" %s ", hexbytes(data)); 143 printf("%16s ", printable(data)); 144 145 putchar('\n'); 146 } 147 148 149 char * 150 hexbytes(uint8 *s) 151 { 152 static char buf[64]; 153 char *p = buf; 154 uint8 c; 155 int i; 156 int n = 0; 157 158 for (i = 0; i < 16; ++i) { 159 c = *s++; 160 *p++ = "0123456789abcdef"[c/16]; 161 *p++ = "0123456789abcdef"[c%16]; 162 163 if (++n == BytesBetweenSpace) { 164 *p++ = ' '; 165 n = 0; 166 } 167 168 if ((i == 7) && (BytesBetweenSpace == 1)) 169 *p++ = ' '; 170 } 171 *p++ = ' '; 172 *p = 0; 173 174 return buf; 175 } 176 177 178 char * 179 printable (uint8 *s) 180 { 181 static char buf[16]; 182 char *p = buf; 183 uint8 c; 184 int i = 16; 185 186 while (i--) { 187 c = *s++; 188 *p++ = (isgraph(c) ? c : '.'); 189 } 190 *p = 0; 191 192 return buf; 193 } 194