aboutsummaryrefslogtreecommitdiff
path: root/util-linux
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2022-10-12 10:43:26 +0100
committerRon Yorston <rmy@pobox.com>2022-10-12 10:43:26 +0100
commit49c6f079acb4edae84b4496bd941cdbb5048ba01 (patch)
treeac54ecaad45050f7bfe274a11db29882aa32a9a8 /util-linux
parenta55cf07365ec2ff51749a77e09ae9edac79a99fe (diff)
parentc8c1fcdba163f264a503380bc63485aacd09214c (diff)
downloadbusybox-w32-49c6f079acb4edae84b4496bd941cdbb5048ba01.tar.gz
busybox-w32-49c6f079acb4edae84b4496bd941cdbb5048ba01.tar.bz2
busybox-w32-49c6f079acb4edae84b4496bd941cdbb5048ba01.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'util-linux')
-rw-r--r--util-linux/hexdump_xxd.c114
1 files changed, 89 insertions, 25 deletions
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c
index 4372ac770..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,61 +70,110 @@
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
72static void reverse(unsigned opt, const char *filename) 73#define fillbuf bb_common_bufsiz1
74
75static 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
86static 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
102 get_new_line:
79 while ((buf = xmalloc_fgetline(fp)) != NULL) { 103 while ((buf = xmalloc_fgetline(fp)) != NULL) {
80 char *p; 104 char *p;
81 105
82 p = buf; 106 p = buf;
83 if (!(opt & OPT_p)) { 107 if (!(opt & OPT_p)) {
84 /* skip address */ 108 char *end;
85 while (isxdigit(*p)) p++; 109 off_t ofs;
110 skip_address:
111 p = skip_whitespace(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;
86 /* 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 */
87 /* If it's there, skip it: */ 130 /* But if colon is there, skip it: */
88 if (*p == ':') p++; 131 if (*p == ':')
89 132 p++;
90//TODO: seek (or zero-pad if unseekable) to the address position
91//NOTE: -s SEEK value should be added to the address before seeking
92 } 133 }
93 134
94 /* Process hex bytes optionally separated by whitespace */ 135 /* Process hex bytes optionally separated by whitespace */
95 for (;;) { 136 for (;;) {
96 uint8_t val, c; 137 uint8_t val, c;
138 int badchar = 0;
97 nibble1: 139 nibble1:
98 p = skip_whitespace(p); 140 if (opt & OPT_p)
99 141 p = skip_whitespace(p);
100 c = *p++; 142 c = *p++;
101 if (isdigit(c)) 143 if (isdigit(c))
102 val = c - '0'; 144 val = c - '0';
103 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') 145 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
104 val = (c|0x20) - ('a' - 10); 146 val = (c|0x20) - ('a' - 10);
105 else { 147 else {
106 /* xxd V1.10 is inconsistent here. 148 /* xxd V1.10 allows one non-hexnum char:
107 * echo -e "31 !3 0a 0a" | xxd -r -p 149 * echo -e "31 !3 0a 0a" | xxd -r -p
108 * is "10<a0>" (no <cr>) - "!" is ignored, 150 * is "10<a0>" (no <cr>) - "!" is ignored,
109 * but 151 * but stops for more than one:
110 * echo -e "31 !!343434\n30 0a" | xxd -r -p 152 * echo -e "31 !!343434\n30 0a" | xxd -r -p
111 * is "10<cr>" - "!!" drops rest of the line. 153 * is "10<cr>" - "!!" drops rest of the line.
112 * We will ignore all invalid chars: 154 * Note: this also covers whitespace chars:
155 * xxxxxxxx: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f 0123456789:;<=>?
156 * detects this ^ - skips this one space
157 * xxxxxxxx: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f 0123456789:;<=>?
158 * detects this ^^ - skips the rest
113 */ 159 */
114 if (c != '\0') 160 if (c == '\0' || badchar)
115 goto nibble1; 161 break;
116 break; 162 badchar++;
163 goto nibble1;
117 } 164 }
118 val <<= 4; 165 val <<= 4;
119 166
120 /* Works the same with xxd V1.10:
121 * echo "31 09 32 0a" | xxd -r -p
122 * echo "31 0 9 32 0a" | xxd -r -p
123 * thus allow whitespace even within the byte:
124 */
125 nibble2: 167 nibble2:
126 p = skip_whitespace(p); 168 if (opt & OPT_p) {
169 /* Works the same with xxd V1.10:
170 * echo "31 09 32 0a" | xxd -r -p
171 * echo "31 0 9 32 0a" | xxd -r -p
172 * thus allow whitespace (even multiple chars)
173 * after byte's 1st char:
174 */
175 p = skip_whitespace(p);
176 }
127 177
128 c = *p++; 178 c = *p++;
129 if (isdigit(c)) 179 if (isdigit(c))
@@ -132,7 +182,16 @@ static void reverse(unsigned opt, const char *filename)
132 val |= (c|0x20) - ('a' - 10); 182 val |= (c|0x20) - ('a' - 10);
133 else { 183 else {
134 if (c != '\0') { 184 if (c != '\0') {
135 /* "...3<not_hex_char>..." ignores both chars */ 185 /* "...3<not_hex_char>...": ignore "3",
186 * skip everything up to next hexchar or newline:
187 */
188 while (!isxdigit(*p)) {
189 if (*p == '\0') {
190 free(buf);
191 goto get_new_line;
192 }
193 p++;
194 }
136 goto nibble1; 195 goto nibble1;
137 } 196 }
138 /* Nibbles can join even through newline: 197 /* Nibbles can join even through newline:
@@ -143,10 +202,13 @@ static void reverse(unsigned opt, const char *filename)
143 p = buf = xmalloc_fgetline(fp); 202 p = buf = xmalloc_fgetline(fp);
144 if (!buf) 203 if (!buf)
145 break; 204 break;
205 if (!(opt & OPT_p)) /* -p and !-p: different behavior */
206 goto skip_address;
146 goto nibble2; 207 goto nibble2;
147 } 208 }
148 putchar(val); 209 putchar(val);
149 } 210 cur++;
211 } /* for(;;) */
150 free(buf); 212 free(buf);
151 } 213 }
152 //fclose(fp); 214 //fclose(fp);
@@ -173,6 +235,8 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
173 unsigned opt; 235 unsigned opt;
174 int r; 236 int r;
175 237
238 setup_common_bufsiz();
239
176 dumper = alloc_dumper(); 240 dumper = alloc_dumper();
177 241
178 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 */,
@@ -200,7 +264,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
200 } 264 }
201 265
202 if (opt & OPT_r) { 266 if (opt & OPT_r) {
203 reverse(opt, argv[0]); 267 reverse(opt, argv[0], opt_s);
204 } 268 }
205 269
206 if (opt & OPT_o) { 270 if (opt & OPT_o) {