diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2022-08-22 15:40:47 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2022-08-22 15:40:47 +0200 |
commit | f318adaaab3288fe72cb853bf7ede56790a13182 (patch) | |
tree | 417db541833ecac1843e0c8f7534b5d23e9bb83e /util-linux | |
parent | 5a9d2b6e024e6c20d4d7b8c170985554c0df043d (diff) | |
download | busybox-w32-f318adaaab3288fe72cb853bf7ede56790a13182.tar.gz busybox-w32-f318adaaab3288fe72cb853bf7ede56790a13182.tar.bz2 busybox-w32-f318adaaab3288fe72cb853bf7ede56790a13182.zip |
xxd -r: without -p, stop at more than one whitespace, closes 14786
function old new delta
xxd_main 888 1076 +188
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'util-linux')
-rw-r--r-- | util-linux/hexdump_xxd.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c index 4372ac770..dbda34bc5 100644 --- a/util-linux/hexdump_xxd.c +++ b/util-linux/hexdump_xxd.c | |||
@@ -76,12 +76,14 @@ static void reverse(unsigned opt, const char *filename) | |||
76 | 76 | ||
77 | fp = filename ? xfopen_for_read(filename) : stdin; | 77 | fp = filename ? xfopen_for_read(filename) : stdin; |
78 | 78 | ||
79 | get_new_line: | ||
79 | while ((buf = xmalloc_fgetline(fp)) != NULL) { | 80 | while ((buf = xmalloc_fgetline(fp)) != NULL) { |
80 | char *p; | 81 | char *p; |
81 | 82 | ||
82 | p = buf; | 83 | p = buf; |
83 | if (!(opt & OPT_p)) { | 84 | if (!(opt & OPT_p)) { |
84 | /* skip address */ | 85 | skip_address: |
86 | p = skip_whitespace(p); | ||
85 | while (isxdigit(*p)) p++; | 87 | while (isxdigit(*p)) p++; |
86 | /* NB: for xxd -r, first hex portion is address even without colon */ | 88 | /* NB: for xxd -r, first hex portion is address even without colon */ |
87 | /* If it's there, skip it: */ | 89 | /* If it's there, skip it: */ |
@@ -94,36 +96,45 @@ static void reverse(unsigned opt, const char *filename) | |||
94 | /* Process hex bytes optionally separated by whitespace */ | 96 | /* Process hex bytes optionally separated by whitespace */ |
95 | for (;;) { | 97 | for (;;) { |
96 | uint8_t val, c; | 98 | uint8_t val, c; |
99 | int badchar = 0; | ||
97 | nibble1: | 100 | nibble1: |
98 | p = skip_whitespace(p); | 101 | if (opt & OPT_p) |
99 | 102 | p = skip_whitespace(p); | |
100 | c = *p++; | 103 | c = *p++; |
101 | if (isdigit(c)) | 104 | if (isdigit(c)) |
102 | val = c - '0'; | 105 | val = c - '0'; |
103 | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') | 106 | else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') |
104 | val = (c|0x20) - ('a' - 10); | 107 | val = (c|0x20) - ('a' - 10); |
105 | else { | 108 | else { |
106 | /* xxd V1.10 is inconsistent here. | 109 | /* xxd V1.10 allows one non-hexnum char: |
107 | * echo -e "31 !3 0a 0a" | xxd -r -p | 110 | * echo -e "31 !3 0a 0a" | xxd -r -p |
108 | * is "10<a0>" (no <cr>) - "!" is ignored, | 111 | * is "10<a0>" (no <cr>) - "!" is ignored, |
109 | * but | 112 | * but stops for more than one: |
110 | * echo -e "31 !!343434\n30 0a" | xxd -r -p | 113 | * echo -e "31 !!343434\n30 0a" | xxd -r -p |
111 | * is "10<cr>" - "!!" drops rest of the line. | 114 | * is "10<cr>" - "!!" drops rest of the line. |
112 | * We will ignore all invalid chars: | 115 | * Note: this also covers whitespace chars: |
116 | * xxxxxxxx: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f 0123456789:;<=>? | ||
117 | * detects this ^ - skips this one space | ||
118 | * xxxxxxxx: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f 0123456789:;<=>? | ||
119 | * detects this ^^ - skips the rest | ||
113 | */ | 120 | */ |
114 | if (c != '\0') | 121 | if (c == '\0' || badchar) |
115 | goto nibble1; | 122 | break; |
116 | break; | 123 | badchar++; |
124 | goto nibble1; | ||
117 | } | 125 | } |
118 | val <<= 4; | 126 | val <<= 4; |
119 | 127 | ||
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: | 128 | nibble2: |
126 | p = skip_whitespace(p); | 129 | if (opt & OPT_p) { |
130 | /* Works the same with xxd V1.10: | ||
131 | * echo "31 09 32 0a" | xxd -r -p | ||
132 | * echo "31 0 9 32 0a" | xxd -r -p | ||
133 | * thus allow whitespace (even multiple chars) | ||
134 | * after byte's 1st char: | ||
135 | */ | ||
136 | p = skip_whitespace(p); | ||
137 | } | ||
127 | 138 | ||
128 | c = *p++; | 139 | c = *p++; |
129 | if (isdigit(c)) | 140 | if (isdigit(c)) |
@@ -132,7 +143,16 @@ static void reverse(unsigned opt, const char *filename) | |||
132 | val |= (c|0x20) - ('a' - 10); | 143 | val |= (c|0x20) - ('a' - 10); |
133 | else { | 144 | else { |
134 | if (c != '\0') { | 145 | if (c != '\0') { |
135 | /* "...3<not_hex_char>..." ignores both chars */ | 146 | /* "...3<not_hex_char>...": ignore "3", |
147 | * skip everything up to next hexchar or newline: | ||
148 | */ | ||
149 | while (!isxdigit(*p)) { | ||
150 | if (*p == '\0') { | ||
151 | free(buf); | ||
152 | goto get_new_line; | ||
153 | } | ||
154 | p++; | ||
155 | } | ||
136 | goto nibble1; | 156 | goto nibble1; |
137 | } | 157 | } |
138 | /* Nibbles can join even through newline: | 158 | /* Nibbles can join even through newline: |
@@ -143,10 +163,12 @@ static void reverse(unsigned opt, const char *filename) | |||
143 | p = buf = xmalloc_fgetline(fp); | 163 | p = buf = xmalloc_fgetline(fp); |
144 | if (!buf) | 164 | if (!buf) |
145 | break; | 165 | break; |
166 | if (!(opt & OPT_p)) /* -p and !-p: different behavior */ | ||
167 | goto skip_address; | ||
146 | goto nibble2; | 168 | goto nibble2; |
147 | } | 169 | } |
148 | putchar(val); | 170 | putchar(val); |
149 | } | 171 | } /* for(;;) */ |
150 | free(buf); | 172 | free(buf); |
151 | } | 173 | } |
152 | //fclose(fp); | 174 | //fclose(fp); |