| author | |
| committer | |
| log | 72fb2443e0e5dd0c8c3a0265428832796b4ff548 |
| tree | dd4cfda1e44784a80538ccd3c6d776c3fb664651 |
| parent | b46344fd01db28384b51d9898ef25c4825bb19b0 |
closes #30011 files changed, 381 insertions(+), 374 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -223,6 +223,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}") |
| 223 | 223 | install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}") |
| 224 | 224 | install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}") |
| 225 | 225 | install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") |
| 226 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os") | |
| 226 | 227 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 227 | 228 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 228 | 229 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/errno.zig" DESTINATION "${ZIG_STD_DEST}/os") |
example/cat/main.zig+9-7| ... | ... | @@ -1,23 +1,25 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const io = std.io; |
| 3 | 3 | const mem = std.mem; |
| 4 | const os = std.os; | |
| 4 | 5 | |
| 5 | pub fn main(args: [][]u8) -> %void { | |
| 6 | const exe = args[0]; | |
| 6 | pub fn main() -> %void { | |
| 7 | const exe = os.args.at(0); | |
| 7 | 8 | var catted_anything = false; |
| 8 | for (args[1...]) |arg| { | |
| 9 | var arg_i: usize = 1; | |
| 10 | while (arg_i < os.args.count(); arg_i += 1) { | |
| 11 | const arg = os.args.at(arg_i); | |
| 9 | 12 | if (mem.eql(u8, arg, "-")) { |
| 10 | 13 | catted_anything = true; |
| 11 | 14 | %return cat_stream(&io.stdin); |
| 12 | 15 | } else if (arg[0] == '-') { |
| 13 | 16 | return usage(exe); |
| 14 | 17 | } else { |
| 15 | var is: io.InStream = undefined; | |
| 16 | is.open(arg) %% |err| { | |
| 18 | var is = io.InStream.open(arg, null) %% |err| { | |
| 17 | 19 | %%io.stderr.printf("Unable to open file: {}\n", @errorName(err)); |
| 18 | 20 | return err; |
| 19 | 21 | }; |
| 20 | defer %%is.close(); | |
| 22 | defer is.close(); | |
| 21 | 23 | |
| 22 | 24 | catted_anything = true; |
| 23 | 25 | %return cat_stream(&is); |
| ... | ... | @@ -29,7 +31,7 @@ pub fn main(args: [][]u8) -> %void { |
| 29 | 31 | %return io.stdout.flush(); |
| 30 | 32 | } |
| 31 | 33 | |
| 32 | fn usage(exe: []u8) -> %void { | |
| 34 | fn usage(exe: []const u8) -> %void { | |
| 33 | 35 | %%io.stderr.printf("Usage: {} [FILE]...\n", exe); |
| 34 | 36 | return error.Invalid; |
| 35 | 37 | } |
example/guess_number/main.zig+1-1| ... | ... | @@ -4,7 +4,7 @@ const fmt = std.fmt; |
| 4 | 4 | const Rand = std.rand.Rand; |
| 5 | 5 | const os = std.os; |
| 6 | 6 | |
| 7 | pub fn main(args: [][]u8) -> %void { | |
| 7 | pub fn main() -> %void { | |
| 8 | 8 | %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n"); |
| 9 | 9 | |
| 10 | 10 | var seed_bytes: [@sizeOf(usize)]u8 = undefined; |
example/hello_world/hello.zig+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | const io = @import("std").io; |
| 2 | 2 | |
| 3 | pub fn main(args: [][]u8) -> %void { | |
| 3 | pub fn main() -> %void { | |
| 4 | 4 | %%io.stdout.printf("Hello, world!\n"); |
| 5 | 5 | } |
std/build.zig+6-3| ... | ... | @@ -39,11 +39,13 @@ pub const Builder = struct { |
| 39 | 39 | return exe; |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | pub fn make(self: &Builder, cli_args: []const []const u8) -> %void { | |
| 42 | pub fn make(self: &Builder, leftover_arg_index: usize) -> %void { | |
| 43 | 43 | var env_map = %return os.getEnvMap(self.allocator); |
| 44 | 44 | |
| 45 | 45 | var verbose = false; |
| 46 | for (cli_args) |arg| { | |
| 46 | var arg_i: usize = leftover_arg_index; | |
| 47 | while (arg_i < os.args.count(); arg_i += 1) { | |
| 48 | const arg = os.args.at(arg_i); | |
| 47 | 49 | if (mem.eql(u8, arg, "--verbose")) { |
| 48 | 50 | verbose = true; |
| 49 | 51 | } else { |
| ... | ... | @@ -95,7 +97,8 @@ pub const Builder = struct { |
| 95 | 97 | } |
| 96 | 98 | |
| 97 | 99 | printInvocation(self.zig_exe, zig_args); |
| 98 | var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), env_map, | |
| 100 | // TODO issue #301 | |
| 101 | var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), &env_map, | |
| 99 | 102 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator); |
| 100 | 103 | const term = %return child.wait(); |
| 101 | 104 | switch (term) { |
std/os/child_process.zig created+280| ... | ... | @@ -0,0 +1,280 @@ |
| 1 | const io = @import("../io.zig"); | |
| 2 | const os = @import("index.zig"); | |
| 3 | const posix = os.posix; | |
| 4 | const mem = @import("../mem.zig"); | |
| 5 | const Allocator = mem.Allocator; | |
| 6 | const errno = @import("errno.zig"); | |
| 7 | const debug = @import("../debug.zig"); | |
| 8 | const assert = debug.assert; | |
| 9 | ||
| 10 | pub const ChildProcess = struct { | |
| 11 | pid: i32, | |
| 12 | err_pipe: [2]i32, | |
| 13 | ||
| 14 | stdin: ?io.OutStream, | |
| 15 | stdout: ?io.InStream, | |
| 16 | stderr: ?io.InStream, | |
| 17 | ||
| 18 | pub const Term = enum { | |
| 19 | Clean: i32, | |
| 20 | Signal: i32, | |
| 21 | Stopped: i32, | |
| 22 | Unknown: i32, | |
| 23 | }; | |
| 24 | ||
| 25 | pub const StdIo = enum { | |
| 26 | Inherit, | |
| 27 | Ignore, | |
| 28 | Pipe, | |
| 29 | Close, | |
| 30 | }; | |
| 31 | ||
| 32 | pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap, | |
| 33 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | |
| 34 | { | |
| 35 | switch (@compileVar("os")) { | |
| 36 | Os.linux, Os.macosx, Os.ios, Os.darwin => { | |
| 37 | return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator); | |
| 38 | }, | |
| 39 | else => @compileError("Unsupported OS"), | |
| 40 | } | |
| 41 | } | |
| 42 | ||
| 43 | pub fn wait(self: &ChildProcess) -> %Term { | |
| 44 | defer { | |
| 45 | os.posixClose(self.err_pipe[0]); | |
| 46 | os.posixClose(self.err_pipe[1]); | |
| 47 | }; | |
| 48 | ||
| 49 | var status: i32 = undefined; | |
| 50 | while (true) { | |
| 51 | const err = posix.getErrno(posix.waitpid(self.pid, &status, 0)); | |
| 52 | if (err > 0) { | |
| 53 | switch (err) { | |
| 54 | errno.EINVAL, errno.ECHILD => unreachable, | |
| 55 | errno.EINTR => continue, | |
| 56 | else => { | |
| 57 | if (const *stdin ?= self.stdin) { stdin.close(); } | |
| 58 | if (const *stdout ?= self.stdin) { stdout.close(); } | |
| 59 | if (const *stderr ?= self.stdin) { stderr.close(); } | |
| 60 | return error.Unexpected; | |
| 61 | }, | |
| 62 | } | |
| 63 | } | |
| 64 | break; | |
| 65 | } | |
| 66 | ||
| 67 | if (const *stdin ?= self.stdin) { stdin.close(); } | |
| 68 | if (const *stdout ?= self.stdin) { stdout.close(); } | |
| 69 | if (const *stderr ?= self.stdin) { stderr.close(); } | |
| 70 | ||
| 71 | // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after | |
| 72 | // waitpid, so this write is guaranteed to be after the child | |
| 73 | // pid potentially wrote an error. This way we can do a blocking | |
| 74 | // read on the error pipe and either get @maxValue(ErrInt) (no error) or | |
| 75 | // an error code. | |
| 76 | %return writeIntFd(self.err_pipe[1], @maxValue(ErrInt)); | |
| 77 | const err_int = %return readIntFd(self.err_pipe[0]); | |
| 78 | // Here we potentially return the fork child's error | |
| 79 | // from the parent pid. | |
| 80 | if (err_int != @maxValue(ErrInt)) { | |
| 81 | return error(err_int); | |
| 82 | } | |
| 83 | ||
| 84 | return statusToTerm(status); | |
| 85 | } | |
| 86 | ||
| 87 | fn statusToTerm(status: i32) -> Term { | |
| 88 | return if (posix.WIFEXITED(status)) { | |
| 89 | Term.Clean { posix.WEXITSTATUS(status) } | |
| 90 | } else if (posix.WIFSIGNALED(status)) { | |
| 91 | Term.Signal { posix.WTERMSIG(status) } | |
| 92 | } else if (posix.WIFSTOPPED(status)) { | |
| 93 | Term.Stopped { posix.WSTOPSIG(status) } | |
| 94 | } else { | |
| 95 | Term.Unknown { status } | |
| 96 | }; | |
| 97 | } | |
| 98 | ||
| 99 | fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap, | |
| 100 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | |
| 101 | { | |
| 102 | // TODO issue #295 | |
| 103 | //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | |
| 104 | var stdin_pipe: [2]i32 = undefined; | |
| 105 | if (stdin == StdIo.Pipe) | |
| 106 | stdin_pipe = %return makePipe(); | |
| 107 | %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | |
| 108 | ||
| 109 | // TODO issue #295 | |
| 110 | //const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined; | |
| 111 | var stdout_pipe: [2]i32 = undefined; | |
| 112 | if (stdout == StdIo.Pipe) | |
| 113 | stdout_pipe = %return makePipe(); | |
| 114 | %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | |
| 115 | ||
| 116 | // TODO issue #295 | |
| 117 | //const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined; | |
| 118 | var stderr_pipe: [2]i32 = undefined; | |
| 119 | if (stderr == StdIo.Pipe) | |
| 120 | stderr_pipe = %return makePipe(); | |
| 121 | %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | |
| 122 | ||
| 123 | const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore); | |
| 124 | // TODO issue #295 | |
| 125 | //const dev_null_fd = if (any_ignore) { | |
| 126 | // %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) | |
| 127 | //} else { | |
| 128 | // undefined | |
| 129 | //}; | |
| 130 | var dev_null_fd: i32 = undefined; | |
| 131 | if (any_ignore) | |
| 132 | dev_null_fd = %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null); | |
| 133 | ||
| 134 | // This pipe is used to communicate errors between the time of fork | |
| 135 | // and execve from the child process to the parent process. | |
| 136 | const err_pipe = %return makePipe(); | |
| 137 | %defer destroyPipe(err_pipe); | |
| 138 | ||
| 139 | const pid = posix.fork(); | |
| 140 | const pid_err = posix.getErrno(pid); | |
| 141 | if (pid_err > 0) { | |
| 142 | return switch (pid_err) { | |
| 143 | errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources, | |
| 144 | else => error.Unexpected, | |
| 145 | }; | |
| 146 | } | |
| 147 | if (pid == 0) { | |
| 148 | // we are the child | |
| 149 | setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %% | |
| 150 | |err| forkChildErrReport(err_pipe[1], err); | |
| 151 | setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %% | |
| 152 | |err| forkChildErrReport(err_pipe[1], err); | |
| 153 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | |
| 154 | |err| forkChildErrReport(err_pipe[1], err); | |
| 155 | ||
| 156 | const err = posix.getErrno(%return os.posixExecve(exe_path, args, env_map, allocator)); | |
| 157 | assert(err > 0); | |
| 158 | forkChildErrReport(err_pipe[1], switch (err) { | |
| 159 | errno.EFAULT => unreachable, | |
| 160 | errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources, | |
| 161 | errno.EACCES, errno.EPERM => error.AccessDenied, | |
| 162 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, | |
| 163 | errno.EIO, errno.ELOOP => error.FileSystem, | |
| 164 | errno.EISDIR => error.IsDir, | |
| 165 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | |
| 166 | errno.ETXTBSY => error.FileBusy, | |
| 167 | else => error.Unexpected, | |
| 168 | }); | |
| 169 | } | |
| 170 | ||
| 171 | // we are the parent | |
| 172 | if (stdin == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); } | |
| 173 | if (stdout == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); } | |
| 174 | if (stderr == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); } | |
| 175 | if (any_ignore) { os.posixClose(dev_null_fd); } | |
| 176 | ||
| 177 | return ChildProcess { | |
| 178 | .pid = i32(pid), | |
| 179 | .err_pipe = err_pipe, | |
| 180 | ||
| 181 | .stdin = if (stdin == StdIo.Pipe) { | |
| 182 | io.OutStream { | |
| 183 | .fd = stdin_pipe[1], | |
| 184 | .buffer = undefined, | |
| 185 | .index = 0, | |
| 186 | } | |
| 187 | } else { | |
| 188 | null | |
| 189 | }, | |
| 190 | .stdout = if (stdout == StdIo.Pipe) { | |
| 191 | io.InStream { | |
| 192 | .fd = stdout_pipe[0], | |
| 193 | } | |
| 194 | } else { | |
| 195 | null | |
| 196 | }, | |
| 197 | .stderr = if (stderr == StdIo.Pipe) { | |
| 198 | io.InStream { | |
| 199 | .fd = stderr_pipe[0], | |
| 200 | } | |
| 201 | } else { | |
| 202 | null | |
| 203 | }, | |
| 204 | }; | |
| 205 | } | |
| 206 | ||
| 207 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void { | |
| 208 | switch (stdio) { | |
| 209 | StdIo.Pipe => %return os.posixDup2(pipe_fd, std_fileno), | |
| 210 | StdIo.Close => os.posixClose(std_fileno), | |
| 211 | StdIo.Inherit => {}, | |
| 212 | StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno), | |
| 213 | } | |
| 214 | } | |
| 215 | }; | |
| 216 | ||
| 217 | fn makePipe() -> %[2]i32 { | |
| 218 | var fds: [2]i32 = undefined; | |
| 219 | const err = posix.getErrno(posix.pipe(&fds)); | |
| 220 | if (err > 0) { | |
| 221 | return switch (err) { | |
| 222 | errno.EMFILE, errno.ENFILE => error.SysResources, | |
| 223 | else => error.Unexpected, | |
| 224 | } | |
| 225 | } | |
| 226 | return fds; | |
| 227 | } | |
| 228 | ||
| 229 | fn destroyPipe(pipe: &const [2]i32) { | |
| 230 | os.posixClose((*pipe)[0]); | |
| 231 | os.posixClose((*pipe)[1]); | |
| 232 | } | |
| 233 | ||
| 234 | // Child of fork calls this to report an error to the fork parent. | |
| 235 | // Then the child exits. | |
| 236 | fn forkChildErrReport(fd: i32, err: error) -> noreturn { | |
| 237 | _ = writeIntFd(fd, ErrInt(err)); | |
| 238 | posix.exit(1); | |
| 239 | } | |
| 240 | ||
| 241 | const ErrInt = @intType(false, @sizeOf(error) * 8); | |
| 242 | fn writeIntFd(fd: i32, value: ErrInt) -> %void { | |
| 243 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | |
| 244 | mem.writeInt(bytes[0...], value, true); | |
| 245 | ||
| 246 | var index: usize = 0; | |
| 247 | while (index < bytes.len) { | |
| 248 | const amt_written = posix.write(fd, &bytes[index], bytes.len - index); | |
| 249 | const err = posix.getErrno(amt_written); | |
| 250 | if (err > 0) { | |
| 251 | switch (err) { | |
| 252 | errno.EINTR => continue, | |
| 253 | errno.EINVAL => unreachable, | |
| 254 | else => return error.SysResources, | |
| 255 | } | |
| 256 | } | |
| 257 | index += amt_written; | |
| 258 | } | |
| 259 | } | |
| 260 | ||
| 261 | fn readIntFd(fd: i32) -> %ErrInt { | |
| 262 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | |
| 263 | ||
| 264 | var index: usize = 0; | |
| 265 | while (index < bytes.len) { | |
| 266 | const amt_written = posix.read(fd, &bytes[index], bytes.len - index); | |
| 267 | const err = posix.getErrno(amt_written); | |
| 268 | if (err > 0) { | |
| 269 | switch (err) { | |
| 270 | errno.EINTR => continue, | |
| 271 | errno.EINVAL => unreachable, | |
| 272 | else => return error.SysResources, | |
| 273 | } | |
| 274 | } | |
| 275 | index += amt_written; | |
| 276 | } | |
| 277 | ||
| 278 | return mem.readInt(bytes[0...], ErrInt, true); | |
| 279 | } | |
| 280 |
std/os/index.zig+28-285| ... | ... | @@ -9,6 +9,7 @@ pub const posix = switch(@compileVar("os")) { |
| 9 | 9 | }; |
| 10 | 10 | |
| 11 | 11 | pub const max_noalloc_path_len = 1024; |
| 12 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | |
| 12 | 13 | |
| 13 | 14 | const debug = @import("../debug.zig"); |
| 14 | 15 | const assert = debug.assert; |
| ... | ... | @@ -20,7 +21,6 @@ const c = @import("../c/index.zig"); |
| 20 | 21 | const mem = @import("../mem.zig"); |
| 21 | 22 | const Allocator = mem.Allocator; |
| 22 | 23 | |
| 23 | const io = @import("../io.zig"); | |
| 24 | 24 | const HashMap = @import("../hash_map.zig").HashMap; |
| 25 | 25 | const cstr = @import("../cstr.zig"); |
| 26 | 26 | |
| ... | ... | @@ -96,23 +96,6 @@ pub coldcc fn abort() -> noreturn { |
| 96 | 96 | } |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | fn makePipe() -> %[2]i32 { | |
| 100 | var fds: [2]i32 = undefined; | |
| 101 | const err = posix.getErrno(posix.pipe(&fds)); | |
| 102 | if (err > 0) { | |
| 103 | return switch (err) { | |
| 104 | errno.EMFILE, errno.ENFILE => error.SysResources, | |
| 105 | else => error.Unexpected, | |
| 106 | } | |
| 107 | } | |
| 108 | return fds; | |
| 109 | } | |
| 110 | ||
| 111 | fn destroyPipe(pipe: &const [2]i32) { | |
| 112 | posixClose((*pipe)[0]); | |
| 113 | posixClose((*pipe)[1]); | |
| 114 | } | |
| 115 | ||
| 116 | 99 | /// Calls POSIX close, and keeps trying if it gets interrupted. |
| 117 | 100 | pub fn posixClose(fd: i32) { |
| 118 | 101 | while (true) { |
| ... | ... | @@ -202,54 +185,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc |
| 202 | 185 | } |
| 203 | 186 | } |
| 204 | 187 | |
| 205 | const ErrInt = @intType(false, @sizeOf(error) * 8); | |
| 206 | fn writeIntFd(fd: i32, value: ErrInt) -> %void { | |
| 207 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | |
| 208 | mem.writeInt(bytes[0...], value, true); | |
| 209 | ||
| 210 | var index: usize = 0; | |
| 211 | while (index < bytes.len) { | |
| 212 | const amt_written = posix.write(fd, &bytes[index], bytes.len - index); | |
| 213 | const err = posix.getErrno(amt_written); | |
| 214 | if (err > 0) { | |
| 215 | switch (err) { | |
| 216 | errno.EINTR => continue, | |
| 217 | errno.EINVAL => unreachable, | |
| 218 | else => return error.SysResources, | |
| 219 | } | |
| 220 | } | |
| 221 | index += amt_written; | |
| 222 | } | |
| 223 | } | |
| 224 | ||
| 225 | fn readIntFd(fd: i32) -> %ErrInt { | |
| 226 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | |
| 227 | ||
| 228 | var index: usize = 0; | |
| 229 | while (index < bytes.len) { | |
| 230 | const amt_written = posix.read(fd, &bytes[index], bytes.len - index); | |
| 231 | const err = posix.getErrno(amt_written); | |
| 232 | if (err > 0) { | |
| 233 | switch (err) { | |
| 234 | errno.EINTR => continue, | |
| 235 | errno.EINVAL => unreachable, | |
| 236 | else => return error.SysResources, | |
| 237 | } | |
| 238 | } | |
| 239 | index += amt_written; | |
| 240 | } | |
| 241 | ||
| 242 | return mem.readInt(bytes[0...], ErrInt, true); | |
| 243 | } | |
| 244 | ||
| 245 | // Child of fork calls this to report an error to the fork parent. | |
| 246 | // Then the child exits. | |
| 247 | fn forkChildErrReport(fd: i32, err: error) -> noreturn { | |
| 248 | _ = writeIntFd(fd, ErrInt(err)); | |
| 249 | posix.exit(1); | |
| 250 | } | |
| 251 | ||
| 252 | fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void { | |
| 188 | pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { | |
| 253 | 189 | while (true) { |
| 254 | 190 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); |
| 255 | 191 | if (err > 0) { |
| ... | ... | @@ -264,218 +200,13 @@ fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void { |
| 264 | 200 | } |
| 265 | 201 | } |
| 266 | 202 | |
| 267 | pub const ChildProcess = struct { | |
| 268 | pid: i32, | |
| 269 | err_pipe: [2]i32, | |
| 270 | ||
| 271 | stdin: ?io.OutStream, | |
| 272 | stdout: ?io.InStream, | |
| 273 | stderr: ?io.InStream, | |
| 274 | ||
| 275 | pub const Term = enum { | |
| 276 | Clean: i32, | |
| 277 | Signal: i32, | |
| 278 | Stopped: i32, | |
| 279 | Unknown: i32, | |
| 280 | }; | |
| 281 | ||
| 282 | pub const StdIo = enum { | |
| 283 | Inherit, | |
| 284 | Ignore, | |
| 285 | Pipe, | |
| 286 | Close, | |
| 287 | }; | |
| 288 | ||
| 289 | pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap, | |
| 290 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | |
| 291 | { | |
| 292 | switch (@compileVar("os")) { | |
| 293 | Os.linux, Os.macosx, Os.ios, Os.darwin => { | |
| 294 | return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator); | |
| 295 | }, | |
| 296 | else => @compileError("Unsupported OS"), | |
| 297 | } | |
| 298 | } | |
| 299 | ||
| 300 | pub fn wait(self: &ChildProcess) -> %Term { | |
| 301 | defer { | |
| 302 | posixClose(self.err_pipe[0]); | |
| 303 | posixClose(self.err_pipe[1]); | |
| 304 | }; | |
| 305 | ||
| 306 | var status: i32 = undefined; | |
| 307 | while (true) { | |
| 308 | const err = posix.getErrno(posix.waitpid(self.pid, &status, 0)); | |
| 309 | if (err > 0) { | |
| 310 | switch (err) { | |
| 311 | errno.EINVAL, errno.ECHILD => unreachable, | |
| 312 | errno.EINTR => continue, | |
| 313 | else => { | |
| 314 | if (const *stdin ?= self.stdin) { stdin.close(); } | |
| 315 | if (const *stdout ?= self.stdin) { stdout.close(); } | |
| 316 | if (const *stderr ?= self.stdin) { stderr.close(); } | |
| 317 | return error.Unexpected; | |
| 318 | }, | |
| 319 | } | |
| 320 | } | |
| 321 | break; | |
| 322 | } | |
| 323 | ||
| 324 | if (const *stdin ?= self.stdin) { stdin.close(); } | |
| 325 | if (const *stdout ?= self.stdin) { stdout.close(); } | |
| 326 | if (const *stderr ?= self.stdin) { stderr.close(); } | |
| 327 | ||
| 328 | // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after | |
| 329 | // waitpid, so this write is guaranteed to be after the child | |
| 330 | // pid potentially wrote an error. This way we can do a blocking | |
| 331 | // read on the error pipe and either get @maxValue(ErrInt) (no error) or | |
| 332 | // an error code. | |
| 333 | %return writeIntFd(self.err_pipe[1], @maxValue(ErrInt)); | |
| 334 | const err_int = %return readIntFd(self.err_pipe[0]); | |
| 335 | // Here we potentially return the fork child's error | |
| 336 | // from the parent pid. | |
| 337 | if (err_int != @maxValue(ErrInt)) { | |
| 338 | return error(err_int); | |
| 339 | } | |
| 340 | ||
| 341 | return statusToTerm(status); | |
| 342 | } | |
| 343 | ||
| 344 | fn statusToTerm(status: i32) -> Term { | |
| 345 | return if (posix.WIFEXITED(status)) { | |
| 346 | Term.Clean { posix.WEXITSTATUS(status) } | |
| 347 | } else if (posix.WIFSIGNALED(status)) { | |
| 348 | Term.Signal { posix.WTERMSIG(status) } | |
| 349 | } else if (posix.WIFSTOPPED(status)) { | |
| 350 | Term.Stopped { posix.WSTOPSIG(status) } | |
| 351 | } else { | |
| 352 | Term.Unknown { status } | |
| 353 | }; | |
| 354 | } | |
| 355 | ||
| 356 | fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap, | |
| 357 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | |
| 358 | { | |
| 359 | // TODO issue #295 | |
| 360 | //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | |
| 361 | var stdin_pipe: [2]i32 = undefined; | |
| 362 | if (stdin == StdIo.Pipe) | |
| 363 | stdin_pipe = %return makePipe(); | |
| 364 | %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | |
| 365 | ||
| 366 | // TODO issue #295 | |
| 367 | //const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined; | |
| 368 | var stdout_pipe: [2]i32 = undefined; | |
| 369 | if (stdout == StdIo.Pipe) | |
| 370 | stdout_pipe = %return makePipe(); | |
| 371 | %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | |
| 372 | ||
| 373 | // TODO issue #295 | |
| 374 | //const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined; | |
| 375 | var stderr_pipe: [2]i32 = undefined; | |
| 376 | if (stderr == StdIo.Pipe) | |
| 377 | stderr_pipe = %return makePipe(); | |
| 378 | %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | |
| 379 | ||
| 380 | const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore); | |
| 381 | // TODO issue #295 | |
| 382 | //const dev_null_fd = if (any_ignore) { | |
| 383 | // %return posixOpen("/dev/null", posix.O_RDWR, 0, null) | |
| 384 | //} else { | |
| 385 | // undefined | |
| 386 | //}; | |
| 387 | var dev_null_fd: i32 = undefined; | |
| 388 | if (any_ignore) | |
| 389 | dev_null_fd = %return posixOpen("/dev/null", posix.O_RDWR, 0, null); | |
| 390 | ||
| 391 | // This pipe is used to communicate errors between the time of fork | |
| 392 | // and execve from the child process to the parent process. | |
| 393 | const err_pipe = %return makePipe(); | |
| 394 | %defer destroyPipe(err_pipe); | |
| 395 | ||
| 396 | const pid = posix.fork(); | |
| 397 | const pid_err = linux.getErrno(pid); | |
| 398 | if (pid_err > 0) { | |
| 399 | return switch (pid_err) { | |
| 400 | errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources, | |
| 401 | else => error.Unexpected, | |
| 402 | }; | |
| 403 | } | |
| 404 | if (pid == 0) { | |
| 405 | // we are the child | |
| 406 | setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %% | |
| 407 | |err| forkChildErrReport(err_pipe[1], err); | |
| 408 | setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %% | |
| 409 | |err| forkChildErrReport(err_pipe[1], err); | |
| 410 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | |
| 411 | |err| forkChildErrReport(err_pipe[1], err); | |
| 412 | ||
| 413 | const err = posix.getErrno(%return execve(exe_path, args, env_map, allocator)); | |
| 414 | assert(err > 0); | |
| 415 | forkChildErrReport(err_pipe[1], switch (err) { | |
| 416 | errno.EFAULT => unreachable, | |
| 417 | errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources, | |
| 418 | errno.EACCES, errno.EPERM => error.AccessDenied, | |
| 419 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, | |
| 420 | errno.EIO, errno.ELOOP => error.FileSystem, | |
| 421 | errno.EISDIR => error.IsDir, | |
| 422 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | |
| 423 | errno.ETXTBSY => error.FileBusy, | |
| 424 | else => error.Unexpected, | |
| 425 | }); | |
| 426 | } | |
| 427 | ||
| 428 | // we are the parent | |
| 429 | if (stdin == StdIo.Pipe) { posixClose(stdin_pipe[0]); } | |
| 430 | if (stdout == StdIo.Pipe) { posixClose(stdout_pipe[1]); } | |
| 431 | if (stderr == StdIo.Pipe) { posixClose(stderr_pipe[1]); } | |
| 432 | if (any_ignore) { posixClose(dev_null_fd); } | |
| 433 | ||
| 434 | return ChildProcess { | |
| 435 | .pid = i32(pid), | |
| 436 | .err_pipe = err_pipe, | |
| 437 | ||
| 438 | .stdin = if (stdin == StdIo.Pipe) { | |
| 439 | io.OutStream { | |
| 440 | .fd = stdin_pipe[1], | |
| 441 | .buffer = undefined, | |
| 442 | .index = 0, | |
| 443 | } | |
| 444 | } else { | |
| 445 | null | |
| 446 | }, | |
| 447 | .stdout = if (stdout == StdIo.Pipe) { | |
| 448 | io.InStream { | |
| 449 | .fd = stdout_pipe[0], | |
| 450 | } | |
| 451 | } else { | |
| 452 | null | |
| 453 | }, | |
| 454 | .stderr = if (stderr == StdIo.Pipe) { | |
| 455 | io.InStream { | |
| 456 | .fd = stderr_pipe[0], | |
| 457 | } | |
| 458 | } else { | |
| 459 | null | |
| 460 | }, | |
| 461 | }; | |
| 462 | } | |
| 463 | ||
| 464 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void { | |
| 465 | switch (stdio) { | |
| 466 | StdIo.Pipe => %return dup2NoIntr(pipe_fd, std_fileno), | |
| 467 | StdIo.Close => posixClose(std_fileno), | |
| 468 | StdIo.Inherit => {}, | |
| 469 | StdIo.Ignore => %return dup2NoIntr(dev_null_fd, std_fileno), | |
| 470 | } | |
| 471 | } | |
| 472 | }; | |
| 473 | ||
| 474 | 203 | /// This function must allocate memory to add a null terminating bytes on path and each arg. |
| 475 | 204 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null |
| 476 | 205 | /// pointers after the args and after the environment variables. |
| 477 | 206 | /// Also make the first arg equal to path. |
| 478 | fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize { | |
| 207 | pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, | |
| 208 | allocator: &Allocator) -> %usize | |
| 209 | { | |
| 479 | 210 | const path_buf = %return allocator.alloc(u8, path.len + 1); |
| 480 | 211 | defer allocator.free(path_buf); |
| 481 | 212 | @memcpy(&path_buf[0], &path[0], path.len); |
| ... | ... | @@ -604,6 +335,19 @@ pub const EnvMap = struct { |
| 604 | 335 | mem.copy(u8, result, value); |
| 605 | 336 | return result; |
| 606 | 337 | } |
| 338 | ||
| 339 | fn hash_slice_u8(k: []const u8) -> u32 { | |
| 340 | // FNV 32-bit hash | |
| 341 | var h: u32 = 2166136261; | |
| 342 | for (k) |b| { | |
| 343 | h = (h ^ b) *% 16777619; | |
| 344 | } | |
| 345 | return h; | |
| 346 | } | |
| 347 | ||
| 348 | fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { | |
| 349 | return mem.eql(u8, a, b); | |
| 350 | } | |
| 607 | 351 | }; |
| 608 | 352 | |
| 609 | 353 | pub fn getEnvMap(allocator: &Allocator) -> %EnvMap { |
| ... | ... | @@ -641,15 +385,14 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 { |
| 641 | 385 | return null; |
| 642 | 386 | } |
| 643 | 387 | |
| 644 | fn hash_slice_u8(k: []const u8) -> u32 { | |
| 645 | // FNV 32-bit hash | |
| 646 | var h: u32 = 2166136261; | |
| 647 | for (k) |b| { | |
| 648 | h = (h ^ b) *% 16777619; | |
| 649 | } | |
| 650 | return h; | |
| 651 | } | |
| 388 | pub const args = struct { | |
| 389 | pub var raw: []&u8 = undefined; | |
| 652 | 390 | |
| 653 | fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { | |
| 654 | return mem.eql(u8, a, b); | |
| 655 | } | |
| 391 | pub fn count() -> usize { | |
| 392 | return raw.len; | |
| 393 | } | |
| 394 | pub fn at(i: usize) -> []const u8 { | |
| 395 | const s = raw[i]; | |
| 396 | return s[0...cstr.len(s)]; | |
| 397 | } | |
| 398 | }; |
std/special/bootstrap.zig+2-8| ... | ... | @@ -37,20 +37,14 @@ fn callMainAndExit() -> noreturn { |
| 37 | 37 | exit(0); |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | var args_data: [32][]u8 = undefined; | |
| 41 | 40 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { |
| 42 | // TODO create args API to make it work with > 32 args | |
| 43 | const args = args_data[0...argc]; | |
| 44 | for (args) |_, i| { | |
| 45 | const ptr = argv[i]; | |
| 46 | args[i] = ptr[0...std.cstr.len(ptr)]; | |
| 47 | } | |
| 41 | std.os.args.raw = argv[0...argc]; | |
| 48 | 42 | |
| 49 | 43 | var env_count: usize = 0; |
| 50 | 44 | while (envp[env_count] != null; env_count += 1) {} |
| 51 | 45 | std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count]; |
| 52 | 46 | |
| 53 | return root.main(args); | |
| 47 | return root.main(); | |
| 54 | 48 | } |
| 55 | 49 | |
| 56 | 50 | export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { |
std/special/build_runner.zig+6-5| ... | ... | @@ -1,18 +1,19 @@ |
| 1 | 1 | const root = @import("@build"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | const io = std.io; |
| 4 | const os = std.os; | |
| 4 | 5 | const Builder = std.build.Builder; |
| 5 | 6 | const mem = std.mem; |
| 6 | 7 | |
| 7 | 8 | error InvalidArgs; |
| 8 | 9 | |
| 9 | pub fn main(args: [][]u8) -> %void { | |
| 10 | if (args.len < 2) { | |
| 10 | pub fn main() -> %void { | |
| 11 | if (os.args.count() < 2) { | |
| 11 | 12 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); |
| 12 | 13 | return error.InvalidArgs; |
| 13 | 14 | } |
| 14 | const zig_exe = args[1]; | |
| 15 | const leftover_args = args[2...]; | |
| 15 | const zig_exe = os.args.at(1); | |
| 16 | const leftover_arg_index = 2; | |
| 16 | 17 | |
| 17 | 18 | // TODO use a more general purpose allocator here |
| 18 | 19 | var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); |
| ... | ... | @@ -20,5 +21,5 @@ pub fn main(args: [][]u8) -> %void { |
| 20 | 21 | |
| 21 | 22 | var builder = Builder.init(zig_exe, &inc_allocator.allocator); |
| 22 | 23 | root.build(&builder); |
| 23 | %return builder.make(leftover_args); | |
| 24 | %return builder.make(leftover_arg_index); | |
| 24 | 25 | } |
std/special/test_runner.zig+1-1| ... | ... | @@ -7,7 +7,7 @@ const TestFn = struct { |
| 7 | 7 | |
| 8 | 8 | extern var zig_test_fn_list: []TestFn; |
| 9 | 9 | |
| 10 | pub fn main(args: [][]u8) -> %void { | |
| 10 | pub fn main() -> %void { | |
| 11 | 11 | for (zig_test_fn_list) |testFn, i| { |
| 12 | 12 | %%io.stderr.printf("Test {}/{} {}...", i + 1, zig_test_fn_list.len, testFn.name); |
| 13 | 13 |
test/run_tests.cpp+46-63| ... | ... | @@ -215,7 +215,7 @@ export fn main(argc: c_int, argv: &&u8) -> c_int { |
| 215 | 215 | use @import("std").io; |
| 216 | 216 | use @import("foo.zig"); |
| 217 | 217 | |
| 218 | pub fn main(args: [][]u8) -> %void { | |
| 218 | pub fn main() -> %void { | |
| 219 | 219 | privateFunction(); |
| 220 | 220 | %%stdout.printf("OK 2\n"); |
| 221 | 221 | } |
| ... | ... | @@ -245,7 +245,7 @@ pub fn printText() { |
| 245 | 245 | use @import("foo.zig"); |
| 246 | 246 | use @import("bar.zig"); |
| 247 | 247 | |
| 248 | pub fn main(args: [][]u8) -> %void { | |
| 248 | pub fn main() -> %void { | |
| 249 | 249 | foo_function(); |
| 250 | 250 | bar_function(); |
| 251 | 251 | } |
| ... | ... | @@ -281,7 +281,7 @@ pub fn foo_function() -> bool { |
| 281 | 281 | TestCase *tc = add_simple_case("two files use import each other", R"SOURCE( |
| 282 | 282 | use @import("a.zig"); |
| 283 | 283 | |
| 284 | pub fn main(args: [][]u8) -> %void { | |
| 284 | pub fn main() -> %void { | |
| 285 | 285 | ok(); |
| 286 | 286 | } |
| 287 | 287 | )SOURCE", "OK\n"); |
| ... | ... | @@ -309,7 +309,7 @@ pub const b_text = a_text; |
| 309 | 309 | add_simple_case("hello world without libc", R"SOURCE( |
| 310 | 310 | const io = @import("std").io; |
| 311 | 311 | |
| 312 | pub fn main(args: [][]u8) -> %void { | |
| 312 | pub fn main() -> %void { | |
| 313 | 313 | %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); |
| 314 | 314 | } |
| 315 | 315 | )SOURCE", "Hello, world!\n0012 012 a\n"); |
| ... | ... | @@ -446,7 +446,7 @@ const io = @import("std").io; |
| 446 | 446 | const z = io.stdin_fileno; |
| 447 | 447 | const x : @typeOf(y) = 1234; |
| 448 | 448 | const y : u16 = 5678; |
| 449 | pub fn main(args: [][]u8) -> %void { | |
| 449 | pub fn main() -> %void { | |
| 450 | 450 | var x_local : i32 = print_ok(x); |
| 451 | 451 | } |
| 452 | 452 | 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 { |
| 471 | 471 | } |
| 472 | 472 | } |
| 473 | 473 | |
| 474 | export fn main(args: c_int, argv: &&u8) -> c_int { | |
| 474 | export fn main() -> c_int { | |
| 475 | 475 | var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; |
| 476 | 476 | |
| 477 | 477 | c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); |
| ... | ... | @@ -516,7 +516,7 @@ const Bar = struct { |
| 516 | 516 | fn method(b: &const Bar) -> bool { true } |
| 517 | 517 | }; |
| 518 | 518 | |
| 519 | pub fn main(args: [][]u8) -> %void { | |
| 519 | pub fn main() -> %void { | |
| 520 | 520 | const bar = Bar {.field2 = 13,}; |
| 521 | 521 | const foo = Foo {.field1 = bar,}; |
| 522 | 522 | if (!foo.method()) { |
| ... | ... | @@ -532,7 +532,7 @@ pub fn main(args: [][]u8) -> %void { |
| 532 | 532 | |
| 533 | 533 | add_simple_case("defer with only fallthrough", R"SOURCE( |
| 534 | 534 | const io = @import("std").io; |
| 535 | pub fn main(args: [][]u8) -> %void { | |
| 535 | pub fn main() -> %void { | |
| 536 | 536 | %%io.stdout.printf("before\n"); |
| 537 | 537 | defer %%io.stdout.printf("defer1\n"); |
| 538 | 538 | defer %%io.stdout.printf("defer2\n"); |
| ... | ... | @@ -544,11 +544,12 @@ pub fn main(args: [][]u8) -> %void { |
| 544 | 544 | |
| 545 | 545 | add_simple_case("defer with return", R"SOURCE( |
| 546 | 546 | const io = @import("std").io; |
| 547 | pub fn main(args: [][]u8) -> %void { | |
| 547 | const os = @import("std").os; | |
| 548 | pub fn main() -> %void { | |
| 548 | 549 | %%io.stdout.printf("before\n"); |
| 549 | 550 | defer %%io.stdout.printf("defer1\n"); |
| 550 | 551 | defer %%io.stdout.printf("defer2\n"); |
| 551 | if (args.len == 1) return; | |
| 552 | if (os.args.count() == 1) return; | |
| 552 | 553 | defer %%io.stdout.printf("defer3\n"); |
| 553 | 554 | %%io.stdout.printf("after\n"); |
| 554 | 555 | } |
| ... | ... | @@ -557,7 +558,7 @@ pub fn main(args: [][]u8) -> %void { |
| 557 | 558 | |
| 558 | 559 | add_simple_case("%defer and it fails", R"SOURCE( |
| 559 | 560 | const io = @import("std").io; |
| 560 | pub fn main(args: [][]u8) -> %void { | |
| 561 | pub fn main() -> %void { | |
| 561 | 562 | do_test() %% return; |
| 562 | 563 | } |
| 563 | 564 | fn do_test() -> %void { |
| ... | ... | @@ -577,7 +578,7 @@ fn its_gonna_fail() -> %void { |
| 577 | 578 | |
| 578 | 579 | add_simple_case("%defer and it passes", R"SOURCE( |
| 579 | 580 | const io = @import("std").io; |
| 580 | pub fn main(args: [][]u8) -> %void { | |
| 581 | pub fn main() -> %void { | |
| 581 | 582 | do_test() %% return; |
| 582 | 583 | } |
| 583 | 584 | fn do_test() -> %void { |
| ... | ... | @@ -597,7 +598,7 @@ fn its_gonna_pass() -> %void { } |
| 597 | 598 | const foo_txt = @embedFile("foo.txt"); |
| 598 | 599 | const io = @import("std").io; |
| 599 | 600 | |
| 600 | pub fn main(args: [][]u8) -> %void { | |
| 601 | pub fn main() -> %void { | |
| 601 | 602 | %%io.stdout.printf(foo_txt); |
| 602 | 603 | } |
| 603 | 604 | )SOURCE", "1234\nabcd\n"); |
| ... | ... | @@ -1388,9 +1389,13 @@ fn something() -> %void { } |
| 1388 | 1389 | ".tmp_source.zig:3:5: error: expected type 'void', found 'error'"); |
| 1389 | 1390 | |
| 1390 | 1391 | add_compile_fail_case("wrong return type for main", R"SOURCE( |
| 1391 | pub fn main(args: [][]u8) { } | |
| 1392 | )SOURCE", 1, ".tmp_source.zig:2:27: error: expected return type of main to be '%void', instead is 'void'"); | |
| 1392 | pub fn main() { } | |
| 1393 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected return type of main to be '%void', instead is 'void'"); | |
| 1393 | 1394 | |
| 1395 | add_compile_fail_case("double ?? on main return value", R"SOURCE( | |
| 1396 | pub fn main() -> ??void { | |
| 1397 | } | |
| 1398 | )SOURCE", 1, ".tmp_source.zig:2:18: error: expected return type of main to be '%void', instead is '??void'"); | |
| 1394 | 1399 | |
| 1395 | 1400 | add_compile_fail_case("invalid pointer for var type", R"SOURCE( |
| 1396 | 1401 | extern fn ext() -> usize; |
| ... | ... | @@ -1689,11 +1694,6 @@ fn bar(a: i32, b: []const u8) { |
| 1689 | 1694 | ".tmp_source.zig:8:5: error: found compile log statement", |
| 1690 | 1695 | ".tmp_source.zig:3:17: note: called from here"); |
| 1691 | 1696 | |
| 1692 | add_compile_fail_case("double ?? on main return value", R"SOURCE( | |
| 1693 | pub fn main(args: [][]u8) -> ??void { | |
| 1694 | } | |
| 1695 | )SOURCE", 1, ".tmp_source.zig:2:30: error: expected return type of main to be '%void', instead is '??void'"); | |
| 1696 | ||
| 1697 | 1697 | add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE( |
| 1698 | 1698 | const u2 = @intType(false, 2); |
| 1699 | 1699 | const u3 = @intType(false, 3); |
| ... | ... | @@ -1844,7 +1844,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1844 | 1844 | @breakpoint(); |
| 1845 | 1845 | while (true) {} |
| 1846 | 1846 | } |
| 1847 | pub fn main(args: [][]u8) -> %void { | |
| 1847 | pub fn main() -> %void { | |
| 1848 | 1848 | if (!@compileVar("is_release")) { |
| 1849 | 1849 | @panic("oh no"); |
| 1850 | 1850 | } |
| ... | ... | @@ -1856,7 +1856,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1856 | 1856 | @breakpoint(); |
| 1857 | 1857 | while (true) {} |
| 1858 | 1858 | } |
| 1859 | pub fn main(args: [][]u8) -> %void { | |
| 1859 | pub fn main() -> %void { | |
| 1860 | 1860 | const a = []i32{1, 2, 3, 4}; |
| 1861 | 1861 | baz(bar(a)); |
| 1862 | 1862 | } |
| ... | ... | @@ -1872,7 +1872,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1872 | 1872 | while (true) {} |
| 1873 | 1873 | } |
| 1874 | 1874 | error Whatever; |
| 1875 | pub fn main(args: [][]u8) -> %void { | |
| 1875 | pub fn main() -> %void { | |
| 1876 | 1876 | const x = add(65530, 10); |
| 1877 | 1877 | if (x == 0) return error.Whatever; |
| 1878 | 1878 | } |
| ... | ... | @@ -1887,7 +1887,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1887 | 1887 | while (true) {} |
| 1888 | 1888 | } |
| 1889 | 1889 | error Whatever; |
| 1890 | pub fn main(args: [][]u8) -> %void { | |
| 1890 | pub fn main() -> %void { | |
| 1891 | 1891 | const x = sub(10, 20); |
| 1892 | 1892 | if (x == 0) return error.Whatever; |
| 1893 | 1893 | } |
| ... | ... | @@ -1902,7 +1902,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1902 | 1902 | while (true) {} |
| 1903 | 1903 | } |
| 1904 | 1904 | error Whatever; |
| 1905 | pub fn main(args: [][]u8) -> %void { | |
| 1905 | pub fn main() -> %void { | |
| 1906 | 1906 | const x = mul(300, 6000); |
| 1907 | 1907 | if (x == 0) return error.Whatever; |
| 1908 | 1908 | } |
| ... | ... | @@ -1917,7 +1917,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1917 | 1917 | while (true) {} |
| 1918 | 1918 | } |
| 1919 | 1919 | error Whatever; |
| 1920 | pub fn main(args: [][]u8) -> %void { | |
| 1920 | pub fn main() -> %void { | |
| 1921 | 1921 | const x = neg(-32768); |
| 1922 | 1922 | if (x == 32767) return error.Whatever; |
| 1923 | 1923 | } |
| ... | ... | @@ -1932,7 +1932,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1932 | 1932 | while (true) {} |
| 1933 | 1933 | } |
| 1934 | 1934 | error Whatever; |
| 1935 | pub fn main(args: [][]u8) -> %void { | |
| 1935 | pub fn main() -> %void { | |
| 1936 | 1936 | const x = div(-32768, -1); |
| 1937 | 1937 | if (x == 32767) return error.Whatever; |
| 1938 | 1938 | } |
| ... | ... | @@ -1947,7 +1947,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1947 | 1947 | while (true) {} |
| 1948 | 1948 | } |
| 1949 | 1949 | error Whatever; |
| 1950 | pub fn main(args: [][]u8) -> %void { | |
| 1950 | pub fn main() -> %void { | |
| 1951 | 1951 | const x = shl(-16385, 1); |
| 1952 | 1952 | if (x == 0) return error.Whatever; |
| 1953 | 1953 | } |
| ... | ... | @@ -1962,7 +1962,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1962 | 1962 | while (true) {} |
| 1963 | 1963 | } |
| 1964 | 1964 | error Whatever; |
| 1965 | pub fn main(args: [][]u8) -> %void { | |
| 1965 | pub fn main() -> %void { | |
| 1966 | 1966 | const x = shl(0b0010111111111111, 3); |
| 1967 | 1967 | if (x == 0) return error.Whatever; |
| 1968 | 1968 | } |
| ... | ... | @@ -1977,7 +1977,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1977 | 1977 | while (true) {} |
| 1978 | 1978 | } |
| 1979 | 1979 | error Whatever; |
| 1980 | pub fn main(args: [][]u8) -> %void { | |
| 1980 | pub fn main() -> %void { | |
| 1981 | 1981 | const x = div0(999, 0); |
| 1982 | 1982 | } |
| 1983 | 1983 | fn div0(a: i32, b: i32) -> i32 { |
| ... | ... | @@ -1991,7 +1991,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1991 | 1991 | while (true) {} |
| 1992 | 1992 | } |
| 1993 | 1993 | error Whatever; |
| 1994 | pub fn main(args: [][]u8) -> %void { | |
| 1994 | pub fn main() -> %void { | |
| 1995 | 1995 | const x = divExact(10, 3); |
| 1996 | 1996 | if (x == 0) return error.Whatever; |
| 1997 | 1997 | } |
| ... | ... | @@ -2006,7 +2006,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2006 | 2006 | while (true) {} |
| 2007 | 2007 | } |
| 2008 | 2008 | error Whatever; |
| 2009 | pub fn main(args: [][]u8) -> %void { | |
| 2009 | pub fn main() -> %void { | |
| 2010 | 2010 | const x = widenSlice([]u8{1, 2, 3, 4, 5}); |
| 2011 | 2011 | if (x.len == 0) return error.Whatever; |
| 2012 | 2012 | } |
| ... | ... | @@ -2021,7 +2021,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2021 | 2021 | while (true) {} |
| 2022 | 2022 | } |
| 2023 | 2023 | error Whatever; |
| 2024 | pub fn main(args: [][]u8) -> %void { | |
| 2024 | pub fn main() -> %void { | |
| 2025 | 2025 | const x = shorten_cast(200); |
| 2026 | 2026 | if (x == 0) return error.Whatever; |
| 2027 | 2027 | } |
| ... | ... | @@ -2036,7 +2036,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2036 | 2036 | while (true) {} |
| 2037 | 2037 | } |
| 2038 | 2038 | error Whatever; |
| 2039 | pub fn main(args: [][]u8) -> %void { | |
| 2039 | pub fn main() -> %void { | |
| 2040 | 2040 | const x = unsigned_cast(-10); |
| 2041 | 2041 | if (x == 0) return error.Whatever; |
| 2042 | 2042 | } |
| ... | ... | @@ -2051,7 +2051,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2051 | 2051 | while (true) {} |
| 2052 | 2052 | } |
| 2053 | 2053 | error Whatever; |
| 2054 | pub fn main(args: [][]u8) -> %void { | |
| 2054 | pub fn main() -> %void { | |
| 2055 | 2055 | %%bar(); |
| 2056 | 2056 | } |
| 2057 | 2057 | fn bar() -> %void { |
| ... | ... | @@ -2064,7 +2064,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2064 | 2064 | @breakpoint(); |
| 2065 | 2065 | while (true) {} |
| 2066 | 2066 | } |
| 2067 | pub fn main(args: [][]u8) -> %void { | |
| 2067 | pub fn main() -> %void { | |
| 2068 | 2068 | _ = bar(9999); |
| 2069 | 2069 | } |
| 2070 | 2070 | fn bar(x: u32) -> error { |
| ... | ... | @@ -2500,25 +2500,13 @@ static void run_test(TestCase *test_case) { |
| 2500 | 2500 | } |
| 2501 | 2501 | } |
| 2502 | 2502 | |
| 2503 | static void run_all_tests(bool reverse) { | |
| 2504 | if (reverse) { | |
| 2505 | for (size_t i = test_cases.length;;) { | |
| 2506 | TestCase *test_case = test_cases.at(i); | |
| 2507 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); | |
| 2508 | fflush(stdout); | |
| 2509 | run_test(test_case); | |
| 2510 | printf("OK\n"); | |
| 2511 | if (i == 0) break; | |
| 2512 | i -= 1; | |
| 2513 | } | |
| 2514 | } else { | |
| 2515 | for (size_t i = 0; i < test_cases.length; i += 1) { | |
| 2516 | TestCase *test_case = test_cases.at(i); | |
| 2517 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); | |
| 2518 | fflush(stdout); | |
| 2519 | run_test(test_case); | |
| 2520 | printf("OK\n"); | |
| 2521 | } | |
| 2503 | static void run_all_tests(void) { | |
| 2504 | for (size_t i = 0; i < test_cases.length; i += 1) { | |
| 2505 | TestCase *test_case = test_cases.at(i); | |
| 2506 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); | |
| 2507 | fflush(stdout); | |
| 2508 | run_test(test_case); | |
| 2509 | printf("OK\n"); | |
| 2522 | 2510 | } |
| 2523 | 2511 | printf("%zu tests passed.\n", test_cases.length); |
| 2524 | 2512 | } |
| ... | ... | @@ -2530,18 +2518,13 @@ static void cleanup(void) { |
| 2530 | 2518 | } |
| 2531 | 2519 | |
| 2532 | 2520 | static int usage(const char *arg0) { |
| 2533 | fprintf(stderr, "Usage: %s [--reverse]\n", arg0); | |
| 2521 | fprintf(stderr, "Usage: %s\n", arg0); | |
| 2534 | 2522 | return 1; |
| 2535 | 2523 | } |
| 2536 | 2524 | |
| 2537 | 2525 | int main(int argc, char **argv) { |
| 2538 | bool reverse = false; | |
| 2539 | 2526 | for (int i = 1; i < argc; i += 1) { |
| 2540 | if (strcmp(argv[i], "--reverse") == 0) { | |
| 2541 | reverse = true; | |
| 2542 | } else { | |
| 2543 | return usage(argv[0]); | |
| 2544 | } | |
| 2527 | return usage(argv[0]); | |
| 2545 | 2528 | } |
| 2546 | 2529 | add_compiling_test_cases(); |
| 2547 | 2530 | add_debug_safety_test_cases(); |
| ... | ... | @@ -2549,6 +2532,6 @@ int main(int argc, char **argv) { |
| 2549 | 2532 | add_parseh_test_cases(); |
| 2550 | 2533 | add_self_hosted_tests(); |
| 2551 | 2534 | add_std_lib_tests(); |
| 2552 | run_all_tests(reverse); | |
| 2535 | run_all_tests(); | |
| 2553 | 2536 | cleanup(); |
| 2554 | 2537 | } |