aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-10-08 23:03:54 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-10-08 23:03:54 +0200
commit86ba007b84ae1ebe35e88c57e023caac3d2d9903 (patch)
tree5e80e0d26c2cefec73ba7f2000adccca62641daf
parentd315a77a79817d364a1562f4457c21fbb8174025 (diff)
downloadbusybox-w32-86ba007b84ae1ebe35e88c57e023caac3d2d9903.tar.gz
busybox-w32-86ba007b84ae1ebe35e88c57e023caac3d2d9903.tar.bz2
busybox-w32-86ba007b84ae1ebe35e88c57e023caac3d2d9903.zip
xxd: fix -p -r, closes 13881
function old new delta xxd_main 893 890 -3 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rwxr-xr-xtestsuite/xxd.tests6
-rw-r--r--util-linux/hexdump_xxd.c51
2 files changed, 44 insertions, 13 deletions
diff --git a/testsuite/xxd.tests b/testsuite/xxd.tests
index 2e80be5fe..76fa96af9 100755
--- a/testsuite/xxd.tests
+++ b/testsuite/xxd.tests
@@ -31,4 +31,10 @@ testing 'xxd -p with 31 NULs' \
31 '' \ 31 '' \
32 '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' 32 '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
33 33
34testing 'xxd -p -r' \
35 'xxd -p -r' \
36 '01234567765432100123456776543210' \
37 '' \
38 '30313233343536373736353433323130 30313233343536373736353433323130'
39
34exit $FAILCOUNT 40exit $FAILCOUNT
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c
index fe78f6242..76dada983 100644
--- a/util-linux/hexdump_xxd.c
+++ b/util-linux/hexdump_xxd.c
@@ -69,7 +69,7 @@
69#define OPT_c (1 << 7) 69#define OPT_c (1 << 7)
70#define OPT_o (1 << 8) 70#define OPT_o (1 << 8)
71 71
72static void reverse(unsigned opt, unsigned cols, const char *filename) 72static void reverse(unsigned opt, const char *filename)
73{ 73{
74 FILE *fp; 74 FILE *fp;
75 char *buf; 75 char *buf;
@@ -77,9 +77,9 @@ static void reverse(unsigned opt, unsigned cols, const char *filename)
77 fp = filename ? xfopen_for_read(filename) : stdin; 77 fp = filename ? xfopen_for_read(filename) : stdin;
78 78
79 while ((buf = xmalloc_fgetline(fp)) != NULL) { 79 while ((buf = xmalloc_fgetline(fp)) != NULL) {
80 char *p = buf; 80 char *p;
81 unsigned cnt = cols;
82 81
82 p = buf;
83 if (!(opt & OPT_p)) { 83 if (!(opt & OPT_p)) {
84 /* skip address */ 84 /* skip address */
85 while (isxdigit(*p)) p++; 85 while (isxdigit(*p)) p++;
@@ -92,9 +92,9 @@ static void reverse(unsigned opt, unsigned cols, const char *filename)
92 } 92 }
93 93
94 /* Process hex bytes optionally separated by whitespace */ 94 /* Process hex bytes optionally separated by whitespace */
95 do { 95 for (;;) {
96 uint8_t val, c; 96 uint8_t val, c;
97 97 nibble1:
98 p = skip_whitespace(p); 98 p = skip_whitespace(p);
99 99
100 c = *p++; 100 c = *p++;
@@ -102,8 +102,19 @@ static void reverse(unsigned opt, unsigned cols, const char *filename)
102 val = c - '0'; 102 val = c - '0';
103 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') 103 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
104 val = (c|0x20) - ('a' - 10); 104 val = (c|0x20) - ('a' - 10);
105 else 105 else {
106 /* xxd V1.10 is inconsistent here.
107 * echo -e "31 !3 0a 0a" | xxd -r -p
108 * is "10<a0>" (no <cr>) - "!" is ignored,
109 * but
110 * echo -e "31 !!343434\n30 0a" | xxd -r -p
111 * is "10<cr>" - "!!" drops rest of the line.
112 * We will ignore all invalid chars:
113 */
114 if (c != '\0')
115 goto nibble1;
106 break; 116 break;
117 }
107 val <<= 4; 118 val <<= 4;
108 119
109 /* Works the same with xxd V1.10: 120 /* Works the same with xxd V1.10:
@@ -111,6 +122,7 @@ static void reverse(unsigned opt, unsigned cols, const char *filename)
111 * echo "31 0 9 32 0a" | xxd -r -p 122 * echo "31 0 9 32 0a" | xxd -r -p
112 * thus allow whitespace even within the byte: 123 * thus allow whitespace even within the byte:
113 */ 124 */
125 nibble2:
114 p = skip_whitespace(p); 126 p = skip_whitespace(p);
115 127
116 c = *p++; 128 c = *p++;
@@ -118,10 +130,23 @@ static void reverse(unsigned opt, unsigned cols, const char *filename)
118 val |= c - '0'; 130 val |= c - '0';
119 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') 131 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
120 val |= (c|0x20) - ('a' - 10); 132 val |= (c|0x20) - ('a' - 10);
121 else 133 else {
122 break; 134 if (c != '\0') {
135 /* "...3<not_hex_char>..." ignores both chars */
136 goto nibble1;
137 }
138 /* Nibbles can join even through newline:
139 * echo -e "31 3\n2 0a" | xxd -r -p
140 * is "12<cr>".
141 */
142 free(buf);
143 p = buf = xmalloc_fgetline(fp);
144 if (!buf)
145 break;
146 goto nibble2;
147 }
123 putchar(val); 148 putchar(val);
124 } while (!(opt & OPT_p) || --cnt != 0); 149 }
125 free(buf); 150 free(buf);
126 } 151 }
127 //fclose(fp); 152 //fclose(fp);
@@ -174,6 +199,10 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
174 //BUGGY for /proc/version (unseekable?) 199 //BUGGY for /proc/version (unseekable?)
175 } 200 }
176 201
202 if (opt & OPT_r) {
203 reverse(opt, argv[0]);
204 }
205
177 if (opt & OPT_o) { 206 if (opt & OPT_o) {
178 /* -o accepts negative numbers too */ 207 /* -o accepts negative numbers too */
179 dumper->xxd_displayoff = xstrtoll(opt_o, /*base:*/ 0); 208 dumper->xxd_displayoff = xstrtoll(opt_o, /*base:*/ 0);
@@ -194,10 +223,6 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
194 bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " 223 bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: "
195 } 224 }
196 225
197 if (opt & OPT_r) {
198 reverse(opt, cols, argv[0]);
199 }
200
201 if (bytes < 1 || bytes >= cols) { 226 if (bytes < 1 || bytes >= cols) {
202 sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "XX" 227 sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "XX"
203 bb_dump_add(dumper, buf); 228 bb_dump_add(dumper, buf);