working version and not working steamParser

This commit is contained in:
Dario48 2026-06-19 18:44:20 +02:00
commit 182b7d3f21
7 changed files with 348 additions and 323 deletions

View file

@ -1,22 +1,13 @@
const std = @import("std");
const c = @import("imgui");
const CError = error{cError};
fn wrap(@"fn": anytype, fnArgs: anytype) CError!void {
const ret = @call(.auto, @"fn", fnArgs);
if (ret != 0) {
std.log.err("function " ++ @typeName(@TypeOf(@"fn")) ++ " returned code {}", .{ret});
return error.cError;
}
}
fn setFlags(flags: []const c_int, io: *c.struct_ImGuiIO_t) void {
for (flags) |flag| {
io.ConfigFlags |= flag;
}
}
export fn glfw_error_callback(@"error": c_int, description: [*c]const u8) void {
export fn glfw_error_callback(@"error": c_int, description: [*c]const u8) callconv(.c) void {
std.log.err("GLFW error {}: {s}", .{ @"error", description });
}
@ -71,8 +62,10 @@ fn formatArgv(alloc: std.mem.Allocator, format: []const u8, path: []const u8) ![
'\\' => {
if (escaped)
try inner.append(alloc, '\\')
else
else {
escaped = true;
continue;
}
},
's' => try if (escaped) inner.appendSlice(alloc, path) else inner.append(alloc, 's'),
'\t'...'\r', ' ' => |w| {
@ -89,6 +82,11 @@ fn formatArgv(alloc: std.mem.Allocator, format: []const u8, path: []const u8) ![
}
if (escaped) escaped = false;
}
const owned = try inner.toOwnedSlice(alloc);
errdefer alloc.free(owned);
try outer.append(alloc, owned);
return outer.toOwnedSlice(alloc);
}
@ -99,7 +97,7 @@ const opts = struct {
classic: bool = false,
width: f32 = 1280,
height: f32 = 800,
zonPath: [:0]const u8 = ".",
zonPath: []const u8 = ".",
};
var args: opts = .{};
@ -130,6 +128,16 @@ const floatOptMap = map[1];
var argv: ?[][]u8 = null;
var stackTraceBuf: [32]usize = undefined; // you never know how long the rabbit stack trace goes
var stackTrace: std.debug.StackTrace = undefined;
var caughtErr: ?anyerror = null;
fn handleErr(caught: anyerror) void {
caughtErr = caught;
stackTrace = std.debug.captureCurrentStackTrace(.{}, &stackTraceBuf);
c.ImGui_OpenPopup("errPopup", 0);
}
pub fn main(init: std.process.Init) !void {
{
var iter = try init.minimal.args.iterateAllocator(init.gpa);
@ -143,7 +151,9 @@ pub fn main(init: std.process.Init) !void {
if (std.mem.cutScalar(u8, i, '=')) |v| {
const opt, const value = v;
if (floatOptMap.get(opt)) |o|
o.* = try std.fmt.parseFloat(f32, value);
o.* = try std.fmt.parseFloat(f32, value)
else if (std.mem.eql(u8, opt, "zonPath"))
args.zonPath = value;
}
}
}
@ -159,7 +169,7 @@ pub fn main(init: std.process.Init) !void {
defer file.close(init.io);
var buf: [1024]u8 = undefined;
var reader = file.reader(init.io, &buf);
const content = try reader.interface.allocRemainingAlignedSentinel(init.gpa, .unlimited, .of(u8), 0);
const content = try reader.interface.allocRemainingAlignedSentinel(init.arena.allocator(), .unlimited, .of(u8), 0);
var diag: std.zon.parse.Diagnostics = .{};
const zon = std.zon.parse.fromSliceAlloc(struct {
@ -168,29 +178,30 @@ pub fn main(init: std.process.Init) !void {
exec_format: []const u8,
},
roms: []struct {
name: [:0]const u8,
name: []const u8,
emu: []const u8,
path: []const u8,
},
}, init.gpa, content, &diag, .{}) catch |err| {
}, init.arena.allocator(), content, &diag, .{}) catch |err| {
std.log.err("{f}", .{diag});
return err;
};
defer std.zon.parse.free(init.gpa, zon);
_ = c.glfwSetErrorCallback(glfw_error_callback);
try wrap(c.glfwInit, .{});
if (c.glfwInit() == 0) return error.glfwInitError;
defer c.glfwTerminate();
const glsl_version = "#version 300 es";
c.glfwWindowHint(c.GLFW_VERSION_MAJOR, 3);
c.glfwWindowHint(c.GLFW_VERSION_MINOR, 3);
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 3);
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 0);
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_OPENGL_ES_API);
const main_scale = c.cImGui_ImplGlfw_GetContentScaleForMonitor(c.glfwGetPrimaryMonitor());
const window = c.glfwCreateWindow(@trunc(args.width * main_scale), @trunc(args.height * main_scale), "choose rom to execute", c.glfwGetPrimaryMonitor(), null) orelse return error.GLFWWindowInitErr;
const window = c.glfwCreateWindow(@trunc(args.width), @trunc(args.height), "choose rom to execute", null, null) orelse return error.GLFWWindowInitErr;
defer c.glfwDestroyWindow(window);
const main_scale = c.cImGui_ImplGlfw_GetContentScaleForMonitor(c.glfwGetWindowMonitor(window));
c.glfwSetWindowSize(window, @trunc(args.width * main_scale), @trunc(args.height * main_scale));
c.glfwMakeContextCurrent(window);
c.glfwSwapInterval(@intFromBool(args.vsync)); // enable vsync
@ -221,7 +232,11 @@ pub fn main(init: std.process.Init) !void {
defer c.cImGui_ImplOpenGL3_Shutdown();
const clear_color = c.ImVec4{ .x = 0.45, .y = 0.55, .w = 0.60, .z = 1 };
var loopArena = std.heap.ArenaAllocator.init(init.gpa);
var searchBuf: [512]u8 = undefined;
searchBuf[0] = 0;
while (c.glfwWindowShouldClose(window) == 0) {
defer _ = loopArena.reset(.free_all);
c.glfwPollEvents();
if (c.glfwGetWindowAttrib(window, c.GLFW_ICONIFIED) != 0) {
c.cImGui_ImplGlfw_Sleep(10);
@ -232,31 +247,58 @@ pub fn main(init: std.process.Init) !void {
c.ImGui_NewFrame();
{
if (!c.ImGui_Begin("console", null, 0)) return error.BeginError;
const viewport = c.ImGui_GetMainViewport();
c.ImGui_SetNextWindowPos(viewport.*.WorkPos, 0);
c.ImGui_SetNextWindowSize(viewport.*.WorkSize, 0);
const flags = c.ImGuiWindowFlags_NoTitleBar |
c.ImGuiWindowFlags_NoResize |
c.ImGuiWindowFlags_NoMove |
c.ImGuiWindowFlags_NoScrollbar |
c.ImGuiWindowFlags_NoCollapse |
c.ImGuiWindowFlags_NoBringToFrontOnFocus;
if (!c.ImGui_Begin("emu_ui", null, flags)) return error.BeginError;
defer c.ImGui_End();
var err: anyerror = error.NoError;
errdefer |encounteredErr| {
err = encounteredErr;
c.ImGui_OpenPopup("errPopup", 0);
}
{
if (c.ImGui_BeginPopup("errPopUp", 0)) {
if (c.ImGui_BeginPopupModal("errPopup", null, c.ImGuiWindowFlags_AlwaysAutoResize)) {
defer c.ImGui_EndPopup();
c.ImGui_Text("encontered error '%s'", @errorName(err).ptr);
c.ImGui_Text("encontered error '%s'", @errorName(caughtErr orelse unreachable).ptr);
const label = "ok";
const text_width = c.ImGui_CalcTextSize(label).x;
const button_width = text_width + c.ImGui_GetStyle().*.FramePadding.x * 2;
const window_width = c.ImGui_GetContentRegionAvail().x;
c.ImGui_SetCursorPosX((window_width - button_width) / 2);
if (c.ImGui_Button(label))
c.ImGui_CloseCurrentPopup();
} else if (caughtErr) |err| {
stackTrace.return_addresses.ptr = @ptrCast(&stackTrace.return_addresses[1]);
stackTrace.return_addresses.len = stackTrace.return_addresses.len - 1;
std.debug.dumpStackTrace(&stackTrace);
return err;
}
}
for (zon.roms) |rom| {
if (c.ImGui_Button(rom.name.ptr)) {
for (zon.emus) |emu|
if (std.mem.eql(u8, emu.name, rom.emu)) {
c.glfwSetWindowShouldClose(window, 1);
argv = try formatArgv(init.arena.allocator(), emu.exec_format, rom.name);
};
return error.InvalidEmu;
}
_ = c.ImGui_InputText("search", &searchBuf, searchBuf.len, 0);
const text = std.mem.sliceTo(&searchBuf, 0);
outer: for (zon.roms) |rom| {
if (text.len == 0 or std.mem.containsAtLeast(u8, rom.name, 1, text))
if (c.ImGui_Button((try std.fmt.allocPrintSentinel(loopArena.allocator(), "{s}: {s}", .{ rom.name, rom.emu }, 0)).ptr)) {
std.log.debug("rom.emu: '{s}'", .{rom.emu});
for (zon.emus) |emu| {
std.log.debug(" emu.name: '{s}'", .{emu.name});
if (std.mem.eql(u8, emu.name, rom.emu)) {
argv = formatArgv(init.arena.allocator(), emu.exec_format, rom.path) catch |err| blk: {
handleErr(err);
break :blk null;
};
if (argv) |_|
c.glfwSetWindowShouldClose(window, 1);
break :outer;
}
}
handleErr(error.InvalidEmu);
};
}
}
@ -274,6 +316,9 @@ pub fn main(init: std.process.Init) !void {
}
if (argv) |a| {
std.log.debug("args.len: {}", .{a.len});
for (a, 0..) |arg, i|
std.log.debug("args[{}]: {s}", .{ i, arg });
return std.process.replace(init.io, .{ .argv = a });
}
}

65
src/steamParser.zig Normal file
View file

@ -0,0 +1,65 @@
const std = @import("std");
var opts: struct {
zonPath: []const u8 = ".",
steamPath: []const u8 = "~/.steam/root/",
} = .{};
pub fn main(init: std.process.Init) !void {
var args = try init.minimal.args.iterateAllocator(init.gpa);
defer args.deinit();
while (args.next()) |arg| {
if (std.mem.eql(u8, arg, "-z"))
opts.zonPath = args.next() orelse {
std.log.err("argoument -z should be followed by a path", .{});
return error.argErr;
}
else if (std.mem.eql(u8, arg, "-s"))
opts.steamPath = args.next() orelse {
std.log.err("argoument -s should be followed by a path", .{});
return error.argErr;
}
else if (std.mem.cutScalar(u8, &arg, '=')) |cut| {
const o, const v = cut;
if (std.mem.eql(u8, o, "--zonPath"))
opts.zonPath = v
else if (std.mem.eql(u8, o, "--steamPath"))
opts.steamPath = v;
}
}
const file = std.Io.Dir.cwd().openFile(init.io, args.zonPath, .{ .allow_directory = false }) catch |err| switch (err) {
error.IsDir => blk: {
const dir = try std.Io.Dir.cwd().openDir(init.io, args.zonPath, .{});
defer dir.close(init.io);
break :blk try dir.openFile(init.io, "rom_list.zon", .{});
},
else => |e| return e,
};
defer file.close(init.io);
var buf: [1024]u8 = undefined;
var reader = file.reader(init.io, &buf);
const content = try reader.interface.allocRemainingAlignedSentinel(init.arena.allocator(), .unlimited, .of(u8), 0);
var diag: std.zon.parse.Diagnostics = .{};
const zon = std.zon.parse.fromSliceAlloc(struct {
emus: []struct {
name: []const u8,
exec_format: []const u8,
},
roms: []struct {
name: []const u8,
emu: []const u8,
path: []const u8,
},
}, init.arena.allocator(), content, &diag, .{}) catch |err| {
std.log.err("{f}", .{diag});
return err;
};
const alreadySaved: std.StringHashMap(null) = .init(init.gpa);
defer alreadySaved.deinit();
for (zon.roms) |rom| {
if (std.mem.eql(u8, "steam", rom.emu))
try alreadySaved.put(rom.name, {});
}
}