authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-09 18:27:50-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-09 18:27:50-05:00
loga2bd9f8912ade5149855dc6e2371aaae49093660
tree04dab23f1d6d730b5266506422daf820124fa139
parente7bf8f3f04efc280a76a3a38b4e6d470d279e41a

std lib: modify allocator idiom

Before we accepted a nullable allocator for some stuff like opening files. Now we require an allocator. Use the mem.FixedBufferAllocator pattern if a bound on the amount to allocate is known. This also establishes the pattern that usually an allocator is the first argument to a function (possibly after "self"). fix docs for std.cstr.addNullByte self hosted compiler: * only build docs when explicitly asked to * clean up main * stub out zig fmt

15 files changed, 103 insertions(+), 136 deletions(-)

build.zig-1
...@@ -78,7 +78,6 @@ pub fn build(b: &Builder) !void {...@@ -78,7 +78,6 @@ pub fn build(b: &Builder) !void {
78 exe.linkSystemLibrary("c");78 exe.linkSystemLibrary("c");
7979
80 b.default_step.dependOn(&exe.step);80 b.default_step.dependOn(&exe.step);
81 b.default_step.dependOn(docs_step);
8281
83 const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") ?? false;82 const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") ?? false;
84 if (!skip_self_hosted) {83 if (!skip_self_hosted) {
doc/docgen.zig+3-3
...@@ -31,10 +31,10 @@ pub fn main() !void {...@@ -31,10 +31,10 @@ pub fn main() !void {
31 const out_file_name = try (args_it.next(allocator) ?? @panic("expected output arg"));31 const out_file_name = try (args_it.next(allocator) ?? @panic("expected output arg"));
32 defer allocator.free(out_file_name);32 defer allocator.free(out_file_name);
3333
34 var in_file = try io.File.openRead(in_file_name, allocator);34 var in_file = try io.File.openRead(allocator, in_file_name);
35 defer in_file.close();35 defer in_file.close();
3636
37 var out_file = try io.File.openWrite(out_file_name, allocator);37 var out_file = try io.File.openWrite(allocator, out_file_name);
38 defer out_file.close();38 defer out_file.close();
3939
40 var file_in_stream = io.FileInStream.init(&in_file);40 var file_in_stream = io.FileInStream.init(&in_file);
...@@ -723,7 +723,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var...@@ -723,7 +723,7 @@ fn genHtml(allocator: &mem.Allocator, tokenizer: &Tokenizer, toc: &Toc, out: var
723 try out.print("<pre><code class=\"zig\">{}</code></pre>", escaped_source);723 try out.print("<pre><code class=\"zig\">{}</code></pre>", escaped_source);
724 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);724 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
725 const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);725 const tmp_source_file_name = try os.path.join(allocator, tmp_dir_name, name_plus_ext);
726 try io.writeFile(tmp_source_file_name, trimmed_raw_source, null);726 try io.writeFile(allocator, tmp_source_file_name, trimmed_raw_source);
727 727
728 switch (code.id) {728 switch (code.id) {
729 Code.Id.Exe => |expected_outcome| {729 Code.Id.Exe => |expected_outcome| {
example/cat/main.zig+1-1
...@@ -20,7 +20,7 @@ pub fn main() !void {...@@ -20,7 +20,7 @@ pub fn main() !void {
20 } else if (arg[0] == '-') {20 } else if (arg[0] == '-') {
21 return usage(exe);21 return usage(exe);
22 } else {22 } else {
23 var file = io.File.openRead(arg, null) catch |err| {23 var file = io.File.openRead(allocator, arg) catch |err| {
24 warn("Unable to open file: {}\n", @errorName(err));24 warn("Unable to open file: {}\n", @errorName(err));
25 return err;25 return err;
26 };26 };
src-self-hosted/main.zig+35-30
...@@ -16,15 +16,6 @@ const c = @import("c.zig");...@@ -16,15 +16,6 @@ const c = @import("c.zig");
1616
17const default_zig_cache_name = "zig-cache";17const default_zig_cache_name = "zig-cache";
1818
19pub fn main() !void {
20 main2() catch |err| {
21 if (err != error.InvalidCommandLineArguments) {
22 warn("{}\n", @errorName(err));
23 }
24 return err;
25 };
26}
27
28const Cmd = enum {19const Cmd = enum {
29 None,20 None,
30 Build,21 Build,
...@@ -35,21 +26,25 @@ const Cmd = enum {...@@ -35,21 +26,25 @@ const Cmd = enum {
35 Targets,26 Targets,
36};27};
3728
38fn badArgs(comptime format: []const u8, args: ...) error {29fn badArgs(comptime format: []const u8, args: ...) noreturn {
39 var stderr = try io.getStdErr();30 var stderr = io.getStdErr() catch std.os.exit(1);
40 var stderr_stream_adapter = io.FileOutStream.init(&stderr);31 var stderr_stream_adapter = io.FileOutStream.init(&stderr);
41 const stderr_stream = &stderr_stream_adapter.stream;32 const stderr_stream = &stderr_stream_adapter.stream;
42 try stderr_stream.print(format ++ "\n\n", args);33 stderr_stream.print(format ++ "\n\n", args) catch std.os.exit(1);
43 try printUsage(&stderr_stream_adapter.stream);34 printUsage(&stderr_stream_adapter.stream) catch std.os.exit(1);
44 return error.InvalidCommandLineArguments;35 std.os.exit(1);
45}36}
4637
47pub fn main2() !void {38pub fn main() !void {
48 const allocator = std.heap.c_allocator;39 const allocator = std.heap.c_allocator;
4940
50 const args = try os.argsAlloc(allocator);41 const args = try os.argsAlloc(allocator);
51 defer os.argsFree(allocator, args);42 defer os.argsFree(allocator, args);
5243
44 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) {
45 return fmtMain(allocator, args[2..]);
46 }
47
53 var cmd = Cmd.None;48 var cmd = Cmd.None;
54 var build_kind: Module.Kind = undefined;49 var build_kind: Module.Kind = undefined;
55 var build_mode: builtin.Mode = builtin.Mode.Debug;50 var build_mode: builtin.Mode = builtin.Mode.Debug;
...@@ -169,7 +164,7 @@ pub fn main2() !void {...@@ -169,7 +164,7 @@ pub fn main2() !void {
169 } else if (mem.eql(u8, arg, "--pkg-end")) {164 } else if (mem.eql(u8, arg, "--pkg-end")) {
170 @panic("TODO --pkg-end");165 @panic("TODO --pkg-end");
171 } else if (arg_i + 1 >= args.len) {166 } else if (arg_i + 1 >= args.len) {
172 return badArgs("expected another argument after {}", arg);167 badArgs("expected another argument after {}", arg);
173 } else {168 } else {
174 arg_i += 1;169 arg_i += 1;
175 if (mem.eql(u8, arg, "--output")) {170 if (mem.eql(u8, arg, "--output")) {
...@@ -184,7 +179,7 @@ pub fn main2() !void {...@@ -184,7 +179,7 @@ pub fn main2() !void {
184 } else if (mem.eql(u8, args[arg_i], "off")) {179 } else if (mem.eql(u8, args[arg_i], "off")) {
185 color = ErrColor.Off;180 color = ErrColor.Off;
186 } else {181 } else {
187 return badArgs("--color options are 'auto', 'on', or 'off'");182 badArgs("--color options are 'auto', 'on', or 'off'");
188 }183 }
189 } else if (mem.eql(u8, arg, "--emit")) {184 } else if (mem.eql(u8, arg, "--emit")) {
190 if (mem.eql(u8, args[arg_i], "asm")) {185 if (mem.eql(u8, args[arg_i], "asm")) {
...@@ -194,7 +189,7 @@ pub fn main2() !void {...@@ -194,7 +189,7 @@ pub fn main2() !void {
194 } else if (mem.eql(u8, args[arg_i], "llvm-ir")) {189 } else if (mem.eql(u8, args[arg_i], "llvm-ir")) {
195 emit_file_type = Emit.LlvmIr;190 emit_file_type = Emit.LlvmIr;
196 } else {191 } else {
197 return badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'");192 badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'");
198 }193 }
199 } else if (mem.eql(u8, arg, "--name")) {194 } else if (mem.eql(u8, arg, "--name")) {
200 out_name_arg = args[arg_i];195 out_name_arg = args[arg_i];
...@@ -262,7 +257,7 @@ pub fn main2() !void {...@@ -262,7 +257,7 @@ pub fn main2() !void {
262 } else if (mem.eql(u8, arg, "--test-cmd")) {257 } else if (mem.eql(u8, arg, "--test-cmd")) {
263 @panic("TODO --test-cmd");258 @panic("TODO --test-cmd");
264 } else {259 } else {
265 return badArgs("invalid argument: {}", arg);260 badArgs("invalid argument: {}", arg);
266 }261 }
267 }262 }
268 } else if (cmd == Cmd.None) {263 } else if (cmd == Cmd.None) {
...@@ -285,18 +280,18 @@ pub fn main2() !void {...@@ -285,18 +280,18 @@ pub fn main2() !void {
285 cmd = Cmd.Test;280 cmd = Cmd.Test;
286 build_kind = Module.Kind.Exe;281 build_kind = Module.Kind.Exe;
287 } else {282 } else {
288 return badArgs("unrecognized command: {}", arg);283 badArgs("unrecognized command: {}", arg);
289 }284 }
290 } else switch (cmd) {285 } else switch (cmd) {
291 Cmd.Build, Cmd.TranslateC, Cmd.Test => {286 Cmd.Build, Cmd.TranslateC, Cmd.Test => {
292 if (in_file_arg == null) {287 if (in_file_arg == null) {
293 in_file_arg = arg;288 in_file_arg = arg;
294 } else {289 } else {
295 return badArgs("unexpected extra parameter: {}", arg);290 badArgs("unexpected extra parameter: {}", arg);
296 }291 }
297 },292 },
298 Cmd.Version, Cmd.Zen, Cmd.Targets => {293 Cmd.Version, Cmd.Zen, Cmd.Targets => {
299 return badArgs("unexpected extra parameter: {}", arg);294 badArgs("unexpected extra parameter: {}", arg);
300 },295 },
301 Cmd.None => unreachable,296 Cmd.None => unreachable,
302 }297 }
...@@ -333,15 +328,15 @@ pub fn main2() !void {...@@ -333,15 +328,15 @@ pub fn main2() !void {
333// }328// }
334329
335 switch (cmd) {330 switch (cmd) {
336 Cmd.None => return badArgs("expected command"),331 Cmd.None => badArgs("expected command"),
337 Cmd.Zen => return printZen(),332 Cmd.Zen => return printZen(),
338 Cmd.Build, Cmd.Test, Cmd.TranslateC => {333 Cmd.Build, Cmd.Test, Cmd.TranslateC => {
339 if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) {334 if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) {
340 return badArgs("expected source file argument or at least one --object or --assembly argument");335 badArgs("expected source file argument or at least one --object or --assembly argument");
341 } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) {336 } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) {
342 return badArgs("expected source file argument");337 badArgs("expected source file argument");
343 } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) {338 } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) {
344 return badArgs("When building an object file, --object arguments are invalid");339 badArgs("When building an object file, --object arguments are invalid");
345 }340 }
346341
347 const root_name = switch (cmd) {342 const root_name = switch (cmd) {
...@@ -351,9 +346,9 @@ pub fn main2() !void {...@@ -351,9 +346,9 @@ pub fn main2() !void {
351 } else if (in_file_arg) |in_file_path| {346 } else if (in_file_arg) |in_file_path| {
352 const basename = os.path.basename(in_file_path);347 const basename = os.path.basename(in_file_path);
353 var it = mem.split(basename, ".");348 var it = mem.split(basename, ".");
354 break :x it.next() ?? return badArgs("file name cannot be empty");349 break :x it.next() ?? badArgs("file name cannot be empty");
355 } else {350 } else {
356 return badArgs("--name [name] not provided and unable to infer");351 badArgs("--name [name] not provided and unable to infer");
357 }352 }
358 },353 },
359 Cmd.Test => "test",354 Cmd.Test => "test",
...@@ -428,7 +423,7 @@ pub fn main2() !void {...@@ -428,7 +423,7 @@ pub fn main2() !void {
428 module.linker_rdynamic = rdynamic;423 module.linker_rdynamic = rdynamic;
429424
430 if (mmacosx_version_min != null and mios_version_min != null) {425 if (mmacosx_version_min != null and mios_version_min != null) {
431 return badArgs("-mmacosx-version-min and -mios-version-min options not allowed together");426 badArgs("-mmacosx-version-min and -mios-version-min options not allowed together");
432 }427 }
433428
434 if (mmacosx_version_min) |ver| {429 if (mmacosx_version_min) |ver| {
...@@ -477,6 +472,7 @@ fn printUsage(stream: var) !void {...@@ -477,6 +472,7 @@ fn printUsage(stream: var) !void {
477 \\ build-exe [source] create executable from source or object files472 \\ build-exe [source] create executable from source or object files
478 \\ build-lib [source] create library from source or object files473 \\ build-lib [source] create library from source or object files
479 \\ build-obj [source] create object from source or assembly474 \\ build-obj [source] create object from source or assembly
475 \\ fmt [file] parse file and render in canonical zig format
480 \\ translate-c [source] convert c code to zig code476 \\ translate-c [source] convert c code to zig code
481 \\ targets list available compilation targets477 \\ targets list available compilation targets
482 \\ test [source] create and run a test build478 \\ test [source] create and run a test build
...@@ -564,6 +560,15 @@ fn printZen() !void {...@@ -564,6 +560,15 @@ fn printZen() !void {
564 );560 );
565}561}
566562
563fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
564 for (file_paths) |file_path| {
565 var file = try io.File.openRead(allocator, file_path);
566 defer file.close();
567
568 warn("opened {} (todo tokenize and parse and render)\n", file_path);
569 }
570}
571
567/// Caller must free result572/// Caller must free result
568fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {573fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 {
569 if (zig_install_prefix_arg) |zig_install_prefix| {574 if (zig_install_prefix_arg) |zig_install_prefix| {
...@@ -588,7 +593,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8...@@ -588,7 +593,7 @@ fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8
588 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");593 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig");
589 defer allocator.free(test_index_file);594 defer allocator.free(test_index_file);
590595
591 var file = try io.File.openRead(test_index_file, allocator);596 var file = try io.File.openRead(allocator, test_index_file);
592 file.close();597 file.close();
593598
594 return test_zig_dir;599 return test_zig_dir;
src-self-hosted/module.zig+1-1
...@@ -213,7 +213,7 @@ pub const Module = struct {...@@ -213,7 +213,7 @@ pub const Module = struct {
213 };213 };
214 errdefer self.allocator.free(root_src_real_path);214 errdefer self.allocator.free(root_src_real_path);
215215
216 const source_code = io.readFileAllocExtra(root_src_real_path, self.allocator, 3) catch |err| {216 const source_code = io.readFileAllocExtra(self.allocator, root_src_real_path, 3) catch |err| {
217 try printError("unable to open '{}': {}", root_src_real_path, err);217 try printError("unable to open '{}': {}", root_src_real_path, err);
218 return err;218 return err;
219 };219 };
std/build.zig+1-1
...@@ -1890,7 +1890,7 @@ pub const WriteFileStep = struct {...@@ -1890,7 +1890,7 @@ pub const WriteFileStep = struct {
1890 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));1890 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
1891 return err;1891 return err;
1892 };1892 };
1893 io.writeFile(full_path, self.data, self.builder.allocator) catch |err| {1893 io.writeFile(self.builder.allocator, full_path, self.data) catch |err| {
1894 warn("unable to write {}: {}\n", full_path, @errorName(err));1894 warn("unable to write {}: {}\n", full_path, @errorName(err));
1895 return err;1895 return err;
1896 };1896 };
std/cstr.zig+1-2
...@@ -39,8 +39,7 @@ fn testCStrFnsImpl() void {...@@ -39,8 +39,7 @@ fn testCStrFnsImpl() void {
39 assert(len(c"123456789") == 9);39 assert(len(c"123456789") == 9);
40}40}
4141
42/// Returns a mutable slice with exactly the same size which is guaranteed to42/// Returns a mutable slice with 1 more byte of length which is a null byte.
43/// have a null byte after it.
44/// Caller owns the returned memory.43/// Caller owns the returned memory.
45pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) ![]u8 {44pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) ![]u8 {
46 const result = try allocator.alloc(u8, slice.len + 1);45 const result = try allocator.alloc(u8, slice.len + 1);
std/debug/index.zig+1-1
...@@ -265,7 +265,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {...@@ -265,7 +265,7 @@ pub fn openSelfDebugInfo(allocator: &mem.Allocator) !&ElfStackTrace {
265}265}
266266
267fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &const LineInfo) !void {267fn printLineFromFile(allocator: &mem.Allocator, out_stream: var, line_info: &const LineInfo) !void {
268 var f = try io.File.openRead(line_info.file_name, allocator);268 var f = try io.File.openRead(allocator, line_info.file_name);
269 defer f.close();269 defer f.close();
270 // TODO fstat and make sure that the file has the correct size270 // TODO fstat and make sure that the file has the correct size
271271
std/io.zig+19-28
...@@ -110,19 +110,16 @@ pub const File = struct {...@@ -110,19 +110,16 @@ pub const File = struct {
110110
111 const OpenError = os.WindowsOpenError || os.PosixOpenError;111 const OpenError = os.WindowsOpenError || os.PosixOpenError;
112112
113 /// `path` may need to be copied in memory to add a null terminating byte. In this case113 /// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
114 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
115 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
116 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
117 /// Call close to clean up.114 /// Call close to clean up.
118 pub fn openRead(path: []const u8, allocator: ?&mem.Allocator) OpenError!File {115 pub fn openRead(allocator: &mem.Allocator, path: []const u8) OpenError!File {
119 if (is_posix) {116 if (is_posix) {
120 const flags = system.O_LARGEFILE|system.O_RDONLY;117 const flags = system.O_LARGEFILE|system.O_RDONLY;
121 const fd = try os.posixOpen(path, flags, 0, allocator);118 const fd = try os.posixOpen(allocator, path, flags, 0);
122 return openHandle(fd);119 return openHandle(fd);
123 } else if (is_windows) {120 } else if (is_windows) {
124 const handle = try os.windowsOpen(path, system.GENERIC_READ, system.FILE_SHARE_READ,121 const handle = try os.windowsOpen(allocator, path, system.GENERIC_READ, system.FILE_SHARE_READ,
125 system.OPEN_EXISTING, system.FILE_ATTRIBUTE_NORMAL, allocator);122 system.OPEN_EXISTING, system.FILE_ATTRIBUTE_NORMAL);
126 return openHandle(handle);123 return openHandle(handle);
127 } else {124 } else {
128 unreachable;125 unreachable;
...@@ -130,25 +127,22 @@ pub const File = struct {...@@ -130,25 +127,22 @@ pub const File = struct {
130 }127 }
131128
132 /// Calls `openWriteMode` with 0o666 for the mode.129 /// Calls `openWriteMode` with 0o666 for the mode.
133 pub fn openWrite(path: []const u8, allocator: ?&mem.Allocator) !File {130 pub fn openWrite(allocator: &mem.Allocator, path: []const u8) !File {
134 return openWriteMode(path, 0o666, allocator);131 return openWriteMode(allocator, path, 0o666);
135132
136 }133 }
137134
138 /// `path` may need to be copied in memory to add a null terminating byte. In this case135 /// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
139 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
140 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
141 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
142 /// Call close to clean up.136 /// Call close to clean up.
143 pub fn openWriteMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) !File {137 pub fn openWriteMode(allocator: &mem.Allocator, path: []const u8, mode: usize) !File {
144 if (is_posix) {138 if (is_posix) {
145 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;139 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
146 const fd = try os.posixOpen(path, flags, mode, allocator);140 const fd = try os.posixOpen(allocator, path, flags, mode);
147 return openHandle(fd);141 return openHandle(fd);
148 } else if (is_windows) {142 } else if (is_windows) {
149 const handle = try os.windowsOpen(path, system.GENERIC_WRITE,143 const handle = try os.windowsOpen(allocator, path, system.GENERIC_WRITE,
150 system.FILE_SHARE_WRITE|system.FILE_SHARE_READ|system.FILE_SHARE_DELETE,144 system.FILE_SHARE_WRITE|system.FILE_SHARE_READ|system.FILE_SHARE_DELETE,
151 system.CREATE_ALWAYS, system.FILE_ATTRIBUTE_NORMAL, allocator);145 system.CREATE_ALWAYS, system.FILE_ATTRIBUTE_NORMAL);
152 return openHandle(handle);146 return openHandle(handle);
153 } else {147 } else {
154 unreachable;148 unreachable;
...@@ -521,24 +515,21 @@ pub fn OutStream(comptime Error: type) type {...@@ -521,24 +515,21 @@ pub fn OutStream(comptime Error: type) type {
521 };515 };
522}516}
523517
524/// `path` may need to be copied in memory to add a null terminating byte. In this case518/// `path` needs to be copied in memory to add a null terminating byte, hence the allocator.
525/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed519pub fn writeFile(allocator: &mem.Allocator, path: []const u8, data: []const u8) !void {
526/// size buffer is too small, and the provided allocator is null, `error.NameTooLong` is returned.520 var file = try File.openWrite(allocator, path);
527/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
528pub fn writeFile(path: []const u8, data: []const u8, allocator: ?&mem.Allocator) !void {
529 var file = try File.openWrite(path, allocator);
530 defer file.close();521 defer file.close();
531 try file.write(data);522 try file.write(data);
532}523}
533524
534/// On success, caller owns returned buffer.525/// On success, caller owns returned buffer.
535pub fn readFileAlloc(path: []const u8, allocator: &mem.Allocator) ![]u8 {526pub fn readFileAlloc(allocator: &mem.Allocator, path: []const u8) ![]u8 {
536 return readFileAllocExtra(path, allocator, 0);527 return readFileAllocExtra(allocator, path, 0);
537}528}
538/// On success, caller owns returned buffer.529/// On success, caller owns returned buffer.
539/// Allocates extra_len extra bytes at the end of the file buffer, which are uninitialized.530/// Allocates extra_len extra bytes at the end of the file buffer, which are uninitialized.
540pub fn readFileAllocExtra(path: []const u8, allocator: &mem.Allocator, extra_len: usize) ![]u8 {531pub fn readFileAllocExtra(allocator: &mem.Allocator, path: []const u8, extra_len: usize) ![]u8 {
541 var file = try File.openRead(path, allocator);532 var file = try File.openRead(allocator, path);
542 defer file.close();533 defer file.close();
543534
544 const size = try file.getEndPos();535 const size = try file.getEndPos();
std/io_test.zig+2-2
...@@ -13,7 +13,7 @@ test "write a file, read it, then delete it" {...@@ -13,7 +13,7 @@ test "write a file, read it, then delete it" {
13 rng.fillBytes(data[0..]);13 rng.fillBytes(data[0..]);
14 const tmp_file_name = "temp_test_file.txt";14 const tmp_file_name = "temp_test_file.txt";
15 {15 {
16 var file = try io.File.openWrite(tmp_file_name, allocator);16 var file = try io.File.openWrite(allocator, tmp_file_name);
17 defer file.close();17 defer file.close();
1818
19 var file_out_stream = io.FileOutStream.init(&file);19 var file_out_stream = io.FileOutStream.init(&file);
...@@ -25,7 +25,7 @@ test "write a file, read it, then delete it" {...@@ -25,7 +25,7 @@ test "write a file, read it, then delete it" {
25 try buf_stream.flush();25 try buf_stream.flush();
26 }26 }
27 {27 {
28 var file = try io.File.openRead(tmp_file_name, allocator);28 var file = try io.File.openRead(allocator, tmp_file_name);
29 defer file.close();29 defer file.close();
3030
31 const file_size = try file.getEndPos();31 const file_size = try file.getEndPos();
std/os/child_process.zig+17-11
...@@ -360,11 +360,14 @@ pub const ChildProcess = struct {...@@ -360,11 +360,14 @@ pub const ChildProcess = struct {
360 errdefer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };360 errdefer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
361361
362 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);362 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
363 const dev_null_fd = if (any_ignore)363 const dev_null_fd = if (any_ignore) blk: {
364 try os.posixOpen("/dev/null", posix.O_RDWR, 0, null)364 const dev_null_path = "/dev/null";
365 else365 var fixed_buffer_mem: [dev_null_path.len + 1]u8 = undefined;
366 undefined366 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
367 ;367 break :blk try os.posixOpen(&fixed_allocator.allocator, "/dev/null", posix.O_RDWR, 0);
368 } else blk: {
369 break :blk undefined;
370 };
368 defer { if (any_ignore) os.close(dev_null_fd); }371 defer { if (any_ignore) os.close(dev_null_fd); }
369372
370 var env_map_owned: BufMap = undefined;373 var env_map_owned: BufMap = undefined;
...@@ -466,12 +469,15 @@ pub const ChildProcess = struct {...@@ -466,12 +469,15 @@ pub const ChildProcess = struct {
466 self.stdout_behavior == StdIo.Ignore or469 self.stdout_behavior == StdIo.Ignore or
467 self.stderr_behavior == StdIo.Ignore);470 self.stderr_behavior == StdIo.Ignore);
468471
469 const nul_handle = if (any_ignore)472 const nul_handle = if (any_ignore) blk: {
470 try os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,473 const nul_file_path = "NUL";
471 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null)474 var fixed_buffer_mem: [nul_file_path.len + 1]u8 = undefined;
472 else475 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
473 undefined476 break :blk try os.windowsOpen(&fixed_allocator.allocator, "NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ,
474 ;477 windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
478 } else blk: {
479 break :blk undefined;
480 };
475 defer { if (any_ignore) os.close(nul_handle); }481 defer { if (any_ignore) os.close(nul_handle); }
476 if (any_ignore) {482 if (any_ignore) {
477 try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);483 try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
std/os/index.zig+14-30
...@@ -15,7 +15,6 @@ pub const posix = switch(builtin.os) {...@@ -15,7 +15,6 @@ pub const posix = switch(builtin.os) {
15 else => @compileError("Unsupported OS"),15 else => @compileError("Unsupported OS"),
16};16};
1717
18pub const max_noalloc_path_len = 1024;
19pub const ChildProcess = @import("child_process.zig").ChildProcess;18pub const ChildProcess = @import("child_process.zig").ChildProcess;
20pub const path = @import("path.zig");19pub const path = @import("path.zig");
2120
...@@ -265,32 +264,14 @@ pub const PosixOpenError = error {...@@ -265,32 +264,14 @@ pub const PosixOpenError = error {
265 Unexpected,264 Unexpected,
266};265};
267266
268/// ::file_path may need to be copied in memory to add a null terminating byte. In this case267/// ::file_path needs to be copied in memory to add a null terminating byte.
269/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed
270/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.
271/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
272/// Calls POSIX open, keeps trying if it gets interrupted, and translates268/// Calls POSIX open, keeps trying if it gets interrupted, and translates
273/// the return value into zig errors.269/// the return value into zig errors.
274pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Allocator) PosixOpenError!i32 {270pub fn posixOpen(allocator: &Allocator, file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
275 var stack_buf: [max_noalloc_path_len]u8 = undefined;271 const path_with_null = try cstr.addNullByte(allocator, file_path);
276 var path0: []u8 = undefined;272 defer allocator.free(path_with_null);
277 var need_free = false;
278
279 if (file_path.len < stack_buf.len) {
280 path0 = stack_buf[0..file_path.len + 1];
281 } else if (allocator) |a| {
282 path0 = try a.alloc(u8, file_path.len + 1);
283 need_free = true;
284 } else {
285 return error.NameTooLong;
286 }
287 defer if (need_free) {
288 (??allocator).free(path0);
289 };
290 mem.copy(u8, path0, file_path);
291 path0[file_path.len] = 0;
292273
293 return posixOpenC(path0.ptr, flags, perm);274 return posixOpenC(path_with_null.ptr, flags, perm);
294}275}
295276
296pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 {277pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) !i32 {
...@@ -784,11 +765,11 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [...@@ -784,11 +765,11 @@ pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: [
784 try getRandomBytes(rand_buf[0..]);765 try getRandomBytes(rand_buf[0..]);
785 b64_fs_encoder.encode(tmp_path[dest_path.len..], rand_buf);766 b64_fs_encoder.encode(tmp_path[dest_path.len..], rand_buf);
786767
787 var out_file = try io.File.openWriteMode(tmp_path, mode, allocator);768 var out_file = try io.File.openWriteMode(allocator, tmp_path, mode);
788 defer out_file.close();769 defer out_file.close();
789 errdefer _ = deleteFile(allocator, tmp_path);770 errdefer _ = deleteFile(allocator, tmp_path);
790771
791 var in_file = try io.File.openRead(source_path, allocator);772 var in_file = try io.File.openRead(allocator, source_path);
792 defer in_file.close();773 defer in_file.close();
793774
794 var buf: [page_size]u8 = undefined;775 var buf: [page_size]u8 = undefined;
...@@ -1074,7 +1055,7 @@ pub const Dir = struct {...@@ -1074,7 +1055,7 @@ pub const Dir = struct {
1074 };1055 };
10751056
1076 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {1057 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
1077 const fd = try posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator);1058 const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0);
1078 return Dir {1059 return Dir {
1079 .allocator = allocator,1060 .allocator = allocator,
1080 .fd = fd,1061 .fd = fd,
...@@ -1642,13 +1623,16 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {...@@ -1642,13 +1623,16 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {
1642pub fn openSelfExe() !io.File {1623pub fn openSelfExe() !io.File {
1643 switch (builtin.os) {1624 switch (builtin.os) {
1644 Os.linux => {1625 Os.linux => {
1645 return io.File.openRead("/proc/self/exe", null);1626 const proc_file_path = "/proc/self/exe";
1627 var fixed_buffer_mem: [proc_file_path.len + 1]u8 = undefined;
1628 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1629 return io.File.openRead(&fixed_allocator.allocator, proc_file_path);
1646 },1630 },
1647 Os.macosx, Os.ios => {1631 Os.macosx, Os.ios => {
1648 var fixed_buffer_mem: [darwin.PATH_MAX]u8 = undefined;1632 var fixed_buffer_mem: [darwin.PATH_MAX * 2]u8 = undefined;
1649 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);1633 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1650 const self_exe_path = try selfExePath(&fixed_allocator.allocator);1634 const self_exe_path = try selfExePath(&fixed_allocator.allocator);
1651 return io.File.openRead(self_exe_path, null);1635 return io.File.openRead(&fixed_allocator.allocator, self_exe_path);
1652 },1636 },
1653 else => @compileError("Unsupported OS"),1637 else => @compileError("Unsupported OS"),
1654 }1638 }
std/os/path.zig+1-1
...@@ -1161,7 +1161,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {...@@ -1161,7 +1161,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) ![]u8 {
1161 return allocator.shrink(u8, result_buf, cstr.len(result_buf.ptr));1161 return allocator.shrink(u8, result_buf, cstr.len(result_buf.ptr));
1162 },1162 },
1163 Os.linux => {1163 Os.linux => {
1164 const fd = try os.posixOpen(pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0, allocator);1164 const fd = try os.posixOpen(allocator, pathname, posix.O_PATH|posix.O_NONBLOCK|posix.O_CLOEXEC, 0);
1165 defer os.close(fd);1165 defer os.close(fd);
11661166
1167 var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;1167 var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;
std/os/windows/util.zig+6-23
...@@ -89,34 +89,17 @@ pub const OpenError = error {...@@ -89,34 +89,17 @@ pub const OpenError = error {
89 PipeBusy,89 PipeBusy,
90 Unexpected,90 Unexpected,
91 OutOfMemory,91 OutOfMemory,
92 NameTooLong,
93};92};
9493
95/// `file_path` may need to be copied in memory to add a null terminating byte. In this case94/// `file_path` needs to be copied in memory to add a null terminating byte, hence the allocator.
96/// a fixed size buffer of size ::max_noalloc_path_len is an attempted solution. If the fixed95pub fn windowsOpen(allocator: &mem.Allocator, file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,
97/// size buffer is too small, and the provided allocator is null, ::error.NameTooLong is returned.96 creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD)
98/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
99pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_mode: windows.DWORD,
100 creation_disposition: windows.DWORD, flags_and_attrs: windows.DWORD, allocator: ?&mem.Allocator)
101 OpenError!windows.HANDLE97 OpenError!windows.HANDLE
102{98{
103 var stack_buf: [os.max_noalloc_path_len]u8 = undefined;99 const path_with_null = try cstr.addNullByte(allocator, file_path);
104 var path0: []u8 = undefined;100 defer allocator.free(path_with_null);
105 var need_free = false;
106 defer if (need_free) (??allocator).free(path0);
107
108 if (file_path.len < stack_buf.len) {
109 path0 = stack_buf[0..file_path.len + 1];
110 } else if (allocator) |a| {
111 path0 = try a.alloc(u8, file_path.len + 1);
112 need_free = true;
113 } else {
114 return error.NameTooLong;
115 }
116 mem.copy(u8, path0, file_path);
117 path0[file_path.len] = 0;
118101
119 const result = windows.CreateFileA(path0.ptr, desired_access, share_mode, null, creation_disposition,102 const result = windows.CreateFileA(path_with_null.ptr, desired_access, share_mode, null, creation_disposition,
120 flags_and_attrs, null);103 flags_and_attrs, null);
121104
122 if (result == windows.INVALID_HANDLE_VALUE) {105 if (result == windows.INVALID_HANDLE_VALUE) {
test/tests.zig+1-1
...@@ -1049,7 +1049,7 @@ pub const GenHContext = struct {...@@ -1049,7 +1049,7 @@ pub const GenHContext = struct {
1049 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);1049 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
10501050
1051 const full_h_path = b.pathFromRoot(self.h_path);1051 const full_h_path = b.pathFromRoot(self.h_path);
1052 const actual_h = try io.readFileAlloc(full_h_path, b.allocator);1052 const actual_h = try io.readFileAlloc(b.allocator, full_h_path);
10531053
1054 for (self.case.expected_lines.toSliceConst()) |expected_line| {1054 for (self.case.expected_lines.toSliceConst()) |expected_line| {
1055 if (mem.indexOf(u8, actual_h, expected_line) == null) {1055 if (mem.indexOf(u8, actual_h, expected_line) == null) {