1
0
Fork 0
This commit is contained in:
Cat /dev/Nulo 2022-02-01 21:17:33 -03:00
commit 22eb995d38
3 changed files with 223 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
zig-cache
src/zig-cache

17
build.zig Normal file
View file

@ -0,0 +1,17 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const lib = b.addStaticLibrary("ini-parser", "src/main.zig");
lib.setBuildMode(mode);
lib.install();
var main_tests = b.addTest("src/main.zig");
main_tests.setBuildMode(mode);
const test_step = b.step("test", "Run library tests");
test_step.dependOn(&main_tests.step);
}

204
src/main.zig Normal file
View file

@ -0,0 +1,204 @@
const std = @import("std");
const testing = std.testing;
const Self = @This();
pub const KeyValue = struct {
key: []const u8,
value: []const u8,
};
pub const Section = struct {
pub const KeyValues = std.ArrayList(KeyValue);
name: []const u8,
key_values: KeyValues,
pub fn init(allocator: std.mem.Allocator, name: []const u8) Section {
return Section{
.name = name,
.key_values = KeyValues.init(allocator),
};
}
pub fn deinit(self: Section) void {
self.key_values.deinit();
}
};
fn scrapComments(str: []const u8) []const u8 {
if (std.mem.indexOf(u8, str, ";")) |index| {
return std.mem.trim(u8, str[0..index], &std.ascii.spaces);
} else {
return std.mem.trim(u8, str, &std.ascii.spaces);
}
}
pub const Sections = std.ArrayList(Section);
allocator: std.mem.Allocator,
sections: Sections,
pub fn parse(allocator: std.mem.Allocator, str: []const u8) !Self {
var self = Self{
.allocator = allocator,
.sections = Sections.init(allocator),
};
errdefer self.sections.deinit();
errdefer for (self.sections.items) |section|
section.deinit();
var iter = std.mem.tokenize(u8, str, "\n");
var line_num: usize = 1;
while (iter.next()) |line| {
defer line_num += 1;
const actual_line = scrapComments(line);
if (actual_line.len == 0) {
continue;
} else if (actual_line[0] == '[') {
var section_name = actual_line[1..];
if (actual_line[actual_line.len - 1] != ']') {
std.log.warn("Invalid section name at line {}", .{line_num});
} else {
section_name = section_name[0 .. section_name.len - 1];
}
try self.sections.append(Section.init(allocator, section_name));
} else {
if (std.mem.indexOf(u8, actual_line, "=")) |index| {
const key = actual_line[0..index];
const value = actual_line[index + 1 ..];
if (self.sections.items.len > 0) {
try self.sections.items[self.sections.items.len - 1]
.key_values.append(.{ .key = key, .value = value });
} else {
std.log.warn("Ignored key-value without section at line {}", .{line_num});
}
} else {
std.log.warn("Ignored invalid key-value at line {}", .{line_num});
}
}
}
return self;
}
pub fn deinit(self: Self) void {
for (self.sections.items) |section| {
section.deinit();
}
self.sections.deinit();
}
test "try parsing" {
const ini_str =
\\; Device level parameters
\\; UseTheseDomainSizes - When enabled (=1), use the sizes defined in the INI
\\; to defined the memory sizes for each domain
\\; When disabled (=0), for STAT_PLC, use the following
\\; defaults:
\\; Max Coils : 32768 elements
\\; Max Input Status: 32768 elements
\\; Max Input Regs: 16384 elements
\\; Max Holding Regs: 16384 elements
\\; All other memory types are 0 elements
\\;; For all other device models, the device communication
\\; interface will attempt to size the memory
\\;
\\; The default value is 0
\\;
\\; UseCounts - When enabled (=1), indicates sizes are in elements
\\; When disabled (=0) indicates sizes are in bytes
\\;
\\; Default value is 0
\\;
\\; ConservesConn - When enabled (=1), indicates that it is normal for the device
\\; to close the connection (typically based on inactivity). The
\\; device communication interface will not assume that the
\\; device is down unless it is unable to create a connection and
\\; get a response when it attempts the current scheduled
\\; operation to retrieve data from the device or modify data.
\\;
\\; When disabled (=0), indicates that a termination of the
\\; connection between the device communication interface and
\\; the device will cause the device communication interface to
\\; assume that the connection is down and terminate the
\\; connection
\\;
\\; Default value is 0.
\\;
\\; ConnSecondary - When Enabled (=1), in a Host Redundant environment,
\\; the device communciation interface will attempt to
\\; maintain a connection with the device on the acting
\\; secondary.
\\;
\\; When Disabled(=0), in a Host Redundant environment,
\\; the device communication interface will terminate its
\\; connection to the device when transitioning to the
\\; secondary.
\\;
\\; Default value is 1.
\\;
\\; OneCoilWrite - When enabled (=1) use Function 5 to write single coils
\\; When disabled (=0) use Function 15 to write single coils
\\;
\\; VersaMax ENIU, VersaPoint ENIU and Modicon 484's ignore this
\\; parameter.
\\;
\\;OneRegiserWrite - When enabled (=1) use Function 6 to write single holding registers
\\; When disabled (=0) use Function 16 to write single holding registers
\\;
\\; VersaMax ENIU, VersaPoint ENIU and Modicon 484's ignore this
\\; parameter.
\\;
\\[DEVICE1]
\\UseTheseDomainSizes=1
\\UseCounts=0
\\OneCoilWrite=0
\\OneRegWrite=0
\\ConservesConn=1
\\ConnSecondary=0
\\COILS=65535
\\DISC INPUTS=65535
\\INPUT REG.=65535
\\HOLDING REG.=65535
\\GEN REF FILE1=0
\\GEN REF FILE2=0
\\GEN REF FILE3=0
\\GEN REF FILE4=0
\\GEN REF FILE5=0
\\GEN REF FILE6=0
\\GEN REF FILE7=0
\\GEN REF FILE8=0
\\GEN REF FILE9=0
\\GEN REF FILE10=0
\\DP_INPUT REG.=0
\\DP_HOLDING REG.=0
\\
\\[DEVICE2]
\\UseTheseDomainSizes=1
\\UseCounts=0
\\OneCoilWrite=0
\\OneRegWrite=0
\\ConservesConn=1
\\ConnSecondary=0
\\COILS=65535
\\DISC INPUTS=65535
\\INPUT REG.=65535
\\HOLDING REG.=65535
\\GEN REF FILE1=0
\\GEN REF FILE2=0
\\GEN REF FILE3=0
\\GEN REF FILE4=0
\\GEN REF FILE5=0
\\GEN REF FILE6=0
\\GEN REF FILE7=0
\\GEN REF FILE8=0
\\GEN REF FILE9=0
\\GEN REF FILE10=0
\\DP_INPUT REG.=0
\\DP_HOLDING REG.=0
;
const ini = try parse(testing.allocator, ini_str);
defer ini.deinit();
try testing.expectEqual(@as(usize, 2), ini.sections.items.len);
try testing.expectEqualStrings("DEVICE1", ini.sections.items[0].name);
try testing.expectEqualStrings("DEVICE2", ini.sections.items[1].name);
try testing.expectEqual(@as(usize, 22), ini.sections.items[0].key_values.items.len);
try testing.expectEqualStrings("OneCoilWrite", ini.sections.items[0].key_values.items[2].key);
try testing.expectEqualStrings("0", ini.sections.items[0].key_values.items[2].value);
}