From 40c7c27b8821e44c34890f1b278b5ef3f2da7bb9 Mon Sep 17 00:00:00 2001 From: AnErrupTion Date: Wed, 21 Jun 2023 15:20:44 +0200 Subject: [PATCH] Partially rewrite utils.c --- src/config.zig | 298 ++++++++++++++++++++++++------------------------ src/ini.zig | 155 ++++++++++++------------- src/interop.zig | 6 +- src/main.zig | 103 ++++++++--------- src/utils.c | 208 --------------------------------- src/utils.h | 2 - src/utils.zig | 114 ++++++++++++++++++ 7 files changed, 396 insertions(+), 490 deletions(-) create mode 100644 src/utils.zig diff --git a/src/config.zig b/src/config.zig index 5fe992a..f25d2f0 100644 --- a/src/config.zig +++ b/src/config.zig @@ -171,7 +171,8 @@ var lang_wayland: [:0]u8 = undefined; var lang_xinitrc: [:0]u8 = undefined; pub fn config_load(cfg_path: []const u8) !void { - var file = try std.fs.cwd().openFile(if (std.mem.eql(u8, cfg_path, "")) INI_CONFIG_PATH ++ "config.ini" else cfg_path, .{}); + var file = try std.fs.cwd().openFile(if (cfg_path.len == 0) INI_CONFIG_PATH ++ "config.ini" else cfg_path, .{}); + defer file.close(); config_buffer = try main.allocator.alloc(u8, INI_CONFIG_MAX_SIZE); @@ -197,45 +198,45 @@ pub fn config_load(cfg_path: []const u8) !void { config_xauth_cmd = try interop.c_str(ly_config.ly.xauth_cmd); config_xsessions = try interop.c_str(ly_config.ly.xsessions); - main.config.animate = ly_config.ly.animate; - main.config.animation = ly_config.ly.animation; - main.config.asterisk = ly_config.ly.asterisk; - main.config.bg = ly_config.ly.bg; - main.config.bigclock = ly_config.ly.bigclock; - main.config.blank_box = ly_config.ly.blank_box; - main.config.blank_password = ly_config.ly.blank_password; - main.config.clock = config_clock.ptr; - main.config.console_dev = config_console_dev.ptr; - main.config.default_input = ly_config.ly.default_input; - main.config.fg = ly_config.ly.fg; - main.config.hide_borders = ly_config.ly.hide_borders; - main.config.hide_f1_commands = ly_config.ly.hide_f1_commands; - main.config.input_len = ly_config.ly.input_len; - main.config.lang = config_lang.ptr; - main.config.load = ly_config.ly.load; - main.config.margin_box_h = ly_config.ly.margin_box_h; - main.config.margin_box_v = ly_config.ly.margin_box_v; - main.config.max_desktop_len = ly_config.ly.max_desktop_len; - main.config.max_login_len = ly_config.ly.max_login_len; - main.config.max_password_len = ly_config.ly.max_password_len; - main.config.mcookie_cmd = config_mcookie_cmd.ptr; - main.config.min_refresh_delta = ly_config.ly.min_refresh_delta; - main.config.path = config_path.ptr; - main.config.restart_cmd = config_restart_cmd.ptr; - main.config.save = ly_config.ly.save; - main.config.save_file = config_save_file.ptr; - main.config.service_name = config_service_name.ptr; - main.config.shutdown_cmd = config_shutdown_cmd.ptr; - main.config.term_reset_cmd = config_term_reset_cmd.ptr; - main.config.tty = ly_config.ly.tty; - main.config.wayland_cmd = config_wayland_cmd.ptr; - main.config.wayland_specifier = ly_config.ly.wayland_specifier; - main.config.waylandsessions = config_waylandsessions.ptr; - main.config.x_cmd = config_x_cmd.ptr; - main.config.xinitrc = config_xinitrc.ptr; - main.config.x_cmd_setup = config_x_cmd_setup.ptr; - main.config.xauth_cmd = config_xauth_cmd.ptr; - main.config.xsessions = config_xsessions.ptr; + main.c_config.animate = ly_config.ly.animate; + main.c_config.animation = ly_config.ly.animation; + main.c_config.asterisk = ly_config.ly.asterisk; + main.c_config.bg = ly_config.ly.bg; + main.c_config.bigclock = ly_config.ly.bigclock; + main.c_config.blank_box = ly_config.ly.blank_box; + main.c_config.blank_password = ly_config.ly.blank_password; + main.c_config.clock = config_clock.ptr; + main.c_config.console_dev = config_console_dev.ptr; + main.c_config.default_input = ly_config.ly.default_input; + main.c_config.fg = ly_config.ly.fg; + main.c_config.hide_borders = ly_config.ly.hide_borders; + main.c_config.hide_f1_commands = ly_config.ly.hide_f1_commands; + main.c_config.input_len = ly_config.ly.input_len; + main.c_config.lang = config_lang.ptr; + main.c_config.load = ly_config.ly.load; + main.c_config.margin_box_h = ly_config.ly.margin_box_h; + main.c_config.margin_box_v = ly_config.ly.margin_box_v; + main.c_config.max_desktop_len = ly_config.ly.max_desktop_len; + main.c_config.max_login_len = ly_config.ly.max_login_len; + main.c_config.max_password_len = ly_config.ly.max_password_len; + main.c_config.mcookie_cmd = config_mcookie_cmd.ptr; + main.c_config.min_refresh_delta = ly_config.ly.min_refresh_delta; + main.c_config.path = config_path.ptr; + main.c_config.restart_cmd = config_restart_cmd.ptr; + main.c_config.save = ly_config.ly.save; + main.c_config.save_file = config_save_file.ptr; + main.c_config.service_name = config_service_name.ptr; + main.c_config.shutdown_cmd = config_shutdown_cmd.ptr; + main.c_config.term_reset_cmd = config_term_reset_cmd.ptr; + main.c_config.tty = ly_config.ly.tty; + main.c_config.wayland_cmd = config_wayland_cmd.ptr; + main.c_config.wayland_specifier = ly_config.ly.wayland_specifier; + main.c_config.waylandsessions = config_waylandsessions.ptr; + main.c_config.x_cmd = config_x_cmd.ptr; + main.c_config.xinitrc = config_xinitrc.ptr; + main.c_config.x_cmd_setup = config_x_cmd_setup.ptr; + main.c_config.xauth_cmd = config_xauth_cmd.ptr; + main.c_config.xsessions = config_xsessions.ptr; } pub fn lang_load() !void { @@ -243,6 +244,7 @@ pub fn lang_load() !void { defer main.allocator.free(path); var file = try std.fs.cwd().openFile(path, .{}); + defer file.close(); lang_buffer = try main.allocator.alloc(u8, INI_CONFIG_MAX_SIZE); @@ -296,119 +298,121 @@ pub fn lang_load() !void { lang_wayland = try interop.c_str(ly_lang.ly.wayland); lang_xinitrc = try interop.c_str(ly_lang.ly.xinitrc); - main.lang.capslock = lang_capslock.ptr; - main.lang.err_alloc = lang_err_alloc.ptr; - main.lang.err_bounds = lang_err_bounds.ptr; - main.lang.err_chdir = lang_err_chdir.ptr; - main.lang.err_console_dev = lang_err_console_dev.ptr; - main.lang.err_dgn_oob = lang_err_dgn_oob.ptr; - main.lang.err_domain = lang_err_domain.ptr; - main.lang.err_hostname = lang_err_hostname.ptr; - main.lang.err_mlock = lang_err_mlock.ptr; - main.lang.err_null = lang_err_null.ptr; - main.lang.err_pam = lang_err_pam.ptr; - main.lang.err_pam_abort = lang_err_pam_abort.ptr; - main.lang.err_pam_acct_expired = lang_err_pam_acct_expired.ptr; - main.lang.err_pam_auth = lang_err_pam_auth.ptr; - main.lang.err_pam_authinfo_unavail = lang_err_pam_authinfo_unavail.ptr; - main.lang.err_pam_authok_reqd = lang_err_pam_authok_reqd.ptr; - main.lang.err_pam_buf = lang_err_pam_buf.ptr; - main.lang.err_pam_cred_err = lang_err_pam_cred_err.ptr; - main.lang.err_pam_cred_expired = lang_err_pam_cred_expired.ptr; - main.lang.err_pam_cred_insufficient = lang_err_pam_cred_insufficient.ptr; - main.lang.err_pam_cred_unavail = lang_err_pam_cred_unavail.ptr; - main.lang.err_pam_maxtries = lang_err_pam_maxtries.ptr; - main.lang.err_pam_perm_denied = lang_err_pam_perm_denied.ptr; - main.lang.err_pam_session = lang_err_pam_session.ptr; - main.lang.err_pam_sys = lang_err_pam_sys.ptr; - main.lang.err_pam_user_unknown = lang_err_pam_user_unknown.ptr; - main.lang.err_path = lang_err_path.ptr; - main.lang.err_perm_dir = lang_err_perm_dir.ptr; - main.lang.err_perm_group = lang_err_perm_group.ptr; - main.lang.err_perm_user = lang_err_perm_user.ptr; - main.lang.err_pwnam = lang_err_pwnam.ptr; - main.lang.err_user_gid = lang_err_user_gid.ptr; - main.lang.err_user_init = lang_err_user_init.ptr; - main.lang.err_user_uid = lang_err_user_uid.ptr; - main.lang.err_xsessions_dir = lang_err_xsessions_dir.ptr; - main.lang.err_xsessions_open = lang_err_xsessions_open.ptr; - main.lang.f1 = lang_f1.ptr; - main.lang.f2 = lang_f2.ptr; - main.lang.login = lang_login.ptr; - main.lang.logout = lang_logout.ptr; - main.lang.numlock = lang_numlock.ptr; - main.lang.password = lang_password.ptr; - main.lang.shell = lang_shell.ptr; - main.lang.wayland = lang_wayland.ptr; - main.lang.xinitrc = lang_xinitrc.ptr; + main.c_lang.capslock = lang_capslock.ptr; + main.c_lang.err_alloc = lang_err_alloc.ptr; + main.c_lang.err_bounds = lang_err_bounds.ptr; + main.c_lang.err_chdir = lang_err_chdir.ptr; + main.c_lang.err_console_dev = lang_err_console_dev.ptr; + main.c_lang.err_dgn_oob = lang_err_dgn_oob.ptr; + main.c_lang.err_domain = lang_err_domain.ptr; + main.c_lang.err_hostname = lang_err_hostname.ptr; + main.c_lang.err_mlock = lang_err_mlock.ptr; + main.c_lang.err_null = lang_err_null.ptr; + main.c_lang.err_pam = lang_err_pam.ptr; + main.c_lang.err_pam_abort = lang_err_pam_abort.ptr; + main.c_lang.err_pam_acct_expired = lang_err_pam_acct_expired.ptr; + main.c_lang.err_pam_auth = lang_err_pam_auth.ptr; + main.c_lang.err_pam_authinfo_unavail = lang_err_pam_authinfo_unavail.ptr; + main.c_lang.err_pam_authok_reqd = lang_err_pam_authok_reqd.ptr; + main.c_lang.err_pam_buf = lang_err_pam_buf.ptr; + main.c_lang.err_pam_cred_err = lang_err_pam_cred_err.ptr; + main.c_lang.err_pam_cred_expired = lang_err_pam_cred_expired.ptr; + main.c_lang.err_pam_cred_insufficient = lang_err_pam_cred_insufficient.ptr; + main.c_lang.err_pam_cred_unavail = lang_err_pam_cred_unavail.ptr; + main.c_lang.err_pam_maxtries = lang_err_pam_maxtries.ptr; + main.c_lang.err_pam_perm_denied = lang_err_pam_perm_denied.ptr; + main.c_lang.err_pam_session = lang_err_pam_session.ptr; + main.c_lang.err_pam_sys = lang_err_pam_sys.ptr; + main.c_lang.err_pam_user_unknown = lang_err_pam_user_unknown.ptr; + main.c_lang.err_path = lang_err_path.ptr; + main.c_lang.err_perm_dir = lang_err_perm_dir.ptr; + main.c_lang.err_perm_group = lang_err_perm_group.ptr; + main.c_lang.err_perm_user = lang_err_perm_user.ptr; + main.c_lang.err_pwnam = lang_err_pwnam.ptr; + main.c_lang.err_user_gid = lang_err_user_gid.ptr; + main.c_lang.err_user_init = lang_err_user_init.ptr; + main.c_lang.err_user_uid = lang_err_user_uid.ptr; + main.c_lang.err_xsessions_dir = lang_err_xsessions_dir.ptr; + main.c_lang.err_xsessions_open = lang_err_xsessions_open.ptr; + main.c_lang.f1 = lang_f1.ptr; + main.c_lang.f2 = lang_f2.ptr; + main.c_lang.login = lang_login.ptr; + main.c_lang.logout = lang_logout.ptr; + main.c_lang.numlock = lang_numlock.ptr; + main.c_lang.password = lang_password.ptr; + main.c_lang.shell = lang_shell.ptr; + main.c_lang.wayland = lang_wayland.ptr; + main.c_lang.xinitrc = lang_xinitrc.ptr; } pub fn config_free() void { - main.allocator.free(config_clock); - main.allocator.free(config_console_dev); - main.allocator.free(config_lang); - main.allocator.free(config_mcookie_cmd); - main.allocator.free(config_path); - main.allocator.free(config_restart_cmd); - main.allocator.free(config_save_file); - main.allocator.free(config_service_name); - main.allocator.free(config_shutdown_cmd); - main.allocator.free(config_term_reset_cmd); - main.allocator.free(config_wayland_cmd); - main.allocator.free(config_waylandsessions); - main.allocator.free(config_x_cmd); - main.allocator.free(config_xinitrc); - main.allocator.free(config_x_cmd_setup); - main.allocator.free(config_xauth_cmd); - main.allocator.free(config_xsessions); + interop.allocator.free(config_clock); + interop.allocator.free(config_console_dev); + interop.allocator.free(config_lang); + interop.allocator.free(config_mcookie_cmd); + interop.allocator.free(config_path); + interop.allocator.free(config_restart_cmd); + interop.allocator.free(config_save_file); + interop.allocator.free(config_service_name); + interop.allocator.free(config_shutdown_cmd); + interop.allocator.free(config_term_reset_cmd); + interop.allocator.free(config_wayland_cmd); + interop.allocator.free(config_waylandsessions); + interop.allocator.free(config_x_cmd); + interop.allocator.free(config_xinitrc); + interop.allocator.free(config_x_cmd_setup); + interop.allocator.free(config_xauth_cmd); + interop.allocator.free(config_xsessions); + main.allocator.free(config_buffer); } pub fn lang_free() void { - main.allocator.free(lang_capslock); - main.allocator.free(lang_err_alloc); - main.allocator.free(lang_err_bounds); - main.allocator.free(lang_err_chdir); - main.allocator.free(lang_err_console_dev); - main.allocator.free(lang_err_dgn_oob); - main.allocator.free(lang_err_domain); - main.allocator.free(lang_err_hostname); - main.allocator.free(lang_err_mlock); - main.allocator.free(lang_err_null); - main.allocator.free(lang_err_pam); - main.allocator.free(lang_err_pam_abort); - main.allocator.free(lang_err_pam_acct_expired); - main.allocator.free(lang_err_pam_auth); - main.allocator.free(lang_err_pam_authinfo_unavail); - main.allocator.free(lang_err_pam_authok_reqd); - main.allocator.free(lang_err_pam_buf); - main.allocator.free(lang_err_pam_cred_err); - main.allocator.free(lang_err_pam_cred_expired); - main.allocator.free(lang_err_pam_cred_insufficient); - main.allocator.free(lang_err_pam_cred_unavail); - main.allocator.free(lang_err_pam_maxtries); - main.allocator.free(lang_err_pam_perm_denied); - main.allocator.free(lang_err_pam_session); - main.allocator.free(lang_err_pam_sys); - main.allocator.free(lang_err_pam_user_unknown); - main.allocator.free(lang_err_path); - main.allocator.free(lang_err_perm_dir); - main.allocator.free(lang_err_perm_group); - main.allocator.free(lang_err_perm_user); - main.allocator.free(lang_err_pwnam); - main.allocator.free(lang_err_user_gid); - main.allocator.free(lang_err_user_init); - main.allocator.free(lang_err_user_uid); - main.allocator.free(lang_err_xsessions_dir); - main.allocator.free(lang_err_xsessions_open); - main.allocator.free(lang_f1); - main.allocator.free(lang_f2); - main.allocator.free(lang_login); - main.allocator.free(lang_logout); - main.allocator.free(lang_numlock); - main.allocator.free(lang_password); - main.allocator.free(lang_shell); - main.allocator.free(lang_wayland); - main.allocator.free(lang_xinitrc); + interop.allocator.free(lang_capslock); + interop.allocator.free(lang_err_alloc); + interop.allocator.free(lang_err_bounds); + interop.allocator.free(lang_err_chdir); + interop.allocator.free(lang_err_console_dev); + interop.allocator.free(lang_err_dgn_oob); + interop.allocator.free(lang_err_domain); + interop.allocator.free(lang_err_hostname); + interop.allocator.free(lang_err_mlock); + interop.allocator.free(lang_err_null); + interop.allocator.free(lang_err_pam); + interop.allocator.free(lang_err_pam_abort); + interop.allocator.free(lang_err_pam_acct_expired); + interop.allocator.free(lang_err_pam_auth); + interop.allocator.free(lang_err_pam_authinfo_unavail); + interop.allocator.free(lang_err_pam_authok_reqd); + interop.allocator.free(lang_err_pam_buf); + interop.allocator.free(lang_err_pam_cred_err); + interop.allocator.free(lang_err_pam_cred_expired); + interop.allocator.free(lang_err_pam_cred_insufficient); + interop.allocator.free(lang_err_pam_cred_unavail); + interop.allocator.free(lang_err_pam_maxtries); + interop.allocator.free(lang_err_pam_perm_denied); + interop.allocator.free(lang_err_pam_session); + interop.allocator.free(lang_err_pam_sys); + interop.allocator.free(lang_err_pam_user_unknown); + interop.allocator.free(lang_err_path); + interop.allocator.free(lang_err_perm_dir); + interop.allocator.free(lang_err_perm_group); + interop.allocator.free(lang_err_perm_user); + interop.allocator.free(lang_err_pwnam); + interop.allocator.free(lang_err_user_gid); + interop.allocator.free(lang_err_user_init); + interop.allocator.free(lang_err_user_uid); + interop.allocator.free(lang_err_xsessions_dir); + interop.allocator.free(lang_err_xsessions_open); + interop.allocator.free(lang_f1); + interop.allocator.free(lang_f2); + interop.allocator.free(lang_login); + interop.allocator.free(lang_logout); + interop.allocator.free(lang_numlock); + interop.allocator.free(lang_password); + interop.allocator.free(lang_shell); + interop.allocator.free(lang_wayland); + interop.allocator.free(lang_xinitrc); + main.allocator.free(lang_buffer); } diff --git a/src/ini.zig b/src/ini.zig index a1c01a7..a2a510b 100644 --- a/src/ini.zig +++ b/src/ini.zig @@ -1,116 +1,92 @@ const std = @import("std"); -// we ignore whitespace and comments pub const Token = union(enum) { comment, section: []const u8, key: []const u8, value: []const u8 }; -pub const State = enum { normal, section, key, value, comment }; - -pub fn getTok(data: []const u8, pos: *usize, state: *State) ?Token { - // if the position advances to the end of the data, there's no more tokens for us - if (pos.* >= data.len) return null; - var cur: u8 = 0; - // used for slicing - var start = pos.*; - var end = start; +pub fn getTok(data: []const u8, pos: *usize) ?Token { + // If the position advances to the end of the data, there's no more tokens for us + if (pos.* >= data.len) { + return null; + } while (pos.* < data.len) { - cur = data[pos.*]; + var current = data[pos.*]; pos.* += 1; - switch (state.*) { - .normal => { - switch (cur) { - '[' => { - state.* = .section; - start = pos.*; - end = start; - }, - '=' => { - state.* = .value; - start = pos.*; - if (std.ascii.isWhitespace(data[start])) start += 1; - end = start; - }, - ';', '#' => { - state.* = .comment; - }, - // if it is whitespace itgets skipped over anyways - else => if (!std.ascii.isWhitespace(cur)) { - state.* = .key; - start = pos.* - 1; - end = start; - }, + + switch (current) { + ' ', '\t', '\r', '\n' => {}, + '[' => { + var start = pos.*; + + current = data[pos.*]; + + while (current != ']') : (pos.* += 1) { + current = data[pos.*]; } + + return Token{ .section = data[start .. pos.* - 1] }; }, - .section => { - end += 1; - switch (cur) { - ']' => { - state.* = .normal; - pos.* += 1; - return Token{ .section = data[start .. end - 1] }; - }, - else => {}, + '=' => { + current = data[pos.*]; + + while (current == ' ' or current == '\t') { + pos.* += 1; + current = data[pos.*]; } + + var start = pos.*; + + while (current != '\n') : (pos.* += 1) { + current = data[pos.*]; + } + + return Token{ .value = if (start == pos.*) "" else data[start .. pos.* - 1] }; }, - .value => { - switch (cur) { - ';', '#' => { - state.* = .comment; - return Token{ .value = data[start .. end - 2] }; - }, - else => { - end += 1; - switch (cur) { - '\n' => { - state.* = .normal; - return Token{ .value = data[start .. end - 2] }; - }, - else => {}, - } - }, + ';', '#' => { + current = data[pos.*]; + + while (current != '\n') : (pos.* += 1) { + current = data[pos.*]; } + + return Token.comment; }, - .comment => { - end += 1; - switch (cur) { - '\n' => { - state.* = .normal; - return Token.comment; - }, - else => {}, - } - }, - .key => { - end += 1; - if (!(std.ascii.isAlphanumeric(cur) or cur == '_')) { - state.* = .normal; - return Token{ .key = data[start..end] }; + else => { + var start = pos.* - 1; + + current = data[pos.*]; + + while (std.ascii.isAlphanumeric(current) or current == '_') : (pos.* += 1) { + current = data[pos.*]; } + + pos.* -= 1; + + return Token{ .key = data[start..pos.*] }; }, } } + return null; } pub fn readToStruct(comptime T: type, data: []const u8) !T { var namespace: []const u8 = ""; var pos: usize = 0; - var state: State = .normal; var ret = std.mem.zeroes(T); - while (getTok(data, &pos, &state)) |tok| { + while (getTok(data, &pos)) |tok| { switch (tok) { .comment => {}, .section => |ns| { namespace = ns; }, .key => |key| { - var next_tok = getTok(data, &pos, &state); + var next_tok = getTok(data, &pos); // if there's nothing just give a comment which is also a syntax error switch (next_tok orelse .comment) { .value => |value| { // now we have the namespace, key, and value // namespace and key are runtime values, so we need to loop the struct instead of using @field inline for (std.meta.fields(T)) |ns_info| { - if (std.mem.eql(u8, ns_info.name, namespace)) { + if (eql(ns_info.name, namespace)) { // @field(ret, ns_info.name) contains the inner struct now // loop over the fields of the inner struct, and check for key matches inline for (std.meta.fields(@TypeOf(@field(ret, ns_info.name)))) |key_info| { @@ -124,11 +100,11 @@ pub fn readToStruct(comptime T: type, data: []const u8) !T { } }, // after a key, a value must follow - else => return error.SyntaxError, + else => return error.NoValueAfterKey, } }, // if we get a value with no key, that's a bit nonsense - .value => return error.SyntaxError, + .value => return error.ValueWithNoKey, } } return ret; @@ -171,6 +147,7 @@ pub fn writeStruct(struct_value: anytype, writer: anytype) !void { } } } +// Checks if the string is actually a single ASCII character, else, parse as an integer fn parseInt(comptime T: type, buf: []const u8, base: u8) std.fmt.ParseIntError!T { if (buf.len == 1) { var first_char = buf[0]; @@ -182,3 +159,21 @@ fn parseInt(comptime T: type, buf: []const u8, base: u8) std.fmt.ParseIntError!T return std.fmt.parseInt(T, buf, base); } +// Checks if 2 strings are equal, but comparing " " with "_" +fn eql(a: []const u8, b: []const u8) bool { + if (a.len != b.len) { + return false; + } + + if (a.ptr == b.ptr) { + return true; + } + + for (a, b) |a_elem, b_elem| { + if (a_elem != if (b_elem == ' ') '_' else b_elem) { + return false; + } + } + + return true; +} diff --git a/src/interop.zig b/src/interop.zig index 1f4eaf3..3cbe2fa 100644 --- a/src/interop.zig +++ b/src/interop.zig @@ -1,7 +1,9 @@ -const main = @import("main.zig"); +const std = @import("std"); + +pub const allocator = std.heap.raw_c_allocator; pub fn c_str(str: []const u8) ![:0]u8 { - const new_str = try main.allocator.allocSentinel(u8, str.len, 0); + const new_str = try allocator.allocSentinel(u8, str.len, 0); for (str, 0..) |c, i| { new_str[i] = c; diff --git a/src/main.zig b/src/main.zig index f147596..8074fed 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,5 +1,6 @@ const std = @import("std"); -const configuration = @import("config.zig"); +const config = @import("config.zig"); +const utils = @import("utils.zig"); pub const c = @cImport({ @cInclude("dragonfail.h"); @@ -22,12 +23,12 @@ var gpa = std.heap.GeneralPurposeAllocator(.{}){}; pub const allocator = gpa.allocator(); // Ly general and language configuration -pub var config: c.struct_config = undefined; -pub var lang: c.struct_lang = undefined; +pub var c_config: c.struct_config = undefined; +pub var c_lang: c.struct_lang = undefined; comptime { - @export(config, .{ .name = "config" }); - @export(lang, .{ .name = "lang" }); + @export(c_config, .{ .name = "config" }); + @export(c_lang, .{ .name = "lang" }); } // Main function @@ -39,8 +40,8 @@ pub fn main() !void { var lang_ptr = try allocator.create(c.struct_lang); defer allocator.destroy(lang_ptr); - config = config_ptr.*; - lang = lang_ptr.*; + c_config = config_ptr.*; + c_lang = lang_ptr.*; // Initialize error library log_init(c.dgn_init()); @@ -78,12 +79,12 @@ pub fn main() !void { } // Load configuration and language - try configuration.config_load(config_path); - try configuration.lang_load(); + try config.config_load(config_path); + try config.lang_load(); if (c.dgn_catch() != 0) { - configuration.config_free(); - configuration.lang_free(); + config.config_free(); + config.lang_free(); std.os.exit(1); } @@ -98,11 +99,11 @@ pub fn main() !void { defer allocator.destroy(password); c.input_desktop(desktop); - c.input_text(username, config.max_login_len); - c.input_text(password, config.max_password_len); + c.input_text(username, config.ly_config.ly.max_login_len); + c.input_text(password, config.ly_config.ly.max_password_len); - c.desktop_load(desktop); - c.load(desktop, username); + utils.desktop_load(desktop); + try utils.load(desktop, username); // Start termbox _ = c.tb_init(); @@ -119,10 +120,10 @@ pub fn main() !void { // Place the cursor on the login field if there is no saved username // If there is, place the curser on the password field var active_input: u8 = 0; - if (config.default_input == c.LOGIN_INPUT and username.text != username.end) { + if (config.ly_config.ly.default_input == c.LOGIN_INPUT and username.text != username.end) { active_input = c.PASSWORD_INPUT; } else { - active_input = config.default_input; + active_input = config.ly_config.ly.default_input; } // Initialize drawing code @@ -146,11 +147,11 @@ pub fn main() !void { else => unreachable, } - if (config.animate) { + if (config.ly_config.ly.animate) { c.animate_init(buffer); if (c.dgn_catch() != 0) { - config.animate = false; + config.ly_config.ly.animate = false; c.dgn_reset(); } } @@ -188,7 +189,7 @@ pub fn main() !void { c.draw_box(buffer); c.draw_clock(buffer); c.draw_labels(buffer); - if (!config.hide_f1_commands) { + if (!config.ly_config.ly.hide_f1_commands) { c.draw_f_commands(); } c.draw_lock_state(buffer); @@ -196,7 +197,7 @@ pub fn main() !void { c.draw_desktop(desktop); c.draw_input(username); c.draw_input_mask(password); - update = config.animate; + update = config.ly_config.ly.animate; } else { std.time.sleep(10000000); // Sleep 0.01 seconds update = c.cascade(buffer, &auth_fails); @@ -207,8 +208,8 @@ pub fn main() !void { var timeout: c_int = -1; - if (config.animate) { - timeout = config.min_refresh_delta; + if (config.ly_config.ly.animate) { + timeout = config.ly_config.ly.min_refresh_delta; } else { // TODO: Use the Zig standard library directly var time = try allocator.create(std.os.linux.timeval); @@ -216,9 +217,9 @@ pub fn main() !void { _ = std.os.linux.gettimeofday(time, undefined); - if (config.bigclock) { + if (config.ly_config.ly.bigclock) { timeout = @intCast(c_int, (60 - @mod(time.tv_sec, 60)) * 1000 - @divTrunc(time.tv_usec, 1000) + 1); - } else if (config.clock != undefined) { + } else if (config.ly_config.ly.clock.len > 0) { timeout = @intCast(c_int, 1000 - @divTrunc(time.tv_usec, 1000) + 1); } } @@ -283,7 +284,7 @@ pub fn main() !void { update = true; }, c.TB_KEY_ENTER => { - c.save(desktop, username); + try utils.save(desktop, username); c.auth(desktop, username, password, buffer); if (c.dgn_catch() != 0) { @@ -296,16 +297,16 @@ pub fn main() !void { buffer.info_line = c.dgn_output_log(); } - if (config.blank_password) { + if (config.ly_config.ly.blank_password) { c.input_text_clear(password); } c.dgn_reset(); } else { - buffer.info_line = lang.logout; + buffer.info_line = c_lang.logout; } - c.load(desktop, username); + try utils.load(desktop, username); // Reset cursor to its normal state _ = std.ChildProcess.exec(.{ .argv = &[_][]const u8{ "/usr/bin/tput", "cnorm" }, .allocator = allocator }) catch return; @@ -330,45 +331,45 @@ pub fn main() !void { // Unload configuration c.draw_free(buffer); - configuration.lang_free(); + config.lang_free(); if (shutdown) { - var shutdown_cmd = try std.fmt.allocPrint(allocator, "{s}", .{config.shutdown_cmd}); + var shutdown_cmd = try std.fmt.allocPrint(allocator, "{s}", .{config.ly_config.ly.shutdown_cmd}); // This will never be freed! But it's fine, we're shutting down the system anyway defer allocator.free(shutdown_cmd); - configuration.config_free(); + config.config_free(); std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", shutdown_cmd }) catch return; } else if (reboot) { - var restart_cmd = try std.fmt.allocPrint(allocator, "{s}", .{config.restart_cmd}); + var restart_cmd = try std.fmt.allocPrint(allocator, "{s}", .{config.ly_config.ly.restart_cmd}); // This will never be freed! But it's fine, we're rebooting the system anyway defer allocator.free(restart_cmd); - configuration.config_free(); + config.config_free(); std.process.execv(allocator, &[_][]const u8{ "/bin/sh", "-c", restart_cmd }) catch return; } else { - configuration.config_free(); + config.config_free(); } } // Low-level error messages fn log_init(log: [*c][*c]u8) void { - log[c.DGN_OK] = lang.err_dgn_oob; - log[c.DGN_NULL] = lang.err_null; - log[c.DGN_ALLOC] = lang.err_alloc; - log[c.DGN_BOUNDS] = lang.err_bounds; - log[c.DGN_DOMAIN] = lang.err_domain; - log[c.DGN_MLOCK] = lang.err_mlock; - log[c.DGN_XSESSIONS_DIR] = lang.err_xsessions_dir; - log[c.DGN_XSESSIONS_OPEN] = lang.err_xsessions_open; - log[c.DGN_PATH] = lang.err_path; - log[c.DGN_CHDIR] = lang.err_chdir; - log[c.DGN_PWNAM] = lang.err_pwnam; - log[c.DGN_USER_INIT] = lang.err_user_init; - log[c.DGN_USER_GID] = lang.err_user_gid; - log[c.DGN_USER_UID] = lang.err_user_uid; - log[c.DGN_PAM] = lang.err_pam; - log[c.DGN_HOSTNAME] = lang.err_hostname; + log[c.DGN_OK] = c_lang.err_dgn_oob; + log[c.DGN_NULL] = c_lang.err_null; + log[c.DGN_ALLOC] = c_lang.err_alloc; + log[c.DGN_BOUNDS] = c_lang.err_bounds; + log[c.DGN_DOMAIN] = c_lang.err_domain; + log[c.DGN_MLOCK] = c_lang.err_mlock; + log[c.DGN_XSESSIONS_DIR] = c_lang.err_xsessions_dir; + log[c.DGN_XSESSIONS_OPEN] = c_lang.err_xsessions_open; + log[c.DGN_PATH] = c_lang.err_path; + log[c.DGN_CHDIR] = c_lang.err_chdir; + log[c.DGN_PWNAM] = c_lang.err_pwnam; + log[c.DGN_USER_INIT] = c_lang.err_user_init; + log[c.DGN_USER_GID] = c_lang.err_user_gid; + log[c.DGN_USER_UID] = c_lang.err_user_uid; + log[c.DGN_PAM] = c_lang.err_pam; + log[c.DGN_HOSTNAME] = c_lang.err_hostname; } diff --git a/src/utils.c b/src/utils.c index bc55e4a..2c08de9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -19,142 +19,6 @@ #include #endif -static void config_handle_str(void* data, char** pars, const int pars_count) -{ - if (*((char**)data) != NULL) - { - free(*((char**)data)); - } - - *((char**)data) = strdup(*pars); -} - -void desktop_crawl( - struct desktop* target, - char* sessions, - enum display_server server) -{ - DIR* dir; - struct dirent* dir_info; - int ok; - - ok = access(sessions, F_OK); - - if (ok == -1) - { - dgn_throw(DGN_XSESSIONS_DIR); - return; - } - - dir = opendir(sessions); - - if (dir == NULL) - { - dgn_throw(DGN_XSESSIONS_OPEN); - return; - } - - char* name = NULL; - char* exec = NULL; - - struct configator_param map_desktop[] = - { - {"Exec", &exec, config_handle_str}, - {"Name", &name, config_handle_str}, - }; - - struct configator_param* map[] = - { - NULL, - map_desktop, - }; - - struct configator_param sections[] = - { - {"Desktop Entry", NULL, NULL}, - }; - - uint16_t map_len[] = {0, 2}; - uint16_t sections_len = 1; - - struct configator desktop_config; - desktop_config.map = map; - desktop_config.map_len = map_len; - desktop_config.sections = sections; - desktop_config.sections_len = sections_len; - -#if defined(NAME_MAX) - char path[NAME_MAX]; -#elif defined(_POSIX_PATH_MAX) - char path[_POSIX_PATH_MAX]; -#else - char path[1024]; -#endif - - dir_info = readdir(dir); - - while (dir_info != NULL) - { - if ((dir_info->d_name)[0] == '.') - { - dir_info = readdir(dir); - continue; - } - - snprintf(path, (sizeof (path)) - 1, "%s/", sessions); - strncat(path, dir_info->d_name, (sizeof (path)) - 1); - configator(&desktop_config, path); - - // if these are wayland sessions, add " (Wayland)" to their names, - // as long as their names don't already contain that string - if (server == DS_WAYLAND && config.wayland_specifier) - { - const char wayland_specifier[] = " (Wayland)"; - if (strstr(name, wayland_specifier) == NULL) - { - name = realloc(name, (strlen(name) + sizeof(wayland_specifier) + 1)); - // using strcat is safe because the string is constant - strcat(name, wayland_specifier); - } - } - - if ((name != NULL) && (exec != NULL)) - { - input_desktop_add(target, name, exec, server); - } - - name = NULL; - exec = NULL; - dir_info = readdir(dir); - } - - closedir(dir); -} - -void desktop_load(struct desktop* target) -{ - // we don't care about desktop environments presence - // because the fallback shell is always available - // so we just dismiss any "throw" for now - int err = 0; - - desktop_crawl(target, config.waylandsessions, DS_WAYLAND); - - if (dgn_catch()) - { - ++err; - dgn_reset(); - } - - desktop_crawl(target, config.xsessions, DS_XORG); - - if (dgn_catch()) - { - ++err; - dgn_reset(); - } -} - static char* hostname_backup = NULL; void hostname(char** out) @@ -211,76 +75,4 @@ void switch_tty(struct term_buf* buf) ioctl(fd, VT_WAITACTIVE, config.tty); fclose(console); -} - -void save(struct desktop* desktop, struct text* login) -{ - if (config.save) - { - FILE* fp = fopen(config.save_file, "wb+"); - - if (fp != NULL) - { - fprintf(fp, "%s\n%d", login->text, desktop->cur); - fclose(fp); - } - } -} - -void load(struct desktop* desktop, struct text* login) -{ - if (!config.load) - { - return; - } - - FILE* fp = fopen(config.save_file, "rb"); - - if (fp == NULL) - { - return; - } - - char* line = malloc(config.max_login_len + 1); - - if (line == NULL) - { - fclose(fp); - return; - } - - if (fgets(line, config.max_login_len + 1, fp)) - { - int len = strlen(line); - strncpy(login->text, line, login->len); - - if (len == 0) - { - login->end = login->text; - } - else - { - login->end = login->text + len - 1; - login->text[len - 1] = '\0'; - } - } - else - { - fclose(fp); - free(line); - return; - } - - if (fgets(line, config.max_login_len + 1, fp)) - { - int saved_cur = abs(atoi(line)); - - if (saved_cur < desktop->len) - { - desktop->cur = saved_cur; - } - } - - fclose(fp); - free(line); } \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 0913580..c5b9028 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,7 +9,5 @@ void desktop_load(struct desktop* target); void hostname(char** out); void free_hostname(); void switch_tty(struct term_buf* buf); -void save(struct desktop* desktop, struct text* login); -void load(struct desktop* desktop, struct text* login); #endif diff --git a/src/utils.zig b/src/utils.zig new file mode 100644 index 0000000..8e62e49 --- /dev/null +++ b/src/utils.zig @@ -0,0 +1,114 @@ +const std = @import("std"); +const main = @import("main.zig"); +const ini = @import("ini.zig"); +const config = @import("config.zig"); +const interop = @import("interop.zig"); + +const DESKTOP_ENTRY_MAX_SIZE: usize = 8 * 1024; + +const Entry = struct { + Desktop_Entry: struct { + Name: []const u8, + Comment: []const u8, + Exec: []const u8, + Type: []const u8, + DesktopNames: []const u8, + }, +}; + +pub export fn desktop_load(target: *main.c.struct_desktop) void { + // We don't care about desktop environments presence + // because the fallback shell is always available + // so we just dismiss any "throw" for now + var err: c_int = 0; + + desktop_crawl(target, config.ly_config.ly.waylandsessions, main.c.DS_WAYLAND) catch {}; + + if (main.c.dgn_catch() != 0) { + err += 1; + main.c.dgn_reset(); + } + + desktop_crawl(target, config.ly_config.ly.xsessions, main.c.DS_XORG) catch {}; + + if (main.c.dgn_catch() != 0) { + err += 1; + main.c.dgn_reset(); + } +} + +pub fn save(desktop: *main.c.struct_desktop, login: *main.c.struct_text) !void { + if (!config.ly_config.ly.save) { + return; + } + + var file = std.fs.openFileAbsolute(config.ly_config.ly.save_file, .{ .mode = .write_only }) catch { + return; + }; + defer file.close(); + + var buffer = try std.fmt.allocPrint(main.allocator, "{s}\n{d}", .{ login.*.text, desktop.*.cur }); + defer main.allocator.free(buffer); + + try file.writeAll(buffer); +} + +pub fn load(desktop: *main.c.struct_desktop, login: *main.c.struct_text) !void { + if (!config.ly_config.ly.load) { + return; + } + + var file = std.fs.openFileAbsolute(config.ly_config.ly.save_file, .{}) catch { + return; + }; + defer file.close(); + + var buffer = try main.allocator.alloc(u8, config.ly_config.ly.max_login_len * 2 + 1); + defer main.allocator.free(buffer); + + _ = try file.readAll(buffer); + + var array = std.mem.splitSequence(u8, buffer, "\n"); + + login.*.text = try interop.c_str(array.first()); // TODO: Free? + desktop.*.cur = try std.fmt.parseUnsigned(u16, array.next().?, 0); +} + +fn desktop_crawl(target: *main.c.struct_desktop, sessions: []const u8, server: main.c.enum_display_server) !void { + var iterable_dir = std.fs.openIterableDirAbsolute(sessions, .{}) catch { + main.c.dgn_throw(main.c.DGN_XSESSIONS_OPEN); + return; + }; + defer iterable_dir.close(); + + var iterator = iterable_dir.iterate(); + + var dir = std.fs.openDirAbsolute(sessions, .{}) catch { + main.c.dgn_throw(main.c.DGN_XSESSIONS_OPEN); + return; + }; + defer dir.close(); + + while (try iterator.next()) |item| { + if (!std.mem.endsWith(u8, item.name, ".desktop")) { + continue; + } + + var file = try dir.openFile(item.name, .{}); + defer file.close(); + + var buffer = try main.allocator.alloc(u8, DESKTOP_ENTRY_MAX_SIZE); // TODO: Free + var length = try file.readAll(buffer); + var entry = try ini.readToStruct(Entry, buffer[0..length]); + + // TODO: If it's a wayland session, add " (Wayland)" to its name, + // as long as it doesn't already contain that string + + const name = entry.Desktop_Entry.Name; + const exec = entry.Desktop_Entry.Exec; + + if (name.len > 0 and exec.len > 0) { + main.c.input_desktop_add(target, (try interop.c_str(name)).ptr, (try interop.c_str(exec)).ptr, server); + } + } +}