const c = @import("ffi").c; const std = @import("std"); const mem = std.mem; const alloc = std.heap.c_allocator; pub const ListEntry = extern struct { next: ?*ListEntry = null, value: [*c]u8 = null, name: [*c]u8 = null, const Self = @This(); pub fn asC(self: *Self) *c.struct_udev_list_entry { return @ptrCast(self); } fn fromC(ptr: *c.struct_udev_list_entry) *Self { return @ptrCast(@alignCast(ptr)); } fn deinit(self: *Self) void { if (self.value) |value| { alloc.free(mem.span(value)); } if (self.name) |name| { alloc.free(mem.span(name)); } } }; export fn udev_list_entry_init(list_entry: ?*c.struct_udev_list_entry) callconv(.c) void { const ptr = list_entry orelse return; const self = ListEntry.fromC(ptr); self.value = null; self.name = null; self.next = null; } export fn udev_list_entry_free(list_entry: ?*c.struct_udev_list_entry) callconv(.c) void { const ptr = list_entry orelse return; const self = ListEntry.fromC(ptr); self.deinit(); alloc.destroy(self); } pub export fn udev_list_entry_free_all(list_entry: ?*c.struct_udev_list_entry) callconv(.c) void { const ptr = list_entry orelse return; var current = ListEntry.fromC(ptr).next; while (current) |entry| { current = entry.next; udev_list_entry_free(entry.asC()); } } pub export fn udev_list_entry_add(list_entry: ?*c.struct_udev_list_entry, name: [*c]const u8, value: [*c]const u8, uniq: c_int) callconv(.c) ?*c.udev_list_entry { const ptr = list_entry orelse return null; const name_ptr = name orelse return null; const self = ListEntry.fromC(ptr); if (uniq != 0) blk: { const list_entry2 = udev_list_entry_get_by_name(list_entry, name_ptr) orelse break :blk; const v = value orelse break :blk; if (list_entry2.value) |old_value| { if (mem.eql(u8, mem.span(old_value), mem.span(v))) { return list_entry2; } alloc.free(mem.span(old_value)); list_entry2.value = null; } list_entry2.value = alloc.dupeZ(u8, mem.span(v)) catch return null; return list_entry2; } const list_entry2 = alloc.create(ListEntry) catch return null; list_entry2.* = .{}; list_entry2.name = alloc.dupeZ(u8, mem.span(name_ptr)) catch { alloc.destroy(list_entry2); return null; }; if (value) |v| { list_entry2.value = alloc.dupeZ(u8, mem.span(v)) catch { list_entry2.deinit(); alloc.destroy(list_entry2); return null; }; } list_entry2.next = self.next; self.next = list_entry2; return list_entry2.asC(); } export fn udev_list_entry_get_next( list_entry: ?*c.struct_udev_list_entry, ) callconv(.c) ?*c.struct_udev_list_entry { if (list_entry) |entry| { return entry.next; } return null; } export fn udev_list_entry_get_by_name( list_entry: ?*c.struct_udev_list_entry, name: [*c]const u8, ) callconv(.c) ?*c.struct_udev_list_entry { const list_entry_ptr = list_entry orelse return null; const name_ptr = name orelse return null; var self = ListEntry.fromC(list_entry_ptr); if (self.name) |self_name| { if (mem.eql(u8, mem.span(self_name), mem.span(name_ptr))) { return self.asC(); } } while (self.next) |next| { self = next; if (self.name) |self_name| { if (mem.eql(u8, mem.span(self_name), mem.span(name_ptr))) { return self.asC(); } } } return null; } export fn udev_list_entry_get_name( list_entry: ?*c.struct_udev_list_entry, ) callconv(.c) [*c]const u8 { if (list_entry) |entry| { return entry.name; } return null; } export fn udev_list_entry_get_value( list_entry: ?*c.struct_udev_list_entry, ) callconv(.c) [*c]const u8 { if (list_entry) |entry| { return entry.value; } return null; }