root.zig (2873B)
1 const std = @import("std"); 2 const tlds = @import("tlds.zig"); 3 const testing = std.testing; 4 5 export fn fence_is_top_level_domain(dom: [*:0]const u8) bool { 6 return isTopLevelDomain(std.mem.span(dom)); 7 } 8 9 fn isTopLevelDomain(dom: []const u8) bool { 10 for (tlds.tab) |tld| { 11 if (std.mem.eql(u8, dom, tld)) return true; 12 } 13 return false; 14 } 15 16 fn isRfc822Char(c: u8) bool { 17 if (!std.ascii.isAscii(c)) return false; 18 switch (c) { 19 0...32, 127 => return false, 20 '(', ')', ',', ';', '<', '>', '"' => return false, 21 } 22 return true; 23 } 24 25 fn quoteDepth(line: []const u8) u8 { 26 const ln = std.mem.trim(u8, line, &std.ascii.whitespace); 27 const first = std.mem.indexOfScalar(u8, ln, '>') orelse return 0; 28 if (first != 0) return 0; 29 30 var depth: u8 = 0; 31 const last = std.mem.lastIndexOfScalar(u8, ln, '>') orelse return 1; 32 for (line[first .. last + 1]) |c| { 33 if (c == '>') { 34 if (depth == 0xff) return depth; 35 depth += 1; 36 continue; 37 } 38 if (std.ascii.isWhitespace(c)) continue; 39 break; 40 } 41 return depth; 42 } 43 44 export fn quote_depth(line: [*:0]const u8) c_int { 45 const n = quoteDepth(std.mem.span(line)); 46 return @as(c_int, n); 47 } 48 49 fn copyAfterLine(dst: std.fs.File, src: std.fs.File, key: []const u8) !usize { 50 var rbuf: [8192]u8 = undefined; 51 var rd = std.fs.File.reader(src, &rbuf).interface; 52 var wbuf: [8192]u8 = undefined; 53 var wr = std.fs.File.writer(dst, &wbuf).interface; 54 while (true) { 55 const line = try rd.takeDelimiterInclusive('\n'); 56 if (std.mem.startsWith(u8, line, key)) { 57 break; 58 } 59 } 60 const n = try rd.streamRemaining(&wr); 61 try wr.flush(); 62 return n; 63 } 64 65 export fn fence_copy_after_line(dst: [*:0]const u8, src: [*:0]const u8, line: [*:0]const u8) usize { 66 const fdst = std.fs.cwd().createFile(std.mem.span(dst), .{}) catch return 0; 67 defer fdst.close(); 68 const fsrc = std.fs.cwd().openFile(std.mem.span(src), .{}) catch return 0; 69 defer fsrc.close(); 70 return copyAfterLine(fdst, fsrc, std.mem.span(line)) catch 0; 71 } 72 73 test "quote depth" { 74 const tests = [_]struct { []const u8, u8 }{ 75 .{ ">>> hello", 3 }, 76 .{ "> >> hello", 3 }, 77 .{ " > hello >", 1 }, 78 .{ "hello>>", 0 }, 79 .{ ">> hello >>", 2 }, 80 .{ "> \t> hello", 2 }, 81 .{ ">", 1 }, 82 .{ "xxx > hello >>", 0 }, 83 }; 84 for (tests) |t| { 85 const got = quoteDepth(t[0]); 86 errdefer std.debug.print("quote depth for \"{s}\"\n", .{t[0]}); 87 try testing.expectEqual(t[1], got); 88 } 89 } 90 91 test "check domains" { 92 try testing.expect(isTopLevelDomain("com")); 93 try testing.expect(isTopLevelDomain("69yamum") == false); 94 95 const str = [_:0]u8{ 'c', 'o', 'm', 0 }; 96 try testing.expect(fence_is_top_level_domain(str[0..])); 97 }