const std = @import("std"); const fs = std.fs; const mem = std.mem; const ascii = std.ascii; const catalog_txt = @embedFile("crc/catalog.txt"); pub fn main() anyerror!void { var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const args = try std.process.argsAlloc(arena); if (args.len <= 1) { usageAndExit(std.io.getStdErr(), args[0], 1); } const zig_src_root = args[1]; if (mem.startsWith(u8, zig_src_root, "-")) { usageAndExit(std.io.getStdErr(), args[0], 1); } var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{}); defer zig_src_dir.close(); const hash_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash" }); var hash_target_dir = try zig_src_dir.makeOpenPath(hash_sub_path, .{}); defer hash_target_dir.close(); const crc_sub_path = try fs.path.join(arena, &.{ "lib", "std", "hash", "crc" }); var crc_target_dir = try zig_src_dir.makeOpenPath(crc_sub_path, .{}); defer crc_target_dir.close(); var zig_code_file = try hash_target_dir.createFile("crc.zig", .{}); defer zig_code_file.close(); var cbw = std.io.bufferedWriter(zig_code_file.writer()); defer cbw.flush() catch unreachable; const code_writer = cbw.writer(); try code_writer.writeAll( \\//! This file is auto-generated by tools/update_crc_catalog.zig. \\ \\const impl = @import("crc/impl.zig"); \\ \\pub const Crc = impl.Crc; \\pub const Polynomial = impl.Polynomial; \\pub const Crc32WithPoly = impl.Crc32WithPoly; \\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; \\ \\pub const Crc32 = Crc32IsoHdlc; \\ \\test { \\ _ = @import("crc/test.zig"); \\} \\ ); var zig_test_file = try crc_target_dir.createFile("test.zig", .{}); defer zig_test_file.close(); var tbw = std.io.bufferedWriter(zig_test_file.writer()); defer tbw.flush() catch unreachable; const test_writer = tbw.writer(); try test_writer.writeAll( \\//! This file is auto-generated by tools/update_crc_catalog.zig. \\ \\const std = @import("std"); \\const testing = std.testing; \\const verify = @import("../verify.zig"); \\const crc = @import("../crc.zig"); \\ \\test "crc32 ieee regression" { \\ const crc32 = crc.Crc32IsoHdlc; \\ try testing.expectEqual(crc32.hash(""), 0x00000000); \\ try testing.expectEqual(crc32.hash("a"), 0xe8b7be43); \\ try testing.expectEqual(crc32.hash("abc"), 0x352441c2); \\} \\ \\test "crc32 castagnoli regression" { \\ const crc32 = crc.Crc32Iscsi; \\ try testing.expectEqual(crc32.hash(""), 0x00000000); \\ try testing.expectEqual(crc32.hash("a"), 0xc1d04330); \\ try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7); \\} \\ \\test "crc32 koopman regression" { \\ const crc32 = crc.Koopman; \\ try testing.expectEqual(crc32.hash(""), 0x00000000); \\ try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a); \\ try testing.expectEqual(crc32.hash("abc"), 0xba2322ac); \\} \\ ); var stream = std.io.fixedBufferStream(catalog_txt); const reader = stream.reader(); while (try reader.readUntilDelimiterOrEofAlloc(arena, '\n', std.math.maxInt(usize))) |line| { if (line.len == 0 or line[0] == '#') continue; var width: []const u8 = undefined; var poly: []const u8 = undefined; var init: []const u8 = undefined; var refin: []const u8 = undefined; var refout: []const u8 = undefined; var xorout: []const u8 = undefined; var check: []const u8 = undefined; var residue: []const u8 = undefined; var name: []const u8 = undefined; var it = mem.splitSequence(u8, line, " "); while (it.next()) |property| { const i = mem.indexOf(u8, property, "=").?; const key = property[0..i]; const value = property[i + 1 ..]; if (mem.eql(u8, key, "width")) { width = value; } else if (mem.eql(u8, key, "poly")) { poly = value; } else if (mem.eql(u8, key, "init")) { init = value; } else if (mem.eql(u8, key, "refin")) { refin = value; } else if (mem.eql(u8, key, "refout")) { refout = value; } else if (mem.eql(u8, key, "xorout")) { xorout = value; } else if (mem.eql(u8, key, "check")) { check = value; } else if (mem.eql(u8, key, "residue")) { residue = value; } else if (mem.eql(u8, key, "name")) { name = mem.trim(u8, value, "\""); } else { unreachable; } } const snakecase = try ascii.allocLowerString(arena, name); defer arena.free(snakecase); _ = mem.replace(u8, snakecase, "-", "_", snakecase); _ = mem.replace(u8, snakecase, "/", "_", snakecase); var buf = try std.ArrayList(u8).initCapacity(arena, snakecase.len); defer buf.deinit(); var prev: u8 = 0; for (snakecase, 0..) |c, i| { if (c == '_') { // do nothing } else if (i == 0) { buf.appendAssumeCapacity(ascii.toUpper(c)); } else if (prev == '_') { buf.appendAssumeCapacity(ascii.toUpper(c)); } else { buf.appendAssumeCapacity(c); } prev = c; } const camelcase = buf.items; try code_writer.writeAll(try std.fmt.allocPrint(arena, \\ \\pub const {s} = Crc(u{s}, .{{ \\ .polynomial = {s}, \\ .initial = {s}, \\ .reflect_input = {s}, \\ .reflect_output = {s}, \\ .xor_output = {s}, \\}}); \\ , .{ camelcase, width, poly, init, refin, refout, xorout })); try test_writer.writeAll(try std.fmt.allocPrint(arena, \\ \\test "{0s}" {{ \\ const {1s} = crc.{1s}; \\ \\ try testing.expectEqual(@as(u{2s}, {3s}), {1s}.hash("123456789")); \\ \\ var c = {1s}.init(); \\ c.update("1234"); \\ c.update("56789"); \\ try testing.expectEqual(@as(u{2s}, {3s}), c.final()); \\}} \\ , .{ name, camelcase, width, check })); } } fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { file.writer().print( \\Usage: {s} /path/git/zig \\ , .{arg0}) catch std.process.exit(1); std.process.exit(code); }