# HG changeset patch # User Rik # Date 1432167521 25200 # Node ID 29eb47fe8e8c68c59cf7769336fc6e109bea9be7 # Parent abf85f8cbd6c33fc7bd5c6641414cdc28714d308 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. diff -r abf85f8cbd6c -r 29eb47fe8e8c NEWS --- 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. diff -r abf85f8cbd6c -r 29eb47fe8e8c libinterp/corefcn/utils.cc --- 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 do_string_escapes (3) +%!warning do_string_escapes ('\xG'); +%!warning do_string_escapes ('\G'); */ const char *