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>
This commit is contained in:
		| @@ -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) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user