compat: move hexdump -R functionality to xxd -r
No binary (build failed)
—
(log yok)
| @@ -15,16 +15,6 @@ | |
| //config: The hexdump utility is used to display binary data in a readable | |
| //config: way that is comparable to the output from most hex editors. | |
| //config: | |
| - | //config:config FEATURE_HEXDUMP_REVERSE |
| - | //config: bool "Support -R, reverse of 'hexdump -Cv'" |
| - | //config: default y |
| - | //config: depends on HEXDUMP |
| - | //config: help |
| - | //config: The hexdump utility is used to display binary data in an ascii |
| - | //config: readable way. This option creates binary data from an ascii input. |
| - | //config: NB: this option is non-standard. It's unwise to use it in scripts |
| - | //config: aimed to be portable. |
| - | //config: |
| //config:config HD | |
| //config: bool "hd (7.8 kb)" | |
| //config: default y | |
| @@ -38,7 +28,7 @@ | |
| //kbuild:lib-$(CONFIG_HD) += hexdump.o | |
| //usage:#define hexdump_trivial_usage | |
| - | //usage: "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..." |
| + | //usage: "[-bcCdefnosvx] [FILE]..." |
| //usage:#define hexdump_full_usage "\n\n" | |
| //usage: "Display FILEs (or stdin) in a user specified format\n" | |
| //usage: "\n -b 1-byte octal display" | |
| @@ -53,9 +43,6 @@ | |
| // exactly the same help text lines in hexdump and xxd: | |
| //usage: "\n -n LENGTH Show only first LENGTH bytes" | |
| //usage: "\n -s OFFSET Skip OFFSET bytes" | |
| - | //usage: IF_FEATURE_HEXDUMP_REVERSE( |
| - | //usage: "\n -R Reverse of 'hexdump -Cv'") |
| - | // TODO: NONCOMPAT!!! move -R to xxd -r |
| //usage: | |
| //usage:#define hd_trivial_usage | |
| //usage: "FILE..." | |
| @@ -94,7 +81,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" IF_FEATURE_HEXDUMP_REVERSE("R"); |
| + | static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v"; |
| int hexdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int hexdump_main(int argc, char **argv) | |
| @@ -102,10 +89,6 @@ int hexdump_main(int argc, char **argv) | |
| dumper_t *dumper = alloc_dumper(); | |
| const char *p; | |
| int ch; | |
| - | #if ENABLE_FEATURE_HEXDUMP_REVERSE |
| - | FILE *fp; |
| - | smallint rdump = 0; |
| - | #endif |
| if (ENABLE_HD | |
| && (!ENABLE_HEXDUMP || !applet_name[2]) | |
| @@ -153,11 +136,6 @@ int hexdump_main(int argc, char **argv) | |
| if (ch == 'v') { | |
| dumper->dump_vflag = ALL; | |
| } | |
| - | #if ENABLE_FEATURE_HEXDUMP_REVERSE |
| - | if (ch == 'R') { |
| - | rdump = 1; |
| - | } |
| - | #endif |
| } | |
| if (!dumper->fshead) { | |
| @@ -167,40 +145,5 @@ int hexdump_main(int argc, char **argv) | |
| argv += optind; | |
| - | #if !ENABLE_FEATURE_HEXDUMP_REVERSE |
| return bb_dump_dump(dumper, argv); | |
| - | #else |
| - | if (!rdump) { |
| - | return bb_dump_dump(dumper, argv); |
| - | } |
| - | |
| - | /* -R: reverse of 'hexdump -Cv' */ |
| - | fp = stdin; |
| - | if (!*argv) { |
| - | argv--; |
| - | goto jump_in; |
| - | } |
| - | |
| - | do { |
| - | char *buf; |
| - | fp = xfopen_for_read(*argv); |
| - | jump_in: |
| - | while ((buf = xmalloc_fgetline(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 |
| } | |
| @@ -50,6 +50,7 @@ | |
| // exactly the same help text lines in hexdump and xxd: | |
| //usage: "\n -l LENGTH Show only first LENGTH bytes" | |
| //usage: "\n -s OFFSET Skip OFFSET bytes" | |
| + | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" |
| // TODO: implement -r (see hexdump -R) | |
| #include "libbb.h" | |
| @@ -57,6 +58,71 @@ | |
| /* This is a NOEXEC applet. Be very careful! */ | |
| + | #define OPT_l (1 << 0) |
| + | #define OPT_s (1 << 1) |
| + | #define OPT_a (1 << 2) |
| + | #define OPT_p (1 << 3) |
| + | #define OPT_r (1 << 4) |
| + | |
| + | static void reverse(unsigned opt, unsigned cols, const char *filename) |
| + | { |
| + | FILE *fp; |
| + | char *buf; |
| + | |
| + | fp = filename ? xfopen_for_read(filename) : stdin; |
| + | |
| + | while ((buf = xmalloc_fgetline(fp)) != NULL) { |
| + | char *p = buf; |
| + | unsigned cnt = cols; |
| + | |
| + | if (!(opt & OPT_p)) { |
| + | /* skip address */ |
| + | while (isxdigit(*p)) p++; |
| + | /* NB: for xxd -r, first hex portion is address even without colon */ |
| + | /* If it's there, skip it: */ |
| + | if (*p == ':') p++; |
| + | |
| + | //TODO: seek (or zero-pad if unseekable) to the address position |
| + | //NOTE: -s SEEK value should be added to the address before seeking |
| + | } |
| + | |
| + | /* Process hex bytes optionally separated by whitespace */ |
| + | do { |
| + | uint8_t val, c; |
| + | |
| + | p = skip_whitespace(p); |
| + | |
| + | c = *p++; |
| + | if (isdigit(c)) |
| + | val = c - '0'; |
| + | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') |
| + | val = (c|0x20) - ('a' - 10); |
| + | else |
| + | break; |
| + | val <<= 4; |
| + | |
| + | /* Works the same with xxd V1.10: |
| + | * echo "31 09 32 0a" | xxd -r -p |
| + | * echo "31 0 9 32 0a" | xxd -r -p |
| + | * thus allow whitespace even within the byte: |
| + | */ |
| + | p = skip_whitespace(p); |
| + | |
| + | c = *p++; |
| + | if (isdigit(c)) |
| + | val |= c - '0'; |
| + | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') |
| + | val |= (c|0x20) - ('a' - 10); |
| + | else |
| + | break; |
| + | putchar(val); |
| + | } while (!(opt & OPT_p) || --cnt != 0); |
| + | free(buf); |
| + | } |
| + | //fclose(fp); |
| + | fflush_stdout_and_exit(EXIT_SUCCESS); |
| + | } |
| + | |
| int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int xxd_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| @@ -69,11 +135,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |
| dumper = alloc_dumper(); | |
| - | #define OPT_l (1 << 0) |
| - | #define OPT_s (1 << 1) |
| - | #define OPT_a (1 << 2) |
| - | #define OPT_p (1 << 3) |
| - | opt = getopt32(argv, "^" "l:s:apg:+c:+" "\0" "?1" /* 1 argument max */, |
| + | opt = getopt32(argv, "^" "l:s:aprg:+c:+" "\0" "?1" /* 1 argument max */, |
| &opt_l, &opt_s, &bytes, &cols | |
| ); | |
| argv += optind; | |
| @@ -107,6 +169,10 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |
| bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " | |
| } | |
| + | if (opt & OPT_r) { |
| + | reverse(opt, cols, argv[0]); |
| + | } |
| + | |
| if (bytes < 1 || bytes >= cols) { | |
| sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" | |
| bb_dump_add(dumper, buf); | |