From e42b03acd81622909e2f9b191887fbd98b0755c9 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 6 May 2024 12:44:45 +0200 Subject: [PATCH] mime: extract string parser --- src/browser/mime.zig | 93 +++----------------------------------------- src/run_tests.zig | 3 ++ src/str/parser.zig | 88 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 87 deletions(-) create mode 100644 src/str/parser.zig diff --git a/src/browser/mime.zig b/src/browser/mime.zig index f7ec4763..73cc8dc9 100644 --- a/src/browser/mime.zig +++ b/src/browser/mime.zig @@ -1,6 +1,10 @@ const std = @import("std"); const testing = std.testing; +const strparser = @import("../str/parser.zig"); +const Reader = strparser.Reader; +const trim = strparser.trim; + const Self = @This(); const MimeError = error{ @@ -21,91 +25,6 @@ pub const Empty = Self{ .mtype = "", .msubtype = "" }; pub const HTML = Self{ .mtype = "text", .msubtype = "html" }; pub const Javascript = Self{ .mtype = "application", .msubtype = "javascript" }; -const reader = struct { - s: []const u8, - i: usize = 0, - - fn until(self: *reader, c: u8) []const u8 { - const ln = self.s.len; - const start = self.i; - while (self.i < ln) { - if (c == self.s[self.i]) return self.s[start..self.i]; - self.i += 1; - } - - return self.s[start..self.i]; - } - - fn tail(self: *reader) []const u8 { - if (self.i > self.s.len) return ""; - defer self.i = self.s.len; - return self.s[self.i..]; - } - - fn skip(self: *reader) bool { - if (self.i >= self.s.len) return false; - self.i += 1; - return true; - } -}; - -test "reader.skip" { - var r = reader{ .s = "foo" }; - try testing.expect(r.skip()); - try testing.expect(r.skip()); - try testing.expect(r.skip()); - try testing.expect(!r.skip()); - try testing.expect(!r.skip()); -} - -test "reader.tail" { - var r = reader{ .s = "foo" }; - try testing.expectEqualStrings("foo", r.tail()); - try testing.expectEqualStrings("", r.tail()); -} - -test "reader.until" { - var r = reader{ .s = "foo.bar.baz" }; - try testing.expectEqualStrings("foo", r.until('.')); - _ = r.skip(); - try testing.expectEqualStrings("bar", r.until('.')); - _ = r.skip(); - try testing.expectEqualStrings("baz", r.until('.')); - - r = reader{ .s = "foo" }; - try testing.expectEqualStrings("foo", r.until('.')); - - r = reader{ .s = "" }; - try testing.expectEqualStrings("", r.until('.')); -} - -fn trim(s: []const u8) []const u8 { - const ln = s.len; - if (ln == 0) { - return ""; - } - var start: usize = 0; - while (start < ln) { - if (!std.ascii.isWhitespace(s[start])) break; - start += 1; - } - - var end: usize = ln; - while (end > 0) { - if (!std.ascii.isWhitespace(s[end - 1])) break; - end -= 1; - } - - return s[start..end]; -} - -test "trim" { - try testing.expectEqualStrings("", trim("")); - try testing.expectEqualStrings("foo", trim("foo")); - try testing.expectEqualStrings("foo", trim(" \n\tfoo")); - try testing.expectEqualStrings("foo", trim("foo \n\t")); -} - // https://mimesniff.spec.whatwg.org/#http-token-code-point fn isHTTPCodePoint(c: u8) bool { return switch (c) { @@ -133,7 +52,7 @@ pub fn parse(s: []const u8) Self.MimeError!Self { if (ln > 255) return MimeError.TooBig; var res = Self{ .mtype = "", .msubtype = "" }; - var r = reader{ .s = s }; + var r = Reader{ .s = s }; res.mtype = trim(r.until('/')); if (res.mtype.len == 0) return MimeError.Invalid; @@ -150,7 +69,7 @@ pub fn parse(s: []const u8) Self.MimeError!Self { // parse well known parameters. // don't check invalid parameter format. - var rp = reader{ .s = res.params }; + var rp = Reader{ .s = res.params }; while (true) { const name = trim(rp.until('=')); if (!rp.skip()) return res; diff --git a/src/run_tests.zig b/src/run_tests.zig index 275b48ad..dd424238 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -264,6 +264,9 @@ test { const dumpTest = @import("browser/dump.zig"); std.testing.refAllDecls(dumpTest); + const mimeTest = @import("browser/mime.zig"); + std.testing.refAllDecls(mimeTest); + const cssTest = @import("css/css.zig"); std.testing.refAllDecls(cssTest); diff --git a/src/str/parser.zig b/src/str/parser.zig new file mode 100644 index 00000000..32c1741a --- /dev/null +++ b/src/str/parser.zig @@ -0,0 +1,88 @@ +// some utils to parser strings. +const std = @import("std"); +const testing = std.testing; + +pub const Reader = struct { + s: []const u8, + i: usize = 0, + + pub fn until(self: *Reader, c: u8) []const u8 { + const ln = self.s.len; + const start = self.i; + while (self.i < ln) { + if (c == self.s[self.i]) return self.s[start..self.i]; + self.i += 1; + } + + return self.s[start..self.i]; + } + + pub fn tail(self: *Reader) []const u8 { + if (self.i > self.s.len) return ""; + defer self.i = self.s.len; + return self.s[self.i..]; + } + + pub fn skip(self: *Reader) bool { + if (self.i >= self.s.len) return false; + self.i += 1; + return true; + } +}; + +test "Reader.skip" { + var r = Reader{ .s = "foo" }; + try testing.expect(r.skip()); + try testing.expect(r.skip()); + try testing.expect(r.skip()); + try testing.expect(!r.skip()); + try testing.expect(!r.skip()); +} + +test "Reader.tail" { + var r = Reader{ .s = "foo" }; + try testing.expectEqualStrings("foo", r.tail()); + try testing.expectEqualStrings("", r.tail()); +} + +test "Reader.until" { + var r = Reader{ .s = "foo.bar.baz" }; + try testing.expectEqualStrings("foo", r.until('.')); + _ = r.skip(); + try testing.expectEqualStrings("bar", r.until('.')); + _ = r.skip(); + try testing.expectEqualStrings("baz", r.until('.')); + + r = Reader{ .s = "foo" }; + try testing.expectEqualStrings("foo", r.until('.')); + + r = Reader{ .s = "" }; + try testing.expectEqualStrings("", r.until('.')); +} + +pub fn trim(s: []const u8) []const u8 { + const ln = s.len; + if (ln == 0) { + return ""; + } + var start: usize = 0; + while (start < ln) { + if (!std.ascii.isWhitespace(s[start])) break; + start += 1; + } + + var end: usize = ln; + while (end > 0) { + if (!std.ascii.isWhitespace(s[end - 1])) break; + end -= 1; + } + + return s[start..end]; +} + +test "trim" { + try testing.expectEqualStrings("", trim("")); + try testing.expectEqualStrings("foo", trim("foo")); + try testing.expectEqualStrings("foo", trim(" \n\tfoo")); + try testing.expectEqualStrings("foo", trim("foo \n\t")); +}