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}