diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2022-08-22 17:28:43 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2022-08-22 17:28:43 +0200 |
commit | 5eceafb1f812ec4dca7fdf6896cfcea6783a78b9 (patch) | |
tree | ac965162ebc73f32e188a6fe84f57ac23c2b533e | |
parent | 0011a6bc2024ec4ee6d8edea203524e758d67833 (diff) | |
download | busybox-w32-5eceafb1f812ec4dca7fdf6896cfcea6783a78b9.tar.gz busybox-w32-5eceafb1f812ec4dca7fdf6896cfcea6783a78b9.tar.bz2 busybox-w32-5eceafb1f812ec4dca7fdf6896cfcea6783a78b9.zip |
xxd -r: handle offsets
function old new delta
xxd_main 1076 1439 +363
.rodata 105239 105251 +12
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 375/0) Total: 375 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | util-linux/hexdump_xxd.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index dbda34bc5..6629407de 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -55,6 +55,7 @@ | |||
55 | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" | 55 | //usage: "\n -r Reverse (with -p, assumes no offsets in input)" |
56 | 56 | ||
57 | #include "libbb.h" | 57 | #include "libbb.h" |
58 | #include "common_bufsiz.h" | ||
58 | #include "dump.h" | 59 | #include "dump.h" |
59 | 60 | ||
60 | /* This is a NOEXEC applet. Be very careful! */ | 61 | /* This is a NOEXEC applet. Be very careful! */ |
@@ -69,10 +70,32 @@ | |||
69 | #define OPT_c (1 << 7) | 70 | #define OPT_c (1 << 7) |
70 | #define OPT_o (1 << 8) | 71 | #define OPT_o (1 << 8) |
71 | 72 | ||
72 | static void reverse(unsigned opt, const char *filename) | 73 | #define fillbuf bb_common_bufsiz1 |
74 | |||
75 | static void write_zeros(off_t count) | ||
76 | { | ||
77 | errno = 0; | ||
78 | do { | ||
79 | unsigned sz = count < COMMON_BUFSIZE ? (unsigned)count : COMMON_BUFSIZE; | ||
80 | if (fwrite(fillbuf, 1, sz, stdout) != sz) | ||
81 | bb_perror_msg_and_die("write error"); | ||
82 | count -= sz; | ||
83 | } while (count != 0); | ||
84 | } | ||
85 | |||
86 | static void reverse(unsigned opt, const char *filename, char *opt_s) | ||
73 | { | 87 | { |
74 | FILE *fp; | 88 | FILE *fp; |
75 | char *buf; | 89 | char *buf; |
90 | off_t cur, opt_s_ofs; | ||
91 | |||
92 | memset(fillbuf, 0, COMMON_BUFSIZE); | ||
93 | opt_s_ofs = cur = 0; | ||
94 | if (opt_s) { | ||
95 | opt_s_ofs = BB_STRTOOFF(opt_s, NULL, 0); | ||
96 | if (errno || opt_s_ofs < 0) | ||
97 | bb_error_msg_and_die("invalid number '%s'", opt_s); | ||
98 | } | ||
76 | 99 | ||
77 | fp = filename ? xfopen_for_read(filename) : stdin; | 100 | fp = filename ? xfopen_for_read(filename) : stdin; |
78 | 101 | ||
@@ -82,15 +105,31 @@ static void reverse(unsigned opt, const char *filename) | |||
82 | 105 | ||
83 | p = buf; | 106 | p = buf; |
84 | if (!(opt & OPT_p)) { | 107 | if (!(opt & OPT_p)) { |
108 | char *end; | ||
109 | off_t ofs; | ||
85 | skip_address: | 110 | skip_address: |
86 | p = skip_whitespace(p); | 111 | p = skip_whitespace(p); |
87 | while (isxdigit(*p)) p++; | 112 | ofs = BB_STRTOOFF(p, &end, 16); |
113 | if ((errno && errno != EINVAL) | ||
114 | || ofs < 0 | ||
115 | /* -s SEEK value should be added before seeking */ | ||
116 | || (ofs += opt_s_ofs) < 0 | ||
117 | ) { | ||
118 | bb_error_msg_and_die("invalid number '%s'", p); | ||
119 | } | ||
120 | if (ofs != cur) { | ||
121 | if (fseeko(stdout, ofs, SEEK_SET) != 0) { | ||
122 | if (ofs < cur) | ||
123 | bb_perror_msg_and_die("cannot seek"); | ||
124 | write_zeros(ofs - cur); | ||
125 | } | ||
126 | cur = ofs; | ||
127 | } | ||
128 | p = end; | ||
88 | /* NB: for xxd -r, first hex portion is address even without colon */ | 129 | /* NB: for xxd -r, first hex portion is address even without colon */ |
89 | /* If it's there, skip it: */ | 130 | /* But if colon is there, skip it: */ |
90 | if (*p == ':') p++; | 131 | if (*p == ':') |
91 | 132 | p++; | |
92 | //TODO: seek (or zero-pad if unseekable) to the address position | ||
93 | //NOTE: -s SEEK value should be added to the address before seeking | ||
94 | } | 133 | } |
95 | 134 | ||
96 | /* Process hex bytes optionally separated by whitespace */ | 135 | /* Process hex bytes optionally separated by whitespace */ |
@@ -168,6 +207,7 @@ static void reverse(unsigned opt, const char *filename) | |||
168 | goto nibble2; | 207 | goto nibble2; |
169 | } | 208 | } |
170 | putchar(val); | 209 | putchar(val); |
210 | cur++; | ||
171 | } /* for(;;) */ | 211 | } /* for(;;) */ |
172 | free(buf); | 212 | free(buf); |
173 | } | 213 | } |
@@ -195,6 +235,8 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
195 | unsigned opt; | 235 | unsigned opt; |
196 | int r; | 236 | int r; |
197 | 237 | ||
238 | setup_common_bufsiz(); | ||
239 | |||
198 | dumper = alloc_dumper(); | 240 | dumper = alloc_dumper(); |
199 | 241 | ||
200 | opt = getopt32(argv, "^" "l:s:apirg:+c:+o:" "\0" "?1" /* 1 argument max */, | 242 | opt = getopt32(argv, "^" "l:s:apirg:+c:+o:" "\0" "?1" /* 1 argument max */, |
@@ -222,7 +264,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) | |||
222 | } | 264 | } |
223 | 265 | ||
224 | if (opt & OPT_r) { | 266 | if (opt & OPT_r) { |
225 | reverse(opt, argv[0]); | 267 | reverse(opt, argv[0], opt_s); |
226 | } | 268 | } |
227 | 269 | ||
228 | if (opt & OPT_o) { | 270 | if (opt & OPT_o) { |