From 5eceafb1f812ec4dca7fdf6896cfcea6783a78b9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Aug 2022 17:28:43 +0200 Subject: [PATCH] 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 --- util-linux/hexdump_xxd.c | 58 ++++++++++++++++++++++++++++++++++------ 1 file 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 @@ //usage: "\n -r Reverse (with -p, assumes no offsets in input)" #include "libbb.h" +#include "common_bufsiz.h" #include "dump.h" /* This is a NOEXEC applet. Be very careful! */ @@ -69,10 +70,32 @@ #define OPT_c (1 << 7) #define OPT_o (1 << 8) -static void reverse(unsigned opt, const char *filename) +#define fillbuf bb_common_bufsiz1 + +static void write_zeros(off_t count) +{ + errno = 0; + do { + unsigned sz = count < COMMON_BUFSIZE ? (unsigned)count : COMMON_BUFSIZE; + if (fwrite(fillbuf, 1, sz, stdout) != sz) + bb_perror_msg_and_die("write error"); + count -= sz; + } while (count != 0); +} + +static void reverse(unsigned opt, const char *filename, char *opt_s) { FILE *fp; char *buf; + off_t cur, opt_s_ofs; + + memset(fillbuf, 0, COMMON_BUFSIZE); + opt_s_ofs = cur = 0; + if (opt_s) { + opt_s_ofs = BB_STRTOOFF(opt_s, NULL, 0); + if (errno || opt_s_ofs < 0) + bb_error_msg_and_die("invalid number '%s'", opt_s); + } fp = filename ? xfopen_for_read(filename) : stdin; @@ -82,15 +105,31 @@ static void reverse(unsigned opt, const char *filename) p = buf; if (!(opt & OPT_p)) { + char *end; + off_t ofs; skip_address: p = skip_whitespace(p); - while (isxdigit(*p)) p++; + ofs = BB_STRTOOFF(p, &end, 16); + if ((errno && errno != EINVAL) + || ofs < 0 + /* -s SEEK value should be added before seeking */ + || (ofs += opt_s_ofs) < 0 + ) { + bb_error_msg_and_die("invalid number '%s'", p); + } + if (ofs != cur) { + if (fseeko(stdout, ofs, SEEK_SET) != 0) { + if (ofs < cur) + bb_perror_msg_and_die("cannot seek"); + write_zeros(ofs - cur); + } + cur = ofs; + } + p = end; /* 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 + /* But if colon is there, skip it: */ + if (*p == ':') + p++; } /* Process hex bytes optionally separated by whitespace */ @@ -168,6 +207,7 @@ static void reverse(unsigned opt, const char *filename) goto nibble2; } putchar(val); + cur++; } /* for(;;) */ free(buf); } @@ -195,6 +235,8 @@ int xxd_main(int argc UNUSED_PARAM, char **argv) unsigned opt; int r; + setup_common_bufsiz(); + dumper = alloc_dumper(); 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) } if (opt & OPT_r) { - reverse(opt, argv[0]); + reverse(opt, argv[0], opt_s); } if (opt & OPT_o) {