changeset 20210:29eb47fe8e8c

Add support for octal and hex escape sequences in single-quoted *printf arguments (bug #39774). * NEWS: Announce support for octal and hex escape sequences in single quoted strings. * utils.cc (do_string_escapes): Add case statements for hex and octal escape sequences and convert strings to numbers. * utils.cc (Fdo_string_escapes): Add BIST tests for octal and hex escape sequences.
author Rik <rik@octave.org>
date Wed, 20 May 2015 17:18:41 -0700
parents abf85f8cbd6c
children f2bc7d23295d
files NEWS libinterp/corefcn/utils.cc
diffstat 2 files changed, 70 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed May 20 08:01:10 2015 -0700
+++ b/NEWS	Wed May 20 17:18:41 2015 -0700
@@ -1,6 +1,11 @@
 Summary of important user-visible changes for version 4.2:
 ---------------------------------------------------------
 
+ ** Octal ('\NNN') and hex ('\xNN') escape sequences in single quoted
+    strings are now interpreted by the function do_string_escapes().
+    The *printf family of functions now supports octal and hex escape
+    sequences in single-quoted strings for Matlab compatibility.
+
  ** mkfifo now interprets the MODE argument as an octal, not decimal, integer.
     This is consistent with the equivalent shell command. 
 
--- a/libinterp/corefcn/utils.cc	Wed May 20 08:01:10 2015 -0700
+++ b/libinterp/corefcn/utils.cc	Wed May 20 17:18:41 2015 -0700
@@ -631,11 +631,7 @@
         {
           switch (s[++j])
             {
-            case '0':
-              retval[i] = '\0';
-              break;
-
-            case 'a':
+            case 'a': // alarm
               retval[i] = '\a';
               break;
 
@@ -675,6 +671,58 @@
               retval[i] = '"';
               break;
 
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7': // octal input
+            {
+              size_t k;
+              int tmpi = s[j] - '0';
+              for (k = j+1; k < std::min (j+3, len); k++)
+                {
+                  int digit = s[k] - '0';
+                  if (digit < 0 || digit > 7)
+                    break;
+                  tmpi <<= 3;
+                  tmpi += digit;
+                }
+              retval[i] = tmpi;
+              j = k - 1;
+              break;
+            }
+
+            case 'x': // hex input
+            {
+              size_t k;
+              int tmpi = 0;
+              for (k = j+1; k < std::min (j+3, len); k++)
+                {
+                  if (! isxdigit (s[k]))
+                    break;
+
+                  tmpi <<= 4;
+                  int digit = s[k];
+                  if (digit >= 'a')
+                    tmpi += digit - 'a' + 10;
+                  else if (digit >= 'A')
+                    tmpi += digit - 'A' + 10;
+                  else
+                    tmpi += digit - '0';
+                }
+
+              if (k == j+1)
+                warning ("malformed hex escape sequence '\\x' --\
+ converting to '\\0'");
+
+              retval[i] = tmpi;
+              j = k - 1;
+              break;
+            }
+
             default:
               warning ("unrecognized escape sequence '\\%c' --\
  converting to '%c'", s[j], s[j]);
@@ -745,9 +793,20 @@
 %!assert (do_string_escapes ('\"double-quoted\"'), "\"double-quoted\"")
 %!assert (do_string_escapes ("\\\"double-quoted\\\""), "\"double-quoted\"")
 
+%!assert (do_string_escapes ('A\4B'), ["A" char(4) "B"])
+%!assert (do_string_escapes ('A\45B'), ["A" char(37) "B"])
+%!assert (do_string_escapes ('A\123B'), ["A" char(83) "B"])
+%!assert (sprintf ('\117\143\164\141\166\145'), "Octave")
+
+%!assert (do_string_escapes ('A\x4G'), ["A" char(4) "G"])
+%!assert (do_string_escapes ('A\x4AG'), ["A" char(74) "G"])
+%!assert (sprintf ('\x4f\x63\x74\x61\x76\x65'), "Octave")
+
 %!error do_string_escapes ()
 %!error do_string_escapes ("foo", "bar")
-%!error do_string_escapes (3)
+%!error <STRING argument> do_string_escapes (3)
+%!warning <malformed hex escape sequence> do_string_escapes ('\xG');
+%!warning <unrecognized escape sequence> do_string_escapes ('\G');
 */
 
 const char *