This commit is contained in:
commit
22eb995d38
3 changed files with 223 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
zig-cache
|
||||
src/zig-cache
|
17
build.zig
Normal file
17
build.zig
Normal 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
204
src/main.zig
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue