authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-31 04:47:55-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-31 04:47:55-04:00
log9e234d4208725b818812765740b474f049d69788
treecfb7b0602d8d5c4219797ef95cc763a970e53586
parent7a96aca39e8eabccf69f5c65cd60a96aa4a7666c

breaking change to std.io API

* Merge io.InStream and io.OutStream into io.File * Introduce io.OutStream and io.InStream interfaces - io.File implements both of these * Move mem.IncrementingAllocator to heap.IncrementingAllocator Instead of: ``` %return std.io.stderr.printf("hello\n"); ``` now do: ``` std.debug.warn("hello\n"); ``` To print to stdout, see `io.getStdOut()`. * Rename std.ArrayList.resizeDown to std.ArrayList.shrink.

21 files changed, 958 insertions(+), 1020 deletions(-)

CMakeLists.txt+2-1
...@@ -521,6 +521,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/index.zig" DESTINATION "${ZIG_S...@@ -521,6 +521,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/index.zig" DESTINATION "${ZIG_S
521install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/lookup.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol")521install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/lookup.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol")
522install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt")522install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt")
523install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")523install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}")
524install(FILES "${CMAKE_SOURCE_DIR}/std/heap.zig" DESTINATION "${ZIG_STD_DEST}")
524install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")525install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
525install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")526install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}")
526install(FILES "${CMAKE_SOURCE_DIR}/std/linked_list.zig" DESTINATION "${ZIG_STD_DEST}")527install(FILES "${CMAKE_SOURCE_DIR}/std/linked_list.zig" DESTINATION "${ZIG_STD_DEST}")
...@@ -605,10 +606,10 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfdi.zig" DESTI...@@ -605,10 +606,10 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfdi.zig" DESTI
605install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")606install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
606install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")607install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
607install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/index.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")608install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/index.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
608install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
609install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivmod.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")609install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivmod.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
610install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivmoddi4.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")610install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivmoddi4.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
611install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivmodti4.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")611install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivmodti4.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
612install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
612install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")613install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
613install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special")614install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special")
614install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")615install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
example/cat/main.zig+18-13
...@@ -2,47 +2,52 @@ const std = @import("std");...@@ -2,47 +2,52 @@ const std = @import("std");
2const io = std.io;2const io = std.io;
3const mem = std.mem;3const mem = std.mem;
4const os = std.os;4const os = std.os;
5const warn = std.debug.warn;
56
6pub fn main() -> %void {7pub fn main() -> %void {
7 const allocator = &std.debug.global_allocator;8 const allocator = &std.debug.global_allocator;
8 var args_it = os.args();9 var args_it = os.args();
9 const exe = %return unwrapArg(??args_it.next(allocator));10 const exe = %return unwrapArg(??args_it.next(allocator));
10 var catted_anything = false;11 var catted_anything = false;
12 var stdout_file = %return io.getStdOut();
13 const stdout = &stdout_file.out_stream;
14
11 while (args_it.next(allocator)) |arg_or_err| {15 while (args_it.next(allocator)) |arg_or_err| {
12 const arg = %return unwrapArg(arg_or_err);16 const arg = %return unwrapArg(arg_or_err);
13 if (mem.eql(u8, arg, "-")) {17 if (mem.eql(u8, arg, "-")) {
14 catted_anything = true;18 catted_anything = true;
15 %return cat_stream(&io.stdin);19 var stdin_file = %return io.getStdIn();
20 %return cat_stream(stdout, &stdin_file.in_stream);
16 } else if (arg[0] == '-') {21 } else if (arg[0] == '-') {
17 return usage(exe);22 return usage(exe);
18 } else {23 } else {
19 var is = io.InStream.open(arg, null) %% |err| {24 var file = io.File.openRead(arg, null) %% |err| {
20 %%io.stderr.printf("Unable to open file: {}\n", @errorName(err));25 warn("Unable to open file: {}\n", @errorName(err));
21 return err;26 return err;
22 };27 };
23 defer is.close();28 defer file.close();
2429
25 catted_anything = true;30 catted_anything = true;
26 %return cat_stream(&is);31 %return cat_stream(stdout, &file.in_stream);
27 }32 }
28 }33 }
29 if (!catted_anything) {34 if (!catted_anything) {
30 %return cat_stream(&io.stdin);35 var stdin_file = %return io.getStdIn();
36 %return cat_stream(stdout, &stdin_file.in_stream);
31 }37 }
32 %return io.stdout.flush();
33}38}
3439
35fn usage(exe: []const u8) -> %void {40fn usage(exe: []const u8) -> %void {
36 %%io.stderr.printf("Usage: {} [FILE]...\n", exe);41 warn("Usage: {} [FILE]...\n", exe);
37 return error.Invalid;42 return error.Invalid;
38}43}
3944
40fn cat_stream(is: &io.InStream) -> %void {45fn cat_stream(stdout: &io.OutStream, is: &io.InStream) -> %void {
41 var buf: [1024 * 4]u8 = undefined;46 var buf: [1024 * 4]u8 = undefined;
4247
43 while (true) {48 while (true) {
44 const bytes_read = is.read(buf[0..]) %% |err| {49 const bytes_read = is.read(buf[0..]) %% |err| {
45 %%io.stderr.printf("Unable to read from stream: {}\n", @errorName(err));50 warn("Unable to read from stream: {}\n", @errorName(err));
46 return err;51 return err;
47 };52 };
4853
...@@ -50,8 +55,8 @@ fn cat_stream(is: &io.InStream) -> %void {...@@ -50,8 +55,8 @@ fn cat_stream(is: &io.InStream) -> %void {
50 break;55 break;
51 }56 }
5257
53 io.stdout.write(buf[0..bytes_read]) %% |err| {58 stdout.write(buf[0..bytes_read]) %% |err| {
54 %%io.stderr.printf("Unable to write to stdout: {}\n", @errorName(err));59 warn("Unable to write to stdout: {}\n", @errorName(err));
55 return err;60 return err;
56 };61 };
57 }62 }
...@@ -59,7 +64,7 @@ fn cat_stream(is: &io.InStream) -> %void {...@@ -59,7 +64,7 @@ fn cat_stream(is: &io.InStream) -> %void {
5964
60fn unwrapArg(arg: %[]u8) -> %[]u8 {65fn unwrapArg(arg: %[]u8) -> %[]u8 {
61 return arg %% |err| {66 return arg %% |err| {
62 %%io.stderr.printf("Unable to parse command line: {}\n", err);67 warn("Unable to parse command line: {}\n", err);
63 return err;68 return err;
64 };69 };
65}70}
example/guess_number/main.zig+14-8
...@@ -5,7 +5,13 @@ const Rand = std.rand.Rand;...@@ -5,7 +5,13 @@ const Rand = std.rand.Rand;
5const os = std.os;5const os = std.os;
66
7pub fn main() -> %void {7pub fn main() -> %void {
8 %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");8 var stdout_file = %return io.getStdOut();
9 const stdout = &stdout_file.out_stream;
10
11 var stdin_file = %return io.getStdIn();
12 const stdin = &stdin_file.in_stream;
13
14 %return stdout.print("Welcome to the Guess Number Game in Zig.\n");
915
10 var seed_bytes: [@sizeOf(usize)]u8 = undefined;16 var seed_bytes: [@sizeOf(usize)]u8 = undefined;
11 %%os.getRandomBytes(seed_bytes[0..]);17 %%os.getRandomBytes(seed_bytes[0..]);
...@@ -15,24 +21,24 @@ pub fn main() -> %void {...@@ -15,24 +21,24 @@ pub fn main() -> %void {
15 const answer = rand.range(u8, 0, 100) + 1;21 const answer = rand.range(u8, 0, 100) + 1;
1622
17 while (true) {23 while (true) {
18 %%io.stdout.printf("\nGuess a number between 1 and 100: ");24 %return stdout.print("\nGuess a number between 1 and 100: ");
19 var line_buf : [20]u8 = undefined;25 var line_buf : [20]u8 = undefined;
2026
21 const line_len = io.stdin.read(line_buf[0..]) %% |err| {27 const line_len = stdin.read(line_buf[0..]) %% |err| {
22 %%io.stdout.printf("Unable to read from stdin: {}\n", @errorName(err));28 %return stdout.print("Unable to read from stdin: {}\n", @errorName(err));
23 return err;29 return err;
24 };30 };
2531
26 const guess = fmt.parseUnsigned(u8, line_buf[0..line_len - 1], 10) %% {32 const guess = fmt.parseUnsigned(u8, line_buf[0..line_len - 1], 10) %% {
27 %%io.stdout.printf("Invalid number.\n");33 %return stdout.print("Invalid number.\n");
28 continue;34 continue;
29 };35 };
30 if (guess > answer) {36 if (guess > answer) {
31 %%io.stdout.printf("Guess lower.\n");37 %return stdout.print("Guess lower.\n");
32 } else if (guess < answer) {38 } else if (guess < answer) {
33 %%io.stdout.printf("Guess higher.\n");39 %return stdout.print("Guess higher.\n");
34 } else {40 } else {
35 %%io.stdout.printf("You win!\n");41 %return stdout.print("You win!\n");
36 return;42 return;
37 }43 }
38 }44 }
example/hello_world/hello.zig+7-2
...@@ -1,5 +1,10 @@...@@ -1,5 +1,10 @@
1const io = @import("std").io;1const std = @import("std");
22
3pub fn main() -> %void {3pub fn main() -> %void {
4 %return io.stdout.printf("Hello, world!\n");4 // If this program is run without stdout attached, exit with an error.
5 var stdout_file = %return std.io.getStdOut();
6 const stdout = &stdout_file.out_stream;
7 // If this program encounters pipe failure when printing to stdout, exit
8 // with an error.
9 %return stdout.print("Hello, world!\n");
5}10}
std/array_list.zig+1-1
...@@ -70,7 +70,7 @@ pub fn ArrayList(comptime T: type) -> type{...@@ -70,7 +70,7 @@ pub fn ArrayList(comptime T: type) -> type{
70 l.len = new_len;70 l.len = new_len;
71 }71 }
7272
73 pub fn resizeDown(l: &Self, new_len: usize) {73 pub fn shrink(l: &Self, new_len: usize) {
74 assert(new_len <= l.len);74 assert(new_len <= l.len);
75 l.len = new_len;75 l.len = new_len;
76 }76 }
std/buffer.zig+6
...@@ -71,6 +71,12 @@ pub const Buffer = struct {...@@ -71,6 +71,12 @@ pub const Buffer = struct {
71 return self.list.toSliceConst()[0..self.len()];71 return self.list.toSliceConst()[0..self.len()];
72 }72 }
7373
74 pub fn shrink(self: &Buffer, new_len: usize) {
75 assert(new_len <= self.len());
76 self.list.shrink(new_len + 1);
77 self.list.items[self.len()] = 0;
78 }
79
74 pub fn resize(self: &Buffer, new_len: usize) -> %void {80 pub fn resize(self: &Buffer, new_len: usize) -> %void {
75 %return self.list.resize(new_len + 1);81 %return self.list.resize(new_len + 1);
76 self.list.items[self.len()] = 0;82 self.list.items[self.len()] = 0;
std/build.zig+46-45
...@@ -1,17 +1,19 @@...@@ -1,17 +1,19 @@
1const std = @import("index.zig");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const io = @import("io.zig");3const io = std.io;
3const mem = @import("mem.zig");4const mem = std.mem;
4const debug = @import("debug.zig");5const debug = std.debug;
5const assert = debug.assert;6const assert = debug.assert;
6const ArrayList = @import("array_list.zig").ArrayList;7const warn = std.debug.warn;
7const HashMap = @import("hash_map.zig").HashMap;8const ArrayList = std.ArrayList;
8const Allocator = @import("mem.zig").Allocator;9const HashMap = std.HashMap;
9const os = @import("os/index.zig");10const Allocator = mem.Allocator;
11const os = std.os;
10const StdIo = os.ChildProcess.StdIo;12const StdIo = os.ChildProcess.StdIo;
11const Term = os.ChildProcess.Term;13const Term = os.ChildProcess.Term;
12const BufSet = @import("buf_set.zig").BufSet;14const BufSet = std.BufSet;
13const BufMap = @import("buf_map.zig").BufMap;15const BufMap = std.BufMap;
14const fmt_lib = @import("fmt/index.zig");16const fmt_lib = std.fmt;
1517
16error ExtraArg;18error ExtraArg;
17error UncleanExit;19error UncleanExit;
...@@ -280,7 +282,7 @@ pub const Builder = struct {...@@ -280,7 +282,7 @@ pub const Builder = struct {
280282
281 for (self.installed_files.toSliceConst()) |installed_file| {283 for (self.installed_files.toSliceConst()) |installed_file| {
282 if (self.verbose) {284 if (self.verbose) {
283 %%io.stderr.printf("rm {}\n", installed_file);285 warn("rm {}\n", installed_file);
284 }286 }
285 _ = os.deleteFile(self.allocator, installed_file);287 _ = os.deleteFile(self.allocator, installed_file);
286 }288 }
...@@ -290,7 +292,7 @@ pub const Builder = struct {...@@ -290,7 +292,7 @@ pub const Builder = struct {
290292
291 fn makeOneStep(self: &Builder, s: &Step) -> %void {293 fn makeOneStep(self: &Builder, s: &Step) -> %void {
292 if (s.loop_flag) {294 if (s.loop_flag) {
293 %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name);295 warn("Dependency loop detected:\n {}\n", s.name);
294 return error.DependencyLoopDetected;296 return error.DependencyLoopDetected;
295 }297 }
296 s.loop_flag = true;298 s.loop_flag = true;
...@@ -298,7 +300,7 @@ pub const Builder = struct {...@@ -298,7 +300,7 @@ pub const Builder = struct {
298 for (s.dependencies.toSlice()) |dep| {300 for (s.dependencies.toSlice()) |dep| {
299 self.makeOneStep(dep) %% |err| {301 self.makeOneStep(dep) %% |err| {
300 if (err == error.DependencyLoopDetected) {302 if (err == error.DependencyLoopDetected) {
301 %%io.stderr.printf(" {}\n", s.name);303 warn(" {}\n", s.name);
302 }304 }
303 return err;305 return err;
304 };306 };
...@@ -315,7 +317,7 @@ pub const Builder = struct {...@@ -315,7 +317,7 @@ pub const Builder = struct {
315 return &top_level_step.step;317 return &top_level_step.step;
316 }318 }
317 }319 }
318 %%io.stderr.printf("Cannot run step '{}' because it does not exist\n", name);320 warn("Cannot run step '{}' because it does not exist\n", name);
319 return error.InvalidStepName;321 return error.InvalidStepName;
320 }322 }
321323
...@@ -326,12 +328,12 @@ pub const Builder = struct {...@@ -326,12 +328,12 @@ pub const Builder = struct {
326 const word = it.next() ?? break;328 const word = it.next() ?? break;
327 if (mem.eql(u8, word, "-isystem")) {329 if (mem.eql(u8, word, "-isystem")) {
328 const include_path = it.next() ?? {330 const include_path = it.next() ?? {
329 %%io.stderr.printf("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");331 warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
330 break;332 break;
331 };333 };
332 self.addCIncludePath(include_path);334 self.addCIncludePath(include_path);
333 } else {335 } else {
334 %%io.stderr.printf("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", word);336 warn("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", word);
335 break;337 break;
336 }338 }
337 }339 }
...@@ -344,7 +346,7 @@ pub const Builder = struct {...@@ -344,7 +346,7 @@ pub const Builder = struct {
344 const word = it.next() ?? break;346 const word = it.next() ?? break;
345 if (mem.eql(u8, word, "-rpath")) {347 if (mem.eql(u8, word, "-rpath")) {
346 const rpath = it.next() ?? {348 const rpath = it.next() ?? {
347 %%io.stderr.printf("Expected argument after -rpath in NIX_LDFLAGS\n");349 warn("Expected argument after -rpath in NIX_LDFLAGS\n");
348 break;350 break;
349 };351 };
350 self.addRPath(rpath);352 self.addRPath(rpath);
...@@ -352,7 +354,7 @@ pub const Builder = struct {...@@ -352,7 +354,7 @@ pub const Builder = struct {
352 const lib_path = word[2..];354 const lib_path = word[2..];
353 self.addLibPath(lib_path);355 self.addLibPath(lib_path);
354 } else {356 } else {
355 %%io.stderr.printf("Unrecognized C flag from NIX_LDFLAGS: {}\n", word);357 warn("Unrecognized C flag from NIX_LDFLAGS: {}\n", word);
356 break;358 break;
357 }359 }
358 }360 }
...@@ -384,13 +386,13 @@ pub const Builder = struct {...@@ -384,13 +386,13 @@ pub const Builder = struct {
384 } else if (mem.eql(u8, s, "false")) {386 } else if (mem.eql(u8, s, "false")) {
385 return false;387 return false;
386 } else {388 } else {
387 %%io.stderr.printf("Expected -D{} to be a boolean, but received '{}'\n", name, s);389 warn("Expected -D{} to be a boolean, but received '{}'\n", name, s);
388 self.markInvalidUserInput();390 self.markInvalidUserInput();
389 return null;391 return null;
390 }392 }
391 },393 },
392 UserValue.List => {394 UserValue.List => {
393 %%io.stderr.printf("Expected -D{} to be a boolean, but received a list.\n", name);395 warn("Expected -D{} to be a boolean, but received a list.\n", name);
394 self.markInvalidUserInput();396 self.markInvalidUserInput();
395 return null;397 return null;
396 },398 },
...@@ -399,12 +401,12 @@ pub const Builder = struct {...@@ -399,12 +401,12 @@ pub const Builder = struct {
399 TypeId.Float => debug.panic("TODO float options to build script"),401 TypeId.Float => debug.panic("TODO float options to build script"),
400 TypeId.String => switch (entry.value.value) {402 TypeId.String => switch (entry.value.value) {
401 UserValue.Flag => {403 UserValue.Flag => {
402 %%io.stderr.printf("Expected -D{} to be a string, but received a boolean.\n", name);404 warn("Expected -D{} to be a string, but received a boolean.\n", name);
403 self.markInvalidUserInput();405 self.markInvalidUserInput();
404 return null;406 return null;
405 },407 },
406 UserValue.List => {408 UserValue.List => {
407 %%io.stderr.printf("Expected -D{} to be a string, but received a list.\n", name);409 warn("Expected -D{} to be a string, but received a list.\n", name);
408 self.markInvalidUserInput();410 self.markInvalidUserInput();
409 return null;411 return null;
410 },412 },
...@@ -437,7 +439,7 @@ pub const Builder = struct {...@@ -437,7 +439,7 @@ pub const Builder = struct {
437 } else if (!release_fast and !release_safe) {439 } else if (!release_fast and !release_safe) {
438 builtin.Mode.Debug440 builtin.Mode.Debug
439 } else {441 } else {
440 %%io.stderr.printf("Both -Drelease-safe and -Drelease-fast specified");442 warn("Both -Drelease-safe and -Drelease-fast specified");
441 self.markInvalidUserInput();443 self.markInvalidUserInput();
442 builtin.Mode.Debug444 builtin.Mode.Debug
443 };445 };
...@@ -474,7 +476,7 @@ pub const Builder = struct {...@@ -474,7 +476,7 @@ pub const Builder = struct {
474 });476 });
475 },477 },
476 UserValue.Flag => {478 UserValue.Flag => {
477 %%io.stderr.printf("Option '-D{}={}' conflicts with flag '-D{}'.\n", name, value, name);479 warn("Option '-D{}={}' conflicts with flag '-D{}'.\n", name, value, name);
478 return true;480 return true;
479 },481 },
480 }482 }
...@@ -490,11 +492,11 @@ pub const Builder = struct {...@@ -490,11 +492,11 @@ pub const Builder = struct {
490 })) |*prev_value| {492 })) |*prev_value| {
491 switch (prev_value.value) {493 switch (prev_value.value) {
492 UserValue.Scalar => |s| {494 UserValue.Scalar => |s| {
493 %%io.stderr.printf("Flag '-D{}' conflicts with option '-D{}={}'.\n", name, name, s);495 warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", name, name, s);
494 return true;496 return true;
495 },497 },
496 UserValue.List => {498 UserValue.List => {
497 %%io.stderr.printf("Flag '-D{}' conflicts with multiple options of the same name.\n", name);499 warn("Flag '-D{}' conflicts with multiple options of the same name.\n", name);
498 return true;500 return true;
499 },501 },
500 UserValue.Flag => {},502 UserValue.Flag => {},
...@@ -536,7 +538,7 @@ pub const Builder = struct {...@@ -536,7 +538,7 @@ pub const Builder = struct {
536 while (true) {538 while (true) {
537 const entry = it.next() ?? break;539 const entry = it.next() ?? break;
538 if (!entry.value.used) {540 if (!entry.value.used) {
539 %%io.stderr.printf("Invalid option: -D{}\n\n", entry.key);541 warn("Invalid option: -D{}\n\n", entry.key);
540 self.markInvalidUserInput();542 self.markInvalidUserInput();
541 }543 }
542 }544 }
...@@ -549,11 +551,11 @@ pub const Builder = struct {...@@ -549,11 +551,11 @@ pub const Builder = struct {
549 }551 }
550552
551 fn printCmd(cwd: ?[]const u8, argv: []const []const u8) {553 fn printCmd(cwd: ?[]const u8, argv: []const []const u8) {
552 if (cwd) |yes_cwd| %%io.stderr.print("cd {} && ", yes_cwd);554 if (cwd) |yes_cwd| warn("cd {} && ", yes_cwd);
553 for (argv) |arg| {555 for (argv) |arg| {
554 %%io.stderr.print("{} ", arg);556 warn("{} ", arg);
555 }557 }
556 %%io.stderr.printf("\n");558 warn("\n");
557 }559 }
558560
559 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,561 fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
...@@ -570,20 +572,20 @@ pub const Builder = struct {...@@ -570,20 +572,20 @@ pub const Builder = struct {
570 child.env_map = env_map;572 child.env_map = env_map;
571573
572 const term = child.spawnAndWait() %% |err| {574 const term = child.spawnAndWait() %% |err| {
573 %%io.stderr.printf("Unable to spawn {}: {}\n", argv[0], @errorName(err));575 warn("Unable to spawn {}: {}\n", argv[0], @errorName(err));
574 return err;576 return err;
575 };577 };
576578
577 switch (term) {579 switch (term) {
578 Term.Exited => |code| {580 Term.Exited => |code| {
579 if (code != 0) {581 if (code != 0) {
580 %%io.stderr.printf("The following command exited with error code {}:\n", code);582 warn("The following command exited with error code {}:\n", code);
581 printCmd(cwd, argv);583 printCmd(cwd, argv);
582 return error.UncleanExit;584 return error.UncleanExit;
583 }585 }
584 },586 },
585 else => {587 else => {
586 %%io.stderr.printf("The following command terminated unexpectedly:\n");588 warn("The following command terminated unexpectedly:\n");
587 printCmd(cwd, argv);589 printCmd(cwd, argv);
588590
589 return error.UncleanExit;591 return error.UncleanExit;
...@@ -594,7 +596,7 @@ pub const Builder = struct {...@@ -594,7 +596,7 @@ pub const Builder = struct {
594596
595 pub fn makePath(self: &Builder, path: []const u8) -> %void {597 pub fn makePath(self: &Builder, path: []const u8) -> %void {
596 os.makePath(self.allocator, self.pathFromRoot(path)) %% |err| {598 os.makePath(self.allocator, self.pathFromRoot(path)) %% |err| {
597 %%io.stderr.printf("Unable to create path {}: {}\n", path, @errorName(err));599 warn("Unable to create path {}: {}\n", path, @errorName(err));
598 return err;600 return err;
599 };601 };
600 }602 }
...@@ -633,17 +635,17 @@ pub const Builder = struct {...@@ -633,17 +635,17 @@ pub const Builder = struct {
633635
634 fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void {636 fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void {
635 if (self.verbose) {637 if (self.verbose) {
636 %%io.stderr.printf("cp {} {}\n", source_path, dest_path);638 warn("cp {} {}\n", source_path, dest_path);
637 }639 }
638640
639 const dirname = os.path.dirname(dest_path);641 const dirname = os.path.dirname(dest_path);
640 const abs_source_path = self.pathFromRoot(source_path);642 const abs_source_path = self.pathFromRoot(source_path);
641 os.makePath(self.allocator, dirname) %% |err| {643 os.makePath(self.allocator, dirname) %% |err| {
642 %%io.stderr.printf("Unable to create path {}: {}\n", dirname, @errorName(err));644 warn("Unable to create path {}: {}\n", dirname, @errorName(err));
643 return err;645 return err;
644 };646 };
645 os.copyFileMode(self.allocator, abs_source_path, dest_path, mode) %% |err| {647 os.copyFileMode(self.allocator, abs_source_path, dest_path, mode) %% |err| {
646 %%io.stderr.printf("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));648 warn("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));
647 return err;649 return err;
648 };650 };
649 }651 }
...@@ -1103,7 +1105,7 @@ pub const LibExeObjStep = struct {...@@ -1103,7 +1105,7 @@ pub const LibExeObjStep = struct {
1103 assert(self.is_zig);1105 assert(self.is_zig);
11041106
1105 if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) {1107 if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) {
1106 %%io.stderr.printf("{}: linker needs 1 or more objects to link\n", self.step.name);1108 warn("{}: linker needs 1 or more objects to link\n", self.step.name);
1107 return error.NeedAnObject;1109 return error.NeedAnObject;
1108 }1110 }
11091111
...@@ -1799,11 +1801,11 @@ pub const WriteFileStep = struct {...@@ -1799,11 +1801,11 @@ pub const WriteFileStep = struct {
1799 const full_path = self.builder.pathFromRoot(self.file_path);1801 const full_path = self.builder.pathFromRoot(self.file_path);
1800 const full_path_dir = os.path.dirname(full_path);1802 const full_path_dir = os.path.dirname(full_path);
1801 os.makePath(self.builder.allocator, full_path_dir) %% |err| {1803 os.makePath(self.builder.allocator, full_path_dir) %% |err| {
1802 %%io.stderr.printf("unable to make path {}: {}\n", full_path_dir, @errorName(err));1804 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
1803 return err;1805 return err;
1804 };1806 };
1805 io.writeFile(full_path, self.data, self.builder.allocator) %% |err| {1807 io.writeFile(full_path, self.data, self.builder.allocator) %% |err| {
1806 %%io.stderr.printf("unable to write {}: {}\n", full_path, @errorName(err));1808 warn("unable to write {}: {}\n", full_path, @errorName(err));
1807 return err;1809 return err;
1808 };1810 };
1809 }1811 }
...@@ -1824,8 +1826,7 @@ pub const LogStep = struct {...@@ -1824,8 +1826,7 @@ pub const LogStep = struct {
18241826
1825 fn make(step: &Step) -> %void {1827 fn make(step: &Step) -> %void {
1826 const self = @fieldParentPtr(LogStep, "step", step);1828 const self = @fieldParentPtr(LogStep, "step", step);
1827 %%io.stderr.write(self.data);1829 warn("{}", self.data);
1828 %%io.stderr.flush();
1829 }1830 }
1830};1831};
18311832
...@@ -1847,7 +1848,7 @@ pub const RemoveDirStep = struct {...@@ -1847,7 +1848,7 @@ pub const RemoveDirStep = struct {
18471848
1848 const full_path = self.builder.pathFromRoot(self.dir_path);1849 const full_path = self.builder.pathFromRoot(self.dir_path);
1849 os.deleteTree(self.builder.allocator, full_path) %% |err| {1850 os.deleteTree(self.builder.allocator, full_path) %% |err| {
1850 %%io.stderr.printf("Unable to remove {}: {}\n", full_path, @errorName(err));1851 warn("Unable to remove {}: {}\n", full_path, @errorName(err));
1851 return err;1852 return err;
1852 };1853 };
1853 }1854 }
...@@ -1896,13 +1897,13 @@ fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_maj...@@ -1896,13 +1897,13 @@ fn doAtomicSymLinks(allocator: &Allocator, output_path: []const u8, filename_maj
1896 // sym link for libfoo.so.1 to libfoo.so.1.2.31897 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1897 const major_only_path = %%os.path.join(allocator, out_dir, filename_major_only);1898 const major_only_path = %%os.path.join(allocator, out_dir, filename_major_only);
1898 os.atomicSymLink(allocator, out_basename, major_only_path) %% |err| {1899 os.atomicSymLink(allocator, out_basename, major_only_path) %% |err| {
1899 %%io.stderr.printf("Unable to symlink {} -> {}\n", major_only_path, out_basename);1900 warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
1900 return err;1901 return err;
1901 };1902 };
1902 // sym link for libfoo.so to libfoo.so.11903 // sym link for libfoo.so to libfoo.so.1
1903 const name_only_path = %%os.path.join(allocator, out_dir, filename_name_only);1904 const name_only_path = %%os.path.join(allocator, out_dir, filename_name_only);
1904 os.atomicSymLink(allocator, filename_major_only, name_only_path) %% |err| {1905 os.atomicSymLink(allocator, filename_major_only, name_only_path) %% |err| {
1905 %%io.stderr.printf("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);1906 warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
1906 return err;1907 return err;
1907 };1908 };
1908}1909}
std/debug.zig+101-98
...@@ -1,10 +1,11 @@...@@ -1,10 +1,11 @@
1const math = @import("math/index.zig");1const std = @import("index.zig");
2const mem = @import("mem.zig");2const math = std.math;
3const io = @import("io.zig");3const mem = std.mem;
4const os = @import("os/index.zig");4const io = std.io;
5const os = std.os;
5const elf = @import("elf.zig");6const elf = @import("elf.zig");
6const DW = @import("dwarf.zig");7const DW = @import("dwarf.zig");
7const ArrayList = @import("array_list.zig").ArrayList;8const ArrayList = std.ArrayList;
8const builtin = @import("builtin");9const builtin = @import("builtin");
910
10error MissingDebugInfo;11error MissingDebugInfo;
...@@ -12,10 +13,42 @@ error InvalidDebugInfo;...@@ -12,10 +13,42 @@ error InvalidDebugInfo;
12error UnsupportedDebugInfo;13error UnsupportedDebugInfo;
1314
1415
16/// Tries to write to stderr, unbuffered, and ignores any error returned.
17/// Does not append a newline.
18/// TODO atomic/multithread support
19var stderr_file: io.File = undefined;
20var stderr_stream: ?&io.OutStream = null;
21pub fn warn(comptime fmt: []const u8, args: ...) {
22 const stderr = getStderrStream() %% return;
23 stderr.print(fmt, args) %% return;
24}
25fn getStderrStream() -> %&io.OutStream {
26 if (stderr_stream) |st| {
27 return st;
28 } else {
29 stderr_file = %return io.getStdErr();
30 const st = &stderr_file.out_stream;
31 stderr_stream = st;
32 return st;
33 };
34}
35
36/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
37pub fn dumpStackTrace() {
38 const stderr = getStderrStream() %% return;
39 writeStackTrace(stderr, &global_allocator, stderr_file.isTty(), 1) %% return;
40}
41
42/// This function invokes undefined behavior when `ok` is `false`.
43/// In Debug and ReleaseSafe modes, calls to this function are always
44/// generated, and the `unreachable` statement triggers a panic.
45/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
46/// optimized away.
15pub fn assert(ok: bool) {47pub fn assert(ok: bool) {
16 if (!ok) {48 if (!ok) {
17 // In ReleaseFast test mode, we still want assert(false) to crash, so49 // In ReleaseFast test mode, we still want assert(false) to crash, so
18 // we insert an explicit call to @panic instead of unreachable.50 // we insert an explicit call to @panic instead of unreachable.
51 // TODO we should use `assertOrPanic` in tests and remove this logic.
19 if (builtin.is_test) {52 if (builtin.is_test) {
20 @panic("assertion failure")53 @panic("assertion failure")
21 } else {54 } else {
...@@ -24,6 +57,14 @@ pub fn assert(ok: bool) {...@@ -24,6 +57,14 @@ pub fn assert(ok: bool) {
24 }57 }
25}58}
2659
60/// Call this function when you want to panic if the condition is not true.
61/// If `ok` is `false`, this function will panic in every release mode.
62pub fn assertOrPanic(ok: bool) {
63 if (!ok) {
64 @panic("assertion failure");
65 }
66}
67
27var panicking = false;68var panicking = false;
28/// This is the default panic implementation.69/// This is the default panic implementation.
29pub fn panic(comptime format: []const u8, args: ...) -> noreturn {70pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
...@@ -41,18 +82,13 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {...@@ -41,18 +82,13 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
41 panicking = true;82 panicking = true;
42 }83 }
4384
44 %%io.stderr.printf(format ++ "\n", args);85 const stderr = getStderrStream() %% os.abort();
45 %%writeStackTrace(&io.stderr, &global_allocator, io.stderr.isTty() %% false, 1);86 stderr.print(format ++ "\n", args) %% os.abort();
46 %%io.stderr.flush();87 writeStackTrace(stderr, &global_allocator, stderr_file.isTty(), 1) %% os.abort();
4788
48 os.abort();89 os.abort();
49}90}
5091
51pub fn printStackTrace() -> %void {
52 %return writeStackTrace(&io.stderr, &global_allocator, io.stderr.isTty() %% false, 1);
53 %return io.stderr.flush();
54}
55
56const GREEN = "\x1b[32;1m";92const GREEN = "\x1b[32;1m";
57const WHITE = "\x1b[37;1m";93const WHITE = "\x1b[37;1m";
58const DIM = "\x1b[2m";94const DIM = "\x1b[2m";
...@@ -69,7 +105,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -69,7 +105,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
69 switch (builtin.object_format) {105 switch (builtin.object_format) {
70 builtin.ObjectFormat.elf => {106 builtin.ObjectFormat.elf => {
71 var stack_trace = ElfStackTrace {107 var stack_trace = ElfStackTrace {
72 .self_exe_stream = undefined,108 .self_exe_file = undefined,
73 .elf = undefined,109 .elf = undefined,
74 .debug_info = undefined,110 .debug_info = undefined,
75 .debug_abbrev = undefined,111 .debug_abbrev = undefined,
...@@ -79,10 +115,10 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -79,10 +115,10 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
79 .compile_unit_list = ArrayList(CompileUnit).init(allocator),115 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
80 };116 };
81 const st = &stack_trace;117 const st = &stack_trace;
82 st.self_exe_stream = %return io.openSelfExe();118 st.self_exe_file = %return os.openSelfExe();
83 defer st.self_exe_stream.close();119 defer st.self_exe_file.close();
84120
85 %return st.elf.openStream(allocator, &st.self_exe_stream);121 %return st.elf.openFile(allocator, &st.self_exe_file);
86 defer st.elf.close();122 defer st.elf.close();
87123
88 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;124 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
...@@ -109,7 +145,6 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -109,7 +145,6 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
109 const compile_unit = findCompileUnit(st, return_address) ?? {145 const compile_unit = findCompileUnit(st, return_address) ?? {
110 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",146 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
111 return_address);147 return_address);
112 %return out_stream.flush();
113 continue;148 continue;
114 };149 };
115 const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);150 const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
...@@ -139,7 +174,6 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -139,7 +174,6 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
139 },174 },
140 else => return err,175 else => return err,
141 };176 };
142 %return out_stream.flush();
143 }177 }
144 },178 },
145 builtin.ObjectFormat.coff => {179 builtin.ObjectFormat.coff => {
...@@ -158,7 +192,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -158,7 +192,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
158}192}
159193
160fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {194fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
161 var f = %return io.InStream.open(line_info.file_name, allocator);195 var f = %return io.File.openRead(line_info.file_name, allocator);
162 defer f.close();196 defer f.close();
163 // TODO fstat and make sure that the file has the correct size197 // TODO fstat and make sure that the file has the correct size
164198
...@@ -167,7 +201,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_...@@ -167,7 +201,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
167 var column: usize = 1;201 var column: usize = 1;
168 var abs_index: usize = 0;202 var abs_index: usize = 0;
169 while (true) {203 while (true) {
170 const amt_read = %return f.read(buf[0..]);204 const amt_read = %return f.in_stream.read(buf[0..]);
171 const slice = buf[0..amt_read];205 const slice = buf[0..amt_read];
172206
173 for (slice) |byte| {207 for (slice) |byte| {
...@@ -191,7 +225,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_...@@ -191,7 +225,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
191}225}
192226
193const ElfStackTrace = struct {227const ElfStackTrace = struct {
194 self_exe_stream: io.InStream,228 self_exe_file: io.File,
195 elf: elf.Elf,229 elf: elf.Elf,
196 debug_info: &elf.SectionHeader,230 debug_info: &elf.SectionHeader,
197 debug_abbrev: &elf.SectionHeader,231 debug_abbrev: &elf.SectionHeader,
...@@ -205,7 +239,7 @@ const ElfStackTrace = struct {...@@ -205,7 +239,7 @@ const ElfStackTrace = struct {
205 }239 }
206240
207 pub fn readString(self: &ElfStackTrace) -> %[]u8 {241 pub fn readString(self: &ElfStackTrace) -> %[]u8 {
208 return readStringRaw(self.allocator(), &self.self_exe_stream);242 return readStringRaw(self.allocator(), &self.self_exe_file.in_stream);
209 }243 }
210};244};
211245
...@@ -424,7 +458,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {...@@ -424,7 +458,7 @@ fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
424458
425fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {459fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
426 const pos = st.debug_str.offset + offset;460 const pos = st.debug_str.offset + offset;
427 %return st.self_exe_stream.seekTo(pos);461 %return st.self_exe_file.seekTo(pos);
428 return st.readString();462 return st.readString();
429}463}
430464
...@@ -533,7 +567,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u...@@ -533,7 +567,7 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
533}567}
534568
535fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {569fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
536 const in_stream = &st.self_exe_stream;570 const in_stream = &st.self_exe_file.in_stream;
537 var result = AbbrevTable.init(st.allocator());571 var result = AbbrevTable.init(st.allocator());
538 while (true) {572 while (true) {
539 const abbrev_code = %return readULeb128(in_stream);573 const abbrev_code = %return readULeb128(in_stream);
...@@ -568,7 +602,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable...@@ -568,7 +602,7 @@ fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable
568 return &header.table;602 return &header.table;
569 }603 }
570 }604 }
571 %return st.self_exe_stream.seekTo(st.debug_abbrev.offset + abbrev_offset);605 %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
572 %return st.abbrev_table_list.append(AbbrevTableHeader {606 %return st.abbrev_table_list.append(AbbrevTableHeader {
573 .offset = abbrev_offset,607 .offset = abbrev_offset,
574 .table = %return parseAbbrevTable(st),608 .table = %return parseAbbrevTable(st),
...@@ -585,8 +619,8 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&...@@ -585,8 +619,8 @@ fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&
585}619}
586620
587fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {621fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
588 const in_stream = &st.self_exe_stream;622 const in_file = &st.self_exe_file;
589 const abbrev_code = %return readULeb128(in_stream);623 const abbrev_code = %return readULeb128(&in_file.in_stream);
590 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;624 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
591625
592 var result = Die {626 var result = Die {
...@@ -598,7 +632,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -...@@ -598,7 +632,7 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -
598 for (table_entry.attrs.toSliceConst()) |attr, i| {632 for (table_entry.attrs.toSliceConst()) |attr, i| {
599 result.attrs.items[i] = Die.Attr {633 result.attrs.items[i] = Die.Attr {
600 .id = attr.attr_id,634 .id = attr.attr_id,
601 .value = %return parseFormValue(st.allocator(), &st.self_exe_stream, attr.form_id, is_64),635 .value = %return parseFormValue(st.allocator(), &st.self_exe_file.in_stream, attr.form_id, is_64),
602 };636 };
603 }637 }
604 return result;638 return result;
...@@ -607,16 +641,16 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -...@@ -607,16 +641,16 @@ fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -
607fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {641fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
608 const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);642 const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
609643
610 const in_stream = &st.self_exe_stream;644 const in_file = &st.self_exe_file;
611 const debug_line_end = st.debug_line.offset + st.debug_line.size;645 const debug_line_end = st.debug_line.offset + st.debug_line.size;
612 var this_offset = st.debug_line.offset;646 var this_offset = st.debug_line.offset;
613 var this_index: usize = 0;647 var this_index: usize = 0;
614648
615 while (this_offset < debug_line_end) : (this_index += 1) {649 while (this_offset < debug_line_end) : (this_index += 1) {
616 %return in_stream.seekTo(this_offset);650 %return in_file.seekTo(this_offset);
617651
618 var is_64: bool = undefined;652 var is_64: bool = undefined;
619 const unit_length = %return readInitialLength(in_stream, &is_64);653 const unit_length = %return readInitialLength(&in_file.in_stream, &is_64);
620 if (unit_length == 0)654 if (unit_length == 0)
621 return error.MissingDebugInfo;655 return error.MissingDebugInfo;
622 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));656 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
...@@ -626,28 +660,28 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -626,28 +660,28 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
626 continue;660 continue;
627 }661 }
628662
629 const version = %return in_stream.readInt(st.elf.is_big_endian, u16);663 const version = %return in_file.in_stream.readInt(st.elf.is_big_endian, u16);
630 if (version != 2) return error.InvalidDebugInfo;664 if (version != 2) return error.InvalidDebugInfo;
631665
632 const prologue_length = %return in_stream.readInt(st.elf.is_big_endian, u32);666 const prologue_length = %return in_file.in_stream.readInt(st.elf.is_big_endian, u32);
633 const prog_start_offset = (%return in_stream.getPos()) + prologue_length;667 const prog_start_offset = (%return in_file.getPos()) + prologue_length;
634668
635 const minimum_instruction_length = %return in_stream.readByte();669 const minimum_instruction_length = %return in_file.in_stream.readByte();
636 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;670 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
637671
638 const default_is_stmt = (%return in_stream.readByte()) != 0;672 const default_is_stmt = (%return in_file.in_stream.readByte()) != 0;
639 const line_base = %return in_stream.readByteSigned();673 const line_base = %return in_file.in_stream.readByteSigned();
640674
641 const line_range = %return in_stream.readByte();675 const line_range = %return in_file.in_stream.readByte();
642 if (line_range == 0)676 if (line_range == 0)
643 return error.InvalidDebugInfo;677 return error.InvalidDebugInfo;
644678
645 const opcode_base = %return in_stream.readByte();679 const opcode_base = %return in_file.in_stream.readByte();
646680
647 const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);681 const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
648682
649 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {683 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
650 standard_opcode_lengths[i] = %return in_stream.readByte();684 standard_opcode_lengths[i] = %return in_file.in_stream.readByte();
651 }}685 }}
652686
653 var include_directories = ArrayList([]u8).init(st.allocator());687 var include_directories = ArrayList([]u8).init(st.allocator());
...@@ -667,9 +701,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -667,9 +701,9 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
667 const file_name = %return st.readString();701 const file_name = %return st.readString();
668 if (file_name.len == 0)702 if (file_name.len == 0)
669 break;703 break;
670 const dir_index = %return readULeb128(in_stream);704 const dir_index = %return readULeb128(&in_file.in_stream);
671 const mtime = %return readULeb128(in_stream);705 const mtime = %return readULeb128(&in_file.in_stream);
672 const len_bytes = %return readULeb128(in_stream);706 const len_bytes = %return readULeb128(&in_file.in_stream);
673 %return file_entries.append(FileEntry {707 %return file_entries.append(FileEntry {
674 .file_name = file_name,708 .file_name = file_name,
675 .dir_index = dir_index,709 .dir_index = dir_index,
...@@ -678,42 +712,32 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -678,42 +712,32 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
678 });712 });
679 }713 }
680714
681 %return in_stream.seekTo(prog_start_offset);715 %return in_file.seekTo(prog_start_offset);
682716
683 while (true) {717 while (true) {
684 //const pos = (%return in_stream.getPos()) - this_offset;718 const opcode = %return in_file.in_stream.readByte();
685 //if (pos == 0x1a3) @breakpoint();
686 //%%io.stderr.printf("\n{x8}\n", pos);
687
688 const opcode = %return in_stream.readByte();
689719
690 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash720 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
691 if (opcode == DW.LNS_extended_op) {721 if (opcode == DW.LNS_extended_op) {
692 const op_size = %return readULeb128(in_stream);722 const op_size = %return readULeb128(&in_file.in_stream);
693 if (op_size < 1)723 if (op_size < 1)
694 return error.InvalidDebugInfo;724 return error.InvalidDebugInfo;
695 sub_op = %return in_stream.readByte();725 sub_op = %return in_file.in_stream.readByte();
696 switch (sub_op) {726 switch (sub_op) {
697 DW.LNE_end_sequence => {727 DW.LNE_end_sequence => {
698 //%%io.stdout.printf(" [0x{x8}] End Sequence\n", pos);
699 prog.end_sequence = true;728 prog.end_sequence = true;
700 if (%return prog.checkLineMatch()) |info| return info;729 if (%return prog.checkLineMatch()) |info| return info;
701 return error.MissingDebugInfo;730 return error.MissingDebugInfo;
702 },731 },
703 DW.LNE_set_address => {732 DW.LNE_set_address => {
704 const addr = %return in_stream.readInt(st.elf.is_big_endian, usize);733 const addr = %return in_file.in_stream.readInt(st.elf.is_big_endian, usize);
705 prog.address = addr;734 prog.address = addr;
706
707 //%%io.stdout.printf(" [0x{x8}] Extended opcode {}: set Address to 0x{x}\n",
708 // pos, sub_op, addr);
709 },735 },
710 DW.LNE_define_file => {736 DW.LNE_define_file => {
711 //%%io.stdout.printf(" [0x{x8}] Define File\n", pos);
712
713 const file_name = %return st.readString();737 const file_name = %return st.readString();
714 const dir_index = %return readULeb128(in_stream);738 const dir_index = %return readULeb128(&in_file.in_stream);
715 const mtime = %return readULeb128(in_stream);739 const mtime = %return readULeb128(&in_file.in_stream);
716 const len_bytes = %return readULeb128(in_stream);740 const len_bytes = %return readULeb128(&in_file.in_stream);
717 %return file_entries.append(FileEntry {741 %return file_entries.append(FileEntry {
718 .file_name = file_name,742 .file_name = file_name,
719 .dir_index = dir_index,743 .dir_index = dir_index,
...@@ -723,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -723,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
723 },747 },
724 else => {748 else => {
725 const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;749 const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
726 %return in_stream.seekForward(fwd_amt);750 %return in_file.seekForward(fwd_amt);
727 },751 },
728 }752 }
729 } else if (opcode >= opcode_base) {753 } else if (opcode >= opcode_base) {
...@@ -733,48 +757,32 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -733,48 +757,32 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
733 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);757 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
734 prog.line += inc_line;758 prog.line += inc_line;
735 prog.address += inc_addr;759 prog.address += inc_addr;
736 //%%io.stdout.printf(
737 // " [0x{x8}] Special opcode {}: advance Address by {} to 0x{x} and Line by {} to {}\n",
738 // pos, adjusted_opcode, inc_addr, prog.address, inc_line, prog.line);
739 if (%return prog.checkLineMatch()) |info| return info;760 if (%return prog.checkLineMatch()) |info| return info;
740 prog.basic_block = false;761 prog.basic_block = false;
741 } else {762 } else {
742 switch (opcode) {763 switch (opcode) {
743 DW.LNS_copy => {764 DW.LNS_copy => {
744 //%%io.stdout.printf(" [0x{x8}] Copy\n", pos);
745
746 if (%return prog.checkLineMatch()) |info| return info;765 if (%return prog.checkLineMatch()) |info| return info;
747 prog.basic_block = false;766 prog.basic_block = false;
748 },767 },
749 DW.LNS_advance_pc => {768 DW.LNS_advance_pc => {
750 const arg = %return readULeb128(in_stream);769 const arg = %return readULeb128(&in_file.in_stream);
751 prog.address += arg * minimum_instruction_length;770 prog.address += arg * minimum_instruction_length;
752
753 //%%io.stdout.printf(" [0x{x8}] Advance PC by {} to 0x{x}\n", pos, arg, prog.address);
754 },771 },
755 DW.LNS_advance_line => {772 DW.LNS_advance_line => {
756 const arg = %return readILeb128(in_stream);773 const arg = %return readILeb128(&in_file.in_stream);
757 prog.line += arg;774 prog.line += arg;
758
759 //%%io.stdout.printf(" [0x{x8}] Advance Line by {} to {}\n", pos, arg, prog.line);
760 },775 },
761 DW.LNS_set_file => {776 DW.LNS_set_file => {
762 const arg = %return readULeb128(in_stream);777 const arg = %return readULeb128(&in_file.in_stream);
763 prog.file = arg;778 prog.file = arg;
764
765 //%%io.stdout.printf(" [0x{x8}] Set File Name to entry {} in the File Name Table\n",
766 // pos, arg);
767 },779 },
768 DW.LNS_set_column => {780 DW.LNS_set_column => {
769 const arg = %return readULeb128(in_stream);781 const arg = %return readULeb128(&in_file.in_stream);
770 prog.column = arg;782 prog.column = arg;
771
772 //%%io.stdout.printf(" [0x{x8}] Set column to {}\n", pos, arg);
773 },783 },
774 DW.LNS_negate_stmt => {784 DW.LNS_negate_stmt => {
775 prog.is_stmt = !prog.is_stmt;785 prog.is_stmt = !prog.is_stmt;
776
777 //%%io.stdout.printf(" [0x{x8}] Set is_stmt to {}\n", pos, if (prog.is_stmt) u8(1) else u8(0));
778 },786 },
779 DW.LNS_set_basic_block => {787 DW.LNS_set_basic_block => {
780 prog.basic_block = true;788 prog.basic_block = true;
...@@ -782,23 +790,18 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe...@@ -782,23 +790,18 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
782 DW.LNS_const_add_pc => {790 DW.LNS_const_add_pc => {
783 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);791 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
784 prog.address += inc_addr;792 prog.address += inc_addr;
785
786 //%%io.stdout.printf(" [0x{x8}] Advance PC by constant {} to 0x{x}\n",
787 // pos, inc_addr, prog.address);
788 },793 },
789 DW.LNS_fixed_advance_pc => {794 DW.LNS_fixed_advance_pc => {
790 const arg = %return in_stream.readInt(st.elf.is_big_endian, u16);795 const arg = %return in_file.in_stream.readInt(st.elf.is_big_endian, u16);
791 prog.address += arg;796 prog.address += arg;
792 },797 },
793 DW.LNS_set_prologue_end => {798 DW.LNS_set_prologue_end => {
794 //%%io.stdout.printf(" [0x{x8}] Set prologue_end to true\n", pos);
795 },799 },
796 else => {800 else => {
797 if (opcode - 1 >= standard_opcode_lengths.len)801 if (opcode - 1 >= standard_opcode_lengths.len)
798 return error.InvalidDebugInfo;802 return error.InvalidDebugInfo;
799 //%%io.stdout.printf(" [0x{x8}] unknown op code {}\n", pos, opcode);
800 const len_bytes = standard_opcode_lengths[opcode - 1];803 const len_bytes = standard_opcode_lengths[opcode - 1];
801 %return in_stream.seekForward(len_bytes);804 %return in_file.seekForward(len_bytes);
802 },805 },
803 }806 }
804 }807 }
...@@ -815,30 +818,30 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {...@@ -815,30 +818,30 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
815 var this_unit_offset = st.debug_info.offset;818 var this_unit_offset = st.debug_info.offset;
816 var cu_index: usize = 0;819 var cu_index: usize = 0;
817 while (this_unit_offset < debug_info_end) {820 while (this_unit_offset < debug_info_end) {
818 %return st.self_exe_stream.seekTo(this_unit_offset);821 %return st.self_exe_file.seekTo(this_unit_offset);
819822
820 var is_64: bool = undefined;823 var is_64: bool = undefined;
821 const unit_length = %return readInitialLength(&st.self_exe_stream, &is_64);824 const unit_length = %return readInitialLength(&st.self_exe_file.in_stream, &is_64);
822 if (unit_length == 0)825 if (unit_length == 0)
823 return;826 return;
824 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));827 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
825828
826 const version = %return st.self_exe_stream.readInt(st.elf.is_big_endian, u16);829 const version = %return st.self_exe_file.in_stream.readInt(st.elf.is_big_endian, u16);
827 if (version < 2 or version > 5) return error.InvalidDebugInfo;830 if (version < 2 or version > 5) return error.InvalidDebugInfo;
828831
829 const debug_abbrev_offset = if (is_64) {832 const debug_abbrev_offset = if (is_64) {
830 %return st.self_exe_stream.readInt(st.elf.is_big_endian, u64)833 %return st.self_exe_file.in_stream.readInt(st.elf.is_big_endian, u64)
831 } else {834 } else {
832 %return st.self_exe_stream.readInt(st.elf.is_big_endian, u32)835 %return st.self_exe_file.in_stream.readInt(st.elf.is_big_endian, u32)
833 };836 };
834837
835 const address_size = %return st.self_exe_stream.readByte();838 const address_size = %return st.self_exe_file.in_stream.readByte();
836 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;839 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
837840
838 const compile_unit_pos = %return st.self_exe_stream.getPos();841 const compile_unit_pos = %return st.self_exe_file.getPos();
839 const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);842 const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
840843
841 %return st.self_exe_stream.seekTo(compile_unit_pos);844 %return st.self_exe_file.seekTo(compile_unit_pos);
842845
843 const compile_unit_die = %return st.allocator().create(Die);846 const compile_unit_die = %return st.allocator().create(Die);
844 *compile_unit_die = %return parseDie(st, abbrev_table, is_64);847 *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
std/elf.zig+61-59
...@@ -1,7 +1,9 @@...@@ -1,7 +1,9 @@
1const io = @import("io.zig");1const std = @import("index.zig");
2const math = @import("math/index.zig");2const io = std.io;
3const mem = @import("mem.zig");3const math = std.math;
4const debug = @import("debug.zig");4const mem = std.mem;
5const debug = std.debug;
6const InStream = std.stream.InStream;
57
6error InvalidFormat;8error InvalidFormat;
79
...@@ -62,7 +64,7 @@ pub const SectionHeader = struct {...@@ -62,7 +64,7 @@ pub const SectionHeader = struct {
62};64};
6365
64pub const Elf = struct {66pub const Elf = struct {
65 in_stream: &io.InStream,67 in_file: &io.File,
66 auto_close_stream: bool,68 auto_close_stream: bool,
67 is_64: bool,69 is_64: bool,
68 is_big_endian: bool,70 is_big_endian: bool,
...@@ -75,44 +77,44 @@ pub const Elf = struct {...@@ -75,44 +77,44 @@ pub const Elf = struct {
75 string_section: &SectionHeader,77 string_section: &SectionHeader,
76 section_headers: []SectionHeader,78 section_headers: []SectionHeader,
77 allocator: &mem.Allocator,79 allocator: &mem.Allocator,
78 prealloc_stream: io.InStream,80 prealloc_file: io.File,
7981
80 /// Call close when done.82 /// Call close when done.
81 pub fn openFile(elf: &Elf, allocator: &mem.Allocator, path: []const u8) -> %void {83 pub fn openPath(elf: &Elf, allocator: &mem.Allocator, path: []const u8) -> %void {
82 %return elf.prealloc_stream.open(path);84 %return elf.prealloc_file.open(path);
83 %return elf.openStream(allocator, &elf.prealloc_stream);85 %return elf.openFile(allocator, &elf.prealloc_file);
84 elf.auto_close_stream = true;86 elf.auto_close_stream = true;
85 }87 }
8688
87 /// Call close when done.89 /// Call close when done.
88 pub fn openStream(elf: &Elf, allocator: &mem.Allocator, stream: &io.InStream) -> %void {90 pub fn openFile(elf: &Elf, allocator: &mem.Allocator, file: &io.File) -> %void {
89 elf.allocator = allocator;91 elf.allocator = allocator;
90 elf.in_stream = stream;92 elf.in_file = file;
91 elf.auto_close_stream = false;93 elf.auto_close_stream = false;
9294
93 var magic: [4]u8 = undefined;95 var magic: [4]u8 = undefined;
94 %return elf.in_stream.readNoEof(magic[0..]);96 %return elf.in_file.in_stream.readNoEof(magic[0..]);
95 if (!mem.eql(u8, magic, "\x7fELF")) return error.InvalidFormat;97 if (!mem.eql(u8, magic, "\x7fELF")) return error.InvalidFormat;
9698
97 elf.is_64 = switch (%return elf.in_stream.readByte()) {99 elf.is_64 = switch (%return elf.in_file.in_stream.readByte()) {
98 1 => false,100 1 => false,
99 2 => true,101 2 => true,
100 else => return error.InvalidFormat,102 else => return error.InvalidFormat,
101 };103 };
102104
103 elf.is_big_endian = switch (%return elf.in_stream.readByte()) {105 elf.is_big_endian = switch (%return elf.in_file.in_stream.readByte()) {
104 1 => false,106 1 => false,
105 2 => true,107 2 => true,
106 else => return error.InvalidFormat,108 else => return error.InvalidFormat,
107 };109 };
108110
109 const version_byte = %return elf.in_stream.readByte();111 const version_byte = %return elf.in_file.in_stream.readByte();
110 if (version_byte != 1) return error.InvalidFormat;112 if (version_byte != 1) return error.InvalidFormat;
111113
112 // skip over padding114 // skip over padding
113 %return elf.in_stream.seekForward(9);115 %return elf.in_file.seekForward(9);
114116
115 elf.file_type = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) {117 elf.file_type = switch (%return elf.in_file.in_stream.readInt(elf.is_big_endian, u16)) {
116 1 => FileType.Relocatable,118 1 => FileType.Relocatable,
117 2 => FileType.Executable,119 2 => FileType.Executable,
118 3 => FileType.Shared,120 3 => FileType.Shared,
...@@ -120,7 +122,7 @@ pub const Elf = struct {...@@ -120,7 +122,7 @@ pub const Elf = struct {
120 else => return error.InvalidFormat,122 else => return error.InvalidFormat,
121 };123 };
122124
123 elf.arch = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) {125 elf.arch = switch (%return elf.in_file.in_stream.readInt(elf.is_big_endian, u16)) {
124 0x02 => Arch.Sparc,126 0x02 => Arch.Sparc,
125 0x03 => Arch.x86,127 0x03 => Arch.x86,
126 0x08 => Arch.Mips,128 0x08 => Arch.Mips,
...@@ -133,34 +135,34 @@ pub const Elf = struct {...@@ -133,34 +135,34 @@ pub const Elf = struct {
133 else => return error.InvalidFormat,135 else => return error.InvalidFormat,
134 };136 };
135137
136 const elf_version = %return elf.in_stream.readInt(elf.is_big_endian, u32);138 const elf_version = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
137 if (elf_version != 1) return error.InvalidFormat;139 if (elf_version != 1) return error.InvalidFormat;
138140
139 if (elf.is_64) {141 if (elf.is_64) {
140 elf.entry_addr = %return elf.in_stream.readInt(elf.is_big_endian, u64);142 elf.entry_addr = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
141 elf.program_header_offset = %return elf.in_stream.readInt(elf.is_big_endian, u64);143 elf.program_header_offset = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
142 elf.section_header_offset = %return elf.in_stream.readInt(elf.is_big_endian, u64);144 elf.section_header_offset = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
143 } else {145 } else {
144 elf.entry_addr = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));146 elf.entry_addr = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
145 elf.program_header_offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));147 elf.program_header_offset = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
146 elf.section_header_offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));148 elf.section_header_offset = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
147 }149 }
148150
149 // skip over flags151 // skip over flags
150 %return elf.in_stream.seekForward(4);152 %return elf.in_file.seekForward(4);
151153
152 const header_size = %return elf.in_stream.readInt(elf.is_big_endian, u16);154 const header_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
153 if ((elf.is_64 and header_size != 64) or155 if ((elf.is_64 and header_size != 64) or
154 (!elf.is_64 and header_size != 52))156 (!elf.is_64 and header_size != 52))
155 {157 {
156 return error.InvalidFormat;158 return error.InvalidFormat;
157 }159 }
158160
159 const ph_entry_size = %return elf.in_stream.readInt(elf.is_big_endian, u16);161 const ph_entry_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
160 const ph_entry_count = %return elf.in_stream.readInt(elf.is_big_endian, u16);162 const ph_entry_count = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
161 const sh_entry_size = %return elf.in_stream.readInt(elf.is_big_endian, u16);163 const sh_entry_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
162 const sh_entry_count = %return elf.in_stream.readInt(elf.is_big_endian, u16);164 const sh_entry_count = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u16);
163 elf.string_section_index = u64(%return elf.in_stream.readInt(elf.is_big_endian, u16));165 elf.string_section_index = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u16));
164166
165 if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;167 if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
166168
...@@ -169,12 +171,12 @@ pub const Elf = struct {...@@ -169,12 +171,12 @@ pub const Elf = struct {
169 const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);171 const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
170 const end_ph = %return math.add(u64, elf.program_header_offset, ph_byte_count);172 const end_ph = %return math.add(u64, elf.program_header_offset, ph_byte_count);
171173
172 const stream_end = %return elf.in_stream.getEndPos();174 const stream_end = %return elf.in_file.getEndPos();
173 if (stream_end < end_sh or stream_end < end_ph) {175 if (stream_end < end_sh or stream_end < end_ph) {
174 return error.InvalidFormat;176 return error.InvalidFormat;
175 }177 }
176178
177 %return elf.in_stream.seekTo(elf.section_header_offset);179 %return elf.in_file.seekTo(elf.section_header_offset);
178180
179 elf.section_headers = %return elf.allocator.alloc(SectionHeader, sh_entry_count);181 elf.section_headers = %return elf.allocator.alloc(SectionHeader, sh_entry_count);
180 %defer elf.allocator.free(elf.section_headers);182 %defer elf.allocator.free(elf.section_headers);
...@@ -183,32 +185,32 @@ pub const Elf = struct {...@@ -183,32 +185,32 @@ pub const Elf = struct {
183 if (sh_entry_size != 64) return error.InvalidFormat;185 if (sh_entry_size != 64) return error.InvalidFormat;
184186
185 for (elf.section_headers) |*section| {187 for (elf.section_headers) |*section| {
186 section.name = %return elf.in_stream.readInt(elf.is_big_endian, u32);188 section.name = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
187 section.sh_type = %return elf.in_stream.readInt(elf.is_big_endian, u32);189 section.sh_type = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
188 section.flags = %return elf.in_stream.readInt(elf.is_big_endian, u64);190 section.flags = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
189 section.addr = %return elf.in_stream.readInt(elf.is_big_endian, u64);191 section.addr = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
190 section.offset = %return elf.in_stream.readInt(elf.is_big_endian, u64);192 section.offset = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
191 section.size = %return elf.in_stream.readInt(elf.is_big_endian, u64);193 section.size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
192 section.link = %return elf.in_stream.readInt(elf.is_big_endian, u32);194 section.link = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
193 section.info = %return elf.in_stream.readInt(elf.is_big_endian, u32);195 section.info = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
194 section.addr_align = %return elf.in_stream.readInt(elf.is_big_endian, u64);196 section.addr_align = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
195 section.ent_size = %return elf.in_stream.readInt(elf.is_big_endian, u64);197 section.ent_size = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u64);
196 }198 }
197 } else {199 } else {
198 if (sh_entry_size != 40) return error.InvalidFormat;200 if (sh_entry_size != 40) return error.InvalidFormat;
199201
200 for (elf.section_headers) |*section| {202 for (elf.section_headers) |*section| {
201 // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?203 // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?
202 section.name = %return elf.in_stream.readInt(elf.is_big_endian, u32);204 section.name = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
203 section.sh_type = %return elf.in_stream.readInt(elf.is_big_endian, u32);205 section.sh_type = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
204 section.flags = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));206 section.flags = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
205 section.addr = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));207 section.addr = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
206 section.offset = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));208 section.offset = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
207 section.size = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));209 section.size = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
208 section.link = %return elf.in_stream.readInt(elf.is_big_endian, u32);210 section.link = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
209 section.info = %return elf.in_stream.readInt(elf.is_big_endian, u32);211 section.info = %return elf.in_file.in_stream.readInt(elf.is_big_endian, u32);
210 section.addr_align = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));212 section.addr_align = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
211 section.ent_size = u64(%return elf.in_stream.readInt(elf.is_big_endian, u32));213 section.ent_size = u64(%return elf.in_file.in_stream.readInt(elf.is_big_endian, u32));
212 }214 }
213 }215 }
214216
...@@ -230,7 +232,7 @@ pub const Elf = struct {...@@ -230,7 +232,7 @@ pub const Elf = struct {
230 elf.allocator.free(elf.section_headers);232 elf.allocator.free(elf.section_headers);
231233
232 if (elf.auto_close_stream)234 if (elf.auto_close_stream)
233 elf.in_stream.close();235 elf.in_file.close();
234 }236 }
235237
236 pub fn findSection(elf: &Elf, name: []const u8) -> %?&SectionHeader {238 pub fn findSection(elf: &Elf, name: []const u8) -> %?&SectionHeader {
...@@ -238,15 +240,15 @@ pub const Elf = struct {...@@ -238,15 +240,15 @@ pub const Elf = struct {
238 if (section.sh_type == SHT_NULL) continue;240 if (section.sh_type == SHT_NULL) continue;
239241
240 const name_offset = elf.string_section.offset + section.name;242 const name_offset = elf.string_section.offset + section.name;
241 %return elf.in_stream.seekTo(name_offset);243 %return elf.in_file.seekTo(name_offset);
242244
243 for (name) |expected_c| {245 for (name) |expected_c| {
244 const target_c = %return elf.in_stream.readByte();246 const target_c = %return elf.in_file.in_stream.readByte();
245 if (target_c == 0 or expected_c != target_c) goto next_section;247 if (target_c == 0 or expected_c != target_c) goto next_section;
246 }248 }
247249
248 {250 {
249 const null_byte = %return elf.in_stream.readByte();251 const null_byte = %return elf.in_file.in_stream.readByte();
250 if (null_byte == 0) return section;252 if (null_byte == 0) return section;
251 }253 }
252254
...@@ -257,6 +259,6 @@ pub const Elf = struct {...@@ -257,6 +259,6 @@ pub const Elf = struct {
257 }259 }
258260
259 pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void {261 pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void {
260 %return elf.in_stream.seekTo(section.offset);262 %return elf.in_file.seekTo(section.offset);
261 }263 }
262};264};
std/fmt/index.zig+40-68
...@@ -19,10 +19,10 @@ const State = enum { // TODO put inside format function and make sure the name a...@@ -19,10 +19,10 @@ const State = enum { // TODO put inside format function and make sure the name a
19};19};
2020
21/// Renders fmt string with args, calling output with slices of bytes.21/// Renders fmt string with args, calling output with slices of bytes.
22/// Return false from output function and output will not be called again.22/// If `output` returns an error, the error is returned from `format` and
23/// Returns false if output ever returned false, true otherwise.23/// `output` is not called again.
24pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,24pub fn format(context: var, output: fn(@typeOf(context), []const u8)->%void,
25 comptime fmt: []const u8, args: ...) -> bool25 comptime fmt: []const u8, args: ...) -> %void
26{26{
27 comptime var start_index = 0;27 comptime var start_index = 0;
28 comptime var state = State.Start;28 comptime var state = State.Start;
...@@ -38,15 +38,13 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -38,15 +38,13 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
38 '{' => {38 '{' => {
39 // TODO if you make this an if statement with `and` then it breaks39 // TODO if you make this an if statement with `and` then it breaks
40 if (start_index < i) {40 if (start_index < i) {
41 if (!output(context, fmt[start_index..i]))41 %return output(context, fmt[start_index..i]);
42 return false;
43 }42 }
44 state = State.OpenBrace;43 state = State.OpenBrace;
45 },44 },
46 '}' => {45 '}' => {
47 if (start_index < i) {46 if (start_index < i) {
48 if (!output(context, fmt[start_index..i]))47 %return output(context, fmt[start_index..i]);
49 return false;
50 }48 }
51 state = State.CloseBrace;49 state = State.CloseBrace;
52 },50 },
...@@ -58,8 +56,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -58,8 +56,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
58 start_index = i;56 start_index = i;
59 },57 },
60 '}' => {58 '}' => {
61 if (!formatValue(args[next_arg], context, output))59 %return formatValue(args[next_arg], context, output);
62 return false;
63 next_arg += 1;60 next_arg += 1;
64 state = State.Start;61 state = State.Start;
65 start_index = i + 1;62 start_index = i + 1;
...@@ -109,8 +106,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -109,8 +106,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
109 },106 },
110 State.Integer => switch (c) {107 State.Integer => switch (c) {
111 '}' => {108 '}' => {
112 if (!formatInt(args[next_arg], radix, uppercase, width, context, output))109 %return formatInt(args[next_arg], radix, uppercase, width, context, output);
113 return false;
114 next_arg += 1;110 next_arg += 1;
115 state = State.Start;111 state = State.Start;
116 start_index = i + 1;112 start_index = i + 1;
...@@ -124,8 +120,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -124,8 +120,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
124 State.IntegerWidth => switch (c) {120 State.IntegerWidth => switch (c) {
125 '}' => {121 '}' => {
126 width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10);122 width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10);
127 if (!formatInt(args[next_arg], radix, uppercase, width, context, output))123 %return formatInt(args[next_arg], radix, uppercase, width, context, output);
128 return false;
129 next_arg += 1;124 next_arg += 1;
130 state = State.Start;125 state = State.Start;
131 start_index = i + 1;126 start_index = i + 1;
...@@ -136,8 +131,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -136,8 +131,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
136 State.BufWidth => switch (c) {131 State.BufWidth => switch (c) {
137 '}' => {132 '}' => {
138 width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10);133 width = comptime %%parseUnsigned(usize, fmt[width_start..i], 10);
139 if (!formatBuf(args[next_arg], width, context, output))134 %return formatBuf(args[next_arg], width, context, output);
140 return false;
141 next_arg += 1;135 next_arg += 1;
142 state = State.Start;136 state = State.Start;
143 start_index = i + 1;137 start_index = i + 1;
...@@ -147,8 +141,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -147,8 +141,7 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
147 },141 },
148 State.Character => switch (c) {142 State.Character => switch (c) {
149 '}' => {143 '}' => {
150 if (!formatAsciiChar(args[next_arg], context, output))144 %return formatAsciiChar(args[next_arg], context, output);
151 return false;
152 next_arg += 1;145 next_arg += 1;
153 state = State.Start;146 state = State.Start;
154 start_index = i + 1;147 start_index = i + 1;
...@@ -166,14 +159,11 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,...@@ -166,14 +159,11 @@ pub fn format(context: var, output: fn(@typeOf(context), []const u8)->bool,
166 }159 }
167 }160 }
168 if (start_index < fmt.len) {161 if (start_index < fmt.len) {
169 if (!output(context, fmt[start_index..]))162 %return output(context, fmt[start_index..]);
170 return false;
171 }163 }
172
173 return true;
174}164}
175165
176pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {166pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void {
177 const T = @typeOf(value);167 const T = @typeOf(value);
178 switch (@typeId(T)) {168 switch (@typeId(T)) {
179 builtin.TypeId.Int => {169 builtin.TypeId.Int => {
...@@ -203,8 +193,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -203,8 +193,7 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
203 }193 }
204 },194 },
205 builtin.TypeId.Error => {195 builtin.TypeId.Error => {
206 if (!output(context, "error."))196 %return output(context, "error.");
207 return false;
208 return output(context, @errorName(value));197 return output(context, @errorName(value));
209 },198 },
210 builtin.TypeId.Pointer => {199 builtin.TypeId.Pointer => {
...@@ -223,27 +212,23 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -223,27 +212,23 @@ pub fn formatValue(value: var, context: var, output: fn(@typeOf(context), []cons
223 }212 }
224}213}
225214
226pub fn formatAsciiChar(c: u8, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {215pub fn formatAsciiChar(c: u8, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void {
227 return output(context, (&c)[0..1]);216 return output(context, (&c)[0..1]);
228}217}
229218
230pub fn formatBuf(buf: []const u8, width: usize,219pub fn formatBuf(buf: []const u8, width: usize,
231 context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool220 context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void
232{221{
233 if (!output(context, buf))222 %return output(context, buf);
234 return false;
235223
236 var leftover_padding = if (width > buf.len) (width - buf.len) else return true;224 var leftover_padding = if (width > buf.len) (width - buf.len) else return;
237 const pad_byte: u8 = ' ';225 const pad_byte: u8 = ' ';
238 while (leftover_padding > 0) : (leftover_padding -= 1) {226 while (leftover_padding > 0) : (leftover_padding -= 1) {
239 if (!output(context, (&pad_byte)[0..1]))227 %return output(context, (&pad_byte)[0..1]);
240 return false;
241 }228 }
242
243 return true;
244}229}
245230
246pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool {231pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void {
247 var x = f64(value);232 var x = f64(value);
248233
249 // Errol doesn't handle these special cases.234 // Errol doesn't handle these special cases.
...@@ -251,8 +236,7 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -251,8 +236,7 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons
251 return output(context, "NaN");236 return output(context, "NaN");
252 }237 }
253 if (math.signbit(x)) {238 if (math.signbit(x)) {
254 if (!output(context, "-"))239 %return output(context, "-");
255 return false;
256 x = -x;240 x = -x;
257 }241 }
258 if (math.isPositiveInf(x)) {242 if (math.isPositiveInf(x)) {
...@@ -264,34 +248,27 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons...@@ -264,34 +248,27 @@ pub fn formatFloat(value: var, context: var, output: fn(@typeOf(context), []cons
264248
265 var buffer: [32]u8 = undefined;249 var buffer: [32]u8 = undefined;
266 const float_decimal = errol3(x, buffer[0..]);250 const float_decimal = errol3(x, buffer[0..]);
267 if (!output(context, float_decimal.digits[0..1]))251 %return output(context, float_decimal.digits[0..1]);
268 return false;252 %return output(context, ".");
269 if (!output(context, "."))
270 return false;
271 if (float_decimal.digits.len > 1) {253 if (float_decimal.digits.len > 1) {
272 const num_digits = if (@typeOf(value) == f32) {254 const num_digits = if (@typeOf(value) == f32) {
273 math.min(usize(9), float_decimal.digits.len)255 math.min(usize(9), float_decimal.digits.len)
274 } else {256 } else {
275 float_decimal.digits.len257 float_decimal.digits.len
276 };258 };
277 if (!output(context, float_decimal.digits[1 .. num_digits]))259 %return output(context, float_decimal.digits[1 .. num_digits]);
278 return false;
279 } else {260 } else {
280 if (!output(context, "0"))261 %return output(context, "0");
281 return false;
282 }262 }
283263
284 if (float_decimal.exp != 1) {264 if (float_decimal.exp != 1) {
285 if (!output(context, "e"))265 %return output(context, "e");
286 return false;266 %return formatInt(float_decimal.exp - 1, 10, false, 0, context, output);
287 if (!formatInt(float_decimal.exp - 1, 10, false, 0, context, output))
288 return false;
289 }267 }
290 return true;
291}268}
292269
293pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,270pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
294 context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool271 context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void
295{272{
296 if (@typeOf(value).is_signed) {273 if (@typeOf(value).is_signed) {
297 return formatIntSigned(value, base, uppercase, width, context, output);274 return formatIntSigned(value, base, uppercase, width, context, output);
...@@ -301,13 +278,12 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,...@@ -301,13 +278,12 @@ pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
301}278}
302279
303fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,280fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
304 context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool281 context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void
305{282{
306 const uint = @IntType(false, @typeOf(value).bit_count);283 const uint = @IntType(false, @typeOf(value).bit_count);
307 if (value < 0) {284 if (value < 0) {
308 const minus_sign: u8 = '-';285 const minus_sign: u8 = '-';
309 if (!output(context, (&minus_sign)[0..1]))286 %return output(context, (&minus_sign)[0..1]);
310 return false;
311 const new_value = uint(-(value + 1)) + 1;287 const new_value = uint(-(value + 1)) + 1;
312 const new_width = if (width == 0) 0 else (width - 1);288 const new_width = if (width == 0) 0 else (width - 1);
313 return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);289 return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);
...@@ -315,8 +291,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -315,8 +291,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
315 return formatIntUnsigned(uint(value), base, uppercase, width, context, output);291 return formatIntUnsigned(uint(value), base, uppercase, width, context, output);
316 } else {292 } else {
317 const plus_sign: u8 = '+';293 const plus_sign: u8 = '+';
318 if (!output(context, (&plus_sign)[0..1]))294 %return output(context, (&plus_sign)[0..1]);
319 return false;
320 const new_value = uint(value);295 const new_value = uint(value);
321 const new_width = if (width == 0) 0 else (width - 1);296 const new_width = if (width == 0) 0 else (width - 1);
322 return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);297 return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);
...@@ -324,7 +299,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -324,7 +299,7 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
324}299}
325300
326fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,301fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
327 context: var, output: fn(@typeOf(context), []const u8)->bool) -> bool302 context: var, output: fn(@typeOf(context), []const u8)->%void) -> %void
328{303{
329 // max_int_digits accounts for the minus sign. when printing an unsigned304 // max_int_digits accounts for the minus sign. when printing an unsigned
330 // number we don't need to do that.305 // number we don't need to do that.
...@@ -348,8 +323,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,...@@ -348,8 +323,7 @@ fn formatIntUnsigned(value: var, base: u8, uppercase: bool, width: usize,
348 const zero_byte: u8 = '0';323 const zero_byte: u8 = '0';
349 var leftover_padding = padding - index;324 var leftover_padding = padding - index;
350 while (true) {325 while (true) {
351 if (!output(context, (&zero_byte)[0..1]))326 %return output(context, (&zero_byte)[0..1]);
352 return false;
353 leftover_padding -= 1;327 leftover_padding -= 1;
354 if (leftover_padding == 0)328 if (leftover_padding == 0)
355 break;329 break;
...@@ -368,17 +342,16 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width:...@@ -368,17 +342,16 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width:
368 .out_buf = out_buf,342 .out_buf = out_buf,
369 .index = 0,343 .index = 0,
370 };344 };
371 _ = formatInt(value, base, uppercase, width, &context, formatIntCallback);345 %%formatInt(value, base, uppercase, width, &context, formatIntCallback);
372 return context.index;346 return context.index;
373}347}
374const FormatIntBuf = struct {348const FormatIntBuf = struct {
375 out_buf: []u8,349 out_buf: []u8,
376 index: usize,350 index: usize,
377};351};
378fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) -> bool {352fn formatIntCallback(context: &FormatIntBuf, bytes: []const u8) -> %void {
379 mem.copy(u8, context.out_buf[context.index..], bytes);353 mem.copy(u8, context.out_buf[context.index..], bytes);
380 context.index += bytes.len;354 context.index += bytes.len;
381 return true;
382}355}
383356
384pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) -> %T {357pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) -> %T {
...@@ -440,28 +413,27 @@ const BufPrintContext = struct {...@@ -440,28 +413,27 @@ const BufPrintContext = struct {
440 remaining: []u8,413 remaining: []u8,
441};414};
442415
443fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> bool {416fn bufPrintWrite(context: &BufPrintContext, bytes: []const u8) -> %void {
444 mem.copy(u8, context.remaining, bytes);417 mem.copy(u8, context.remaining, bytes);
445 context.remaining = context.remaining[bytes.len..];418 context.remaining = context.remaining[bytes.len..];
446 return true;
447}419}
448420
449pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 {421pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) -> []u8 {
450 var context = BufPrintContext { .remaining = buf, };422 var context = BufPrintContext { .remaining = buf, };
451 _ = format(&context, bufPrintWrite, fmt, args);423 %%format(&context, bufPrintWrite, fmt, args);
452 return buf[0..buf.len - context.remaining.len];424 return buf[0..buf.len - context.remaining.len];
453}425}
454426
455pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) -> %[]u8 {427pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) -> %[]u8 {
456 var size: usize = 0;428 var size: usize = 0;
457 _ = format(&size, countSize, fmt, args);429 // Cannot fail because `countSize` cannot fail.
430 %%format(&size, countSize, fmt, args);
458 const buf = %return allocator.alloc(u8, size);431 const buf = %return allocator.alloc(u8, size);
459 return bufPrint(buf, fmt, args);432 return bufPrint(buf, fmt, args);
460}433}
461434
462fn countSize(size: &usize, bytes: []const u8) -> bool {435fn countSize(size: &usize, bytes: []const u8) -> %void {
463 *size += bytes.len;436 *size += bytes.len;
464 return true;
465}437}
466438
467test "buf print int" {439test "buf print int" {
std/heap.zig created+158
...@@ -0,0 +1,158 @@
1const debug = @import("debug.zig");
2const assert = debug.assert;
3const mem = @import("mem.zig");
4const os = @import("os/index.zig");
5const builtin = @import("builtin");
6const Os = builtin.Os;
7const c = @import("c/index.zig");
8
9const Allocator = mem.Allocator;
10
11error OutOfMemory;
12
13pub var c_allocator = Allocator {
14 .allocFn = cAlloc,
15 .reallocFn = cRealloc,
16 .freeFn = cFree,
17};
18
19fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
20 if (c.malloc(usize(n))) |mem| {
21 @ptrCast(&u8, mem)[0..n]
22 } else {
23 error.OutOfMemory
24 }
25}
26
27fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
28 if (new_size <= old_mem.len) {
29 old_mem[0..new_size]
30 } else {
31 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
32 if (c.realloc(old_ptr, usize(new_size))) |mem| {
33 @ptrCast(&u8, mem)[0..new_size]
34 } else {
35 error.OutOfMemory
36 }
37 }
38}
39
40fn cFree(self: &Allocator, old_mem: []u8) {
41 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
42 c.free(old_ptr);
43}
44
45pub const IncrementingAllocator = struct {
46 allocator: Allocator,
47 bytes: []u8,
48 end_index: usize,
49 heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void,
50
51 fn init(capacity: usize) -> %IncrementingAllocator {
52 switch (builtin.os) {
53 Os.linux, Os.darwin, Os.macosx, Os.ios => {
54 const p = os.posix;
55 const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE,
56 p.MAP_PRIVATE|p.MAP_ANONYMOUS|p.MAP_NORESERVE, -1, 0);
57 if (addr == p.MAP_FAILED) {
58 return error.OutOfMemory;
59 }
60 return IncrementingAllocator {
61 .allocator = Allocator {
62 .allocFn = alloc,
63 .reallocFn = realloc,
64 .freeFn = free,
65 },
66 .bytes = @intToPtr(&u8, addr)[0..capacity],
67 .end_index = 0,
68 .heap_handle = {},
69 };
70 },
71 Os.windows => {
72 const heap_handle = os.windows.GetProcessHeap() ?? return error.OutOfMemory;
73 const ptr = os.windows.HeapAlloc(heap_handle, 0, capacity) ?? return error.OutOfMemory;
74 return IncrementingAllocator {
75 .allocator = Allocator {
76 .allocFn = alloc,
77 .reallocFn = realloc,
78 .freeFn = free,
79 },
80 .bytes = @ptrCast(&u8, ptr)[0..capacity],
81 .end_index = 0,
82 .heap_handle = heap_handle,
83 };
84 },
85 else => @compileError("Unsupported OS"),
86 }
87 }
88
89 fn deinit(self: &IncrementingAllocator) {
90 switch (builtin.os) {
91 Os.linux, Os.darwin, Os.macosx, Os.ios => {
92 _ = os.posix.munmap(self.bytes.ptr, self.bytes.len);
93 },
94 Os.windows => {
95 _ = os.windows.HeapFree(self.heap_handle, 0, @ptrCast(os.windows.LPVOID, self.bytes.ptr));
96 },
97 else => @compileError("Unsupported OS"),
98 }
99 }
100
101 fn reset(self: &IncrementingAllocator) {
102 self.end_index = 0;
103 }
104
105 fn bytesLeft(self: &const IncrementingAllocator) -> usize {
106 return self.bytes.len - self.end_index;
107 }
108
109 fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 {
110 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
111 const addr = @ptrToInt(&self.bytes[self.end_index]);
112 const rem = @rem(addr, alignment);
113 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
114 const adjusted_index = self.end_index + march_forward_bytes;
115 const new_end_index = adjusted_index + n;
116 if (new_end_index > self.bytes.len) {
117 return error.OutOfMemory;
118 }
119 const result = self.bytes[adjusted_index .. new_end_index];
120 self.end_index = new_end_index;
121 return result;
122 }
123
124 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
125 if (new_size <= old_mem.len) {
126 return old_mem[0..new_size];
127 } else {
128 const result = %return alloc(allocator, new_size, alignment);
129 mem.copy(u8, result, old_mem);
130 return result;
131 }
132 }
133
134 fn free(allocator: &Allocator, bytes: []u8) {
135 // Do nothing. That's the point of an incrementing allocator.
136 }
137};
138
139test "IncrementingAllocator" {
140 const total_bytes = 100 * 1024 * 1024;
141 var inc_allocator = %%IncrementingAllocator.init(total_bytes);
142 defer inc_allocator.deinit();
143
144 const allocator = &inc_allocator.allocator;
145 const slice = %%allocator.alloc(&i32, 100);
146
147 for (slice) |*item, i| {
148 *item = %%allocator.create(i32);
149 **item = i32(i);
150 }
151
152 assert(inc_allocator.bytesLeft() == total_bytes - @sizeOf(i32) * 100 - @sizeOf(usize) * 100);
153
154 inc_allocator.reset();
155
156 assert(inc_allocator.bytesLeft() == total_bytes);
157}
158
std/index.zig+2
...@@ -15,6 +15,7 @@ pub const elf = @import("elf.zig");...@@ -15,6 +15,7 @@ pub const elf = @import("elf.zig");
15pub const empty_import = @import("empty.zig");15pub const empty_import = @import("empty.zig");
16pub const endian = @import("endian.zig");16pub const endian = @import("endian.zig");
17pub const fmt = @import("fmt/index.zig");17pub const fmt = @import("fmt/index.zig");
18pub const heap = @import("heap.zig");
18pub const io = @import("io.zig");19pub const io = @import("io.zig");
19pub const math = @import("math/index.zig");20pub const math = @import("math/index.zig");
20pub const mem = @import("mem.zig");21pub const mem = @import("mem.zig");
...@@ -45,6 +46,7 @@ test "std" {...@@ -45,6 +46,7 @@ test "std" {
45 _ = @import("io.zig");46 _ = @import("io.zig");
46 _ = @import("math/index.zig");47 _ = @import("math/index.zig");
47 _ = @import("mem.zig");48 _ = @import("mem.zig");
49 _ = @import("heap.zig");
48 _ = @import("net.zig");50 _ = @import("net.zig");
49 _ = @import("os/index.zig");51 _ = @import("os/index.zig");
50 _ = @import("rand.zig");52 _ = @import("rand.zig");
std/io.zig+278-352
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const std = @import("index.zig");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const Os = builtin.Os;3const Os = builtin.Os;
3const system = switch(builtin.os) {4const system = switch(builtin.os) {
...@@ -6,41 +7,19 @@ const system = switch(builtin.os) {...@@ -6,41 +7,19 @@ const system = switch(builtin.os) {
6 Os.windows => @import("os/windows/index.zig"),7 Os.windows => @import("os/windows/index.zig"),
7 else => @compileError("Unsupported OS"),8 else => @compileError("Unsupported OS"),
8};9};
9const c = @import("c/index.zig");10const c = std.c;
1011
11const math = @import("math/index.zig");12const math = std.math;
12const debug = @import("debug.zig");13const debug = std.debug;
13const assert = debug.assert;14const assert = debug.assert;
14const os = @import("os/index.zig");15const os = std.os;
15const mem = @import("mem.zig");16const mem = std.mem;
16const Buffer = @import("buffer.zig").Buffer;17const Buffer = std.Buffer;
17const fmt = @import("fmt/index.zig");18const fmt = std.fmt;
1819
19const is_posix = builtin.os != builtin.Os.windows;20const is_posix = builtin.os != builtin.Os.windows;
20const is_windows = builtin.os == builtin.Os.windows;21const is_windows = builtin.os == builtin.Os.windows;
2122
22pub var stdin = InStream {
23 .fd = if (is_posix) system.STDIN_FILENO else {},
24 .handle_id = if (is_windows) system.STD_INPUT_HANDLE else {},
25 .handle = if (is_windows) null else {},
26};
27
28pub var stdout = OutStream {
29 .fd = if (is_posix) system.STDOUT_FILENO else {},
30 .handle_id = if (is_windows) system.STD_OUTPUT_HANDLE else {},
31 .handle = if (is_windows) null else {},
32 .buffer = undefined,
33 .index = 0,
34};
35
36pub var stderr = OutStream {
37 .fd = if (is_posix) system.STDERR_FILENO else {},
38 .handle_id = if (is_windows) system.STD_ERROR_HANDLE else {},
39 .handle = if (is_windows) null else {},
40 .buffer = undefined,
41 .index = 0,
42};
43
44/// The function received invalid input at runtime. An Invalid error means a23/// The function received invalid input at runtime. An Invalid error means a
45/// bug in the program that called the function.24/// bug in the program that called the function.
46error Invalid;25error Invalid;
...@@ -63,306 +42,125 @@ error PathNotFound;...@@ -63,306 +42,125 @@ error PathNotFound;
63error OutOfMemory;42error OutOfMemory;
64error Unseekable;43error Unseekable;
65error EndOfFile;44error EndOfFile;
66error NoStdHandles;
67
68pub const OutStream = struct {
69 fd: if (is_posix) i32 else void,
70 handle_id: if (is_windows) system.DWORD else void,
71 handle: if (is_windows) ?system.HANDLE else void,
72 buffer: [os.page_size]u8,
73 index: usize,
74
75 /// Calls ::openMode with 0o666 for the mode.
76 pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %OutStream {
77 return openMode(path, 0o666, allocator);
7845
79 }46pub fn getStdErr() -> %File {
8047 const handle = if (is_windows) {
81 /// `path` may need to be copied in memory to add a null terminating byte. In this case48 %return os.windowsGetStdHandle(system.STD_ERROR_HANDLE)
82 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed49 } else if (is_posix) {
83 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.50 system.STDERR_FILENO
84 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.51 } else {
85 /// Call close to clean up.52 unreachable
86 pub fn openMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) -> %OutStream {
87 if (is_posix) {
88 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
89 const fd = %return os.posixOpen(path, flags, mode, allocator);
90 return OutStream {
91 .fd = fd,
92 .handle = {},
93 .handle_id = {},
94 .index = 0,
95 .buffer = undefined,
96 };
97 } else if (is_windows) {
98 const handle = %return os.windowsOpen(path, system.GENERIC_WRITE,
99 system.FILE_SHARE_WRITE|system.FILE_SHARE_READ|system.FILE_SHARE_DELETE,
100 system.CREATE_ALWAYS, system.FILE_ATTRIBUTE_NORMAL, allocator);
101 return OutStream {
102 .fd = {},
103 .handle = handle,
104 .handle_id = undefined,
105 .index = 0,
106 .buffer = undefined,
107 };
108
109 } else {
110 unreachable;
111 }
112
113 }
114
115 pub fn writeByte(self: &OutStream, b: u8) -> %void {
116 if (self.buffer.len == self.index) %return self.flush();
117 self.buffer[self.index] = b;
118 self.index += 1;
119 }
120
121 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
122 if (bytes.len >= self.buffer.len) {
123 %return self.flush();
124 return self.unbufferedWrite(bytes);
125 }
126
127 var src_index: usize = 0;
128
129 while (src_index < bytes.len) {
130 const dest_space_left = self.buffer.len - self.index;
131 const copy_amt = math.min(dest_space_left, bytes.len - src_index);
132 mem.copy(u8, self.buffer[self.index..], bytes[src_index..src_index + copy_amt]);
133 self.index += copy_amt;
134 assert(self.index <= self.buffer.len);
135 if (self.index == self.buffer.len) {
136 %return self.flush();
137 }
138 src_index += copy_amt;
139 }
140 }
141
142 /// Calls print and then flushes the buffer.
143 pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
144 %return self.print(format, args);
145 %return self.flush();
146 }
147
148 /// Does not flush the buffer.
149 pub fn print(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
150 var context = PrintContext {
151 .self = self,
152 .result = {},
153 };
154 _ = fmt.format(&context, printOutput, format, args);
155 return context.result;
156 }
157 const PrintContext = struct {
158 self: &OutStream,
159 result: %void,
160 };53 };
161 fn printOutput(context: &PrintContext, bytes: []const u8) -> bool {54 return File.openHandle(handle);
162 context.self.write(bytes) %% |err| {55}
163 context.result = err;
164 return false;
165 };
166 return true;
167 }
168
169 pub fn flush(self: &OutStream) -> %void {
170 if (self.index == 0)
171 return;
172
173 %return self.unbufferedWrite(self.buffer[0..self.index]);
174 self.index = 0;
175 }
176
177 pub fn close(self: &OutStream) {
178 assert(self.index == 0); // unflushed buffer
179 if (is_posix) {
180 os.posixClose(self.fd);
181 } else if (is_windows) {
182 os.windowsClose(%%self.getHandle());
183 } else {
184 unreachable;
185 }
186 }
18756
188 pub fn isTty(self: &OutStream) -> %bool {57pub fn getStdOut() -> %File {
189 if (is_posix) {58 const handle = if (is_windows) {
190 if (builtin.link_libc) {59 %return os.windowsGetStdHandle(system.STD_OUTPUT_HANDLE)
191 return c.isatty(self.fd) != 0;60 } else if (is_posix) {
192 } else {61 system.STDOUT_FILENO
193 return system.isatty(self.fd);62 } else {
194 }63 unreachable
195 } else if (is_windows) {64 };
196 return os.windowsIsTty(%return self.getHandle());65 return File.openHandle(handle);
197 } else {66}
198 unreachable;
199 }
200 }
20167
202 fn getHandle(self: &OutStream) -> %system.HANDLE {68pub fn getStdIn() -> %File {
203 if (self.handle) |handle| return handle;69 const handle = if (is_windows) {
204 if (system.GetStdHandle(self.handle_id)) |handle| {70 %return os.windowsGetStdHandle(system.STD_INPUT_HANDLE)
205 if (handle == system.INVALID_HANDLE_VALUE) {71 } else if (is_posix) {
206 const err = system.GetLastError();72 system.STDIN_FILENO
207 return switch (err) {73 } else {
208 else => os.unexpectedErrorWindows(err),74 unreachable
209 };75 };
210 }76 return File.openHandle(handle);
211 self.handle = handle;77}
212 return handle;
213 } else {
214 return error.NoStdHandles;
215 }
216 }
21778
218 fn unbufferedWrite(self: &OutStream, bytes: []const u8) -> %void {79pub const File = struct {
219 if (is_posix) {80 /// The OS-specific file descriptor or file handle.
220 %return os.posixWrite(self.fd, bytes);81 handle: os.FileHandle,
221 } else if (is_windows) {
222 const handle = %return self.getHandle();
223 %return os.windowsWrite(handle, bytes);
224 } else {
225 @compileError("Unsupported OS");
226 }
227 }
22882
229};83 /// A file has the `InStream` trait
84 in_stream: InStream,
23085
231// TODO created a BufferedInStream struct and move some of this code there86 /// A file has the `OutStream` trait
232// BufferedInStream API goes on top of minimal InStream API.87 out_stream: OutStream,
233pub const InStream = struct {
234 fd: if (is_posix) i32 else void,
235 handle_id: if (is_windows) system.DWORD else void,
236 handle: if (is_windows) ?system.HANDLE else void,
23788
238 /// `path` may need to be copied in memory to add a null terminating byte. In this case89 /// `path` may need to be copied in memory to add a null terminating byte. In this case
239 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed90 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
240 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.91 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
241 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.92 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
242 /// Call close to clean up.93 /// Call close to clean up.
243 pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %InStream {94 pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) -> %File {
244 if (is_posix) {95 if (is_posix) {
245 const flags = system.O_LARGEFILE|system.O_RDONLY;96 const flags = system.O_LARGEFILE|system.O_RDONLY;
246 const fd = %return os.posixOpen(path, flags, 0, allocator);97 const fd = %return os.posixOpen(path, flags, 0, allocator);
247 return InStream {98 return openHandle(fd);
248 .fd = fd,
249 .handle_id = {},
250 .handle = {},
251 };
252 } else if (is_windows) {99 } else if (is_windows) {
253 const handle = %return os.windowsOpen(path, system.GENERIC_READ, system.FILE_SHARE_READ,100 const handle = %return os.windowsOpen(path, system.GENERIC_READ, system.FILE_SHARE_READ,
254 system.OPEN_EXISTING, system.FILE_ATTRIBUTE_NORMAL, allocator);101 system.OPEN_EXISTING, system.FILE_ATTRIBUTE_NORMAL, allocator);
255 return InStream {102 return openHandle(handle);
256 .fd = {},
257 .handle_id = undefined,
258 .handle = handle,
259 };
260 } else {103 } else {
261 unreachable;104 unreachable;
262 }105 }
263 }106 }
264107
265 /// Upon success, the stream is in an uninitialized state. To continue using it,108 /// Calls `openWriteMode` with 0o666 for the mode.
266 /// you must use the open() function.109 pub fn openWrite(path: []const u8, allocator: ?&mem.Allocator) -> %File {
267 pub fn close(self: &InStream) {110 return openWriteMode(path, 0o666, allocator);
268 if (is_posix) {111
269 os.posixClose(self.fd);
270 } else if (is_windows) {
271 os.windowsClose(%%self.getHandle());
272 } else {
273 unreachable;
274 }
275 }112 }
276113
277 /// Returns the number of bytes read. If the number read is smaller than buf.len, then114 /// `path` may need to be copied in memory to add a null terminating byte. In this case
278 /// the stream reached End Of File.115 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
279 pub fn read(self: &InStream, buf: []u8) -> %usize {116 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
117 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
118 /// Call close to clean up.
119 pub fn openWriteMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) -> %File {
280 if (is_posix) {120 if (is_posix) {
281 var index: usize = 0;121 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
282 while (index < buf.len) {122 const fd = %return os.posixOpen(path, flags, mode, allocator);
283 const amt_read = system.read(self.fd, &buf[index], buf.len - index);123 return openHandle(fd);
284 const read_err = system.getErrno(amt_read);
285 if (read_err > 0) {
286 switch (read_err) {
287 system.EINTR => continue,
288 system.EINVAL => unreachable,
289 system.EFAULT => unreachable,
290 system.EBADF => return error.BadFd,
291 system.EIO => return error.Io,
292 else => return os.unexpectedErrorPosix(read_err),
293 }
294 }
295 if (amt_read == 0) return index;
296 index += amt_read;
297 }
298 return index;
299 } else if (is_windows) {124 } else if (is_windows) {
300 const handle = %return self.getHandle();125 const handle = %return os.windowsOpen(path, system.GENERIC_WRITE,
301 var index: usize = 0;126 system.FILE_SHARE_WRITE|system.FILE_SHARE_READ|system.FILE_SHARE_DELETE,
302 while (index < buf.len) {127 system.CREATE_ALWAYS, system.FILE_ATTRIBUTE_NORMAL, allocator);
303 const want_read_count = system.DWORD(math.min(system.DWORD(@maxValue(system.DWORD)), buf.len - index));128 return openHandle(handle);
304 var amt_read: system.DWORD = undefined;
305 if (system.ReadFile(handle, @ptrCast(&c_void, &buf[index]), want_read_count, &amt_read, null) == 0) {
306 const err = system.GetLastError();
307 return switch (err) {
308 system.ERROR.OPERATION_ABORTED => continue,
309 system.ERROR.BROKEN_PIPE => return index,
310 else => os.unexpectedErrorWindows(err),
311 };
312 }
313 if (amt_read == 0) return index;
314 index += amt_read;
315 }
316 return index;
317 } else {129 } else {
318 unreachable;130 unreachable;
319 }131 }
320 }
321132
322 pub fn readNoEof(is: &InStream, buf: []u8) -> %void {
323 const amt_read = %return is.read(buf);
324 if (amt_read < buf.len) return error.EndOfFile;
325 }133 }
326134
327 pub fn readByte(is: &InStream) -> %u8 {135 pub fn openHandle(handle: os.FileHandle) -> File {
328 var result: [1]u8 = undefined;136 return File {
329 %return is.readNoEof(result[0..]);137 .handle = handle,
330 return result[0];138 .out_stream = OutStream {
331 }139 .writeFn = writeFn,
332140 },
333 pub fn readByteSigned(is: &InStream) -> %i8 {141 .in_stream = InStream {
334 var result: [1]i8 = undefined;142 .readFn = readFn,
335 %return is.readNoEof(([]u8)(result[0..]));143 },
336 return result[0];144 };
337 }
338
339 pub fn readIntLe(is: &InStream, comptime T: type) -> %T {
340 is.readInt(false, T)
341 }145 }
342146
343 pub fn readIntBe(is: &InStream, comptime T: type) -> %T {
344 is.readInt(true, T)
345 }
346147
347 pub fn readInt(is: &InStream, is_be: bool, comptime T: type) -> %T {148 /// Upon success, the stream is in an uninitialized state. To continue using it,
348 var bytes: [@sizeOf(T)]u8 = undefined;149 /// you must use the open() function.
349 %return is.readNoEof(bytes[0..]);150 pub fn close(self: &File) {
350 return mem.readInt(bytes, T, is_be);151 os.close(self.handle);
152 self.handle = undefined;
351 }153 }
352154
353 pub fn readVarInt(is: &InStream, is_be: bool, comptime T: type, size: usize) -> %T {155 /// Calls `os.isTty` on `self.handle`.
354 assert(size <= @sizeOf(T));156 pub fn isTty(self: &File) -> bool {
355 assert(size <= 8);157 return os.isTty(self.handle);
356 var input_buf: [8]u8 = undefined;
357 const input_slice = input_buf[0..size];
358 %return is.readNoEof(input_slice);
359 return mem.readInt(input_slice, T, is_be);
360 }158 }
361159
362 pub fn seekForward(is: &InStream, amount: isize) -> %void {160 pub fn seekForward(self: &File, amount: isize) -> %void {
363 switch (builtin.os) {161 switch (builtin.os) {
364 Os.linux, Os.darwin => {162 Os.linux, Os.darwin => {
365 const result = system.lseek(is.fd, amount, system.SEEK_CUR);163 const result = system.lseek(self.handle, amount, system.SEEK_CUR);
366 const err = system.getErrno(result);164 const err = system.getErrno(result);
367 if (err > 0) {165 if (err > 0) {
368 return switch (err) {166 return switch (err) {
...@@ -379,10 +177,10 @@ pub const InStream = struct {...@@ -379,10 +177,10 @@ pub const InStream = struct {
379 }177 }
380 }178 }
381179
382 pub fn seekTo(is: &InStream, pos: usize) -> %void {180 pub fn seekTo(self: &File, pos: usize) -> %void {
383 switch (builtin.os) {181 switch (builtin.os) {
384 Os.linux, Os.darwin => {182 Os.linux, Os.darwin => {
385 const result = system.lseek(is.fd, @bitCast(isize, pos), system.SEEK_SET);183 const result = system.lseek(self.handle, @bitCast(isize, pos), system.SEEK_SET);
386 const err = system.getErrno(result);184 const err = system.getErrno(result);
387 if (err > 0) {185 if (err > 0) {
388 return switch (err) {186 return switch (err) {
...@@ -399,10 +197,10 @@ pub const InStream = struct {...@@ -399,10 +197,10 @@ pub const InStream = struct {
399 }197 }
400 }198 }
401199
402 pub fn getPos(is: &InStream) -> %usize {200 pub fn getPos(self: &File) -> %usize {
403 switch (builtin.os) {201 switch (builtin.os) {
404 Os.linux, Os.darwin => {202 Os.linux, Os.darwin => {
405 const result = system.lseek(is.fd, 0, system.SEEK_CUR);203 const result = system.lseek(self.handle, 0, system.SEEK_CUR);
406 const err = system.getErrno(result);204 const err = system.getErrno(result);
407 if (err > 0) {205 if (err > 0) {
408 return switch (err) {206 return switch (err) {
...@@ -420,9 +218,9 @@ pub const InStream = struct {...@@ -420,9 +218,9 @@ pub const InStream = struct {
420 }218 }
421 }219 }
422220
423 pub fn getEndPos(is: &InStream) -> %usize {221 pub fn getEndPos(self: &File) -> %usize {
424 var stat: system.Stat = undefined;222 var stat: system.Stat = undefined;
425 const err = system.getErrno(system.fstat(is.fd, &stat));223 const err = system.getErrno(system.fstat(self.handle, &stat));
426 if (err > 0) {224 if (err > 0) {
427 return switch (err) {225 return switch (err) {
428 system.EBADF => error.BadFd,226 system.EBADF => error.BadFd,
...@@ -434,89 +232,217 @@ pub const InStream = struct {...@@ -434,89 +232,217 @@ pub const InStream = struct {
434 return usize(stat.size);232 return usize(stat.size);
435 }233 }
436234
437 pub fn readAll(is: &InStream, buf: &Buffer) -> %void {235 fn readFn(in_stream: &InStream, buffer: []u8) -> %usize {
438 %return buf.resize(os.page_size);236 const self = @fieldParentPtr(File, "in_stream", in_stream);
237 if (is_posix) {
238 var index: usize = 0;
239 while (index < buffer.len) {
240 const amt_read = system.read(self.handle, &buffer[index], buffer.len - index);
241 const read_err = system.getErrno(amt_read);
242 if (read_err > 0) {
243 switch (read_err) {
244 system.EINTR => continue,
245 system.EINVAL => unreachable,
246 system.EFAULT => unreachable,
247 system.EBADF => return error.BadFd,
248 system.EIO => return error.Io,
249 else => return os.unexpectedErrorPosix(read_err),
250 }
251 }
252 if (amt_read == 0) return index;
253 index += amt_read;
254 }
255 return index;
256 } else if (is_windows) {
257 var index: usize = 0;
258 while (index < buffer.len) {
259 const want_read_count = system.DWORD(math.min(system.DWORD(@maxValue(system.DWORD)), buffer.len - index));
260 var amt_read: system.DWORD = undefined;
261 if (system.ReadFile(self.handle, @ptrCast(&c_void, &buffer[index]), want_read_count, &amt_read, null) == 0) {
262 const err = system.GetLastError();
263 return switch (err) {
264 system.ERROR.OPERATION_ABORTED => continue,
265 system.ERROR.BROKEN_PIPE => return index,
266 else => os.unexpectedErrorWindows(err),
267 };
268 }
269 if (amt_read == 0) return index;
270 index += amt_read;
271 }
272 return index;
273 } else {
274 unreachable;
275 }
276 }
277
278 fn writeFn(out_stream: &OutStream, bytes: []const u8) -> %void {
279 const self = @fieldParentPtr(File, "out_stream", out_stream);
280 if (is_posix) {
281 %return os.posixWrite(self.handle, bytes);
282 } else if (is_windows) {
283 %return os.windowsWrite(self.handle, bytes);
284 } else {
285 @compileError("Unsupported OS");
286 }
287 }
288
289};
290
291/// `path` may need to be copied in memory to add a null terminating byte. In this case
292/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed
293/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.
294/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
295pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) -> %void {
296 var file = %return File.openWrite(path, allocator);
297 defer file.close();
298 %return file.out_stream.write(data);
299}
300
301error StreamTooLong;
302error EndOfStream;
303
304pub const InStream = struct {
305 /// Return the number of bytes read. If the number read is smaller than buf.len, it
306 /// means the stream reached the end. Reaching the end of a stream is not an error
307 /// condition.
308 readFn: fn(self: &InStream, buffer: []u8) -> %usize,
309
310 /// Replaces `buffer` contents by reading from the stream until it is finished.
311 /// If `buffer.len()` woould exceed `max_size`, `error.StreamTooLong` is returned and
312 /// the contents read from the stream are lost.
313 pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) -> %void {
314 %return buffer.resize(0);
439315
440 var actual_buf_len: usize = 0;316 var actual_buf_len: usize = 0;
441 while (true) {317 while (true) {
442 const dest_slice = buf.toSlice()[actual_buf_len..];318 const dest_slice = buffer.toSlice()[actual_buf_len..];
443 const bytes_read = %return is.read(dest_slice);319 const bytes_read = %return self.readFn(self, dest_slice);
444 actual_buf_len += bytes_read;320 actual_buf_len += bytes_read;
445321
446 if (bytes_read != dest_slice.len) {322 if (bytes_read != dest_slice.len) {
447 return buf.resize(actual_buf_len);323 buffer.shrink(actual_buf_len);
324 return;
448 }325 }
449326
450 %return buf.resize(actual_buf_len + os.page_size);327 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
328 if (new_buf_size == actual_buf_len)
329 return error.StreamTooLong;
330 %return buffer.resize(new_buf_size);
451 }331 }
452 }332 }
453333
454 pub fn readLine(is: &InStream, buf: &Buffer) -> %void {334 /// Allocates enough memory to hold all the contents of the stream. If the allocated
335 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
336 /// Caller owns returned memory.
337 /// If this function returns an error, the contents from the stream read so far are lost.
338 pub fn readAllAlloc(self: &InStream, allocator: &mem.Allocator, max_size: usize) -> %[]u8 {
339 var buf = Buffer.initNull(allocator);
340 defer buf.deinit();
341
342 %return self.readAllBuffer(self, &buf, max_size);
343 return buf.toOwnedSlice();
344 }
345
346 /// Replaces `buffer` contents by reading from the stream until `delimiter` is found.
347 /// Does not include the delimiter in the result.
348 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
349 /// read from the stream so far are lost.
350 pub fn readUntilDelimiterBuffer(self: &InStream, buffer: &Buffer, delimiter: u8, max_size: usize) -> %void {
455 %return buf.resize(0);351 %return buf.resize(0);
456352
457 while (true) {353 while (true) {
458 var byte: u8 = %return is.readByte();354 var byte: u8 = %return self.readByte();
459 %return buf.appendByte(byte);
460355
461 if (buf.endsWith(os.line_sep)) {356 if (byte == delimiter) {
462 break;357 return;
463 }358 }
464 }
465 }
466359
467 pub fn isTty(self: &InStream) -> %bool {360 if (buf.len() == max_size) {
468 if (is_posix) {361 return error.StreamTooLong;
469 if (builtin.link_libc) {
470 return c.isatty(self.fd) != 0;
471 } else {
472 return system.isatty(self.fd);
473 }362 }
474 } else if (is_windows) {363
475 return os.windowsIsTty(%return self.getHandle());364 %return buf.appendByte(byte);
476 } else {
477 @compileError("Unsupported OS");
478 }365 }
479 }366 }
480367
481 fn getHandle(self: &InStream) -> %system.HANDLE {368 /// Allocates enough memory to read until `delimiter`. If the allocated
482 if (self.handle) |handle| return handle;369 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
483 if (system.GetStdHandle(self.handle_id)) |handle| {370 /// Caller owns returned memory.
484 if (handle == system.INVALID_HANDLE_VALUE) {371 /// If this function returns an error, the contents from the stream read so far are lost.
485 const err = system.GetLastError();372 pub fn readUntilDelimiterAlloc(self: &InStream, allocator: &mem.Allocator,
486 return switch (err) {373 delimiter: u8, max_size: usize) -> %[]u8
487 else => os.unexpectedErrorWindows(err),374 {
488 };375 var buf = Buffer.initNull(allocator);
489 }376 defer buf.deinit();
490 self.handle = handle;377
491 return handle;378 %return self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);
492 } else {379 return buf.toOwnedSlice();
493 return error.NoStdHandles;380 }
494 }381
382 /// Returns the number of bytes read. If the number read is smaller than buf.len, it
383 /// means the stream reached the end. Reaching the end of a stream is not an error
384 /// condition.
385 pub fn read(self: &InStream, buffer: []u8) -> %usize {
386 return self.readFn(self, buffer);
387 }
388
389 /// Same as `read` but end of stream returns `error.EndOfStream`.
390 pub fn readNoEof(self: &InStream, buf: []u8) -> %void {
391 const amt_read = %return self.read(buf);
392 if (amt_read < buf.len) return error.EndOfStream;
393 }
394
395 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
396 pub fn readByte(self: &InStream) -> %u8 {
397 var result: [1]u8 = undefined;
398 %return self.readNoEof(result[0..]);
399 return result[0];
495 }400 }
401
402 /// Same as `readByte` except the returned byte is signed.
403 pub fn readByteSigned(self: &InStream) -> %i8 {
404 return @bitCast(i8, %return self.readByte());
405 }
406
407 pub fn readIntLe(self: &InStream, comptime T: type) -> %T {
408 return self.readInt(false, T);
409 }
410
411 pub fn readIntBe(self: &InStream, comptime T: type) -> %T {
412 return self.readInt(true, T);
413 }
414
415 pub fn readInt(self: &InStream, is_be: bool, comptime T: type) -> %T {
416 var bytes: [@sizeOf(T)]u8 = undefined;
417 %return self.readNoEof(bytes[0..]);
418 return mem.readInt(bytes, T, is_be);
419 }
420
421 pub fn readVarInt(self: &InStream, is_be: bool, comptime T: type, size: usize) -> %T {
422 assert(size <= @sizeOf(T));
423 assert(size <= 8);
424 var input_buf: [8]u8 = undefined;
425 const input_slice = input_buf[0..size];
426 %return self.readNoEof(input_slice);
427 return mem.readInt(input_slice, T, is_be);
428 }
429
430
496};431};
497432
498pub fn openSelfExe() -> %InStream {433pub const OutStream = struct {
499 switch (builtin.os) {434 writeFn: fn(self: &OutStream, bytes: []const u8) -> %void,
500 Os.linux => {435
501 return InStream.open("/proc/self/exe", null);436 pub fn print(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
502 },437 return std.fmt.format(self, self.writeFn, format, args);
503 Os.darwin => {
504 debug.panic("TODO: openSelfExe on Darwin");
505 },
506 else => @compileError("Unsupported OS"),
507 }438 }
508}
509439
510/// `path` may need to be copied in memory to add a null terminating byte. In this case440 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
511/// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed441 return self.writeFn(self, bytes);
512/// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.442 }
513/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.443
514pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) -> %void {444 pub fn writeByte(self: &OutStream, byte: u8) -> %void {
515 // TODO have an unbuffered File abstraction and use that here.445 const slice = (&byte)[0..1];
516 // Then a buffered out stream abstraction can go on top of that for446 return self.writeFn(self, slice);
517 // use cases like stdout and stderr.447 }
518 var out_stream = %return OutStream.open(path, allocator);448};
519 defer out_stream.close();
520 %return out_stream.write(data);
521 %return out_stream.flush();
522}
std/mem.zig-152
...@@ -1,16 +1,9 @@...@@ -1,16 +1,9 @@
1const debug = @import("debug.zig");1const debug = @import("debug.zig");
2const assert = debug.assert;2const assert = debug.assert;
3const math = @import("math/index.zig");3const math = @import("math/index.zig");
4const os = @import("os/index.zig");
5const io = @import("io.zig");
6const builtin = @import("builtin");
7const Os = builtin.Os;
8const c = @import("c/index.zig");
94
10pub const Cmp = math.Cmp;5pub const Cmp = math.Cmp;
116
12error OutOfMemory;
13
14pub const Allocator = struct {7pub const Allocator = struct {
15 /// Allocate byte_count bytes and return them in a slice, with the8 /// Allocate byte_count bytes and return them in a slice, with the
16 /// slicer's pointer aligned at least to alignment bytes.9 /// slicer's pointer aligned at least to alignment bytes.
...@@ -85,151 +78,6 @@ pub const Allocator = struct {...@@ -85,151 +78,6 @@ pub const Allocator = struct {
85 }78 }
86};79};
8780
88pub var c_allocator = Allocator {
89 .allocFn = cAlloc,
90 .reallocFn = cRealloc,
91 .freeFn = cFree,
92};
93
94fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
95 if (c.malloc(usize(n))) |mem| {
96 @ptrCast(&u8, mem)[0..n]
97 } else {
98 error.OutOfMemory
99 }
100}
101
102fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
103 if (new_size <= old_mem.len) {
104 old_mem[0..new_size]
105 } else {
106 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
107 if (c.realloc(old_ptr, usize(new_size))) |mem| {
108 @ptrCast(&u8, mem)[0..new_size]
109 } else {
110 error.OutOfMemory
111 }
112 }
113}
114
115fn cFree(self: &Allocator, old_mem: []u8) {
116 const old_ptr = @ptrCast(&c_void, old_mem.ptr);
117 c.free(old_ptr);
118}
119
120pub const IncrementingAllocator = struct {
121 allocator: Allocator,
122 bytes: []u8,
123 end_index: usize,
124 heap_handle: if (builtin.os == Os.windows) os.windows.HANDLE else void,
125
126 fn init(capacity: usize) -> %IncrementingAllocator {
127 switch (builtin.os) {
128 Os.linux, Os.darwin, Os.macosx, Os.ios => {
129 const p = os.posix;
130 const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE,
131 p.MAP_PRIVATE|p.MAP_ANONYMOUS|p.MAP_NORESERVE, -1, 0);
132 if (addr == p.MAP_FAILED) {
133 return error.OutOfMemory;
134 }
135 return IncrementingAllocator {
136 .allocator = Allocator {
137 .allocFn = alloc,
138 .reallocFn = realloc,
139 .freeFn = free,
140 },
141 .bytes = @intToPtr(&u8, addr)[0..capacity],
142 .end_index = 0,
143 .heap_handle = {},
144 };
145 },
146 Os.windows => {
147 const heap_handle = os.windows.GetProcessHeap() ?? return error.OutOfMemory;
148 const ptr = os.windows.HeapAlloc(heap_handle, 0, capacity) ?? return error.OutOfMemory;
149 return IncrementingAllocator {
150 .allocator = Allocator {
151 .allocFn = alloc,
152 .reallocFn = realloc,
153 .freeFn = free,
154 },
155 .bytes = @ptrCast(&u8, ptr)[0..capacity],
156 .end_index = 0,
157 .heap_handle = heap_handle,
158 };
159 },
160 else => @compileError("Unsupported OS"),
161 }
162 }
163
164 fn deinit(self: &IncrementingAllocator) {
165 switch (builtin.os) {
166 Os.linux, Os.darwin, Os.macosx, Os.ios => {
167 _ = os.posix.munmap(self.bytes.ptr, self.bytes.len);
168 },
169 Os.windows => {
170 _ = os.windows.HeapFree(self.heap_handle, 0, @ptrCast(os.windows.LPVOID, self.bytes.ptr));
171 },
172 else => @compileError("Unsupported OS"),
173 }
174 }
175
176 fn reset(self: &IncrementingAllocator) {
177 self.end_index = 0;
178 }
179
180 fn bytesLeft(self: &const IncrementingAllocator) -> usize {
181 return self.bytes.len - self.end_index;
182 }
183
184 fn alloc(allocator: &Allocator, n: usize, alignment: usize) -> %[]u8 {
185 const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
186 const addr = @ptrToInt(&self.bytes[self.end_index]);
187 const rem = @rem(addr, alignment);
188 const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
189 const adjusted_index = self.end_index + march_forward_bytes;
190 const new_end_index = adjusted_index + n;
191 if (new_end_index > self.bytes.len) {
192 return error.OutOfMemory;
193 }
194 const result = self.bytes[adjusted_index .. new_end_index];
195 self.end_index = new_end_index;
196 return result;
197 }
198
199 fn realloc(allocator: &Allocator, old_mem: []u8, new_size: usize, alignment: usize) -> %[]u8 {
200 if (new_size <= old_mem.len) {
201 return old_mem[0..new_size];
202 } else {
203 const result = %return alloc(allocator, new_size, alignment);
204 copy(u8, result, old_mem);
205 return result;
206 }
207 }
208
209 fn free(allocator: &Allocator, bytes: []u8) {
210 // Do nothing. That's the point of an incrementing allocator.
211 }
212};
213
214test "mem.IncrementingAllocator" {
215 const total_bytes = 100 * 1024 * 1024;
216 var inc_allocator = %%IncrementingAllocator.init(total_bytes);
217 defer inc_allocator.deinit();
218
219 const allocator = &inc_allocator.allocator;
220 const slice = %%allocator.alloc(&i32, 100);
221
222 for (slice) |*item, i| {
223 *item = %%allocator.create(i32);
224 **item = i32(i);
225 }
226
227 assert(inc_allocator.bytesLeft() == total_bytes - @sizeOf(i32) * 100 - @sizeOf(usize) * 100);
228
229 inc_allocator.reset();
230
231 assert(inc_allocator.bytesLeft() == total_bytes);
232}
23381
234/// Copy all of source into dest at position 0.82/// Copy all of source into dest at position 0.
235/// dest.len must be >= source.len.83/// dest.len must be >= source.len.
std/os/child_process.zig+39-103
...@@ -28,9 +28,9 @@ pub const ChildProcess = struct {...@@ -28,9 +28,9 @@ pub const ChildProcess = struct {
2828
29 pub allocator: &mem.Allocator,29 pub allocator: &mem.Allocator,
3030
31 pub stdin: ?&io.OutStream,31 pub stdin: ?io.File,
32 pub stdout: ?&io.InStream,32 pub stdout: ?io.File,
33 pub stderr: ?&io.InStream,33 pub stderr: ?io.File,
3434
35 pub term: ?%Term,35 pub term: ?%Term,
3636
...@@ -250,17 +250,17 @@ pub const ChildProcess = struct {...@@ -250,17 +250,17 @@ pub const ChildProcess = struct {
250 }250 }
251251
252 fn cleanupStreams(self: &ChildProcess) {252 fn cleanupStreams(self: &ChildProcess) {
253 if (self.stdin) |stdin| { stdin.close(); self.allocator.destroy(stdin); self.stdin = null; }253 if (self.stdin) |*stdin| { stdin.close(); self.stdin = null; }
254 if (self.stdout) |stdout| { stdout.close(); self.allocator.destroy(stdout); self.stdout = null; }254 if (self.stdout) |*stdout| { stdout.close(); self.stdout = null; }
255 if (self.stderr) |stderr| { stderr.close(); self.allocator.destroy(stderr); self.stderr = null; }255 if (self.stderr) |*stderr| { stderr.close(); self.stderr = null; }
256 }256 }
257257
258 fn cleanupAfterWait(self: &ChildProcess, status: i32) -> %Term {258 fn cleanupAfterWait(self: &ChildProcess, status: i32) -> %Term {
259 children_nodes.remove(&self.llnode);259 children_nodes.remove(&self.llnode);
260260
261 defer {261 defer {
262 os.posixClose(self.err_pipe[0]);262 os.close(self.err_pipe[0]);
263 os.posixClose(self.err_pipe[1]);263 os.close(self.err_pipe[1]);
264 };264 };
265265
266 // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after266 // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after
...@@ -310,7 +310,7 @@ pub const ChildProcess = struct {...@@ -310,7 +310,7 @@ pub const ChildProcess = struct {
310 } else {310 } else {
311 undefined311 undefined
312 };312 };
313 defer { if (any_ignore) os.posixClose(dev_null_fd); };313 defer { if (any_ignore) os.close(dev_null_fd); };
314314
315 var env_map_owned: BufMap = undefined;315 var env_map_owned: BufMap = undefined;
316 var we_own_env_map: bool = undefined;316 var we_own_env_map: bool = undefined;
...@@ -329,27 +329,6 @@ pub const ChildProcess = struct {...@@ -329,27 +329,6 @@ pub const ChildProcess = struct {
329 const err_pipe = %return makePipe();329 const err_pipe = %return makePipe();
330 %defer destroyPipe(err_pipe);330 %defer destroyPipe(err_pipe);
331331
332 const stdin_ptr = if (self.stdin_behavior == StdIo.Pipe) {
333 %return self.allocator.create(io.OutStream)
334 } else {
335 null
336 };
337 %defer if (stdin_ptr) |ptr| self.allocator.destroy(ptr);
338
339 const stdout_ptr = if (self.stdout_behavior == StdIo.Pipe) {
340 %return self.allocator.create(io.InStream)
341 } else {
342 null
343 };
344 %defer if (stdout_ptr) |ptr| self.allocator.destroy(ptr);
345
346 const stderr_ptr = if (self.stderr_behavior == StdIo.Pipe) {
347 %return self.allocator.create(io.InStream)
348 } else {
349 null
350 };
351 %defer if (stderr_ptr) |ptr| self.allocator.destroy(ptr);
352
353 block_SIGCHLD();332 block_SIGCHLD();
354 const pid_result = posix.fork();333 const pid_result = posix.fork();
355 const pid_err = posix.getErrno(pid_result);334 const pid_err = posix.getErrno(pid_result);
...@@ -390,46 +369,35 @@ pub const ChildProcess = struct {...@@ -390,46 +369,35 @@ pub const ChildProcess = struct {
390369
391 // we are the parent370 // we are the parent
392 const pid = i32(pid_result);371 const pid = i32(pid_result);
393 if (stdin_ptr) |outstream| {372 if (self.stdin_behavior == StdIo.Pipe) {
394 *outstream = io.OutStream {373 self.stdin = io.File.openHandle(stdin_pipe[1]);
395 .fd = stdin_pipe[1],374 } else {
396 .handle = {},375 self.stdin = null;
397 .handle_id = {},
398 .buffer = undefined,
399 .index = 0,
400 };
401 }376 }
402 if (stdout_ptr) |instream| {377 if (self.stdout_behavior == StdIo.Pipe) {
403 *instream = io.InStream {378 self.stdout = io.File.openHandle(stdout_pipe[0]);
404 .fd = stdout_pipe[0],379 } else {
405 .handle = {},380 self.stdout = null;
406 .handle_id = {},
407 };
408 }381 }
409 if (stderr_ptr) |instream| {382 if (self.stderr_behavior == StdIo.Pipe) {
410 *instream = io.InStream {383 self.stderr = io.File.openHandle(stderr_pipe[0]);
411 .fd = stderr_pipe[0],384 } else {
412 .handle = {},385 self.stderr = null;
413 .handle_id = {},
414 };
415 }386 }
416387
417 self.pid = pid;388 self.pid = pid;
418 self.err_pipe = err_pipe;389 self.err_pipe = err_pipe;
419 self.llnode = LinkedList(&ChildProcess).Node.init(self);390 self.llnode = LinkedList(&ChildProcess).Node.init(self);
420 self.term = null;391 self.term = null;
421 self.stdin = stdin_ptr;
422 self.stdout = stdout_ptr;
423 self.stderr = stderr_ptr;
424392
425 // TODO make this atomic so it works even with threads393 // TODO make this atomic so it works even with threads
426 children_nodes.prepend(&self.llnode);394 children_nodes.prepend(&self.llnode);
427395
428 restore_SIGCHLD();396 restore_SIGCHLD();
429397
430 if (self.stdin_behavior == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); }398 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
431 if (self.stdout_behavior == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); }399 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
432 if (self.stderr_behavior == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); }400 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
433 }401 }
434402
435 fn spawnWindows(self: &ChildProcess) -> %void {403 fn spawnWindows(self: &ChildProcess) -> %void {
...@@ -509,27 +477,6 @@ pub const ChildProcess = struct {...@@ -509,27 +477,6 @@ pub const ChildProcess = struct {
509 }477 }
510 %defer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };478 %defer if (self.stdin_behavior == StdIo.Pipe) { windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr); };
511479
512 const stdin_ptr = if (self.stdin_behavior == StdIo.Pipe) {
513 %return self.allocator.create(io.OutStream)
514 } else {
515 null
516 };
517 %defer if (stdin_ptr) |ptr| self.allocator.destroy(ptr);
518
519 const stdout_ptr = if (self.stdout_behavior == StdIo.Pipe) {
520 %return self.allocator.create(io.InStream)
521 } else {
522 null
523 };
524 %defer if (stdout_ptr) |ptr| self.allocator.destroy(ptr);
525
526 const stderr_ptr = if (self.stderr_behavior == StdIo.Pipe) {
527 %return self.allocator.create(io.InStream)
528 } else {
529 null
530 };
531 %defer if (stderr_ptr) |ptr| self.allocator.destroy(ptr);
532
533 const cmd_line = %return windowsCreateCommandLine(self.allocator, self.argv);480 const cmd_line = %return windowsCreateCommandLine(self.allocator, self.argv);
534 defer self.allocator.free(cmd_line);481 defer self.allocator.free(cmd_line);
535482
...@@ -609,36 +556,25 @@ pub const ChildProcess = struct {...@@ -609,36 +556,25 @@ pub const ChildProcess = struct {
609 }556 }
610 };557 };
611558
612 if (stdin_ptr) |outstream| {559 if (self.stdin_behavior == StdIo.Pipe) {
613 *outstream = io.OutStream {560 self.stdin = io.File.openHandle(g_hChildStd_IN_Wr);
614 .fd = {},561 } else {
615 .handle = g_hChildStd_IN_Wr,562 self.stdin = null;
616 .handle_id = undefined,
617 .buffer = undefined,
618 .index = 0,
619 };
620 }563 }
621 if (stdout_ptr) |instream| {564 if (self.stdout_behavior == StdIo.Pipe) {
622 *instream = io.InStream {565 self.stdout = io.File.openHandle(g_hChildStd_OUT_Rd);
623 .fd = {},566 } else {
624 .handle = g_hChildStd_OUT_Rd,567 self.stdout = null;
625 .handle_id = undefined,
626 };
627 }568 }
628 if (stderr_ptr) |instream| {569 if (self.stderr_behavior == StdIo.Pipe) {
629 *instream = io.InStream {570 self.stderr = io.File.openHandle(g_hChildStd_ERR_Rd);
630 .fd = {},571 } else {
631 .handle = g_hChildStd_ERR_Rd,572 self.stderr = null;
632 .handle_id = undefined,
633 };
634 }573 }
635574
636 self.handle = piProcInfo.hProcess;575 self.handle = piProcInfo.hProcess;
637 self.thread_handle = piProcInfo.hThread;576 self.thread_handle = piProcInfo.hThread;
638 self.term = null;577 self.term = null;
639 self.stdin = stdin_ptr;
640 self.stdout = stdout_ptr;
641 self.stderr = stderr_ptr;
642578
643 if (self.stdin_behavior == StdIo.Pipe) { os.windowsClose(??g_hChildStd_IN_Rd); }579 if (self.stdin_behavior == StdIo.Pipe) { os.windowsClose(??g_hChildStd_IN_Rd); }
644 if (self.stderr_behavior == StdIo.Pipe) { os.windowsClose(??g_hChildStd_ERR_Wr); }580 if (self.stderr_behavior == StdIo.Pipe) { os.windowsClose(??g_hChildStd_ERR_Wr); }
...@@ -648,7 +584,7 @@ pub const ChildProcess = struct {...@@ -648,7 +584,7 @@ pub const ChildProcess = struct {
648 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {584 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {
649 switch (stdio) {585 switch (stdio) {
650 StdIo.Pipe => %return os.posixDup2(pipe_fd, std_fileno),586 StdIo.Pipe => %return os.posixDup2(pipe_fd, std_fileno),
651 StdIo.Close => os.posixClose(std_fileno),587 StdIo.Close => os.close(std_fileno),
652 StdIo.Inherit => {},588 StdIo.Inherit => {},
653 StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno),589 StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno),
654 }590 }
...@@ -771,8 +707,8 @@ fn makePipe() -> %[2]i32 {...@@ -771,8 +707,8 @@ fn makePipe() -> %[2]i32 {
771}707}
772708
773fn destroyPipe(pipe: &const [2]i32) {709fn destroyPipe(pipe: &const [2]i32) {
774 os.posixClose((*pipe)[0]);710 os.close((*pipe)[0]);
775 os.posixClose((*pipe)[1]);711 os.close((*pipe)[1]);
776}712}
777713
778// Child of fork calls this to report an error to the fork parent.714// Child of fork calls this to report an error to the fork parent.
std/os/index.zig+65-22
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const Os = builtin.Os;2const Os = builtin.Os;
3const is_windows = builtin.os == Os.windows;3const is_windows = builtin.os == Os.windows;
4const os = this;
45
5pub const windows = @import("windows/index.zig");6pub const windows = @import("windows/index.zig");
6pub const darwin = @import("darwin.zig");7pub const darwin = @import("darwin.zig");
...@@ -26,14 +27,14 @@ pub const UserInfo = @import("get_user_id.zig").UserInfo;...@@ -26,14 +27,14 @@ pub const UserInfo = @import("get_user_id.zig").UserInfo;
26pub const getUserInfo = @import("get_user_id.zig").getUserInfo;27pub const getUserInfo = @import("get_user_id.zig").getUserInfo;
2728
28const windows_util = @import("windows/util.zig");29const windows_util = @import("windows/util.zig");
29pub const windowsClose = windows_util.windowsClose;
30pub const windowsWaitSingle = windows_util.windowsWaitSingle;30pub const windowsWaitSingle = windows_util.windowsWaitSingle;
31pub const windowsWrite = windows_util.windowsWrite;31pub const windowsWrite = windows_util.windowsWrite;
32pub const windowsIsTty = windows_util.windowsIsTty;
33pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;32pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
34pub const windowsOpen = windows_util.windowsOpen;33pub const windowsOpen = windows_util.windowsOpen;
35pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;34pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
3635
36pub const FileHandle = if (is_windows) windows.HANDLE else i32;
37
37const debug = @import("../debug.zig");38const debug = @import("../debug.zig");
38const assert = debug.assert;39const assert = debug.assert;
3940
...@@ -88,7 +89,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {...@@ -88,7 +89,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
88 Os.darwin, Os.macosx, Os.ios => {89 Os.darwin, Os.macosx, Os.ios => {
89 const fd = %return posixOpen("/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC,90 const fd = %return posixOpen("/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC,
90 0, null);91 0, null);
91 defer posixClose(fd);92 defer close(fd);
9293
93 %return posixRead(fd, buf);94 %return posixRead(fd, buf);
94 },95 },
...@@ -165,14 +166,18 @@ pub coldcc fn exit(status: i32) -> noreturn {...@@ -165,14 +166,18 @@ pub coldcc fn exit(status: i32) -> noreturn {
165 }166 }
166}167}
167168
168/// Calls POSIX close, and keeps trying if it gets interrupted.169/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
169pub fn posixClose(fd: i32) {170pub fn close(handle: FileHandle) {
170 while (true) {171 if (is_windows) {
171 const err = posix.getErrno(posix.close(fd));172 windows_util.windowsClose(handle);
172 if (err == posix.EINTR) {173 } else {
173 continue;174 while (true) {
174 } else {175 const err = posix.getErrno(posix.close(handle));
175 return;176 if (err == posix.EINTR) {
177 continue;
178 } else {
179 return;
180 }
176 }181 }
177 }182 }
178}183}
...@@ -716,19 +721,18 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [...@@ -716,19 +721,18 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
716 %return getRandomBytes(rand_buf[0..]);721 %return getRandomBytes(rand_buf[0..]);
717 _ = base64.encodeWithAlphabet(tmp_path[dest_path.len..], rand_buf, b64_fs_alphabet);722 _ = base64.encodeWithAlphabet(tmp_path[dest_path.len..], rand_buf, b64_fs_alphabet);
718723
719 var out_stream = %return io.OutStream.openMode(tmp_path, mode, allocator);724 var out_file = %return io.File.openWriteMode(tmp_path, mode, allocator);
720 defer out_stream.close();725 defer out_file.close();
721 %defer _ = deleteFile(allocator, tmp_path);726 %defer _ = deleteFile(allocator, tmp_path);
722727
723 var in_stream = %return io.InStream.open(source_path, allocator);728 var in_file = %return io.File.openRead(source_path, allocator);
724 defer in_stream.close();729 defer in_file.close();
725730
726 const buf = out_stream.buffer[0..];731 var buf: [page_size]u8 = undefined;
727 while (true) {732 while (true) {
728 const amt = %return in_stream.read(buf);733 const amt = %return in_file.in_stream.read(buf[0..]);
729 out_stream.index = amt;734 %return out_file.out_stream.write(buf[0..amt]);
730 %return out_stream.flush();735 if (amt != buf.len)
731 if (amt != out_stream.buffer.len)
732 return rename(allocator, tmp_path, dest_path);736 return rename(allocator, tmp_path, dest_path);
733 }737 }
734}738}
...@@ -973,7 +977,7 @@ pub const Dir = struct {...@@ -973,7 +977,7 @@ pub const Dir = struct {
973977
974 pub fn close(self: &Dir) {978 pub fn close(self: &Dir) {
975 self.allocator.free(self.buf);979 self.allocator.free(self.buf);
976 posixClose(self.fd);980 close(self.fd);
977 }981 }
978982
979 /// Memory such as file names referenced in this returned entry becomes invalid983 /// Memory such as file names referenced in this returned entry becomes invalid
...@@ -1135,7 +1139,6 @@ test "os.sleep" {...@@ -1135,7 +1139,6 @@ test "os.sleep" {
1135 sleep(0, 1);1139 sleep(0, 1);
1136}1140}
11371141
1138
1139error ResourceLimitReached;1142error ResourceLimitReached;
1140error InvalidUserId;1143error InvalidUserId;
1141error PermissionDenied;1144error PermissionDenied;
...@@ -1184,6 +1187,21 @@ pub fn posix_setregid(rgid: u32, egid: u32) -> %void {...@@ -1184,6 +1187,21 @@ pub fn posix_setregid(rgid: u32, egid: u32) -> %void {
1184 };1187 };
1185}1188}
11861189
1190error NoStdHandles;
1191pub fn windowsGetStdHandle(handle_id: windows.DWORD) -> %windows.HANDLE {
1192 if (windows.GetStdHandle(handle_id)) |handle| {
1193 if (handle == windows.INVALID_HANDLE_VALUE) {
1194 const err = windows.GetLastError();
1195 return switch (err) {
1196 else => os.unexpectedErrorWindows(err),
1197 };
1198 }
1199 return handle;
1200 } else {
1201 return error.NoStdHandles;
1202 }
1203}
1204
1187pub const ArgIteratorPosix = struct {1205pub const ArgIteratorPosix = struct {
1188 index: usize,1206 index: usize,
1189 count: usize,1207 count: usize,
...@@ -1458,3 +1476,28 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) -> error {...@@ -1458,3 +1476,28 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) -> error {
1458 }1476 }
1459 return error.Unexpected;1477 return error.Unexpected;
1460}1478}
1479
1480pub fn openSelfExe() -> %io.File {
1481 switch (builtin.os) {
1482 Os.linux => {
1483 return io.File.openRead("/proc/self/exe", null);
1484 },
1485 Os.darwin => {
1486 @panic("TODO: openSelfExe on Darwin");
1487 },
1488 else => @compileError("Unsupported OS"),
1489 }
1490}
1491
1492pub fn isTty(handle: FileHandle) -> bool {
1493 if (is_windows) {
1494 return windows_util.windowsIsTty(handle);
1495 } else {
1496 if (builtin.link_libc) {
1497 return c.isatty(handle) != 0;
1498 } else {
1499 return posix.isatty(handle);
1500 }
1501 }
1502}
1503
std/os/path.zig+2-2
...@@ -940,7 +940,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {...@@ -940,7 +940,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
940 else => os.unexpectedErrorWindows(err),940 else => os.unexpectedErrorWindows(err),
941 };941 };
942 }942 }
943 defer os.windowsClose(h_file);943 defer os.close(h_file);
944 var buf = %return allocator.alloc(u8, 256);944 var buf = %return allocator.alloc(u8, 256);
945 %defer allocator.free(buf);945 %defer allocator.free(buf);
946 while (true) {946 while (true) {
...@@ -1009,7 +1009,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {...@@ -1009,7 +1009,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
1009 },1009 },
1010 Os.linux => {1010 Os.linux => {
1011 const fd = %return os.posixOpen(pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0, allocator);1011 const fd = %return os.posixOpen(pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0, allocator);
1012 defer os.posixClose(fd);1012 defer os.close(fd);
10131013
1014 var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;1014 var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;
1015 const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}", fd);1015 const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}", fd);
std/special/build_runner.zig+33-27
...@@ -6,6 +6,7 @@ const os = std.os;...@@ -6,6 +6,7 @@ const os = std.os;
6const Builder = std.build.Builder;6const Builder = std.build.Builder;
7const mem = std.mem;7const mem = std.mem;
8const ArrayList = std.ArrayList;8const ArrayList = std.ArrayList;
9const warn = std.debug.warn;
910
10error InvalidArgs;11error InvalidArgs;
1112
...@@ -13,7 +14,7 @@ pub fn main() -> %void {...@@ -13,7 +14,7 @@ pub fn main() -> %void {
13 var arg_it = os.args();14 var arg_it = os.args();
1415
15 // TODO use a more general purpose allocator here16 // TODO use a more general purpose allocator here
16 var inc_allocator = %%mem.IncrementingAllocator.init(20 * 1024 * 1024);17 var inc_allocator = %%std.heap.IncrementingAllocator.init(20 * 1024 * 1024);
17 defer inc_allocator.deinit();18 defer inc_allocator.deinit();
1819
19 const allocator = &inc_allocator.allocator;20 const allocator = &inc_allocator.allocator;
...@@ -23,15 +24,15 @@ pub fn main() -> %void {...@@ -23,15 +24,15 @@ pub fn main() -> %void {
23 _ = arg_it.skip();24 _ = arg_it.skip();
2425
25 const zig_exe = %return unwrapArg(arg_it.next(allocator) ?? {26 const zig_exe = %return unwrapArg(arg_it.next(allocator) ?? {
26 %%io.stderr.printf("Expected first argument to be path to zig compiler\n");27 warn("Expected first argument to be path to zig compiler\n");
27 return error.InvalidArgs;28 return error.InvalidArgs;
28 });29 });
29 const build_root = %return unwrapArg(arg_it.next(allocator) ?? {30 const build_root = %return unwrapArg(arg_it.next(allocator) ?? {
30 %%io.stderr.printf("Expected second argument to be build root directory path\n");31 warn("Expected second argument to be build root directory path\n");
31 return error.InvalidArgs;32 return error.InvalidArgs;
32 });33 });
33 const cache_root = %return unwrapArg(arg_it.next(allocator) ?? {34 const cache_root = %return unwrapArg(arg_it.next(allocator) ?? {
34 %%io.stderr.printf("Expected third argument to be cache root directory path\n");35 warn("Expected third argument to be cache root directory path\n");
35 return error.InvalidArgs;36 return error.InvalidArgs;
36 });37 });
3738
...@@ -42,32 +43,37 @@ pub fn main() -> %void {...@@ -42,32 +43,37 @@ pub fn main() -> %void {
4243
43 var prefix: ?[]const u8 = null;44 var prefix: ?[]const u8 = null;
4445
46 var stderr_file = io.getStdErr();
47 var stderr_stream: %&io.OutStream = if (stderr_file) |*f| &f.out_stream else |err| err;
48 var stdout_file = io.getStdOut();
49 var stdout_stream: %&io.OutStream = if (stdout_file) |*f| &f.out_stream else |err| err;
50
45 while (arg_it.next(allocator)) |err_or_arg| {51 while (arg_it.next(allocator)) |err_or_arg| {
46 const arg = %return unwrapArg(err_or_arg);52 const arg = %return unwrapArg(err_or_arg);
47 if (mem.startsWith(u8, arg, "-D")) {53 if (mem.startsWith(u8, arg, "-D")) {
48 const option_contents = arg[2..];54 const option_contents = arg[2..];
49 if (option_contents.len == 0) {55 if (option_contents.len == 0) {
50 %%io.stderr.printf("Expected option name after '-D'\n\n");56 warn("Expected option name after '-D'\n\n");
51 return usage(&builder, false, &io.stderr);57 return usageAndErr(&builder, false, %return stderr_stream);
52 }58 }
53 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {59 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
54 const option_name = option_contents[0..name_end];60 const option_name = option_contents[0..name_end];
55 const option_value = option_contents[name_end + 1..];61 const option_value = option_contents[name_end + 1..];
56 if (builder.addUserInputOption(option_name, option_value))62 if (builder.addUserInputOption(option_name, option_value))
57 return usage(&builder, false, &io.stderr);63 return usageAndErr(&builder, false, %return stderr_stream);
58 } else {64 } else {
59 if (builder.addUserInputFlag(option_contents))65 if (builder.addUserInputFlag(option_contents))
60 return usage(&builder, false, &io.stderr);66 return usageAndErr(&builder, false, %return stderr_stream);
61 }67 }
62 } else if (mem.startsWith(u8, arg, "-")) {68 } else if (mem.startsWith(u8, arg, "-")) {
63 if (mem.eql(u8, arg, "--verbose")) {69 if (mem.eql(u8, arg, "--verbose")) {
64 builder.verbose = true;70 builder.verbose = true;
65 } else if (mem.eql(u8, arg, "--help")) {71 } else if (mem.eql(u8, arg, "--help")) {
66 return usage(&builder, false, &io.stdout);72 return usage(&builder, false, %return stdout_stream);
67 } else if (mem.eql(u8, arg, "--prefix")) {73 } else if (mem.eql(u8, arg, "--prefix")) {
68 prefix = %return unwrapArg(arg_it.next(allocator) ?? {74 prefix = %return unwrapArg(arg_it.next(allocator) ?? {
69 %%io.stderr.printf("Expected argument after --prefix\n\n");75 warn("Expected argument after --prefix\n\n");
70 return usage(&builder, false, &io.stderr);76 return usageAndErr(&builder, false, %return stderr_stream);
71 });77 });
72 } else if (mem.eql(u8, arg, "--verbose-tokenize")) {78 } else if (mem.eql(u8, arg, "--verbose-tokenize")) {
73 builder.verbose_tokenize = true;79 builder.verbose_tokenize = true;
...@@ -82,8 +88,8 @@ pub fn main() -> %void {...@@ -82,8 +88,8 @@ pub fn main() -> %void {
82 } else if (mem.eql(u8, arg, "--verbose-cimport")) {88 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
83 builder.verbose_cimport = true;89 builder.verbose_cimport = true;
84 } else {90 } else {
85 %%io.stderr.printf("Unrecognized argument: {}\n\n", arg);91 warn("Unrecognized argument: {}\n\n", arg);
86 return usage(&builder, false, &io.stderr);92 return usageAndErr(&builder, false, %return stderr_stream);
87 }93 }
88 } else {94 } else {
89 %%targets.append(arg);95 %%targets.append(arg);
...@@ -94,11 +100,11 @@ pub fn main() -> %void {...@@ -94,11 +100,11 @@ pub fn main() -> %void {
94 root.build(&builder);100 root.build(&builder);
95101
96 if (builder.validateUserInputDidItFail())102 if (builder.validateUserInputDidItFail())
97 return usage(&builder, true, &io.stderr);103 return usageAndErr(&builder, true, %return stderr_stream);
98104
99 builder.make(targets.toSliceConst()) %% |err| {105 builder.make(targets.toSliceConst()) %% |err| {
100 if (err == error.InvalidStepName) {106 if (err == error.InvalidStepName) {
101 return usage(&builder, true, &io.stderr);107 return usageAndErr(&builder, true, %return stderr_stream);
102 }108 }
103 return err;109 return err;
104 };110 };
...@@ -112,7 +118,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -112,7 +118,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
112 }118 }
113119
114 // This usage text has to be synchronized with src/main.cpp120 // This usage text has to be synchronized with src/main.cpp
115 %%out_stream.printf(121 %return out_stream.print(
116 \\Usage: {} build [steps] [options]122 \\Usage: {} build [steps] [options]
117 \\123 \\
118 \\Steps:124 \\Steps:
...@@ -121,10 +127,10 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -121,10 +127,10 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
121127
122 const allocator = builder.allocator;128 const allocator = builder.allocator;
123 for (builder.top_level_steps.toSliceConst()) |top_level_step| {129 for (builder.top_level_steps.toSliceConst()) |top_level_step| {
124 %%out_stream.printf(" {s22} {}\n", top_level_step.step.name, top_level_step.description);130 %return out_stream.print(" {s22} {}\n", top_level_step.step.name, top_level_step.description);
125 }131 }
126132
127 %%out_stream.write(133 %return out_stream.write(
128 \\134 \\
129 \\General Options:135 \\General Options:
130 \\ --help Print this help and exit136 \\ --help Print this help and exit
...@@ -136,17 +142,17 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -136,17 +142,17 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
136 );142 );
137143
138 if (builder.available_options_list.len == 0) {144 if (builder.available_options_list.len == 0) {
139 %%out_stream.print(" (none)\n");145 %return out_stream.print(" (none)\n");
140 } else {146 } else {
141 for (builder.available_options_list.toSliceConst()) |option| {147 for (builder.available_options_list.toSliceConst()) |option| {
142 const name = %%fmt.allocPrint(allocator,148 const name = %return fmt.allocPrint(allocator,
143 " -D{}=${}", option.name, Builder.typeIdName(option.type_id));149 " -D{}=${}", option.name, Builder.typeIdName(option.type_id));
144 defer allocator.free(name);150 defer allocator.free(name);
145 %%out_stream.print("{s24} {}\n", name, option.description);151 %return out_stream.print("{s24} {}\n", name, option.description);
146 }152 }
147 }153 }
148154
149 %%out_stream.write(155 %return out_stream.write(
150 \\156 \\
151 \\Advanced Options:157 \\Advanced Options:
152 \\ --build-file $file Override path to build.zig158 \\ --build-file $file Override path to build.zig
...@@ -159,16 +165,16 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -159,16 +165,16 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
159 \\ --verbose-cimport Enable compiler debug output for C imports165 \\ --verbose-cimport Enable compiler debug output for C imports
160 \\166 \\
161 );167 );
168}
162169
163 %%out_stream.flush();170fn usageAndErr(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) -> error {
164171 usage(builder, already_ran_build, out_stream) %% {};
165 if (out_stream == &io.stderr)172 return error.InvalidArgs;
166 return error.InvalidArgs;
167}173}
168174
169fn unwrapArg(arg: %[]u8) -> %[]u8 {175fn unwrapArg(arg: %[]u8) -> %[]u8 {
170 return arg %% |err| {176 return arg %% |err| {
171 %%io.stderr.printf("Unable to parse command line: {}\n", err);177 warn("Unable to parse command line: {}\n", err);
172 return err;178 return err;
173 };179 };
174}180}
std/special/test_runner.zig+5-3
...@@ -1,13 +1,15 @@...@@ -1,13 +1,15 @@
1const io = @import("std").io;1const std = @import("std");
2const io = std.io;
2const builtin = @import("builtin");3const builtin = @import("builtin");
3const test_fn_list = builtin.__zig_test_fn_slice;4const test_fn_list = builtin.__zig_test_fn_slice;
5const warn = std.debug.warn;
46
5pub fn main() -> %void {7pub fn main() -> %void {
6 for (test_fn_list) |test_fn, i| {8 for (test_fn_list) |test_fn, i| {
7 %%io.stderr.printf("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
810
9 test_fn.func();11 test_fn.func();
1012
11 %%io.stderr.printf("OK\n");13 warn("OK\n");
12 }14 }
13}15}
test/compare_output.zig+44-31
...@@ -17,7 +17,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -17,7 +17,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
17 \\17 \\
18 \\pub fn main() -> %void {18 \\pub fn main() -> %void {
19 \\ privateFunction();19 \\ privateFunction();
20 \\ %%stdout.printf("OK 2\n");20 \\ const stdout = &(%%getStdOut()).out_stream;
21 \\ %%stdout.print("OK 2\n");
21 \\}22 \\}
22 \\23 \\
23 \\fn privateFunction() {24 \\fn privateFunction() {
...@@ -31,7 +32,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -31,7 +32,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
31 \\// purposefully conflicting function with main.zig32 \\// purposefully conflicting function with main.zig
32 \\// but it's private so it should be OK33 \\// but it's private so it should be OK
33 \\fn privateFunction() {34 \\fn privateFunction() {
34 \\ %%stdout.printf("OK 1\n");35 \\ const stdout = &(%%getStdOut()).out_stream;
36 \\ %%stdout.print("OK 1\n");
35 \\}37 \\}
36 \\38 \\
37 \\pub fn printText() {39 \\pub fn printText() {
...@@ -56,7 +58,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -56,7 +58,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
56 tc.addSourceFile("foo.zig",58 tc.addSourceFile("foo.zig",
57 \\use @import("std").io;59 \\use @import("std").io;
58 \\pub fn foo_function() {60 \\pub fn foo_function() {
59 \\ %%stdout.printf("OK\n");61 \\ const stdout = &(%%getStdOut()).out_stream;
62 \\ %%stdout.print("OK\n");
60 \\}63 \\}
61 );64 );
6265
...@@ -66,7 +69,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -66,7 +69,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
66 \\69 \\
67 \\pub fn bar_function() {70 \\pub fn bar_function() {
68 \\ if (foo_function()) {71 \\ if (foo_function()) {
69 \\ %%stdout.printf("OK\n");72 \\ const stdout = &(%%getStdOut()).out_stream;
73 \\ %%stdout.print("OK\n");
70 \\ }74 \\ }
71 \\}75 \\}
72 );76 );
...@@ -97,7 +101,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -97,7 +101,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
97 \\pub const a_text = "OK\n";101 \\pub const a_text = "OK\n";
98 \\102 \\
99 \\pub fn ok() {103 \\pub fn ok() {
100 \\ %%io.stdout.printf(b_text);104 \\ const stdout = &(%%io.getStdOut()).out_stream;
105 \\ %%stdout.print(b_text);
101 \\}106 \\}
102 );107 );
103108
...@@ -114,7 +119,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -114,7 +119,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
114 \\const io = @import("std").io;119 \\const io = @import("std").io;
115 \\120 \\
116 \\pub fn main() -> %void {121 \\pub fn main() -> %void {
117 \\ %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));122 \\ const stdout = &(%%io.getStdOut()).out_stream;
123 \\ %%stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));
118 \\}124 \\}
119 , "Hello, world!\n0012 012 a\n");125 , "Hello, world!\n0012 012 a\n");
120126
...@@ -266,7 +272,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -266,7 +272,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
266 \\ var x_local : i32 = print_ok(x);272 \\ var x_local : i32 = print_ok(x);
267 \\}273 \\}
268 \\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {274 \\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
269 \\ %%io.stdout.printf("OK\n");275 \\ const stdout = &(%%io.getStdOut()).out_stream;
276 \\ %%stdout.print("OK\n");
270 \\ return 0;277 \\ return 0;
271 \\}278 \\}
272 \\const foo : i32 = 0;279 \\const foo : i32 = 0;
...@@ -347,24 +354,26 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -347,24 +354,26 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
347 \\pub fn main() -> %void {354 \\pub fn main() -> %void {
348 \\ const bar = Bar {.field2 = 13,};355 \\ const bar = Bar {.field2 = 13,};
349 \\ const foo = Foo {.field1 = bar,};356 \\ const foo = Foo {.field1 = bar,};
357 \\ const stdout = &(%%io.getStdOut()).out_stream;
350 \\ if (!foo.method()) {358 \\ if (!foo.method()) {
351 \\ %%io.stdout.printf("BAD\n");359 \\ %%stdout.print("BAD\n");
352 \\ }360 \\ }
353 \\ if (!bar.method()) {361 \\ if (!bar.method()) {
354 \\ %%io.stdout.printf("BAD\n");362 \\ %%stdout.print("BAD\n");
355 \\ }363 \\ }
356 \\ %%io.stdout.printf("OK\n");364 \\ %%stdout.print("OK\n");
357 \\}365 \\}
358 , "OK\n");366 , "OK\n");
359367
360 cases.add("defer with only fallthrough",368 cases.add("defer with only fallthrough",
361 \\const io = @import("std").io;369 \\const io = @import("std").io;
362 \\pub fn main() -> %void {370 \\pub fn main() -> %void {
363 \\ %%io.stdout.printf("before\n");371 \\ const stdout = &(%%io.getStdOut()).out_stream;
364 \\ defer %%io.stdout.printf("defer1\n");372 \\ %%stdout.print("before\n");
365 \\ defer %%io.stdout.printf("defer2\n");373 \\ defer %%stdout.print("defer1\n");
366 \\ defer %%io.stdout.printf("defer3\n");374 \\ defer %%stdout.print("defer2\n");
367 \\ %%io.stdout.printf("after\n");375 \\ defer %%stdout.print("defer3\n");
376 \\ %%stdout.print("after\n");
368 \\}377 \\}
369 , "before\nafter\ndefer3\ndefer2\ndefer1\n");378 , "before\nafter\ndefer3\ndefer2\ndefer1\n");
370379
...@@ -372,13 +381,14 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -372,13 +381,14 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
372 \\const io = @import("std").io;381 \\const io = @import("std").io;
373 \\const os = @import("std").os;382 \\const os = @import("std").os;
374 \\pub fn main() -> %void {383 \\pub fn main() -> %void {
375 \\ %%io.stdout.printf("before\n");384 \\ const stdout = &(%%io.getStdOut()).out_stream;
376 \\ defer %%io.stdout.printf("defer1\n");385 \\ %%stdout.print("before\n");
377 \\ defer %%io.stdout.printf("defer2\n");386 \\ defer %%stdout.print("defer1\n");
387 \\ defer %%stdout.print("defer2\n");
378 \\ var args_it = @import("std").os.args();388 \\ var args_it = @import("std").os.args();
379 \\ if (args_it.skip() and !args_it.skip()) return;389 \\ if (args_it.skip() and !args_it.skip()) return;
380 \\ defer %%io.stdout.printf("defer3\n");390 \\ defer %%stdout.print("defer3\n");
381 \\ %%io.stdout.printf("after\n");391 \\ %%stdout.print("after\n");
382 \\}392 \\}
383 , "before\ndefer2\ndefer1\n");393 , "before\ndefer2\ndefer1\n");
384394
...@@ -388,12 +398,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -388,12 +398,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
388 \\ do_test() %% return;398 \\ do_test() %% return;
389 \\}399 \\}
390 \\fn do_test() -> %void {400 \\fn do_test() -> %void {
391 \\ %%io.stdout.printf("before\n");401 \\ const stdout = &(%%io.getStdOut()).out_stream;
392 \\ defer %%io.stdout.printf("defer1\n");402 \\ %%stdout.print("before\n");
393 \\ %defer %%io.stdout.printf("deferErr\n");403 \\ defer %%stdout.print("defer1\n");
404 \\ %defer %%stdout.print("deferErr\n");
394 \\ %return its_gonna_fail();405 \\ %return its_gonna_fail();
395 \\ defer %%io.stdout.printf("defer3\n");406 \\ defer %%stdout.print("defer3\n");
396 \\ %%io.stdout.printf("after\n");407 \\ %%stdout.print("after\n");
397 \\}408 \\}
398 \\error IToldYouItWouldFail;409 \\error IToldYouItWouldFail;
399 \\fn its_gonna_fail() -> %void {410 \\fn its_gonna_fail() -> %void {
...@@ -407,12 +418,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -407,12 +418,13 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
407 \\ do_test() %% return;418 \\ do_test() %% return;
408 \\}419 \\}
409 \\fn do_test() -> %void {420 \\fn do_test() -> %void {
410 \\ %%io.stdout.printf("before\n");421 \\ const stdout = &(%%io.getStdOut()).out_stream;
411 \\ defer %%io.stdout.printf("defer1\n");422 \\ %%stdout.print("before\n");
412 \\ %defer %%io.stdout.printf("deferErr\n");423 \\ defer %%stdout.print("defer1\n");
424 \\ %defer %%stdout.print("deferErr\n");
413 \\ %return its_gonna_pass();425 \\ %return its_gonna_pass();
414 \\ defer %%io.stdout.printf("defer3\n");426 \\ defer %%stdout.print("defer3\n");
415 \\ %%io.stdout.printf("after\n");427 \\ %%stdout.print("after\n");
416 \\}428 \\}
417 \\fn its_gonna_pass() -> %void { }429 \\fn its_gonna_pass() -> %void { }
418 , "before\nafter\ndefer3\ndefer1\n");430 , "before\nafter\ndefer3\ndefer1\n");
...@@ -423,7 +435,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -423,7 +435,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
423 \\const io = @import("std").io;435 \\const io = @import("std").io;
424 \\436 \\
425 \\pub fn main() -> %void {437 \\pub fn main() -> %void {
426 \\ %%io.stdout.printf(foo_txt);438 \\ const stdout = &(%%io.getStdOut()).out_stream;
439 \\ %%stdout.print(foo_txt);
427 \\}440 \\}
428 , "1234\nabcd\n");441 , "1234\nabcd\n");
429442
test/tests.zig+36-33
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const debug = std.debug;2const debug = std.debug;
3const warn = debug.warn;
3const build = std.build;4const build = std.build;
4const os = std.os;5const os = std.os;
5const StdIo = os.ChildProcess.StdIo;6const StdIo = os.ChildProcess.StdIo;
...@@ -50,6 +51,8 @@ const test_targets = []TestTarget {...@@ -50,6 +51,8 @@ const test_targets = []TestTarget {
5051
51error TestFailed;52error TestFailed;
5253
54const max_stdout_size = 1 * 1024 * 1024; // 1 MB
55
53pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {56pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
54 const cases = %%b.allocator.create(CompareOutputContext);57 const cases = %%b.allocator.create(CompareOutputContext);
55 *cases = CompareOutputContext {58 *cases = CompareOutputContext {
...@@ -231,7 +234,7 @@ pub const CompareOutputContext = struct {...@@ -231,7 +234,7 @@ pub const CompareOutputContext = struct {
231234
232 const full_exe_path = b.pathFromRoot(self.exe_path);235 const full_exe_path = b.pathFromRoot(self.exe_path);
233236
234 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);237 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
235238
236 const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);239 const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);
237 defer child.deinit();240 defer child.deinit();
...@@ -246,8 +249,8 @@ pub const CompareOutputContext = struct {...@@ -246,8 +249,8 @@ pub const CompareOutputContext = struct {
246 var stdout = Buffer.initNull(b.allocator);249 var stdout = Buffer.initNull(b.allocator);
247 var stderr = Buffer.initNull(b.allocator);250 var stderr = Buffer.initNull(b.allocator);
248251
249 %%(??child.stdout).readAll(&stdout);252 %%(??child.stdout).in_stream.readAllBuffer(&stdout, max_stdout_size);
250 %%(??child.stderr).readAll(&stderr);253 %%(??child.stderr).in_stream.readAllBuffer(&stderr, max_stdout_size);
251254
252 const term = child.wait() %% |err| {255 const term = child.wait() %% |err| {
253 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));256 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
...@@ -255,19 +258,19 @@ pub const CompareOutputContext = struct {...@@ -255,19 +258,19 @@ pub const CompareOutputContext = struct {
255 switch (term) {258 switch (term) {
256 Term.Exited => |code| {259 Term.Exited => |code| {
257 if (code != 0) {260 if (code != 0) {
258 %%io.stderr.printf("Process {} exited with error code {}\n", full_exe_path, code);261 warn("Process {} exited with error code {}\n", full_exe_path, code);
259 return error.TestFailed;262 return error.TestFailed;
260 }263 }
261 },264 },
262 else => {265 else => {
263 %%io.stderr.printf("Process {} terminated unexpectedly\n", full_exe_path);266 warn("Process {} terminated unexpectedly\n", full_exe_path);
264 return error.TestFailed;267 return error.TestFailed;
265 },268 },
266 };269 };
267270
268271
269 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {272 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {
270 %%io.stderr.printf(273 warn(
271 \\274 \\
272 \\========= Expected this output: =========275 \\========= Expected this output: =========
273 \\{}276 \\{}
...@@ -277,7 +280,7 @@ pub const CompareOutputContext = struct {...@@ -277,7 +280,7 @@ pub const CompareOutputContext = struct {
277 , self.expected_output, stdout.toSliceConst());280 , self.expected_output, stdout.toSliceConst());
278 return error.TestFailed;281 return error.TestFailed;
279 }282 }
280 %%io.stderr.printf("OK\n");283 warn("OK\n");
281 }284 }
282 };285 };
283286
...@@ -310,7 +313,7 @@ pub const CompareOutputContext = struct {...@@ -310,7 +313,7 @@ pub const CompareOutputContext = struct {
310313
311 const full_exe_path = b.pathFromRoot(self.exe_path);314 const full_exe_path = b.pathFromRoot(self.exe_path);
312315
313 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);316 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
314317
315 const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);318 const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);
316 defer child.deinit();319 defer child.deinit();
...@@ -328,24 +331,24 @@ pub const CompareOutputContext = struct {...@@ -328,24 +331,24 @@ pub const CompareOutputContext = struct {
328 switch (term) {331 switch (term) {
329 Term.Exited => |code| {332 Term.Exited => |code| {
330 if (code != expected_exit_code) {333 if (code != expected_exit_code) {
331 %%io.stderr.printf("\nProgram expected to exit with code {} " ++334 warn("\nProgram expected to exit with code {} " ++
332 "but exited with code {}\n", expected_exit_code, code);335 "but exited with code {}\n", expected_exit_code, code);
333 return error.TestFailed;336 return error.TestFailed;
334 }337 }
335 },338 },
336 Term.Signal => |sig| {339 Term.Signal => |sig| {
337 %%io.stderr.printf("\nProgram expected to exit with code {} " ++340 warn("\nProgram expected to exit with code {} " ++
338 "but instead signaled {}\n", expected_exit_code, sig);341 "but instead signaled {}\n", expected_exit_code, sig);
339 return error.TestFailed;342 return error.TestFailed;
340 },343 },
341 else => {344 else => {
342 %%io.stderr.printf("\nProgram expected to exit with code {}" ++345 warn("\nProgram expected to exit with code {}" ++
343 " but exited in an unexpected way\n", expected_exit_code);346 " but exited in an unexpected way\n", expected_exit_code);
344 return error.TestFailed;347 return error.TestFailed;
345 },348 },
346 }349 }
347350
348 %%io.stderr.printf("OK\n");351 warn("OK\n");
349 }352 }
350 };353 };
351354
...@@ -554,7 +557,7 @@ pub const CompileErrorContext = struct {...@@ -554,7 +557,7 @@ pub const CompileErrorContext = struct {
554 Mode.ReleaseFast => %%zig_args.append("--release-fast"),557 Mode.ReleaseFast => %%zig_args.append("--release-fast"),
555 }558 }
556559
557 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);560 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
558561
559 if (b.verbose) {562 if (b.verbose) {
560 printInvocation(zig_args.toSliceConst());563 printInvocation(zig_args.toSliceConst());
...@@ -573,8 +576,8 @@ pub const CompileErrorContext = struct {...@@ -573,8 +576,8 @@ pub const CompileErrorContext = struct {
573 var stdout_buf = Buffer.initNull(b.allocator);576 var stdout_buf = Buffer.initNull(b.allocator);
574 var stderr_buf = Buffer.initNull(b.allocator);577 var stderr_buf = Buffer.initNull(b.allocator);
575578
576 %%(??child.stdout).readAll(&stdout_buf);579 %%(??child.stdout).in_stream.readAllBuffer(&stdout_buf, max_stdout_size);
577 %%(??child.stderr).readAll(&stderr_buf);580 %%(??child.stderr).in_stream.readAllBuffer(&stderr_buf, max_stdout_size);
578581
579 const term = child.wait() %% |err| {582 const term = child.wait() %% |err| {
580 debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));583 debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));
...@@ -582,12 +585,12 @@ pub const CompileErrorContext = struct {...@@ -582,12 +585,12 @@ pub const CompileErrorContext = struct {
582 switch (term) {585 switch (term) {
583 Term.Exited => |code| {586 Term.Exited => |code| {
584 if (code == 0) {587 if (code == 0) {
585 %%io.stderr.printf("Compilation incorrectly succeeded\n");588 warn("Compilation incorrectly succeeded\n");
586 return error.TestFailed;589 return error.TestFailed;
587 }590 }
588 },591 },
589 else => {592 else => {
590 %%io.stderr.printf("Process {} terminated unexpectedly\n", b.zig_exe);593 warn("Process {} terminated unexpectedly\n", b.zig_exe);
591 return error.TestFailed;594 return error.TestFailed;
592 },595 },
593 };596 };
...@@ -597,7 +600,7 @@ pub const CompileErrorContext = struct {...@@ -597,7 +600,7 @@ pub const CompileErrorContext = struct {
597 const stderr = stderr_buf.toSliceConst();600 const stderr = stderr_buf.toSliceConst();
598601
599 if (stdout.len != 0) {602 if (stdout.len != 0) {
600 %%io.stderr.printf(603 warn(
601 \\604 \\
602 \\Expected empty stdout, instead found:605 \\Expected empty stdout, instead found:
603 \\================================================606 \\================================================
...@@ -610,7 +613,7 @@ pub const CompileErrorContext = struct {...@@ -610,7 +613,7 @@ pub const CompileErrorContext = struct {
610613
611 for (self.case.expected_errors.toSliceConst()) |expected_error| {614 for (self.case.expected_errors.toSliceConst()) |expected_error| {
612 if (mem.indexOf(u8, stderr, expected_error) == null) {615 if (mem.indexOf(u8, stderr, expected_error) == null) {
613 %%io.stderr.printf(616 warn(
614 \\617 \\
615 \\========= Expected this compile error: =========618 \\========= Expected this compile error: =========
616 \\{}619 \\{}
...@@ -621,15 +624,15 @@ pub const CompileErrorContext = struct {...@@ -621,15 +624,15 @@ pub const CompileErrorContext = struct {
621 return error.TestFailed;624 return error.TestFailed;
622 }625 }
623 }626 }
624 %%io.stderr.printf("OK\n");627 warn("OK\n");
625 }628 }
626 };629 };
627630
628 fn printInvocation(args: []const []const u8) {631 fn printInvocation(args: []const []const u8) {
629 for (args) |arg| {632 for (args) |arg| {
630 %%io.stderr.printf("{} ", arg);633 warn("{} ", arg);
631 }634 }
632 %%io.stderr.printf("\n");635 warn("\n");
633 }636 }
634637
635 pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8,638 pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8,
...@@ -822,7 +825,7 @@ pub const ParseCContext = struct {...@@ -822,7 +825,7 @@ pub const ParseCContext = struct {
822 %%zig_args.append("parsec");825 %%zig_args.append("parsec");
823 %%zig_args.append(b.pathFromRoot(root_src));826 %%zig_args.append(b.pathFromRoot(root_src));
824827
825 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);828 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
826829
827 if (b.verbose) {830 if (b.verbose) {
828 printInvocation(zig_args.toSliceConst());831 printInvocation(zig_args.toSliceConst());
...@@ -841,8 +844,8 @@ pub const ParseCContext = struct {...@@ -841,8 +844,8 @@ pub const ParseCContext = struct {
841 var stdout_buf = Buffer.initNull(b.allocator);844 var stdout_buf = Buffer.initNull(b.allocator);
842 var stderr_buf = Buffer.initNull(b.allocator);845 var stderr_buf = Buffer.initNull(b.allocator);
843846
844 %%(??child.stdout).readAll(&stdout_buf);847 %%(??child.stdout).in_stream.readAllBuffer(&stdout_buf, max_stdout_size);
845 %%(??child.stderr).readAll(&stderr_buf);848 %%(??child.stderr).in_stream.readAllBuffer(&stderr_buf, max_stdout_size);
846849
847 const term = child.wait() %% |err| {850 const term = child.wait() %% |err| {
848 debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));851 debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));
...@@ -850,16 +853,16 @@ pub const ParseCContext = struct {...@@ -850,16 +853,16 @@ pub const ParseCContext = struct {
850 switch (term) {853 switch (term) {
851 Term.Exited => |code| {854 Term.Exited => |code| {
852 if (code != 0) {855 if (code != 0) {
853 %%io.stderr.printf("Compilation failed with exit code {}\n", code);856 warn("Compilation failed with exit code {}\n", code);
854 return error.TestFailed;857 return error.TestFailed;
855 }858 }
856 },859 },
857 Term.Signal => |code| {860 Term.Signal => |code| {
858 %%io.stderr.printf("Compilation failed with signal {}\n", code);861 warn("Compilation failed with signal {}\n", code);
859 return error.TestFailed;862 return error.TestFailed;
860 },863 },
861 else => {864 else => {
862 %%io.stderr.printf("Compilation terminated unexpectedly\n");865 warn("Compilation terminated unexpectedly\n");
863 return error.TestFailed;866 return error.TestFailed;
864 },867 },
865 };868 };
...@@ -868,7 +871,7 @@ pub const ParseCContext = struct {...@@ -868,7 +871,7 @@ pub const ParseCContext = struct {
868 const stderr = stderr_buf.toSliceConst();871 const stderr = stderr_buf.toSliceConst();
869872
870 if (stderr.len != 0 and !self.case.allow_warnings) {873 if (stderr.len != 0 and !self.case.allow_warnings) {
871 %%io.stderr.printf(874 warn(
872 \\====== parsec emitted warnings: ============875 \\====== parsec emitted warnings: ============
873 \\{}876 \\{}
874 \\============================================877 \\============================================
...@@ -879,7 +882,7 @@ pub const ParseCContext = struct {...@@ -879,7 +882,7 @@ pub const ParseCContext = struct {
879882
880 for (self.case.expected_lines.toSliceConst()) |expected_line| {883 for (self.case.expected_lines.toSliceConst()) |expected_line| {
881 if (mem.indexOf(u8, stdout, expected_line) == null) {884 if (mem.indexOf(u8, stdout, expected_line) == null) {
882 %%io.stderr.printf(885 warn(
883 \\886 \\
884 \\========= Expected this output: ================887 \\========= Expected this output: ================
885 \\{}888 \\{}
...@@ -890,15 +893,15 @@ pub const ParseCContext = struct {...@@ -890,15 +893,15 @@ pub const ParseCContext = struct {
890 return error.TestFailed;893 return error.TestFailed;
891 }894 }
892 }895 }
893 %%io.stderr.printf("OK\n");896 warn("OK\n");
894 }897 }
895 };898 };
896899
897 fn printInvocation(args: []const []const u8) {900 fn printInvocation(args: []const []const u8) {
898 for (args) |arg| {901 for (args) |arg| {
899 %%io.stderr.printf("{} ", arg);902 warn("{} ", arg);
900 }903 }
901 %%io.stderr.printf("\n");904 warn("\n");
902 }905 }
903906
904 pub fn create(self: &ParseCContext, allow_warnings: bool, filename: []const u8, name: []const u8,907 pub fn create(self: &ParseCContext, allow_warnings: bool, filename: []const u8, name: []const u8,