Commit 4f6981bbe3

Andrew Kelley <andrew@ziglang.org>
2023-01-10 06:36:18
add std.Ini for basic .ini file parsing
1 parent f945c2a
Changed files (1)
lib
lib/std/Ini.zig
@@ -0,0 +1,66 @@
+bytes: []const u8,
+
+pub const SectionIterator = struct {
+    ini: Ini,
+    next_index: ?usize,
+    header: []const u8,
+
+    pub fn next(it: *SectionIterator) ?[]const u8 {
+        const bytes = it.ini.bytes;
+        const start = it.next_index orelse return null;
+        const end = mem.indexOfPos(u8, bytes, start, "\n[") orelse bytes.len;
+        const result = bytes[start..end];
+        if (mem.indexOfPos(u8, bytes, start, it.header)) |next_index| {
+            it.next_index = next_index + it.header.len;
+        } else {
+            it.next_index = null;
+        }
+        return result;
+    }
+};
+
+/// Asserts that `header` includes "\n[" at the beginning and "]\n" at the end.
+/// `header` must remain valid for the lifetime of the iterator.
+pub fn iterateSection(ini: Ini, header: []const u8) SectionIterator {
+    assert(mem.startsWith(u8, header, "\n["));
+    assert(mem.endsWith(u8, header, "]\n"));
+    const first_header = header[1..];
+    const next_index = if (mem.indexOf(u8, ini.bytes, first_header)) |i|
+        i + first_header.len
+    else
+        null;
+    return .{
+        .ini = ini,
+        .next_index = next_index,
+        .header = header,
+    };
+}
+
+const std = @import("std.zig");
+const mem = std.mem;
+const assert = std.debug.assert;
+const Ini = @This();
+const testing = std.testing;
+
+test iterateSection {
+    const example =
+        \\[package]
+        \\name=libffmpeg
+        \\version=5.1.2
+        \\
+        \\[dependency]
+        \\id=libz
+        \\url=url1
+        \\
+        \\[dependency]
+        \\id=libmp3lame
+        \\url=url2
+    ;
+    var ini: Ini = .{ .bytes = example };
+    var it = ini.iterateSection("\n[dependency]\n");
+    const section1 = it.next() orelse return error.TestFailed;
+    try testing.expectEqualStrings("id=libz\nurl=url1\n", section1);
+    const section2 = it.next() orelse return error.TestFailed;
+    try testing.expectEqualStrings("id=libmp3lame\nurl=url2", section2);
+    try testing.expect(it.next() == null);
+}