master
1const std = @import("std");
2const fs = std.fs;
3const mem = std.mem;
4const ascii = std.ascii;
5
6const catalog_txt = @embedFile("crc/catalog.txt");
7
8pub fn main() anyerror!void {
9 var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
10 defer arena_state.deinit();
11 const arena = arena_state.allocator();
12
13 const args = try std.process.argsAlloc(arena);
14 if (args.len <= 1) printUsageAndExit(args[0]);
15
16 const zig_src_root = args[1];
17 if (mem.startsWith(u8, zig_src_root, "-")) printUsageAndExit(args[0]);
18
19 var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{});
20 defer zig_src_dir.close();
21
22 const hash_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash" });
23 var hash_target_dir = try zig_src_dir.makeOpenPath(hash_sub_path, .{});
24 defer hash_target_dir.close();
25
26 const crc_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash", "crc" });
27 var crc_target_dir = try zig_src_dir.makeOpenPath(crc_sub_path, .{});
28 defer crc_target_dir.close();
29
30 var zig_code_file = try hash_target_dir.createFile("crc.zig", .{});
31 defer zig_code_file.close();
32 var zig_code_file_buffer: [4096]u8 = undefined;
33 var zig_code_file_writer = zig_code_file.writer(&zig_code_file_buffer);
34 const code_writer = &zig_code_file_writer.interface;
35
36 try code_writer.writeAll(
37 \\//! This file is auto-generated by tools/update_crc_catalog.zig.
38 \\
39 \\const impl = @import("crc/impl.zig");
40 \\
41 \\pub const Crc = impl.Crc;
42 \\pub const Polynomial = impl.Polynomial;
43 \\pub const Crc32WithPoly = impl.Crc32WithPoly;
44 \\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly;
45 \\
46 \\pub const Crc32 = Crc32IsoHdlc;
47 \\
48 \\test {
49 \\ _ = @import("crc/test.zig");
50 \\}
51 \\
52 );
53
54 var zig_test_file = try crc_target_dir.createFile("test.zig", .{});
55 defer zig_test_file.close();
56 var zig_test_file_buffer: [4096]u8 = undefined;
57 var zig_test_file_writer = zig_test_file.writer(&zig_test_file_buffer);
58 const test_writer = &zig_test_file_writer.interface;
59
60 try test_writer.writeAll(
61 \\//! This file is auto-generated by tools/update_crc_catalog.zig.
62 \\
63 \\const std = @import("std");
64 \\const testing = std.testing;
65 \\const verify = @import("../verify.zig");
66 \\const crc = @import("../crc.zig");
67 \\
68 \\test "crc32 ieee regression" {
69 \\ const crc32 = crc.Crc32IsoHdlc;
70 \\ try testing.expectEqual(crc32.hash(""), 0x00000000);
71 \\ try testing.expectEqual(crc32.hash("a"), 0xe8b7be43);
72 \\ try testing.expectEqual(crc32.hash("abc"), 0x352441c2);
73 \\}
74 \\
75 \\test "crc32 castagnoli regression" {
76 \\ const crc32 = crc.Crc32Iscsi;
77 \\ try testing.expectEqual(crc32.hash(""), 0x00000000);
78 \\ try testing.expectEqual(crc32.hash("a"), 0xc1d04330);
79 \\ try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7);
80 \\}
81 \\
82 \\test "crc32 koopman regression" {
83 \\ const crc32 = crc.Koopman;
84 \\ try testing.expectEqual(crc32.hash(""), 0x00000000);
85 \\ try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a);
86 \\ try testing.expectEqual(crc32.hash("abc"), 0xba2322ac);
87 \\}
88 \\
89 );
90
91 var reader: std.Io.Reader = .fixed(catalog_txt);
92
93 while (try reader.takeDelimiter('\n')) |line| {
94 if (line.len == 0 or line[0] == '#')
95 continue;
96
97 var width: []const u8 = undefined;
98 var poly: []const u8 = undefined;
99 var init: []const u8 = undefined;
100 var refin: []const u8 = undefined;
101 var refout: []const u8 = undefined;
102 var xorout: []const u8 = undefined;
103 var check: []const u8 = undefined;
104 var residue: []const u8 = undefined;
105 var name: []const u8 = undefined;
106
107 var it = mem.splitSequence(u8, line, " ");
108 while (it.next()) |property| {
109 const i = mem.indexOf(u8, property, "=").?;
110 const key = property[0..i];
111 const value = property[i + 1 ..];
112 if (mem.eql(u8, key, "width")) {
113 width = value;
114 } else if (mem.eql(u8, key, "poly")) {
115 poly = value;
116 } else if (mem.eql(u8, key, "init")) {
117 init = value;
118 } else if (mem.eql(u8, key, "refin")) {
119 refin = value;
120 } else if (mem.eql(u8, key, "refout")) {
121 refout = value;
122 } else if (mem.eql(u8, key, "xorout")) {
123 xorout = value;
124 } else if (mem.eql(u8, key, "check")) {
125 check = value;
126 } else if (mem.eql(u8, key, "residue")) {
127 residue = value;
128 } else if (mem.eql(u8, key, "name")) {
129 name = mem.trim(u8, value, "\"");
130 } else {
131 unreachable;
132 }
133 }
134
135 const snakecase = try ascii.allocLowerString(arena, name);
136 defer arena.free(snakecase);
137
138 _ = mem.replace(u8, snakecase, "-", "_", snakecase);
139 _ = mem.replace(u8, snakecase, "/", "_", snakecase);
140
141 var buf = try std.array_list.Managed(u8).initCapacity(arena, snakecase.len);
142 defer buf.deinit();
143
144 var prev: u8 = 0;
145 for (snakecase, 0..) |c, i| {
146 if (c == '_') {
147 // do nothing
148 } else if (i == 0) {
149 buf.appendAssumeCapacity(ascii.toUpper(c));
150 } else if (prev == '_') {
151 buf.appendAssumeCapacity(ascii.toUpper(c));
152 } else {
153 buf.appendAssumeCapacity(c);
154 }
155 prev = c;
156 }
157
158 const camelcase = buf.items;
159
160 try code_writer.writeAll(try std.fmt.allocPrint(arena,
161 \\
162 \\pub const {s} = Crc(u{s}, .{{
163 \\ .polynomial = {s},
164 \\ .initial = {s},
165 \\ .reflect_input = {s},
166 \\ .reflect_output = {s},
167 \\ .xor_output = {s},
168 \\}});
169 \\
170 , .{ camelcase, width, poly, init, refin, refout, xorout }));
171
172 try test_writer.writeAll(try std.fmt.allocPrint(arena,
173 \\
174 \\test "{0s}" {{
175 \\ const {1s} = crc.{1s};
176 \\
177 \\ try testing.expectEqual(@as(u{2s}, {3s}), {1s}.hash("123456789"));
178 \\
179 \\ var c = {1s}.init();
180 \\ c.update("1234");
181 \\ c.update("56789");
182 \\ try testing.expectEqual(@as(u{2s}, {3s}), c.final());
183 \\}}
184 \\
185 , .{ name, camelcase, width, check }));
186 }
187
188 try code_writer.flush();
189 try test_writer.flush();
190}
191
192fn printUsageAndExit(arg0: []const u8) noreturn {
193 const w, _ = std.debug.lockStderrWriter(&.{});
194 defer std.debug.unlockStderrWriter();
195 printUsage(w, arg0) catch std.process.exit(2);
196 std.process.exit(1);
197}
198
199fn printUsage(w: *std.Io.Writer, arg0: []const u8) std.Io.Writer.Error!void {
200 return w.print(
201 \\Usage: {s} /path/git/zig
202 \\
203 , .{arg0});
204}