From 8d5ca3b250bb59ee0711fc35287fabb27bb1c9f0 Mon Sep 17 00:00:00 2001 From: Dustin Taylor Date: Wed, 10 Aug 2022 21:01:00 -0400 Subject: [PATCH 1/3] initial windows console io fix --- lib/std/Progress.zig | 8 +-- lib/std/io.zig | 57 ++++++++++++++------- lib/std/io/console_reader.zig | 87 +++++++++++++++++++++++++++++++++ lib/std/io/console_writer.zig | 63 ++++++++++++++++++++++++ lib/std/io/reader.zig | 38 ++++++++++++++ lib/std/os/windows.zig | 39 +++++++++++++++ lib/std/os/windows/kernel32.zig | 17 +++++++ lib/std/unicode.zig | 17 +++++++ src/Compilation.zig | 7 ++- src/main.zig | 20 ++++---- src/print_env.zig | 2 +- src/print_zir.zig | 4 +- 12 files changed, 322 insertions(+), 37 deletions(-) create mode 100644 lib/std/io/console_reader.zig create mode 100644 lib/std/io/console_writer.zig diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index fe2f7bc795b0..d587da43e8b8 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -15,7 +15,7 @@ const Progress = @This(); /// `null` if the current node (and its children) should /// not print on update() -terminal: ?std.fs.File = undefined, +terminal: ?std.io.StdErrType = undefined, /// Is this a windows API terminal (note: this is not the same as being run on windows /// because other terminals exist like MSYS/git-bash) @@ -143,7 +143,7 @@ pub const Node = struct { /// API to return Progress rather than accept it as a parameter. /// `estimated_total_items` value of 0 means unknown. pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node { - const stderr = std.io.getStdErr(); + var stderr: std.io.StdErrType = std.io.getStdErr(); self.terminal = null; if (stderr.supportsAnsiEscapeCodes()) { self.terminal = stderr; @@ -196,7 +196,7 @@ fn refreshWithHeldLock(self: *Progress) void { const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; if (is_dumb and self.dont_print_on_dumb) return; - const file = self.terminal orelse return; + var file = self.terminal orelse return; var end: usize = 0; if (self.columns_written > 0) { @@ -297,7 +297,7 @@ fn refreshWithHeldLock(self: *Progress) void { } pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { - const file = self.terminal orelse { + var file = self.terminal orelse { std.debug.print(format, args); return; }; diff --git a/lib/std/io.zig b/lib/std/io.zig index 50d134b856a7..0cddf46ad38d 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -46,14 +46,20 @@ fn getStdOutHandle() os.fd_t { return os.STDOUT_FILENO; } +pub const StdOutType = if (builtin.os.tag == .windows) ConsoleWriter(4096) else File; + /// TODO: async stdout on windows without a dedicated thread. /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 -pub fn getStdOut() File { - return File{ - .handle = getStdOutHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = default_mode, - }; +pub fn getStdOut() StdOutType { + if (builtin.os.tag == .windows) { + return .{ .handle = getStdOutHandle() }; + } else { + return File{ + .handle = getStdOutHandle(), + .capable_io_mode = .blocking, + .intended_io_mode = default_mode, + }; + } } fn getStdErrHandle() os.fd_t { @@ -68,14 +74,20 @@ fn getStdErrHandle() os.fd_t { return os.STDERR_FILENO; } +pub const StdErrType = if (builtin.os.tag == .windows) ConsoleWriter(4096) else File; + /// This returns a `File` that is configured to block with every write, in order /// to facilitate better debugging. This can be changed by modifying the `intended_io_mode` field. -pub fn getStdErr() File { - return File{ - .handle = getStdErrHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = .blocking, - }; +pub fn getStdErr() StdErrType { + if (builtin.os.tag == .windows) { + return .{ .handle = getStdErrHandle() }; + } else { + return File{ + .handle = getStdErrHandle(), + .capable_io_mode = .blocking, + .intended_io_mode = .blocking, + }; + } } fn getStdInHandle() os.fd_t { @@ -90,14 +102,20 @@ fn getStdInHandle() os.fd_t { return os.STDIN_FILENO; } +pub const StdInType = if (builtin.os.tag == .windows) ConsoleReader(4096) else File; + /// TODO: async stdin on windows without a dedicated thread. /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 -pub fn getStdIn() File { - return File{ - .handle = getStdInHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = default_mode, - }; +pub fn getStdIn() StdInType { + if (builtin.os.tag == .windows) { + return .{ .handle = getStdInHandle() }; + } else { + return File{ + .handle = getStdInHandle(), + .capable_io_mode = .blocking, + .intended_io_mode = default_mode, + }; + } } pub const Reader = @import("io/reader.zig").Reader; @@ -149,6 +167,9 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt pub const StreamSource = @import("io/stream_source.zig").StreamSource; +pub const ConsoleReader = @import("io/console_reader.zig").ConsoleReader; +pub const ConsoleWriter = @import("io/console_writer.zig").ConsoleWriter; + /// A Writer that doesn't write to anything. pub const null_writer = @as(NullWriter, .{ .context = {} }); diff --git a/lib/std/io/console_reader.zig b/lib/std/io/console_reader.zig new file mode 100644 index 000000000000..11b379593c2b --- /dev/null +++ b/lib/std/io/console_reader.zig @@ -0,0 +1,87 @@ +const std = @import("std"); +const fifo = std.fifo; +const io = std.io; +const math = std.math; +const os = std.os; +const unicode = std.unicode; + +pub fn ConsoleReader(comptime u16_max_buffer_size: usize) type { + return struct { + const Self = @This(); + const FifoType = fifo.LinearFifo(u8, fifo.LinearFifoBufferType{ .Static = 4 }); + pub const Error = os.ReadError || error{InvalidUTF16LE}; + pub const Reader = io.Reader(*Self, Error, read); + + handle: os.fd_t, + surrogate: ?u16 = null, + fifo_utf8: FifoType = FifoType.init(), + + pub fn read(self: *Self, dest: []u8) Error!usize { + if (!os.isatty(self.handle)) { + // Non console handles should go straight to reading like a file + // Examples of this happening are when pipes are used as indicated in the docs + // https://docs.microsoft.com/en-us/windows/console/readconsole + return os.windows.ReadFile(self.handle, dest, null, .blocking); + } + + var dest_index: usize = 0; + while (dest_index < dest.len) { + // Read from a utf8 buffer for any potential missing bytes needed for a codepoint + const written = self.fifo_utf8.read(dest[dest_index..]); + if (written != 0) { + dest_index += written; + continue; + } + const delta_len = dest.len - dest_index; + if (delta_len < 4) { + // Not enough room is left in the destination buffer to handle larger codepoint lengths + // Read a character at a time and place the encoding utf8 bytes into a fifo buffer + self.fifo_utf8.realign(); + const n = try self.readConsoleToUtf8(self.fifo_utf8.writableSlice(0), 1); + if (n == 0) return dest_index; + self.fifo_utf8.update(n); + } else { + const n = try self.readConsoleToUtf8(dest[delta_len..], u16_max_buffer_size); + if (n == 0) return dest_index; + dest_index += n; + } + } + return dest.len; + } + + fn readConsoleToUtf8(self: *Self, dest: []u8, comptime u16_buffer_size: usize) Error!usize { + var utf16_buffer: [u16_buffer_size]u16 = undefined; + const end = if (u16_buffer_size > 1) math.min(dest.len / 3, u16_buffer_size) else u16_buffer_size; + + const n = try self.readConsole(utf16_buffer[0..end]); + if (n == 0) return n; + + return unicode.utf16leToUtf8(dest, utf16_buffer[0..n]) catch return Error.InvalidUTF16LE; + } + + fn readConsole(self: *Self, buffer: []u16) Error!usize { + if (buffer.len == 0) return 0; + var start: usize = 0; + if (self.surrogate != null) { + buffer[0] = self.surrogate.?; + self.surrogate = null; + start = 1; + } + + var n = try os.windows.ReadConsoleW(self.handle, buffer[start..], null); + + if (n > 0) { + const last_char = buffer[n - 1]; + if (0xd800 <= last_char and last_char <= 0xdfff) { + self.surrogate = last_char; + n -= 1; + } + } + return n; + } + + pub fn reader(self: *Self) Reader { + return .{ .context = self }; + } + }; +} diff --git a/lib/std/io/console_writer.zig b/lib/std/io/console_writer.zig new file mode 100644 index 000000000000..4ad1f34bad57 --- /dev/null +++ b/lib/std/io/console_writer.zig @@ -0,0 +1,63 @@ +const std = @import("std"); +const fifo = std.fifo; +const io = std.io; +const os = std.os; +const unicode = std.unicode; + +const File = std.fs.File; + +pub fn ConsoleWriter(comptime u16_max_buffer_size: usize) type { + return struct { + const Self = @This(); + pub const Error = os.WriteError || error{InvalidUtf8}; + pub const Writer = io.Writer(*Self, Error, write); + + handle: os.fd_t = undefined, + + pub fn isTty(self: Self) bool { + return os.isatty(self.handle); + } + + pub fn supportsAnsiEscapeCodes(self: Self) bool { + return os.isCygwinPty(self.handle); + } + + pub fn write(self: *Self, data: []const u8) Error!usize { + if (data.len == 0) return @as(usize, 0); + + if (!os.isatty(self.handle)) { + // Non console handles should go straight to reading like a file + // Examples of this happening are when pipes are used as indicated in the docs + // https://docs.microsoft.com/en-us/windows/console/writeconsole + return os.windows.WriteFile(self.handle, data, null, .blocking); + } + + var utf16 = [_]u16{0} ** u16_max_buffer_size; + const max_data_len = unicode.getClampedUtf8SizeForUtf16LeSize(data, utf16.len) catch return Error.InvalidUtf8; + const n = unicode.utf8ToUtf16Le(utf16[0..], data[0..max_data_len]) catch return Error.InvalidUtf8; + const m = try os.windows.WriteConsoleW(self.handle, utf16[0..n]); + + if (n != m) { + // If the number of u16s don't match between converted utf8 chars and what's written to console, + // We need to calculate the number of bytes written provided from Windows. + return unicode.getClampedUtf8SizeForUtf16LeSize(data, m) catch unreachable; + } + return max_data_len; + } + + pub fn writeAll(self: *Self, bytes: []const u8) Error!void { + var index: usize = 0; + while (index != bytes.len) { + index += try self.write(bytes[index..]); + } + } + + pub fn writeFileAll(self: *Self, in_file: File, args: File.WriteFileOptions) File.WriteFileError!void { + return (File{ .handle = self.handle }).writeFileAll(in_file, args); + } + + pub fn writer(self: *Self) Writer { + return .{ .context = self }; + } + }; +} diff --git a/lib/std/io/reader.zig b/lib/std/io/reader.zig index 16acef8e4814..cf3a4ceef08a 100644 --- a/lib/std/io/reader.zig +++ b/lib/std/io/reader.zig @@ -95,6 +95,44 @@ pub fn Reader( return array_list.toOwnedSlice(); } + /// Reads all the bytes from the current position to the end of the file. + /// On success, caller owns returned buffer. + /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. + /// If `size_hint` is specified the initial buffer size is calculated using + /// that value, otherwise an arbitrary value is used instead. + /// Allows specifying alignment and a sentinel value. + pub fn readToEndAllocOptions( + self: Self, + allocator: mem.Allocator, + max_bytes: usize, + size_hint: ?usize, + comptime alignment: u29, + comptime optional_sentinel: ?u8, + ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { + // If no size hint is provided fall back to the size=0 code path + const size = size_hint orelse 0; + + // The file size returned by stat is used as hint to set the buffer + // size. If the reported size is zero, as it happens on Linux for files + // in /proc, a small buffer is allocated instead. + const initial_cap = (if (size > 0) size else 1024) + @boolToInt(optional_sentinel != null); + var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap); + defer array_list.deinit(); + + self.readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) { + error.StreamTooLong => return error.FileTooBig, + else => |e| return e, + }; + + if (optional_sentinel) |sentinel| { + try array_list.append(sentinel); + const buf = array_list.toOwnedSlice(); + return buf[0 .. buf.len - 1 :sentinel]; + } else { + return array_list.toOwnedSlice(); + } + } + /// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found. /// Does not include the delimiter in the result. /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 3e42ee5f2d08..9b2fbd80f001 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -512,6 +512,21 @@ pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64, io_mode: std.io.Mo } } +pub fn ReadConsoleW(in_hFile: HANDLE, buffer: []u16, control: ?*CONSOLE_READCONSOLE_CONTROL) ReadFileError!usize { + const want_read_count = @intCast(DWORD, math.min(@as(DWORD, maxInt(DWORD)), buffer.len)); + var amt_read: DWORD = undefined; + + if (kernel32.ReadConsoleW(in_hFile, buffer.ptr, want_read_count, &amt_read, control) == 0) { + switch (kernel32.GetLastError()) { + .BROKEN_PIPE => return 0, + .HANDLE_EOF => return 0, + else => |err| return unexpectedError(err), + } + } + + return amt_read; +} + pub const WriteFileError = error{ SystemResources, OperationAborted, @@ -604,6 +619,23 @@ pub fn WriteFile( } } +pub fn WriteConsoleW(handle: HANDLE, buffer: []const u16) WriteFileError!usize { + var written: DWORD = undefined; + if (kernel32.WriteConsoleW(handle, buffer.ptr, @intCast(u32, buffer.len), &written, null) == 0) { + switch (kernel32.GetLastError()) { + .INVALID_USER_BUFFER => return error.SystemResources, + .NOT_ENOUGH_MEMORY => return error.SystemResources, + .OPERATION_ABORTED => return error.OperationAborted, + .NOT_ENOUGH_QUOTA => return error.SystemResources, + .IO_PENDING => unreachable, + .BROKEN_PIPE => return error.BrokenPipe, + .INVALID_HANDLE => return error.NotOpenForWriting, + else => |err| return unexpectedError(err), + } + } + return written; +} + pub const SetCurrentDirectoryError = error{ NameTooLong, InvalidUtf8, @@ -3722,3 +3754,10 @@ pub const HANDLER_ROUTINE = switch (builtin.zig_backend) { .stage1 => fn (dwCtrlType: DWORD) callconv(.C) BOOL, else => *const fn (dwCtrlType: DWORD) callconv(.C) BOOL, }; + +pub const CONSOLE_READCONSOLE_CONTROL = extern struct { + nLength: ULONG, + nInitialChars: ULONG, + dwCtrlWakeupMask: ULONG, + dwControlKeyState: ULONG, +}; diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig index 9e6f5df97bd7..e40a434f0f52 100644 --- a/lib/std/os/windows/kernel32.zig +++ b/lib/std/os/windows/kernel32.zig @@ -57,6 +57,7 @@ const UCHAR = windows.UCHAR; const FARPROC = windows.FARPROC; const INIT_ONCE_FN = windows.INIT_ONCE_FN; const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION; +const CONSOLE_READCONSOLE_CONTROL = windows.CONSOLE_READCONSOLE_CONTROL; pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque; pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong; @@ -284,6 +285,14 @@ pub extern "kernel32" fn ReadFile( in_out_lpOverlapped: ?*OVERLAPPED, ) callconv(WINAPI) BOOL; +pub extern "kernel32" fn ReadConsoleW( + in_hFile: HANDLE, + out_lpBuffer: [*]u16, + in_nNumberOfBytesToRead: DWORD, + out_lpNumberOfBytesRead: ?*DWORD, + in_pInputControl: ?*CONSOLE_READCONSOLE_CONTROL, +) callconv(WINAPI) BOOL; + pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(WINAPI) BOOL; pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL; @@ -348,6 +357,14 @@ pub extern "kernel32" fn WriteFile( in_out_lpOverlapped: ?*OVERLAPPED, ) callconv(WINAPI) BOOL; +pub extern "kernel32" fn WriteConsoleW( + in_hConsoleOutput: HANDLE, + in_lpBuffer: [*]const u16, + in_nNumberOfCharsToWrite: DWORD, + out_lpNumberOfCharsWritten: ?*DWORD, + reserved_lpReserved: ?LPVOID, +) callconv(WINAPI) BOOL; + pub extern "kernel32" fn WriteFileEx(hFile: HANDLE, lpBuffer: [*]const u8, nNumberOfBytesToWrite: DWORD, lpOverlapped: *OVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE) callconv(WINAPI) BOOL; pub extern "kernel32" fn LoadLibraryW(lpLibFileName: [*:0]const u16) callconv(WINAPI) ?HMODULE; diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 81a7ed838fe3..bf3d2a5f0184 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -775,6 +775,23 @@ fn calcUtf16LeLen(utf8: []const u8) usize { return dest_len; } +pub fn getClampedUtf8SizeForUtf16LeSize(utf8: []const u8, utf16le_size: usize) !usize { + var src_i: usize = 0; + var dest_len: usize = 0; + while (src_i < utf8.len) { + const n = try utf8ByteSequenceLength(utf8[src_i]); + const next_src_i = src_i + n; + const codepoint = try utf8Decode(utf8[src_i..next_src_i]); + + const u16_len: usize = if (codepoint < 0x10000) 1 else 2; + if (dest_len + u16_len > utf16le_size) return src_i; + dest_len += u16_len; + src_i = next_src_i; + } + + return src_i; +} + /// Print the given `utf16le` string fn formatUtf16le( utf16le: []const u16, diff --git a/src/Compilation.zig b/src/Compilation.zig index af39154a3f23..965791bccc57 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -381,8 +381,8 @@ pub const AllErrors = struct { pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void { std.debug.getStderrMutex().lock(); defer std.debug.getStderrMutex().unlock(); - const stderr = std.io.getStdErr(); - return msg.renderToWriter(ttyconf, stderr.writer(), "error", .Red, 0) catch return; + const stderr = std.io.getStdErr().writer(); + return msg.renderToWriter(ttyconf, stderr, "error", .Red, 0) catch return; } pub fn renderToWriter( @@ -4767,6 +4767,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable; \\pub const zig_backend = std.builtin.CompilerBackend.{}; + \\/// Temporary until self-hosted supports the `cpu.arch` value. + \\pub const stage2_arch: std.Target.Cpu.Arch = .{}; \\ \\pub const output_mode = std.builtin.OutputMode.{}; \\pub const link_mode = std.builtin.LinkMode.{}; @@ -4781,6 +4783,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca , .{ build_options.version, std.zig.fmtId(@tagName(zig_backend)), + std.zig.fmtId(@tagName(target.cpu.arch)), std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)), std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)), comp.bin_file.options.is_test, diff --git a/src/main.zig b/src/main.zig index c103cddcd45c..02b5335422dc 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3964,10 +3964,10 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi fn readSourceFileToEndAlloc( allocator: mem.Allocator, - input: *const fs.File, + input_reader: anytype, size_hint: ?usize, ) ![:0]u8 { - const source_code = input.readToEndAllocOptions( + const source_code = input_reader.readToEndAllocOptions( allocator, max_src_size, size_hint, @@ -4096,8 +4096,8 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void fatal("cannot use --stdin with positional arguments", .{}); } - const stdin = io.getStdIn(); - const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| { + const stdin = io.getStdIn().reader(); + const source_code = readSourceFileToEndAlloc(gpa, stdin, null) catch |err| { fatal("unable to read stdin: {}", .{err}); }; defer gpa.free(source_code); @@ -4227,7 +4227,7 @@ const FmtError = error{ NotOpenForWriting, UnsupportedEncoding, ConnectionResetByPeer, -} || fs.File.OpenError; +} || fs.File.OpenError || io.StdErrType.Error; fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) { @@ -5033,8 +5033,8 @@ pub fn cmdAstCheck( .mtime = stat.mtime, }; } else { - const stdin = io.getStdIn(); - const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| { + const stdin = io.getStdIn().reader(); + const source = readSourceFileToEndAlloc(arena, stdin, null) catch |err| { fatal("unable to read stdin: {}", .{err}); }; file.sub_file_path = ""; @@ -5094,10 +5094,10 @@ pub fn cmdAstCheck( const extra_bytes = file.zir.extra.len * @sizeOf(u32); const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + file.zir.string_bytes.len * @sizeOf(u8); - const stdout = io.getStdOut(); + const stdout = io.getStdOut().writer(); const fmtIntSizeBin = std.fmt.fmtIntSizeBin; // zig fmt: off - try stdout.writer().print( + try stdout.print( \\# Source bytes: {} \\# Tokens: {} ({}) \\# AST Nodes: {} ({}) @@ -5118,7 +5118,7 @@ pub fn cmdAstCheck( // zig fmt: on } - return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut()); + return @import("print_zir.zig").renderAsTextToFileWriter(gpa, &file, io.getStdOut().writer()); } /// This is only enabled for debug builds. diff --git a/src/print_env.zig b/src/print_env.zig index ad772d416b66..982e3fb424fa 100644 --- a/src/print_env.zig +++ b/src/print_env.zig @@ -4,7 +4,7 @@ const introspect = @import("introspect.zig"); const Allocator = std.mem.Allocator; const fatal = @import("main.zig").fatal; -pub fn cmdEnv(gpa: Allocator, args: []const []const u8, stdout: std.fs.File.Writer) !void { +pub fn cmdEnv(gpa: Allocator, args: []const []const u8, stdout: std.io.StdOutType.Writer) !void { _ = args; const self_exe_path = try introspect.findZigExePath(gpa); defer gpa.free(self_exe_path); diff --git a/src/print_zir.zig b/src/print_zir.zig index 4bc96c42591c..428f8ac2b4b4 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -9,10 +9,10 @@ const Module = @import("Module.zig"); const LazySrcLoc = Module.LazySrcLoc; /// Write human-readable, debug formatted ZIR code to a file. -pub fn renderAsTextToFile( +pub fn renderAsTextToFileWriter( gpa: Allocator, scope_file: *Module.File, - fs_file: std.fs.File, + file_writer: anytype, ) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); From ae93cdbe5d4ba04d327a43b8dec1738c784ae6f1 Mon Sep 17 00:00:00 2001 From: Dustin Taylor Date: Thu, 18 Aug 2022 16:49:13 -0400 Subject: [PATCH 2/3] threadlocal buffer fix --- lib/std/Progress.zig | 8 +-- lib/std/fs/file.zig | 94 ++++++++++++++++++++++++++++++++++- lib/std/io.zig | 53 ++++++-------------- lib/std/io/console_reader.zig | 87 -------------------------------- lib/std/io/console_writer.zig | 63 ----------------------- lib/std/io/reader.zig | 38 -------------- src/Compilation.zig | 4 +- src/main.zig | 14 +++--- src/print_env.zig | 2 +- src/print_zir.zig | 4 +- 10 files changed, 124 insertions(+), 243 deletions(-) delete mode 100644 lib/std/io/console_reader.zig delete mode 100644 lib/std/io/console_writer.zig diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index d587da43e8b8..fe2f7bc795b0 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -15,7 +15,7 @@ const Progress = @This(); /// `null` if the current node (and its children) should /// not print on update() -terminal: ?std.io.StdErrType = undefined, +terminal: ?std.fs.File = undefined, /// Is this a windows API terminal (note: this is not the same as being run on windows /// because other terminals exist like MSYS/git-bash) @@ -143,7 +143,7 @@ pub const Node = struct { /// API to return Progress rather than accept it as a parameter. /// `estimated_total_items` value of 0 means unknown. pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node { - var stderr: std.io.StdErrType = std.io.getStdErr(); + const stderr = std.io.getStdErr(); self.terminal = null; if (stderr.supportsAnsiEscapeCodes()) { self.terminal = stderr; @@ -196,7 +196,7 @@ fn refreshWithHeldLock(self: *Progress) void { const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; if (is_dumb and self.dont_print_on_dumb) return; - var file = self.terminal orelse return; + const file = self.terminal orelse return; var end: usize = 0; if (self.columns_written > 0) { @@ -297,7 +297,7 @@ fn refreshWithHeldLock(self: *Progress) void { } pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { - var file = self.terminal orelse { + const file = self.terminal orelse { std.debug.print(format, args); return; }; diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index 5de746150b42..0f5a483268d5 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -8,8 +8,13 @@ const assert = std.debug.assert; const windows = os.windows; const Os = std.builtin.Os; const maxInt = std.math.maxInt; +const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = 4 }); const is_windows = builtin.os.tag == .windows; +threadlocal var win_surrogate: ?u16 = null; +threadlocal var win_fifo_utf8: FifoType = FifoType.init(); +const win_u16_buffer_size = 4096; + pub const File = struct { /// The OS-specific file descriptor or file handle. handle: Handle, @@ -968,7 +973,11 @@ pub const File = struct { pub fn read(self: File, buffer: []u8) ReadError!usize { if (is_windows) { - return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode); + if (!self.isTty()) { + return windows.ReadFile(self.handle, buffer, null, self.intended_io_mode); + } + + return readWindowsConsole(self, buffer); } if (self.intended_io_mode == .blocking) { @@ -978,6 +987,68 @@ pub const File = struct { } } + /// readWindowsConsole reads a Windows console (cmd, powershell, etc) handle in a wide char format (utf16le) and converts to utf8. + /// It relies on a set of threadlocal vars to convert utf16le chars to utf8 for when the u8 buffer is too small. + fn readWindowsConsole(self: File, buffer: []u8) ReadError!usize { + var dest_index: usize = 0; + while (dest_index < buffer.len) { + // Read from a utf8 buffer for any potential missing bytes needed for a codepoint + const written = win_fifo_utf8.read(buffer[dest_index..]); + if (written != 0) { + dest_index += written; + continue; + } + const delta_len = buffer.len - dest_index; + if (delta_len < 4) { + // Not enough room is left in the destination buffer to handle larger codepoint lengths + // Read a character at a time and place the encoding utf8 bytes into a fifo buffer + win_fifo_utf8.realign(); + const n = try self.readWindowsConsoleToUtf8(win_fifo_utf8.writableSlice(0), 1); + if (n == 0) return dest_index; + win_fifo_utf8.update(n); + } else { + const n = try self.readWindowsConsoleToUtf8(buffer[delta_len..], win_u16_buffer_size); + if (n == 0) return dest_index; + dest_index += n; + } + } + return buffer.len; + } + + fn readWindowsConsoleToUtf8(self: File, dest: []u8, comptime u16_buffer_size: usize) ReadError!usize { + var utf16_buffer: [u16_buffer_size]u16 = undefined; + const end = if (u16_buffer_size > 1) math.min(dest.len / 3, u16_buffer_size) else u16_buffer_size; + + const n = try self.readWindowsConsoleW(utf16_buffer[0..end]); + if (n == 0) return n; + + return std.unicode.utf16leToUtf8(dest, utf16_buffer[0..n]) catch return ReadError.Unexpected; + } + + fn readWindowsConsoleW(self: File, buffer: []u16) ReadError!usize { + if (buffer.len == 0) return 0; + var start: usize = 0; + + // If we stored a surrogate half, place it back at the beginning of this buffer + if (win_surrogate != null) { + buffer[0] = win_surrogate.?; + win_surrogate = null; + start = 1; + } + + var n = try os.windows.ReadConsoleW(self.handle, buffer[start..], null); + + // Remove and store incomplete surrogate at end of buffer + if (n > 0) { + const last_char = buffer[n - 1]; + if (0xd800 <= last_char and last_char <= 0xdfff) { + win_surrogate = last_char; + n -= 1; + } + } + return n; + } + /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it /// means the file reached the end. Reaching the end of a file is not an error condition. pub fn readAll(self: File, buffer: []u8) ReadError!usize { @@ -1105,7 +1176,11 @@ pub const File = struct { pub fn write(self: File, bytes: []const u8) WriteError!usize { if (is_windows) { - return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode); + if (!self.isTty()) { + return windows.WriteFile(self.handle, bytes, null, self.intended_io_mode); + } + + return writeWindowsConsole(self, bytes); } if (self.intended_io_mode == .blocking) { @@ -1115,6 +1190,21 @@ pub const File = struct { } } + /// writeWindowsConsole writes to a Windows console (cmd, powershell, etc) handle with utf8 input to a wide char format (utf16le). + fn writeWindowsConsole(self: File, bytes: []const u8) WriteError!usize { + var utf16 = [_]u16{0} ** win_u16_buffer_size; + const max_data_len = std.unicode.getClampedUtf8SizeForUtf16LeSize(bytes, utf16.len) catch return WriteError.Unexpected; + const n = std.unicode.utf8ToUtf16Le(utf16[0..], bytes[0..max_data_len]) catch return WriteError.Unexpected; + const m = try os.windows.WriteConsoleW(self.handle, utf16[0..n]); + + if (n != m) { + // If the number of u16s don't match between converted utf8 chars and what's written to console, + // we need to calculate the number of bytes written provided from Windows. + return std.unicode.getClampedUtf8SizeForUtf16LeSize(bytes, m) catch unreachable; + } + return max_data_len; + } + pub fn writeAll(self: File, bytes: []const u8) WriteError!void { var index: usize = 0; while (index < bytes.len) { diff --git a/lib/std/io.zig b/lib/std/io.zig index 0cddf46ad38d..307890fa48d0 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -46,20 +46,14 @@ fn getStdOutHandle() os.fd_t { return os.STDOUT_FILENO; } -pub const StdOutType = if (builtin.os.tag == .windows) ConsoleWriter(4096) else File; - /// TODO: async stdout on windows without a dedicated thread. /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 -pub fn getStdOut() StdOutType { - if (builtin.os.tag == .windows) { - return .{ .handle = getStdOutHandle() }; - } else { - return File{ - .handle = getStdOutHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = default_mode, - }; - } +pub fn getStdOut() File { + return File{ + .handle = getStdOutHandle(), + .capable_io_mode = .blocking, + .intended_io_mode = default_mode, + }; } fn getStdErrHandle() os.fd_t { @@ -74,20 +68,14 @@ fn getStdErrHandle() os.fd_t { return os.STDERR_FILENO; } -pub const StdErrType = if (builtin.os.tag == .windows) ConsoleWriter(4096) else File; - /// This returns a `File` that is configured to block with every write, in order /// to facilitate better debugging. This can be changed by modifying the `intended_io_mode` field. pub fn getStdErr() StdErrType { - if (builtin.os.tag == .windows) { - return .{ .handle = getStdErrHandle() }; - } else { - return File{ - .handle = getStdErrHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = .blocking, - }; - } + return File{ + .handle = getStdErrHandle(), + .capable_io_mode = .blocking, + .intended_io_mode = .blocking, + }; } fn getStdInHandle() os.fd_t { @@ -102,20 +90,14 @@ fn getStdInHandle() os.fd_t { return os.STDIN_FILENO; } -pub const StdInType = if (builtin.os.tag == .windows) ConsoleReader(4096) else File; - /// TODO: async stdin on windows without a dedicated thread. /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 pub fn getStdIn() StdInType { - if (builtin.os.tag == .windows) { - return .{ .handle = getStdInHandle() }; - } else { - return File{ - .handle = getStdInHandle(), - .capable_io_mode = .blocking, - .intended_io_mode = default_mode, - }; - } + return File{ + .handle = getStdInHandle(), + .capable_io_mode = .blocking, + .intended_io_mode = default_mode, + }; } pub const Reader = @import("io/reader.zig").Reader; @@ -167,9 +149,6 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt pub const StreamSource = @import("io/stream_source.zig").StreamSource; -pub const ConsoleReader = @import("io/console_reader.zig").ConsoleReader; -pub const ConsoleWriter = @import("io/console_writer.zig").ConsoleWriter; - /// A Writer that doesn't write to anything. pub const null_writer = @as(NullWriter, .{ .context = {} }); diff --git a/lib/std/io/console_reader.zig b/lib/std/io/console_reader.zig deleted file mode 100644 index 11b379593c2b..000000000000 --- a/lib/std/io/console_reader.zig +++ /dev/null @@ -1,87 +0,0 @@ -const std = @import("std"); -const fifo = std.fifo; -const io = std.io; -const math = std.math; -const os = std.os; -const unicode = std.unicode; - -pub fn ConsoleReader(comptime u16_max_buffer_size: usize) type { - return struct { - const Self = @This(); - const FifoType = fifo.LinearFifo(u8, fifo.LinearFifoBufferType{ .Static = 4 }); - pub const Error = os.ReadError || error{InvalidUTF16LE}; - pub const Reader = io.Reader(*Self, Error, read); - - handle: os.fd_t, - surrogate: ?u16 = null, - fifo_utf8: FifoType = FifoType.init(), - - pub fn read(self: *Self, dest: []u8) Error!usize { - if (!os.isatty(self.handle)) { - // Non console handles should go straight to reading like a file - // Examples of this happening are when pipes are used as indicated in the docs - // https://docs.microsoft.com/en-us/windows/console/readconsole - return os.windows.ReadFile(self.handle, dest, null, .blocking); - } - - var dest_index: usize = 0; - while (dest_index < dest.len) { - // Read from a utf8 buffer for any potential missing bytes needed for a codepoint - const written = self.fifo_utf8.read(dest[dest_index..]); - if (written != 0) { - dest_index += written; - continue; - } - const delta_len = dest.len - dest_index; - if (delta_len < 4) { - // Not enough room is left in the destination buffer to handle larger codepoint lengths - // Read a character at a time and place the encoding utf8 bytes into a fifo buffer - self.fifo_utf8.realign(); - const n = try self.readConsoleToUtf8(self.fifo_utf8.writableSlice(0), 1); - if (n == 0) return dest_index; - self.fifo_utf8.update(n); - } else { - const n = try self.readConsoleToUtf8(dest[delta_len..], u16_max_buffer_size); - if (n == 0) return dest_index; - dest_index += n; - } - } - return dest.len; - } - - fn readConsoleToUtf8(self: *Self, dest: []u8, comptime u16_buffer_size: usize) Error!usize { - var utf16_buffer: [u16_buffer_size]u16 = undefined; - const end = if (u16_buffer_size > 1) math.min(dest.len / 3, u16_buffer_size) else u16_buffer_size; - - const n = try self.readConsole(utf16_buffer[0..end]); - if (n == 0) return n; - - return unicode.utf16leToUtf8(dest, utf16_buffer[0..n]) catch return Error.InvalidUTF16LE; - } - - fn readConsole(self: *Self, buffer: []u16) Error!usize { - if (buffer.len == 0) return 0; - var start: usize = 0; - if (self.surrogate != null) { - buffer[0] = self.surrogate.?; - self.surrogate = null; - start = 1; - } - - var n = try os.windows.ReadConsoleW(self.handle, buffer[start..], null); - - if (n > 0) { - const last_char = buffer[n - 1]; - if (0xd800 <= last_char and last_char <= 0xdfff) { - self.surrogate = last_char; - n -= 1; - } - } - return n; - } - - pub fn reader(self: *Self) Reader { - return .{ .context = self }; - } - }; -} diff --git a/lib/std/io/console_writer.zig b/lib/std/io/console_writer.zig deleted file mode 100644 index 4ad1f34bad57..000000000000 --- a/lib/std/io/console_writer.zig +++ /dev/null @@ -1,63 +0,0 @@ -const std = @import("std"); -const fifo = std.fifo; -const io = std.io; -const os = std.os; -const unicode = std.unicode; - -const File = std.fs.File; - -pub fn ConsoleWriter(comptime u16_max_buffer_size: usize) type { - return struct { - const Self = @This(); - pub const Error = os.WriteError || error{InvalidUtf8}; - pub const Writer = io.Writer(*Self, Error, write); - - handle: os.fd_t = undefined, - - pub fn isTty(self: Self) bool { - return os.isatty(self.handle); - } - - pub fn supportsAnsiEscapeCodes(self: Self) bool { - return os.isCygwinPty(self.handle); - } - - pub fn write(self: *Self, data: []const u8) Error!usize { - if (data.len == 0) return @as(usize, 0); - - if (!os.isatty(self.handle)) { - // Non console handles should go straight to reading like a file - // Examples of this happening are when pipes are used as indicated in the docs - // https://docs.microsoft.com/en-us/windows/console/writeconsole - return os.windows.WriteFile(self.handle, data, null, .blocking); - } - - var utf16 = [_]u16{0} ** u16_max_buffer_size; - const max_data_len = unicode.getClampedUtf8SizeForUtf16LeSize(data, utf16.len) catch return Error.InvalidUtf8; - const n = unicode.utf8ToUtf16Le(utf16[0..], data[0..max_data_len]) catch return Error.InvalidUtf8; - const m = try os.windows.WriteConsoleW(self.handle, utf16[0..n]); - - if (n != m) { - // If the number of u16s don't match between converted utf8 chars and what's written to console, - // We need to calculate the number of bytes written provided from Windows. - return unicode.getClampedUtf8SizeForUtf16LeSize(data, m) catch unreachable; - } - return max_data_len; - } - - pub fn writeAll(self: *Self, bytes: []const u8) Error!void { - var index: usize = 0; - while (index != bytes.len) { - index += try self.write(bytes[index..]); - } - } - - pub fn writeFileAll(self: *Self, in_file: File, args: File.WriteFileOptions) File.WriteFileError!void { - return (File{ .handle = self.handle }).writeFileAll(in_file, args); - } - - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - }; -} diff --git a/lib/std/io/reader.zig b/lib/std/io/reader.zig index cf3a4ceef08a..16acef8e4814 100644 --- a/lib/std/io/reader.zig +++ b/lib/std/io/reader.zig @@ -95,44 +95,6 @@ pub fn Reader( return array_list.toOwnedSlice(); } - /// Reads all the bytes from the current position to the end of the file. - /// On success, caller owns returned buffer. - /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. - /// If `size_hint` is specified the initial buffer size is calculated using - /// that value, otherwise an arbitrary value is used instead. - /// Allows specifying alignment and a sentinel value. - pub fn readToEndAllocOptions( - self: Self, - allocator: mem.Allocator, - max_bytes: usize, - size_hint: ?usize, - comptime alignment: u29, - comptime optional_sentinel: ?u8, - ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { - // If no size hint is provided fall back to the size=0 code path - const size = size_hint orelse 0; - - // The file size returned by stat is used as hint to set the buffer - // size. If the reported size is zero, as it happens on Linux for files - // in /proc, a small buffer is allocated instead. - const initial_cap = (if (size > 0) size else 1024) + @boolToInt(optional_sentinel != null); - var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap); - defer array_list.deinit(); - - self.readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) { - error.StreamTooLong => return error.FileTooBig, - else => |e| return e, - }; - - if (optional_sentinel) |sentinel| { - try array_list.append(sentinel); - const buf = array_list.toOwnedSlice(); - return buf[0 .. buf.len - 1 :sentinel]; - } else { - return array_list.toOwnedSlice(); - } - } - /// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found. /// Does not include the delimiter in the result. /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the diff --git a/src/Compilation.zig b/src/Compilation.zig index 965791bccc57..818f2b1b6b5f 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -381,8 +381,8 @@ pub const AllErrors = struct { pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void { std.debug.getStderrMutex().lock(); defer std.debug.getStderrMutex().unlock(); - const stderr = std.io.getStdErr().writer(); - return msg.renderToWriter(ttyconf, stderr, "error", .Red, 0) catch return; + const stderr = std.io.getStdErr(); + return msg.renderToWriter(ttyconf, stderr.writer(), "error", .Red, 0) catch return; } pub fn renderToWriter( diff --git a/src/main.zig b/src/main.zig index 1129d2c50026..e7827e3a2a78 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3964,10 +3964,10 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi fn readSourceFileToEndAlloc( allocator: mem.Allocator, - input_reader: anytype, + input: *const fs.File, size_hint: ?usize, ) ![:0]u8 { - const source_code = input_reader.readToEndAllocOptions( + const source_code = input.readToEndAllocOptions( allocator, max_src_size, size_hint, @@ -4096,8 +4096,8 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void fatal("cannot use --stdin with positional arguments", .{}); } - const stdin = io.getStdIn().reader(); - const source_code = readSourceFileToEndAlloc(gpa, stdin, null) catch |err| { + const stdin = io.getStdIn(); + const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| { fatal("unable to read stdin: {}", .{err}); }; defer gpa.free(source_code); @@ -5034,7 +5034,7 @@ pub fn cmdAstCheck( .mtime = stat.mtime, }; } else { - const stdin = io.getStdIn().reader(); + const stdin = io.getStdIn(); const source = readSourceFileToEndAlloc(arena, stdin, null) catch |err| { fatal("unable to read stdin: {}", .{err}); }; @@ -5095,10 +5095,10 @@ pub fn cmdAstCheck( const extra_bytes = file.zir.extra.len * @sizeOf(u32); const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + file.zir.string_bytes.len * @sizeOf(u8); - const stdout = io.getStdOut().writer(); + const stdout = io.getStdOut(); const fmtIntSizeBin = std.fmt.fmtIntSizeBin; // zig fmt: off - try stdout.print( + try stdout.writer().print( \\# Source bytes: {} \\# Tokens: {} ({}) \\# AST Nodes: {} ({}) diff --git a/src/print_env.zig b/src/print_env.zig index 982e3fb424fa..ad772d416b66 100644 --- a/src/print_env.zig +++ b/src/print_env.zig @@ -4,7 +4,7 @@ const introspect = @import("introspect.zig"); const Allocator = std.mem.Allocator; const fatal = @import("main.zig").fatal; -pub fn cmdEnv(gpa: Allocator, args: []const []const u8, stdout: std.io.StdOutType.Writer) !void { +pub fn cmdEnv(gpa: Allocator, args: []const []const u8, stdout: std.fs.File.Writer) !void { _ = args; const self_exe_path = try introspect.findZigExePath(gpa); defer gpa.free(self_exe_path); diff --git a/src/print_zir.zig b/src/print_zir.zig index 3f56965853f1..579a7970b7de 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -9,10 +9,10 @@ const Module = @import("Module.zig"); const LazySrcLoc = Module.LazySrcLoc; /// Write human-readable, debug formatted ZIR code to a file. -pub fn renderAsTextToFileWriter( +pub fn renderAsTextToFile( gpa: Allocator, scope_file: *Module.File, - file_writer: anytype, + fs_file: std.fs.File, ) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); From 6865708360edf77cec5bcd1b42afebf35880d4b8 Mon Sep 17 00:00:00 2001 From: Dustin Taylor Date: Thu, 18 Aug 2022 16:51:32 -0400 Subject: [PATCH 3/3] More cleanup from init commit --- lib/std/io.zig | 4 ++-- src/Compilation.zig | 3 --- src/main.zig | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/std/io.zig b/lib/std/io.zig index 307890fa48d0..50d134b856a7 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -70,7 +70,7 @@ fn getStdErrHandle() os.fd_t { /// This returns a `File` that is configured to block with every write, in order /// to facilitate better debugging. This can be changed by modifying the `intended_io_mode` field. -pub fn getStdErr() StdErrType { +pub fn getStdErr() File { return File{ .handle = getStdErrHandle(), .capable_io_mode = .blocking, @@ -92,7 +92,7 @@ fn getStdInHandle() os.fd_t { /// TODO: async stdin on windows without a dedicated thread. /// https://github.com/ziglang/zig/pull/4816#issuecomment-604521023 -pub fn getStdIn() StdInType { +pub fn getStdIn() File { return File{ .handle = getStdInHandle(), .capable_io_mode = .blocking, diff --git a/src/Compilation.zig b/src/Compilation.zig index 818f2b1b6b5f..af39154a3f23 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4767,8 +4767,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable; \\pub const zig_backend = std.builtin.CompilerBackend.{}; - \\/// Temporary until self-hosted supports the `cpu.arch` value. - \\pub const stage2_arch: std.Target.Cpu.Arch = .{}; \\ \\pub const output_mode = std.builtin.OutputMode.{}; \\pub const link_mode = std.builtin.LinkMode.{}; @@ -4783,7 +4781,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca , .{ build_options.version, std.zig.fmtId(@tagName(zig_backend)), - std.zig.fmtId(@tagName(target.cpu.arch)), std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)), std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)), comp.bin_file.options.is_test, diff --git a/src/main.zig b/src/main.zig index e7827e3a2a78..971fe19e36c6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5035,7 +5035,7 @@ pub fn cmdAstCheck( }; } else { const stdin = io.getStdIn(); - const source = readSourceFileToEndAlloc(arena, stdin, null) catch |err| { + const source = readSourceFileToEndAlloc(arena, &stdin, null) catch |err| { fatal("unable to read stdin: {}", .{err}); }; file.sub_file_path = ""; @@ -5119,7 +5119,7 @@ pub fn cmdAstCheck( // zig fmt: on } - return @import("print_zir.zig").renderAsTextToFileWriter(gpa, &file, io.getStdOut().writer()); + return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut()); } /// This is only enabled for debug builds.