aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/xxd.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2015-07-02 11:44:01 -0500
committerRob Landley <rob@landley.net>2015-07-02 11:44:01 -0500
commit4ab24f2228b5d51491a5ef2a59ebcf424dced6f7 (patch)
tree71a94a81ffc6186687b98b2e66a7acf5af6cdd43 /toys/pending/xxd.c
parent8a2c0876754baa2085bce94d6778b5d2f4aee937 (diff)
downloadtoybox-4ab24f2228b5d51491a5ef2a59ebcf424dced6f7.tar.gz
The android guys sent in xxd. It doesn't share code with od and hexdump. Hmmm...
Diffstat (limited to 'toys/pending/xxd.c')
-rw-r--r--toys/pending/xxd.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/toys/pending/xxd.c b/toys/pending/xxd.c
new file mode 100644
index 00000000..3a84c988
--- /dev/null
+++ b/toys/pending/xxd.c
@@ -0,0 +1,97 @@
+/* xxd.c - hexdump.
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * TODO: support for reversing a hexdump back into the original data.
+ * TODO: support > 4GiB files?
+ * TODO: -s seek
+
+USE_XXD(NEWTOY(xxd, ">1c#l#g#", TOYFLAG_USR|TOYFLAG_BIN))
+
+config XXD
+ bool "xxd"
+ default n
+ help
+ usage: xxd [-c n] [-g n] [-l n] [file]
+
+ Hexdump a file to stdout. If no file is listed, copy from stdin.
+ Filename "-" is a synonym for stdin.
+
+ -c n Show n bytes per line (default 16).
+ -g n Group bytes by adding a ' ' every n bytes (default 2).
+ -l n Limit of n bytes before stopping (default is no limit).
+*/
+
+#define FOR_xxd
+#include "toys.h"
+
+static const char* hex_digits = "0123456789abcdef";
+
+GLOBALS(
+ long bytes_per_group; // -g
+ long limit; // -l
+ long bytes_per_line; // -c
+)
+
+static void xxd_file(FILE *fp)
+{
+ // "0000000: 4c69 6e75 7820 7665 7273 696f 6e20 332e Linux version 3.".
+ size_t hex_size = 8 + 2 +
+ 2*TT.bytes_per_line + TT.bytes_per_line/TT.bytes_per_group + 1;
+ size_t line_size = hex_size + TT.bytes_per_line + 1;
+ char *line = xmalloc(line_size);
+ int offset = 0;
+ int bytes_this_line = 0;
+ int line_index = 0;
+ int ch;
+
+ memset(line, ' ', line_size);
+ line[line_size - 1] = 0;
+
+ while ((ch = getc(fp)) != EOF) {
+ if (bytes_this_line == 0) line_index = sprintf(line, "%08x: ", offset);
+ ++offset;
+
+ line[line_index++] = hex_digits[(ch >> 4) & 0xf];
+ line[line_index++] = hex_digits[ch & 0xf];
+ line[hex_size + bytes_this_line] = (ch >= ' ' && ch <= '~') ? ch : '.';
+
+ ++bytes_this_line;
+ if (bytes_this_line == TT.bytes_per_line) {
+ puts(line);
+ memset(line, ' ', line_size - 1);
+ bytes_this_line = 0;
+ } else if ((bytes_this_line % TT.bytes_per_group) == 0) {
+ line[line_index++] = ' ';
+ }
+ if ((toys.optflags & FLAG_l) && offset == TT.limit) {
+ break;
+ }
+ }
+ if (bytes_this_line != 0) {
+ line[hex_size + bytes_this_line] = 0;
+ puts(line);
+ }
+
+ if (CFG_FREE) free(line);
+}
+
+void xxd_main(void)
+{
+ FILE *fp;
+
+ if (!TT.bytes_per_line) TT.bytes_per_line = 16;
+ else if (TT.bytes_per_line < 0)
+ error_exit("invalid -c value: %d", TT.bytes_per_line);
+
+ if (!TT.bytes_per_group) TT.bytes_per_group = 2;
+ else if (TT.bytes_per_group < 0)
+ error_exit("invalid -g value: %d", TT.bytes_per_group);
+
+ if (!*toys.optargs || !strcmp(*toys.optargs, "-")) fp = stdin;
+ else fp = xfopen(*toys.optargs, "r");
+
+ xxd_file(fp);
+
+ fclose(fp);
+}