parent
b46344fd01
commit
72fb2443e0
|
@ -223,6 +223,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}")
|
|||
install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os")
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/std/os/errno.zig" DESTINATION "${ZIG_STD_DEST}/os")
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
const std = @import("std");
|
||||
const io = std.io;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
const exe = args[0];
|
||||
pub fn main() -> %void {
|
||||
const exe = os.args.at(0);
|
||||
var catted_anything = false;
|
||||
for (args[1...]) |arg| {
|
||||
var arg_i: usize = 1;
|
||||
while (arg_i < os.args.count(); arg_i += 1) {
|
||||
const arg = os.args.at(arg_i);
|
||||
if (mem.eql(u8, arg, "-")) {
|
||||
catted_anything = true;
|
||||
%return cat_stream(&io.stdin);
|
||||
} else if (arg[0] == '-') {
|
||||
return usage(exe);
|
||||
} else {
|
||||
var is: io.InStream = undefined;
|
||||
is.open(arg) %% |err| {
|
||||
var is = io.InStream.open(arg, null) %% |err| {
|
||||
%%io.stderr.printf("Unable to open file: {}\n", @errorName(err));
|
||||
return err;
|
||||
};
|
||||
defer %%is.close();
|
||||
defer is.close();
|
||||
|
||||
catted_anything = true;
|
||||
%return cat_stream(&is);
|
||||
|
@ -29,7 +31,7 @@ pub fn main(args: [][]u8) -> %void {
|
|||
%return io.stdout.flush();
|
||||
}
|
||||
|
||||
fn usage(exe: []u8) -> %void {
|
||||
fn usage(exe: []const u8) -> %void {
|
||||
%%io.stderr.printf("Usage: {} [FILE]...\n", exe);
|
||||
return error.Invalid;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ const fmt = std.fmt;
|
|||
const Rand = std.rand.Rand;
|
||||
const os = std.os;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
%%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
|
||||
|
||||
var seed_bytes: [@sizeOf(usize)]u8 = undefined;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const io = @import("std").io;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
%%io.stdout.printf("Hello, world!\n");
|
||||
}
|
||||
|
|
|
@ -39,11 +39,13 @@ pub const Builder = struct {
|
|||
return exe;
|
||||
}
|
||||
|
||||
pub fn make(self: &Builder, cli_args: []const []const u8) -> %void {
|
||||
pub fn make(self: &Builder, leftover_arg_index: usize) -> %void {
|
||||
var env_map = %return os.getEnvMap(self.allocator);
|
||||
|
||||
var verbose = false;
|
||||
for (cli_args) |arg| {
|
||||
var arg_i: usize = leftover_arg_index;
|
||||
while (arg_i < os.args.count(); arg_i += 1) {
|
||||
const arg = os.args.at(arg_i);
|
||||
if (mem.eql(u8, arg, "--verbose")) {
|
||||
verbose = true;
|
||||
} else {
|
||||
|
@ -95,7 +97,8 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
printInvocation(self.zig_exe, zig_args);
|
||||
var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), env_map,
|
||||
// TODO issue #301
|
||||
var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), &env_map,
|
||||
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
|
||||
const term = %return child.wait();
|
||||
switch (term) {
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
const io = @import("../io.zig");
|
||||
const os = @import("index.zig");
|
||||
const posix = os.posix;
|
||||
const mem = @import("../mem.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const errno = @import("errno.zig");
|
||||
const debug = @import("../debug.zig");
|
||||
const assert = debug.assert;
|
||||
|
||||
pub const ChildProcess = struct {
|
||||
pid: i32,
|
||||
err_pipe: [2]i32,
|
||||
|
||||
stdin: ?io.OutStream,
|
||||
stdout: ?io.InStream,
|
||||
stderr: ?io.InStream,
|
||||
|
||||
pub const Term = enum {
|
||||
Clean: i32,
|
||||
Signal: i32,
|
||||
Stopped: i32,
|
||||
Unknown: i32,
|
||||
};
|
||||
|
||||
pub const StdIo = enum {
|
||||
Inherit,
|
||||
Ignore,
|
||||
Pipe,
|
||||
Close,
|
||||
};
|
||||
|
||||
pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap,
|
||||
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
|
||||
{
|
||||
switch (@compileVar("os")) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.darwin => {
|
||||
return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator);
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait(self: &ChildProcess) -> %Term {
|
||||
defer {
|
||||
os.posixClose(self.err_pipe[0]);
|
||||
os.posixClose(self.err_pipe[1]);
|
||||
};
|
||||
|
||||
var status: i32 = undefined;
|
||||
while (true) {
|
||||
const err = posix.getErrno(posix.waitpid(self.pid, &status, 0));
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
errno.EINVAL, errno.ECHILD => unreachable,
|
||||
errno.EINTR => continue,
|
||||
else => {
|
||||
if (const *stdin ?= self.stdin) { stdin.close(); }
|
||||
if (const *stdout ?= self.stdin) { stdout.close(); }
|
||||
if (const *stderr ?= self.stdin) { stderr.close(); }
|
||||
return error.Unexpected;
|
||||
},
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (const *stdin ?= self.stdin) { stdin.close(); }
|
||||
if (const *stdout ?= self.stdin) { stdout.close(); }
|
||||
if (const *stderr ?= self.stdin) { stderr.close(); }
|
||||
|
||||
// Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
|
||||
// waitpid, so this write is guaranteed to be after the child
|
||||
// pid potentially wrote an error. This way we can do a blocking
|
||||
// read on the error pipe and either get @maxValue(ErrInt) (no error) or
|
||||
// an error code.
|
||||
%return writeIntFd(self.err_pipe[1], @maxValue(ErrInt));
|
||||
const err_int = %return readIntFd(self.err_pipe[0]);
|
||||
// Here we potentially return the fork child's error
|
||||
// from the parent pid.
|
||||
if (err_int != @maxValue(ErrInt)) {
|
||||
return error(err_int);
|
||||
}
|
||||
|
||||
return statusToTerm(status);
|
||||
}
|
||||
|
||||
fn statusToTerm(status: i32) -> Term {
|
||||
return if (posix.WIFEXITED(status)) {
|
||||
Term.Clean { posix.WEXITSTATUS(status) }
|
||||
} else if (posix.WIFSIGNALED(status)) {
|
||||
Term.Signal { posix.WTERMSIG(status) }
|
||||
} else if (posix.WIFSTOPPED(status)) {
|
||||
Term.Stopped { posix.WSTOPSIG(status) }
|
||||
} else {
|
||||
Term.Unknown { status }
|
||||
};
|
||||
}
|
||||
|
||||
fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap,
|
||||
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
|
||||
{
|
||||
// TODO issue #295
|
||||
//const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
|
||||
var stdin_pipe: [2]i32 = undefined;
|
||||
if (stdin == StdIo.Pipe)
|
||||
stdin_pipe = %return makePipe();
|
||||
%defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); };
|
||||
|
||||
// TODO issue #295
|
||||
//const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined;
|
||||
var stdout_pipe: [2]i32 = undefined;
|
||||
if (stdout == StdIo.Pipe)
|
||||
stdout_pipe = %return makePipe();
|
||||
%defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); };
|
||||
|
||||
// TODO issue #295
|
||||
//const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined;
|
||||
var stderr_pipe: [2]i32 = undefined;
|
||||
if (stderr == StdIo.Pipe)
|
||||
stderr_pipe = %return makePipe();
|
||||
%defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); };
|
||||
|
||||
const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore);
|
||||
// TODO issue #295
|
||||
//const dev_null_fd = if (any_ignore) {
|
||||
// %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null)
|
||||
//} else {
|
||||
// undefined
|
||||
//};
|
||||
var dev_null_fd: i32 = undefined;
|
||||
if (any_ignore)
|
||||
dev_null_fd = %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null);
|
||||
|
||||
// This pipe is used to communicate errors between the time of fork
|
||||
// and execve from the child process to the parent process.
|
||||
const err_pipe = %return makePipe();
|
||||
%defer destroyPipe(err_pipe);
|
||||
|
||||
const pid = posix.fork();
|
||||
const pid_err = posix.getErrno(pid);
|
||||
if (pid_err > 0) {
|
||||
return switch (pid_err) {
|
||||
errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
if (pid == 0) {
|
||||
// we are the child
|
||||
setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %%
|
||||
|err| forkChildErrReport(err_pipe[1], err);
|
||||
setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %%
|
||||
|err| forkChildErrReport(err_pipe[1], err);
|
||||
setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
|
||||
|err| forkChildErrReport(err_pipe[1], err);
|
||||
|
||||
const err = posix.getErrno(%return os.posixExecve(exe_path, args, env_map, allocator));
|
||||
assert(err > 0);
|
||||
forkChildErrReport(err_pipe[1], switch (err) {
|
||||
errno.EFAULT => unreachable,
|
||||
errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources,
|
||||
errno.EACCES, errno.EPERM => error.AccessDenied,
|
||||
errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
|
||||
errno.EIO, errno.ELOOP => error.FileSystem,
|
||||
errno.EISDIR => error.IsDir,
|
||||
errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
|
||||
errno.ETXTBSY => error.FileBusy,
|
||||
else => error.Unexpected,
|
||||
});
|
||||
}
|
||||
|
||||
// we are the parent
|
||||
if (stdin == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); }
|
||||
if (stdout == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); }
|
||||
if (stderr == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); }
|
||||
if (any_ignore) { os.posixClose(dev_null_fd); }
|
||||
|
||||
return ChildProcess {
|
||||
.pid = i32(pid),
|
||||
.err_pipe = err_pipe,
|
||||
|
||||
.stdin = if (stdin == StdIo.Pipe) {
|
||||
io.OutStream {
|
||||
.fd = stdin_pipe[1],
|
||||
.buffer = undefined,
|
||||
.index = 0,
|
||||
}
|
||||
} else {
|
||||
null
|
||||
},
|
||||
.stdout = if (stdout == StdIo.Pipe) {
|
||||
io.InStream {
|
||||
.fd = stdout_pipe[0],
|
||||
}
|
||||
} else {
|
||||
null
|
||||
},
|
||||
.stderr = if (stderr == StdIo.Pipe) {
|
||||
io.InStream {
|
||||
.fd = stderr_pipe[0],
|
||||
}
|
||||
} else {
|
||||
null
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {
|
||||
switch (stdio) {
|
||||
StdIo.Pipe => %return os.posixDup2(pipe_fd, std_fileno),
|
||||
StdIo.Close => os.posixClose(std_fileno),
|
||||
StdIo.Inherit => {},
|
||||
StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn makePipe() -> %[2]i32 {
|
||||
var fds: [2]i32 = undefined;
|
||||
const err = posix.getErrno(posix.pipe(&fds));
|
||||
if (err > 0) {
|
||||
return switch (err) {
|
||||
errno.EMFILE, errno.ENFILE => error.SysResources,
|
||||
else => error.Unexpected,
|
||||
}
|
||||
}
|
||||
return fds;
|
||||
}
|
||||
|
||||
fn destroyPipe(pipe: &const [2]i32) {
|
||||
os.posixClose((*pipe)[0]);
|
||||
os.posixClose((*pipe)[1]);
|
||||
}
|
||||
|
||||
// Child of fork calls this to report an error to the fork parent.
|
||||
// Then the child exits.
|
||||
fn forkChildErrReport(fd: i32, err: error) -> noreturn {
|
||||
_ = writeIntFd(fd, ErrInt(err));
|
||||
posix.exit(1);
|
||||
}
|
||||
|
||||
const ErrInt = @intType(false, @sizeOf(error) * 8);
|
||||
fn writeIntFd(fd: i32, value: ErrInt) -> %void {
|
||||
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
|
||||
mem.writeInt(bytes[0...], value, true);
|
||||
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) {
|
||||
const amt_written = posix.write(fd, &bytes[index], bytes.len - index);
|
||||
const err = posix.getErrno(amt_written);
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
errno.EINTR => continue,
|
||||
errno.EINVAL => unreachable,
|
||||
else => return error.SysResources,
|
||||
}
|
||||
}
|
||||
index += amt_written;
|
||||
}
|
||||
}
|
||||
|
||||
fn readIntFd(fd: i32) -> %ErrInt {
|
||||
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
|
||||
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) {
|
||||
const amt_written = posix.read(fd, &bytes[index], bytes.len - index);
|
||||
const err = posix.getErrno(amt_written);
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
errno.EINTR => continue,
|
||||
errno.EINVAL => unreachable,
|
||||
else => return error.SysResources,
|
||||
}
|
||||
}
|
||||
index += amt_written;
|
||||
}
|
||||
|
||||
return mem.readInt(bytes[0...], ErrInt, true);
|
||||
}
|
||||
|
313
std/os/index.zig
313
std/os/index.zig
|
@ -9,6 +9,7 @@ pub const posix = switch(@compileVar("os")) {
|
|||
};
|
||||
|
||||
pub const max_noalloc_path_len = 1024;
|
||||
pub const ChildProcess = @import("child_process.zig").ChildProcess;
|
||||
|
||||
const debug = @import("../debug.zig");
|
||||
const assert = debug.assert;
|
||||
|
@ -20,7 +21,6 @@ const c = @import("../c/index.zig");
|
|||
const mem = @import("../mem.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
const io = @import("../io.zig");
|
||||
const HashMap = @import("../hash_map.zig").HashMap;
|
||||
const cstr = @import("../cstr.zig");
|
||||
|
||||
|
@ -96,23 +96,6 @@ pub coldcc fn abort() -> noreturn {
|
|||
}
|
||||
}
|
||||
|
||||
fn makePipe() -> %[2]i32 {
|
||||
var fds: [2]i32 = undefined;
|
||||
const err = posix.getErrno(posix.pipe(&fds));
|
||||
if (err > 0) {
|
||||
return switch (err) {
|
||||
errno.EMFILE, errno.ENFILE => error.SysResources,
|
||||
else => error.Unexpected,
|
||||
}
|
||||
}
|
||||
return fds;
|
||||
}
|
||||
|
||||
fn destroyPipe(pipe: &const [2]i32) {
|
||||
posixClose((*pipe)[0]);
|
||||
posixClose((*pipe)[1]);
|
||||
}
|
||||
|
||||
/// Calls POSIX close, and keeps trying if it gets interrupted.
|
||||
pub fn posixClose(fd: i32) {
|
||||
while (true) {
|
||||
|
@ -202,54 +185,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc
|
|||
}
|
||||
}
|
||||
|
||||
const ErrInt = @intType(false, @sizeOf(error) * 8);
|
||||
fn writeIntFd(fd: i32, value: ErrInt) -> %void {
|
||||
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
|
||||
mem.writeInt(bytes[0...], value, true);
|
||||
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) {
|
||||
const amt_written = posix.write(fd, &bytes[index], bytes.len - index);
|
||||
const err = posix.getErrno(amt_written);
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
errno.EINTR => continue,
|
||||
errno.EINVAL => unreachable,
|
||||
else => return error.SysResources,
|
||||
}
|
||||
}
|
||||
index += amt_written;
|
||||
}
|
||||
}
|
||||
|
||||
fn readIntFd(fd: i32) -> %ErrInt {
|
||||
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
|
||||
|
||||
var index: usize = 0;
|
||||
while (index < bytes.len) {
|
||||
const amt_written = posix.read(fd, &bytes[index], bytes.len - index);
|
||||
const err = posix.getErrno(amt_written);
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
errno.EINTR => continue,
|
||||
errno.EINVAL => unreachable,
|
||||
else => return error.SysResources,
|
||||
}
|
||||
}
|
||||
index += amt_written;
|
||||
}
|
||||
|
||||
return mem.readInt(bytes[0...], ErrInt, true);
|
||||
}
|
||||
|
||||
// Child of fork calls this to report an error to the fork parent.
|
||||
// Then the child exits.
|
||||
fn forkChildErrReport(fd: i32, err: error) -> noreturn {
|
||||
_ = writeIntFd(fd, ErrInt(err));
|
||||
posix.exit(1);
|
||||
}
|
||||
|
||||
fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void {
|
||||
pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
|
||||
while (true) {
|
||||
const err = posix.getErrno(posix.dup2(old_fd, new_fd));
|
||||
if (err > 0) {
|
||||
|
@ -264,218 +200,13 @@ fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void {
|
|||
}
|
||||
}
|
||||
|
||||
pub const ChildProcess = struct {
|
||||
pid: i32,
|
||||
err_pipe: [2]i32,
|
||||
|
||||
stdin: ?io.OutStream,
|
||||
stdout: ?io.InStream,
|
||||
stderr: ?io.InStream,
|
||||
|
||||
pub const Term = enum {
|
||||
Clean: i32,
|
||||
Signal: i32,
|
||||
Stopped: i32,
|
||||
Unknown: i32,
|
||||
};
|
||||
|
||||
pub const StdIo = enum {
|
||||
Inherit,
|
||||
Ignore,
|
||||
Pipe,
|
||||
Close,
|
||||
};
|
||||
|
||||
pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap,
|
||||
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
|
||||
{
|
||||
switch (@compileVar("os")) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.darwin => {
|
||||
return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator);
|
||||
},
|
||||
else => @compileError("Unsupported OS"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait(self: &ChildProcess) -> %Term {
|
||||
defer {
|
||||
posixClose(self.err_pipe[0]);
|
||||
posixClose(self.err_pipe[1]);
|
||||
};
|
||||
|
||||
var status: i32 = undefined;
|
||||
while (true) {
|
||||
const err = posix.getErrno(posix.waitpid(self.pid, &status, 0));
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
errno.EINVAL, errno.ECHILD => unreachable,
|
||||
errno.EINTR => continue,
|
||||
else => {
|
||||
if (const *stdin ?= self.stdin) { stdin.close(); }
|
||||
if (const *stdout ?= self.stdin) { stdout.close(); }
|
||||
if (const *stderr ?= self.stdin) { stderr.close(); }
|
||||
return error.Unexpected;
|
||||
},
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (const *stdin ?= self.stdin) { stdin.close(); }
|
||||
if (const *stdout ?= self.stdin) { stdout.close(); }
|
||||
if (const *stderr ?= self.stdin) { stderr.close(); }
|
||||
|
||||
// Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
|
||||
// waitpid, so this write is guaranteed to be after the child
|
||||
// pid potentially wrote an error. This way we can do a blocking
|
||||
// read on the error pipe and either get @maxValue(ErrInt) (no error) or
|
||||
// an error code.
|
||||
%return writeIntFd(self.err_pipe[1], @maxValue(ErrInt));
|
||||
const err_int = %return readIntFd(self.err_pipe[0]);
|
||||
// Here we potentially return the fork child's error
|
||||
// from the parent pid.
|
||||
if (err_int != @maxValue(ErrInt)) {
|
||||
return error(err_int);
|
||||
}
|
||||
|
||||
return statusToTerm(status);
|
||||
}
|
||||
|
||||
fn statusToTerm(status: i32) -> Term {
|
||||
return if (posix.WIFEXITED(status)) {
|
||||
Term.Clean { posix.WEXITSTATUS(status) }
|
||||
} else if (posix.WIFSIGNALED(status)) {
|
||||
Term.Signal { posix.WTERMSIG(status) }
|
||||
} else if (posix.WIFSTOPPED(status)) {
|
||||
Term.Stopped { posix.WSTOPSIG(status) }
|
||||
} else {
|
||||
Term.Unknown { status }
|
||||
};
|
||||
}
|
||||
|
||||
fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap,
|
||||
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
|
||||
{
|
||||
// TODO issue #295
|
||||
//const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
|
||||
var stdin_pipe: [2]i32 = undefined;
|
||||
if (stdin == StdIo.Pipe)
|
||||
stdin_pipe = %return makePipe();
|
||||
%defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); };
|
||||
|
||||
// TODO issue #295
|
||||
//const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined;
|
||||
var stdout_pipe: [2]i32 = undefined;
|
||||
if (stdout == StdIo.Pipe)
|
||||
stdout_pipe = %return makePipe();
|
||||
%defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); };
|
||||
|
||||
// TODO issue #295
|
||||
//const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined;
|
||||
var stderr_pipe: [2]i32 = undefined;
|
||||
if (stderr == StdIo.Pipe)
|
||||
stderr_pipe = %return makePipe();
|
||||
%defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); };
|
||||
|
||||
const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore);
|
||||
// TODO issue #295
|
||||
//const dev_null_fd = if (any_ignore) {
|
||||
// %return posixOpen("/dev/null", posix.O_RDWR, 0, null)
|
||||
//} else {
|
||||
// undefined
|
||||
//};
|
||||
var dev_null_fd: i32 = undefined;
|
||||
if (any_ignore)
|
||||
dev_null_fd = %return posixOpen("/dev/null", posix.O_RDWR, 0, null);
|
||||
|
||||
// This pipe is used to communicate errors between the time of fork
|
||||
// and execve from the child process to the parent process.
|
||||
const err_pipe = %return makePipe();
|
||||
%defer destroyPipe(err_pipe);
|
||||
|
||||
const pid = posix.fork();
|
||||
const pid_err = linux.getErrno(pid);
|
||||
if (pid_err > 0) {
|
||||
return switch (pid_err) {
|
||||
errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources,
|
||||
else => error.Unexpected,
|
||||
};
|
||||
}
|
||||
if (pid == 0) {
|
||||
// we are the child
|
||||
setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %%
|
||||
|err| forkChildErrReport(err_pipe[1], err);
|
||||
setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %%
|
||||
|err| forkChildErrReport(err_pipe[1], err);
|
||||
setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
|
||||
|err| forkChildErrReport(err_pipe[1], err);
|
||||
|
||||
const err = posix.getErrno(%return execve(exe_path, args, env_map, allocator));
|
||||
assert(err > 0);
|
||||
forkChildErrReport(err_pipe[1], switch (err) {
|
||||
errno.EFAULT => unreachable,
|
||||
errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources,
|
||||
errno.EACCES, errno.EPERM => error.AccessDenied,
|
||||
errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
|
||||
errno.EIO, errno.ELOOP => error.FileSystem,
|
||||
errno.EISDIR => error.IsDir,
|
||||
errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
|
||||
errno.ETXTBSY => error.FileBusy,
|
||||
else => error.Unexpected,
|
||||
});
|
||||
}
|
||||
|
||||
// we are the parent
|
||||
if (stdin == StdIo.Pipe) { posixClose(stdin_pipe[0]); }
|
||||
if (stdout == StdIo.Pipe) { posixClose(stdout_pipe[1]); }
|
||||
if (stderr == StdIo.Pipe) { posixClose(stderr_pipe[1]); }
|
||||
if (any_ignore) { posixClose(dev_null_fd); }
|
||||
|
||||
return ChildProcess {
|
||||
.pid = i32(pid),
|
||||
.err_pipe = err_pipe,
|
||||
|
||||
.stdin = if (stdin == StdIo.Pipe) {
|
||||
io.OutStream {
|
||||
.fd = stdin_pipe[1],
|
||||
.buffer = undefined,
|
||||
.index = 0,
|
||||
}
|
||||
} else {
|
||||
null
|
||||
},
|
||||
.stdout = if (stdout == StdIo.Pipe) {
|
||||
io.InStream {
|
||||
.fd = stdout_pipe[0],
|
||||
}
|
||||
} else {
|
||||
null
|
||||
},
|
||||
.stderr = if (stderr == StdIo.Pipe) {
|
||||
io.InStream {
|
||||
.fd = stderr_pipe[0],
|
||||
}
|
||||
} else {
|
||||
null
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {
|
||||
switch (stdio) {
|
||||
StdIo.Pipe => %return dup2NoIntr(pipe_fd, std_fileno),
|
||||
StdIo.Close => posixClose(std_fileno),
|
||||
StdIo.Inherit => {},
|
||||
StdIo.Ignore => %return dup2NoIntr(dev_null_fd, std_fileno),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// This function must allocate memory to add a null terminating bytes on path and each arg.
|
||||
/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
|
||||
/// pointers after the args and after the environment variables.
|
||||
/// Also make the first arg equal to path.
|
||||
fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize {
|
||||
pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap,
|
||||
allocator: &Allocator) -> %usize
|
||||
{
|
||||
const path_buf = %return allocator.alloc(u8, path.len + 1);
|
||||
defer allocator.free(path_buf);
|
||||
@memcpy(&path_buf[0], &path[0], path.len);
|
||||
|
@ -604,6 +335,19 @@ pub const EnvMap = struct {
|
|||
mem.copy(u8, result, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn hash_slice_u8(k: []const u8) -> u32 {
|
||||
// FNV 32-bit hash
|
||||
var h: u32 = 2166136261;
|
||||
for (k) |b| {
|
||||
h = (h ^ b) *% 16777619;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
|
||||
return mem.eql(u8, a, b);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn getEnvMap(allocator: &Allocator) -> %EnvMap {
|
||||
|
@ -641,15 +385,14 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 {
|
|||
return null;
|
||||
}
|
||||
|
||||
fn hash_slice_u8(k: []const u8) -> u32 {
|
||||
// FNV 32-bit hash
|
||||
var h: u32 = 2166136261;
|
||||
for (k) |b| {
|
||||
h = (h ^ b) *% 16777619;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
pub const args = struct {
|
||||
pub var raw: []&u8 = undefined;
|
||||
|
||||
fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
|
||||
return mem.eql(u8, a, b);
|
||||
}
|
||||
pub fn count() -> usize {
|
||||
return raw.len;
|
||||
}
|
||||
pub fn at(i: usize) -> []const u8 {
|
||||
const s = raw[i];
|
||||
return s[0...cstr.len(s)];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -37,20 +37,14 @@ fn callMainAndExit() -> noreturn {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
var args_data: [32][]u8 = undefined;
|
||||
fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
|
||||
// TODO create args API to make it work with > 32 args
|
||||
const args = args_data[0...argc];
|
||||
for (args) |_, i| {
|
||||
const ptr = argv[i];
|
||||
args[i] = ptr[0...std.cstr.len(ptr)];
|
||||
}
|
||||
std.os.args.raw = argv[0...argc];
|
||||
|
||||
var env_count: usize = 0;
|
||||
while (envp[env_count] != null; env_count += 1) {}
|
||||
std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count];
|
||||
|
||||
return root.main(args);
|
||||
return root.main();
|
||||
}
|
||||
|
||||
export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
const root = @import("@build");
|
||||
const std = @import("std");
|
||||
const io = std.io;
|
||||
const os = std.os;
|
||||
const Builder = std.build.Builder;
|
||||
const mem = std.mem;
|
||||
|
||||
error InvalidArgs;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
if (args.len < 2) {
|
||||
pub fn main() -> %void {
|
||||
if (os.args.count() < 2) {
|
||||
%%io.stderr.printf("Expected first argument to be path to zig compiler\n");
|
||||
return error.InvalidArgs;
|
||||
}
|
||||
const zig_exe = args[1];
|
||||
const leftover_args = args[2...];
|
||||
const zig_exe = os.args.at(1);
|
||||
const leftover_arg_index = 2;
|
||||
|
||||
// TODO use a more general purpose allocator here
|
||||
var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024);
|
||||
|
@ -20,5 +21,5 @@ pub fn main(args: [][]u8) -> %void {
|
|||
|
||||
var builder = Builder.init(zig_exe, &inc_allocator.allocator);
|
||||
root.build(&builder);
|
||||
%return builder.make(leftover_args);
|
||||
%return builder.make(leftover_arg_index);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ const TestFn = struct {
|
|||
|
||||
extern var zig_test_fn_list: []TestFn;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
for (zig_test_fn_list) |testFn, i| {
|
||||
%%io.stderr.printf("Test {}/{} {}...", i + 1, zig_test_fn_list.len, testFn.name);
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ export fn main(argc: c_int, argv: &&u8) -> c_int {
|
|||
use @import("std").io;
|
||||
use @import("foo.zig");
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
privateFunction();
|
||||
%%stdout.printf("OK 2\n");
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ pub fn printText() {
|
|||
use @import("foo.zig");
|
||||
use @import("bar.zig");
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
foo_function();
|
||||
bar_function();
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ pub fn foo_function() -> bool {
|
|||
TestCase *tc = add_simple_case("two files use import each other", R"SOURCE(
|
||||
use @import("a.zig");
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
ok();
|
||||
}
|
||||
)SOURCE", "OK\n");
|
||||
|
@ -309,7 +309,7 @@ pub const b_text = a_text;
|
|||
add_simple_case("hello world without libc", R"SOURCE(
|
||||
const io = @import("std").io;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
%%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));
|
||||
}
|
||||
)SOURCE", "Hello, world!\n0012 012 a\n");
|
||||
|
@ -446,7 +446,7 @@ const io = @import("std").io;
|
|||
const z = io.stdin_fileno;
|
||||
const x : @typeOf(y) = 1234;
|
||||
const y : u16 = 5678;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
var x_local : i32 = print_ok(x);
|
||||
}
|
||||
fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
|
||||
|
@ -471,7 +471,7 @@ export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
|
|||
}
|
||||
}
|
||||
|
||||
export fn main(args: c_int, argv: &&u8) -> c_int {
|
||||
export fn main() -> c_int {
|
||||
var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
|
||||
|
||||
c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
|
||||
|
@ -516,7 +516,7 @@ const Bar = struct {
|
|||
fn method(b: &const Bar) -> bool { true }
|
||||
};
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const bar = Bar {.field2 = 13,};
|
||||
const foo = Foo {.field1 = bar,};
|
||||
if (!foo.method()) {
|
||||
|
@ -532,7 +532,7 @@ pub fn main(args: [][]u8) -> %void {
|
|||
|
||||
add_simple_case("defer with only fallthrough", R"SOURCE(
|
||||
const io = @import("std").io;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
%%io.stdout.printf("before\n");
|
||||
defer %%io.stdout.printf("defer1\n");
|
||||
defer %%io.stdout.printf("defer2\n");
|
||||
|
@ -544,11 +544,12 @@ pub fn main(args: [][]u8) -> %void {
|
|||
|
||||
add_simple_case("defer with return", R"SOURCE(
|
||||
const io = @import("std").io;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
const os = @import("std").os;
|
||||
pub fn main() -> %void {
|
||||
%%io.stdout.printf("before\n");
|
||||
defer %%io.stdout.printf("defer1\n");
|
||||
defer %%io.stdout.printf("defer2\n");
|
||||
if (args.len == 1) return;
|
||||
if (os.args.count() == 1) return;
|
||||
defer %%io.stdout.printf("defer3\n");
|
||||
%%io.stdout.printf("after\n");
|
||||
}
|
||||
|
@ -557,7 +558,7 @@ pub fn main(args: [][]u8) -> %void {
|
|||
|
||||
add_simple_case("%defer and it fails", R"SOURCE(
|
||||
const io = @import("std").io;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
do_test() %% return;
|
||||
}
|
||||
fn do_test() -> %void {
|
||||
|
@ -577,7 +578,7 @@ fn its_gonna_fail() -> %void {
|
|||
|
||||
add_simple_case("%defer and it passes", R"SOURCE(
|
||||
const io = @import("std").io;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
do_test() %% return;
|
||||
}
|
||||
fn do_test() -> %void {
|
||||
|
@ -597,7 +598,7 @@ fn its_gonna_pass() -> %void { }
|
|||
const foo_txt = @embedFile("foo.txt");
|
||||
const io = @import("std").io;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
%%io.stdout.printf(foo_txt);
|
||||
}
|
||||
)SOURCE", "1234\nabcd\n");
|
||||
|
@ -1388,9 +1389,13 @@ fn something() -> %void { }
|
|||
".tmp_source.zig:3:5: error: expected type 'void', found 'error'");
|
||||
|
||||
add_compile_fail_case("wrong return type for main", R"SOURCE(
|
||||
pub fn main(args: [][]u8) { }
|
||||
)SOURCE", 1, ".tmp_source.zig:2:27: error: expected return type of main to be '%void', instead is 'void'");
|
||||
pub fn main() { }
|
||||
)SOURCE", 1, ".tmp_source.zig:2:15: error: expected return type of main to be '%void', instead is 'void'");
|
||||
|
||||
add_compile_fail_case("double ?? on main return value", R"SOURCE(
|
||||
pub fn main() -> ??void {
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:2:18: error: expected return type of main to be '%void', instead is '??void'");
|
||||
|
||||
add_compile_fail_case("invalid pointer for var type", R"SOURCE(
|
||||
extern fn ext() -> usize;
|
||||
|
@ -1689,11 +1694,6 @@ fn bar(a: i32, b: []const u8) {
|
|||
".tmp_source.zig:8:5: error: found compile log statement",
|
||||
".tmp_source.zig:3:17: note: called from here");
|
||||
|
||||
add_compile_fail_case("double ?? on main return value", R"SOURCE(
|
||||
pub fn main(args: [][]u8) -> ??void {
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:2:30: error: expected return type of main to be '%void', instead is '??void'");
|
||||
|
||||
add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE(
|
||||
const u2 = @intType(false, 2);
|
||||
const u3 = @intType(false, 3);
|
||||
|
@ -1844,7 +1844,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
@breakpoint();
|
||||
while (true) {}
|
||||
}
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
if (!@compileVar("is_release")) {
|
||||
@panic("oh no");
|
||||
}
|
||||
|
@ -1856,7 +1856,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
@breakpoint();
|
||||
while (true) {}
|
||||
}
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const a = []i32{1, 2, 3, 4};
|
||||
baz(bar(a));
|
||||
}
|
||||
|
@ -1872,7 +1872,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = add(65530, 10);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -1887,7 +1887,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = sub(10, 20);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -1902,7 +1902,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = mul(300, 6000);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -1917,7 +1917,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = neg(-32768);
|
||||
if (x == 32767) return error.Whatever;
|
||||
}
|
||||
|
@ -1932,7 +1932,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = div(-32768, -1);
|
||||
if (x == 32767) return error.Whatever;
|
||||
}
|
||||
|
@ -1947,7 +1947,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = shl(-16385, 1);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -1962,7 +1962,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = shl(0b0010111111111111, 3);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -1977,7 +1977,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = div0(999, 0);
|
||||
}
|
||||
fn div0(a: i32, b: i32) -> i32 {
|
||||
|
@ -1991,7 +1991,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = divExact(10, 3);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -2006,7 +2006,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = widenSlice([]u8{1, 2, 3, 4, 5});
|
||||
if (x.len == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -2021,7 +2021,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = shorten_cast(200);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -2036,7 +2036,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
const x = unsigned_cast(-10);
|
||||
if (x == 0) return error.Whatever;
|
||||
}
|
||||
|
@ -2051,7 +2051,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
while (true) {}
|
||||
}
|
||||
error Whatever;
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
%%bar();
|
||||
}
|
||||
fn bar() -> %void {
|
||||
|
@ -2064,7 +2064,7 @@ pub fn panic(message: []const u8) -> noreturn {
|
|||
@breakpoint();
|
||||
while (true) {}
|
||||
}
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
pub fn main() -> %void {
|
||||
_ = bar(9999);
|
||||
}
|
||||
fn bar(x: u32) -> error {
|
||||
|
@ -2500,25 +2500,13 @@ static void run_test(TestCase *test_case) {
|
|||
}
|
||||
}
|
||||
|
||||
static void run_all_tests(bool reverse) {
|
||||
if (reverse) {
|
||||
for (size_t i = test_cases.length;;) {
|
||||
TestCase *test_case = test_cases.at(i);
|
||||
printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
|
||||
fflush(stdout);
|
||||
run_test(test_case);
|
||||
printf("OK\n");
|
||||
if (i == 0) break;
|
||||
i -= 1;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < test_cases.length; i += 1) {
|
||||
TestCase *test_case = test_cases.at(i);
|
||||
printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
|
||||
fflush(stdout);
|
||||
run_test(test_case);
|
||||
printf("OK\n");
|
||||
}
|
||||
static void run_all_tests(void) {
|
||||
for (size_t i = 0; i < test_cases.length; i += 1) {
|
||||
TestCase *test_case = test_cases.at(i);
|
||||
printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
|
||||
fflush(stdout);
|
||||
run_test(test_case);
|
||||
printf("OK\n");
|
||||
}
|
||||
printf("%zu tests passed.\n", test_cases.length);
|
||||
}
|
||||
|
@ -2530,18 +2518,13 @@ static void cleanup(void) {
|
|||
}
|
||||
|
||||
static int usage(const char *arg0) {
|
||||
fprintf(stderr, "Usage: %s [--reverse]\n", arg0);
|
||||
fprintf(stderr, "Usage: %s\n", arg0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bool reverse = false;
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
if (strcmp(argv[i], "--reverse") == 0) {
|
||||
reverse = true;
|
||||
} else {
|
||||
return usage(argv[0]);
|
||||
}
|
||||
return usage(argv[0]);
|
||||
}
|
||||
add_compiling_test_cases();
|
||||
add_debug_safety_test_cases();
|
||||
|
@ -2549,6 +2532,6 @@ int main(int argc, char **argv) {
|
|||
add_parseh_test_cases();
|
||||
add_self_hosted_tests();
|
||||
add_std_lib_tests();
|
||||
run_all_tests(reverse);
|
||||
run_all_tests();
|
||||
cleanup();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue