]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
od: fix '+N.' bug
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 29 Jun 2025 00:29:22 +0000 (17:29 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 29 Jun 2025 04:00:41 +0000 (21:00 -0700)
* src/od.c (parse_old_offset): First arg is now char *,
not char const *.  If a decimal number, temporarily
modify the string so that xstrtoumax does not complain
about the '.'.
* tests/od/od.pl: Test for the bug.

NEWS
src/od.c
tests/od/od.pl

diff --git a/NEWS b/NEWS
index 4a958770c7b4a3c971ee0086d0fa2907a2f38b58..d0b6e794a7fab194105d489dc69fc8278d91b53e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   Instead, it either outputs correctly or diagnoses a too-large width.
   [This bug was present in "the beginning".]
 
+  od +N. (where N is a decimal number) works again as per POSIX.
+  [bug introduced on 1995-01-25]
+
   sort with key character offsets of SIZE_MAX, could induce
   a read of 1 byte before an allocated heap buffer. For example:
   'sort +0.18446744073709551615R input' on 64 bit systems.
index 8bb463ca8bf67b5b0fc1c51cc7b596741358c6bb..fd5fc45bd4129f58da34864afbde6382fc4de9c8 100644 (file)
--- a/src/od.c
+++ b/src/od.c
@@ -1402,7 +1402,7 @@ get_lcm (void)
    leading '+' return true and set *OFFSET to the offset it denotes.  */
 
 static bool
-parse_old_offset (char const *s, uintmax_t *offset)
+parse_old_offset (char *s, uintmax_t *offset)
 {
   int radix;
 
@@ -1414,10 +1414,24 @@ parse_old_offset (char const *s, uintmax_t *offset)
     ++s;
 
   /* Determine the radix we'll use to interpret S.  If there is a '.',
+     optionally followed by 'B' or 'b' and then end of string,
      it's decimal, otherwise, if the string begins with '0X'or '0x',
      it's hexadecimal, else octal.  */
-  if (strchr (s, '.') != nullptr)
-    radix = 10;
+  char *dot = strchr (s, '.');
+  if (dot)
+    {
+      bool b = dot[1] == 'B' || dot[1] == 'b';
+      if (dot[b + 1])
+        dot = nullptr;
+    }
+
+  if (dot)
+    {
+      /* Temporarily remove the '.' from the decimal string.  */
+      dot[0] = dot[1];
+      dot[1] = '\0';
+      radix = 10;
+    }
   else
     {
       if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
@@ -1426,7 +1440,16 @@ parse_old_offset (char const *s, uintmax_t *offset)
         radix = 8;
     }
 
-  return xstrtoumax (s, nullptr, radix, offset, "Bb") == LONGINT_OK;
+  enum strtol_error s_err = xstrtoumax (s, nullptr, radix, offset, "Bb");
+
+  if (dot)
+    {
+      /* Restore the decimal string's original value.  */
+      dot[1] = dot[0];
+      dot[0] = '.';
+    }
+
+  return s_err == LONGINT_OK;
 }
 
 /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
index 5bb271e607febc803110e54582cc8f75c5cd70de..9688607c6e79889f2b474269288ecb5a6c882731 100755 (executable)
@@ -60,6 +60,10 @@ my @Tests =
      ['j-proc', "-An -c -j $proc_file_byte_count $proc_file",
                                {IN=>{f2=>'e'}}, {OUT=>"   e\n"}],
 
+     # Check that the traditional form '+N.' works, as per POSIX.
+     ['trad-dot1', '+1.', {IN_PIPE=>'a'}, {OUT=>"0000001\n"}],
+     ['trad-dot512', '+1.b', {IN_PIPE => 'a' x 512}, {OUT=>"0001000\n"}],
+
      # Ensure that a large width does not cause trouble.
      # From coreutils-7.0 through coreutils-8.21, these would print
      # approximately 128KiB of padding.