Skip to content

Commit 10cfba6

Browse files
authored
Merge pull request #18 from AshAmetrine/zig-0.16.0
Update to Zig 0.16.0
2 parents 918f16d + a1dc910 commit 10cfba6

9 files changed

Lines changed: 119 additions & 103 deletions

File tree

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ jobs:
1010
- uses: actions/checkout@v3
1111
- uses: mlugg/setup-zig@v2
1212
with:
13-
version: 0.15.0
13+
version: 0.16.0
1414
- run: zig build test

README.md

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,19 @@ This is a very simple ini-parser library that provides:
1212
### Zig
1313

1414
```zig
15-
pub fn main() !void {
16-
const file = try std.fs.cwd().openFile("example.ini", .{});
17-
defer file.close();
18-
19-
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
20-
defer if (gpa.deinit() != .ok) @panic("memory leaked");
15+
pub fn main(init: std.process.Init) !void {
16+
const io = init.io;
17+
const file = try std.Io.Dir.cwd().openFile(io, "example.ini", .{});
18+
defer file.close(io);
2119
2220
var read_buffer: [1024]u8 = undefined;
23-
var file_reader = file.reader(&read_buffer);
24-
var parser = ini.parse(gpa.allocator(), &file_reader.interface, ";#");
21+
var file_reader = file.reader(io, &read_buffer);
22+
var parser = ini.parse(init.gpa, &file_reader.interface, ";#");
2523
defer parser.deinit();
2624
2725
var write_buffer: [1024]u8 = undefined;
28-
var file_writer = std.fs.File.stdout().writer(&write_buffer);
29-
var writer = &file_writer.interface;
26+
var file_writer = std.Io.File.stdout().writer(io, &write_buffer);
27+
const writer = &file_writer.interface;
3028
defer writer.flush() catch @panic("Could not flush to stdout");
3129
3230
while (try parser.next()) |record| {
@@ -36,8 +34,7 @@ pub fn main() !void {
3634
.enumeration => |value| try writer.print("{s}\n", .{value}),
3735
}
3836
}
39-
}
40-
```
37+
}```
4138
4239
### C
4340

build.zig

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,29 @@ pub fn build(b: *std.Build) void {
1010
.target = target,
1111
});
1212

13+
const ini_c_header = b.addTranslateC(.{
14+
.root_source_file = b.path("src/ini.h"),
15+
.target = target,
16+
.optimize = optimize,
17+
});
18+
1319
const lib = b.addLibrary(.{
1420
.name = "ini",
1521
.root_module = b.createModule(.{
1622
.root_source_file = b.path("src/lib.zig"),
1723
.target = target,
1824
.optimize = optimize,
25+
.link_libc = true,
26+
.imports = &.{
27+
.{
28+
.name = "c",
29+
.module = ini_c_header.createModule(),
30+
},
31+
},
1932
}),
2033
});
2134
lib.bundle_compiler_rt = true;
22-
lib.addIncludePath(b.path("src"));
23-
lib.linkLibC();
35+
lib.root_module.addIncludePath(b.path("src"));
2436
lib.installHeader(b.path("src/ini.h"), "ini.h");
2537
b.installArtifact(lib);
2638

@@ -30,19 +42,19 @@ pub fn build(b: *std.Build) void {
3042
.root_module = b.createModule(.{
3143
.optimize = optimize,
3244
.target = target,
45+
.link_libc = true,
3346
}),
3447
});
35-
example_c.addCSourceFile(.{
48+
example_c.root_module.addCSourceFile(.{
3649
.file = b.path("example/example.c"),
3750
.flags = &.{
3851
"-Wall",
3952
"-Wextra",
4053
"-pedantic",
4154
},
4255
});
43-
example_c.addIncludePath(b.path("src"));
44-
example_c.linkLibrary(lib);
45-
example_c.linkLibC();
56+
example_c.root_module.addIncludePath(b.path("src"));
57+
example_c.root_module.linkLibrary(lib);
4658
example_step.dependOn(&b.addInstallArtifact(example_c, .{}).step);
4759

4860
const example_zig = b.addExecutable(.{
@@ -51,9 +63,11 @@ pub fn build(b: *std.Build) void {
5163
.root_source_file = b.path("example/example.zig"),
5264
.optimize = optimize,
5365
.target = target,
66+
.imports = &.{
67+
.{ .name = "ini", .module = b.modules.get("ini").? },
68+
},
5469
}),
5570
});
56-
example_zig.root_module.addImport("ini", b.modules.get("ini").?);
5771
example_step.dependOn(&b.addInstallArtifact(example_zig, .{}).step);
5872

5973
const test_step = b.step("test", "Run library tests");
@@ -71,10 +85,16 @@ pub fn build(b: *std.Build) void {
7185
.root_source_file = b.path("src/lib-test.zig"),
7286
.optimize = optimize,
7387
.target = target,
88+
.link_libc = true,
89+
.imports = &.{
90+
.{
91+
.name = "c",
92+
.module = ini_c_header.createModule(),
93+
},
94+
},
7495
}),
7596
});
76-
binding_tests.addIncludePath(b.path("src"));
77-
binding_tests.linkLibrary(lib);
78-
binding_tests.linkLibC();
97+
binding_tests.root_module.addIncludePath(b.path("src"));
98+
binding_tests.root_module.linkLibrary(lib);
7999
test_step.dependOn(&b.addRunArtifact(binding_tests).step);
80100
}

build.zig.zon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
.name = .ini,
33
.fingerprint = 0x7757b668623d2460,
44
.version = "0.1.0",
5-
.minimum_zig_version = "0.15.0",
5+
.minimum_zig_version = "0.16.0",
66
.paths = .{
77
"LICENCE",
88
"README.md",

example/example.zig

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
const std = @import("std");
22
const ini = @import("ini");
33

4-
pub fn main() !void {
5-
const file = try std.fs.cwd().openFile("example.ini", .{});
6-
defer file.close();
7-
8-
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
9-
defer if (gpa.deinit() != .ok) @panic("memory leaked");
4+
pub fn main(init: std.process.Init) !void {
5+
const io = init.io;
6+
const file = try std.Io.Dir.cwd().openFile(io, "example.ini", .{});
7+
defer file.close(io);
108

119
var read_buffer: [1024]u8 = undefined;
12-
var file_reader = file.reader(&read_buffer);
13-
var parser = ini.parse(gpa.allocator(), &file_reader.interface, ";#");
10+
var file_reader = file.reader(io, &read_buffer);
11+
var parser = ini.parse(init.gpa, &file_reader.interface, ";#");
1412
defer parser.deinit();
1513

1614
var write_buffer: [1024]u8 = undefined;
17-
var file_writer = std.fs.File.stdout().writer(&write_buffer);
18-
var writer = &file_writer.interface;
15+
var file_writer = std.Io.File.stdout().writer(io, &write_buffer);
16+
const writer = &file_writer.interface;
1917
defer writer.flush() catch @panic("Could not flush to stdout");
2018

2119
while (try parser.next()) |record| {

src/ini.zig

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,39 +37,37 @@ fn insertNulTerminator(slice: []const u8) [:0]const u8 {
3737
pub const Parser = struct {
3838
const Self = @This();
3939

40-
allocator: std.mem.Allocator,
41-
line_buffer: std.array_list.Managed(u8),
42-
reader: *std.io.Reader,
40+
line_writer: std.Io.Writer.Allocating,
41+
reader: *std.Io.Reader,
4342
comment_characters: []const u8,
4443

4544
pub fn deinit(self: *Self) void {
46-
self.line_buffer.deinit();
45+
self.line_writer.deinit();
4746
self.* = undefined;
4847
}
4948

5049
pub fn next(self: *Self) !?Record {
51-
var write_buffer: [1024]u8 = undefined;
52-
var old_writer_adapter = self.line_buffer.writer().adaptToNewApi(&write_buffer);
53-
var writer = &old_writer_adapter.new_interface;
54-
self.line_buffer.clearRetainingCapacity();
50+
self.line_writer.clearRetainingCapacity();
5551
while (true) {
56-
_ = try self.reader.streamDelimiterLimit(writer, '\n', .limited(4096));
57-
try writer.flush();
52+
_ = try self.reader.streamDelimiterLimit(&self.line_writer.writer, '\n', .limited(4096));
53+
54+
var line: []const u8 = self.line_writer.written();
55+
5856
const discarded = self.reader.discard(.limited(1)) catch |e| blk: {
5957
switch (e) {
6058
error.EndOfStream => {
61-
if (self.line_buffer.items.len == 0)
59+
if (line.len == 0)
6260
return null;
6361
break :blk 0;
6462
},
6563
else => return e,
6664
}
6765
};
68-
if (self.line_buffer.items.len == 0 and discarded == 0)
66+
if (line.len == 0 and discarded == 0)
6967
return null;
70-
try self.line_buffer.append(0); // append guaranteed space for sentinel
68+
try self.line_writer.writer.writeByte(0); // append guaranteed space for sentinel
69+
line = self.line_writer.written();
7170

72-
var line: []const u8 = self.line_buffer.items;
7371
var last_index: usize = 0;
7472

7573
// handle comments and escaping
@@ -81,8 +79,9 @@ pub const Parser = struct {
8179
const previous_char = line[previous_index];
8280

8381
if (previous_char == '\\') {
84-
_ = self.line_buffer.orderedRemove(previous_index);
85-
line = self.line_buffer.items;
82+
var buf = self.line_writer.written();
83+
@memmove(buf[previous_index .. buf.len - 1], buf[index..buf.len]);
84+
self.line_writer.shrinkRetainingCapacity(buf.len - 1);
8685

8786
last_index = index + 1;
8887
continue;
@@ -98,7 +97,7 @@ pub const Parser = struct {
9897
}
9998

10099
if (line.len == 0) {
101-
self.line_buffer.clearRetainingCapacity();
100+
self.line_writer.clearRetainingCapacity();
102101
continue;
103102
}
104103

@@ -122,10 +121,9 @@ pub const Parser = struct {
122121
};
123122

124123
/// Returns a new parser that can read the ini structure
125-
pub fn parse(allocator: std.mem.Allocator, reader: *std.io.Reader, comment_characters: []const u8) Parser {
124+
pub fn parse(allocator: std.mem.Allocator, reader: *std.Io.Reader, comment_characters: []const u8) Parser {
126125
return Parser{
127-
.allocator = allocator,
128-
.line_buffer = std.array_list.Managed(u8).init(allocator),
126+
.line_writer = std.Io.Writer.Allocating.init(allocator),
129127
.reader = reader,
130128
.comment_characters = comment_characters,
131129
};

src/lib-test.zig

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
const std = @import("std");
2-
3-
const c = @cImport({
4-
@cInclude("ini.h");
5-
});
2+
const c = @import("c");
63

74
test "parser create/destroy" {
85
var buffer: c.ini_Parser = undefined;

src/lib.zig

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
const std = @import("std");
22
const ini = @import("ini.zig");
3-
4-
const c = @cImport({
5-
@cInclude("ini.h");
6-
});
3+
const c = @import("c");
74

85
const Record = extern struct {
96
type: Type,
@@ -29,12 +26,12 @@ const Record = extern struct {
2926
};
3027

3128
const BufferParser = struct {
32-
stream: std.io.Reader,
29+
stream: std.Io.Reader,
3330
parser: ini.Parser,
3431
};
3532

3633
const FileParser = struct {
37-
old_reader_adapter: CReader.Adapter,
34+
reader: CReader,
3835
parser: ini.Parser,
3936
};
4037

@@ -70,7 +67,7 @@ comptime {
7067
export fn ini_create_buffer(parser: *IniParser, data: [*]const u8, data_length: usize, comment_characters: [*]const u8, comment_characters_length: usize) void {
7168
parser.* = IniParser{
7269
.buffer = .{
73-
.stream = std.io.Reader.fixed(data[0..data_length]),
70+
.stream = std.Io.Reader.fixed(data[0..data_length]),
7471
.parser = undefined,
7572
},
7673
};
@@ -81,12 +78,12 @@ export fn ini_create_buffer(parser: *IniParser, data: [*]const u8, data_length:
8178
export fn ini_create_file(parser: *IniParser, read_buffer: [*]u8, read_buffer_length: usize, file: *std.c.FILE, comment_characters: [*]const u8, comment_characters_length: usize) void {
8279
parser.* = IniParser{
8380
.file = .{
84-
.old_reader_adapter = cReader(file).adaptToNewApi(read_buffer[0..read_buffer_length]),
81+
.reader = CReader.init(file, read_buffer[0..read_buffer_length]),
8582
.parser = undefined,
8683
},
8784
};
8885

89-
parser.file.parser = ini.parse(std.heap.c_allocator, &parser.file.old_reader_adapter.new_interface, comment_characters[0..comment_characters_length]);
86+
parser.file.parser = ini.parse(std.heap.c_allocator, &parser.file.reader.interface, comment_characters[0..comment_characters_length]);
9087
}
9188

9289
export fn ini_destroy(parser: *IniParser) void {
@@ -97,7 +94,7 @@ export fn ini_destroy(parser: *IniParser) void {
9794
parser.* = undefined;
9895
}
9996

100-
const ParseError = error{ OutOfMemory, StreamTooLong } || std.io.Reader.Error || std.io.Writer.Error;
97+
const ParseError = error{ OutOfMemory, StreamTooLong } || std.Io.Reader.Error || std.Io.Writer.Error;
10198

10299
fn mapError(err: ParseError) IniError {
103100
return switch (err) {
@@ -141,28 +138,37 @@ export fn ini_next(parser: *IniParser, record: *Record) IniError {
141138
return .success;
142139
}
143140

144-
const CReader = std.Io.GenericReader(*std.c.FILE, std.fs.File.ReadError, cReaderRead);
141+
extern "c" fn feof(stream: *std.c.FILE) c_int;
145142

146-
fn cReader(c_file: *std.c.FILE) CReader {
147-
return .{ .context = c_file };
148-
}
143+
const CReader = struct {
144+
file: *std.c.FILE,
145+
interface: std.Io.Reader,
149146

150-
fn cReaderRead(c_file: *std.c.FILE, bytes: []u8) std.fs.File.ReadError!usize {
151-
const amt_read = std.c.fread(bytes.ptr, 1, bytes.len, c_file);
152-
if (amt_read >= 0) return amt_read;
153-
switch (@as(std.os.E, @enumFromInt(std.c._errno().*))) {
154-
.SUCCESS => unreachable,
155-
.INVAL => unreachable,
156-
.FAULT => unreachable,
157-
.AGAIN => unreachable, // this is a blocking API
158-
.BADF => unreachable, // always a race condition
159-
.DESTADDRREQ => unreachable, // connect was never called
160-
.DQUOT => return error.DiskQuota,
161-
.FBIG => return error.FileTooBig,
162-
.IO => return error.InputOutput,
163-
.NOSPC => return error.NoSpaceLeft,
164-
.PERM => return error.AccessDenied,
165-
.PIPE => return error.BrokenPipe,
166-
else => |err| return std.os.unexpectedErrno(err),
147+
fn init(file: *std.c.FILE, buffer: []u8) CReader {
148+
return .{
149+
.file = file,
150+
.interface = .{
151+
.vtable = &.{ .stream = stream },
152+
.buffer = buffer,
153+
.seek = 0,
154+
.end = 0,
155+
},
156+
};
167157
}
168-
}
158+
159+
fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
160+
const creader: *CReader = @alignCast(@fieldParentPtr("interface", r));
161+
162+
if (limit == .nothing) return 0;
163+
const dest = limit.slice(try w.writableSliceGreedy(1));
164+
165+
const n = std.c.fread(dest.ptr, 1, dest.len, creader.file);
166+
if (n > 0) {
167+
w.advance(n);
168+
return n;
169+
}
170+
171+
if (feof(creader.file) != 0) return error.EndOfStream;
172+
return error.ReadFailed;
173+
}
174+
};

0 commit comments

Comments
 (0)