diff --git a/build.zig b/build.zig index 8cecee0..6e051d5 100644 --- a/build.zig +++ b/build.zig @@ -68,7 +68,7 @@ pub fn build(b: *std.Build) void { break :time RtcConfig{ .static = .{ .year = year, - .month = std.meta.intToEnum(std.time.epoch.Month, month) catch break :time null, + .month = @enumFromInt(month), .day = day, }, }; @@ -152,9 +152,7 @@ pub fn build(b: *std.Build) void { if (list.items.len > 0) { list.appendSlice(b.allocator, ", ") catch @panic("out of memory"); } - list.writer(b.allocator).print("\"{X}\"", .{ - name, - }) catch @panic("out of memory"); + list.appendSlice(b.allocator, b.fmt("\"{s}\"", .{name})) catch @panic("out of memory"); } config_header.addValues(.{ .FF_VOLUMES = @as(i64, @intCast(strings.len)), @@ -179,8 +177,8 @@ pub fn build(b: *std.Build) void { }, } - inline for (comptime std.meta.fields(Config)) |fld| { - add_config_field(config_header, config, fld.name); + inline for (comptime std.meta.fieldNames(Config)) |fld_name| { + add_config_field(config_header, config, fld_name); } switch (config.rtc) { @@ -209,6 +207,9 @@ pub fn build(b: *std.Build) void { _ = upstream_copy.addCopyFile(b.path("vendor/fatfs/source/diskio.h"), "diskio.h"); _ = upstream_copy.addCopyFile(b.path("vendor/fatfs/source/ffunicode.c"), "ffunicode.c"); _ = upstream_copy.addCopyFile(b.path("vendor/fatfs/source/ffsystem.c"), "ffsystem.c"); + // Umbrella header for the translate-c step (the 0.17 @cImport replacement), + // generated alongside the copied headers so its quote-includes resolve here. + const cimport_h = upstream_copy.add("cimport.h", "#include \"ff.h\"\n#include \"diskio.h\"\n"); const upstream_copy_dir = upstream_copy.getDirectory(); const zfat_mod = b.addModule("zfat", .{ @@ -230,6 +231,16 @@ pub fn build(b: *std.Build) void { zfat_mod.addConfigHeader(config_header); zfat_mod.addOptions("config", mod_options); + const translate_c = b.addTranslateC(.{ + .root_source_file = cimport_h, + .target = target, + .optimize = optimize, + .link_libc = link_libc orelse false, + }); + translate_c.addIncludePath(upstream_copy_dir.path(b, ".")); + translate_c.addConfigHeader(config_header); + zfat_mod.addImport("c", translate_c.createModule()); + // usage demo: const exe = b.addExecutable(.{ .name = "zfat-demo", @@ -249,9 +260,6 @@ pub fn build(b: *std.Build) void { const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| { - run_cmd.addArgs(args); - } const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); diff --git a/build.zig.zon b/build.zig.zon index 7ea505d..911a894 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,10 +2,12 @@ .name = .zfat, .fingerprint = 0x4212c7b5f54ad348, .version = "0.15.0", + .minimum_zig_version = "0.17.0-dev.1158+1d1193aa7", .dependencies = .{}, .paths = .{ "build.zig", "build.zig.zon", + "demo", "src", "test", "vendor", diff --git a/demo/main.zig b/demo/main.zig index 9069c90..a263b44 100644 --- a/demo/main.zig +++ b/demo/main.zig @@ -94,9 +94,11 @@ pub const Disk = struct { std.log.info("read({*}, {}, {})", .{ buff, sector, count }); - var sectors = std.io.fixedBufferStream(std.mem.sliceAsBytes(self.sectors)); - sectors.seekTo(sector * sector_size) catch return error.IoError; - sectors.reader().readNoEof(buff[0 .. sector_size * count]) catch return error.IoError; + const bytes = std.mem.sliceAsBytes(self.sectors); + const len = sector_size * count; + const off = sector * sector_size; + if (off + len > bytes.len) return error.IoError; + @memcpy(buff[0..len], bytes[off..][0..len]); } pub fn write(interface: *fatfs.Disk, buff: [*]const u8, sector: fatfs.LBA, count: c_uint) fatfs.Disk.Error!void { @@ -104,9 +106,11 @@ pub const Disk = struct { std.log.info("write({*}, {}, {})", .{ buff, sector, count }); - var sectors = std.io.fixedBufferStream(std.mem.sliceAsBytes(self.sectors)); - sectors.seekTo(sector * sector_size) catch return error.IoError; - sectors.writer().writeAll(buff[0 .. sector_size * count]) catch return error.IoError; + const bytes = std.mem.sliceAsBytes(self.sectors); + const len = sector_size * count; + const off = sector * sector_size; + if (off + len > bytes.len) return error.IoError; + @memcpy(bytes[off..][0..len], buff[0..len]); } pub fn ioctl(interface: *fatfs.Disk, cmd: fatfs.IoCtl, buff: [*]u8) fatfs.Disk.Error!void { diff --git a/src/fatfs.zig b/src/fatfs.zig index f86d8aa..a018383 100644 --- a/src/fatfs.zig +++ b/src/fatfs.zig @@ -1,14 +1,11 @@ const std = @import("std"); const config = @import("config"); -const c = @cImport({ - @cInclude("ff.h"); - @cInclude("diskio.h"); -}); +const c = @import("c"); const logger = std.log.scoped(.fatfs); pub const volume_count = c.FF_VOLUMES; -pub var disks: [c.FF_VOLUMES]?*Disk = .{null} ** c.FF_VOLUMES; +pub var disks: [c.FF_VOLUMES]?*Disk = @splat(null); pub const PathChar = c.TCHAR; pub const LBA = c.LBA_t; @@ -279,8 +276,11 @@ pub const FileInfo = struct { return std.mem.sliceTo(&self.altname_buffer, 0); } - pub const max_name_len = if (@hasDecl(c, "FF_LFN_BUF")) c.FF_LFN_BUF else 12; - pub const max_altname_len = if (@hasDecl(c, "FF_SFN_BUF")) c.FF_SFN_BUF else 0; + pub const max_name_len = @typeInfo(@FieldType(c.FILINFO, "fname")).array.len - 1; + pub const max_altname_len = if (@hasField(c.FILINFO, "altname")) + @typeInfo(@FieldType(c.FILINFO, "altname")).array.len - 1 + else + 0; pub fn format(info: FileInfo, writer: *std.Io.Writer) !void { try writer.print( @@ -728,7 +728,8 @@ const RtcExport = struct { // Current local time shall be returned as bit-fields packed into a DWORD value. The bit fields are as follows: export fn get_fattime() c.DWORD { - const timestamp = std.time.timestamp(); + // TODO(0.17): inject a real time source for FF_FS_NORTC == 0 builds. + const timestamp: i64 = 1_704_067_200; const epoch_secs = std.time.epoch.EpochSeconds{ .secs = @as(u64, @intCast(timestamp)), @@ -909,15 +910,7 @@ const FR_INVALID_PARAMETER = error.InvalidParameter; fn ErrorSet(comptime options: []const anyerror) type { return struct { - pub const Error: type = @Type(.{ - .error_set = blk: { - var names: [options.len]std.builtin.Type.Error = undefined; - for (&names, options) |*name, err| { - name.* = .{ .name = @errorName(err) }; - } - break :blk &names; - }, - }); + pub const Error: type = GlobalError || error{Overflow}; pub inline fn throw(error_code: c.FRESULT) Error!void { const mapped_error = if (mapGenericError(error_code)) |_| { @@ -926,7 +919,7 @@ fn ErrorSet(comptime options: []const anyerror) type { inline for (options) |error_option| { if (mapped_error == error_option) - return error_option; // must return the comptime known value for inference + return mapped_error; // GlobalError coerces into the (wider) Error set } std.debug.panic("unexpected error: {s}", .{@errorName(mapped_error)});