diff --git a/include/auth.h b/include/auth.h index 6c5a346..2464a86 100644 --- a/include/auth.h +++ b/include/auth.h @@ -7,6 +7,6 @@ #include "sessions.h" bool launch(char* user, char* passwd, struct session session, void (*cb)(void), - struct behavior* behavior); + struct config* config); #endif diff --git a/include/config.h b/include/config.h index 1b49cf6..7a1a65d 100644 --- a/include/config.h +++ b/include/config.h @@ -2,77 +2,166 @@ #define CONFIGH_ #include -#include +#include #include "keys.h" +#include "macros.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 // if not prepared accordingly, it might break -struct theme_colors { - char* bg; - char* fg; - char* err; - char* s_wayland; - char* s_xorg; - char* s_shell; - char* e_hostname; - char* e_date; - char* e_box; - char* e_header; - char* e_user; - char* e_passwd; - char* e_badpasswd; - char* e_key; -}; +#define TABLE_COLORS(F, name) \ + F(char*, bg, STRING, "48;2;38;28;28", name) \ + F(char*, fg, STRING, "22;24;38;2;245;245;245", name) \ + F(char*, err, STRING, "1;31", name) \ + F(char*, s_wayland, STRING, "38;2;255;174;66", name) \ + F(char*, s_xorg, STRING, "38;2;37;175;255", name) \ + F(char*, s_shell, STRING, "38;2;34;140;34", name) \ + F(char*, e_hostname, STRING, "38;2;255;64;64", name) \ + F(char*, e_date, STRING, "38;2;144;144;144", name) \ + F(char*, e_box, STRING, "38;2;122;122;122", name) \ + F(char*, e_header, STRING, "4;38;2;0;255;0", name) \ + F(char*, e_user, STRING, "36", name) \ + F(char*, e_passwd, STRING, "4;38;2;245;245;205", name) \ + F(char*, e_badpasswd, STRING, "3;4;31", name) \ + F(char*, e_key, STRING, "38;2;255;174;66", name) + +BUILD(colors, TABLE_COLORS); // even if they're multiple bytes long // they should only take up 1 char size on display -struct theme_chars { - char* hb; - char* vb; +#define TABLE_CHARS(F, name) \ + F(char*, hb, STRING, "─", name) \ + 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; - char* ctr; - char* cbl; - char* cbr; -}; +BUILD(chars, TABLE_CHARS); -struct theme { - struct theme_colors colors; - struct theme_chars chars; -}; +#define TABLE_FUNCTIONS(F, name) \ + F(enum keys, poweroff, KEY, F1, name) \ + F(enum keys, reboot, KEY, F2, name) \ + F(enum keys, refresh, KEY, F5, name) -struct functions { - enum keys poweroff; - enum keys reboot; - enum keys refresh; -}; +BUILD(functions, TABLE_FUNCTIONS); -struct strings { - char* f_poweroff; - char* f_reboot; - char* f_refresh; - char* e_user; - char* e_passwd; - char* s_wayland; - char* s_xorg; - char* s_shell; -}; +#define TABLE_STRINGS(F, name) \ + F(char*, f_poweroff, STRING, "poweroff", name) \ + F(char*, f_reboot, STRING, "reboot", name) \ + F(char*, f_refresh, STRING, "refresh", name) \ + F(char*, e_user, STRING, "user", name) \ + F(char*, e_passwd, STRING, "password", name) \ + F(char*, s_wayland, STRING, "wayland", name) \ + F(char*, s_xorg, STRING, "xorg", name) \ + F(char*, s_shell, STRING, "shell", name) -struct behavior { - bool include_defshell; - struct Vector source; - struct Vector user_source; -}; +BUILD(strings, TABLE_STRINGS); +#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 theme theme; - struct functions functions; - struct strings strings; - struct behavior behavior; + struct table_colors colors; + struct table_chars chars; + struct table_functions functions; + 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 diff --git a/include/macros.h b/include/macros.h index 93344d3..c549cf1 100644 --- a/include/macros.h +++ b/include/macros.h @@ -20,4 +20,6 @@ #define UNULLABLE #endif +#define LEN(X) (sizeof(X) / sizeof((X)[0])) + #endif diff --git a/include/ui.h b/include/ui.h index bbdb1cc..a6962e4 100644 --- a/include/ui.h +++ b/include/ui.h @@ -4,7 +4,7 @@ #include "config.h" #include "util.h" -void setup(struct config); +void setup(struct config* config); int load(struct Vector* users, struct Vector* sessions); void print_err(const char*); void print_errno(const char*); diff --git a/include/util.h b/include/util.h index 2afb588..1f5de5f 100644 --- a/include/util.h +++ b/include/util.h @@ -2,13 +2,14 @@ #define UTILH_ #include +#include #include #include #include #include "keys.h" -enum keys find_keyname(char*); +int find_keyname(enum keys* at, char* name); enum keys find_ansi(char*); void read_press(u_char*, char*); @@ -18,7 +19,7 @@ struct Vector { void** pages; }; -struct Vector vec_new(); +extern const struct Vector VEC_NEW; int vec_resize(struct Vector*, size_t size); int vec_reserve(struct Vector*, size_t size); int vec_reserve_exact(struct Vector*, size_t size); diff --git a/src/auth.c b/src/auth.c index e19c93e..4957db4 100644 --- a/src/auth.c +++ b/src/auth.c @@ -94,7 +94,7 @@ void sourceFileTry(char* file) { } 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"); 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); 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, * i)); */ - sourceFileTry((char*)vec_get(&behavior->source, i)); + sourceFileTry((char*)vec_get(&config->behavior.source, i)); } /* printf("\n"); */ if (pw->pw_dir) { uint home_len = strlen(pw->pw_dir); - for (size_t i = 0; i < behavior->user_source.length; i++) { - char* file2sourcepath = (char*)vec_get(&behavior->user_source, i); + for (size_t i = 0; i < config->behavior.user_source.length; i++) { + char* file2sourcepath = (char*)vec_get(&config->behavior.user_source, i); size_t newbuf_len = home_len + strlen(file2sourcepath) + 2; char* newbuf = malloc(newbuf_len); // nullbyte and slash 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) bool launch(char* user, char* passwd, struct session session, void (*cb)(void), - struct behavior* behavior) { + struct config* config) { struct passwd* pw = getpwnam(user); if (pw == NULL) { 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); - moarEnv(user, session, pw, behavior); + moarEnv(user, session, pw, config); // TODO: chown stdin to user // does it inherit stdin from parent and diff --git a/src/config.c b/src/config.c index 0f93a37..29a8e96 100644 --- a/src/config.c +++ b/src/config.c @@ -1,155 +1,221 @@ -#include #include +#include +#include #include #include #include +#include #include "config.h" +#include "desktop.h" +#include "log.h" #include "util.h" -// Alr so ima explain the bitfield returned by `cb` a bit -// 4 bits: -// 0b0001: break out of parsing (returning true) -// 0b0010: free the value -// 0b0100: free the key -// 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; +// NOLINTNEXTLINE(modernize-macro-to-enum) +#define UPPER_HALF_BYTE 4 +int parse_hex(char* _at, char x1, char x2) { + // make linter happy + u_char* at = (u_char*)_at; - char* buf = NULL; - size_t alloc_size = 0; - size_t read_size; - while ((read_size = getline(&buf, &alloc_size, fd)) != -1) { - ok = true; - char* key = malloc(read_size); - if (key == NULL) { - ok = false; - 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 { - free(key); - free(value); - } + *at = 0; + + if ('0' <= x1 && x1 <= '9') { + *at += (x1 - '0') << UPPER_HALF_BYTE; + } else if ('A' <= x1 && x1 <= 'F') { + *at += (x1 - 'A' + 10) << UPPER_HALF_BYTE; + } else if ('a' <= x1 && x1 <= 'f') { + *at += (x1 - 'a' + 10) << UPPER_HALF_BYTE; + } else { + return -1; } - if (buf != NULL) free(buf); - return ok; + if ('0' <= x2 && x2 <= '9') { + *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; -// Yanderedev code (wanna fix this with a table or smth) -// NOLINTNEXTLINE(readability-identifier-length,readability-function-cognitive-complexity) -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; +struct parser_error { + const char* NULLABLE msg; + size_t col; +}; - 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) { - // struct stat sb; - errno = 0; +#define FAIL(str) return (struct parser_error){str, 0} +#define NOFAIL return (struct parser_error){NULL, 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"); if (fd == NULL) { 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 " "env variable", stderr); - return NULL; + return -1; } - // if(stat(path, &sb) != 0) { - // perror("stat"); - // } - g_config = malloc(sizeof(struct config)); - 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); + bool ret = read_desktop(fd, config, config_line_handler); (void)fclose(fd); if (!ret) { - free(g_config); - return NULL; + return -1; } - return g_config; + return 0; } diff --git a/src/desktop.c b/src/desktop.c index b3ed57f..6c33739 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -5,7 +5,20 @@ #include #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, 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) { 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); - table_name = realloc(buf, read_size); - table_name[read_size - 1] = '\0'; // newline - buf = NULL; - alloc_size = 0; + buf_start[strlen(buf_start) - 1] = '\0'; + table_name = strdup(buf_start + 1); + if (table_name == NULL) { + ret = -1; + break; + } } else { // Find '=' size_t eq_idx = 0; - while (buf[eq_idx] != '\0') { - if (buf[eq_idx] == '=') break; + while (buf_start[eq_idx] != '\0') { + if (buf_start[eq_idx] == '=') break; eq_idx++; } // impossible with a min len of 1 (empty line) if (eq_idx == 0) continue; // Check its not end - if (buf[eq_idx] != '=') { + if (buf_start[eq_idx] != '=') { ret = -1; break; } // Key & Value - char* key = buf; - buf[eq_idx] = '\0'; // the equal - char* value = &buf[eq_idx + 1]; - buf[read_size - 1] = '\0'; // the newline + char* key = buf_start; + buf_start[eq_idx] = '\0'; // the equal + key = trim_str(key); + char* value = &buf_start[eq_idx + 1]; + buf_start[read_size - 1] = '\0'; // the newline + value = trim_str(value); // Callback struct status cb_ret = cb(ctx, table_name, key, value); diff --git a/src/main.c b/src/main.c index 8efa6c1..d4efdfc 100644 --- a/src/main.c +++ b/src/main.c @@ -14,6 +14,7 @@ #include "util.h" int main(int argc, char* argv[]) { + // Logger char* log_output = getenv("LIDM_LOG"); if (log_output) { FILE* log_fd = fopen(log_output, "w"); @@ -26,17 +27,17 @@ int main(int argc, char* argv[]) { log_init(log_fd); } + // Chvt if (argc == 2) chvt_str(argv[1]); + struct config config = default_config; char* conf_override = getenv("LIDM_CONF"); - struct config* config = - parse_config(conf_override == NULL ? "/etc/lidm.ini" : conf_override); - if (config == NULL) { - // NOLINT(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) + char* conf_path = conf_override ? conf_override : "/etc/lidm.ini"; + if (parse_config(&config, conf_path) != 0) { (void)fputs("error parsing config\n", stderr); return 1; } - setup(*config); + setup(&config); struct Vector users = get_human_users(); struct Vector sessions = get_avaliable_sessions(); diff --git a/src/sessions.c b/src/sessions.c index 4c745bd..a188013 100644 --- a/src/sessions.c +++ b/src/sessions.c @@ -35,7 +35,7 @@ struct status cb(void* _ctx, char* NULLABLE table, char* key, char* value) { ret.finish = false; 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; 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 #define LIKELY_BOUND_SESSIONS 8 struct Vector get_avaliable_sessions() { - struct Vector sessions = vec_new(); + struct Vector sessions = VEC_NEW; vec_reserve(&sessions, LIKELY_BOUND_SESSIONS); cb_sessions = &sessions; diff --git a/src/ui.c b/src/ui.c index 1229e6f..35a7a33 100644 --- a/src/ui.c +++ b/src/ui.c @@ -49,11 +49,9 @@ static struct termios orig_term; static struct termios term; static struct winsize window; -static struct theme theme; -static struct functions functions; -static struct strings strings; -static struct behavior behavior; -void setup(struct config __config) { +struct config* g_config = NULL; +void setup(struct config* config) { + g_config = config; ioctl(STDOUT_FILENO, TIOCGWINSZ, &window); // 2 padding top and bottom for footer and vertical compensation @@ -63,11 +61,6 @@ void setup(struct config __config) { exit(1); } - theme = __config.theme; - functions = __config.functions; - strings = __config.strings; - behavior = __config.behavior; - tcgetattr(STDOUT_FILENO, &orig_term); term = orig_term; // save term // "stty" attrs @@ -76,7 +69,8 @@ void setup(struct config __config) { // save cursor pos, save screen, set color and reset 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(); atexit(restore_all); @@ -227,7 +221,7 @@ struct session get_current_session() { if (of_session.current_opt != 0) { // this is for the default user shell :P, not the greatest // 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) { struct session shell_session; shell_session.type = SHELL; @@ -333,7 +327,8 @@ int load(struct Vector* users, struct Vector* sessions) { 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_passwd = ofield_new(0); @@ -345,15 +340,15 @@ int load(struct Vector* users, struct Vector* sessions) { // put hostname printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", boxstart.y + 2, - boxstart.x + 12 - (uint)strlen(hostname), theme.colors.e_hostname, - hostname, theme.colors.fg); + boxstart.x + 12 - (uint)strlen(hostname), g_config->colors.e_hostname, + hostname, g_config->colors.fg); if (hostname != unknown_str) free(hostname); // put date char* fmtd_time = fmt_time(); printf("\x1b[%d;%dH\x1b[%sm%s\x1b[%sm", boxstart.y + 2, - boxstart.x + boxw - 3 - (uint)strlen(fmtd_time), theme.colors.e_date, - fmtd_time, theme.colors.fg); + boxstart.x + boxw - 3 - (uint)strlen(fmtd_time), + g_config->colors.e_date, fmtd_time, g_config->colors.fg); free(fmtd_time); print_field(SESSION); @@ -372,14 +367,14 @@ int load(struct Vector* users, struct Vector* sessions) { if (ansi_code != -1) { if (ansi_code == ESC) { esc = 2; - } else if (ansi_code == functions.refresh) { + } else if (ansi_code == g_config->functions.refresh) { restore_all(); return 0; - } else if (ansi_code == functions.reboot) { + } else if (ansi_code == g_config->functions.reboot) { restore_all(); reboot(RB_AUTOBOOT); exit(0); - } else if (ansi_code == functions.poweroff) { + } else if (ansi_code == g_config->functions.poweroff) { restore_all(); reboot(RB_POWER_OFF); exit(0); @@ -395,7 +390,7 @@ int load(struct Vector* users, struct Vector* sessions) { } else { if (len == 1 && *seq == '\n') { 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); ffield_cursor_focus(); } @@ -424,31 +419,31 @@ static void print_session(struct uint_point origin, struct session session, clean_line(origin, 5); const char* session_type; if (session.type == XORG) { - session_type = strings.s_xorg; + session_type = g_config->strings.s_xorg; } else if (session.type == WAYLAND) { - session_type = strings.s_wayland; + session_type = g_config->strings.s_wayland; } else { - session_type = strings.s_shell; + session_type = g_config->strings.s_shell; } printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm", - (ulong)(origin.x + 11 - strlen(session_type)), theme.colors.e_header, - session_type, theme.colors.fg); + (ulong)(origin.x + 11 - strlen(session_type)), + g_config->colors.e_header, session_type, g_config->colors.fg); char* session_color; if (session.type == XORG) { - session_color = theme.colors.s_xorg; + session_color = g_config->colors.s_xorg; } else if (session.type == WAYLAND) { - session_color = theme.colors.s_wayland; + session_color = g_config->colors.s_wayland; } else { - session_color = theme.colors.s_shell; + session_color = g_config->colors.s_shell; } if (multiple) { 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 { 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) { clean_line(origin, 7); printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm", - (ulong)(origin.x + 11 - strlen(strings.e_user)), theme.colors.e_header, - strings.e_user, theme.colors.fg); + (ulong)(origin.x + 11 - strlen(g_config->strings.e_user)), + 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) { 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 { 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) { clean_line(origin, 9); printf("\r\x1b[%luC\x1b[%sm%s\x1b[%sm", - (ulong)(origin.x + 11 - strlen(strings.e_passwd)), - theme.colors.e_header, strings.e_passwd, theme.colors.fg); + (ulong)(origin.x + 11 - strlen(g_config->strings.e_passwd)), + g_config->colors.e_header, g_config->strings.e_passwd, + g_config->colors.fg); char* pass_color; if (err) - pass_color = theme.colors.e_badpasswd; + pass_color = g_config->colors.e_badpasswd; else - pass_color = theme.colors.e_passwd; + pass_color = g_config->colors.e_passwd; ulong prompt_len = sizeof(passwd_prompt); 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("%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) { @@ -517,30 +514,34 @@ static void print_box() { // TODO: check min sizes 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); - print_row(boxw - 2, 1, theme.chars.ctl, theme.chars.ctr, theme.chars.hb); - print_empty_row(boxw - 2, boxh - 2, theme.chars.vb, theme.chars.vb); - print_row(boxw - 2, 1, theme.chars.cbl, theme.chars.cbr, theme.chars.hb); - printf("\x1b[%sm", theme.colors.fg); + print_row(boxw - 2, 1, g_config->chars.ctl, g_config->chars.ctr, + g_config->chars.hb); + print_empty_row(boxw - 2, boxh - 2, g_config->chars.vb, g_config->chars.vb); + 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); } static void print_footer() { - size_t bsize = snprintf(NULL, 0, "%s %s %s %s %s %s", strings.f_poweroff, - key_names[functions.poweroff], strings.f_reboot, - key_names[functions.reboot], strings.f_refresh, - key_names[functions.refresh]); + size_t bsize = snprintf( + NULL, 0, "%s %s %s %s %s %s", g_config->strings.f_poweroff, + key_names[g_config->functions.poweroff], g_config->strings.f_reboot, + key_names[g_config->functions.reboot], g_config->strings.f_refresh, + key_names[g_config->functions.refresh]); uint row = window.ws_row - 1; uint col = window.ws_col - 2 - bsize; printf( "\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", - theme.colors.e_key, theme.colors.fg, row, col, - key_names[functions.poweroff], key_names[functions.reboot], - key_names[functions.refresh], strings.f_poweroff, strings.f_reboot, - strings.f_refresh); + g_config->colors.e_key, g_config->colors.fg, row, col, + key_names[g_config->functions.poweroff], + key_names[g_config->functions.reboot], + key_names[g_config->functions.refresh], g_config->strings.f_poweroff, + g_config->strings.f_reboot, g_config->strings.f_refresh); fflush(stdout); } @@ -554,10 +555,10 @@ void print_errno(const char* descr) { struct uint_point origin = box_start(); if (descr == NULL) 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 { 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)); } } diff --git a/src/users.c b/src/users.c index 6ecb0b7..cb3da34 100644 --- a/src/users.c +++ b/src/users.c @@ -42,7 +42,7 @@ int build_user(struct user* NNULLABLE user, struct passwd* p) { // NOLINTNEXTLINE(modernize-macro-to-enum) #define LIKELY_BOUND_USERS 4 struct Vector get_human_users() { - struct Vector users = vec_new(); + struct Vector users = VEC_NEW; vec_reserve(&users, LIKELY_BOUND_USERS); struct passwd* NULLABLE pwd; diff --git a/src/util.c b/src/util.c index 84f9efc..79b19a7 100644 --- a/src/util.c +++ b/src/util.c @@ -11,13 +11,15 @@ 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++) { - 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"); - exit(1); + return -1; } enum keys find_ansi(char* seq) { @@ -63,11 +65,11 @@ static int selret_magic() { } // Vector shii -struct Vector vec_new() { - struct Vector vec; - vec_reset(&vec); - return vec; -} +const struct Vector VEC_NEW = { + .length = 0, + .capacity = 0, + .pages = NULL, +}; int vec_resize(struct Vector* vec, size_t size) { 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) { - vec->length = 0; - vec->capacity = 0; - vec->pages = NULL; + *vec = (struct Vector){ + .length = 0, + .capacity = 0, + .pages = NULL, + }; } void* vec_pop(struct Vector* vec) {