Paul Eggert wrote:
> As a minor point, both uses like this:
> 
> '4' <= *p && *p <= '7'
> 
> can be replaced with something like this:
> 
> '4' <= *p
> 
...
> 
> The replacements are not only shorter, but easier
> to understand, because otherwise the reader is left
> wondering why that unnecessary comparison to '7'
> (or '0') is in there.

Yep, you are right - as the octal value of *p/*b is checked later, this
shorter way is better readable and shorter.
Added the NEWS entry in addition to address Eric's email.

Greetings,
         Ondrej Vasik
>From 81802d8daf94684300b55272d171e65b53d5fede Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Va=C5=A1=C3=ADk?= <[email protected]>
Date: Mon, 6 Dec 2010 17:10:31 +0100
Subject: [PATCH] echo,printf,stat: Allow only 8-bit octal input for backslash-escaped chars

* src/echo.c: (usage) Document \NNN octal format in --help
              (main) Allow only 8-bit octal input for backslash-escaped chars
* src/printf.c: (print_esc) Likewise
* src/stat.c:   (print_it)  Likewise
* doc/coreutils.texi: Clarify printf documentation about byte octal input
* tests/misc/printf: Add test for "like 9-bit" octal value backslash-escaped
                     char
---
 NEWS               |    4 ++++
 doc/coreutils.texi |    6 +++---
 src/echo.c         |    7 ++++++-
 src/printf.c       |   10 +++++++---
 src/stat.c         |    4 +++-
 tests/misc/printf  |    3 +++
 6 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/NEWS b/NEWS
index c3110a3..c8a45ee 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   sort -u with at least two threads could attempt to read through a
   corrupted pointer. [bug introduced in coreutils-8.6]
 
+  echo, printf and stat now don't allow 9-bit octal values for
+  backslash-escaped chars.
+
+
 ** New features
 
   split accepts the --number option to generate a specific number of files.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 34d9ff0..11a9d16 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11116,9 +11116,9 @@ the command @samp{printf %g 3,14} is an error.
 @kindex \...@var{ooo}
 @kindex \...@var{hh}
 @command{printf} interprets @sam...@var{ooo}} in @var{format} as an octal number
-(if @var{ooo} is 1 to 3 octal digits) specifying a character to print,
-and @samp...@var{hh}} as a hexadecimal number (if @var{hh} is 1 to 2 hex
-digits) specifying a character to print.
+(if @var{ooo} is 1 to 3 octal digits byte value) specifying a character
+to print, and @samp...@var{hh}} as a hexadecimal number (if @var{hh} is
+1 to 2 hex digits) specifying a character to print.
 
 @kindex \uhhhh
 @kindex \Uhhhhhhhh
diff --git a/src/echo.c b/src/echo.c
index 6a1eeed..b72dcd5 100644
--- a/src/echo.c
+++ b/src/echo.c
@@ -78,6 +78,7 @@ If -e is in effect, the following sequences are recognized:\n\
 "), stdout);
       fputs (_("\
   \\0NNN   byte with octal value NNN (1 to 3 digits)\n\
+  \\NNN    byte with octal value NNN (1 to 3 digits)\n\
   \\xHH    byte with hexadecimal value HH (1 to 2 digits)\n\
 "), stdout);
       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
@@ -197,6 +198,7 @@ just_echo:
         {
           char const *s = argv[0];
           unsigned char c;
+          bool threeoctdigits = false;
 
           while ((c = *s++))
             {
@@ -235,12 +237,15 @@ just_echo:
                       c = *s++;
                       /* Fall through.  */
                     case '1': case '2': case '3':
+                      if (c < '4')
+                        threeoctdigits = true;
                     case '4': case '5': case '6': case '7':
                       c -= '0';
                       if ('0' <= *s && *s <= '7')
                         c = c * 8 + (*s++ - '0');
-                      if ('0' <= *s && *s <= '7')
+                      if (threeoctdigits && '0' <= *s && *s <= '7')
                         c = c * 8 + (*s++ - '0');
+                      threeoctdigits = false;
                       break;
                     case '\\': break;
 
diff --git a/src/printf.c b/src/printf.c
index 1f5451e..ca05118 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -236,6 +236,7 @@ print_esc (const char *escstart, bool octal_0)
   const char *p = escstart + 1;
   int esc_value = 0;		/* Value of \nnn escape. */
   int esc_length;		/* Length of \nnn escape. */
+  int max_octdigits = 3;        /* Maximum length of byte octal input. */
 
   if (*p == 'x')
     {
@@ -252,9 +253,12 @@ print_esc (const char *escstart, bool octal_0)
     {
       /* Parse \0ooo (if octal_0 && *p == '0') or \ooo (otherwise).
          Allow \ooo if octal_0 && *p != '0'; this is an undocumented
-         extension to POSIX that is compatible with Bash 2.05b.  */
-      for (esc_length = 0, p += octal_0 && *p == '0';
-           esc_length < 3 && isodigit (*p);
+         extension to POSIX that is compatible with Bash 2.05b.
+         If the octal character begins with number 4 or higher,
+         only 2 octal digits fit to byte */
+      for (esc_length = 0, p += octal_0 && *p == '0',
+           max_octdigits -= '4' <= *p;
+           esc_length < max_octdigits && isodigit (*p);
            ++esc_length, ++p)
         esc_value = esc_value * 8 + octtobin (*p);
       putchar (esc_value);
diff --git a/src/stat.c b/src/stat.c
index b419f19..005aa8e 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -1096,7 +1096,9 @@ print_it (char const *format, char const *filename,
             {
               int esc_value = octtobin (*b);
               int esc_length = 1;	/* number of octal digits */
-              for (++b; esc_length < 3 && isodigit (*b);
+              int max_octdigits = 3;    /* maximum length of byte octal input */
+              for (max_octdigits -= '4' <= *b, ++b;
+                   esc_length < max_octdigits && isodigit (*b);
                    ++esc_length, ++b)
                 {
                   esc_value = esc_value * 8 + octtobin (*b);
diff --git a/tests/misc/printf b/tests/misc/printf
index b02352b..9c99853 100755
--- a/tests/misc/printf
+++ b/tests/misc/printf
@@ -72,6 +72,8 @@ POSIXLY_CORRECT=1 \
 
 "$prog" '11 %*c\n' 2 x >>out || fail=1
 
+"$prog" '12 \0610\n' >>out || fail=1
+
 "$prog" '%#d\n' 0 >>out 2> /dev/null && fail=1
 
 "$prog" '%0s\n' 0 >>out 2> /dev/null && fail=1
@@ -92,6 +94,7 @@ cat <<\EOF > exp
 9 0 x
 10 0x
 11  x
+12 10
 EOF
 
 compare out exp || fail=1
-- 
1.7.1

Reply via email to