Hex dump: Difference between revisions
Content added Content deleted
m (→{{header|Julia}}: add final count) |
(Added C solution) |
||
Line 64: | Line 64: | ||
Other hexdump/xxd features and a command line interface to your program are optional. |
Other hexdump/xxd features and a command line interface to your program are optional. |
||
=={{header|C}}== |
|||
<syntaxhighlight lang="c">#include <ctype.h> |
|||
#include <errno.h> |
|||
#include <limits.h> |
|||
#include <stdbool.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#define BYTES_HEX 16 |
|||
#define BYTES_BIN 6 |
|||
static void print_hex(const char* data, long count) { |
|||
long i = 0; |
|||
for (; i < count; ++i) { |
|||
if (i % 8 == 0) |
|||
putchar(' '); |
|||
printf(" %02x", (unsigned char)data[i]); |
|||
} |
|||
for (; i < BYTES_HEX; ++i) { |
|||
if (i % 8 == 0) |
|||
putchar(' '); |
|||
printf(" "); |
|||
} |
|||
} |
|||
static void print_binary(const char* data, long count) { |
|||
long i = 0; |
|||
putchar(' '); |
|||
for (; i < count; ++i) { |
|||
unsigned char c = data[i]; |
|||
putchar(' '); |
|||
for (unsigned char m = 1 << 7; m != 0; m >>= 1) |
|||
putchar((c & m) ? '1' : '0'); |
|||
} |
|||
for (; i < BYTES_BIN; ++i) |
|||
printf(" "); |
|||
} |
|||
static void print_chars(const char* data, long count) { |
|||
for (long i = 0; i < count; ++i) { |
|||
unsigned char c = data[i]; |
|||
putchar(isprint(c) ? c : '.'); |
|||
} |
|||
} |
|||
static bool string_to_long(const char* str, long* value) { |
|||
char* eptr; |
|||
long result = strtol(str, &eptr, 0); |
|||
if (errno || *eptr || result < 0) |
|||
return false; |
|||
*value = result; |
|||
return true; |
|||
} |
|||
static void usage(const char* program) { |
|||
fprintf(stderr, "usage: %s [-b] [-s skip] [-n length] filename\n", program); |
|||
} |
|||
int main(int argc, char** argv) { |
|||
long offset = 0; |
|||
long max_length = LONG_MAX; |
|||
bool binary = false; |
|||
int i = 1; |
|||
for (; i < argc && argv[i][0] == '-'; ++i) { |
|||
switch (argv[i][1]) { |
|||
case 's': |
|||
if (++i == argc) { |
|||
usage(argv[0]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
if (!string_to_long(argv[i], &offset)) { |
|||
fprintf(stderr, "Invalid skip '%s'.\n", argv[i]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
break; |
|||
case 'n': |
|||
if (++i == argc) { |
|||
usage(argv[0]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
if (!string_to_long(argv[i], &max_length)) { |
|||
fprintf(stderr, "Invalid length '%s'.\n", argv[i]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
break; |
|||
case 'b': |
|||
binary = true; |
|||
break; |
|||
default: |
|||
usage(argv[0]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
} |
|||
if (i + 1 != argc) { |
|||
usage(argv[0]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
FILE* fp = fopen(argv[i], "rb"); |
|||
if (!fp) { |
|||
perror(argv[i]); |
|||
return EXIT_FAILURE; |
|||
} |
|||
if (fseek(fp, 0, SEEK_END)) { |
|||
perror("fseek"); |
|||
fclose(fp); |
|||
return EXIT_FAILURE; |
|||
} |
|||
long max_offset = ftell(fp); |
|||
if (offset > max_offset) |
|||
offset = max_offset; |
|||
if (fseek(fp, offset, SEEK_SET)) { |
|||
perror("fseek"); |
|||
fclose(fp); |
|||
return EXIT_FAILURE; |
|||
} |
|||
char data[BYTES_HEX]; |
|||
const long max_count = binary ? BYTES_BIN : BYTES_HEX; |
|||
for (long length = 0; length <= max_length;) { |
|||
printf("%08lx", offset); |
|||
long count = fread(data, 1, max_count, fp); |
|||
if (count > max_length - length) |
|||
count = max_length - length; |
|||
if (count == 0) { |
|||
putchar('\n'); |
|||
break; |
|||
} |
|||
if (binary) |
|||
print_binary(data, count); |
|||
else |
|||
print_hex(data, count); |
|||
printf(" |"); |
|||
print_chars(data, count); |
|||
printf("|\n"); |
|||
offset += count; |
|||
length += count; |
|||
} |
|||
fclose(fp); |
|||
return EXIT_SUCCESS; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
Hexadecimal output: |
|||
<pre> |
|||
00000000 ff fe 52 00 6f 00 73 00 65 00 74 00 74 00 61 00 |..R.o.s.e.t.t.a.| |
|||
00000010 20 00 43 00 6f 00 64 00 65 00 20 00 69 00 73 00 | .C.o.d.e. .i.s.| |
|||
00000020 20 00 61 00 20 00 70 00 72 00 6f 00 67 00 72 00 | .a. .p.r.o.g.r.| |
|||
00000030 61 00 6d 00 6d 00 69 00 6e 00 67 00 20 00 63 00 |a.m.m.i.n.g. .c.| |
|||
00000040 68 00 72 00 65 00 73 00 74 00 6f 00 6d 00 61 00 |h.r.e.s.t.o.m.a.| |
|||
00000050 74 00 68 00 79 00 20 00 73 00 69 00 74 00 65 00 |t.h.y. .s.i.t.e.| |
|||
00000060 20 00 3d d8 00 de 2e 00 | .=.....| |
|||
00000068 |
|||
</pre> |
|||
Binary output: |
|||
<pre> |
|||
00000000 11111111 11111110 01010010 00000000 01101111 00000000 |..R.o.| |
|||
00000006 01110011 00000000 01100101 00000000 01110100 00000000 |s.e.t.| |
|||
0000000c 01110100 00000000 01100001 00000000 00100000 00000000 |t.a. .| |
|||
00000012 01000011 00000000 01101111 00000000 01100100 00000000 |C.o.d.| |
|||
00000018 01100101 00000000 00100000 00000000 01101001 00000000 |e. .i.| |
|||
0000001e 01110011 00000000 00100000 00000000 01100001 00000000 |s. .a.| |
|||
00000024 00100000 00000000 01110000 00000000 01110010 00000000 | .p.r.| |
|||
0000002a 01101111 00000000 01100111 00000000 01110010 00000000 |o.g.r.| |
|||
00000030 01100001 00000000 01101101 00000000 01101101 00000000 |a.m.m.| |
|||
00000036 01101001 00000000 01101110 00000000 01100111 00000000 |i.n.g.| |
|||
0000003c 00100000 00000000 01100011 00000000 01101000 00000000 | .c.h.| |
|||
00000042 01110010 00000000 01100101 00000000 01110011 00000000 |r.e.s.| |
|||
00000048 01110100 00000000 01101111 00000000 01101101 00000000 |t.o.m.| |
|||
0000004e 01100001 00000000 01110100 00000000 01101000 00000000 |a.t.h.| |
|||
00000054 01111001 00000000 00100000 00000000 01110011 00000000 |y. .s.| |
|||
0000005a 01101001 00000000 01110100 00000000 01100101 00000000 |i.t.e.| |
|||
00000060 00100000 00000000 00111101 11011000 00000000 11011110 | .=...| |
|||
00000066 00101110 00000000 |..| |
|||
00000068 |
|||
</pre> |
|||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |