[git commit] od: for !DESKTOP, match output more closely to GNU coreutils 9.1, implement -s

Denys Vlasenko vda.linux at googlemail.com
Thu May 25 15:40:20 UTC 2023


commit: https://git.busybox.net/busybox/commit/?id=e2287f99fe6f21fd6435ad04340170ad4ba5f6b3
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 coreutils/od.c     | 55 ++++++++++++++++++++++--------------
 libbb/dump.c       | 30 ++++++++++++++------
 testsuite/od.tests | 83 +++++++++++++++++++++++++++++-------------------------
 3 files changed, 100 insertions(+), 68 deletions(-)

diff --git a/coreutils/od.c b/coreutils/od.c
index dcf1bd6f6..6d562ea91 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 fcdee8343..cfb9d94f9 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 0b949d5f0..500e0e638 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"


More information about the busybox-cvs mailing list