diff options
| author | Anhgelus Morhtuuzh <william@herges.fr> | 2026-04-19 14:02:37 +0200 |
|---|---|---|
| committer | Anhgelus Morhtuuzh <william@herges.fr> | 2026-04-19 14:02:37 +0200 |
| commit | d1480f97e3c8ce82151d409e7c9d1545d44f3a99 (patch) | |
| tree | 08337cb10e5c3fb6ddd820b0f117f33a20fb4328 | |
| parent | 8c5214df39ab82c3d42ccd492d8699f8a5aadb0a (diff) | |
feat(lib): export functions
| -rw-r--r-- | build.zig | 3 | ||||
| -rw-r--r-- | src/root.zig | 83 |
2 files changed, 76 insertions, 10 deletions
@@ -7,6 +7,7 @@ pub fn build(b: *std.Build) void { const mod = b.addModule("typdown", .{ .root_source_file = b.path("src/root.zig"), .target = target, + .link_libc = true, }); //const exe = b.addExecutable(.{ @@ -30,7 +31,7 @@ pub fn build(b: *std.Build) void { //if (b.args) |args| { // run_cmd.addArgs(args); //} - + const mod_tests = b.addTest(.{ .root_module = mod, }); diff --git a/src/root.zig b/src/root.zig index 2bc3125..bd183ff 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,19 +1,84 @@ const std = @import("std"); pub const parser = @import("parser.zig"); +pub const Error = parser.Error; -pub fn bufferedPrint() !void { - // Stdout is for the actual output of your application, for example if you - // are implementing gzip, then only the compressed bytes should be sent to - // stdout, not any debugging messages. - var stdout_buffer: [1024]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); - const stdout = &stdout_writer.interface; +fn getErrorCode(err: Error) u8 { + return switch (err) { + Error.OutOfMemory => 1, + Error.InvalidUtf8 => 2, + Error.FeatureNotSupported => 3, + Error.ModifierNotClosed => 4, + Error.InvalidTitleContent => 5, + }; +} - try stdout.print("Run `zig build test` to run the tests.\n", .{}); +/// Returns the static string linked with the error code. +export fn getErrorString(code: u8) [*:0]const u8 { + return switch (code) { + 1 => "out of memory", + 2 => "invalid UTF-8", + 3 => "feature not supported", + 4 => "modifier not closed", + 5 => "invalid title content", + else => unreachable, + }; +} - try stdout.flush(); // Don't forget to flush! +/// Parse the content. +/// Code is a pointer to an u8 populated with an error code > 0. +/// +/// Returns a not null strings and set the code to 0 if everything is fine. +/// Else, it returns null and set an error code above 0. +/// Use getErrorString to retrieve the string linked with the error code. +export fn parse(content: [*:0]const u8, code: *u8) ?[*:0]const u8 { + const alloc = std.heap.c_allocator; + const res = parser.parse(alloc, std.mem.span(content)) catch |err| { + code.* = getErrorCode(err); + return null; + }; + defer alloc.free(res); + code.* = 0; + return alloc.dupeZ(u8, res) catch |err| { + code.* = getErrorCode(err); + return null; + }; } test { std.testing.refAllDeclsRecursive(@This()); } + +fn doTest(content: [*:0]const u8, exp: []const u8, exp_code: u8) !void { + const expect = std.testing.expect; + + var code: u8 = undefined; + const raw = parse(content, &code) orelse { + expect(code == exp_code) catch |err| { + std.debug.print("{}\n", .{code}); + return err; + }; + return; + }; + const res = std.mem.span(raw); + defer std.heap.c_allocator.free(res); + + expect(code == 0) catch |err| { + std.debug.print("{}\n", .{code}); + return err; + }; + expect(std.mem.eql(u8, exp, res)) catch |err| { + std.debug.print("{s}\n", .{res}); + return err; + }; +} + +test "exported parse" { + // valid + try doTest("hello world", "<p>hello world</p>", 0); + try doTest("he*ll*o world", "<p>he<b>ll</b>o world</p>", 0); + try doTest("# title", "<h1>title</h1>", 0); + + // invalid + try doTest("he*llo world", "", getErrorCode(Error.ModifierNotClosed)); + try doTest("# title :::", "", getErrorCode(Error.InvalidTitleContent)); +} |
