wyag

Write yourself a git
Log | Files | Refs | README

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 }