Commit 8435351581

hryx <codroid@gmail.com>
2019-06-25 07:37:19
Escape C string literals
1 parent f845994
Changed files (1)
src-self-hosted
src-self-hosted/translate_c.zig
@@ -678,10 +678,20 @@ fn transStringLiteral(
     const kind = ZigClangStringLiteral_getKind(stmt);
     switch (kind) {
         .Ascii, .UTF8 => {
-            var len: usize = undefined;
-            const cstr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len);
+            var clen: usize = undefined;
+            const cstr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &clen);
             const zstr = try rp.c.str(cstr);
-            const token = try appendTokenFmt(rp.c, .StringLiteral, "c\"{}\"", zstr); // TODO: escape string
+
+            var len: usize = 0;
+            for (zstr) |c| len += escapeChar(c).len;
+
+            const buf = try rp.c.a().alloc(u8, len + "c\"\"".len);
+            buf[0] = 'c';
+            buf[1] = '"';
+            writeEscapedString(buf[2..], zstr);
+            buf[buf.len - 1] = '"';
+
+            const token = try appendToken(rp.c, .StringLiteral, buf);
             const node = try rp.c.a().create(ast.Node.StringLiteral);
             node.* = ast.Node.StringLiteral{
                 .base = ast.Node{ .id = .StringLiteral },
@@ -704,6 +714,37 @@ fn transStringLiteral(
     }
 }
 
+fn escapedStringLen(s: []const u8) usize {
+    var len: usize = 0;
+    for (s) |c| len += escapeChar(c).len;
+    return len;
+}
+
+fn writeEscapedString(buf: []u8, s: []const u8) void {
+    var i: usize = 0;
+    for (s) |c| {
+        const escaped = escapeChar(c);
+        std.mem.copy(u8, buf[i..], escaped);
+        i += escaped.len;
+    }
+}
+
+fn escapeChar(c: u8) []const u8 {
+    // TODO: https://github.com/ziglang/zig/issues/2749
+    switch (c) {
+        // Printable ASCII except for ' " \
+        ' ', '!', '#'...'&', '('...'[', ']'...'~' => return ([_]u8{c})[0..],
+        '\'', '\"', '\\' => return ([_]u8{ '\\', c })[0..],
+        '\n' => return "\\n"[0..],
+        '\r' => return "\\r"[0..],
+        '\t' => return "\\t"[0..],
+        else => {
+            var buf: [4]u8 = undefined;
+            return std.fmt.bufPrint(buf[0..], "\\x{x2}", c) catch unreachable;
+        },
+    }
+}
+
 fn transCCast(
     rp: RestorePoint,
     scope: *Scope,