2019-07-16 11:52:22 +02:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdbool.h>
|
2019-07-17 10:12:14 +02:00
|
|
|
#include <ctype.h>
|
2019-07-16 11:52:22 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <pwd.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#define LOG_MODULE "config"
|
|
|
|
|
#define LOG_ENABLE_DBG 0
|
|
|
|
|
#include "log.h"
|
|
|
|
|
|
2019-07-21 11:06:28 +02:00
|
|
|
static const uint32_t default_foreground = 0xdcdccc;
|
|
|
|
|
static const uint32_t default_background = 0x111111;
|
|
|
|
|
|
|
|
|
|
static const uint32_t default_regular[] = {
|
|
|
|
|
0x000000,
|
|
|
|
|
0xcc9393,
|
|
|
|
|
0x7f9f7f,
|
|
|
|
|
0xd0bf8f,
|
|
|
|
|
0x6ca0a3,
|
|
|
|
|
0xdc8cc3,
|
|
|
|
|
0x93e0e3,
|
|
|
|
|
0xdcdccc,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const uint32_t default_bright[] = {
|
2019-08-23 19:42:14 +02:00
|
|
|
0x666666,
|
2019-07-21 11:06:28 +02:00
|
|
|
0xdca3a3,
|
|
|
|
|
0xbfebbf,
|
|
|
|
|
0xf0dfaf,
|
|
|
|
|
0x8cd0d3,
|
|
|
|
|
0xdc8cc3,
|
|
|
|
|
0x93e0e3,
|
|
|
|
|
0xffffff,
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-17 09:29:56 +02:00
|
|
|
static char *
|
|
|
|
|
get_shell(void)
|
|
|
|
|
{
|
|
|
|
|
struct passwd *passwd = getpwuid(getuid());
|
|
|
|
|
if (passwd == NULL) {
|
|
|
|
|
LOG_ERRNO("failed to lookup user");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *shell = passwd->pw_shell;
|
|
|
|
|
LOG_DBG("user's shell: %s", shell);
|
|
|
|
|
|
|
|
|
|
return strdup(shell);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
static char *
|
|
|
|
|
get_config_path_user_config(void)
|
|
|
|
|
{
|
|
|
|
|
struct passwd *passwd = getpwuid(getuid());
|
|
|
|
|
if (passwd == NULL) {
|
|
|
|
|
LOG_ERRNO("failed to lookup user");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *home_dir = passwd->pw_dir;
|
|
|
|
|
LOG_DBG("user's home directory: %s", home_dir);
|
|
|
|
|
|
|
|
|
|
int len = snprintf(NULL, 0, "%s/.config/footrc", home_dir);
|
|
|
|
|
char *path = malloc(len + 1);
|
|
|
|
|
snprintf(path, len + 1, "%s/.config/footrc", home_dir);
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
get_config_path_xdg(void)
|
|
|
|
|
{
|
|
|
|
|
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
|
|
|
|
|
if (xdg_config_home == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
int len = snprintf(NULL, 0, "%s/footrc", xdg_config_home);
|
|
|
|
|
char *path = malloc(len + 1);
|
|
|
|
|
snprintf(path, len + 1, "%s/footrc", xdg_config_home);
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
get_config_path(void)
|
|
|
|
|
{
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
|
|
char *config = get_config_path_xdg();
|
|
|
|
|
if (config != NULL && stat(config, &st) == 0 && S_ISREG(st.st_mode))
|
|
|
|
|
return config;
|
|
|
|
|
free(config);
|
|
|
|
|
|
|
|
|
|
/* 'Default' XDG_CONFIG_HOME */
|
|
|
|
|
config = get_config_path_user_config();
|
|
|
|
|
if (config != NULL && stat(config, &st) == 0 && S_ISREG(st.st_mode))
|
|
|
|
|
return config;
|
|
|
|
|
free(config);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 18:54:58 +02:00
|
|
|
static bool
|
2019-07-29 20:13:26 +02:00
|
|
|
str_to_ulong(const char *s, int base, unsigned long *res)
|
2019-07-23 18:54:58 +02:00
|
|
|
{
|
|
|
|
|
if (s == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
char *end = NULL;
|
|
|
|
|
|
2019-07-29 20:13:26 +02:00
|
|
|
*res = strtoul(s, &end, base);
|
|
|
|
|
return errno == 0 && *end == '\0';
|
|
|
|
|
}
|
2019-07-23 18:54:58 +02:00
|
|
|
|
2019-08-15 18:15:43 +02:00
|
|
|
static bool
|
|
|
|
|
str_to_double(const char *s, double *res)
|
|
|
|
|
{
|
|
|
|
|
if (s == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
char *end = NULL;
|
|
|
|
|
|
|
|
|
|
*res = strtod(s, &end);
|
|
|
|
|
return errno == 0 && *end == '\0';
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-29 20:13:26 +02:00
|
|
|
static bool
|
|
|
|
|
str_to_color(const char *s, uint32_t *color, const char *path, int lineno)
|
|
|
|
|
{
|
|
|
|
|
unsigned long value;
|
|
|
|
|
if (!str_to_ulong(s, 16, &value)) {
|
|
|
|
|
LOG_ERRNO("%s:%d: invalid color: %s", path, lineno, s);
|
2019-07-23 18:54:58 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-29 20:13:26 +02:00
|
|
|
*color = value & 0xffffff;
|
2019-07-23 18:54:58 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
static bool
|
2019-07-17 10:12:14 +02:00
|
|
|
parse_section_main(const char *key, const char *value, struct config *conf,
|
|
|
|
|
const char *path, unsigned lineno)
|
2019-07-16 11:52:22 +02:00
|
|
|
{
|
2019-07-18 14:29:40 +02:00
|
|
|
if (strcmp(key, "term") == 0) {
|
|
|
|
|
free(conf->term);
|
|
|
|
|
conf->term = strdup(value);
|
2019-07-16 11:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-17 09:40:58 +02:00
|
|
|
else if (strcmp(key, "shell") == 0) {
|
|
|
|
|
free(conf->shell);
|
|
|
|
|
conf->shell = strdup(value);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-23 17:26:41 +02:00
|
|
|
else if (strcmp(key, "geometry") == 0) {
|
|
|
|
|
unsigned width, height;
|
|
|
|
|
if (sscanf(value, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
|
|
|
|
LOG_ERR(
|
|
|
|
|
"%s: %d: expected WIDTHxHEIGHT, where both are positive integers: %s",
|
|
|
|
|
path, lineno, value);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conf->width = width;
|
|
|
|
|
conf->height = height;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-18 14:29:40 +02:00
|
|
|
else if (strcmp(key, "font") == 0) {
|
2019-07-30 18:04:28 +02:00
|
|
|
char *copy = strdup(value);
|
|
|
|
|
for (const char *font = strtok(copy, ","); font != NULL; font = strtok(NULL, ","))
|
|
|
|
|
tll_push_back(conf->fonts, strdup(font));
|
|
|
|
|
free(copy);
|
2019-07-18 14:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-29 20:13:26 +02:00
|
|
|
else if (strcmp(key, "workers") == 0) {
|
|
|
|
|
unsigned long count;
|
|
|
|
|
if (!str_to_ulong(value, 10, &count)) {
|
|
|
|
|
LOG_ERR("%s:%d: expected an integer: %s", path, lineno, value);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
conf->render_worker_count = count;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-01 19:28:14 +02:00
|
|
|
else if (strcmp(key, "scrollback") == 0) {
|
|
|
|
|
unsigned long lines;
|
|
|
|
|
if (!str_to_ulong(value, 10, &lines)) {
|
|
|
|
|
LOG_ERR("%s:%d: expected an integer: %s", path, lineno, value);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
conf->scrollback_lines = lines;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
else {
|
2019-07-17 10:12:14 +02:00
|
|
|
LOG_WARN("%s:%u: invalid key: %s", path, lineno, key);
|
2019-07-16 11:52:22 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-21 11:31:16 +02:00
|
|
|
static bool
|
|
|
|
|
parse_section_colors(const char *key, const char *value, struct config *conf,
|
|
|
|
|
const char *path, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
uint32_t *color = NULL;
|
|
|
|
|
|
|
|
|
|
if (strcmp(key, "foreground") == 0) color = &conf->colors.fg;
|
|
|
|
|
else if (strcmp(key, "background") == 0) color = &conf->colors.bg;
|
|
|
|
|
else if (strcmp(key, "regular0") == 0) color = &conf->colors.regular[0];
|
|
|
|
|
else if (strcmp(key, "regular1") == 0) color = &conf->colors.regular[1];
|
|
|
|
|
else if (strcmp(key, "regular2") == 0) color = &conf->colors.regular[2];
|
|
|
|
|
else if (strcmp(key, "regular3") == 0) color = &conf->colors.regular[3];
|
|
|
|
|
else if (strcmp(key, "regular4") == 0) color = &conf->colors.regular[4];
|
|
|
|
|
else if (strcmp(key, "regular5") == 0) color = &conf->colors.regular[5];
|
|
|
|
|
else if (strcmp(key, "regular6") == 0) color = &conf->colors.regular[6];
|
|
|
|
|
else if (strcmp(key, "regular7") == 0) color = &conf->colors.regular[7];
|
|
|
|
|
else if (strcmp(key, "bright0") == 0) color = &conf->colors.bright[0];
|
|
|
|
|
else if (strcmp(key, "bright1") == 0) color = &conf->colors.bright[1];
|
|
|
|
|
else if (strcmp(key, "bright2") == 0) color = &conf->colors.bright[2];
|
|
|
|
|
else if (strcmp(key, "bright3") == 0) color = &conf->colors.bright[3];
|
|
|
|
|
else if (strcmp(key, "bright4") == 0) color = &conf->colors.bright[4];
|
|
|
|
|
else if (strcmp(key, "bright5") == 0) color = &conf->colors.bright[5];
|
|
|
|
|
else if (strcmp(key, "bright6") == 0) color = &conf->colors.bright[6];
|
|
|
|
|
else if (strcmp(key, "bright7") == 0) color = &conf->colors.bright[7];
|
2019-08-15 18:15:43 +02:00
|
|
|
else if (strcmp(key, "alpha") == 0) {
|
|
|
|
|
double alpha;
|
|
|
|
|
if (!str_to_double(value, &alpha) || alpha < 0. || alpha > 1.) {
|
|
|
|
|
LOG_ERR("%s: %d: alpha: expected a value in the range 0.0-1.0",
|
|
|
|
|
path, lineno);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 22:06:06 +02:00
|
|
|
conf->colors.alpha = alpha * 65535.;
|
2019-08-15 18:15:43 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-07-21 11:31:16 +02:00
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
LOG_ERR("%s:%d: invalid key: %s", path, lineno, key);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 18:54:58 +02:00
|
|
|
uint32_t color_value;
|
|
|
|
|
if (!str_to_color(value, &color_value, path, lineno))
|
2019-07-21 11:31:16 +02:00
|
|
|
return false;
|
|
|
|
|
|
2019-07-23 18:54:58 +02:00
|
|
|
*color = color_value;
|
2019-07-21 11:31:16 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-22 20:15:14 +02:00
|
|
|
static bool
|
|
|
|
|
parse_section_cursor(const char *key, const char *value, struct config *conf,
|
|
|
|
|
const char *path, unsigned lineno)
|
|
|
|
|
{
|
|
|
|
|
if (strcmp(key, "style") == 0) {
|
|
|
|
|
if (strcmp(value, "block") == 0)
|
|
|
|
|
conf->cursor.style = CURSOR_BLOCK;
|
|
|
|
|
else if (strcmp(value, "bar") == 0)
|
|
|
|
|
conf->cursor.style = CURSOR_BAR;
|
|
|
|
|
else if (strcmp(value, "underline") == 0)
|
|
|
|
|
conf->cursor.style = CURSOR_UNDERLINE;
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
LOG_ERR("%s:%d: invalid 'style': %s", path, lineno, value);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 18:54:58 +02:00
|
|
|
else if (strcmp(key, "color") == 0) {
|
|
|
|
|
char *value_copy = strdup(value);
|
|
|
|
|
const char *text = strtok(value_copy, " ");
|
|
|
|
|
const char *cursor = strtok(NULL, " ");
|
|
|
|
|
|
|
|
|
|
uint32_t text_color, cursor_color;
|
|
|
|
|
if (text == NULL || cursor == NULL ||
|
|
|
|
|
!str_to_color(text, &text_color, path, lineno) ||
|
|
|
|
|
!str_to_color(cursor, &cursor_color, path, lineno))
|
|
|
|
|
{
|
|
|
|
|
LOG_ERR("%s:%d: invalid cursor colors: %s", path, lineno, value);
|
|
|
|
|
free(value_copy);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conf->cursor.color.text = 1 << 31 | text_color;
|
|
|
|
|
conf->cursor.color.cursor = 1 << 31 | cursor_color;
|
|
|
|
|
free(value_copy);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-22 20:15:14 +02:00
|
|
|
else {
|
|
|
|
|
LOG_ERR("%s:%d: invalid key: %s", path, lineno, key);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
static bool
|
|
|
|
|
parse_config_file(FILE *f, struct config *conf, const char *path)
|
|
|
|
|
{
|
|
|
|
|
enum section {
|
|
|
|
|
SECTION_MAIN,
|
2019-07-21 11:31:16 +02:00
|
|
|
SECTION_COLORS,
|
2019-07-22 20:15:14 +02:00
|
|
|
SECTION_CURSOR,
|
2019-07-16 11:52:22 +02:00
|
|
|
} section = SECTION_MAIN;
|
|
|
|
|
|
|
|
|
|
/* Function pointer, called for each key/value line */
|
|
|
|
|
typedef bool (*parser_fun_t)(
|
2019-07-17 10:12:14 +02:00
|
|
|
const char *key, const char *value, struct config *conf,
|
|
|
|
|
const char *path, unsigned lineno);
|
2019-07-16 11:52:22 +02:00
|
|
|
|
|
|
|
|
/* Maps sections to line parser functions */
|
|
|
|
|
static const parser_fun_t section_parser_map[] = {
|
|
|
|
|
[SECTION_MAIN] = &parse_section_main,
|
2019-07-21 11:31:16 +02:00
|
|
|
[SECTION_COLORS] = &parse_section_colors,
|
2019-07-22 20:15:14 +02:00
|
|
|
[SECTION_CURSOR] = &parse_section_cursor,
|
2019-07-16 11:52:22 +02:00
|
|
|
};
|
|
|
|
|
|
2019-07-17 10:32:22 +02:00
|
|
|
#if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
2019-07-17 10:12:14 +02:00
|
|
|
static const char *const section_names[] = {
|
|
|
|
|
[SECTION_MAIN] = "main",
|
2019-07-21 11:31:16 +02:00
|
|
|
[SECTION_COLORS] = "colors",
|
2019-07-22 20:15:14 +02:00
|
|
|
[SECTION_CURSOR] = "cursor",
|
2019-07-17 10:12:14 +02:00
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
unsigned lineno = 0;
|
2019-07-21 11:46:46 +02:00
|
|
|
char *_line = NULL;
|
2019-07-16 11:52:22 +02:00
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
lineno++;
|
|
|
|
|
|
2019-08-12 19:31:56 +02:00
|
|
|
_line = NULL;
|
2019-07-16 11:52:22 +02:00
|
|
|
size_t count = 0;
|
2019-07-21 11:46:46 +02:00
|
|
|
ssize_t ret = getline(&_line, &count, f);
|
2019-07-16 11:52:22 +02:00
|
|
|
|
|
|
|
|
if (ret < 0) {
|
2019-07-21 11:46:46 +02:00
|
|
|
free(_line);
|
2019-07-16 11:52:22 +02:00
|
|
|
if (errno != 0) {
|
|
|
|
|
LOG_ERRNO("failed to read from configuration");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
/* Strip whitespace */
|
|
|
|
|
char *line = _line;
|
|
|
|
|
{
|
|
|
|
|
while (isspace(*line))
|
|
|
|
|
line++;
|
|
|
|
|
if (line[0] != '\0') {
|
|
|
|
|
char *end = line + strlen(line) - 1;
|
|
|
|
|
while (isspace(*end))
|
|
|
|
|
end--;
|
|
|
|
|
*(end + 1) = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Empty line, or comment */
|
|
|
|
|
if (line[0] == '\0' || line[0] == '#') {
|
|
|
|
|
free(_line);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for new section */
|
2019-07-21 11:31:16 +02:00
|
|
|
if (line[0] == '[') {
|
|
|
|
|
char *end = strchr(line, ']');
|
|
|
|
|
if (end == NULL) {
|
|
|
|
|
LOG_ERR("%s:%d: syntax error: %s", path, lineno, line);
|
2019-07-21 11:46:46 +02:00
|
|
|
goto err;
|
2019-07-21 11:31:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
|
|
if (strcmp(&line[1], "colors") == 0)
|
|
|
|
|
section = SECTION_COLORS;
|
2019-07-22 20:15:14 +02:00
|
|
|
else if (strcmp(&line[1], "cursor") == 0)
|
|
|
|
|
section = SECTION_CURSOR;
|
2019-07-21 11:31:16 +02:00
|
|
|
else {
|
|
|
|
|
LOG_ERR("%s:%d: invalid section name: %s", path, lineno, &line[1]);
|
2019-07-21 11:46:46 +02:00
|
|
|
goto err;
|
2019-07-21 11:31:16 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
free(_line);
|
2019-07-21 11:31:16 +02:00
|
|
|
continue;
|
2019-07-16 11:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-17 10:12:14 +02:00
|
|
|
char *key = strtok(line, "=");
|
|
|
|
|
char *value = strtok(NULL, "\n");
|
|
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
/* Strip trailing whitespace from key (leading stripped earlier) */
|
2019-07-17 10:12:14 +02:00
|
|
|
{
|
2019-07-21 11:46:46 +02:00
|
|
|
assert(!isspace(*key));
|
|
|
|
|
|
2019-07-17 10:12:14 +02:00
|
|
|
char *end = key + strlen(key) - 1;
|
|
|
|
|
while (isspace(*end))
|
|
|
|
|
end--;
|
|
|
|
|
*(end + 1) = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value == NULL) {
|
|
|
|
|
if (key != NULL && strlen(key) > 0 && key[0] != '#') {
|
|
|
|
|
LOG_ERR("%s:%d: syntax error: %s", path, lineno, line);
|
2019-07-21 11:46:46 +02:00
|
|
|
goto err;
|
2019-07-17 10:12:14 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
free(_line);
|
2019-07-17 10:12:14 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
/* Strip leading whitespace from value (trailing stripped earlier) */
|
2019-07-17 10:12:14 +02:00
|
|
|
{
|
|
|
|
|
while (isspace(*value))
|
|
|
|
|
value++;
|
2019-07-21 11:46:46 +02:00
|
|
|
assert(!isspace(*(value + strlen(value) - 1)));
|
2019-07-17 10:12:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key[0] == '#') {
|
2019-07-21 11:46:46 +02:00
|
|
|
free(_line);
|
2019-07-17 10:12:14 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DBG("section=%s, key='%s', value='%s'",
|
|
|
|
|
section_names[section], key, value);
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
parser_fun_t section_parser = section_parser_map[section];
|
|
|
|
|
assert(section_parser != NULL);
|
|
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
if (!section_parser(key, value, conf, path, lineno))
|
|
|
|
|
goto err;
|
2019-07-16 11:52:22 +02:00
|
|
|
|
2019-07-21 11:46:46 +02:00
|
|
|
free(_line);
|
2019-07-16 11:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2019-07-21 11:46:46 +02:00
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
free(_line);
|
|
|
|
|
return false;
|
2019-07-16 11:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-17 10:12:14 +02:00
|
|
|
bool
|
|
|
|
|
config_load(struct config *conf)
|
2019-07-16 11:52:22 +02:00
|
|
|
{
|
2019-07-17 10:12:14 +02:00
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
*conf = (struct config) {
|
2019-07-18 14:29:40 +02:00
|
|
|
.term = strdup("foot"),
|
2019-07-17 09:29:56 +02:00
|
|
|
.shell = get_shell(),
|
2019-08-23 17:26:41 +02:00
|
|
|
.width = -1,
|
|
|
|
|
.height = -1,
|
2019-07-30 18:04:28 +02:00
|
|
|
.fonts = tll_init(),
|
2019-08-01 19:28:14 +02:00
|
|
|
.scrollback_lines = 1000,
|
2019-07-21 11:06:28 +02:00
|
|
|
|
|
|
|
|
.colors = {
|
|
|
|
|
.fg = default_foreground,
|
|
|
|
|
.bg = default_background,
|
|
|
|
|
.regular = {
|
|
|
|
|
default_regular[0],
|
|
|
|
|
default_regular[1],
|
|
|
|
|
default_regular[2],
|
|
|
|
|
default_regular[3],
|
|
|
|
|
default_regular[4],
|
|
|
|
|
default_regular[5],
|
|
|
|
|
default_regular[6],
|
|
|
|
|
default_regular[7],
|
|
|
|
|
},
|
|
|
|
|
.bright = {
|
|
|
|
|
default_bright[0],
|
|
|
|
|
default_bright[1],
|
|
|
|
|
default_bright[2],
|
|
|
|
|
default_bright[3],
|
|
|
|
|
default_bright[4],
|
|
|
|
|
default_bright[5],
|
|
|
|
|
default_bright[6],
|
|
|
|
|
default_bright[7],
|
|
|
|
|
},
|
2019-08-16 22:06:06 +02:00
|
|
|
.alpha = 0xffff,
|
2019-07-21 11:06:28 +02:00
|
|
|
},
|
2019-07-22 20:15:14 +02:00
|
|
|
|
|
|
|
|
.cursor = {
|
|
|
|
|
.style = CURSOR_BLOCK,
|
2019-07-23 18:54:58 +02:00
|
|
|
.color = {
|
|
|
|
|
.text = 0,
|
|
|
|
|
.cursor = 0,
|
|
|
|
|
},
|
2019-07-22 20:15:14 +02:00
|
|
|
},
|
2019-07-29 20:13:26 +02:00
|
|
|
|
|
|
|
|
.render_worker_count = sysconf(_SC_NPROCESSORS_ONLN),
|
2019-07-16 11:52:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
char *path = get_config_path();
|
|
|
|
|
if (path == NULL) {
|
|
|
|
|
/* Default conf */
|
|
|
|
|
LOG_WARN("no configuration found, using defaults");
|
2019-07-22 18:21:25 +02:00
|
|
|
ret = true;
|
2019-07-16 11:52:22 +02:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-12 19:31:21 +02:00
|
|
|
LOG_INFO("loading configuration from %s", path);
|
|
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
FILE *f = fopen(path, "r");
|
|
|
|
|
if (f == NULL) {
|
|
|
|
|
LOG_ERR("%s: failed to open", path);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-17 10:12:14 +02:00
|
|
|
ret = parse_config_file(f, conf, path);
|
2019-07-16 11:52:22 +02:00
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
out:
|
2019-07-30 18:04:28 +02:00
|
|
|
tll_push_back(conf->fonts, strdup("monospace"));
|
2019-07-16 11:52:22 +02:00
|
|
|
free(path);
|
2019-07-17 10:12:14 +02:00
|
|
|
return ret;
|
2019-07-16 11:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
config_free(struct config conf)
|
|
|
|
|
{
|
2019-07-21 11:46:46 +02:00
|
|
|
free(conf.term);
|
2019-07-17 09:29:56 +02:00
|
|
|
free(conf.shell);
|
2019-07-30 18:04:28 +02:00
|
|
|
tll_free_and_free(conf.fonts, free);
|
2019-07-16 11:52:22 +02:00
|
|
|
}
|