mirror of
https://github.com/javalsai/lidm.git
synced 2025-07-03 14:25:03 +02:00
feat: modernize config
- config now is more toml like
- no need to declare all fields, it implements defaults
- no yanderedev code, introspection babbyyy 😎
- desktop and config files parser semi-unification
- misc tweaks all over (mainly allocation failures handling)
This commit is contained in:
parent
3480393a66
commit
5174f0b2bf
@ -7,6 +7,6 @@
|
|||||||
#include "sessions.h"
|
#include "sessions.h"
|
||||||
|
|
||||||
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
||||||
struct behavior* behavior);
|
struct config* config);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
197
include/config.h
197
include/config.h
@ -2,77 +2,166 @@
|
|||||||
#define CONFIGH_
|
#define CONFIGH_
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
|
#include "macros.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
enum introspection_type {
|
||||||
|
STRING,
|
||||||
|
BOOL,
|
||||||
|
KEY,
|
||||||
|
STRING_ARRAY,
|
||||||
|
};
|
||||||
|
static const char* const intros_tys_names[] = {
|
||||||
|
[STRING] = "STRING",
|
||||||
|
[BOOL] = "BOOL",
|
||||||
|
[KEY] = "KEY",
|
||||||
|
[STRING_ARRAY] = "STRING_ARRAY",
|
||||||
|
};
|
||||||
|
|
||||||
|
union introspection_variant {
|
||||||
|
char* string;
|
||||||
|
bool boolean;
|
||||||
|
enum keys key;
|
||||||
|
char** string_array;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct introspection_item {
|
||||||
|
char* NNULLABLE name;
|
||||||
|
size_t offset;
|
||||||
|
enum introspection_type typ;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define INTROS_ITEM(key, table, ty) \
|
||||||
|
{ \
|
||||||
|
.name = #key, \
|
||||||
|
.offset = offsetof(table, key), \
|
||||||
|
.typ = (ty), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STRUCT_BUILDER(cty, name, ty, def, tname) cty name;
|
||||||
|
#define DEFAULT_BUILDER(cty, name, ty, def, tname) .name = (def),
|
||||||
|
#define INTROS_BUILDER(cty, name, ty, def, tname) \
|
||||||
|
INTROS_ITEM(name, struct table_##tname, ty),
|
||||||
|
|
||||||
|
#define BUILD_TABLE(table, TABLE) \
|
||||||
|
struct table_##table { \
|
||||||
|
TABLE(STRUCT_BUILDER, table) \
|
||||||
|
}
|
||||||
|
#define BUILD_DEFAULT(table, TABLE) \
|
||||||
|
static const struct table_##table default_table_##table = { \
|
||||||
|
TABLE(DEFAULT_BUILDER, table)}
|
||||||
|
#define BUILD_INTROS(table, TABLE) \
|
||||||
|
static const struct introspection_item intros_table_##table[] = { \
|
||||||
|
TABLE(INTROS_BUILDER, table)}
|
||||||
|
|
||||||
|
#define BUILD(table, TABLE) \
|
||||||
|
BUILD_TABLE(table, TABLE); \
|
||||||
|
BUILD_DEFAULT(table, TABLE); \
|
||||||
|
BUILD_INTROS(table, TABLE);
|
||||||
|
|
||||||
// should be ansi escape codes under \x1b[...m
|
// should be ansi escape codes under \x1b[...m
|
||||||
// if not prepared accordingly, it might break
|
// if not prepared accordingly, it might break
|
||||||
struct theme_colors {
|
#define TABLE_COLORS(F, name) \
|
||||||
char* bg;
|
F(char*, bg, STRING, "48;2;38;28;28", name) \
|
||||||
char* fg;
|
F(char*, fg, STRING, "22;24;38;2;245;245;245", name) \
|
||||||
char* err;
|
F(char*, err, STRING, "1;31", name) \
|
||||||
char* s_wayland;
|
F(char*, s_wayland, STRING, "38;2;255;174;66", name) \
|
||||||
char* s_xorg;
|
F(char*, s_xorg, STRING, "38;2;37;175;255", name) \
|
||||||
char* s_shell;
|
F(char*, s_shell, STRING, "38;2;34;140;34", name) \
|
||||||
char* e_hostname;
|
F(char*, e_hostname, STRING, "38;2;255;64;64", name) \
|
||||||
char* e_date;
|
F(char*, e_date, STRING, "38;2;144;144;144", name) \
|
||||||
char* e_box;
|
F(char*, e_box, STRING, "38;2;122;122;122", name) \
|
||||||
char* e_header;
|
F(char*, e_header, STRING, "4;38;2;0;255;0", name) \
|
||||||
char* e_user;
|
F(char*, e_user, STRING, "36", name) \
|
||||||
char* e_passwd;
|
F(char*, e_passwd, STRING, "4;38;2;245;245;205", name) \
|
||||||
char* e_badpasswd;
|
F(char*, e_badpasswd, STRING, "3;4;31", name) \
|
||||||
char* e_key;
|
F(char*, e_key, STRING, "38;2;255;174;66", name)
|
||||||
};
|
|
||||||
|
BUILD(colors, TABLE_COLORS);
|
||||||
|
|
||||||
// even if they're multiple bytes long
|
// even if they're multiple bytes long
|
||||||
// they should only take up 1 char size on display
|
// they should only take up 1 char size on display
|
||||||
struct theme_chars {
|
#define TABLE_CHARS(F, name) \
|
||||||
char* hb;
|
F(char*, hb, STRING, "─", name) \
|
||||||
char* vb;
|
F(char*, vb, STRING, "│", name) \
|
||||||
|
F(char*, ctl, STRING, "┌", name) \
|
||||||
|
F(char*, ctr, STRING, "┐", name) \
|
||||||
|
F(char*, cbl, STRING, "└", name) \
|
||||||
|
F(char*, cbr, STRING, "┘", name)
|
||||||
|
|
||||||
char* ctl;
|
BUILD(chars, TABLE_CHARS);
|
||||||
char* ctr;
|
|
||||||
char* cbl;
|
|
||||||
char* cbr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct theme {
|
#define TABLE_FUNCTIONS(F, name) \
|
||||||
struct theme_colors colors;
|
F(enum keys, poweroff, KEY, F1, name) \
|
||||||
struct theme_chars chars;
|
F(enum keys, reboot, KEY, F2, name) \
|
||||||
};
|
F(enum keys, refresh, KEY, F5, name)
|
||||||
|
|
||||||
struct functions {
|
BUILD(functions, TABLE_FUNCTIONS);
|
||||||
enum keys poweroff;
|
|
||||||
enum keys reboot;
|
|
||||||
enum keys refresh;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct strings {
|
#define TABLE_STRINGS(F, name) \
|
||||||
char* f_poweroff;
|
F(char*, f_poweroff, STRING, "poweroff", name) \
|
||||||
char* f_reboot;
|
F(char*, f_reboot, STRING, "reboot", name) \
|
||||||
char* f_refresh;
|
F(char*, f_refresh, STRING, "refresh", name) \
|
||||||
char* e_user;
|
F(char*, e_user, STRING, "user", name) \
|
||||||
char* e_passwd;
|
F(char*, e_passwd, STRING, "password", name) \
|
||||||
char* s_wayland;
|
F(char*, s_wayland, STRING, "wayland", name) \
|
||||||
char* s_xorg;
|
F(char*, s_xorg, STRING, "xorg", name) \
|
||||||
char* s_shell;
|
F(char*, s_shell, STRING, "shell", name)
|
||||||
};
|
|
||||||
|
|
||||||
struct behavior {
|
BUILD(strings, TABLE_STRINGS);
|
||||||
bool include_defshell;
|
|
||||||
struct Vector source;
|
|
||||||
struct Vector user_source;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
#define NULL_VEC \
|
||||||
|
(struct Vector) { \
|
||||||
|
0, 0, NULL \
|
||||||
|
}
|
||||||
|
#define TABLE_BEHAVIOR(F, name) \
|
||||||
|
F(bool, include_defshell, BOOL, true, name) \
|
||||||
|
F(struct Vector, source, STRING_ARRAY, NULL_VEC, name) \
|
||||||
|
F(struct Vector, user_source, STRING_ARRAY, NULL_VEC, name)
|
||||||
|
|
||||||
|
BUILD(behavior, TABLE_BEHAVIOR);
|
||||||
|
|
||||||
|
//// CONFIG
|
||||||
struct config {
|
struct config {
|
||||||
struct theme theme;
|
struct table_colors colors;
|
||||||
struct functions functions;
|
struct table_chars chars;
|
||||||
struct strings strings;
|
struct table_functions functions;
|
||||||
struct behavior behavior;
|
struct table_strings strings;
|
||||||
|
struct table_behavior behavior;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config* parse_config(char* path);
|
static const struct config default_config = {
|
||||||
|
.colors = default_table_colors,
|
||||||
|
.chars = default_table_chars,
|
||||||
|
.functions = default_table_functions,
|
||||||
|
.strings = default_table_strings,
|
||||||
|
.behavior = default_table_behavior,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct introspection_table {
|
||||||
|
char* NNULLABLE tname;
|
||||||
|
size_t offset;
|
||||||
|
const struct introspection_item* NNULLABLE intros;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct introspection_table config_instrospection[] = {
|
||||||
|
{"colors", offsetof(struct config, colors), intros_table_colors,
|
||||||
|
sizeof(intros_table_colors) / sizeof(intros_table_colors[0])},
|
||||||
|
{"chars", offsetof(struct config, chars), intros_table_chars,
|
||||||
|
sizeof(intros_table_chars) / sizeof(intros_table_chars[0])},
|
||||||
|
{"functions", offsetof(struct config, functions), intros_table_functions,
|
||||||
|
sizeof(intros_table_functions) / sizeof(intros_table_functions[0])},
|
||||||
|
{"strings", offsetof(struct config, strings), intros_table_strings,
|
||||||
|
sizeof(intros_table_strings) / sizeof(intros_table_strings[0])},
|
||||||
|
{"behavior", offsetof(struct config, behavior), intros_table_behavior,
|
||||||
|
sizeof(intros_table_behavior) / sizeof(intros_table_behavior[0])},
|
||||||
|
};
|
||||||
|
|
||||||
|
//// FUNCTIONS
|
||||||
|
int parse_config(struct config* NNULLABLE config, char* NNULLABLE path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,4 +20,6 @@
|
|||||||
#define UNULLABLE
|
#define UNULLABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LEN(X) (sizeof(X) / sizeof((X)[0]))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
void setup(struct config);
|
void setup(struct config* config);
|
||||||
int load(struct Vector* users, struct Vector* sessions);
|
int load(struct Vector* users, struct Vector* sessions);
|
||||||
void print_err(const char*);
|
void print_err(const char*);
|
||||||
void print_errno(const char*);
|
void print_errno(const char*);
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
#define UTILH_
|
#define UTILH_
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
|
|
||||||
enum keys find_keyname(char*);
|
int find_keyname(enum keys* at, char* name);
|
||||||
enum keys find_ansi(char*);
|
enum keys find_ansi(char*);
|
||||||
void read_press(u_char*, char*);
|
void read_press(u_char*, char*);
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ struct Vector {
|
|||||||
void** pages;
|
void** pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vector vec_new();
|
extern const struct Vector VEC_NEW;
|
||||||
int vec_resize(struct Vector*, size_t size);
|
int vec_resize(struct Vector*, size_t size);
|
||||||
int vec_reserve(struct Vector*, size_t size);
|
int vec_reserve(struct Vector*, size_t size);
|
||||||
int vec_reserve_exact(struct Vector*, size_t size);
|
int vec_reserve_exact(struct Vector*, size_t size);
|
||||||
|
14
src/auth.c
14
src/auth.c
@ -94,7 +94,7 @@ void sourceFileTry(char* file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void moarEnv(char* user, struct session session, struct passwd* pw,
|
void moarEnv(char* user, struct session session, struct passwd* pw,
|
||||||
struct behavior* behavior) {
|
struct config* config) {
|
||||||
if (chdir(pw->pw_dir) == -1) print_errno("can't chdir to user home");
|
if (chdir(pw->pw_dir) == -1) print_errno("can't chdir to user home");
|
||||||
|
|
||||||
setenv("HOME", pw->pw_dir, true);
|
setenv("HOME", pw->pw_dir, true);
|
||||||
@ -113,16 +113,16 @@ void moarEnv(char* user, struct session session, struct passwd* pw,
|
|||||||
setenv("XDG_SESSION_TYPE", xdg_session_type, true);
|
setenv("XDG_SESSION_TYPE", xdg_session_type, true);
|
||||||
|
|
||||||
printf("\n\n\n\n\x1b[1m");
|
printf("\n\n\n\n\x1b[1m");
|
||||||
for (size_t i = 0; i < behavior->source.length; i++) {
|
for (size_t i = 0; i < config->behavior.source.length; i++) {
|
||||||
/* printf("DEBUG(source)!!!! %d %s\n", i, (char*)vec_get(&behavior->source,
|
/* printf("DEBUG(source)!!!! %d %s\n", i, (char*)vec_get(&behavior->source,
|
||||||
* i)); */
|
* i)); */
|
||||||
sourceFileTry((char*)vec_get(&behavior->source, i));
|
sourceFileTry((char*)vec_get(&config->behavior.source, i));
|
||||||
}
|
}
|
||||||
/* printf("\n"); */
|
/* printf("\n"); */
|
||||||
if (pw->pw_dir) {
|
if (pw->pw_dir) {
|
||||||
uint home_len = strlen(pw->pw_dir);
|
uint home_len = strlen(pw->pw_dir);
|
||||||
for (size_t i = 0; i < behavior->user_source.length; i++) {
|
for (size_t i = 0; i < config->behavior.user_source.length; i++) {
|
||||||
char* file2sourcepath = (char*)vec_get(&behavior->user_source, i);
|
char* file2sourcepath = (char*)vec_get(&config->behavior.user_source, i);
|
||||||
size_t newbuf_len = home_len + strlen(file2sourcepath) + 2;
|
size_t newbuf_len = home_len + strlen(file2sourcepath) + 2;
|
||||||
char* newbuf = malloc(newbuf_len); // nullbyte and slash
|
char* newbuf = malloc(newbuf_len); // nullbyte and slash
|
||||||
if (newbuf == NULL) continue; // can't bother
|
if (newbuf == NULL) continue; // can't bother
|
||||||
@ -150,7 +150,7 @@ void moarEnv(char* user, struct session session, struct passwd* pw,
|
|||||||
|
|
||||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||||
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
||||||
struct behavior* behavior) {
|
struct config* config) {
|
||||||
struct passwd* pw = getpwnam(user);
|
struct passwd* pw = getpwnam(user);
|
||||||
if (pw == NULL) {
|
if (pw == NULL) {
|
||||||
print_err("could not get user info");
|
print_err("could not get user info");
|
||||||
@ -197,7 +197,7 @@ bool launch(char* user, char* passwd, struct session session, void (*cb)(void),
|
|||||||
}
|
}
|
||||||
|
|
||||||
free((void*)envlist);
|
free((void*)envlist);
|
||||||
moarEnv(user, session, pw, behavior);
|
moarEnv(user, session, pw, config);
|
||||||
|
|
||||||
// TODO: chown stdin to user
|
// TODO: chown stdin to user
|
||||||
// does it inherit stdin from parent and
|
// does it inherit stdin from parent and
|
||||||
|
353
src/config.c
353
src/config.c
@ -1,155 +1,221 @@
|
|||||||
#include <errno.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "desktop.h"
|
||||||
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
// Alr so ima explain the bitfield returned by `cb` a bit
|
// NOLINTNEXTLINE(modernize-macro-to-enum)
|
||||||
// 4 bits:
|
#define UPPER_HALF_BYTE 4
|
||||||
// 0b0001: break out of parsing (returning true)
|
int parse_hex(char* _at, char x1, char x2) {
|
||||||
// 0b0010: free the value
|
// make linter happy
|
||||||
// 0b0100: free the key
|
u_char* at = (u_char*)_at;
|
||||||
// 0b1000: break out of parsing (returning false)
|
|
||||||
//
|
|
||||||
// This would return true if everything goes fine, false otherwise (malloc
|
|
||||||
// error, broke parsing, etc)
|
|
||||||
// NOLINTBEGIN(modernize-macro-to-enum)
|
|
||||||
#define LN_BREAK_OK 0b0001
|
|
||||||
#define LN_FREE_VALUE 0b0010
|
|
||||||
#define LN_FREE_KEY 0b0100
|
|
||||||
#define LN_FREE_KV (LN_FREE_KEY | LN_FREE_VALUE)
|
|
||||||
#define LN_BREAK_ERR 0b1000
|
|
||||||
// NOLINTEND(modernize-macro-to-enum)
|
|
||||||
bool line_parser(FILE* fd, u_char (*cb)(char* key, char* value)) {
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
char* buf = NULL;
|
*at = 0;
|
||||||
size_t alloc_size = 0;
|
|
||||||
size_t read_size;
|
if ('0' <= x1 && x1 <= '9') {
|
||||||
while ((read_size = getline(&buf, &alloc_size, fd)) != -1) {
|
*at += (x1 - '0') << UPPER_HALF_BYTE;
|
||||||
ok = true;
|
} else if ('A' <= x1 && x1 <= 'F') {
|
||||||
char* key = malloc(read_size);
|
*at += (x1 - 'A' + 10) << UPPER_HALF_BYTE;
|
||||||
if (key == NULL) {
|
} else if ('a' <= x1 && x1 <= 'f') {
|
||||||
ok = false;
|
*at += (x1 - 'a' + 10) << UPPER_HALF_BYTE;
|
||||||
break;
|
|
||||||
}
|
|
||||||
char* value = malloc(read_size);
|
|
||||||
if (value == NULL) {
|
|
||||||
free(key);
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
|
||||||
if (sscanf(buf, "%[^ ] = %[^\n]\n", key, value) == 2) {
|
|
||||||
u_char ret = cb(key, value);
|
|
||||||
if (ret & LN_FREE_KEY) free(key);
|
|
||||||
if (ret & LN_FREE_VALUE) free(value);
|
|
||||||
if (ret & LN_BREAK_ERR) {
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ret & LN_BREAK_OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
free(key);
|
return -1;
|
||||||
free(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf != NULL) free(buf);
|
if ('0' <= x2 && x2 <= '9') {
|
||||||
return ok;
|
*at += (x2 - '0');
|
||||||
|
} else if ('A' <= x2 && x2 <= 'F') {
|
||||||
|
*at += (x2 - 'A' + 10);
|
||||||
|
} else if ('a' <= x2 && x2 <= 'f') {
|
||||||
|
*at += (x2 - 'a' + 10);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct config* g_config;
|
struct parser_error {
|
||||||
// Yanderedev code (wanna fix this with a table or smth)
|
const char* NULLABLE msg;
|
||||||
// NOLINTNEXTLINE(readability-identifier-length,readability-function-cognitive-complexity)
|
size_t col;
|
||||||
u_char config_line_handler(char* k, char* v) {
|
};
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
|
||||||
if (strcmp(k, "colors.bg") == 0)
|
|
||||||
g_config->theme.colors.bg = v;
|
|
||||||
else if (strcmp(k, "colors.fg") == 0)
|
|
||||||
g_config->theme.colors.fg = v;
|
|
||||||
else if (strcmp(k, "colors.err") == 0)
|
|
||||||
g_config->theme.colors.err = v;
|
|
||||||
else if (strcmp(k, "colors.s_wayland") == 0)
|
|
||||||
g_config->theme.colors.s_wayland = v;
|
|
||||||
else if (strcmp(k, "colors.s_xorg") == 0)
|
|
||||||
g_config->theme.colors.s_xorg = v;
|
|
||||||
else if (strcmp(k, "colors.s_shell") == 0)
|
|
||||||
g_config->theme.colors.s_shell = v;
|
|
||||||
else if (strcmp(k, "colors.e_hostname") == 0)
|
|
||||||
g_config->theme.colors.e_hostname = v;
|
|
||||||
else if (strcmp(k, "colors.e_date") == 0)
|
|
||||||
g_config->theme.colors.e_date = v;
|
|
||||||
else if (strcmp(k, "colors.e_box") == 0)
|
|
||||||
g_config->theme.colors.e_box = v;
|
|
||||||
else if (strcmp(k, "colors.e_header") == 0)
|
|
||||||
g_config->theme.colors.e_header = v;
|
|
||||||
else if (strcmp(k, "colors.e_user") == 0)
|
|
||||||
g_config->theme.colors.e_user = v;
|
|
||||||
else if (strcmp(k, "colors.e_passwd") == 0)
|
|
||||||
g_config->theme.colors.e_passwd = v;
|
|
||||||
else if (strcmp(k, "colors.e_badpasswd") == 0)
|
|
||||||
g_config->theme.colors.e_badpasswd = v;
|
|
||||||
else if (strcmp(k, "colors.e_key") == 0)
|
|
||||||
g_config->theme.colors.e_key = v;
|
|
||||||
else if (strcmp(k, "chars.hb") == 0)
|
|
||||||
g_config->theme.chars.hb = v;
|
|
||||||
else if (strcmp(k, "chars.vb") == 0)
|
|
||||||
g_config->theme.chars.vb = v;
|
|
||||||
else if (strcmp(k, "chars.ctl") == 0)
|
|
||||||
g_config->theme.chars.ctl = v;
|
|
||||||
else if (strcmp(k, "chars.ctr") == 0)
|
|
||||||
g_config->theme.chars.ctr = v;
|
|
||||||
else if (strcmp(k, "chars.cbl") == 0)
|
|
||||||
g_config->theme.chars.cbl = v;
|
|
||||||
else if (strcmp(k, "chars.cbr") == 0)
|
|
||||||
g_config->theme.chars.cbr = v;
|
|
||||||
else if (strcmp(k, "functions.poweroff") == 0) {
|
|
||||||
g_config->functions.poweroff = find_keyname(v);
|
|
||||||
return LN_FREE_KV;
|
|
||||||
} else if (strcmp(k, "functions.reboot") == 0) {
|
|
||||||
g_config->functions.reboot = find_keyname(v);
|
|
||||||
return LN_FREE_KV;
|
|
||||||
} else if (strcmp(k, "functions.refresh") == 0) {
|
|
||||||
g_config->functions.refresh = find_keyname(v);
|
|
||||||
return LN_FREE_KV;
|
|
||||||
} else if (strcmp(k, "strings.f_poweroff") == 0)
|
|
||||||
g_config->strings.f_poweroff = v;
|
|
||||||
else if (strcmp(k, "strings.f_reboot") == 0)
|
|
||||||
g_config->strings.f_reboot = v;
|
|
||||||
else if (strcmp(k, "strings.f_refresh") == 0)
|
|
||||||
g_config->strings.f_refresh = v;
|
|
||||||
else if (strcmp(k, "strings.e_user") == 0)
|
|
||||||
g_config->strings.e_user = v;
|
|
||||||
else if (strcmp(k, "strings.e_passwd") == 0)
|
|
||||||
g_config->strings.e_passwd = v;
|
|
||||||
else if (strcmp(k, "strings.s_wayland") == 0)
|
|
||||||
g_config->strings.s_wayland = v;
|
|
||||||
else if (strcmp(k, "strings.s_xorg") == 0)
|
|
||||||
g_config->strings.s_xorg = v;
|
|
||||||
else if (strcmp(k, "strings.s_shell") == 0)
|
|
||||||
g_config->strings.s_shell = v;
|
|
||||||
else if (strcmp(k, "behavior.include_defshell") == 0) {
|
|
||||||
g_config->behavior.include_defshell = strcmp(v, "true") == 0;
|
|
||||||
return LN_FREE_KV;
|
|
||||||
} else if (strcmp(k, "behavior.source") == 0)
|
|
||||||
vec_push(&g_config->behavior.source, v);
|
|
||||||
else if (strcmp(k, "behavior.user_source") == 0)
|
|
||||||
vec_push(&g_config->behavior.user_source, v);
|
|
||||||
else
|
|
||||||
return LN_BREAK_ERR | LN_FREE_KV;
|
|
||||||
|
|
||||||
return LN_FREE_KEY;
|
#define FAIL(str) \
|
||||||
|
return (struct parser_error) { \
|
||||||
|
str, p - raw \
|
||||||
|
}
|
||||||
|
#define NOFAIL return (struct parser_error){NULL, 0}
|
||||||
|
struct parser_error parse_str_inplace(char* raw) {
|
||||||
|
// reader pointer
|
||||||
|
char* p = raw; // NOLINT(readability-identifier-length)
|
||||||
|
if (*p != '"') FAIL("Strign not quoted");
|
||||||
|
p++;
|
||||||
|
|
||||||
|
// writer iterator, by nature will always be under the reader
|
||||||
|
size_t i = 0; // NOLINT(readability-identifier-length)
|
||||||
|
while (*p != '\0') {
|
||||||
|
if (*p == '"') {
|
||||||
|
if (p[1] == '\0') {
|
||||||
|
raw[i] = '\0';
|
||||||
|
NOFAIL;
|
||||||
|
}
|
||||||
|
FAIL("String finished but theres content after");
|
||||||
|
}
|
||||||
|
if (*p == '\\') {
|
||||||
|
p++;
|
||||||
|
if (*p == '\0') break;
|
||||||
|
switch (*p) {
|
||||||
|
case '\\':
|
||||||
|
raw[i++] = '\\';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
raw[i++] = '\t';
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
raw[i++] = '\n';
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
raw[i++] = '\"';
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
raw[i++] = '\'';
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
if (p[1] == '\0' || p[2] == '\0') goto unfinished;
|
||||||
|
if (parse_hex(&raw[i++], p[1], p[2]) != 0)
|
||||||
|
FAIL("Invalid hex escape sequence");
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FAIL("Invalid escape variant");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
raw[i++] = *p;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unfinished:
|
||||||
|
FAIL("Unfinished string");
|
||||||
}
|
}
|
||||||
|
#undef FAIL
|
||||||
|
#undef NOFAIL
|
||||||
|
|
||||||
struct config* parse_config(char* path) {
|
#define FAIL(str) return (struct parser_error){str, 0}
|
||||||
// struct stat sb;
|
#define NOFAIL return (struct parser_error){NULL, 0}
|
||||||
errno = 0;
|
union typ_ptr {
|
||||||
|
char** string;
|
||||||
|
bool* boolean;
|
||||||
|
enum keys* key;
|
||||||
|
struct Vector* vec;
|
||||||
|
uintptr_t ptr;
|
||||||
|
};
|
||||||
|
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||||
|
struct parser_error parse_key(enum introspection_type typ, union typ_ptr at,
|
||||||
|
char* key, size_t offset) {
|
||||||
|
char* aux_str = NULL;
|
||||||
|
struct parser_error aux_err;
|
||||||
|
|
||||||
|
switch (typ) {
|
||||||
|
case STRING:
|
||||||
|
aux_str = strdup(key);
|
||||||
|
if (!aux_str) FAIL("allocation failure");
|
||||||
|
aux_err = parse_str_inplace(aux_str);
|
||||||
|
if (aux_err.msg != NULL) return aux_err;
|
||||||
|
// FIXME: it be broken, prob the ptr arithmetic or smth, we mem leak instead 😎
|
||||||
|
// If the ptr is not the default it means it was prev allocated, we should
|
||||||
|
// free
|
||||||
|
// if (*(char**)((uintptr_t)(&default_config) + offset) != *at.string) {
|
||||||
|
// free(*at.string);
|
||||||
|
// }
|
||||||
|
*at.string = aux_str;
|
||||||
|
break;
|
||||||
|
case BOOL:
|
||||||
|
if (strcmp(key, "true") == 0)
|
||||||
|
*at.boolean = true;
|
||||||
|
else if (strcmp(key, "false") == 0)
|
||||||
|
*at.boolean = false;
|
||||||
|
else {
|
||||||
|
FAIL("Invalid key value, wasn't 'true' nor 'false'");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY:
|
||||||
|
// NOLINTNEXTLINE(performance-no-int-to-ptr)
|
||||||
|
if (find_keyname(at.key, key) != 0) {
|
||||||
|
FAIL("Keyboard KEY name not found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STRING_ARRAY:
|
||||||
|
aux_str = strdup(key);
|
||||||
|
if (!aux_str) FAIL("allocation failure");
|
||||||
|
aux_err = parse_str_inplace(aux_str);
|
||||||
|
if (aux_err.msg != NULL) return aux_err;
|
||||||
|
vec_push(at.vec, aux_str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NOFAIL;
|
||||||
|
}
|
||||||
|
#undef FAIL
|
||||||
|
#undef NOFAIL
|
||||||
|
|
||||||
|
// NOLINTBEGIN(readability-identifier-length,readability-function-cognitive-complexity,readability-identifier-length)
|
||||||
|
struct status config_line_handler(void* _config, char* table, char* k,
|
||||||
|
char* v) {
|
||||||
|
struct config* config = (struct config*)_config;
|
||||||
|
struct status ret = {.finish = false};
|
||||||
|
|
||||||
|
const struct introspection_table* this_intros_table = NULL;
|
||||||
|
for (size_t i = 0; i < LEN(config_instrospection); i++) {
|
||||||
|
if (table == NULL) {
|
||||||
|
if (table != config_instrospection[i].tname) continue;
|
||||||
|
} else if (strcmp(config_instrospection[i].tname, table) != 0)
|
||||||
|
continue;
|
||||||
|
this_intros_table = &config_instrospection[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this_intros_table == NULL) {
|
||||||
|
log_printf("[E] table '%s' is not part of the config\n", table);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct introspection_item* this_intros_key = NULL;
|
||||||
|
for (size_t i = 0; i < this_intros_table->len; i++) {
|
||||||
|
if (strcmp(this_intros_table->intros[i].name, k) != 0) continue;
|
||||||
|
this_intros_key = &this_intros_table->intros[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this_intros_key == NULL) {
|
||||||
|
log_printf("[E] key '%s' is not part of the table '%s' in config\n", k,
|
||||||
|
table);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = this_intros_table->offset + this_intros_key->offset;
|
||||||
|
union typ_ptr k_addr = {.ptr = (uintptr_t)config + offset};
|
||||||
|
|
||||||
|
struct parser_error err = parse_key(this_intros_key->typ, k_addr, v, offset);
|
||||||
|
if (err.msg != NULL) {
|
||||||
|
log_printf("[E] cfg parser, failed to parse [%s.%s] (%s): %s\n", table, k,
|
||||||
|
intros_tys_names[this_intros_key->typ], err.msg);
|
||||||
|
log_printf("%s\n%*c^\n", v, err.col);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_printf("[I] cfg parsed [%s.%s]\n", table, k);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// NOLINTEND(readability-identifier-length,readability-function-cognitive-complexity,readability-identifier-length)
|
||||||
|
|
||||||
|
int parse_config(struct config* NNULLABLE config, char* NNULLABLE path) {
|
||||||
FILE* fd = fopen(path, "r");
|
FILE* fd = fopen(path, "r");
|
||||||
if (fd == NULL) {
|
if (fd == NULL) {
|
||||||
perror("fopen");
|
perror("fopen");
|
||||||
@ -157,23 +223,14 @@ struct config* parse_config(char* path) {
|
|||||||
"Please place a config file at /etc/lidm.ini or set the LIDM_CONF "
|
"Please place a config file at /etc/lidm.ini or set the LIDM_CONF "
|
||||||
"env variable",
|
"env variable",
|
||||||
stderr);
|
stderr);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
// if(stat(path, &sb) != 0) {
|
|
||||||
// perror("stat");
|
|
||||||
// }
|
|
||||||
|
|
||||||
g_config = malloc(sizeof(struct config));
|
bool ret = read_desktop(fd, config, config_line_handler);
|
||||||
g_config->behavior.source = vec_new();
|
|
||||||
g_config->behavior.user_source = vec_new();
|
|
||||||
|
|
||||||
if (g_config == NULL) return NULL;
|
|
||||||
bool ret = line_parser(fd, config_line_handler);
|
|
||||||
(void)fclose(fd);
|
(void)fclose(fd);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
free(g_config);
|
return -1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_config;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,20 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
#include "macros.h"
|
|
||||||
|
char* trim_str(char* str) {
|
||||||
|
while (*str == ' ' || *str == '\t')
|
||||||
|
str++;
|
||||||
|
|
||||||
|
size_t i = strlen(str);
|
||||||
|
while (i > 0) {
|
||||||
|
if (str[i - 1] != ' ' && str[i - 1] != '\t' && str[i - 1] != '\n') break;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
str[i] = '\0';
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
int read_desktop(FILE* fd, void* ctx,
|
int read_desktop(FILE* fd, void* ctx,
|
||||||
struct status (*cb)(void* ctx, char* table, char* key,
|
struct status (*cb)(void* ctx, char* table, char* key,
|
||||||
@ -19,34 +32,42 @@ int read_desktop(FILE* fd, void* ctx,
|
|||||||
while ((read_size = getline(&buf, &alloc_size, fd)) > 0) {
|
while ((read_size = getline(&buf, &alloc_size, fd)) > 0) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
if (read_size <= 1) continue;
|
char* buf_start = trim_str(buf);
|
||||||
|
size_t indent_size = buf_start - buf;
|
||||||
|
|
||||||
if (buf[0] == '[' && buf[read_size - 2] == ']') {
|
if (read_size - indent_size < 1) continue;
|
||||||
|
if (*buf_start == '#') continue;
|
||||||
|
|
||||||
|
if (*buf_start == '[' && buf_start[strlen(buf_start) - 1] == ']') {
|
||||||
if (table_name != NULL) free(table_name);
|
if (table_name != NULL) free(table_name);
|
||||||
table_name = realloc(buf, read_size);
|
buf_start[strlen(buf_start) - 1] = '\0';
|
||||||
table_name[read_size - 1] = '\0'; // newline
|
table_name = strdup(buf_start + 1);
|
||||||
buf = NULL;
|
if (table_name == NULL) {
|
||||||
alloc_size = 0;
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Find '='
|
// Find '='
|
||||||
size_t eq_idx = 0;
|
size_t eq_idx = 0;
|
||||||
while (buf[eq_idx] != '\0') {
|
while (buf_start[eq_idx] != '\0') {
|
||||||
if (buf[eq_idx] == '=') break;
|
if (buf_start[eq_idx] == '=') break;
|
||||||
eq_idx++;
|
eq_idx++;
|
||||||
}
|
}
|
||||||
// impossible with a min len of 1 (empty line)
|
// impossible with a min len of 1 (empty line)
|
||||||
if (eq_idx == 0) continue;
|
if (eq_idx == 0) continue;
|
||||||
// Check its not end
|
// Check its not end
|
||||||
if (buf[eq_idx] != '=') {
|
if (buf_start[eq_idx] != '=') {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key & Value
|
// Key & Value
|
||||||
char* key = buf;
|
char* key = buf_start;
|
||||||
buf[eq_idx] = '\0'; // the equal
|
buf_start[eq_idx] = '\0'; // the equal
|
||||||
char* value = &buf[eq_idx + 1];
|
key = trim_str(key);
|
||||||
buf[read_size - 1] = '\0'; // the newline
|
char* value = &buf_start[eq_idx + 1];
|
||||||
|
buf_start[read_size - 1] = '\0'; // the newline
|
||||||
|
value = trim_str(value);
|
||||||
|
|
||||||
// Callback
|
// Callback
|
||||||
struct status cb_ret = cb(ctx, table_name, key, value);
|
struct status cb_ret = cb(ctx, table_name, key, value);
|
||||||
|
11
src/main.c
11
src/main.c
@ -14,6 +14,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
// Logger
|
||||||
char* log_output = getenv("LIDM_LOG");
|
char* log_output = getenv("LIDM_LOG");
|
||||||
if (log_output) {
|
if (log_output) {
|
||||||
FILE* log_fd = fopen(log_output, "w");
|
FILE* log_fd = fopen(log_output, "w");
|
||||||
@ -26,17 +27,17 @@ int main(int argc, char* argv[]) {
|
|||||||
log_init(log_fd);
|
log_init(log_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chvt
|
||||||
if (argc == 2) chvt_str(argv[1]);
|
if (argc == 2) chvt_str(argv[1]);
|
||||||
|
|
||||||
|
struct config config = default_config;
|
||||||
char* conf_override = getenv("LIDM_CONF");
|
char* conf_override = getenv("LIDM_CONF");
|
||||||
struct config* config =
|
char* conf_path = conf_override ? conf_override : "/etc/lidm.ini";
|
||||||
parse_config(conf_override == NULL ? "/etc/lidm.ini" : conf_override);
|
if (parse_config(&config, conf_path) != 0) {
|
||||||
if (config == NULL) {
|
|
||||||
// NOLINT(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
|
||||||
(void)fputs("error parsing config\n", stderr);
|
(void)fputs("error parsing config\n", stderr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
setup(*config);
|
setup(&config);
|
||||||
|
|
||||||
struct Vector users = get_human_users();
|
struct Vector users = get_human_users();
|
||||||
struct Vector sessions = get_avaliable_sessions();
|
struct Vector sessions = get_avaliable_sessions();
|
||||||
|
@ -35,7 +35,7 @@ struct status cb(void* _ctx, char* NULLABLE table, char* key, char* value) {
|
|||||||
ret.finish = false;
|
ret.finish = false;
|
||||||
|
|
||||||
if (table == NULL) return ret;
|
if (table == NULL) return ret;
|
||||||
if (strcmp(table, "[Desktop Entry]") != 0) return ret;
|
if (strcmp(table, "Desktop Entry") != 0) return ret;
|
||||||
|
|
||||||
char** NULLABLE copy_at = NULL;
|
char** NULLABLE copy_at = NULL;
|
||||||
if (strcmp(key, "Name") == 0) {
|
if (strcmp(key, "Name") == 0) {
|
||||||
@ -117,7 +117,7 @@ static int fn(const char* fpath, const struct stat* sb, int typeflag) {
|
|||||||
// This code is designed to be run purely single threaded
|
// This code is designed to be run purely single threaded
|
||||||
#define LIKELY_BOUND_SESSIONS 8
|
#define LIKELY_BOUND_SESSIONS 8
|
||||||
struct Vector get_avaliable_sessions() {
|
struct Vector get_avaliable_sessions() {
|
||||||
struct Vector sessions = vec_new();
|
struct Vector sessions = VEC_NEW;
|
||||||
vec_reserve(&sessions, LIKELY_BOUND_SESSIONS);
|
vec_reserve(&sessions, LIKELY_BOUND_SESSIONS);
|
||||||
|
|
||||||
cb_sessions = &sessions;
|
cb_sessions = &sessions;
|
||||||
|
113
src/ui.c
113
src/ui.c
@ -49,11 +49,9 @@ static struct termios orig_term;
|
|||||||
static struct termios term;
|
static struct termios term;
|
||||||
static struct winsize window;
|
static struct winsize window;
|
||||||
|
|
||||||
static struct theme theme;
|
struct config* g_config = NULL;
|
||||||
static struct functions functions;
|
void setup(struct config* config) {
|
||||||
static struct strings strings;
|
g_config = config;
|
||||||
static struct behavior behavior;
|
|
||||||
void setup(struct config __config) {
|
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &window);
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &window);
|
||||||
|
|
||||||
// 2 padding top and bottom for footer and vertical compensation
|
// 2 padding top and bottom for footer and vertical compensation
|
||||||
@ -63,11 +61,6 @@ void setup(struct config __config) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
theme = __config.theme;
|
|
||||||
functions = __config.functions;
|
|
||||||
strings = __config.strings;
|
|
||||||
behavior = __config.behavior;
|
|
||||||
|
|
||||||
tcgetattr(STDOUT_FILENO, &orig_term);
|
tcgetattr(STDOUT_FILENO, &orig_term);
|
||||||
term = orig_term; // save term
|
term = orig_term; // save term
|
||||||
// "stty" attrs
|
// "stty" attrs
|
||||||
@ -76,7 +69,8 @@ void setup(struct config __config) {
|
|||||||
|
|
||||||
// save cursor pos, save screen, set color and reset screen
|
// save cursor pos, save screen, set color and reset screen
|
||||||
// (applying color to all screen)
|
// (applying color to all screen)
|
||||||
printf("\x1b[s\x1b[?47h\x1b[%s;%sm\x1b[2J", theme.colors.bg, theme.colors.fg);
|
printf("\x1b[s\x1b[?47h\x1b[%s;%sm\x1b[2J", g_config->colors.bg,
|
||||||
|
g_config->colors.fg);
|
||||||
|
|
||||||
print_footer();
|
print_footer();
|
||||||
atexit(restore_all);
|
atexit(restore_all);
|
||||||
@ -227,7 +221,7 @@ struct session get_current_session() {
|
|||||||
if (of_session.current_opt != 0) {
|
if (of_session.current_opt != 0) {
|
||||||
// this is for the default user shell :P, not the greatest
|
// this is for the default user shell :P, not the greatest
|
||||||
// implementation but I want to get his done
|
// implementation but I want to get his done
|
||||||
if (behavior.include_defshell &&
|
if (g_config->behavior.include_defshell &&
|
||||||
of_session.current_opt == gsessions->length + 1) {
|
of_session.current_opt == gsessions->length + 1) {
|
||||||
struct session shell_session;
|
struct session shell_session;
|
||||||
shell_session.type = SHELL;
|
shell_session.type = SHELL;
|
||||||
@ -333,7 +327,8 @@ int load(struct Vector* users, struct Vector* sessions) {
|
|||||||
hostname[15] = '\0';
|
hostname[15] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
of_session = ofield_new(sessions->length + behavior.include_defshell);
|
of_session =
|
||||||
|
ofield_new(sessions->length + g_config->behavior.include_defshell);
|
||||||
of_user = ofield_new(users->length);
|
of_user = ofield_new(users->length);
|
||||||
of_passwd = ofield_new(0);
|
of_passwd = ofield_new(0);
|
||||||
|
|
||||||
@ -345,15 +340,15 @@ int load(struct Vector* users, struct Vector* sessions) {
|
|||||||
|
|
||||||
// put hostname
|
// put hostname
|
||||||
printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", boxstart.y + 2,
|
printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", boxstart.y + 2,
|
||||||
boxstart.x + 12 - (uint)strlen(hostname), theme.colors.e_hostname,
|
boxstart.x + 12 - (uint)strlen(hostname), g_config->colors.e_hostname,
|
||||||
hostname, theme.colors.fg);
|
hostname, g_config->colors.fg);
|
||||||
if (hostname != unknown_str) free(hostname);
|
if (hostname != unknown_str) free(hostname);
|
||||||
|
|
||||||
// put date
|
// put date
|
||||||
char* fmtd_time = fmt_time();
|
char* fmtd_time = fmt_time();
|
||||||
printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", boxstart.y + 2,
|
printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", boxstart.y + 2,
|
||||||
boxstart.x + boxw - 3 - (uint)strlen(fmtd_time), theme.colors.e_date,
|
boxstart.x + boxw - 3 - (uint)strlen(fmtd_time),
|
||||||
fmtd_time, theme.colors.fg);
|
g_config->colors.e_date, fmtd_time, g_config->colors.fg);
|
||||||
free(fmtd_time);
|
free(fmtd_time);
|
||||||
|
|
||||||
print_field(SESSION);
|
print_field(SESSION);
|
||||||
@ -372,14 +367,14 @@ int load(struct Vector* users, struct Vector* sessions) {
|
|||||||
if (ansi_code != -1) {
|
if (ansi_code != -1) {
|
||||||
if (ansi_code == ESC) {
|
if (ansi_code == ESC) {
|
||||||
esc = 2;
|
esc = 2;
|
||||||
} else if (ansi_code == functions.refresh) {
|
} else if (ansi_code == g_config->functions.refresh) {
|
||||||
restore_all();
|
restore_all();
|
||||||
return 0;
|
return 0;
|
||||||
} else if (ansi_code == functions.reboot) {
|
} else if (ansi_code == g_config->functions.reboot) {
|
||||||
restore_all();
|
restore_all();
|
||||||
reboot(RB_AUTOBOOT);
|
reboot(RB_AUTOBOOT);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if (ansi_code == functions.poweroff) {
|
} else if (ansi_code == g_config->functions.poweroff) {
|
||||||
restore_all();
|
restore_all();
|
||||||
reboot(RB_POWER_OFF);
|
reboot(RB_POWER_OFF);
|
||||||
exit(0);
|
exit(0);
|
||||||
@ -395,7 +390,7 @@ int load(struct Vector* users, struct Vector* sessions) {
|
|||||||
} else {
|
} else {
|
||||||
if (len == 1 && *seq == '\n') {
|
if (len == 1 && *seq == '\n') {
|
||||||
if (!launch(get_current_user().username, of_passwd.efield.content,
|
if (!launch(get_current_user().username, of_passwd.efield.content,
|
||||||
get_current_session(), &restore_all, &behavior)) {
|
get_current_session(), &restore_all, g_config)) {
|
||||||
print_passwd(box_start(), of_passwd.efield.length, true);
|
print_passwd(box_start(), of_passwd.efield.length, true);
|
||||||
ffield_cursor_focus();
|
ffield_cursor_focus();
|
||||||
}
|
}
|
||||||
@ -424,31 +419,31 @@ static void print_session(struct uint_point origin, struct session session,
|
|||||||
clean_line(origin, 5);
|
clean_line(origin, 5);
|
||||||
const char* session_type;
|
const char* session_type;
|
||||||
if (session.type == XORG) {
|
if (session.type == XORG) {
|
||||||
session_type = strings.s_xorg;
|
session_type = g_config->strings.s_xorg;
|
||||||
} else if (session.type == WAYLAND) {
|
} else if (session.type == WAYLAND) {
|
||||||
session_type = strings.s_wayland;
|
session_type = g_config->strings.s_wayland;
|
||||||
} else {
|
} else {
|
||||||
session_type = strings.s_shell;
|
session_type = g_config->strings.s_shell;
|
||||||
}
|
}
|
||||||
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
|
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
|
||||||
(ulong)(origin.x + 11 - strlen(session_type)), theme.colors.e_header,
|
(ulong)(origin.x + 11 - strlen(session_type)),
|
||||||
session_type, theme.colors.fg);
|
g_config->colors.e_header, session_type, g_config->colors.fg);
|
||||||
|
|
||||||
char* session_color;
|
char* session_color;
|
||||||
if (session.type == XORG) {
|
if (session.type == XORG) {
|
||||||
session_color = theme.colors.s_xorg;
|
session_color = g_config->colors.s_xorg;
|
||||||
} else if (session.type == WAYLAND) {
|
} else if (session.type == WAYLAND) {
|
||||||
session_color = theme.colors.s_wayland;
|
session_color = g_config->colors.s_wayland;
|
||||||
} else {
|
} else {
|
||||||
session_color = theme.colors.s_shell;
|
session_color = g_config->colors.s_shell;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
printf("\r\x1b[%dC< \x1b[%sm%s\x1b[%sm >", origin.x + 14, session_color,
|
printf("\r\x1b[%dC< \x1b[%sm%s\x1b[%sm >", origin.x + 14, session_color,
|
||||||
session.name, theme.colors.fg);
|
session.name, g_config->colors.fg);
|
||||||
} else {
|
} else {
|
||||||
printf("\r\x1b[%dC\x1b[%sm%s\x1b[%sm", origin.x + 14, session_color,
|
printf("\r\x1b[%dC\x1b[%sm%s\x1b[%sm", origin.x + 14, session_color,
|
||||||
session.name, theme.colors.fg);
|
session.name, g_config->colors.fg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,17 +452,18 @@ static void print_user(struct uint_point origin, struct user user,
|
|||||||
bool multiple) {
|
bool multiple) {
|
||||||
clean_line(origin, 7);
|
clean_line(origin, 7);
|
||||||
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
|
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
|
||||||
(ulong)(origin.x + 11 - strlen(strings.e_user)), theme.colors.e_header,
|
(ulong)(origin.x + 11 - strlen(g_config->strings.e_user)),
|
||||||
strings.e_user, theme.colors.fg);
|
g_config->colors.e_header, g_config->strings.e_user,
|
||||||
|
g_config->colors.fg);
|
||||||
|
|
||||||
char* user_color = theme.colors.e_user;
|
char* user_color = g_config->colors.e_user;
|
||||||
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
printf("\r\x1b[%dC< \x1b[%sm%s\x1b[%sm >", origin.x + 14, user_color,
|
printf("\r\x1b[%dC< \x1b[%sm%s\x1b[%sm >", origin.x + 14, user_color,
|
||||||
user.display_name, theme.colors.fg);
|
user.display_name, g_config->colors.fg);
|
||||||
} else {
|
} else {
|
||||||
printf("\r\x1b[%dC\x1b[%sm%s\x1b[%sm", origin.x + 14, user_color,
|
printf("\r\x1b[%dC\x1b[%sm%s\x1b[%sm", origin.x + 14, user_color,
|
||||||
user.display_name, theme.colors.fg);
|
user.display_name, g_config->colors.fg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,14 +472,15 @@ static char passwd_prompt[33];
|
|||||||
static void print_passwd(struct uint_point origin, uint length, bool err) {
|
static void print_passwd(struct uint_point origin, uint length, bool err) {
|
||||||
clean_line(origin, 9);
|
clean_line(origin, 9);
|
||||||
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
|
printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm",
|
||||||
(ulong)(origin.x + 11 - strlen(strings.e_passwd)),
|
(ulong)(origin.x + 11 - strlen(g_config->strings.e_passwd)),
|
||||||
theme.colors.e_header, strings.e_passwd, theme.colors.fg);
|
g_config->colors.e_header, g_config->strings.e_passwd,
|
||||||
|
g_config->colors.fg);
|
||||||
|
|
||||||
char* pass_color;
|
char* pass_color;
|
||||||
if (err)
|
if (err)
|
||||||
pass_color = theme.colors.e_badpasswd;
|
pass_color = g_config->colors.e_badpasswd;
|
||||||
else
|
else
|
||||||
pass_color = theme.colors.e_passwd;
|
pass_color = g_config->colors.e_passwd;
|
||||||
|
|
||||||
ulong prompt_len = sizeof(passwd_prompt);
|
ulong prompt_len = sizeof(passwd_prompt);
|
||||||
ulong actual_len = length > prompt_len ? prompt_len : length;
|
ulong actual_len = length > prompt_len ? prompt_len : length;
|
||||||
@ -494,7 +491,7 @@ static void print_passwd(struct uint_point origin, uint length, bool err) {
|
|||||||
printf("\r\x1b[%dC\x1b[%sm", origin.x + 14, pass_color);
|
printf("\r\x1b[%dC\x1b[%sm", origin.x + 14, pass_color);
|
||||||
printf("%s", passwd_prompt);
|
printf("%s", passwd_prompt);
|
||||||
|
|
||||||
printf("\x1b[%sm", theme.colors.fg);
|
printf("\x1b[%sm", g_config->colors.fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_empty_row(uint w, uint n, char* edge1, char* edge2) {
|
static void print_empty_row(uint w, uint n, char* edge1, char* edge2) {
|
||||||
@ -517,30 +514,34 @@ static void print_box() {
|
|||||||
// TODO: check min sizes
|
// TODO: check min sizes
|
||||||
const struct uint_point bstart = box_start();
|
const struct uint_point bstart = box_start();
|
||||||
|
|
||||||
printf("\x1b[%d;%dH\x1b[%sm", bstart.y, bstart.x, theme.colors.e_box);
|
printf("\x1b[%d;%dH\x1b[%sm", bstart.y, bstart.x, g_config->colors.e_box);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
print_row(boxw - 2, 1, theme.chars.ctl, theme.chars.ctr, theme.chars.hb);
|
print_row(boxw - 2, 1, g_config->chars.ctl, g_config->chars.ctr,
|
||||||
print_empty_row(boxw - 2, boxh - 2, theme.chars.vb, theme.chars.vb);
|
g_config->chars.hb);
|
||||||
print_row(boxw - 2, 1, theme.chars.cbl, theme.chars.cbr, theme.chars.hb);
|
print_empty_row(boxw - 2, boxh - 2, g_config->chars.vb, g_config->chars.vb);
|
||||||
printf("\x1b[%sm", theme.colors.fg);
|
print_row(boxw - 2, 1, g_config->chars.cbl, g_config->chars.cbr,
|
||||||
|
g_config->chars.hb);
|
||||||
|
printf("\x1b[%sm", g_config->colors.fg);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_footer() {
|
static void print_footer() {
|
||||||
size_t bsize = snprintf(NULL, 0, "%s %s %s %s %s %s", strings.f_poweroff,
|
size_t bsize = snprintf(
|
||||||
key_names[functions.poweroff], strings.f_reboot,
|
NULL, 0, "%s %s %s %s %s %s", g_config->strings.f_poweroff,
|
||||||
key_names[functions.reboot], strings.f_refresh,
|
key_names[g_config->functions.poweroff], g_config->strings.f_reboot,
|
||||||
key_names[functions.refresh]);
|
key_names[g_config->functions.reboot], g_config->strings.f_refresh,
|
||||||
|
key_names[g_config->functions.refresh]);
|
||||||
|
|
||||||
uint row = window.ws_row - 1;
|
uint row = window.ws_row - 1;
|
||||||
uint col = window.ws_col - 2 - bsize;
|
uint col = window.ws_col - 2 - bsize;
|
||||||
printf(
|
printf(
|
||||||
"\x1b[%3$d;%4$dH%8$s \x1b[%1$sm%5$s\x1b[%2$sm %9$s "
|
"\x1b[%3$d;%4$dH%8$s \x1b[%1$sm%5$s\x1b[%2$sm %9$s "
|
||||||
"\x1b[%1$sm%6$s\x1b[%2$sm %10$s \x1b[%1$sm%7$s\x1b[%2$sm",
|
"\x1b[%1$sm%6$s\x1b[%2$sm %10$s \x1b[%1$sm%7$s\x1b[%2$sm",
|
||||||
theme.colors.e_key, theme.colors.fg, row, col,
|
g_config->colors.e_key, g_config->colors.fg, row, col,
|
||||||
key_names[functions.poweroff], key_names[functions.reboot],
|
key_names[g_config->functions.poweroff],
|
||||||
key_names[functions.refresh], strings.f_poweroff, strings.f_reboot,
|
key_names[g_config->functions.reboot],
|
||||||
strings.f_refresh);
|
key_names[g_config->functions.refresh], g_config->strings.f_poweroff,
|
||||||
|
g_config->strings.f_reboot, g_config->strings.f_refresh);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,10 +555,10 @@ void print_errno(const char* descr) {
|
|||||||
struct uint_point origin = box_start();
|
struct uint_point origin = box_start();
|
||||||
if (descr == NULL)
|
if (descr == NULL)
|
||||||
fprintf(stderr, "\x1b[%d;%dH\x1b[%smunknown error(%d): %s", origin.y - 1,
|
fprintf(stderr, "\x1b[%d;%dH\x1b[%smunknown error(%d): %s", origin.y - 1,
|
||||||
origin.x, theme.colors.err, errno, strerror(errno));
|
origin.x, g_config->colors.err, errno, strerror(errno));
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "\x1b[%d;%dH\x1b[%sm%s(%d): %s", origin.y - 1, origin.x,
|
fprintf(stderr, "\x1b[%d;%dH\x1b[%sm%s(%d): %s", origin.y - 1, origin.x,
|
||||||
theme.colors.err, descr, errno, strerror(errno));
|
g_config->colors.err, descr, errno, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ int build_user(struct user* NNULLABLE user, struct passwd* p) {
|
|||||||
// NOLINTNEXTLINE(modernize-macro-to-enum)
|
// NOLINTNEXTLINE(modernize-macro-to-enum)
|
||||||
#define LIKELY_BOUND_USERS 4
|
#define LIKELY_BOUND_USERS 4
|
||||||
struct Vector get_human_users() {
|
struct Vector get_human_users() {
|
||||||
struct Vector users = vec_new();
|
struct Vector users = VEC_NEW;
|
||||||
vec_reserve(&users, LIKELY_BOUND_USERS);
|
vec_reserve(&users, LIKELY_BOUND_USERS);
|
||||||
|
|
||||||
struct passwd* NULLABLE pwd;
|
struct passwd* NULLABLE pwd;
|
||||||
|
28
src/util.c
28
src/util.c
@ -11,13 +11,15 @@
|
|||||||
|
|
||||||
static int selret_magic();
|
static int selret_magic();
|
||||||
|
|
||||||
enum keys find_keyname(char* name) {
|
int find_keyname(enum keys* at, char* name) {
|
||||||
for (size_t i = 0; i < sizeof(key_mappings) / sizeof(key_mappings[0]); i++) {
|
for (size_t i = 0; i < sizeof(key_mappings) / sizeof(key_mappings[0]); i++) {
|
||||||
if (strcmp(key_names[i], name) == 0) return (enum keys)i;
|
if (strcmp(key_names[i], name) == 0) {
|
||||||
|
*at = (enum keys)i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
perror("key not found");
|
return -1;
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum keys find_ansi(char* seq) {
|
enum keys find_ansi(char* seq) {
|
||||||
@ -63,11 +65,11 @@ static int selret_magic() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vector shii
|
// Vector shii
|
||||||
struct Vector vec_new() {
|
const struct Vector VEC_NEW = {
|
||||||
struct Vector vec;
|
.length = 0,
|
||||||
vec_reset(&vec);
|
.capacity = 0,
|
||||||
return vec;
|
.pages = NULL,
|
||||||
}
|
};
|
||||||
|
|
||||||
int vec_resize(struct Vector* vec, size_t size) {
|
int vec_resize(struct Vector* vec, size_t size) {
|
||||||
void** new_location = realloc(vec->pages, size * sizeof(void*));
|
void** new_location = realloc(vec->pages, size * sizeof(void*));
|
||||||
@ -120,9 +122,11 @@ void vec_clear(struct Vector* vec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vec_reset(struct Vector* vec) {
|
void vec_reset(struct Vector* vec) {
|
||||||
vec->length = 0;
|
*vec = (struct Vector){
|
||||||
vec->capacity = 0;
|
.length = 0,
|
||||||
vec->pages = NULL;
|
.capacity = 0,
|
||||||
|
.pages = NULL,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void* vec_pop(struct Vector* vec) {
|
void* vec_pop(struct Vector* vec) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user