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 {...@@ -378,13 +378,16 @@ pub fn main() !void {
378378
379 validateSystemLibraryOptions(builder);379 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
383 if (help_menu)386 if (help_menu)
384 return usage(builder, stdout_writer);387 return usage(builder, &stdout_writer);
385388
386 if (steps_menu)389 if (steps_menu)
387 return steps(builder, stdout_writer);390 return steps(builder, &stdout_writer);
388391
389 var run: Run = .{392 var run: Run = .{
390 .max_rss = max_rss,393 .max_rss = max_rss,
...@@ -696,24 +699,23 @@ fn runStepNames(...@@ -696,24 +699,23 @@ fn runStepNames(
696 const ttyconf = run.ttyconf;699 const ttyconf = run.ttyconf;
697700
698 if (run.summary != .none) {701 if (run.summary != .none) {
699 std.debug.lockStdErr();702 var bw = std.debug.lockStdErr2();
700 defer std.debug.unlockStdErr();703 defer std.debug.unlockStdErr();
701 const stderr = run.stderr;
702704
703 const total_count = success_count + failure_count + pending_count + skipped_count;705 const total_count = success_count + failure_count + pending_count + skipped_count;
704 ttyconf.setColor(stderr, .cyan) catch {};706 ttyconf.setColor(&bw, .cyan) catch {};
705 stderr.writeAll("Build Summary:") catch {};707 bw.writeAll("Build Summary:") catch {};
706 ttyconf.setColor(stderr, .reset) catch {};708 ttyconf.setColor(&bw, .reset) catch {};
707 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};709 bw.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
708 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};710 if (skipped_count > 0) bw.print("; {d} skipped", .{skipped_count}) catch {};
709 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_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 {};713 if (test_count > 0) bw.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 {};714 if (test_skip_count > 0) bw.print("; {d} skipped", .{test_skip_count}) catch {};
713 if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};715 if (test_fail_count > 0) bw.print("; {d} failed", .{test_fail_count}) catch {};
714 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_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
718 // Print a fancy tree with build results.720 // Print a fancy tree with build results.
719 var step_stack_copy = try step_stack.clone(gpa);721 var step_stack_copy = try step_stack.clone(gpa);
...@@ -722,7 +724,7 @@ fn runStepNames(...@@ -722,7 +724,7 @@ fn runStepNames(
722 var print_node: PrintNode = .{ .parent = null };724 var print_node: PrintNode = .{ .parent = null };
723 if (step_names.len == 0) {725 if (step_names.len == 0) {
724 print_node.last = true;726 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 {};
726 } else {728 } else {
727 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {729 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
728 var i: usize = step_names.len;730 var i: usize = step_names.len;
...@@ -741,7 +743,7 @@ fn runStepNames(...@@ -741,7 +743,7 @@ fn runStepNames(
741 for (step_names, 0..) |step_name, i| {743 for (step_names, 0..) |step_name, i| {
742 const tls = b.top_level_steps.get(step_name).?;744 const tls = b.top_level_steps.get(step_name).?;
743 print_node.last = i + 1 == last_index;745 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 {};
745 }747 }
746 }748 }
747 }749 }
...@@ -775,7 +777,7 @@ const PrintNode = struct {...@@ -775,7 +777,7 @@ const PrintNode = struct {
775 last: bool = false,777 last: bool = false,
776};778};
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 {
779 const parent = node.parent orelse return;781 const parent = node.parent orelse return;
780 if (parent.parent == null) return;782 if (parent.parent == null) return;
781 try printPrefix(parent, stderr, ttyconf);783 try printPrefix(parent, stderr, ttyconf);
...@@ -789,7 +791,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void...@@ -789,7 +791,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void
789 }791 }
790}792}
791793
792fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {794fn printChildNodePrefix(stderr: *std.io.BufferedWriter, ttyconf: std.io.tty.Config) !void {
793 try stderr.writeAll(switch (ttyconf) {795 try stderr.writeAll(switch (ttyconf) {
794 .no_color, .windows_api => "+- ",796 .no_color, .windows_api => "+- ",
795 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─797 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
...@@ -798,7 +800,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {...@@ -798,7 +800,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
798800
799fn printStepStatus(801fn printStepStatus(
800 s: *Step,802 s: *Step,
801 stderr: File,803 stderr: *std.io.BufferedWriter,
802 ttyconf: std.io.tty.Config,804 ttyconf: std.io.tty.Config,
803 run: *const Run,805 run: *const Run,
804) !void {806) !void {
...@@ -820,10 +822,10 @@ fn printStepStatus(...@@ -820,10 +822,10 @@ fn printStepStatus(
820 try stderr.writeAll(" cached");822 try stderr.writeAll(" cached");
821 } else if (s.test_results.test_count > 0) {823 } else if (s.test_results.test_count > 0) {
822 const pass_count = s.test_results.passCount();824 const pass_count = s.test_results.passCount();
823 try stderr.writer().print(" {d} passed", .{pass_count});825 try stderr.print(" {d} passed", .{pass_count});
824 if (s.test_results.skip_count > 0) {826 if (s.test_results.skip_count > 0) {
825 try ttyconf.setColor(stderr, .yellow);827 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});
827 }829 }
828 } else {830 } else {
829 try stderr.writeAll(" success");831 try stderr.writeAll(" success");
...@@ -832,15 +834,15 @@ fn printStepStatus(...@@ -832,15 +834,15 @@ fn printStepStatus(
832 if (s.result_duration_ns) |ns| {834 if (s.result_duration_ns) |ns| {
833 try ttyconf.setColor(stderr, .dim);835 try ttyconf.setColor(stderr, .dim);
834 if (ns >= std.time.ns_per_min) {836 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});
836 } else if (ns >= std.time.ns_per_s) {838 } 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});
838 } else if (ns >= std.time.ns_per_ms) {840 } 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});
840 } else if (ns >= std.time.ns_per_us) {842 } 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});
842 } else {844 } else {
843 try stderr.writer().print(" {d}ns", .{ns});845 try stderr.print(" {d}ns", .{ns});
844 }846 }
845 try ttyconf.setColor(stderr, .reset);847 try ttyconf.setColor(stderr, .reset);
846 }848 }
...@@ -848,13 +850,13 @@ fn printStepStatus(...@@ -848,13 +850,13 @@ fn printStepStatus(
848 const rss = s.result_peak_rss;850 const rss = s.result_peak_rss;
849 try ttyconf.setColor(stderr, .dim);851 try ttyconf.setColor(stderr, .dim);
850 if (rss >= 1000_000_000) {852 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});
852 } else if (rss >= 1000_000) {854 } 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});
854 } else if (rss >= 1000) {856 } else if (rss >= 1000) {
855 try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});857 try stderr.print(" MaxRSS:{d}K", .{rss / 1000});
856 } else {858 } else {
857 try stderr.writer().print(" MaxRSS:{d}B", .{rss});859 try stderr.print(" MaxRSS:{d}B", .{rss});
858 }860 }
859 try ttyconf.setColor(stderr, .reset);861 try ttyconf.setColor(stderr, .reset);
860 }862 }
...@@ -866,7 +868,7 @@ fn printStepStatus(...@@ -866,7 +868,7 @@ fn printStepStatus(
866 if (skip == .skipped_oom) {868 if (skip == .skipped_oom) {
867 try stderr.writeAll(" (not enough memory)");869 try stderr.writeAll(" (not enough memory)");
868 try ttyconf.setColor(stderr, .dim);870 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 });
870 try ttyconf.setColor(stderr, .yellow);872 try ttyconf.setColor(stderr, .yellow);
871 }873 }
872 try stderr.writeAll("\n");874 try stderr.writeAll("\n");
...@@ -878,23 +880,23 @@ fn printStepStatus(...@@ -878,23 +880,23 @@ fn printStepStatus(
878880
879fn printStepFailure(881fn printStepFailure(
880 s: *Step,882 s: *Step,
881 stderr: File,883 stderr: *std.io.BufferedWriter,
882 ttyconf: std.io.tty.Config,884 ttyconf: std.io.tty.Config,
883) !void {885) !void {
884 if (s.result_error_bundle.errorMessageCount() > 0) {886 if (s.result_error_bundle.errorMessageCount() > 0) {
885 try ttyconf.setColor(stderr, .red);887 try ttyconf.setColor(stderr, .red);
886 try stderr.writer().print(" {d} errors\n", .{888 try stderr.print(" {d} errors\n", .{
887 s.result_error_bundle.errorMessageCount(),889 s.result_error_bundle.errorMessageCount(),
888 });890 });
889 try ttyconf.setColor(stderr, .reset);891 try ttyconf.setColor(stderr, .reset);
890 } else if (!s.test_results.isSuccess()) {892 } else if (!s.test_results.isSuccess()) {
891 try stderr.writer().print(" {d}/{d} passed", .{893 try stderr.print(" {d}/{d} passed", .{
892 s.test_results.passCount(), s.test_results.test_count,894 s.test_results.passCount(), s.test_results.test_count,
893 });895 });
894 if (s.test_results.fail_count > 0) {896 if (s.test_results.fail_count > 0) {
895 try stderr.writeAll(", ");897 try stderr.writeAll(", ");
896 try ttyconf.setColor(stderr, .red);898 try ttyconf.setColor(stderr, .red);
897 try stderr.writer().print("{d} failed", .{899 try stderr.print("{d} failed", .{
898 s.test_results.fail_count,900 s.test_results.fail_count,
899 });901 });
900 try ttyconf.setColor(stderr, .reset);902 try ttyconf.setColor(stderr, .reset);
...@@ -902,7 +904,7 @@ fn printStepFailure(...@@ -902,7 +904,7 @@ fn printStepFailure(
902 if (s.test_results.skip_count > 0) {904 if (s.test_results.skip_count > 0) {
903 try stderr.writeAll(", ");905 try stderr.writeAll(", ");
904 try ttyconf.setColor(stderr, .yellow);906 try ttyconf.setColor(stderr, .yellow);
905 try stderr.writer().print("{d} skipped", .{907 try stderr.print("{d} skipped", .{
906 s.test_results.skip_count,908 s.test_results.skip_count,
907 });909 });
908 try ttyconf.setColor(stderr, .reset);910 try ttyconf.setColor(stderr, .reset);
...@@ -910,7 +912,7 @@ fn printStepFailure(...@@ -910,7 +912,7 @@ fn printStepFailure(
910 if (s.test_results.leak_count > 0) {912 if (s.test_results.leak_count > 0) {
911 try stderr.writeAll(", ");913 try stderr.writeAll(", ");
912 try ttyconf.setColor(stderr, .red);914 try ttyconf.setColor(stderr, .red);
913 try stderr.writer().print("{d} leaked", .{915 try stderr.print("{d} leaked", .{
914 s.test_results.leak_count,916 s.test_results.leak_count,
915 });917 });
916 try ttyconf.setColor(stderr, .reset);918 try ttyconf.setColor(stderr, .reset);
...@@ -932,7 +934,7 @@ fn printTreeStep(...@@ -932,7 +934,7 @@ fn printTreeStep(
932 b: *std.Build,934 b: *std.Build,
933 s: *Step,935 s: *Step,
934 run: *const Run,936 run: *const Run,
935 stderr: File,937 stderr: *std.io.BufferedWriter,
936 ttyconf: std.io.tty.Config,938 ttyconf: std.io.tty.Config,
937 parent_node: *PrintNode,939 parent_node: *PrintNode,
938 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),940 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
...@@ -992,7 +994,7 @@ fn printTreeStep(...@@ -992,7 +994,7 @@ fn printTreeStep(
992 if (s.dependencies.items.len == 0) {994 if (s.dependencies.items.len == 0) {
993 try stderr.writeAll(" (reused)\n");995 try stderr.writeAll(" (reused)\n");
994 } else {996 } else {
995 try stderr.writer().print(" (+{d} more reused dependencies)\n", .{997 try stderr.print(" (+{d} more reused dependencies)\n", .{
996 s.dependencies.items.len,998 s.dependencies.items.len,
997 });999 });
998 }1000 }
...@@ -1129,11 +1131,11 @@ fn workerMakeOneStep(...@@ -1129,11 +1131,11 @@ fn workerMakeOneStep(
1129 const show_stderr = s.result_stderr.len > 0;1131 const show_stderr = s.result_stderr.len > 0;
11301132
1131 if (show_error_msgs or show_compile_errors or show_stderr) {1133 if (show_error_msgs or show_compile_errors or show_stderr) {
1132 std.debug.lockStdErr();1134 var bw = std.debug.lockStdErr2();
1133 defer std.debug.unlockStdErr();1135 defer std.debug.unlockStdErr();
11341136
1135 const gpa = b.allocator;1137 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 {};
1137 }1139 }
11381140
1139 handle_result: {1141 handle_result: {
...@@ -1190,7 +1192,7 @@ pub fn printErrorMessages(...@@ -1190,7 +1192,7 @@ pub fn printErrorMessages(
1190 gpa: Allocator,1192 gpa: Allocator,
1191 failing_step: *Step,1193 failing_step: *Step,
1192 options: std.zig.ErrorBundle.RenderOptions,1194 options: std.zig.ErrorBundle.RenderOptions,
1193 stderr: File,1195 stderr: *std.io.BufferedWriter,
1194 prominent_compile_errors: bool,1196 prominent_compile_errors: bool,
1195) !void {1197) !void {
1196 // Provide context for where these error messages are coming from by1198 // Provide context for where these error messages are coming from by
...@@ -1209,7 +1211,7 @@ pub fn printErrorMessages(...@@ -1209,7 +1211,7 @@ pub fn printErrorMessages(
1209 var indent: usize = 0;1211 var indent: usize = 0;
1210 while (step_stack.pop()) |s| : (indent += 1) {1212 while (step_stack.pop()) |s| : (indent += 1) {
1211 if (indent > 0) {1213 if (indent > 0) {
1212 try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);1214 try stderr.splatByteAll(' ', (indent - 1) * 3);
1213 try printChildNodePrefix(stderr, ttyconf);1215 try printChildNodePrefix(stderr, ttyconf);
1214 }1216 }
12151217
...@@ -1231,7 +1233,7 @@ pub fn printErrorMessages(...@@ -1231,7 +1233,7 @@ pub fn printErrorMessages(
1231 }1233 }
12321234
1233 if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) {1235 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);
1235 }1237 }
12361238
1237 for (failing_step.result_error_msgs.items) |msg| {1239 for (failing_step.result_error_msgs.items) |msg| {
...@@ -1243,27 +1245,29 @@ pub fn printErrorMessages(...@@ -1243,27 +1245,29 @@ pub fn printErrorMessages(
1243 }1245 }
1244}1246}
12451247
1246fn steps(builder: *std.Build, out_stream: anytype) !void {1248fn steps(builder: *std.Build, bw: *std.io.BufferedWriter) !void {
1247 const allocator = builder.allocator;1249 const allocator = builder.allocator;
1248 for (builder.top_level_steps.values()) |top_level_step| {1250 for (builder.top_level_steps.values()) |top_level_step| {
1249 const name = if (&top_level_step.step == builder.default_step)1251 const name = if (&top_level_step.step == builder.default_step)
1250 try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})1252 try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
1251 else1253 else
1252 top_level_step.step.name;1254 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 });
1254 }1256 }
1255}1257}
12561258
1257fn usage(b: *std.Build, out_stream: anytype) !void {1259var stdout_buffer: [256]u8 = undefined;
1258 try out_stream.print(1260
1261fn usage(b: *std.Build, bw: *std.io.BufferedWriter) !void {
1262 try bw.print(
1259 \\Usage: {s} build [steps] [options]1263 \\Usage: {s} build [steps] [options]
1260 \\1264 \\
1261 \\Steps:1265 \\Steps:
1262 \\1266 \\
1263 , .{b.graph.zig_exe});1267 , .{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(
1267 \\1271 \\
1268 \\General Options:1272 \\General Options:
1269 \\ -p, --prefix [path] Where to install files (default: zig-out)1273 \\ -p, --prefix [path] Where to install files (default: zig-out)
...@@ -1319,25 +1323,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void {...@@ -1319,25 +1323,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13191323
1320 const arena = b.allocator;1324 const arena = b.allocator;
1321 if (b.available_options_list.items.len == 0) {1325 if (b.available_options_list.items.len == 0) {
1322 try out_stream.print(" (none)\n", .{});1326 try bw.print(" (none)\n", .{});
1323 } else {1327 } else {
1324 for (b.available_options_list.items) |option| {1328 for (b.available_options_list.items) |option| {
1325 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{1329 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
1326 option.name,1330 option.name,
1327 @tagName(option.type_id),1331 @tagName(option.type_id),
1328 });1332 });
1329 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });1333 try bw.print("{s:<30} {s}\n", .{ name, option.description });
1330 if (option.enum_options) |enum_options| {1334 if (option.enum_options) |enum_options| {
1331 const padding = " " ** 33;1335 const padding = " " ** 33;
1332 try out_stream.writeAll(padding ++ "Supported Values:\n");1336 try bw.writeAll(padding ++ "Supported Values:\n");
1333 for (enum_options) |enum_option| {1337 for (enum_options) |enum_option| {
1334 try out_stream.print(padding ++ " {s}\n", .{enum_option});1338 try bw.print(padding ++ " {s}\n", .{enum_option});
1335 }1339 }
1336 }1340 }
1337 }1341 }
1338 }1342 }
13391343
1340 try out_stream.writeAll(1344 try bw.writeAll(
1341 \\1345 \\
1342 \\System Integration Options:1346 \\System Integration Options:
1343 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers1347 \\ --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 {...@@ -1352,7 +1356,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
1352 \\1356 \\
1353 );1357 );
1354 if (b.graph.system_library_options.entries.len == 0) {1358 if (b.graph.system_library_options.entries.len == 0) {
1355 try out_stream.writeAll(" (none) -\n");1359 try bw.writeAll(" (none) -\n");
1356 } else {1360 } else {
1357 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {1361 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1358 const status = switch (v) {1362 const status = switch (v) {
...@@ -1360,11 +1364,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void {...@@ -1360,11 +1364,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
1360 .declared_disabled => "no",1364 .declared_disabled => "no",
1361 .user_enabled, .user_disabled => unreachable, // already emitted error1365 .user_enabled, .user_disabled => unreachable, // already emitted error
1362 };1366 };
1363 try out_stream.print(" {s:<43} {s}\n", .{ k, status });1367 try bw.print(" {s:<43} {s}\n", .{ k, status });
1364 }1368 }
1365 }1369 }
13661370
1367 try out_stream.writeAll(1371 try bw.writeAll(
1368 \\1372 \\
1369 \\Advanced Options:1373 \\Advanced Options:
1370 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error1374 \\ -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...@@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
112112
113fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {113fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
114 const gpa = run.step.owner.allocator;114 const gpa = run.step.owner.allocator;
115 const stderr = std.io.getStdErr();
116115
117 const compile = run.producer.?;116 const compile = run.producer.?;
118 const prog_node = parent_prog_node.start(compile.step.name, 0);117 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...@@ -125,9 +124,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, par
125 const show_stderr = compile.step.result_stderr.len > 0;124 const show_stderr = compile.step.result_stderr.len > 0;
126125
127 if (show_error_msgs or show_compile_errors or show_stderr) {126 if (show_error_msgs or show_compile_errors or show_stderr) {
128 std.debug.lockStdErr();127 var bw = std.debug.lockStdErr2();
129 defer std.debug.unlockStdErr();128 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 {};
131 }130 }
132131
133 const rebuilt_bin_path = result catch |err| switch (err) {132 const rebuilt_bin_path = result catch |err| switch (err) {
...@@ -152,10 +151,9 @@ fn fuzzWorkerRun(...@@ -152,10 +151,9 @@ fn fuzzWorkerRun(
152151
153 run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) {152 run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) {
154 error.MakeFailed => {153 error.MakeFailed => {
155 const stderr = std.io.getStdErr();154 var bw = std.debug.lockStdErr2();
156 std.debug.lockStdErr();
157 defer std.debug.unlockStdErr();155 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 {};
159 return;157 return;
160 },158 },
161 else => {159 else => {
lib/std/Build/Step/CheckObject.zig+9-8
...@@ -1393,7 +1393,8 @@ const MachODumper = struct {...@@ -1393,7 +1393,8 @@ const MachODumper = struct {
1393 },1393 },
1394 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {1394 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
1395 name_buf.clearRetainingCapacity();1395 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));
1397 try name_buf.append(0);1398 try name_buf.append(0);
1398 },1399 },
1399 macho.BIND_OPCODE_SET_ADDEND_SLEB => {1400 macho.BIND_OPCODE_SET_ADDEND_SLEB => {
...@@ -2430,10 +2431,11 @@ const WasmDumper = struct {...@@ -2430,10 +2431,11 @@ const WasmDumper = struct {
2430 return error.UnsupportedWasmVersion;2431 return error.UnsupportedWasmVersion;
2431 }2432 }
24322433
2433 var output = std.ArrayList(u8).init(gpa);2434 var output: std.io.AllocatingWriter = undefined;
2435 const bw = output.init(gpa);
2434 defer output.deinit();2436 defer output.deinit();
2435 parseAndDumpInner(step, check, bytes, &fbs, &output) catch |err| switch (err) {2437 parseAndDumpInner(step, check, bytes, &fbs, bw) catch |err| switch (err) {
2436 error.EndOfStream => try output.appendSlice("\n<UnexpectedEndOfStream>"),2438 error.EndOfStream => try bw.writeAll("\n<UnexpectedEndOfStream>"),
2437 else => |e| return e,2439 else => |e| return e,
2438 };2440 };
2439 return output.toOwnedSlice();2441 return output.toOwnedSlice();
...@@ -2443,11 +2445,10 @@ const WasmDumper = struct {...@@ -2443,11 +2445,10 @@ const WasmDumper = struct {
2443 step: *Step,2445 step: *Step,
2444 check: Check,2446 check: Check,
2445 bytes: []const u8,2447 bytes: []const u8,
2446 fbs: *std.io.FixedBufferStream([]const u8),2448 fbs: *std.io.FixedBufferStream,
2447 output: *std.ArrayList(u8),2449 bw: *std.io.BufferedWriter,
2448 ) !void {2450 ) !void {
2449 const reader = fbs.reader();2451 const reader = fbs.reader();
2450 const writer = output.writer();
24512452
2452 switch (check.kind) {2453 switch (check.kind) {
2453 .headers => {2454 .headers => {
...@@ -2457,7 +2458,7 @@ const WasmDumper = struct {...@@ -2457,7 +2458,7 @@ const WasmDumper = struct {
2457 };2458 };
24582459
2459 const section_length = try std.leb.readUleb128(u32, reader);2460 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);
2461 fbs.pos += section_length;2462 fbs.pos += section_length;
2462 } else |_| {} // reached end of stream2463 } else |_| {} // reached end of stream
2463 },2464 },
lib/std/Build/Step/Compile.zig+6-6
...@@ -2040,17 +2040,17 @@ fn checkCompileErrors(compile: *Compile) !void {...@@ -2040,17 +2040,17 @@ fn checkCompileErrors(compile: *Compile) !void {
2040 .exact => |expect_lines| {2040 .exact => |expect_lines| {
2041 for (expect_lines) |expect_line| {2041 for (expect_lines) |expect_line| {
2042 const actual_line = actual_line_it.next() orelse {2042 const actual_line = actual_line_it.next() orelse {
2043 try expected_generated.appendSlice(expect_line);2043 try expected_generated.appendSlice(arena, expect_line);
2044 try expected_generated.append('\n');2044 try expected_generated.append(arena, '\n');
2045 continue;2045 continue;
2046 };2046 };
2047 if (matchCompileError(actual_line, expect_line)) {2047 if (matchCompileError(actual_line, expect_line)) {
2048 try expected_generated.appendSlice(actual_line);2048 try expected_generated.appendSlice(arena, actual_line);
2049 try expected_generated.append('\n');2049 try expected_generated.append(arena, '\n');
2050 continue;2050 continue;
2051 }2051 }
2052 try expected_generated.appendSlice(expect_line);2052 try expected_generated.appendSlice(arena, expect_line);
2053 try expected_generated.append('\n');2053 try expected_generated.append(arena, '\n');
2054 }2054 }
20552055
2056 if (mem.eql(u8, expected_generated.items, actual_errors)) return;2056 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) !...@@ -599,14 +599,14 @@ fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !
599 try output.appendSlice(if (b) " 1\n" else " 0\n");599 try output.appendSlice(if (b) " 1\n" else " 0\n");
600 },600 },
601 .int => |i| {601 .int => |i| {
602 try output.writer().print("%define {s} {d}\n", .{ name, i });602 try output.print("%define {s} {d}\n", .{ name, i });
603 },603 },
604 .ident => |ident| {604 .ident => |ident| {
605 try output.writer().print("%define {s} {s}\n", .{ name, ident });605 try output.print("%define {s} {s}\n", .{ name, ident });
606 },606 },
607 .string => |string| {607 .string => |string| {
608 // TODO: use nasm-specific escaping instead of zig string literals608 // 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) });
610 },610 },
611 }611 }
612}612}
...@@ -707,7 +707,7 @@ fn expand_variables_cmake(...@@ -707,7 +707,7 @@ fn expand_variables_cmake(
707 try result.append(if (b) '1' else '0');707 try result.append(if (b) '1' else '0');
708 },708 },
709 .int => |i| {709 .int => |i| {
710 try result.writer().print("{d}", .{i});710 try result.print("{d}", .{i});
711 },711 },
712 .ident, .string => |s| {712 .ident, .string => |s| {
713 try result.appendSlice(s);713 try result.appendSlice(s);
...@@ -764,7 +764,7 @@ fn expand_variables_cmake(...@@ -764,7 +764,7 @@ fn expand_variables_cmake(
764 try result.append(if (b) '1' else '0');764 try result.append(if (b) '1' else '0');
765 },765 },
766 .int => |i| {766 .int => |i| {
767 try result.writer().print("{d}", .{i});767 try result.print("{d}", .{i});
768 },768 },
769 .ident, .string => |s| {769 .ident, .string => |s| {
770 try result.appendSlice(s);770 try result.appendSlice(s);
lib/std/Uri.zig+4-3
...@@ -445,13 +445,14 @@ test remove_dot_segments {...@@ -445,13 +445,14 @@ test remove_dot_segments {
445445
446/// 5.2.3. Merge Paths446/// 5.2.3. Merge Paths
447fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component {447fn 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.*);
449 if (!base.isEmpty()) {450 if (!base.isEmpty()) {
450 try aux.writer().print("{path}", .{base});451 aux.print("{fpath}", .{base}) catch |err| return @errorCast(err);
451 aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse452 aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse
452 return remove_dot_segments(new);453 return remove_dot_segments(new);
453 }454 }
454 try aux.writer().print("/{s}", .{new});455 aux.print("/{s}", .{new}) catch |err| return @errorCast(err);
455 const merged_path = remove_dot_segments(aux.getWritten());456 const merged_path = remove_dot_segments(aux.getWritten());
456 aux_buf.* = aux_buf.*[merged_path.percent_encoded.len..];457 aux_buf.* = aux_buf.*[merged_path.percent_encoded.len..];
457 return merged_path;458 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...@@ -338,6 +338,12 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty
338 @memcpy(self.items[old_len..][0..items.len], items);338 @memcpy(self.items[old_len..][0..items.len], items);
339 }339 }
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
341 /// Append a value to the list `n` times.347 /// Append a value to the list `n` times.
342 /// Allocates more memory as necessary.348 /// Allocates more memory as necessary.
343 /// Invalidates element pointers if additional memory is needed.349 /// Invalidates element pointers if additional memory is needed.
...@@ -902,7 +908,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig...@@ -902,7 +908,15 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig
902 var aw: std.io.AllocatingWriter = undefined;908 var aw: std.io.AllocatingWriter = undefined;
903 const bw = aw.fromArrayList(gpa, self);909 const bw = aw.fromArrayList(gpa, self);
904 defer self.* = aw.toArrayList();910 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;
906 }920 }
907921
908 /// Append a value to the list `n` times.922 /// Append a value to the list `n` times.
lib/std/http/Server.zig+64-14
...@@ -421,9 +421,9 @@ pub const Request = struct {...@@ -421,9 +421,9 @@ pub const Request = struct {
421 try request.server.connection.stream.writeAll(h.items);421 try request.server.connection.stream.writeAll(h.items);
422 return;422 return;
423 }423 }
424 h.fixedWriter().print("{s} {d} {s}\r\n", .{424 h.printAssumeCapacity("{s} {d} {s}\r\n", .{
425 @tagName(options.version), @intFromEnum(options.status), phrase,425 @tagName(options.version), @intFromEnum(options.status), phrase,
426 }) catch unreachable;426 });
427427
428 switch (options.version) {428 switch (options.version) {
429 .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),429 .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
...@@ -434,7 +434,7 @@ pub const Request = struct {...@@ -434,7 +434,7 @@ pub const Request = struct {
434 .none => {},434 .none => {},
435 .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),435 .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
436 } else {436 } else {
437 h.fixedWriter().print("content-length: {d}\r\n", .{content.len}) catch unreachable;437 h.printAssumeCapacity("content-length: {d}\r\n", .{content.len});
438 }438 }
439439
440 var chunk_header_buffer: [18]u8 = undefined;440 var chunk_header_buffer: [18]u8 = undefined;
...@@ -573,9 +573,9 @@ pub const Request = struct {...@@ -573,9 +573,9 @@ pub const Request = struct {
573 h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n");573 h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n");
574 break :eb true;574 break :eb true;
575 } else eb: {575 } else eb: {
576 h.fixedWriter().print("{s} {d} {s}\r\n", .{576 h.printAssumeCapacity("{s} {d} {s}\r\n", .{
577 @tagName(o.version), @intFromEnum(o.status), phrase,577 @tagName(o.version), @intFromEnum(o.status), phrase,
578 }) catch unreachable;578 });
579579
580 switch (o.version) {580 switch (o.version) {
581 .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),581 .@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
...@@ -586,7 +586,7 @@ pub const Request = struct {...@@ -586,7 +586,7 @@ pub const Request = struct {
586 .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),586 .chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
587 .none => {},587 .none => {},
588 } else if (options.content_length) |len| {588 } 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});
590 } else {590 } else {
591 h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n");591 h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n");
592 }592 }
...@@ -889,12 +889,34 @@ pub const Response = struct {...@@ -889,12 +889,34 @@ pub const Response = struct {
889 /// when the end of stream occurs by calling `end`.889 /// when the end of stream occurs by calling `end`.
890 pub fn write(r: *Response, bytes: []const u8) WriteError!usize {890 pub fn write(r: *Response, bytes: []const u8) WriteError!usize {
891 switch (r.transfer_encoding) {891 switch (r.transfer_encoding) {
892 .content_length, .none => return write_cl(r, bytes),892 .content_length, .none => return @errorCast(cl_writeSplat(r, &.{bytes}, 1)),
893 .chunked => return write_chunked(r, bytes),893 .chunked => return @errorCast(chunked_writeSplat(r, &.{bytes}, 1)),
894 }894 }
895 }895 }
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 {
898 const r: *Response = @constCast(@alignCast(@ptrCast(context)));920 const r: *Response = @constCast(@alignCast(@ptrCast(context)));
899921
900 var trash: u64 = std.math.maxInt(u64);922 var trash: u64 = std.math.maxInt(u64);
...@@ -944,7 +966,29 @@ pub const Response = struct {...@@ -944,7 +966,29 @@ pub const Response = struct {
944 return bytes.len;966 return bytes.len;
945 }967 }
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 {
948 const r: *Response = @constCast(@alignCast(@ptrCast(context)));992 const r: *Response = @constCast(@alignCast(@ptrCast(context)));
949 assert(r.transfer_encoding == .chunked);993 assert(r.transfer_encoding == .chunked);
950994
...@@ -1115,11 +1159,17 @@ pub const Response = struct {...@@ -1115,11 +1159,17 @@ pub const Response = struct {
1115 r.chunk_len = 0;1159 r.chunk_len = 0;
1116 }1160 }
11171161
1118 pub fn writer(r: *Response) std.io.AnyWriter {1162 pub fn writer(r: *Response) std.io.Writer {
1119 return .{1163 return .{
1120 .writeFn = switch (r.transfer_encoding) {1164 .vtable = switch (r.transfer_encoding) {
1121 .none, .content_length => write_cl,1165 .none, .content_length => &.{
1122 .chunked => write_chunked,1166 .writeSplat = cl_writeSplat,
1167 .writeFile = cl_writeFile,
1168 },
1169 .chunked => &.{
1170 .writeSplat = chunked_writeSplat,
1171 .writeFile = chunked_writeFile,
1172 },
1123 },1173 },
1124 .context = r,1174 .context = r,
1125 };1175 };
lib/std/io.zig-13
...@@ -123,19 +123,6 @@ pub fn GenericReader(...@@ -123,19 +123,6 @@ pub fn GenericReader(
123 return @errorCast(self.any().readAllAlloc(allocator, max_size));123 return @errorCast(self.any().readAllAlloc(allocator, max_size));
124 }124 }
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
139 pub inline fn readUntilDelimiterAlloc(126 pub inline fn readUntilDelimiterAlloc(
140 self: Self,127 self: Self,
141 allocator: Allocator,128 allocator: Allocator,
lib/std/io/AllocatingWriter.zig+2
...@@ -17,6 +17,8 @@ const assert = std.debug.assert;...@@ -17,6 +17,8 @@ const assert = std.debug.assert;
17/// returning a slice that includes both.17/// returning a slice that includes both.
18written: []u8,18written: []u8,
19allocator: std.mem.Allocator,19allocator: std.mem.Allocator,
20/// When using this API, it is not necessary to call
21/// `std.io.BufferedWriter.flush`.
20buffered_writer: std.io.BufferedWriter,22buffered_writer: std.io.BufferedWriter,
2123
22const vtable: std.io.Writer.VTable = .{24const vtable: std.io.Writer.VTable = .{
lib/std/io/BufferedWriter.zig+3-3
...@@ -33,7 +33,7 @@ pub fn writer(bw: *BufferedWriter) Writer {...@@ -33,7 +33,7 @@ pub fn writer(bw: *BufferedWriter) Writer {
33 return .{33 return .{
34 .context = bw,34 .context = bw,
35 .vtable = &.{35 .vtable = &.{
36 .write = passthru_writeSplat,36 .writeSplat = passthru_writeSplat,
37 .writeFile = passthru_writeFile,37 .writeFile = passthru_writeFile,
38 },38 },
39 };39 };
...@@ -1003,7 +1003,7 @@ pub fn printFloat(...@@ -1003,7 +1003,7 @@ pub fn printFloat(
1003 'x' => {1003 'x' => {
1004 var sub_bw: BufferedWriter = undefined;1004 var sub_bw: BufferedWriter = undefined;
1005 sub_bw.initFixed(&buf);1005 sub_bw.initFixed(&buf);
1006 sub_bw.printFloatHexadecimal(value, options) catch unreachable;1006 sub_bw.printFloatHexadecimal(value, options.precision) catch unreachable;
1007 return alignBufferOptions(bw, sub_bw.getWritten(), options);1007 return alignBufferOptions(bw, sub_bw.getWritten(), options);
1008 },1008 },
1009 else => invalidFmtError(fmt, value),1009 else => invalidFmtError(fmt, value),
...@@ -1103,7 +1103,7 @@ pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision:...@@ -1103,7 +1103,7 @@ pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision:
1103 // Add trailing zeros if explicitly requested.1103 // Add trailing zeros if explicitly requested.
1104 if (opt_precision) |precision| if (precision > 0) {1104 if (opt_precision) |precision| if (precision > 0) {
1105 if (precision > trimmed.len)1105 if (precision > trimmed.len)
1106 try bw.writeByteNTimes('0', precision - trimmed.len);1106 try bw.splatByteAll('0', precision - trimmed.len);
1107 };1107 };
1108 try bw.writeAll("p");1108 try bw.writeAll("p");
1109 try printIntOptions(bw, exponent - exponent_bias, 10, .lower, .{});1109 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...@@ -93,108 +93,14 @@ pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyer
93 return try array_list.toOwnedSlice();93 return try array_list.toOwnedSlice();
94}94}
9595
96/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.96/// Appends to `bw` contents by reading from the stream until `delimiter` is found.
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.
191/// Does not write the delimiter itself.97/// Does not write the delimiter itself.
192/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,98/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,
193/// returns `error.StreamTooLong` and finishes appending.99/// returns `error.StreamTooLong` and finishes appending.
194/// If `optional_max_size` is null, appending is unbounded.100/// If `optional_max_size` is null, appending is unbounded.
195pub fn streamUntilDelimiter(101pub fn streamUntilDelimiter(
196 self: Self,102 self: Self,
197 writer: anytype,103 bw: *std.io.BufferedWriter,
198 delimiter: u8,104 delimiter: u8,
199 optional_max_size: ?usize,105 optional_max_size: ?usize,
200) anyerror!void {106) anyerror!void {
...@@ -202,14 +108,14 @@ pub fn streamUntilDelimiter(...@@ -202,14 +108,14 @@ pub fn streamUntilDelimiter(
202 for (0..max_size) |_| {108 for (0..max_size) |_| {
203 const byte: u8 = try self.readByte();109 const byte: u8 = try self.readByte();
204 if (byte == delimiter) return;110 if (byte == delimiter) return;
205 try writer.writeByte(byte);111 try bw.writeByte(byte);
206 }112 }
207 return error.StreamTooLong;113 return error.StreamTooLong;
208 } else {114 } else {
209 while (true) {115 while (true) {
210 const byte: u8 = try self.readByte();116 const byte: u8 = try self.readByte();
211 if (byte == delimiter) return;117 if (byte == delimiter) return;
212 try writer.writeByte(byte);118 try bw.writeByte(byte);
213 }119 }
214 // Can not throw `error.StreamTooLong` since there are no boundary.120 // Can not throw `error.StreamTooLong` since there are no boundary.
215 }121 }
lib/std/tar/writer.zig+156-167
...@@ -2,187 +2,176 @@ const std = @import("std");...@@ -2,187 +2,176 @@ const std = @import("std");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
44
5/// Creates tar Writer which will write tar content to the `underlying_writer`.5pub const Writer = struct {
6/// Use setRoot to nest all following entries under single root. If file don't6 const block_size = @sizeOf(Header);
7/// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will7 const empty_block: [block_size]u8 = [_]u8{0} ** block_size;
8/// be used for long names. Options enables setting file premission mode and8
9/// mtime. Default is to use current time for mtime and 0o664 for file mode.9 /// Options for writing file/dir/link. If left empty 0o664 is used for
10pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) {10 /// file mode and current time for mtime.
11 return .{ .underlying_writer = underlying_writer };11 pub const Options = struct {
12}12 /// File system permission mode.
1313 mode: u32 = 0,
14pub fn Writer(comptime WriterType: type) type {14 /// File system modification time.
15 return struct {15 mtime: u64 = 0,
16 const block_size = @sizeOf(Header);16 };
17 const empty_block: [block_size]u8 = [_]u8{0} ** block_size;17 const Self = @This();
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();
2818
29 underlying_writer: WriterType,19 underlying_writer: *std.io.BufferedWriter,
30 prefix: []const u8 = "",20 prefix: []const u8 = "",
31 mtime_now: u64 = 0,21 mtime_now: u64 = 0,
3222
33 /// Sets prefix for all other write* method paths.23 /// Sets prefix for all other write* method paths.
34 pub fn setRoot(self: *Self, root: []const u8) !void {24 pub fn setRoot(self: *Self, root: []const u8) !void {
35 if (root.len > 0)25 if (root.len > 0)
36 try self.writeDir(root, .{});26 try self.writeDir(root, .{});
3727
38 self.prefix = root;28 self.prefix = root;
39 }29 }
4030
41 /// Writes directory.31 /// Writes directory.
42 pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void {32 pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void {
43 try self.writeHeader(.directory, sub_path, "", 0, opt);33 try self.writeHeader(.directory, sub_path, "", 0, opt);
44 }34 }
4535
46 /// Writes file system file.36 /// Writes file system file.
47 pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void {37 pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void {
48 const stat = try file.stat();38 const stat = try file.stat();
49 const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));39 const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
5040
51 var header = Header{};41 var header = Header{};
52 try self.setPath(&header, sub_path);42 try self.setPath(&header, sub_path);
53 try header.setSize(stat.size);43 try header.setSize(stat.size);
54 try header.setMtime(mtime);44 try header.setMtime(mtime);
55 try header.write(self.underlying_writer);45 try header.write(self.underlying_writer);
5646
57 try self.underlying_writer.writeFile(file);47 try self.underlying_writer.writeFileAll(file, .{ .len = .init(stat.size) });
58 try self.writePadding(stat.size);48 try self.writePadding(stat.size);
59 }49 }
6050
61 /// Writes file reading file content from `reader`. Number of bytes in51 /// Writes file reading file content from `reader`. Number of bytes in
62 /// reader must be equal to `size`.52 /// reader must be equal to `size`.
63 pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void {53 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);54 try self.writeHeader(.regular, sub_path, "", @intCast(size), opt);
6555
66 var counting_reader = std.io.countingReader(reader);56 var counting_reader = std.io.countingReader(reader);
67 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();57 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
68 try fifo.pump(counting_reader.reader(), self.underlying_writer);58 try fifo.pump(counting_reader.reader(), self.underlying_writer);
69 if (counting_reader.bytes_read != size) return error.WrongReaderSize;59 if (counting_reader.bytes_read != size) return error.WrongReaderSize;
70 try self.writePadding(size);60 try self.writePadding(size);
71 }61 }
7262
73 /// Writes file using bytes buffer `content` for size and file content.63 /// 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 {64 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);65 try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt);
76 try self.underlying_writer.writeAll(content);66 try self.underlying_writer.writeAll(content);
77 try self.writePadding(content.len);67 try self.writePadding(content.len);
78 }68 }
7969
80 /// Writes symlink.70 /// Writes symlink.
81 pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void {71 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);72 try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt);
83 }73 }
8474
85 /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and75 /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
86 /// default for entry mode .76 /// default for entry mode .
87 pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {77 pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
88 switch (entry.kind) {78 switch (entry.kind) {
89 .directory => {79 .directory => {
90 try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });80 try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
91 },81 },
92 .file => {82 .file => {
93 var file = try entry.dir.openFile(entry.basename, .{});83 var file = try entry.dir.openFile(entry.basename, .{});
94 defer file.close();84 defer file.close();
95 try self.writeFile(entry.path, file);85 try self.writeFile(entry.path, file);
96 },86 },
97 .sym_link => {87 .sym_link => {
98 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;88 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
99 const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);89 const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);
100 try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });90 try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
101 },91 },
102 else => {92 else => {
103 return error.UnsupportedWalkerEntryKind;93 return error.UnsupportedWalkerEntryKind;
104 },94 },
105 }
106 }95 }
96 }
10797
108 fn writeHeader(98 fn writeHeader(
109 self: *Self,99 self: *Self,
110 typeflag: Header.FileType,100 typeflag: Header.FileType,
111 sub_path: []const u8,101 sub_path: []const u8,
112 link_name: []const u8,102 link_name: []const u8,
113 size: u64,103 size: u64,
114 opt: Options,104 opt: Options,
115 ) !void {105 ) !void {
116 var header = Header.init(typeflag);106 var header = Header.init(typeflag);
117 try self.setPath(&header, sub_path);107 try self.setPath(&header, sub_path);
118 try header.setSize(size);108 try header.setSize(size);
119 try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow());109 try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow());
120 if (opt.mode != 0)110 if (opt.mode != 0)
121 try header.setMode(opt.mode);111 try header.setMode(opt.mode);
122 if (typeflag == .symbolic_link)112 if (typeflag == .symbolic_link)
123 header.setLinkname(link_name) catch |err| switch (err) {113 header.setLinkname(link_name) catch |err| switch (err) {
124 error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}),114 error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}),
125 else => return err,115 else => return err,
126 };116 };
127 try header.write(self.underlying_writer);117 try header.write(self.underlying_writer);
128 }118 }
129119
130 fn mtimeNow(self: *Self) u64 {120 fn mtimeNow(self: *Self) u64 {
131 if (self.mtime_now == 0)121 if (self.mtime_now == 0)
132 self.mtime_now = @intCast(std.time.timestamp());122 self.mtime_now = @intCast(std.time.timestamp());
133 return self.mtime_now;123 return self.mtime_now;
134 }124 }
135125
136 fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {126 fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
137 const stat = try entry.dir.statFile(entry.basename);127 const stat = try entry.dir.statFile(entry.basename);
138 return @intCast(@divFloor(stat.mtime, std.time.ns_per_s));128 return @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
139 }129 }
140130
141 /// Writes path in posix header, if don't fit (in name+prefix; 100+155131 /// Writes path in posix header, if don't fit (in name+prefix; 100+155
142 /// bytes) writes it in gnu extended header.132 /// bytes) writes it in gnu extended header.
143 fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void {133 fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void {
144 header.setPath(self.prefix, sub_path) catch |err| switch (err) {134 header.setPath(self.prefix, sub_path) catch |err| switch (err) {
145 error.NameTooLong => {135 error.NameTooLong => {
146 // write extended header136 // write extended header
147 const buffers: []const []const u8 = if (self.prefix.len == 0)137 const buffers: []const []const u8 = if (self.prefix.len == 0)
148 &.{sub_path}138 &.{sub_path}
149 else139 else
150 &.{ self.prefix, "/", sub_path };140 &.{ self.prefix, "/", sub_path };
151 try self.writeExtendedHeader(.gnu_long_name, buffers);141 try self.writeExtendedHeader(.gnu_long_name, buffers);
152 },142 },
153 else => return err,143 else => return err,
154 };144 };
155 }145 }
156146
157 /// Writes gnu extended header: gnu_long_name or gnu_long_link.147 /// Writes gnu extended header: gnu_long_name or gnu_long_link.
158 fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void {148 fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void {
159 var len: usize = 0;149 var len: usize = 0;
160 for (buffers) |buf|150 for (buffers) |buf|
161 len += buf.len;151 len += buf.len;
162152
163 var header = Header.init(typeflag);153 var header = Header.init(typeflag);
164 try header.setSize(len);154 try header.setSize(len);
165 try header.write(self.underlying_writer);155 try header.write(self.underlying_writer);
166 for (buffers) |buf|156 for (buffers) |buf|
167 try self.underlying_writer.writeAll(buf);157 try self.underlying_writer.writeAll(buf);
168 try self.writePadding(len);158 try self.writePadding(len);
169 }159 }
170160
171 fn writePadding(self: *Self, bytes: u64) !void {161 fn writePadding(self: *Self, bytes: u64) !void {
172 const pos: usize = @intCast(bytes % block_size);162 const pos: usize = @intCast(bytes % block_size);
173 if (pos == 0) return;163 if (pos == 0) return;
174 try self.underlying_writer.writeAll(empty_block[pos..]);164 try self.underlying_writer.writeAll(empty_block[pos..]);
175 }165 }
176166
177 /// Tar should finish with two zero blocks, but 'reasonable system must167 /// Tar should finish with two zero blocks, but 'reasonable system must
178 /// not assume that such a block exists when reading an archive' (from168 /// not assume that such a block exists when reading an archive' (from
179 /// reference). In practice it is safe to skip this finish.169 /// reference). In practice it is safe to skip this finish.
180 pub fn finish(self: *Self) !void {170 pub fn finish(self: *Self) !void {
181 try self.underlying_writer.writeAll(&empty_block);171 try self.underlying_writer.writeAll(&empty_block);
182 try self.underlying_writer.writeAll(&empty_block);172 try self.underlying_writer.writeAll(&empty_block);
183 }173 }
184 };174};
185}
186175
187/// A struct that is exactly 512 bytes and matches tar file format. This is176/// A struct that is exactly 512 bytes and matches tar file format. This is
188/// intended to be used for outputting tar files; for parsing there is177/// intended to be used for outputting tar files; for parsing there is
...@@ -431,14 +420,14 @@ test "write files" {...@@ -431,14 +420,14 @@ test "write files" {
431 {420 {
432 const root = "root";421 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) };
435 defer output.deinit();425 defer output.deinit();
436 var wrt = writer(output.writer());
437 try wrt.setRoot(root);426 try wrt.setRoot(root);
438 for (files) |file|427 for (files) |file|
439 try wrt.writeFileBytes(file.path, file.content, .{});428 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() };
442 var iter = std.tar.iterator(431 var iter = std.tar.iterator(
443 input.reader(),432 input.reader(),
444 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },433 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },
...@@ -467,15 +456,15 @@ test "write files" {...@@ -467,15 +456,15 @@ test "write files" {
467 }456 }
468 // without root457 // without root
469 {458 {
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) };
471 defer output.deinit();461 defer output.deinit();
472 var wrt = writer(output.writer());
473 for (files) |file| {462 for (files) |file| {
474 var content = std.io.fixedBufferStream(file.content);463 var content = std.io.fixedBufferStream(file.content);
475 try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{});464 try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{});
476 }465 }
477466
478 var input = std.io.fixedBufferStream(output.items);467 var input: std.io.FixedBufferStream = .{ .buffer = output.getWritten() };
479 var iter = std.tar.iterator(468 var iter = std.tar.iterator(
480 input.reader(),469 input.reader(),
481 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },470 .{ .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(...@@ -635,7 +635,7 @@ pub fn parseTargetQueryOrReportFatalError(
635 var help_text = std.ArrayList(u8).init(allocator);635 var help_text = std.ArrayList(u8).init(allocator);
636 defer help_text.deinit();636 defer help_text.deinit();
637 for (diags.arch.?.allCpuModels()) |cpu| {637 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;
639 }639 }
640 std.log.info("available CPUs for architecture '{s}':\n{s}", .{640 std.log.info("available CPUs for architecture '{s}':\n{s}", .{
641 @tagName(diags.arch.?), help_text.items,641 @tagName(diags.arch.?), help_text.items,
...@@ -648,7 +648,7 @@ pub fn parseTargetQueryOrReportFatalError(...@@ -648,7 +648,7 @@ pub fn parseTargetQueryOrReportFatalError(
648 var help_text = std.ArrayList(u8).init(allocator);648 var help_text = std.ArrayList(u8).init(allocator);
649 defer help_text.deinit();649 defer help_text.deinit();
650 for (diags.arch.?.allFeaturesList()) |feature| {650 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;
652 }652 }
653 std.log.info("available CPU features for architecture '{s}':\n{s}", .{653 std.log.info("available CPU features for architecture '{s}':\n{s}", .{
654 @tagName(diags.arch.?), help_text.items,654 @tagName(diags.arch.?), help_text.items,
...@@ -661,7 +661,7 @@ pub fn parseTargetQueryOrReportFatalError(...@@ -661,7 +661,7 @@ pub fn parseTargetQueryOrReportFatalError(
661 var help_text = std.ArrayList(u8).init(allocator);661 var help_text = std.ArrayList(u8).init(allocator);
662 defer help_text.deinit();662 defer help_text.deinit();
663 inline for (@typeInfo(std.Target.ObjectFormat).@"enum".fields) |field| {663 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;
665 }665 }
666 std.log.info("available object formats:\n{s}", .{help_text.items});666 std.log.info("available object formats:\n{s}", .{help_text.items});
667 }667 }
...@@ -672,7 +672,7 @@ pub fn parseTargetQueryOrReportFatalError(...@@ -672,7 +672,7 @@ pub fn parseTargetQueryOrReportFatalError(
672 var help_text = std.ArrayList(u8).init(allocator);672 var help_text = std.ArrayList(u8).init(allocator);
673 defer help_text.deinit();673 defer help_text.deinit();
674 inline for (@typeInfo(std.Target.Cpu.Arch).@"enum".fields) |field| {674 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;
676 }676 }
677 std.log.info("available architectures:\n{s} native\n", .{help_text.items});677 std.log.info("available architectures:\n{s} native\n", .{help_text.items});
678 }678 }
lib/std/zig/ErrorBundle.zig+8-8
...@@ -194,11 +194,11 @@ fn renderErrorMessageToWriter(...@@ -194,11 +194,11 @@ fn renderErrorMessageToWriter(
194) anyerror!void {194) anyerror!void {
195 const ttyconf = options.ttyconf;195 const ttyconf = options.ttyconf;
196 var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() };196 var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() };
197 const counting_bw = counting_writer.unbufferedWriter();197 var counting_bw = counting_writer.unbufferedWriter();
198 const err_msg = eb.getErrorMessage(err_msg_index);198 const err_msg = eb.getErrorMessage(err_msg_index);
199 if (err_msg.src_loc != .none) {199 if (err_msg.src_loc != .none) {
200 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));200 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
201 try counting_bw.writeByteNTimes(' ', indent);201 try counting_bw.splatByteAll(' ', indent);
202 try ttyconf.setColor(bw, .bold);202 try ttyconf.setColor(bw, .bold);
203 try counting_bw.print("{s}:{d}:{d}: ", .{203 try counting_bw.print("{s}:{d}:{d}: ", .{
204 eb.nullTerminatedString(src.data.src_path),204 eb.nullTerminatedString(src.data.src_path),
...@@ -210,7 +210,7 @@ fn renderErrorMessageToWriter(...@@ -210,7 +210,7 @@ fn renderErrorMessageToWriter(
210 try counting_bw.writeAll(": ");210 try counting_bw.writeAll(": ");
211 // This is the length of the part before the error message:211 // This is the length of the part before the error message:
212 // e.g. "file.zig:4:5: error: "212 // 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);
214 try ttyconf.setColor(bw, .reset);214 try ttyconf.setColor(bw, .reset);
215 try ttyconf.setColor(bw, .bold);215 try ttyconf.setColor(bw, .bold);
216 if (err_msg.count == 1) {216 if (err_msg.count == 1) {
...@@ -233,11 +233,11 @@ fn renderErrorMessageToWriter(...@@ -233,11 +233,11 @@ fn renderErrorMessageToWriter(
233 const before_caret = src.data.span_main - src.data.span_start;233 const before_caret = src.data.span_main - src.data.span_start;
234 // -1 since span.main includes the caret234 // -1 since span.main includes the caret
235 const after_caret = src.data.span_end -| src.data.span_main -| 1;235 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);
237 try ttyconf.setColor(bw, .green);237 try ttyconf.setColor(bw, .green);
238 try bw.writeByteNTimes('~', before_caret);238 try bw.splatByteAll('~', before_caret);
239 try bw.writeByte('^');239 try bw.writeByte('^');
240 try bw.writeByteNTimes('~', after_caret);240 try bw.splatByteAll('~', after_caret);
241 try bw.writeByte('\n');241 try bw.writeByte('\n');
242 try ttyconf.setColor(bw, .reset);242 try ttyconf.setColor(bw, .reset);
243 }243 }
...@@ -277,7 +277,7 @@ fn renderErrorMessageToWriter(...@@ -277,7 +277,7 @@ fn renderErrorMessageToWriter(
277 }277 }
278 } else {278 } else {
279 try ttyconf.setColor(bw, color);279 try ttyconf.setColor(bw, color);
280 try bw.writeByteNTimes(' ', indent);280 try bw.splatByteAll(' ', indent);
281 try bw.writeAll(kind);281 try bw.writeAll(kind);
282 try bw.writeAll(": ");282 try bw.writeAll(": ");
283 try ttyconf.setColor(bw, .reset);283 try ttyconf.setColor(bw, .reset);
...@@ -306,7 +306,7 @@ fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter,...@@ -306,7 +306,7 @@ fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter,
306 try bw.writeAll(line);306 try bw.writeAll(line);
307 if (lines.index == null) break;307 if (lines.index == null) break;
308 try bw.writeByte('\n');308 try bw.writeByte('\n');
309 try bw.writeByteNTimes(' ', indent);309 try bw.splatByteAll(' ', indent);
310 }310 }
311}311}
312312
lib/std/zig/LibCInstallation.zig+2-2
...@@ -370,7 +370,7 @@ fn findNativeIncludeDirWindows(...@@ -370,7 +370,7 @@ fn findNativeIncludeDirWindows(
370370
371 for (installs) |install| {371 for (installs) |install| {
372 result_buf.shrinkAndFree(0);372 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
375 var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {375 var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
376 error.FileNotFound,376 error.FileNotFound,
...@@ -417,7 +417,7 @@ fn findNativeCrtDirWindows(...@@ -417,7 +417,7 @@ fn findNativeCrtDirWindows(
417417
418 for (installs) |install| {418 for (installs) |install| {
419 result_buf.shrinkAndFree(0);419 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
422 var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {422 var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
423 error.FileNotFound,423 error.FileNotFound,