Last active
October 21, 2023 02:03
-
-
Save Tetralux/c0e2439d560441f313b5cd314987bcae to your computer and use it in GitHub Desktop.
Rudimentary INI parser in Zig
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const string = []const u8; | |
const Allocator = std.mem.Allocator; | |
/// Given an entire INI string, parses it into a map of key-value pairs. | |
/// The pairs are all freed by a call to `Parser.deinit`, and retrieved via `Parser.get`. | |
/// If you need them to live beyond that, use `some_other_allocator.dupe(u8, value)`. | |
pub const Parser = struct { | |
data: std.StringArrayHashMap(string), | |
arena: std.heap.ArenaAllocator, | |
/// Parses an entire INI string into a map of key-value pairs. | |
/// See `Parser.get` and `Parser.deinit`. | |
pub fn parse(input: string, ally: Allocator) !Parser { | |
var p = Parser { | |
.data = undefined, | |
.arena = std.heap.ArenaAllocator.init(ally), | |
}; | |
p.data = std.StringArrayHashMap(string).init(p.arena.allocator()); | |
try p.data.ensureTotalCapacity(32); | |
errdefer p.deinit(); | |
var stream = std.io.fixedBufferStream(input); | |
const r = stream.reader(); | |
while (try r.readUntilDelimiterOrEofAlloc(p.arena.allocator(), '\n', std.math.maxInt(u32))) |line| { | |
const trimmed_line = std.mem.trim(u8, line, "\r\n\t"); | |
if (trimmed_line.len == 0) continue; | |
if (trimmed_line[0] == '#') continue; | |
if (std.mem.indexOfScalar(u8, trimmed_line, '=')) |i| { | |
const key = std.mem.trim(u8, trimmed_line[0..i-1], "\r\t "); | |
const value = std.mem.trim(u8, trimmed_line[i+1..], "\r\t "); | |
try p.data.put(key, value); | |
} | |
} | |
return p; | |
} | |
/// Frees all key-value pairs that were allocated by `Parser.parse`. | |
pub fn deinit(p: *Parser) void { | |
p.arena.deinit(); | |
p.* = undefined; | |
} | |
/// Lookup a key. | |
/// | |
/// The string returned by this function is freed by `Parser.deinit`. | |
/// If you need it to live beyond that, use `some_other_allocator.dupe(u8, value)`. | |
pub fn get(p: *Parser, key: string) ?string { | |
return p.data.get(key); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment