diff options
-rw-r--r-- | coreutils/od.c | 55 | ||||
-rw-r--r-- | libbb/dump.c | 30 | ||||
-rwxr-xr-x | testsuite/od.tests | 83 |
3 files changed, 100 insertions, 68 deletions
diff --git a/coreutils/od.c b/coreutils/od.c index dcf1bd6..6d562ea 100644 --- a/coreutils/od.c +++ b/coreutils/od.c @@ -22,7 +22,7 @@ //usage:#if !ENABLE_DESKTOP //usage:#define od_trivial_usage -//usage: "[-aBbcDdeFfHhIiLlOovXx] [FILE]" +//usage: "[-aBbcDdeFfHhIiLlOoXxsv] [FILE]" //usage:#define od_full_usage "\n\n" //usage: "Print FILE (or stdin) unambiguously, as octal bytes by default" //usage:#endif @@ -144,29 +144,42 @@ odoffset(dumper_t *dumper, int argc, char ***argvp) } } +// A format string contains format units separated by whitespace. +// A format unit contains up to three items: an iteration count, a byte count, +// and a format. +// The iteration count is an optional integer (default 1) +// Each format is applied iteration count times. +// The byte count is an optional integer. It defines the number +// of bytes to be interpreted by each iteration of the format. +// If an iteration count and/or a byte count is specified, a slash must be +// placed after the iteration count and/or before the byte count +// to disambiguate them. +// The format is required and must be surrounded by " "s. +// It is a printf-style format. static const char *const add_strings[] ALIGN_PTR = { - "16/1 \"%3_u \" \"\\n\"", /* a */ - "8/2 \" %06o \" \"\\n\"", /* B, o */ - "16/1 \"%03o \" \"\\n\"", /* b */ - "16/1 \"%3_c \" \"\\n\"", /* c */ - "8/2 \" %05u \" \"\\n\"", /* d */ - "4/4 \" %010u \" \"\\n\"", /* D */ - "2/8 \" %21.14e \" \"\\n\"", /* e (undocumented in od), F */ - "4/4 \" %14.7e \" \"\\n\"", /* f */ - "4/4 \" %08x \" \"\\n\"", /* H, X */ - "8/2 \" %04x \" \"\\n\"", /* h, x */ - "4/4 \" %11d \" \"\\n\"", /* I, L, l */ - "8/2 \" %6d \" \"\\n\"", /* i */ - "4/4 \" %011o \" \"\\n\"", /* O */ + "16/1 \"%3_u \" \"\\n\"", /* 0: a */ + "8/2 \"%06o \" \"\\n\"", /* 1: B (undocumented in od), o */ + "16/1 \"%03o \" \"\\n\"", /* 2: b */ + "16/1 \"%3_c \" \"\\n\"", /* 3: c */ + "8/2 \"%5u \" \"\\n\"", /* 4: d */ + "4/4 \"%10u \" \"\\n\"", /* 5: D */ + "2/8 \"%24.14e \" \"\\n\"", /* 6: e (undocumented in od), F */ + "4/4 \"%15.7e \" \"\\n\"", /* 7: f */ + "4/4 \"%08x \" \"\\n\"", /* 8: H, X */ + "8/2 \"%04x \" \"\\n\"", /* 9: h, x */ + "2/8 \"%20lld \" \"\\n\"", /* 10: I, L, l */ + "4/4 \"%11d \" \"\\n\"", /* 11: i */ + "4/4 \"%011o \" \"\\n\"", /* 12: O */ + "8/2 \"%6d \" \"\\n\"", /* 13: s */ }; -static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv"; +static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxsv"; static const char od_o2si[] ALIGN1 = { - 0, 1, 2, 3, 5, - 4, 6, 6, 7, 8, - 9, 0xa, 0xb, 0xa, 0xa, - 0xc, 1, 8, 9, + 0, 1, 2, 3, 5, /* aBbcD */ + 4, 6, 6, 7, 8, /* deFfH */ + 9, 10, 11, 10, 10, /* hIiLl */ + 12, 1, 8, 9, 13 /* OoXxs */ }; int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -184,9 +197,9 @@ int od_main(int argc, char **argv) if (first) { first = 0; bb_dump_add(dumper, "\"%07.7_Ao\n\""); - bb_dump_add(dumper, "\"%07.7_ao \""); + bb_dump_add(dumper, "\"%07.7_ao \""); } else { - bb_dump_add(dumper, "\" \""); + bb_dump_add(dumper, "\" \""); } bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); } else { /* P, p, s, w, or other unhandled */ diff --git a/libbb/dump.c b/libbb/dump.c index fcdee83..cfb9d94 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -187,6 +187,10 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) ++p2; ++p1; + if (*p1 == 'l') { /* %lld etc */ + ++p2; + ++p1; + } DO_INT_CONV: e = strchr(int_convs, *p1); /* "diouxX"? */ if (!e) @@ -194,7 +198,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) pr->flags = F_INT; if (e > int_convs + 1) /* not d or i? */ pr->flags = F_UINT; - byte_count_str = "\004\002\001"; + byte_count_str = "\010\004\002\001"; goto DO_BYTE_COUNT; } else if (strchr(int_convs, *p1)) { /* %d etc */ @@ -601,22 +605,32 @@ static NOINLINE void display(priv_dumper_t* dumper) break; } case F_INT: { - int ival; - short sval; + union { + uint16_t val16; + uint32_t val32; + uint64_t val64; + } u; + int value = *bp; switch (pr->bcnt) { case 1: - printf(pr->fmt, (int) *bp); break; case 2: - memcpy(&sval, bp, sizeof(sval)); - printf(pr->fmt, (int) sval); + memcpy(&u.val16, bp, 2); + value = u.val16; break; case 4: - memcpy(&ival, bp, sizeof(ival)); - printf(pr->fmt, ival); + memcpy(&u.val32, bp, 4); + value = u.val32; break; + case 8: + memcpy(&u.val64, bp, 8); +//A hack. Users _must_ use %llX formats to not truncate high bits + printf(pr->fmt, (long long) u.val64); + goto skip; } + printf(pr->fmt, value); + skip: break; } case F_P: diff --git a/testsuite/od.tests b/testsuite/od.tests index 0b949d5..500e0e6 100755 --- a/testsuite/od.tests +++ b/testsuite/od.tests @@ -9,14 +9,19 @@ input="$(printf '\001\002\003\nABC\xfe')" le=false -{ printf '\0\1' | od -i | grep -q 256; } && le=true +{ printf '\0\1' | od -s | grep -q 256; } && le=true readonly le +# NB: +# sed 's/ *$//' truncates trailing spaces. +# This needs to be fixed properly (not output them). +# For now, the tests ignore them (does not require a match). + optional !DESKTOP testing "od -a (!DESKTOP)" \ - "od -a" \ + "od -a | sed 's/ *$//'" \ "\ -0000000 soh stx etx lf A B C fe +0000000 soh stx etx lf A B C fe 0000010 " \ "" "$input" @@ -24,9 +29,9 @@ SKIP= optional !DESKTOP testing "od -B (!DESKTOP)" \ - "od -B" \ + "od -B | sed 's/ *$//'" \ "\ -0000000 001001 005003 041101 177103 +0000000 001001 005003 041101 177103 0000010 " \ "" "$input" @@ -35,9 +40,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -o (!DESKTOP little-endian)" \ - "od -o" \ + "od -o | sed 's/ *$//'" \ "\ -0000000 001001 005003 041101 177103 +0000000 001001 005003 041101 177103 0000010 " \ "" "$input" @@ -45,9 +50,9 @@ SKIP= optional !DESKTOP testing "od -b (!DESKTOP)" \ - "od -b" \ + "od -b | sed 's/ *$//'" \ "\ -0000000 001 002 003 012 101 102 103 376 +0000000 001 002 003 012 101 102 103 376 0000010 " \ "" "$input" @@ -55,9 +60,9 @@ SKIP= optional !DESKTOP testing "od -c (!DESKTOP)" \ - "od -c" \ + "od -c | sed 's/ *$//'" \ "\ -0000000 001 002 003 \\\\n A B C 376 +0000000 001 002 003 \\\\n A B C 376 0000010 " \ "" "$input" @@ -66,9 +71,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -d (!DESKTOP little-endian)" \ - "od -d" \ + "od -d | sed 's/ *$//'" \ "\ -0000000 00513 02563 16961 65091 +0000000 513 2563 16961 65091 0000010 " \ "" "$input" @@ -77,9 +82,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -D (!DESKTOP little-endian)" \ - "od -D" \ + "od -D | sed 's/ *$//'" \ "\ -0000000 0167969281 4265820737 +0000000 167969281 4265820737 0000010 " \ "" "$input" @@ -88,9 +93,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -e (!DESKTOP little-endian)" \ - "od -e" \ + "od -e | sed 's/ *$//'" \ "\ -0000000 -1.61218556514036e+300 +0000000 -1.61218556514036e+300 0000010 " \ "" "$input" @@ -99,9 +104,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -F (!DESKTOP little-endian)" \ - "od -F" \ + "od -F | sed 's/ *$//'" \ "\ -0000000 -1.61218556514036e+300 +0000000 -1.61218556514036e+300 0000010 " \ "" "$input" @@ -109,9 +114,9 @@ testing "od -F (!DESKTOP little-endian)" \ optional !DESKTOP $le || SKIP=1 testing "od -f (!DESKTOP little-endian)" \ - "od -f" \ + "od -f | sed 's/ *$//'" \ "\ -0000000 6.3077975e-33 -6.4885867e+37 +0000000 6.3077975e-33 -6.4885867e+37 0000010 " \ "" "$input" @@ -120,9 +125,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -H (!DESKTOP little-endian)" \ - "od -H" \ + "od -H | sed 's/ *$//'" \ "\ -0000000 0a030201 fe434241 +0000000 0a030201 fe434241 0000010 " \ "" "$input" @@ -131,9 +136,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -X (!DESKTOP little-endian)" \ - "od -X" \ + "od -X | sed 's/ *$//'" \ "\ -0000000 0a030201 fe434241 +0000000 0a030201 fe434241 0000010 " \ "" "$input" @@ -142,9 +147,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -h (!DESKTOP little-endian)" \ - "od -h" \ + "od -h | sed 's/ *$//'" \ "\ -0000000 0201 0a03 4241 fe43 +0000000 0201 0a03 4241 fe43 0000010 " \ "" "$input" @@ -153,9 +158,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -x (!DESKTOP little-endian)" \ - "od -x" \ + "od -x | sed 's/ *$//'" \ "\ -0000000 0201 0a03 4241 fe43 +0000000 0201 0a03 4241 fe43 0000010 " \ "" "$input" @@ -164,9 +169,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -I (!DESKTOP little-endian)" \ - "od -I" \ + "od -I | sed 's/ *$//'" \ "\ -0000000 167969281 -29146559 +0000000 -125183517527965183 0000010 " \ "" "$input" @@ -175,9 +180,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -L (!DESKTOP little-endian)" \ - "od -L" \ + "od -L | sed 's/ *$//'" \ "\ -0000000 167969281 -29146559 +0000000 -125183517527965183 0000010 " \ "" "$input" @@ -186,9 +191,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -i (!DESKTOP little-endian)" \ - "od -i" \ + "od -i | sed 's/ *$//'" \ "\ -0000000 513 2563 16961 -445 +0000000 167969281 -29146559 0000010 " \ "" "$input" @@ -197,9 +202,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -O (!DESKTOP little-endian)" \ - "od -O" \ + "od -O | sed 's/ *$//'" \ "\ -0000000 01200601001 37620641101 +0000000 01200601001 37620641101 0000010 " \ "" "$input" @@ -208,9 +213,9 @@ SKIP= optional !DESKTOP $le || SKIP=1 testing "od -l (!DESKTOP little-endian)" \ - "od -l" \ + "od -l | sed 's/ *$//'" \ "\ -0000000 167969281 -29146559 +0000000 -125183517527965183 0000010 " \ "" "$input" |