const std = @import("std"); const fern = @import("fern"); const zlua = @import("zlua"); const Lua = zlua.Lua; const maivi = @import("../root.zig"); pub fn lua_openstr(l: *Lua) !i32 { l.createTable(0, 2); l.pushFunction(zlua.wrap(len)); l.setField(-2, "len"); l.pushFunction(zlua.wrap(split)); l.setField(-2, "split"); l.pushFunction(zlua.wrap(escape)); l.setField(-2, "escape"); return 1; } pub fn len(l: *Lua) !i32 { l.argCheck(l.isString(-1), -1, "string"); const str = try l.toString(-1); const s = try maivi.allocator.dupe(u8, str); defer maivi.allocator.free(s); const str_len = try std.unicode.calcUtf16LeLen(str); l.pushInteger(@intCast(str_len)); return 1; } pub fn split(l: *Lua) !i32 { l.argCheck(l.isString(-2), -2, "string"); l.argCheck(l.isString(-1), -1, "string"); const str = try l.toString(-2); const s = try maivi.allocator.dupe(u8, str); defer maivi.allocator.free(s); const sep_str = try l.toString(-1); const sep = try maivi.allocator.dupe(u8, sep_str); defer maivi.allocator.free(sep); l.newTable(); var it = std.mem.splitSequence(u8, s, sep); while (it.next()) |x| { _ = l.pushString(x); const index = l.lenRaw(-2) + 1; l.setIndexRaw(-2, @intCast(index)); } return 1; } pub fn escape(l: *Lua) !i32 { l.argCheck(l.isString(-1), -1, "string"); const stack_size_on_entry = l.getTop(); const strz = try l.toString(-1); var result: std.ArrayList(u8) = try .initCapacity(maivi.allocator, 0x100); defer result.deinit(maivi.allocator); for (strz) |char| { const escaped: ?[]const u8 = switch (char) { '<' => "<", '>' => ">", '&' => "&", '"' => """, else => null, }; if (escaped) |e| try result.appendSlice(maivi.allocator, e) else try result.append(maivi.allocator, char); } const escaped = try result.toOwnedSlice(maivi.allocator); defer maivi.allocator.free(escaped); if (l.getTop() != stack_size_on_entry) return error.UnexpectedStackSize; _ = l.pushString(escaped); return 1; }