authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-16 23:14:10-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:26-07:00
log716b4489be09bc34ac5470658722924460d36a5d
tree2da6dcad7747358a0df9c08580b7474076749b21
parente60adb97d06f85adef7a0e2a2f320e04d0dce052

update more of the std lib to new API


16 files changed, 350 insertions(+), 398 deletions(-)

lib/compiler/build_runner.zig+64-60
......@@ -378,13 +378,16 @@ pub fn main() !void {
378378
379379 validateSystemLibraryOptions(builder);
380380
381 const stdout_writer = io.getStdOut().writer();
381 var stdout_writer: std.io.BufferedWriter = .{
382 .buffer = &stdout_buffer,
383 .unbuffered_writer = std.io.getStdOut().writer(),
384 };
382385
383386 if (help_menu)
384 return usage(builder, stdout_writer);
387 return usage(builder, &stdout_writer);
385388
386389 if (steps_menu)
387 return steps(builder, stdout_writer);
390 return steps(builder, &stdout_writer);
388391
389392 var run: Run = .{
390393 .max_rss = max_rss,
......@@ -696,24 +699,23 @@ fn runStepNames(
696699 const ttyconf = run.ttyconf;
697700
698701 if (run.summary != .none) {
699 std.debug.lockStdErr();
702 var bw = std.debug.lockStdErr2();
700703 defer std.debug.unlockStdErr();
701 const stderr = run.stderr;
702704
703705 const total_count = success_count + failure_count + pending_count + skipped_count;
704 ttyconf.setColor(stderr, .cyan) catch {};
705 stderr.writeAll("Build Summary:") catch {};
706 ttyconf.setColor(stderr, .reset) catch {};
707 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
708 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
709 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
706 ttyconf.setColor(&bw, .cyan) catch {};
707 bw.writeAll("Build Summary:") catch {};
708 ttyconf.setColor(&bw, .reset) catch {};
709 bw.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
710 if (skipped_count > 0) bw.print("; {d} skipped", .{skipped_count}) catch {};
711 if (failure_count > 0) bw.print("; {d} failed", .{failure_count}) catch {};
710712
711 if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
712 if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {};
713 if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};
714 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
713 if (test_count > 0) bw.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
714 if (test_skip_count > 0) bw.print("; {d} skipped", .{test_skip_count}) catch {};
715 if (test_fail_count > 0) bw.print("; {d} failed", .{test_fail_count}) catch {};
716 if (test_leak_count > 0) bw.print("; {d} leaked", .{test_leak_count}) catch {};
715717
716 stderr.writeAll("\n") catch {};
718 bw.writeAll("\n") catch {};
717719
718720 // Print a fancy tree with build results.
719721 var step_stack_copy = try step_stack.clone(gpa);
......@@ -722,7 +724,7 @@ fn runStepNames(
722724 var print_node: PrintNode = .{ .parent = null };
723725 if (step_names.len == 0) {
724726 print_node.last = true;
725 printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
727 printTreeStep(b, b.default_step, run, &bw, ttyconf, &print_node, &step_stack_copy) catch {};
726728 } else {
727729 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
728730 var i: usize = step_names.len;
......@@ -741,7 +743,7 @@ fn runStepNames(
741743 for (step_names, 0..) |step_name, i| {
742744 const tls = b.top_level_steps.get(step_name).?;
743745 print_node.last = i + 1 == last_index;
744 printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
746 printTreeStep(b, &tls.step, run, &bw, ttyconf, &print_node, &step_stack_copy) catch {};
745747 }
746748 }
747749 }
......@@ -775,7 +777,7 @@ const PrintNode = struct {
775777 last: bool = false,
776778};
777779
778fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
780fn printPrefix(node: *PrintNode, stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void {
779781 const parent = node.parent orelse return;
780782 if (parent.parent == null) return;
781783 try printPrefix(parent, stderr, ttyconf);
......@@ -789,7 +791,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void
789791 }
790792}
791793
792fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
794fn printChildNodePrefix(stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void {
793795 try stderr.writeAll(switch (ttyconf) {
794796 .no_color, .windows_api => "+- ",
795797 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
......@@ -798,7 +800,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
798800
799801fn printStepStatus(
800802 s: *Step,
801 stderr: File,
803 stderr: *std.io.BufferedWriter,
802804 ttyconf: std.io.tty.Config,
803805 run: *const Run,
804806) !void {
......@@ -820,10 +822,10 @@ fn printStepStatus(
820822 try stderr.writeAll(" cached");
821823 } else if (s.test_results.test_count > 0) {
822824 const pass_count = s.test_results.passCount();
823 try stderr.writer().print(" {d} passed", .{pass_count});
825 try stderr.print(" {d} passed", .{pass_count});
824826 if (s.test_results.skip_count > 0) {
825827 try ttyconf.setColor(stderr, .yellow);
826 try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
828 try stderr.print(" {d} skipped", .{s.test_results.skip_count});
827829 }
828830 } else {
829831 try stderr.writeAll(" success");
......@@ -832,15 +834,15 @@ fn printStepStatus(
832834 if (s.result_duration_ns) |ns| {
833835 try ttyconf.setColor(stderr, .dim);
834836 if (ns >= std.time.ns_per_min) {
835 try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
837 try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
836838 } else if (ns >= std.time.ns_per_s) {
837 try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s});
839 try stderr.print(" {d}s", .{ns / std.time.ns_per_s});
838840 } else if (ns >= std.time.ns_per_ms) {
839 try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms});
841 try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms});
840842 } else if (ns >= std.time.ns_per_us) {
841 try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us});
843 try stderr.print(" {d}us", .{ns / std.time.ns_per_us});
842844 } else {
843 try stderr.writer().print(" {d}ns", .{ns});
845 try stderr.print(" {d}ns", .{ns});
844846 }
845847 try ttyconf.setColor(stderr, .reset);
846848 }
......@@ -848,13 +850,13 @@ fn printStepStatus(
848850 const rss = s.result_peak_rss;
849851 try ttyconf.setColor(stderr, .dim);
850852 if (rss >= 1000_000_000) {
851 try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
853 try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
852854 } else if (rss >= 1000_000) {
853 try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000});
855 try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000});
854856 } else if (rss >= 1000) {
855 try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});
857 try stderr.print(" MaxRSS:{d}K", .{rss / 1000});
856858 } else {
857 try stderr.writer().print(" MaxRSS:{d}B", .{rss});
859 try stderr.print(" MaxRSS:{d}B", .{rss});
858860 }
859861 try ttyconf.setColor(stderr, .reset);
860862 }
......@@ -866,7 +868,7 @@ fn printStepStatus(
866868 if (skip == .skipped_oom) {
867869 try stderr.writeAll(" (not enough memory)");
868870 try ttyconf.setColor(stderr, .dim);
869 try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
871 try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
870872 try ttyconf.setColor(stderr, .yellow);
871873 }
872874 try stderr.writeAll("\n");
......@@ -878,23 +880,23 @@ fn printStepStatus(
878880
879881fn printStepFailure(
880882 s: *Step,
881 stderr: File,
883 stderr: *std.io.BufferedWriter,
882884 ttyconf: std.io.tty.Config,
883885) !void {
884886 if (s.result_error_bundle.errorMessageCount() > 0) {
885887 try ttyconf.setColor(stderr, .red);
886 try stderr.writer().print(" {d} errors\n", .{
888 try stderr.print(" {d} errors\n", .{
887889 s.result_error_bundle.errorMessageCount(),
888890 });
889891 try ttyconf.setColor(stderr, .reset);
890892 } else if (!s.test_results.isSuccess()) {
891 try stderr.writer().print(" {d}/{d} passed", .{
893 try stderr.print(" {d}/{d} passed", .{
892894 s.test_results.passCount(), s.test_results.test_count,
893895 });
894896 if (s.test_results.fail_count > 0) {
895897 try stderr.writeAll(", ");
896898 try ttyconf.setColor(stderr, .red);
897 try stderr.writer().print("{d} failed", .{
899 try stderr.print("{d} failed", .{
898900 s.test_results.fail_count,
899901 });
900902 try ttyconf.setColor(stderr, .reset);
......@@ -902,7 +904,7 @@ fn printStepFailure(
902904 if (s.test_results.skip_count > 0) {
903905 try stderr.writeAll(", ");
904906 try ttyconf.setColor(stderr, .yellow);
905 try stderr.writer().print("{d} skipped", .{
907 try stderr.print("{d} skipped", .{
906908 s.test_results.skip_count,
907909 });
908910 try ttyconf.setColor(stderr, .reset);
......@@ -910,7 +912,7 @@ fn printStepFailure(
910912 if (s.test_results.leak_count > 0) {
911913 try stderr.writeAll(", ");
912914 try ttyconf.setColor(stderr, .red);
913 try stderr.writer().print("{d} leaked", .{
915 try stderr.print("{d} leaked", .{
914916 s.test_results.leak_count,
915917 });
916918 try ttyconf.setColor(stderr, .reset);
......@@ -932,7 +934,7 @@ fn printTreeStep(
932934 b: *std.Build,
933935 s: *Step,
934936 run: *const Run,
935 stderr: File,
937 stderr: *std.io.BufferedWriter,
936938 ttyconf: std.io.tty.Config,
937939 parent_node: *PrintNode,
938940 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
......@@ -992,7 +994,7 @@ fn printTreeStep(
992994 if (s.dependencies.items.len == 0) {
993995 try stderr.writeAll(" (reused)\n");
994996 } else {
995 try stderr.writer().print(" (+{d} more reused dependencies)\n", .{
997 try stderr.print(" (+{d} more reused dependencies)\n", .{
996998 s.dependencies.items.len,
997999 });
9981000 }
......@@ -1129,11 +1131,11 @@ fn workerMakeOneStep(
11291131 const show_stderr = s.result_stderr.len > 0;
11301132
11311133 if (show_error_msgs or show_compile_errors or show_stderr) {
1132 std.debug.lockStdErr();
1134 var bw = std.debug.lockStdErr2();
11331135 defer std.debug.unlockStdErr();
11341136
11351137 const gpa = b.allocator;
1136 printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {};
1138 printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, &bw, run.prominent_compile_errors) catch {};
11371139 }
11381140
11391141 handle_result: {
......@@ -1190,7 +1192,7 @@ pub fn printErrorMessages(
11901192 gpa: Allocator,
11911193 failing_step: *Step,
11921194 options: std.zig.ErrorBundle.RenderOptions,
1193 stderr: File,
1195 stderr: *std.io.BufferedWriter,
11941196 prominent_compile_errors: bool,
11951197) !void {
11961198 // Provide context for where these error messages are coming from by
......@@ -1209,7 +1211,7 @@ pub fn printErrorMessages(
12091211 var indent: usize = 0;
12101212 while (step_stack.pop()) |s| : (indent += 1) {
12111213 if (indent > 0) {
1212 try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);
1214 try stderr.splatByteAll(' ', (indent - 1) * 3);
12131215 try printChildNodePrefix(stderr, ttyconf);
12141216 }
12151217
......@@ -1231,7 +1233,7 @@ pub fn printErrorMessages(
12311233 }
12321234
12331235 if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) {
1234 try failing_step.result_error_bundle.renderToWriter(options, stderr.writer());
1236 try failing_step.result_error_bundle.renderToWriter(options, stderr);
12351237 }
12361238
12371239 for (failing_step.result_error_msgs.items) |msg| {
......@@ -1243,27 +1245,29 @@ pub fn printErrorMessages(
12431245 }
12441246}
12451247
1246fn steps(builder: *std.Build, out_stream: anytype) !void {
1248fn steps(builder: *std.Build, bw: *std.io.BufferedWriter) !void {
12471249 const allocator = builder.allocator;
12481250 for (builder.top_level_steps.values()) |top_level_step| {
12491251 const name = if (&top_level_step.step == builder.default_step)
12501252 try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
12511253 else
12521254 top_level_step.step.name;
1253 try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
1255 try bw.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
12541256 }
12551257}
12561258
1257fn usage(b: *std.Build, out_stream: anytype) !void {
1258 try out_stream.print(
1259var stdout_buffer: [256]u8 = undefined;
1260
1261fn usage(b: *std.Build, bw: *std.io.BufferedWriter) !void {
1262 try bw.print(
12591263 \\Usage: {s} build [steps] [options]
12601264 \\
12611265 \\Steps:
12621266 \\
12631267 , .{b.graph.zig_exe});
1264 try steps(b, out_stream);
1268 try steps(b, bw);
12651269
1266 try out_stream.writeAll(
1270 try bw.writeAll(
12671271 \\
12681272 \\General Options:
12691273 \\ -p, --prefix [path] Where to install files (default: zig-out)
......@@ -1319,25 +1323,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13191323
13201324 const arena = b.allocator;
13211325 if (b.available_options_list.items.len == 0) {
1322 try out_stream.print(" (none)\n", .{});
1326 try bw.print(" (none)\n", .{});
13231327 } else {
13241328 for (b.available_options_list.items) |option| {
13251329 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
13261330 option.name,
13271331 @tagName(option.type_id),
13281332 });
1329 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
1333 try bw.print("{s:<30} {s}\n", .{ name, option.description });
13301334 if (option.enum_options) |enum_options| {
13311335 const padding = " " ** 33;
1332 try out_stream.writeAll(padding ++ "Supported Values:\n");
1336 try bw.writeAll(padding ++ "Supported Values:\n");
13331337 for (enum_options) |enum_option| {
1334 try out_stream.print(padding ++ " {s}\n", .{enum_option});
1338 try bw.print(padding ++ " {s}\n", .{enum_option});
13351339 }
13361340 }
13371341 }
13381342 }
13391343
1340 try out_stream.writeAll(
1344 try bw.writeAll(
13411345 \\
13421346 \\System Integration Options:
13431347 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
......@@ -1352,7 +1356,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13521356 \\
13531357 );
13541358 if (b.graph.system_library_options.entries.len == 0) {
1355 try out_stream.writeAll(" (none) -\n");
1359 try bw.writeAll(" (none) -\n");
13561360 } else {
13571361 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
13581362 const status = switch (v) {
......@@ -1360,11 +1364,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13601364 .declared_disabled => "no",
13611365 .user_enabled, .user_disabled => unreachable, // already emitted error
13621366 };
1363 try out_stream.print(" {s:<43} {s}\n", .{ k, status });
1367 try bw.print(" {s:<43} {s}\n", .{ k, status });
13641368 }
13651369 }
13661370
1367 try out_stream.writeAll(
1371 try bw.writeAll(
13681372 \\
13691373 \\Advanced Options:
13701374 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
lib/std/Build/Fuzz.zig+4-6
......@@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
112112
113113fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
114114 const gpa = run.step.owner.allocator;
115 const stderr = std.io.getStdErr();
116115
117116 const compile = run.producer.?;
118117 const prog_node = parent_prog_node.start(compile.step.name, 0);
......@@ -125,9 +124,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, par
125124 const show_stderr = compile.step.result_stderr.len > 0;
126125
127126 if (show_error_msgs or show_compile_errors or show_stderr) {
128 std.debug.lockStdErr();
127 var bw = std.debug.lockStdErr2();
129128 defer std.debug.unlockStdErr();
130 build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
129 build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, &bw, false) catch {};
131130 }
132131
133132 const rebuilt_bin_path = result catch |err| switch (err) {
......@@ -152,10 +151,9 @@ fn fuzzWorkerRun(
152151
153152 run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) {
154153 error.MakeFailed => {
155 const stderr = std.io.getStdErr();
156 std.debug.lockStdErr();
154 var bw = std.debug.lockStdErr2();
157155 defer std.debug.unlockStdErr();
158 build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
156 build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, &bw, false) catch {};
159157 return;
160158 },
161159 else => {
lib/std/Build/Step/CheckObject.zig+9-8
......@@ -1393,7 +1393,8 @@ const MachODumper = struct {
13931393 },
13941394 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
13951395 name_buf.clearRetainingCapacity();
1396 try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32));
1396 if (true) @panic("TODO fix this");
1397 //try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32));
13971398 try name_buf.append(0);
13981399 },
13991400 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
......@@ -2430,10 +2431,11 @@ const WasmDumper = struct {
24302431 return error.UnsupportedWasmVersion;
24312432 }
24322433
2433 var output = std.ArrayList(u8).init(gpa);
2434 var output: std.io.AllocatingWriter = undefined;
2435 const bw = output.init(gpa);
24342436 defer output.deinit();
2435 parseAndDumpInner(step, check, bytes, &fbs, &output) catch |err| switch (err) {
2436 error.EndOfStream => try output.appendSlice("\n<UnexpectedEndOfStream>"),
2437 parseAndDumpInner(step, check, bytes, &fbs, bw) catch |err| switch (err) {
2438 error.EndOfStream => try bw.writeAll("\n<UnexpectedEndOfStream>"),
24372439 else => |e| return e,
24382440 };
24392441 return output.toOwnedSlice();
......@@ -2443,11 +2445,10 @@ const WasmDumper = struct {
24432445 step: *Step,
24442446 check: Check,
24452447 bytes: []const u8,
2446 fbs: *std.io.FixedBufferStream([]const u8),
2447 output: *std.ArrayList(u8),
2448 fbs: *std.io.FixedBufferStream,
2449 bw: *std.io.BufferedWriter,
24482450 ) !void {
24492451 const reader = fbs.reader();
2450 const writer = output.writer();
24512452
24522453 switch (check.kind) {
24532454 .headers => {
......@@ -2457,7 +2458,7 @@ const WasmDumper = struct {
24572458 };
24582459
24592460 const section_length = try std.leb.readUleb128(u32, reader);
2460 try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], writer);
2461 try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], bw);
24612462 fbs.pos += section_length;
24622463 } else |_| {} // reached end of stream
24632464 },
lib/std/Build/Step/Compile.zig+6-6
......@@ -2040,17 +2040,17 @@ fn checkCompileErrors(compile: *Compile) !void {
20402040 .exact => |expect_lines| {
20412041 for (expect_lines) |expect_line| {
20422042 const actual_line = actual_line_it.next() orelse {
2043 try expected_generated.appendSlice(expect_line);
2044 try expected_generated.append('\n');
2043 try expected_generated.appendSlice(arena, expect_line);
2044 try expected_generated.append(arena, '\n');
20452045 continue;
20462046 };
20472047 if (matchCompileError(actual_line, expect_line)) {
2048 try expected_generated.appendSlice(actual_line);
2049 try expected_generated.append('\n');
2048 try expected_generated.appendSlice(arena, actual_line);
2049 try expected_generated.append(arena, '\n');
20502050 continue;
20512051 }
2052 try expected_generated.appendSlice(expect_line);
2053 try expected_generated.append('\n');
2052 try expected_generated.appendSlice(arena, expect_line);
2053 try expected_generated.append(arena, '\n');
20542054 }
20552055
20562056 if (mem.eql(u8, expected_generated.items, actual_errors)) return;
lib/std/Build/Step/ConfigHeader.zig+5-5
......@@ -599,14 +599,14 @@ fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !
599599 try output.appendSlice(if (b) " 1\n" else " 0\n");
600600 },
601601 .int => |i| {
602 try output.writer().print("%define {s} {d}\n", .{ name, i });
602 try output.print("%define {s} {d}\n", .{ name, i });
603603 },
604604 .ident => |ident| {
605 try output.writer().print("%define {s} {s}\n", .{ name, ident });
605 try output.print("%define {s} {s}\n", .{ name, ident });
606606 },
607607 .string => |string| {
608608 // TODO: use nasm-specific escaping instead of zig string literals
609 try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) });
609 try output.print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) });
610610 },
611611 }
612612}
......@@ -707,7 +707,7 @@ fn expand_variables_cmake(
707707 try result.append(if (b) '1' else '0');
708708 },
709709 .int => |i| {
710 try result.writer().print("{d}", .{i});
710 try result.print("{d}", .{i});
711711 },
712712 .ident, .string => |s| {
713713 try result.appendSlice(s);
......@@ -764,7 +764,7 @@ fn expand_variables_cmake(
764764 try result.append(if (b) '1' else '0');
765765 },
766766 .int => |i| {
767 try result.writer().print("{d}", .{i});
767 try result.print("{d}", .{i});
768768 },
769769 .ident, .string => |s| {
770770 try result.appendSlice(s);
lib/std/Uri.zig+4-3
......@@ -445,13 +445,14 @@ test remove_dot_segments {
445445
446446/// 5.2.3. Merge Paths
447447fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component {
448 var aux = std.io.fixedBufferStream(aux_buf.*);
448 var aux: std.io.BufferedWriter = undefined;
449 aux.initFixed(aux_buf.*);
449450 if (!base.isEmpty()) {
450 try aux.writer().print("{path}", .{base});
451 aux.print("{fpath}", .{base}) catch |err| return @errorCast(err);
451452 aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse
452453 return remove_dot_segments(new);
453454 }
454 try aux.writer().print("/{s}", .{new});
455 aux.print("/{s}", .{new}) catch |err| return @errorCast(err);
455456 const merged_path = remove_dot_segments(aux.getWritten());
456457 aux_buf.* = aux_buf.*[merged_path.percent_encoded.len..];
457458 return merged_path;
lib/std/array_list.zig+15-1
......@@ -338,6 +338,12 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty
338338 @memcpy(self.items[old_len..][0..items.len], items);
339339 }
340340
341 pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
342 var unmanaged = self.moveToUnmanaged();
343 try unmanaged.print(self.allocator, fmt, args);
344 self.* = unmanaged.toManaged(self.allocator);
345 }
346
341347 /// Append a value to the list `n` times.
342348 /// Allocates more memory as necessary.
343349 /// Invalidates element pointers if additional memory is needed.
......@@ -902,7 +908,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig
902908 var aw: std.io.AllocatingWriter = undefined;
903909 const bw = aw.fromArrayList(gpa, self);
904910 defer self.* = aw.toArrayList();
905 bw.print(fmt, args) catch return error.OutOfMemory;
911 return @errorCast(bw.print(fmt, args));
912 }
913
914 pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void {
915 comptime assert(T == u8);
916 var bw: std.io.BufferedWriter = undefined;
917 bw.initFixed(self.unusedCapacitySlice());
918 bw.print(fmt, args) catch unreachable;
919 self.items.len += bw.end;
906920 }
907921
908922 /// Append a value to the list `n` times.
lib/std/http/Server.zig+64-14
......@@ -421,9 +421,9 @@ pub const Request = struct {
421421 try request.server.connection.stream.writeAll(h.items);
422422 return;
423423 }
424 h.fixedWriter().print("{s} {d} {s}\r\n", .{
424 h.printAssumeCapacity("{s} {d} {s}\r\n", .{
425425 @tagName(options.version), @intFromEnum(options.status), phrase,
426 }) catch unreachable;
426 });
427427
428428 switch (options.version) {
429429 .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
......@@ -434,7 +434,7 @@ pub const Request = struct {
434434 .none => {},
435435 .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
436436 } else {
437 h.fixedWriter().print("content-length: {d}\r\n", .{content.len}) catch unreachable;
437 h.printAssumeCapacity("content-length: {d}\r\n", .{content.len});
438438 }
439439
440440 var chunk_header_buffer: [18]u8 = undefined;
......@@ -573,9 +573,9 @@ pub const Request = struct {
573573 h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n");
574574 break :eb true;
575575 } else eb: {
576 h.fixedWriter().print("{s} {d} {s}\r\n", .{
576 h.printAssumeCapacity("{s} {d} {s}\r\n", .{
577577 @tagName(o.version), @intFromEnum(o.status), phrase,
578 }) catch unreachable;
578 });
579579
580580 switch (o.version) {
581581 .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
......@@ -586,7 +586,7 @@ pub const Request = struct {
586586 .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
587587 .none => {},
588588 } else if (options.content_length) |len| {
589 h.fixedWriter().print("content-length: {d}\r\n", .{len}) catch unreachable;
589 h.printAssumeCapacity("content-length: {d}\r\n", .{len});
590590 } else {
591591 h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n");
592592 }
......@@ -889,12 +889,34 @@ pub const Response = struct {
889889 /// when the end of stream occurs by calling `end`.
890890 pub fn write(r: *Response, bytes: []const u8) WriteError!usize {
891891 switch (r.transfer_encoding) {
892 .content_length, .none => return write_cl(r, bytes),
893 .chunked => return write_chunked(r, bytes),
892 .content_length, .none => return @errorCast(cl_writeSplat(r, &.{bytes}, 1)),
893 .chunked => return @errorCast(chunked_writeSplat(r, &.{bytes}, 1)),
894894 }
895895 }
896896
897 fn write_cl(context: *const anyopaque, bytes: []const u8) WriteError!usize {
897 fn cl_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize {
898 _ = splat;
899 return cl_write(context, data[0]); // TODO: try to send all the data
900 }
901
902 fn cl_writeFile(
903 context: *anyopaque,
904 file: std.fs.File,
905 offset: u64,
906 len: std.io.Writer.VTable.FileLen,
907 headers_and_trailers: []const []const u8,
908 headers_len: usize,
909 ) anyerror!usize {
910 _ = context;
911 _ = file;
912 _ = offset;
913 _ = len;
914 _ = headers_and_trailers;
915 _ = headers_len;
916 return error.Unimplemented;
917 }
918
919 fn cl_write(context: *anyopaque, bytes: []const u8) WriteError!usize {
898920 const r: *Response = @constCast(@alignCast(@ptrCast(context)));
899921
900922 var trash: u64 = std.math.maxInt(u64);
......@@ -944,7 +966,29 @@ pub const Response = struct {
944966 return bytes.len;
945967 }
946968
947 fn write_chunked(context: *const anyopaque, bytes: []const u8) WriteError!usize {
969 fn chunked_writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize {
970 _ = splat;
971 return chunked_write(context, data[0]); // TODO: try to send all the data
972 }
973
974 fn chunked_writeFile(
975 context: *anyopaque,
976 file: std.fs.File,
977 offset: u64,
978 len: std.io.Writer.VTable.FileLen,
979 headers_and_trailers: []const []const u8,
980 headers_len: usize,
981 ) anyerror!usize {
982 _ = context;
983 _ = file;
984 _ = offset;
985 _ = len;
986 _ = headers_and_trailers;
987 _ = headers_len;
988 return error.Unimplemented;
989 }
990
991 fn chunked_write(context: *anyopaque, bytes: []const u8) WriteError!usize {
948992 const r: *Response = @constCast(@alignCast(@ptrCast(context)));
949993 assert(r.transfer_encoding == .chunked);
950994
......@@ -1115,11 +1159,17 @@ pub const Response = struct {
11151159 r.chunk_len = 0;
11161160 }
11171161
1118 pub fn writer(r: *Response) std.io.AnyWriter {
1162 pub fn writer(r: *Response) std.io.Writer {
11191163 return .{
1120 .writeFn = switch (r.transfer_encoding) {
1121 .none, .content_length => write_cl,
1122 .chunked => write_chunked,
1164 .vtable = switch (r.transfer_encoding) {
1165 .none, .content_length => &.{
1166 .writeSplat = cl_writeSplat,
1167 .writeFile = cl_writeFile,
1168 },
1169 .chunked => &.{
1170 .writeSplat = chunked_writeSplat,
1171 .writeFile = chunked_writeFile,
1172 },
11231173 },
11241174 .context = r,
11251175 };
lib/std/io.zig-13
......@@ -123,19 +123,6 @@ pub fn GenericReader(
123123 return @errorCast(self.any().readAllAlloc(allocator, max_size));
124124 }
125125
126 pub inline fn readUntilDelimiterArrayList(
127 self: Self,
128 array_list: *std.ArrayList(u8),
129 delimiter: u8,
130 max_size: usize,
131 ) (NoEofError || Allocator.Error || error{StreamTooLong})!void {
132 return @errorCast(self.any().readUntilDelimiterArrayList(
133 array_list,
134 delimiter,
135 max_size,
136 ));
137 }
138
139126 pub inline fn readUntilDelimiterAlloc(
140127 self: Self,
141128 allocator: Allocator,
lib/std/io/AllocatingWriter.zig+2
......@@ -17,6 +17,8 @@ const assert = std.debug.assert;
1717/// returning a slice that includes both.
1818written: []u8,
1919allocator: std.mem.Allocator,
20/// When using this API, it is not necessary to call
21/// `std.io.BufferedWriter.flush`.
2022buffered_writer: std.io.BufferedWriter,
2123
2224const vtable: std.io.Writer.VTable = .{
lib/std/io/BufferedWriter.zig+3-3
......@@ -33,7 +33,7 @@ pub fn writer(bw: *BufferedWriter) Writer {
3333 return .{
3434 .context = bw,
3535 .vtable = &.{
36 .write = passthru_writeSplat,
36 .writeSplat = passthru_writeSplat,
3737 .writeFile = passthru_writeFile,
3838 },
3939 };
......@@ -1003,7 +1003,7 @@ pub fn printFloat(
10031003 'x' => {
10041004 var sub_bw: BufferedWriter = undefined;
10051005 sub_bw.initFixed(&buf);
1006 sub_bw.printFloatHexadecimal(value, options) catch unreachable;
1006 sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable;
10071007 return alignBufferOptions(bw, sub_bw.getWritten(), options);
10081008 },
10091009 else => invalidFmtError(fmt, value),
......@@ -1103,7 +1103,7 @@ pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision:
11031103 // Add trailing zeros if explicitly requested.
11041104 if (opt_precision) |precision| if (precision > 0) {
11051105 if (precision > trimmed.len)
1106 try bw.writeByteNTimes('0', precision - trimmed.len);
1106 try bw.splatByteAll('0', precision - trimmed.len);
11071107 };
11081108 try bw.writeAll("p");
11091109 try printIntOptions(bw, exponent - exponent_bias, 10, .lower, .{});
lib/std/io/Reader.zig+4-98
......@@ -93,108 +93,14 @@ pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyer
9393 return try array_list.toOwnedSlice();
9494}
9595
96/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
97/// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found.
98/// Does not include the delimiter in the result.
99/// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
100/// `std.ArrayList` is populated with `max_size` bytes from the stream.
101pub fn readUntilDelimiterArrayList(
102 self: Self,
103 array_list: *std.ArrayList(u8),
104 delimiter: u8,
105 max_size: usize,
106) anyerror!void {
107 array_list.shrinkRetainingCapacity(0);
108 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
109}
110
111/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
112/// Allocates enough memory to read until `delimiter`. If the allocated
113/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
114/// Caller owns returned memory.
115/// If this function returns an error, the contents from the stream read so far are lost.
116pub fn readUntilDelimiterAlloc(
117 self: Self,
118 allocator: mem.Allocator,
119 delimiter: u8,
120 max_size: usize,
121) anyerror![]u8 {
122 var array_list = std.ArrayList(u8).init(allocator);
123 defer array_list.deinit();
124 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
125 return try array_list.toOwnedSlice();
126}
127
128/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
129/// Reads from the stream until specified byte is found. If the buffer is not
130/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
131/// If end-of-stream is found, `error.EndOfStream` is returned.
132/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
133/// delimiter byte is written to the output buffer but is not included
134/// in the returned slice.
135pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) anyerror![]u8 {
136 var fbs = std.io.fixedBufferStream(buf);
137 try self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len);
138 const output = fbs.getWritten();
139 buf[output.len] = delimiter; // emulating old behaviour
140 return output;
141}
142
143/// Deprecated: use `streamUntilDelimiter` with ArrayList's (or any other's) writer instead.
144/// Allocates enough memory to read until `delimiter` or end-of-stream.
145/// If the allocated memory would be greater than `max_size`, returns
146/// `error.StreamTooLong`. If end-of-stream is found, returns the rest
147/// of the stream. If this function is called again after that, returns
148/// null.
149/// Caller owns returned memory.
150/// If this function returns an error, the contents from the stream read so far are lost.
151pub fn readUntilDelimiterOrEofAlloc(
152 self: Self,
153 allocator: mem.Allocator,
154 delimiter: u8,
155 max_size: usize,
156) anyerror!?[]u8 {
157 var array_list = std.ArrayList(u8).init(allocator);
158 defer array_list.deinit();
159 self.streamUntilDelimiter(array_list.writer(), delimiter, max_size) catch |err| switch (err) {
160 error.EndOfStream => if (array_list.items.len == 0) {
161 return null;
162 },
163 else => |e| return e,
164 };
165 return try array_list.toOwnedSlice();
166}
167
168/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
169/// Reads from the stream until specified byte is found. If the buffer is not
170/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
171/// If end-of-stream is found, returns the rest of the stream. If this
172/// function is called again after that, returns null.
173/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
174/// delimiter byte is written to the output buffer but is not included
175/// in the returned slice.
176pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) anyerror!?[]u8 {
177 var fbs = std.io.fixedBufferStream(buf);
178 self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len) catch |err| switch (err) {
179 error.EndOfStream => if (fbs.getWritten().len == 0) {
180 return null;
181 },
182
183 else => |e| return e,
184 };
185 const output = fbs.getWritten();
186 buf[output.len] = delimiter; // emulating old behaviour
187 return output;
188}
189
190/// Appends to the `writer` contents by reading from the stream until `delimiter` is found.
96/// Appends to `bw` contents by reading from the stream until `delimiter` is found.
19197/// Does not write the delimiter itself.
19298/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,
19399/// returns `error.StreamTooLong` and finishes appending.
194100/// If `optional_max_size` is null, appending is unbounded.
195101pub fn streamUntilDelimiter(
196102 self: Self,
197 writer: anytype,
103 bw: *std.io.BufferedWriter,
198104 delimiter: u8,
199105 optional_max_size: ?usize,
200106) anyerror!void {
......@@ -202,14 +108,14 @@ pub fn streamUntilDelimiter(
202108 for (0..max_size) |_| {
203109 const byte: u8 = try self.readByte();
204110 if (byte == delimiter) return;
205 try writer.writeByte(byte);
111 try bw.writeByte(byte);
206112 }
207113 return error.StreamTooLong;
208114 } else {
209115 while (true) {
210116 const byte: u8 = try self.readByte();
211117 if (byte == delimiter) return;
212 try writer.writeByte(byte);
118 try bw.writeByte(byte);
213119 }
214120 // Can not throw `error.StreamTooLong` since there are no boundary.
215121 }
lib/std/tar/writer.zig+156-167
......@@ -2,187 +2,176 @@ const std = @import("std");
22const assert = std.debug.assert;
33const testing = std.testing;
44
5/// Creates tar Writer which will write tar content to the `underlying_writer`.
6/// Use setRoot to nest all following entries under single root. If file don't
7/// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will
8/// be used for long names. Options enables setting file premission mode and
9/// mtime. Default is to use current time for mtime and 0o664 for file mode.
10pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) {
11 return .{ .underlying_writer = underlying_writer };
12}
13
14pub fn Writer(comptime WriterType: type) type {
15 return struct {
16 const block_size = @sizeOf(Header);
17 const empty_block: [block_size]u8 = [_]u8{0} ** block_size;
18
19 /// Options for writing file/dir/link. If left empty 0o664 is used for
20 /// file mode and current time for mtime.
21 pub const Options = struct {
22 /// File system permission mode.
23 mode: u32 = 0,
24 /// File system modification time.
25 mtime: u64 = 0,
26 };
27 const Self = @This();
5pub const Writer = struct {
6 const block_size = @sizeOf(Header);
7 const empty_block: [block_size]u8 = [_]u8{0} ** block_size;
8
9 /// Options for writing file/dir/link. If left empty 0o664 is used for
10 /// file mode and current time for mtime.
11 pub const Options = struct {
12 /// File system permission mode.
13 mode: u32 = 0,
14 /// File system modification time.
15 mtime: u64 = 0,
16 };
17 const Self = @This();
2818
29 underlying_writer: WriterType,
30 prefix: []const u8 = "",
31 mtime_now: u64 = 0,
19 underlying_writer: *std.io.BufferedWriter,
20 prefix: []const u8 = "",
21 mtime_now: u64 = 0,
3222
33 /// Sets prefix for all other write* method paths.
34 pub fn setRoot(self: *Self, root: []const u8) !void {
35 if (root.len > 0)
36 try self.writeDir(root, .{});
23 /// Sets prefix for all other write* method paths.
24 pub fn setRoot(self: *Self, root: []const u8) !void {
25 if (root.len > 0)
26 try self.writeDir(root, .{});
3727
38 self.prefix = root;
39 }
28 self.prefix = root;
29 }
4030
41 /// Writes directory.
42 pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void {
43 try self.writeHeader(.directory, sub_path, "", 0, opt);
44 }
31 /// Writes directory.
32 pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void {
33 try self.writeHeader(.directory, sub_path, "", 0, opt);
34 }
4535
46 /// Writes file system file.
47 pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void {
48 const stat = try file.stat();
49 const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
36 /// Writes file system file.
37 pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void {
38 const stat = try file.stat();
39 const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
5040
51 var header = Header{};
52 try self.setPath(&header, sub_path);
53 try header.setSize(stat.size);
54 try header.setMtime(mtime);
55 try header.write(self.underlying_writer);
41 var header = Header{};
42 try self.setPath(&header, sub_path);
43 try header.setSize(stat.size);
44 try header.setMtime(mtime);
45 try header.write(self.underlying_writer);
5646
57 try self.underlying_writer.writeFile(file);
58 try self.writePadding(stat.size);
59 }
47 try self.underlying_writer.writeFileAll(file, .{ .len = .init(stat.size) });
48 try self.writePadding(stat.size);
49 }
6050
61 /// Writes file reading file content from `reader`. Number of bytes in
62 /// reader must be equal to `size`.
63 pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void {
64 try self.writeHeader(.regular, sub_path, "", @intCast(size), opt);
51 /// Writes file reading file content from `reader`. Number of bytes in
52 /// reader must be equal to `size`.
53 pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void {
54 try self.writeHeader(.regular, sub_path, "", @intCast(size), opt);
6555
66 var counting_reader = std.io.countingReader(reader);
67 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
68 try fifo.pump(counting_reader.reader(), self.underlying_writer);
69 if (counting_reader.bytes_read != size) return error.WrongReaderSize;
70 try self.writePadding(size);
71 }
56 var counting_reader = std.io.countingReader(reader);
57 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
58 try fifo.pump(counting_reader.reader(), self.underlying_writer);
59 if (counting_reader.bytes_read != size) return error.WrongReaderSize;
60 try self.writePadding(size);
61 }
7262
73 /// Writes file using bytes buffer `content` for size and file content.
74 pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void {
75 try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt);
76 try self.underlying_writer.writeAll(content);
77 try self.writePadding(content.len);
78 }
63 /// Writes file using bytes buffer `content` for size and file content.
64 pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void {
65 try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt);
66 try self.underlying_writer.writeAll(content);
67 try self.writePadding(content.len);
68 }
7969
80 /// Writes symlink.
81 pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void {
82 try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt);
83 }
70 /// Writes symlink.
71 pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void {
72 try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt);
73 }
8474
85 /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
86 /// default for entry mode .
87 pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
88 switch (entry.kind) {
89 .directory => {
90 try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
91 },
92 .file => {
93 var file = try entry.dir.openFile(entry.basename, .{});
94 defer file.close();
95 try self.writeFile(entry.path, file);
96 },
97 .sym_link => {
98 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
99 const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);
100 try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
101 },
102 else => {
103 return error.UnsupportedWalkerEntryKind;
104 },
105 }
75 /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
76 /// default for entry mode .
77 pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
78 switch (entry.kind) {
79 .directory => {
80 try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
81 },
82 .file => {
83 var file = try entry.dir.openFile(entry.basename, .{});
84 defer file.close();
85 try self.writeFile(entry.path, file);
86 },
87 .sym_link => {
88 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
89 const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);
90 try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
91 },
92 else => {
93 return error.UnsupportedWalkerEntryKind;
94 },
10695 }
96 }
10797
108 fn writeHeader(
109 self: *Self,
110 typeflag: Header.FileType,
111 sub_path: []const u8,
112 link_name: []const u8,
113 size: u64,
114 opt: Options,
115 ) !void {
116 var header = Header.init(typeflag);
117 try self.setPath(&header, sub_path);
118 try header.setSize(size);
119 try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow());
120 if (opt.mode != 0)
121 try header.setMode(opt.mode);
122 if (typeflag == .symbolic_link)
123 header.setLinkname(link_name) catch |err| switch (err) {
124 error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}),
125 else => return err,
126 };
127 try header.write(self.underlying_writer);
128 }
98 fn writeHeader(
99 self: *Self,
100 typeflag: Header.FileType,
101 sub_path: []const u8,
102 link_name: []const u8,
103 size: u64,
104 opt: Options,
105 ) !void {
106 var header = Header.init(typeflag);
107 try self.setPath(&header, sub_path);
108 try header.setSize(size);
109 try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow());
110 if (opt.mode != 0)
111 try header.setMode(opt.mode);
112 if (typeflag == .symbolic_link)
113 header.setLinkname(link_name) catch |err| switch (err) {
114 error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}),
115 else => return err,
116 };
117 try header.write(self.underlying_writer);
118 }
129119
130 fn mtimeNow(self: *Self) u64 {
131 if (self.mtime_now == 0)
132 self.mtime_now = @intCast(std.time.timestamp());
133 return self.mtime_now;
134 }
120 fn mtimeNow(self: *Self) u64 {
121 if (self.mtime_now == 0)
122 self.mtime_now = @intCast(std.time.timestamp());
123 return self.mtime_now;
124 }
135125
136 fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
137 const stat = try entry.dir.statFile(entry.basename);
138 return @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
139 }
126 fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
127 const stat = try entry.dir.statFile(entry.basename);
128 return @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
129 }
140130
141 /// Writes path in posix header, if don't fit (in name+prefix; 100+155
142 /// bytes) writes it in gnu extended header.
143 fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void {
144 header.setPath(self.prefix, sub_path) catch |err| switch (err) {
145 error.NameTooLong => {
146 // write extended header
147 const buffers: []const []const u8 = if (self.prefix.len == 0)
148 &.{sub_path}
149 else
150 &.{ self.prefix, "/", sub_path };
151 try self.writeExtendedHeader(.gnu_long_name, buffers);
152 },
153 else => return err,
154 };
155 }
131 /// Writes path in posix header, if don't fit (in name+prefix; 100+155
132 /// bytes) writes it in gnu extended header.
133 fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void {
134 header.setPath(self.prefix, sub_path) catch |err| switch (err) {
135 error.NameTooLong => {
136 // write extended header
137 const buffers: []const []const u8 = if (self.prefix.len == 0)
138 &.{sub_path}
139 else
140 &.{ self.prefix, "/", sub_path };
141 try self.writeExtendedHeader(.gnu_long_name, buffers);
142 },
143 else => return err,
144 };
145 }
156146
157 /// Writes gnu extended header: gnu_long_name or gnu_long_link.
158 fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void {
159 var len: usize = 0;
160 for (buffers) |buf|
161 len += buf.len;
162
163 var header = Header.init(typeflag);
164 try header.setSize(len);
165 try header.write(self.underlying_writer);
166 for (buffers) |buf|
167 try self.underlying_writer.writeAll(buf);
168 try self.writePadding(len);
169 }
147 /// Writes gnu extended header: gnu_long_name or gnu_long_link.
148 fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void {
149 var len: usize = 0;
150 for (buffers) |buf|
151 len += buf.len;
152
153 var header = Header.init(typeflag);
154 try header.setSize(len);
155 try header.write(self.underlying_writer);
156 for (buffers) |buf|
157 try self.underlying_writer.writeAll(buf);
158 try self.writePadding(len);
159 }
170160
171 fn writePadding(self: *Self, bytes: u64) !void {
172 const pos: usize = @intCast(bytes % block_size);
173 if (pos == 0) return;
174 try self.underlying_writer.writeAll(empty_block[pos..]);
175 }
161 fn writePadding(self: *Self, bytes: u64) !void {
162 const pos: usize = @intCast(bytes % block_size);
163 if (pos == 0) return;
164 try self.underlying_writer.writeAll(empty_block[pos..]);
165 }
176166
177 /// Tar should finish with two zero blocks, but 'reasonable system must
178 /// not assume that such a block exists when reading an archive' (from
179 /// reference). In practice it is safe to skip this finish.
180 pub fn finish(self: *Self) !void {
181 try self.underlying_writer.writeAll(&empty_block);
182 try self.underlying_writer.writeAll(&empty_block);
183 }
184 };
185}
167 /// Tar should finish with two zero blocks, but 'reasonable system must
168 /// not assume that such a block exists when reading an archive' (from
169 /// reference). In practice it is safe to skip this finish.
170 pub fn finish(self: *Self) !void {
171 try self.underlying_writer.writeAll(&empty_block);
172 try self.underlying_writer.writeAll(&empty_block);
173 }
174};
186175
187176/// A struct that is exactly 512 bytes and matches tar file format. This is
188177/// intended to be used for outputting tar files; for parsing there is
......@@ -431,14 +420,14 @@ test "write files" {
431420 {
432421 const root = "root";
433422
434 var output = std.ArrayList(u8).init(testing.allocator);
423 var output: std.io.AllocatingWriter = undefined;
424 var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) };
435425 defer output.deinit();
436 var wrt = writer(output.writer());
437426 try wrt.setRoot(root);
438427 for (files) |file|
439428 try wrt.writeFileBytes(file.path, file.content, .{});
440429
441 var input = std.io.fixedBufferStream(output.items);
430 var input: std.io.FixedBufferStream = .{ .buffer = output.getWritten() };
442431 var iter = std.tar.iterator(
443432 input.reader(),
444433 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },
......@@ -467,15 +456,15 @@ test "write files" {
467456 }
468457 // without root
469458 {
470 var output = std.ArrayList(u8).init(testing.allocator);
459 var output: std.io.AllocatingWriter = undefined;
460 var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) };
471461 defer output.deinit();
472 var wrt = writer(output.writer());
473462 for (files) |file| {
474463 var content = std.io.fixedBufferStream(file.content);
475464 try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{});
476465 }
477466
478 var input = std.io.fixedBufferStream(output.items);
467 var input: std.io.FixedBufferStream = .{ .buffer = output.getWritten() };
479468 var iter = std.tar.iterator(
480469 input.reader(),
481470 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },
lib/std/zig.zig+4-4
......@@ -635,7 +635,7 @@ pub fn parseTargetQueryOrReportFatalError(
635635 var help_text = std.ArrayList(u8).init(allocator);
636636 defer help_text.deinit();
637637 for (diags.arch.?.allCpuModels()) |cpu| {
638 help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help;
638 help_text.print(" {s}\n", .{cpu.name}) catch break :help;
639639 }
640640 std.log.info("available CPUs for architecture '{s}':\n{s}", .{
641641 @tagName(diags.arch.?), help_text.items,
......@@ -648,7 +648,7 @@ pub fn parseTargetQueryOrReportFatalError(
648648 var help_text = std.ArrayList(u8).init(allocator);
649649 defer help_text.deinit();
650650 for (diags.arch.?.allFeaturesList()) |feature| {
651 help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help;
651 help_text.print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help;
652652 }
653653 std.log.info("available CPU features for architecture '{s}':\n{s}", .{
654654 @tagName(diags.arch.?), help_text.items,
......@@ -661,7 +661,7 @@ pub fn parseTargetQueryOrReportFatalError(
661661 var help_text = std.ArrayList(u8).init(allocator);
662662 defer help_text.deinit();
663663 inline for (@typeInfo(std.Target.ObjectFormat).@"enum".fields) |field| {
664 help_text.writer().print(" {s}\n", .{field.name}) catch break :help;
664 help_text.print(" {s}\n", .{field.name}) catch break :help;
665665 }
666666 std.log.info("available object formats:\n{s}", .{help_text.items});
667667 }
......@@ -672,7 +672,7 @@ pub fn parseTargetQueryOrReportFatalError(
672672 var help_text = std.ArrayList(u8).init(allocator);
673673 defer help_text.deinit();
674674 inline for (@typeInfo(std.Target.Cpu.Arch).@"enum".fields) |field| {
675 help_text.writer().print(" {s}\n", .{field.name}) catch break :help;
675 help_text.print(" {s}\n", .{field.name}) catch break :help;
676676 }
677677 std.log.info("available architectures:\n{s} native\n", .{help_text.items});
678678 }
lib/std/zig/ErrorBundle.zig+8-8
......@@ -194,11 +194,11 @@ fn renderErrorMessageToWriter(
194194) anyerror!void {
195195 const ttyconf = options.ttyconf;
196196 var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() };
197 const counting_bw = counting_writer.unbufferedWriter();
197 var counting_bw = counting_writer.unbufferedWriter();
198198 const err_msg = eb.getErrorMessage(err_msg_index);
199199 if (err_msg.src_loc != .none) {
200200 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
201 try counting_bw.writeByteNTimes(' ', indent);
201 try counting_bw.splatByteAll(' ', indent);
202202 try ttyconf.setColor(bw, .bold);
203203 try counting_bw.print("{s}:{d}:{d}: ", .{
204204 eb.nullTerminatedString(src.data.src_path),
......@@ -210,7 +210,7 @@ fn renderErrorMessageToWriter(
210210 try counting_bw.writeAll(": ");
211211 // This is the length of the part before the error message:
212212 // e.g. "file.zig:4:5: error: "
213 const prefix_len: usize = @intCast(counting_bw.context.bytes_written);
213 const prefix_len: usize = @intCast(counting_writer.bytes_written);
214214 try ttyconf.setColor(bw, .reset);
215215 try ttyconf.setColor(bw, .bold);
216216 if (err_msg.count == 1) {
......@@ -233,11 +233,11 @@ fn renderErrorMessageToWriter(
233233 const before_caret = src.data.span_main - src.data.span_start;
234234 // -1 since span.main includes the caret
235235 const after_caret = src.data.span_end -| src.data.span_main -| 1;
236 try bw.writeByteNTimes(' ', src.data.column - before_caret);
236 try bw.splatByteAll(' ', src.data.column - before_caret);
237237 try ttyconf.setColor(bw, .green);
238 try bw.writeByteNTimes('~', before_caret);
238 try bw.splatByteAll('~', before_caret);
239239 try bw.writeByte('^');
240 try bw.writeByteNTimes('~', after_caret);
240 try bw.splatByteAll('~', after_caret);
241241 try bw.writeByte('\n');
242242 try ttyconf.setColor(bw, .reset);
243243 }
......@@ -277,7 +277,7 @@ fn renderErrorMessageToWriter(
277277 }
278278 } else {
279279 try ttyconf.setColor(bw, color);
280 try bw.writeByteNTimes(' ', indent);
280 try bw.splatByteAll(' ', indent);
281281 try bw.writeAll(kind);
282282 try bw.writeAll(": ");
283283 try ttyconf.setColor(bw, .reset);
......@@ -306,7 +306,7 @@ fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter,
306306 try bw.writeAll(line);
307307 if (lines.index == null) break;
308308 try bw.writeByte('\n');
309 try bw.writeByteNTimes(' ', indent);
309 try bw.splatByteAll(' ', indent);
310310 }
311311}
312312
lib/std/zig/LibCInstallation.zig+2-2
......@@ -370,7 +370,7 @@ fn findNativeIncludeDirWindows(
370370
371371 for (installs) |install| {
372372 result_buf.shrinkAndFree(0);
373 try result_buf.writer().print("{s}\\Include\\{s}\\ucrt", .{ install.path, install.version });
373 try result_buf.print("{s}\\Include\\{s}\\ucrt", .{ install.path, install.version });
374374
375375 var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
376376 error.FileNotFound,
......@@ -417,7 +417,7 @@ fn findNativeCrtDirWindows(
417417
418418 for (installs) |install| {
419419 result_buf.shrinkAndFree(0);
420 try result_buf.writer().print("{s}\\Lib\\{s}\\ucrt\\{s}", .{ install.path, install.version, arch_sub_dir });
420 try result_buf.print("{s}\\Lib\\{s}\\ucrt\\{s}", .{ install.path, install.version, arch_sub_dir });
421421
422422 var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
423423 error.FileNotFound,