diff --git a/build.zig b/build.zig index 8b4efcc..294472e 100644 --- a/build.zig +++ b/build.zig @@ -199,8 +199,8 @@ pub fn build(b: *std.Build) !void { // Copy data files to install directory const install_data = b.addInstallDirectory(.{ .source_dir = upstream.path("data"), - .install_dir = .bin, - .install_subdir = "data", + .install_dir = .{ .custom = "share" }, + .install_subdir = "link", }); install_data.step.dependOn(&download_link_step.step); diff --git a/src/main.zig b/src/main.zig index 4973cbf..efc9547 100644 --- a/src/main.zig +++ b/src/main.zig @@ -84,49 +84,68 @@ fn sendWemoCommand(allocator: std.mem.Allocator, device_entry: std.hash_map.Stri } fn loadDeviceConfig(allocator: std.mem.Allocator, bin_dir: []const u8) !std.StringHashMap([]const u8) { + // Try current directory first + if (loadConfigFromPath(allocator, "controlData.json")) |config| { + return config; + } else |_| {} + + // Try controlData.json in bin directory + const json_path = try std.fs.path.join(allocator, &[_][]const u8{ bin_dir, "controlData.json" }); + defer allocator.free(json_path); + if (loadConfigFromPath(allocator, json_path)) |config| { + return config; + } else |_| {} + + // Try ../share/pos relative to bin directory + const share_path = try std.fs.path.join(allocator, &[_][]const u8{ bin_dir, "../share/pos/controlData.json" }); + defer allocator.free(share_path); + if (loadConfigFromPath(allocator, share_path)) |config| { + return config; + } else |_| {} + + return loadDevicesFromTxt(allocator, bin_dir); +} + +fn loadConfigFromPath(allocator: std.mem.Allocator, path: []const u8) !std.StringHashMap([]const u8) { var devices = std.StringHashMap([]const u8).init(allocator); + const file = if (std.fs.path.isAbsolute(path)) + std.fs.openFileAbsolute(path, .{}) catch return error.FileNotFound + else + std.fs.cwd().openFile(path, .{}) catch return error.FileNotFound; + defer file.close(); + + const content = try file.readToEndAlloc(allocator, 1024 * 1024); + defer allocator.free(content); + var stderr_writer = std.fs.File.stderr().writer(&.{}); const stderr = &stderr_writer.interface; - // Try controlData.json first - const json_path = try std.fs.path.join(allocator, &[_][]const u8{ bin_dir, "controlData.json" }); - defer allocator.free(json_path); + const parsed = std.json.parseFromSlice(std.json.Value, allocator, content, .{}) catch |err| { + try stderr.print( + "Failed to parse controlData.json: {}. Ignoring controlData.json, looking for devices.txt", + .{err}, + ); + return error.ParseError; + }; + defer parsed.deinit(); - if (std.fs.openFileAbsolute(json_path, .{})) |file| { - defer file.close(); + const root = parsed.value.object; + const device_array = root.get("devices").?.array; - const content = try file.readToEndAlloc(allocator, 1024 * 1024); - defer allocator.free(content); + for (device_array.items) |device| { + const device_obj = device.object; + const name = device_obj.get("name").?.string; + const url = device_obj.get("url").?.string; - const parsed = std.json.parseFromSlice(std.json.Value, allocator, content, .{}) catch |err| { - try stderr.print( - "Failed to parse controlData.json: {}. Ignoring controlData.json, looking for devices.txt", - .{err}, - ); - return loadDevicesFromTxt(allocator, bin_dir); - }; - defer parsed.deinit(); - - const root = parsed.value.object; - const device_array = root.get("devices").?.array; - - for (device_array.items) |device| { - const device_obj = device.object; - const name = device_obj.get("name").?.string; - const url = device_obj.get("url").?.string; - - if (name.len > 0) { - const name_copy = try allocator.alloc(u8, name.len); - _ = std.ascii.lowerString(name_copy, name); - try devices.put(name_copy, try allocator.dupe(u8, url)); - std.log.debug("Loaded device: '{s}' -> {s}", .{ name, url }); - } + if (name.len > 0) { + const name_copy = try allocator.alloc(u8, name.len); + _ = std.ascii.lowerString(name_copy, name); + try devices.put(name_copy, try allocator.dupe(u8, url)); + std.log.debug("Loaded device: '{s}' -> {s}", .{ name, url }); } - - return devices; - } else |_| { - return loadDevicesFromTxt(allocator, bin_dir); } + + return devices; } fn loadDevicesFromTxt(allocator: std.mem.Allocator, bin_dir: []const u8) !std.StringHashMap([]const u8) { diff --git a/src/root.zig b/src/root.zig index d9fa6f0..79ca8ae 100644 --- a/src/root.zig +++ b/src/root.zig @@ -291,10 +291,10 @@ pub const Parser = struct { pub fn init(allocator: std.mem.Allocator) !Parser { const dict = c.dictionary_create( - @ptrCast(@constCast("data/4.0.dict")), - @ptrCast(@constCast("data/4.0.knowledge")), - @ptrCast(@constCast("data/4.0.constituent-knowledge")), - @ptrCast(@constCast("data/4.0.affix")), + @ptrCast(@constCast("../share/link/4.0.dict")), + @ptrCast(@constCast("../share/link/4.0.knowledge")), + @ptrCast(@constCast("../share/link/4.0.constituent-knowledge")), + @ptrCast(@constCast("../share/link/4.0.affix")), ); if (dict == null) return error.DictionaryCreationFailed; @@ -319,13 +319,13 @@ pub const Parser = struct { } pub fn initWithDataDir(allocator: std.mem.Allocator, data_dir: []const u8) !Parser { - const dict_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "data/4.0.dict" }); + const dict_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "../share/link/4.0.dict" }); defer allocator.free(dict_path); - const knowledge_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "data/4.0.knowledge" }); + const knowledge_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "../share/link/4.0.knowledge" }); defer allocator.free(knowledge_path); - const constituent_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "data/4.0.constituent-knowledge" }); + const constituent_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "../share/link/4.0.constituent-knowledge" }); defer allocator.free(constituent_path); - const affix_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "data/4.0.affix" }); + const affix_path = try std.fs.path.join(allocator, &[_][]const u8{ data_dir, "../share/link/4.0.affix" }); defer allocator.free(affix_path); const dict_cstr = try allocator.dupeZ(u8, dict_path);