diff options
Diffstat (limited to 'util-linux/hexdump_xxd.c')
-rw-r--r-- | util-linux/hexdump_xxd.c | 77 |
1 files changed, 72 insertions, 5 deletions
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 6cf6d0297..d2f4b6ed8 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -50,6 +50,7 @@ | |||
50 | // exactly the same help text lines in hexdump and xxd: | 50 | // exactly the same help text lines in hexdump and xxd: |
51 | //usage: "\n -l LENGTH Show only first LENGTH bytes" | 51 | //usage: "\n -l LENGTH Show only first LENGTH bytes" |
52 | //usage: "\n -s OFFSET Skip OFFSET bytes" | 52 | //usage: "\n -s OFFSET Skip OFFSET bytes" |
53 | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" | ||
53 | // TODO: implement -r (see hexdump -R) | 54 | // TODO: implement -r (see hexdump -R) |
54 | 55 | ||
55 | #include "libbb.h" | 56 | #include "libbb.h" |
@@ -57,6 +58,71 @@ | |||
57 | 58 | ||
58 | /* This is a NOEXEC applet. Be very careful! */ | 59 | /* This is a NOEXEC applet. Be very careful! */ |
59 | 60 | ||
61 | #define OPT_l (1 << 0) | ||
62 | #define OPT_s (1 << 1) | ||
63 | #define OPT_a (1 << 2) | ||
64 | #define OPT_p (1 << 3) | ||
65 | #define OPT_r (1 << 4) | ||
66 | |||
67 | static void reverse(unsigned opt, unsigned cols, const char *filename) | ||
68 | { | ||
69 | FILE *fp; | ||
70 | char *buf; | ||
71 | |||
72 | fp = filename ? xfopen_for_read(filename) : stdin; | ||
73 | |||
74 | while ((buf = xmalloc_fgetline(fp)) != NULL) { | ||
75 | char *p = buf; | ||
76 | unsigned cnt = cols; | ||
77 | |||
78 | if (!(opt & OPT_p)) { | ||
79 | /* skip address */ | ||
80 | while (isxdigit(*p)) p++; | ||
81 | /* NB: for xxd -r, first hex portion is address even without colon */ | ||
82 | /* If it's there, skip it: */ | ||
83 | if (*p == ':') p++; | ||
84 | |||
85 | //TODO: seek (or zero-pad if unseekable) to the address position | ||
86 | //NOTE: -s SEEK value should be added to the address before seeking | ||
87 | } | ||
88 | |||
89 | /* Process hex bytes optionally separated by whitespace */ | ||
90 | do { | ||
91 | uint8_t val, c; | ||
92 | |||
93 | p = skip_whitespace(p); | ||
94 | |||
95 | c = *p++; | ||
96 | if (isdigit(c)) | ||
97 | val = c - '0'; | ||
98 | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') | ||
99 | val = (c|0x20) - ('a' - 10); | ||
100 | else | ||
101 | break; | ||
102 | val <<= 4; | ||
103 | |||
104 | /* Works the same with xxd V1.10: | ||
105 | * echo "31 09 32 0a" | xxd -r -p | ||
106 | * echo "31 0 9 32 0a" | xxd -r -p | ||
107 | * thus allow whitespace even within the byte: | ||
108 | */ | ||
109 | p = skip_whitespace(p); | ||
110 | |||
111 | c = *p++; | ||
112 | if (isdigit(c)) | ||
113 | val |= c - '0'; | ||
114 | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') | ||
115 | val |= (c|0x20) - ('a' - 10); | ||
116 | else | ||
117 | break; | ||
118 | putchar(val); | ||
119 | } while (!(opt & OPT_p) || --cnt != 0); | ||
120 | free(buf); | ||
121 | } | ||
122 | //fclose(fp); | ||
123 | fflush_stdout_and_exit(EXIT_SUCCESS); | ||
124 | } | ||
125 | |||
60 | int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 126 | int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
61 | int xxd_main(int argc UNUSED_PARAM, char **argv) | 127 | int xxd_main(int argc UNUSED_PARAM, char **argv) |
62 | { | 128 | { |
@@ -69,11 +135,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
69 | 135 | ||
70 | dumper = alloc_dumper(); | 136 | dumper = alloc_dumper(); |
71 | 137 | ||
72 | #define OPT_l (1 << 0) | 138 | opt = getopt32(argv, "^" "l:s:aprg:+c:+" "\0" "?1" /* 1 argument max */, |
73 | #define OPT_s (1 << 1) | ||
74 | #define OPT_a (1 << 2) | ||
75 | #define OPT_p (1 << 3) | ||
76 | opt = getopt32(argv, "^" "l:s:apg:+c:+" "\0" "?1" /* 1 argument max */, | ||
77 | &opt_l, &opt_s, &bytes, &cols | 139 | &opt_l, &opt_s, &bytes, &cols |
78 | ); | 140 | ); |
79 | argv += optind; | 141 | argv += optind; |
@@ -107,6 +169,10 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
107 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " | 169 | bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " |
108 | } | 170 | } |
109 | 171 | ||
172 | if (opt & OPT_r) { | ||
173 | reverse(opt, cols, argv[0]); | ||
174 | } | ||
175 | |||
110 | if (bytes < 1 || bytes >= cols) { | 176 | if (bytes < 1 || bytes >= cols) { |
111 | sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" | 177 | sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" |
112 | bb_dump_add(dumper, buf); | 178 | bb_dump_add(dumper, buf); |
@@ -141,6 +207,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
141 | bb_dump_add(dumper, buf); | 207 | bb_dump_add(dumper, buf); |
142 | } else { | 208 | } else { |
143 | bb_dump_add(dumper, "\"\n\""); | 209 | bb_dump_add(dumper, "\"\n\""); |
210 | dumper->eofstring = "\n"; | ||
144 | } | 211 | } |
145 | 212 | ||
146 | return bb_dump_dump(dumper, argv); | 213 | return bb_dump_dump(dumper, argv); |