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); |
