std.io.getStdOut and related fns no longer can error

Thanks to the Windows Process Environment Block, it is possible to
obtain handles to the standard input, output, and error streams without
possibility of failure.
This commit is contained in:
Andrew Kelley 2019-11-12 20:36:07 -05:00
parent 8bae70454d
commit 0237e7a701
17 changed files with 76 additions and 115 deletions

View File

@ -202,11 +202,8 @@
const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
const stdout_file = try std.io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");
const stdout = &std.io.getStdOut().outStream().stream;
try stdout.print("Hello, {}!\n", "world");
}
{#code_end#}
<p>

View File

@ -131,9 +131,7 @@ fn printPad(stdout: var, s: []const u8) !void {
}
pub fn main() !void {
var stdout_file = try std.io.getStdOut();
var stdout_out_stream = stdout_file.outStream();
const stdout = &stdout_out_stream.stream;
const stdout = &std.io.getStdOut().outStream().stream;
var buffer: [1024]u8 = undefined;
var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);

View File

@ -49,15 +49,15 @@ var stderr_mutex = std.Mutex.init();
pub fn warn(comptime fmt: []const u8, args: ...) void {
const held = stderr_mutex.acquire();
defer held.release();
const stderr = getStderrStream() catch return;
const stderr = getStderrStream();
stderr.print(fmt, args) catch return;
}
pub fn getStderrStream() !*io.OutStream(File.WriteError) {
pub fn getStderrStream() *io.OutStream(File.WriteError) {
if (stderr_stream) |st| {
return st;
} else {
stderr_file = try io.getStdErr();
stderr_file = io.getStdErr();
stderr_file_out_stream = stderr_file.outStream();
const st = &stderr_file_out_stream.stream;
stderr_stream = st;
@ -90,7 +90,7 @@ fn wantTtyColor() bool {
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
const stderr = getStderrStream() catch return;
const stderr = getStderrStream();
if (builtin.strip_debug_info) {
stderr.print("Unable to dump stack trace: debug info stripped\n") catch return;
return;
@ -109,7 +109,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
/// unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
const stderr = getStderrStream() catch return;
const stderr = getStderrStream();
if (builtin.strip_debug_info) {
stderr.print("Unable to dump stack trace: debug info stripped\n") catch return;
return;
@ -182,7 +182,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
const stderr = getStderrStream() catch return;
const stderr = getStderrStream();
if (builtin.strip_debug_info) {
stderr.print("Unable to dump stack trace: debug info stripped\n") catch return;
return;
@ -237,7 +237,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
// which first called panic can finish printing a stack trace.
os.abort();
}
const stderr = getStderrStream() catch os.abort();
const stderr = getStderrStream();
stderr.print(format ++ "\n", args) catch os.abort();
if (trace) |t| {
dumpStackTrace(t.*);

View File

@ -34,28 +34,23 @@ else
Mode.blocking;
pub const is_async = mode != .blocking;
pub const GetStdIoError = os.windows.GetStdHandleError;
pub fn getStdOut() GetStdIoError!File {
pub fn getStdOut() File {
if (builtin.os == .windows) {
const handle = try os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE);
return File.openHandle(handle);
return File.openHandle(os.windows.peb().ProcessParameters.hStdOutput);
}
return File.openHandle(os.STDOUT_FILENO);
}
pub fn getStdErr() GetStdIoError!File {
pub fn getStdErr() File {
if (builtin.os == .windows) {
const handle = try os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE);
return File.openHandle(handle);
return File.openHandle(os.windows.peb().ProcessParameters.hStdError);
}
return File.openHandle(os.STDERR_FILENO);
}
pub fn getStdIn() GetStdIoError!File {
pub fn getStdIn() File {
if (builtin.os == .windows) {
const handle = try os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE);
return File.openHandle(handle);
return File.openHandle(os.windows.peb().ProcessParameters.hStdInput);
}
return File.openHandle(os.STDIN_FILENO);
}
@ -598,7 +593,7 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr
self.index = 0;
}
fn writeFn(out_stream: *Stream, bytes: []const u8) !void {
fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
const self = @fieldParentPtr(Self, "stream", out_stream);
if (bytes.len >= self.buffer.len) {
@ -814,8 +809,7 @@ pub const BufferedAtomicFile = struct {
};
pub fn readLine(buf: *std.Buffer) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
var stdin_stream = getStdIn().inStream();
return readLineFrom(&stdin_stream.stream, buf);
}
@ -856,8 +850,7 @@ test "io.readLineFrom" {
}
pub fn readLineSlice(slice: []u8) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
var stdin_stream = getStdIn().inStream();
return readLineSliceFrom(&stdin_stream.stream, slice);
}

View File

@ -1015,7 +1015,7 @@ pub const Value = union(enum) {
var held = std.debug.getStderrMutex().acquire();
defer held.release();
const stderr = std.debug.getStderrStream() catch return;
const stderr = std.debug.getStderrStream();
self.dumpStream(stderr, 1024) catch return;
}
@ -1026,7 +1026,7 @@ pub const Value = union(enum) {
var held = std.debug.getStderrMutex().acquire();
defer held.release();
const stderr = std.debug.getStderrStream() catch return;
const stderr = std.debug.getStderrStream();
self.dumpStreamIndent(indent, stderr, 1024) catch return;
}
}

View File

@ -98,11 +98,8 @@ pub const Progress = struct {
/// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
/// API to return Progress rather than accept it as a parameter.
pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node {
if (std.io.getStdErr()) |stderr| {
self.terminal = if (stderr.supportsAnsiEscapeCodes()) stderr else null;
} else |_| {
self.terminal = null;
}
const stderr = std.io.getStdErr();
self.terminal = if (stderr.supportsAnsiEscapeCodes()) stderr else null;
self.root = Node{
.context = self,
.parent = null,

View File

@ -43,19 +43,8 @@ pub fn main() !void {
var targets = ArrayList([]const u8).init(allocator);
var stderr_file = io.getStdErr();
var stderr_file_stream: File.OutStream = undefined;
var stderr_stream = if (stderr_file) |f| x: {
stderr_file_stream = f.outStream();
break :x &stderr_file_stream.stream;
} else |err| err;
var stdout_file = io.getStdOut();
var stdout_file_stream: File.OutStream = undefined;
var stdout_stream = if (stdout_file) |f| x: {
stdout_file_stream = f.outStream();
break :x &stdout_file_stream.stream;
} else |err| err;
const stderr_stream = &io.getStdErr().outStream().stream;
const stdout_stream = &io.getStdOut().outStream().stream;
while (arg_it.next(allocator)) |err_or_arg| {
const arg = try unwrapArg(err_or_arg);
@ -63,37 +52,37 @@ pub fn main() !void {
const option_contents = arg[2..];
if (option_contents.len == 0) {
warn("Expected option name after '-D'\n\n");
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
}
if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
const option_name = option_contents[0..name_end];
const option_value = option_contents[name_end + 1 ..];
if (try builder.addUserInputOption(option_name, option_value))
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
} else {
if (try builder.addUserInputFlag(option_contents))
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
}
} else if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--verbose")) {
builder.verbose = true;
} else if (mem.eql(u8, arg, "--help")) {
return usage(builder, false, try stdout_stream);
return usage(builder, false, stdout_stream);
} else if (mem.eql(u8, arg, "--prefix")) {
builder.install_prefix = try unwrapArg(arg_it.next(allocator) orelse {
warn("Expected argument after --prefix\n\n");
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
});
} else if (mem.eql(u8, arg, "--search-prefix")) {
const search_prefix = try unwrapArg(arg_it.next(allocator) orelse {
warn("Expected argument after --search-prefix\n\n");
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
});
builder.addSearchPrefix(search_prefix);
} else if (mem.eql(u8, arg, "--override-lib-dir")) {
builder.override_lib_dir = try unwrapArg(arg_it.next(allocator) orelse {
warn("Expected argument after --override-lib-dir\n\n");
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
});
} else if (mem.eql(u8, arg, "--verbose-tokenize")) {
builder.verbose_tokenize = true;
@ -111,7 +100,7 @@ pub fn main() !void {
builder.verbose_cc = true;
} else {
warn("Unrecognized argument: {}\n\n", arg);
return usageAndErr(builder, false, try stderr_stream);
return usageAndErr(builder, false, stderr_stream);
}
} else {
try targets.append(arg);
@ -122,12 +111,12 @@ pub fn main() !void {
try runBuild(builder);
if (builder.validateUserInputDidItFail())
return usageAndErr(builder, true, try stderr_stream);
return usageAndErr(builder, true, stderr_stream);
builder.make(targets.toSliceConst()) catch |err| {
switch (err) {
error.InvalidStepName => {
return usageAndErr(builder, true, try stderr_stream);
return usageAndErr(builder, true, stderr_stream);
},
error.UncleanExit => process.exit(1),
else => return err,

View File

@ -2,9 +2,7 @@ const builtin = @import("builtin");
const std = @import("std");
pub fn main() !void {
var stdout_file = try std.io.getStdOut();
var stdout_out_stream = stdout_file.outStream();
const stdout = &stdout_out_stream.stream;
const stdout = &std.io.getStdOut().outStream().stream;
const args = try std.process.argsAlloc(std.heap.direct_allocator);

View File

@ -1451,11 +1451,11 @@ test "zig fmt: preserve spacing" {
\\const std = @import("std");
\\
\\pub fn main() !void {
\\ var stdout_file = try std.io.getStdOut;
\\ var stdout_file = try std.io.getStdOut;
\\ var stdout_file = std.io.getStdOut;
\\ var stdout_file = std.io.getStdOut;
\\
\\ var stdout_file = try std.io.getStdOut;
\\ var stdout_file = try std.io.getStdOut;
\\ var stdout_file = std.io.getStdOut;
\\ var stdout_file = std.io.getStdOut;
\\}
\\
);
@ -2565,8 +2565,7 @@ const maxInt = std.math.maxInt;
var fixed_buffer_mem: [100 * 1024]u8 = undefined;
fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
var stderr_file = try io.getStdErr();
var stderr = &stderr_file.outStream().stream;
const stderr = &io.getStdErr().outStream().stream;
const tree = try std.zig.parse(allocator, source);
defer tree.deinit();

View File

@ -56,13 +56,10 @@ pub fn main() !void {
// libc allocator is guaranteed to have this property.
const allocator = std.heap.c_allocator;
var stdout_file = try std.io.getStdOut();
var stdout_out_stream = stdout_file.outStream();
stdout = &stdout_out_stream.stream;
stdout = &std.io.getStdOut().outStream().stream;
stderr_file = try std.io.getStdErr();
var stderr_out_stream = stderr_file.outStream();
stderr = &stderr_out_stream.stream;
stderr_file = std.io.getStdErr();
stderr = &stderr_file.outStream().stream;
const args = try process.argsAlloc(allocator);
// TODO I'm getting unreachable code here, which shouldn't happen
@ -619,7 +616,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
process.exit(1);
}
var stdin_file = try io.getStdIn();
var stdin_file = io.getStdIn();
var stdin = stdin_file.inStream();
const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);

View File

@ -166,13 +166,9 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
try args_list.append(std.mem.toSliceConst(u8, argv[arg_i]));
}
var stdout_file = try std.io.getStdOut();
var stdout_out_stream = stdout_file.outStream();
stdout = &stdout_out_stream.stream;
stderr_file = try std.io.getStdErr();
var stderr_out_stream = stderr_file.outStream();
stderr = &stderr_out_stream.stream;
stdout = &std.io.getStdOut().outStream().stream;
stderr_file = std.io.getStdErr();
stderr = &stderr_file.outStream().stream;
const args = args_list.toSliceConst();
var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args[2..]);
@ -203,7 +199,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
process.exit(1);
}
var stdin_file = try io.getStdIn();
const stdin_file = io.getStdIn();
var stdin = stdin_file.inStream();
const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);

View File

@ -181,7 +181,7 @@ pub const TestContext = struct {
},
Compilation.Event.Error => |err| return err,
Compilation.Event.Fail => |msgs| {
var stderr = try std.io.getStdErr();
const stderr = std.io.getStdErr();
try stderr.write("build incorrectly failed:\n");
for (msgs) |msg| {
defer msg.destroy();
@ -231,7 +231,7 @@ pub const TestContext = struct {
text,
);
std.debug.warn("\n====found:========\n");
var stderr = try std.io.getStdErr();
const stderr = std.io.getStdErr();
for (msgs) |msg| {
defer msg.destroy();
try msg.printToFile(stderr, errmsg.Color.Auto);

View File

@ -19,7 +19,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() void {
\\ privateFunction();
\\ const stdout = &(getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &getStdOut().outStream().stream;
\\ stdout.print("OK 2\n") catch unreachable;
\\}
\\
@ -34,7 +34,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\// purposefully conflicting function with main.zig
\\// but it's private so it should be OK
\\fn privateFunction() void {
\\ const stdout = &(getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &getStdOut().outStream().stream;
\\ stdout.print("OK 1\n") catch unreachable;
\\}
\\
@ -60,7 +60,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
tc.addSourceFile("foo.zig",
\\usingnamespace @import("std").io;
\\pub fn foo_function() void {
\\ const stdout = &(getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &getStdOut().outStream().stream;
\\ stdout.print("OK\n") catch unreachable;
\\}
);
@ -71,7 +71,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn bar_function() void {
\\ if (foo_function()) {
\\ const stdout = &(getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &getStdOut().outStream().stream;
\\ stdout.print("OK\n") catch unreachable;
\\ }
\\}
@ -103,7 +103,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub const a_text = "OK\n";
\\
\\pub fn ok() void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print(b_text) catch unreachable;
\\}
);
@ -121,7 +121,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\
\\pub fn main() void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", @as(u32, 12), @as(u16, 0x12), @as(u8, 'a')) catch unreachable;
\\}
, "Hello, world!\n 12 12 a\n");
@ -264,7 +264,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ var x_local : i32 = print_ok(x);
\\}
\\fn print_ok(val: @typeOf(x)) @typeOf(foo) {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print("OK\n") catch unreachable;
\\ return 0;
\\}
@ -346,7 +346,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub fn main() void {
\\ const bar = Bar {.field2 = 13,};
\\ const foo = Foo {.field1 = bar,};
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ if (!foo.method()) {
\\ stdout.print("BAD\n") catch unreachable;
\\ }
@ -360,7 +360,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.add("defer with only fallthrough",
\\const io = @import("std").io;
\\pub fn main() void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ defer stdout.print("defer2\n") catch unreachable;
@ -373,7 +373,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\const os = @import("std").os;
\\pub fn main() void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ defer stdout.print("defer2\n") catch unreachable;
@ -390,7 +390,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ errdefer stdout.print("deferErr\n") catch unreachable;
@ -409,7 +409,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print("before\n") catch unreachable;
\\ defer stdout.print("defer1\n") catch unreachable;
\\ errdefer stdout.print("deferErr\n") catch unreachable;
@ -426,7 +426,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\
\\pub fn main() void {
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
\\ const stdout = &io.getStdOut().outStream().stream;
\\ stdout.print(foo_txt) catch unreachable;
\\}
, "1234\nabcd\n");
@ -445,7 +445,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() !void {
\\ var args_it = std.process.args();
\\ var stdout_file = try io.getStdOut();
\\ var stdout_file = io.getStdOut();
\\ var stdout_adapter = stdout_file.outStream();
\\ const stdout = &stdout_adapter.stream;
\\ var index: usize = 0;
@ -486,7 +486,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() !void {
\\ var args_it = std.process.args();
\\ var stdout_file = try io.getStdOut();
\\ var stdout_file = io.getStdOut();
\\ var stdout_adapter = stdout_file.outStream();
\\ const stdout = &stdout_adapter.stream;
\\ var index: usize = 0;

View File

@ -179,8 +179,8 @@ fn expandNode(node: Node, output: *ArrayList(Buffer)) ExpandNodeError!void {
}
pub fn main() !void {
var stdin_file = try io.getStdIn();
var stdout_file = try io.getStdOut();
const stdin_file = io.getStdIn();
const stdout_file = io.getStdOut();
var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator);
defer arena.deinit();

View File

@ -10,30 +10,28 @@ pub fn main() !void {
var args_it = process.args();
const exe = try unwrapArg(args_it.next(allocator).?);
var catted_anything = false;
var stdout_file = try io.getStdOut();
const stdout_file = io.getStdOut();
while (args_it.next(allocator)) |arg_or_err| {
const arg = try unwrapArg(arg_or_err);
if (mem.eql(u8, arg, "-")) {
catted_anything = true;
var stdin_file = try io.getStdIn();
try cat_file(&stdout_file, &stdin_file);
try cat_file(stdout_file, io.getStdIn());
} else if (arg[0] == '-') {
return usage(exe);
} else {
var file = File.openRead(arg) catch |err| {
const file = File.openRead(arg) catch |err| {
warn("Unable to open file: {}\n", @errorName(err));
return err;
};
defer file.close();
catted_anything = true;
try cat_file(&stdout_file, &file);
try cat_file(stdout_file, file);
}
}
if (!catted_anything) {
var stdin_file = try io.getStdIn();
try cat_file(&stdout_file, &stdin_file);
try cat_file(stdout_file, io.getStdIn());
}
}
@ -42,7 +40,7 @@ fn usage(exe: []const u8) !void {
return error.Invalid;
}
fn cat_file(stdout: *File, file: *File) !void {
fn cat_file(stdout: File, file: File) !void {
var buf: [1024 * 4]u8 = undefined;
while (true) {

View File

@ -4,8 +4,7 @@ const io = std.io;
const fmt = std.fmt;
pub fn main() !void {
var stdout_file = try io.getStdOut();
const stdout = &stdout_file.outStream().stream;
const stdout = &io.getStdOut().outStream().stream;
try stdout.print("Welcome to the Guess Number Game in Zig.\n");

View File

@ -2,7 +2,7 @@ const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
const stdout_file = try std.io.getStdOut();
const stdout_file = std.io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");