1const std = @import("std");
2const File = std.fs.File;
3const Reader = std.fs.File.Reader;
4const Writer = std.fs.File.Writer;
5
6pub fn main() !void {
7 const in = std.io.getStdIn();
8 const out = std.io.getStdOut();
9 Uf.init().streamCopy(in.reader(), out.writer()) catch |err| {
10 try std.io.getStdErr().writer().print("Error {}", .{err});
11 };
12}
13
14const buf_size = 1_000_000;
15
16const Uf = struct {
17 const Self = @This();
18
19 var out_buf: [buf_size]u8 = undefined;
20 var out_index: u32 = 0;
21
22 fn init() Self {
23 return Self{};
24 }
25
26 fn flush(_: Self, out: anytype) !void {
27 _ = try out.write(out_buf[0..out_index]);
28 out_index = 0;
29 }
30
31 fn writeChar(self: Self, out: anytype, c: u8) !void {
32 if (out_index >= buf_size) {
33 try self.flush(out);
34 }
35 out_buf[out_index] = c;
36 out_index += 1;
37 }
38
39 fn streamCopy(self: Self, reader: anytype, writer: anytype) !void {
40 var hit = false;
41 var second = false;
42 var in_buf: [buf_size]u8 = undefined;
43 while (true) {
44 const size = try reader.read(&in_buf);
45
46 for (in_buf[0..size]) |c| {
47 if (hit and c == '\n') {
48 if (second == false) {
49 second = true;
50 } else {
51 continue;
52 }
53 } else if (hit and c != '\n') {
54 if (second) {
55 try self.writeChar(writer, '\n');
56 } else {
57 try self.writeChar(writer, ' ');
58 }
59 hit = false;
60 second = false;
61 } else if (c == '\n') {
62 hit = true;
63 continue;
64 }
65
66 try self.writeChar(writer, c);
67 }
68
69 if (size != in_buf.len) {
70 try self.flush(writer);
71 return;
72 }
73 }
74 }
75};
76
77test "Test format" {
78 const text_in =
79 \\# This is a markdown
80 \\
81 \\Lorem ipsum dolor sit amet,
82 \\consectetur adipiscing elit.
83 \\
84 \\
85 \\
86 \\Praesent pharetra sit amet ante sit amet consequat.
87 ;
88
89 const text_out =
90 \\# This is a markdown
91 \\
92 \\Lorem ipsum dolor sit amet, consectetur adipiscing elit.
93 \\
94 \\Praesent pharetra sit amet ante sit amet consequat.
95 ;
96
97 var stream = std.io.fixedBufferStream(text_in);
98
99 var list = std.ArrayList(u8).init(std.testing.allocator);
100 defer list.deinit();
101
102 try Uf.init().streamCopy(stream.reader(), list.writer());
103 try std.testing.expect(std.mem.eql(u8, text_out, list.items));
104}