Skip to content

Commit 7e62c14

Browse files
committed
std.c: define freopen() and the stdio streams
This allows for daemonization and output-redirection sorts of code in libc-linked Zig projects on *nix-y platforms to affect the stdio stream usage of other libc-based library code the project may be linking, e.g.: // Set stderr to go nowhere without errors: _ = std.c.freopen("/dev/null", "r+", std.c.stderr()); // Append stdout to a file: _ = std.c.freopen("/tmp/output.txt", "a", std.c.stdout()); The stdio streams are returned from function calls because they're commonly #defines in the libc headers pointing at variously-named externs, and one doesn't generally assign to them directly anyways (freopen() is the portable way to assign something new to a stdio stream). NetBSD, OpenBSD, and Solaris stdio streams are not supported in this patch and will cause a compileError if you try to use the them, for now. Supporting them would require a more complex and fragile solution using a definition of "FILE" that is not just an opaque type (because their C libraries publish an extern array of FILE objects and then #define the stdio stream names as pointers to the array elements).
1 parent 2f3cd17 commit 7e62c14

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

lib/std/c.zig

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10482,6 +10482,7 @@ pub const futex = switch (native_os) {
1048210482
pub extern "c" var environ: [*:null]?[*:0]u8;
1048310483

1048410484
pub extern "c" fn fopen(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
10485+
pub extern "c" fn freopen(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8, noalias stream: *FILE) ?*FILE;
1048510486
pub extern "c" fn fclose(stream: *FILE) c_int;
1048610487
pub extern "c" fn fwrite(noalias ptr: [*]const u8, size_of_type: usize, item_count: usize, noalias stream: *FILE) usize;
1048710488
pub extern "c" fn fread(noalias ptr: [*]u8, size_of_type: usize, item_count: usize, noalias stream: *FILE) usize;
@@ -10782,6 +10783,34 @@ pub const pthread_t = switch (native_os) {
1078210783
};
1078310784
pub const FILE = opaque {};
1078410785

10786+
// NetBSD, OpenBSD, and Solaris definitions could be created, but the stdio
10787+
// streams on these are stored in an extern array of FILE objects, so we'd need
10788+
// precise definitions of the size of "struct FILE" for various arches and
10789+
// versions to get the correct offsets...
10790+
pub fn stdin() *FILE {
10791+
return switch (native_os) {
10792+
.linux, .serenity, .haiku => private.stdin,
10793+
.freebsd, .dragonfly, .macos, .ios, .tvos, .watchos, .visionos => private.__stdinp,
10794+
else => @compileError("stdio streams unsupported on this platform"),
10795+
};
10796+
}
10797+
10798+
pub fn stdout() *FILE {
10799+
return switch (native_os) {
10800+
.linux, .serenity, .haiku => private.stdout,
10801+
.freebsd, .dragonfly, .macos, .ios, .tvos, .watchos, .visionos => private.__stdoutp,
10802+
else => @compileError("stdio streams unsupported on this platform"),
10803+
};
10804+
}
10805+
10806+
pub fn stderr() *FILE {
10807+
return switch (native_os) {
10808+
.linux, .serenity, .haiku => private.stderr,
10809+
.freebsd, .dragonfly, .macos, .ios, .tvos, .watchos, .visionos => private.__stderrp,
10810+
else => @compileError("std streams unsupported on this platform"),
10811+
};
10812+
}
10813+
1078510814
pub extern "c" fn dlopen(path: ?[*:0]const u8, mode: RTLD) ?*anyopaque;
1078610815
pub extern "c" fn dlclose(handle: *anyopaque) c_int;
1078710816
pub extern "c" fn dlsym(handle: ?*anyopaque, symbol: [*:0]const u8) ?*anyopaque;
@@ -11283,6 +11312,16 @@ const private = struct {
1128311312
extern "c" fn __libc_current_sigrtmin() c_int;
1128411313
extern "c" fn __libc_current_sigrtmax() c_int;
1128511314

11315+
// Linux, Serenity, Haiku
11316+
extern "c" var stdin: *FILE;
11317+
extern "c" var stdout: *FILE;
11318+
extern "c" var stderr: *FILE;
11319+
11320+
// FreeBSD, Dragonfly, Darwin
11321+
extern "c" var __stdinp: *FILE;
11322+
extern "c" var __stdoutp: *FILE;
11323+
extern "c" var __stderrp: *FILE;
11324+
1128611325
// Don't forget to add another clown when an OS picks yet another unique
1128711326
// symbol name for errno location!
1128811327
// 🤡🤡🤡🤡🤡🤡

0 commit comments

Comments
 (0)