diff --git a/src/common/util.zig b/src/common/util.zig index acaab31..51df927 100644 --- a/src/common/util.zig +++ b/src/common/util.zig @@ -130,36 +130,7 @@ pub fn TerminatedArray(comptime n: usize, comptime T: type, comptime sentinel: T }; } -pub fn StackArrayList(comptime size: usize, comptime T: type) type { - return struct { - items: [size]T = undefined, - len: usize = 0, - - pub fn fromSlice(items: []const T) !@This() { - if (size < items.len) - return error.SliceToBig; - - var res: @This() = undefined; - mem.copy(T, &res.items, items); - res.len = items.len; - return res; - } - - pub fn span(list: anytype) Span(@TypeOf(list)) { - return list.items[0..list.len]; - } - - fn Span(comptime List: type) type { - var info = @typeInfo(List); - info.Pointer.size = .Slice; - info.Pointer.child = T; - info.Pointer.alignment = @alignOf(T); - return @Type(info); - } - }; -} - -pub const Path = StackArrayList(fs.MAX_PATH_BYTES, u8); +pub const Path = std.BoundedArray(u8, fs.MAX_PATH_BYTES); pub const path = struct { pub fn join(paths: []const []const u8) Path { @@ -168,7 +139,7 @@ pub const path = struct { // FixedBufferAllocator + FailingAllocator are used here to ensure that a max // of MAX_PATH_BYTES is allocated, and that only one allocation occures. This // ensures that only a valid path has been allocated into res. - var fba = heap.FixedBufferAllocator.init(&res.items); + var fba = heap.FixedBufferAllocator.init(&res.buffer); var failing = std.testing.FailingAllocator.init(fba.allocator(), 1); const res_slice = fs.path.join(failing.allocator(), paths) catch unreachable; res.len = res_slice.len; @@ -182,7 +153,7 @@ pub const path = struct { // FixedBufferAllocator + FailingAllocator are used here to ensure that a max // of MAX_PATH_BYTES is allocated, and that only one allocation occures. This // ensures that only a valid path has been allocated into res. - var fba = heap.FixedBufferAllocator.init(&res.items); + var fba = heap.FixedBufferAllocator.init(&res.buffer); var failing = debug.FailingAllocator.init(&fba.allocator, 1); const res_slice = fs.path.resolve(&failing.allocator, paths) catch |err| switch (err) { error.OutOfMemory => unreachable, @@ -197,14 +168,14 @@ pub const path = struct { pub const dir = struct { pub fn selfExeDir() !Path { var res: Path = undefined; - const res_slice = try fs.selfExeDirPath(&res.items); + const res_slice = try fs.selfExeDirPath(&res.buffer); res.len = res_slice.len; return res; } pub fn cwd() !Path { var res: Path = undefined; - const res_slice = try os.getcwd(&res.items); + const res_slice = try os.getcwd(&res.buffer); res.len = res_slice.len; return res; } diff --git a/src/gui/Executables.zig b/src/gui/Executables.zig index 4404e4d..008b7f5 100644 --- a/src/gui/Executables.zig +++ b/src/gui/Executables.zig @@ -12,9 +12,9 @@ const process = std.process; const Executables = @This(); arena: heap.ArenaAllocator, -load: util.Path = util.Path{}, -apply: util.Path = util.Path{}, -identify: util.Path = util.Path{}, +load: util.Path = util.Path{ .buffer = undefined }, +apply: util.Path = util.Path{ .buffer = undefined }, +identify: util.Path = util.Path{ .buffer = undefined }, commands: []const Command = &[_]Command{}, const Command = struct { @@ -110,7 +110,7 @@ pub fn find(allocator: mem.Allocator) !Executables { } fn findCore(tool: []const u8) !util.Path { - const self_exe_dir = (try util.dir.selfExeDir()).span(); + const self_exe_dir = (try util.dir.selfExeDir()).slice(); return joinAccess(&[_][]const u8{ self_exe_dir, "core", tool }) catch joinAccess(&[_][]const u8{ self_exe_dir, tool }) catch @@ -142,7 +142,7 @@ fn findInPath(name: []const u8) !util.Path { fn joinAccess(paths: []const []const u8) !util.Path { const res = util.path.join(paths); - try fs.cwd().access(res.span(), .{}); + try fs.cwd().access(res.constSlice(), .{}); return res; } @@ -158,7 +158,7 @@ fn findCommands(arena: *heap.ArenaAllocator) ![]Command { try res.append(command); } else { const command_path = findCommand(line) catch continue; - const command = pathToCommand(arena, command_path.span()) catch continue; + const command = pathToCommand(arena, command_path.constSlice()) catch continue; try res.append(command); } } @@ -172,9 +172,9 @@ const Allocators = struct { }; fn findCommand(name: []const u8) !util.Path { - const self_exe_dir = (try util.dir.selfExeDir()).span(); - const config_dir = (try util.dir.folder(.local_configuration)).span(); - const cwd = (try util.dir.cwd()).span(); + const self_exe_dir = (try util.dir.selfExeDir()).slice(); + const config_dir = (try util.dir.folder(.local_configuration)).slice(); + const cwd = (try util.dir.cwd()).slice(); return joinAccess(&[_][]const u8{ cwd, name }) catch joinAccess(&[_][]const u8{ config_dir, program_name, name }) catch joinAccess(&[_][]const u8{ self_exe_dir, "randomizers", name }) catch @@ -184,12 +184,12 @@ fn findCommand(name: []const u8) !util.Path { fn openCommandFile() !fs.File { const cwd = fs.cwd(); - const config_dir = (try util.dir.folder(.local_configuration)).span(); + const config_dir = (try util.dir.folder(.local_configuration)).slice(); const command_path = util.path.join(&[_][]const u8{ config_dir, program_name, command_file_name, - }).span(); + }).slice(); // TODO: When we want to enable plugin support, readd this //if (cwd.openFile(command_path, .{})) |file| { diff --git a/src/gui/tm35-randomizer.zig b/src/gui/tm35-randomizer.zig index 57b66af..fcfffd4 100644 --- a/src/gui/tm35-randomizer.zig +++ b/src/gui/tm35-randomizer.zig @@ -533,7 +533,25 @@ pub fn drawActions( .save_settings => c.NFD_SaveDialog(null, null, &m_out_path), .load_settings => c.NFD_OpenDialog(null, null, &m_out_path), .load_rom => c.NFD_OpenDialog("gb,gba,nds", null, &m_out_path), - .randomize => c.NFD_SaveDialog("gb,gba,nds", null, &m_out_path), + .randomize => blk: { + const in_rom_path = in_rom.?.path.constSlice(); + const dirname = path.dirname(in_rom_path) orelse "."; + const ext = path.extension(in_rom_path); + const in_name = basenameNoExt(in_rom_path); + + var default_path = util.Path{ .buffer = undefined }; + default_path.appendSlice(dirname) catch {}; + default_path.appendSlice("/") catch {}; + default_path.appendSlice(in_name) catch {}; + default_path.appendSlice("-randomized") catch {}; + default_path.appendSlice(ext) catch {}; + default_path.append(0) catch {}; + + const default = default_path.slice(); + // Ensure we are null terminated even if the above fails. + default[default.len - 1] = 0; + break :blk c.NFD_SaveDialog("gb,gba,nds", default.ptr, &m_out_path); + }, }; const selected_path = switch (dialog_result) { @@ -553,7 +571,7 @@ pub fn drawActions( }, else => unreachable, }; - const selected_path_slice = selected_path.span(); + const selected_path_slice = selected_path.constSlice(); switch (file_browser_kind) { .load_rom => { @@ -563,7 +581,7 @@ pub fn drawActions( const result = std.ChildProcess.exec(.{ .allocator = fba.allocator(), .argv = &[_][]const u8{ - exes.identify.span(), + exes.identify.constSlice(), selected_path_slice, }, }) catch |err| { @@ -589,8 +607,8 @@ pub fn drawActions( .randomize => { // in should never be null here as the "Randomize" button is inactive when // it is. - const in_path = rom.?.path.span(); - const out_path = selected_path.span(); + const in_path = rom.?.path.slice(); + const out_path = selected_path.constSlice(); const stderr = std.io.getStdErr(); outputScript(stderr.writer(), exes, settings.*, in_path, out_path) catch {}; @@ -605,24 +623,24 @@ pub fn drawActions( popups.info("Rom has been randomized!", .{}); }, .load_settings => { - const file = fs.cwd().openFile(selected_path.span(), .{}) catch |err| { - popups.err("Could not open '{s}': {}", .{ selected_path.span(), err }); + const file = fs.cwd().openFile(selected_path.constSlice(), .{}) catch |err| { + popups.err("Could not open '{s}': {}", .{ selected_path.constSlice(), err }); return rom; }; defer file.close(); settings.load(exes, file.reader()) catch |err| { - popups.err("Failed to load from '{s}': {}", .{ selected_path.span(), err }); + popups.err("Failed to load from '{s}': {}", .{ selected_path.constSlice(), err }); return rom; }; }, .save_settings => { - const file = fs.cwd().createFile(selected_path.span(), .{}) catch |err| { - popups.err("Could not open '{s}': {}", .{ selected_path.span(), err }); + const file = fs.cwd().createFile(selected_path.constSlice(), .{}) catch |err| { + popups.err("Could not open '{s}': {}", .{ selected_path.constSlice(), err }); return rom; }; defer file.close(); settings.save(exes, file.writer()) catch |err| { - popups.err("Failed to write to '{s}': {}", .{ selected_path.span(), err }); + popups.err("Failed to write to '{s}': {}", .{ selected_path.constSlice(), err }); return rom; }; }, @@ -633,11 +651,10 @@ pub fn drawActions( pub fn drawInfo(ctx: *nk.Context, m_rom: ?Rom) void { if (c.nk_group_begin(ctx, "Info", border_title_group) == 0) return; - defer c.nk_group_end(ctx); - const rom = m_rom orelse return; - var it = mem.split(u8, rom.info.span(), "\n"); + const info = if (m_rom) |*rom| rom.info.constSlice() else "No rom has been opened yet."; + var it = mem.split(u8, info, "\n"); while (it.next()) |line_notrim| { const line = mem.trimRight(u8, line_notrim, " "); if (line.len == 0) @@ -807,22 +824,22 @@ fn randomize(exes: Executables, settings: Settings, in: []const u8, out: []const .windows => blk: { const cache_dir = try util.dir.folder(.cache); const program_cache_dir = util.path.join(&[_][]const u8{ - cache_dir.span(), + cache_dir.constSlice(), Executables.program_name, }); const script_file_name = util.path.join(&[_][]const u8{ - program_cache_dir.span(), + program_cache_dir.constSlice(), "tmp_scipt.bat", }); { - try fs.cwd().makePath(program_cache_dir.span()); - const file = try fs.cwd().createFile(script_file_name.span(), .{}); + try fs.cwd().makePath(program_cache_dir.constSlice()); + const file = try fs.cwd().createFile(script_file_name.constSlice(), .{}); defer file.close(); try outputScript(file.writer(), exes, settings, in, out); } const cmd = try std.ChildProcess.init( - &[_][]const u8{ "cmd", "/c", "call", script_file_name.span() }, + &[_][]const u8{ "cmd", "/c", "call", script_file_name.constSlice() }, fba.allocator(), ); defer cmd.deinit(); @@ -866,7 +883,7 @@ fn outputScript( const esc = escape.generate(&escapes); try writer.writeAll(quotes); - try esc.escapeWrite(writer, exes.load.span()); + try esc.escapeWrite(writer, exes.load.constSlice()); try writer.writeAll(quotes ++ " " ++ quotes); try esc.escapeWrite(writer, in); try writer.writeAll(quotes ++ " | "); @@ -939,7 +956,7 @@ fn outputScript( } try writer.writeAll(quotes); - try esc.escapeWrite(writer, exes.apply.span()); + try esc.escapeWrite(writer, exes.apply.constSlice()); try writer.writeAll(quotes ++ " --replace --output " ++ quotes); try esc.escapeWrite(writer, out); try writer.writeAll(quotes ++ " " ++ quotes);