Skip to content

std: add fmt option to escape non-printable characters #6218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 2, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lib/std/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
/// - output numeric value in hexadecimal notation
/// - `s`: print a pointer-to-many as a c-string, use zero-termination
/// - `B` and `Bi`: output a memory size in either metric (1000) or power-of-two (1024) based notation. works for both float and integer values.
/// - `e` and `E`: if printing a string, escape non-printable characters
/// - `e`: output floating point value in scientific notation
/// - `d`: output numeric value in decimal notation
/// - `b`: output integer value in binary notation
Expand Down Expand Up @@ -599,6 +600,16 @@ pub fn formatText(
try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, writer);
}
return;
} else if (comptime (std.mem.eql(u8, fmt, "e") or std.mem.eql(u8, fmt, "E"))) {
for (bytes) |c| {
if (std.ascii.isPrint(c)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we consider \t, \n and \r printable? (#4014)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For purposes of a debug print: I don't think they should be considered printable:

  • its hard to visually tell the difference between a tab that is one space wide an a normal space character.
  • I imagine this would often be used for line based output, where escaping newlines is desired.
  • \r is unprintable

try writer.writeByte(c);
} else {
try writer.writeAll("\\x");
try formatInt(c, 16, fmt[0] == 'E', FormatOptions{ .width = 2, .fill = '0' }, writer);
}
}
return;
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
Expand Down Expand Up @@ -1319,6 +1330,12 @@ test "slice" {
try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
}

test "escape non-printable" {
try testFmt("abc", "{e}", .{"abc"});
try testFmt("ab\\xffc", "{e}", .{"ab\xffc"});
try testFmt("ab\\xFFc", "{E}", .{"ab\xffc"});
}

test "pointer" {
{
const value = @intToPtr(*align(1) i32, 0xdeadbeef);
Expand Down