//! Minimal CSV helpers shared by the `/system/configuration/*.csv` config files — the device
//! registry (`/system/configuration/devices.csv`) and the init service list (`/system/configuration/init.csv`).
//! Freestanding, no allocator: returned fields are slices into the source line,
//! so the source must outlive them. `#` starts a comment (whole-line or trailing);
//! whitespace around a field is trimmed, so columns may be padded for alignment.

const std = @import("std");

/// Strip a trailing `#` comment and surrounding whitespace from one raw line.
/// A blank or comment-only line returns "" (length 0) — the caller's skip signal.
pub fn stripComment(raw: []const u8) []const u8 {
    const body = if (std.mem.indexOfScalar(u8, raw, '#')) |hash| raw[0..hash] else raw;
    return std.mem.trim(u8, body, " \t\r\n");
}

/// Iterate the comma-separated fields of a line body, each trimmed of spaces and
/// tabs. Build it from a `stripComment`ed body.
pub const Fields = struct {
    inner: std.mem.SplitIterator(u8, .scalar),

    /// The next field, trimmed, or null when the row is exhausted.
    pub fn next(self: *Fields) ?[]const u8 {
        const field = self.inner.next() orelse return null;
        return std.mem.trim(u8, field, " \t");
    }
};

pub fn fields(body: []const u8) Fields {
    return .{ .inner = std.mem.splitScalar(u8, body, ',') };
}

// --- tests -------------------------------------------------------------------

const testing = std.testing;

test "stripComment trims and drops comments" {
    try testing.expectEqualStrings("a, b", stripComment("  a, b  # trailing\r\n"));
    try testing.expectEqualStrings("", stripComment("   # whole-line comment"));
    try testing.expectEqualStrings("", stripComment("   \t "));
    try testing.expectEqualStrings("x", stripComment("x"));
}

test "fields splits and trims each column" {
    var it = fields(stripComment("pci,  03 , 80  ,  /system/drivers/x  # note"));
    try testing.expectEqualStrings("pci", it.next().?);
    try testing.expectEqualStrings("03", it.next().?);
    try testing.expectEqualStrings("80", it.next().?);
    try testing.expectEqualStrings("/system/drivers/x", it.next().?);
    try testing.expect(it.next() == null);
}

test "a single field yields one column then null" {
    var it = fields(stripComment("/system/services/input"));
    try testing.expectEqualStrings("/system/services/input", it.next().?);
    try testing.expect(it.next() == null);
}
