diff --git a/include/applets.h b/include/applets.h index 587ccbf51..f188232c4 100644 --- a/include/applets.h +++ b/include/applets.h @@ -171,6 +171,7 @@ USE_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_NEVER)) +USE_HD(APPLET_ODDNAME(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hd)) USE_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_HEAD(APPLET(head, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hexdump)) diff --git a/include/usage.h b/include/usage.h index 592316ace..d0eecdb4a 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1384,21 +1384,28 @@ "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" #define hexdump_trivial_usage \ - "[-[bcCdefnosvx]] [OPTION] FILE" + "[-bcCdefnosvx" USE_FEATURE_HEXDUMP_REVERSE("R") "] FILE..." #define hexdump_full_usage \ "Display file(s) or standard input in a user specified format" \ - "\n\nOptions:\n" \ - " -b One-byte octal display\n" \ - " -c One-byte character display\n" \ - " -C Canonical hex+ASCII, 16 bytes per line\n" \ - " -d Two-byte decimal display\n" \ - " -e FORMAT STRING\n" \ - " -f FORMAT FILE\n" \ - " -n LENGTH Interpret only LENGTH bytes of input\n" \ - " -o Two-byte octal display\n" \ - " -s OFFSET Skip OFFSET bytes\n" \ - " -v Display all input data\n" \ - " -x Two-byte hexadecimal display" + "\n\nOptions:" \ + "\n -b One-byte octal display" \ + "\n -c One-byte character display" \ + "\n -C Canonical hex+ASCII, 16 bytes per line" \ + "\n -d Two-byte decimal display" \ + "\n -e FORMAT STRING" \ + "\n -f FORMAT FILE" \ + "\n -n LENGTH Interpret only LENGTH bytes of input" \ + "\n -o Two-byte octal display" \ + "\n -s OFFSET Skip OFFSET bytes" \ + "\n -v Display all input data" \ + "\n -x Two-byte hexadecimal display" \ + USE_FEATURE_HEXDUMP_REVERSE( \ + "\n -R Reverse of 'hexdump -Cv'") \ + +#define hd_trivial_usage \ + "FILE..." +#define hd_full_usage \ + "hd is an alias for hexdump -C" #define hostid_trivial_usage \ "" diff --git a/util-linux/Config.in b/util-linux/Config.in index 107382f51..8b0bbd65d 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in @@ -210,6 +210,22 @@ config HEXDUMP The hexdump utility is used to display binary data in a readable way that is comparable to the output from most hex editors. +config HD + bool "hd" + default n + help + hd is an alias to hexdump -C. + +config FEATURE_HEXDUMP_REVERSE + bool "Support -R, reverse of 'hexdump -Cv'" + default n + depends on HEXDUMP + help + The hexdump utility is used to display binary data in an ascii + readable way. This option creates binary data from an ascii input. + NB: this option is non-standard. It's unwise to use it in scripts + aimed to be portable. + config HWCLOCK bool "hwclock" default n diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c index e6820ae8d..670867054 100644 --- a/util-linux/hexdump.c +++ b/util-linux/hexdump.c @@ -45,7 +45,7 @@ static const char *const add_strings[] = { static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; -static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v"; +static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" USE_FEATURE_HEXDUMP_REVERSE("R"); static const struct suffix_mult suffixes[] = { { "b", 512 }, @@ -59,10 +59,21 @@ int hexdump_main(int argc, char **argv) { const char *p; int ch; +#if ENABLE_FEATURE_HEXDUMP_REVERSE + FILE *fp; + smallint rdump = 0; +#endif bb_dump_vflag = FIRST; bb_dump_length = -1; + if (ENABLE_HD && !applet_name[2]) { /* we are "hd" */ + ch = 'C'; + goto hd_applet; + } + + /* We cannot use getopt32: in hexdump options are cumulative. + * E.g. hexdump -C -C file should dump each line twice */ while ((ch = getopt(argc, argv, hexdump_opts)) > 0) { p = strchr(hexdump_opts, ch); if (!p) @@ -70,28 +81,34 @@ int hexdump_main(int argc, char **argv) if ((p - hexdump_opts) < 5) { bb_dump_add(add_first); bb_dump_add(add_strings[(int)(p - hexdump_opts)]); - } else if (ch == 'C') { + } + /* Save a little bit of space below by omitting the 'else's. */ + if (ch == 'C') { + hd_applet: bb_dump_add("\"%08.8_Ax\n\""); bb_dump_add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); bb_dump_add("\" |\" 16/1 \"%_p\" \"|\\n\""); - } else { - /* Save a little bit of space below by omitting the 'else's. */ - if (ch == 'e') { - bb_dump_add(optarg); - } /* else */ - if (ch == 'f') { - bb_dump_addfile(optarg); - } /* else */ - if (ch == 'n') { - bb_dump_length = xatoi_u(optarg); - } /* else */ - if (ch == 's') { - bb_dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes); - } /* else */ - if (ch == 'v') { - bb_dump_vflag = ALL; - } } + if (ch == 'e') { + bb_dump_add(optarg); + } /* else */ + if (ch == 'f') { + bb_dump_addfile(optarg); + } /* else */ + if (ch == 'n') { + bb_dump_length = xatoi_u(optarg); + } /* else */ + if (ch == 's') { + bb_dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes); + } /* else */ + if (ch == 'v') { + bb_dump_vflag = ALL; + } +#if ENABLE_FEATURE_HEXDUMP_REVERSE + if (ch == 'R') { + rdump = 1; + } +#endif } if (!bb_dump_fshead) { @@ -101,5 +118,40 @@ int hexdump_main(int argc, char **argv) argv += optind; +#if !ENABLE_FEATURE_HEXDUMP_REVERSE return bb_dump_dump(argv); +#else + if (!rdump) { + return bb_dump_dump(argv); + } + + /* -R: reverse of 'hexdump -Cv' */ + fp = stdin; + if (!*argv) { + argv--; + goto jump_in; + } + + do { + char *buf; + fp = xfopen(*argv, "r"); + jump_in: + while ((buf = xmalloc_getline(fp)) != NULL) { + p = buf; + while (1) { + /* skip address or previous byte */ + while (isxdigit(*p)) p++; + while (*p == ' ') p++; + /* '|' char will break the line */ + if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1) + break; + putchar(ch); + } + free(buf); + } + fclose(fp); + } while (*++argv); + + fflush_stdout_and_exit(EXIT_SUCCESS); +#endif }