1const std = @import("std");
2const zfetch = @import("zfetch");
3const fmtValueLiteral = @import("fmt-valueliteral").fmtValueLiteral;
4const ansi = @import("ansi");
5
6pub const version = "17.0.0";
7
8pub fn Main(comptime T: type) type {
9 comptime std.debug.assert(@hasDecl(T, "source_file"));
10 comptime std.debug.assert(@hasDecl(T, "dest_file"));
11 comptime std.debug.assert(@hasDecl(T, "dest_header"));
12 comptime std.debug.assert(@hasDecl(T, "dest_footer"));
13 comptime std.debug.assert(@hasDecl(T, "exec"));
14 return struct {
15 pub fn do() !void {
16 var gpa = std.heap.GeneralPurposeAllocator(.{}){};
17 const alloc = gpa.allocator();
18 defer _ = gpa.deinit();
19
20 const max_size = std.math.maxInt(usize);
21 const source_url = "https://unicode.org/Public/" ++ version ++ "/ucd/" ++ T.source_file ++ ".txt";
22
23 //
24 std.log.info("{s}", .{T.dest_file});
25
26 const file = try std.fs.cwd().createFile(T.dest_file, .{});
27 defer file.close();
28 var bufw = std.io.bufferedWriter(file.writer());
29 const w = bufw.writer();
30
31 try w.writeAll(
32 \\// This file is part of the Unicode Character Database
33 \\// For documentation, see http://www.unicode.org/reports/tr44/
34 \\//
35 \\
36 );
37 try w.print(
38 \\// Based on the source file: {s}
39 \\//
40 \\// zig fmt: off
41 \\
42 \\
43 , .{source_url});
44 try w.writeAll(T.dest_header);
45
46 const req = try zfetch.Request.init(alloc, source_url, null);
47 defer req.deinit();
48 try req.do(.GET, null, null);
49 const r = req.reader();
50
51 var line_num: usize = 1;
52 std.debug.print("0", .{});
53
54 var arena = std.heap.ArenaAllocator.init(alloc);
55 defer arena.deinit();
56 while (true) {
57 const line_raw = r.readUntilDelimiterAlloc(alloc, '\n', max_size) catch |err| switch (err) {
58 error.EndOfStream => break,
59 else => |e| return e,
60 };
61 defer alloc.free(line_raw);
62
63 var real = std.mem.splitScalar(u8, line_raw, '#');
64 const line = real.first();
65
66 if (line.len == 0) {
67 continue;
68 }
69
70 try T.exec(arena.allocator(), line, w);
71
72 std.debug.print("{s}", .{ansi.csi.CursorHorzAbs(1)});
73 std.debug.print("{s}", .{ansi.csi.EraseInLine(0)});
74 std.debug.print("{d}", .{line_num});
75 line_num += 1;
76 }
77 std.debug.print("\n", .{});
78 try w.writeAll(T.dest_footer);
79 if (@hasDecl(T, "after")) try T.after(arena.allocator(), w);
80 try bufw.flush();
81 }
82 };
83}
84
85pub fn nullify(input: ?[]const u8) ?[]const u8 {
86 if (input == null) return null;
87 if (input.?.len == 0) return null;
88 return input;
89}
90
91pub fn RangeEnum(comptime prop: []const u8) type {
92 return struct {
93 pub fn exec(alloc: std.mem.Allocator, line: []const u8, writer: anytype) !void {
94 _ = alloc;
95 var it = std.mem.tokenizeAny(u8, line, "; ");
96
97 const first = it.next().?;
98 const next = std.mem.trimRight(u8, it.next().?, "#");
99
100 if (std.mem.indexOf(u8, first, "..")) |index| {
101 const start = first[0..index];
102 const end = first[index + 2 ..];
103 try writer.print(" .{{ .from = 0x{s}, .to = 0x{s}, .{s} = .{s} }},\n", .{ start, end, prop, next });
104 } else {
105 try writer.print(" .{{ .from = 0x{s}, .to = 0x{s}, .{s} = .{s} }},\n", .{ first, first, prop, next });
106 }
107 }
108 };
109}
110
111pub fn printCodepoint(writer: anytype, input: []const u8) !void {
112 try writer.print(" 0x{s},", .{input});
113}
114
115pub fn printSeq(writer: anytype, input: []const u8) !void {
116 var jt = std.mem.tokenizeScalar(u8, input, ' ');
117 try writer.writeAll(" &.{");
118 while (jt.next()) |jtem| {
119 try printCodepoint(writer, jtem);
120 }
121 try writer.writeAll(" },");
122}