Partially rewrite utils.c

This commit is contained in:
AnErrupTion 2023-06-21 15:20:44 +02:00
parent 2fd2f77ac0
commit 40c7c27b88
7 changed files with 396 additions and 490 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -19,142 +19,6 @@
#include <linux/vt.h>
#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);
}

View File

@ -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

114
src/utils.zig Normal file
View File

@ -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);
}
}
}