inifile.zig (2872B)
1 const std = @import("std"); 2 3 _aa: std.heap.ArenaAllocator, 4 _hmValues: std.StringArrayHashMapUnmanaged([]const u8), 5 6 const IniFile = @This(); 7 // TODO There are a lot more intriciacies of parsing ini files, including: 8 // - comments at the end of lines 9 // - quoted values 10 // - escaped special characters 11 // This implementation does not handle any of them. 12 pub fn parse(ca: std.mem.Allocator, content: []const u8) !IniFile { 13 var self: IniFile = .{ 14 ._aa = std.heap.ArenaAllocator.init(ca), 15 ._hmValues = .{}, 16 }; 17 errdefer self.deinit(); 18 const a = self._aa.allocator(); 19 var section: []const u8 = ""; // Sections are not nested, thankfully 20 var it = std.mem.splitScalar(u8, content, '\n'); 21 lp: while (it.next()) |nxtraw| { 22 const nxt = std.mem.trimLeft(u8, nxtraw, " "); 23 if (nxt.len == 0) continue :lp; 24 switch (nxt[0]) { 25 '#', ';' => continue :lp, 26 '[' => { 27 section = std.mem.trim(u8, nxt, " []"); 28 continue :lp; 29 }, 30 else => { 31 var it2 = std.mem.splitScalar(u8, nxt, '='); 32 const dot = if (section.len > 0) "." else ""; 33 const key = try std.fmt.allocPrint(a, "{s}{s}{s}", .{ section, dot, std.mem.trim(u8, it2.first(), " ") }); 34 const value = std.mem.trim(u8, it2.rest(), " "); 35 try self._hmValues.put(a, key, value); 36 }, 37 } 38 } 39 return self; 40 } 41 42 pub fn get(self: IniFile, key: []const u8) ?[]const u8 { 43 return self._hmValues.get(key); 44 } 45 46 pub fn deinit(self: *IniFile) void { 47 self._hmValues.deinit(self._aa.allocator()); 48 self._aa.deinit(); 49 } 50 51 test "basic ini file" { 52 const content = 53 \\# 54 \\# This is the config file, and 55 \\# a '#' or ';' character indicates 56 \\# a comment 57 \\# 58 \\ 59 \\ somesetting = somevalue 60 \\ 61 \\; core variables 62 \\[core] 63 \\ ; Don't trust file modes 64 \\ filemode = false 65 \\ 66 \\; Our diff algorithm 67 \\[diff] 68 \\ external = /usr/local/bin/diff-wrapper 69 \\ renames = true 70 \\ 71 \\; Proxy settings 72 \\[core] 73 \\ gitproxy=proxy-command for kernel.org 74 \\ gitproxy=default-proxy ; for all the rest 75 \\ 76 \\; HTTP 77 \\[http] 78 \\ sslVerify 79 \\[http "https://weak.example.com"] 80 \\ sslVerify = false 81 \\ cookieFile = /tmp/cookie.txt 82 ; 83 var ini = try IniFile.parse(std.testing.allocator, content); 84 defer ini.deinit(); 85 try std.testing.expectEqualStrings("somevalue", ini.get("somesetting").?); 86 try std.testing.expectEqualStrings("true", ini.get("diff.renames").?); 87 // try std.testing.expectEqualStrings("default-proxy", ini.get("core.gitproxy").?); // FIXME 88 }