mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-31 07:11:09 -04:00
conf: initial support for configuration file
* Look for configuration file in (in this order): - XDG_CONFIG_HOME/footrc - ~/.config/footrc * Currently supports setting the font
This commit is contained in:
parent
22115e1cf4
commit
0d1b4449b9
4 changed files with 200 additions and 7 deletions
178
config.c
Normal file
178
config.c
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#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"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_section_main(char *line, struct config *conf, const char *path, unsigned lineno)
|
||||||
|
{
|
||||||
|
const char *key = strtok(line, "=");
|
||||||
|
const char *value = strtok(NULL, "\n");
|
||||||
|
|
||||||
|
LOG_DBG("%s:%u: key = %s, value=%s", path, lineno, key, value);
|
||||||
|
|
||||||
|
if (strcmp(key, "font") == 0) {
|
||||||
|
free(conf->font);
|
||||||
|
conf->font = strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
LOG_ERR("%s:%u: invalid key: %s", path, lineno, key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_config_file(FILE *f, struct config *conf, const char *path)
|
||||||
|
{
|
||||||
|
enum section {
|
||||||
|
SECTION_MAIN,
|
||||||
|
} section = SECTION_MAIN;
|
||||||
|
|
||||||
|
/* Function pointer, called for each key/value line */
|
||||||
|
typedef bool (*parser_fun_t)(
|
||||||
|
char *line, struct config *conf, const char *path, unsigned lineno);
|
||||||
|
|
||||||
|
/* Maps sections to line parser functions */
|
||||||
|
static const parser_fun_t section_parser_map[] = {
|
||||||
|
[SECTION_MAIN] = &parse_section_main,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned lineno = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
errno = 0;
|
||||||
|
lineno++;
|
||||||
|
|
||||||
|
char *line = NULL;
|
||||||
|
size_t count = 0;
|
||||||
|
ssize_t ret = getline(&line, &count, f);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
free(line);
|
||||||
|
if (errno != 0) {
|
||||||
|
LOG_ERRNO("failed to read from configuration");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No sections yet */
|
||||||
|
if (line[0] == '[' && line[strlen(line) - 1] == ']') {
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_fun_t section_parser = section_parser_map[section];
|
||||||
|
assert(section_parser != NULL);
|
||||||
|
|
||||||
|
if (!section_parser(line, conf, path, lineno)) {
|
||||||
|
free(line);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct config
|
||||||
|
config_load(void)
|
||||||
|
{
|
||||||
|
struct config conf = {
|
||||||
|
.font = strdup("monospace"),
|
||||||
|
};
|
||||||
|
|
||||||
|
char *path = get_config_path();
|
||||||
|
LOG_INFO("loading configuration from %s", path);
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
/* Default conf */
|
||||||
|
LOG_WARN("no configuration found, using defaults");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
LOG_ERR("%s: failed to open", path);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_config_file(f, &conf, path);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path);
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
config_free(struct config conf)
|
||||||
|
{
|
||||||
|
free(conf.font);
|
||||||
|
}
|
||||||
8
config.h
Normal file
8
config.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct config {
|
||||||
|
char *font;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config config_load(void);
|
||||||
|
void config_free(struct config conf);
|
||||||
20
main.c
20
main.c
|
|
@ -19,15 +19,16 @@
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "selection.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "vt.h"
|
#include "vt.h"
|
||||||
#include "selection.h"
|
|
||||||
|
|
||||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
@ -264,12 +265,14 @@ main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
int ret = EXIT_FAILURE;
|
int ret = EXIT_FAILURE;
|
||||||
|
|
||||||
|
struct config conf = config_load();
|
||||||
|
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
{"font", required_argument, 0, 'f'},
|
{"font", required_argument, 0, 'f'},
|
||||||
{NULL, no_argument, 0, 0},
|
{NULL, no_argument, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *font_name = "monospace";
|
//const char *font_name = "monospace";
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int c = getopt_long(argc, argv, ":f:h", longopts, NULL);
|
int c = getopt_long(argc, argv, ":f:h", longopts, NULL);
|
||||||
|
|
@ -278,7 +281,8 @@ main(int argc, char *const *argv)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
font_name = optarg;
|
free(conf.font);
|
||||||
|
conf.font = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
@ -340,19 +344,19 @@ main(int argc, char *const *argv)
|
||||||
thrd_t keyboard_repeater_id;
|
thrd_t keyboard_repeater_id;
|
||||||
thrd_create(&keyboard_repeater_id, &keyboard_repeater, &term);
|
thrd_create(&keyboard_repeater_id, &keyboard_repeater, &term);
|
||||||
|
|
||||||
term.fonts[0] = font_from_name(font_name);
|
term.fonts[0] = font_from_name(conf.font);
|
||||||
if (term.fonts[0] == NULL)
|
if (term.fonts[0] == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
{
|
{
|
||||||
char fname[1024];
|
char fname[1024];
|
||||||
snprintf(fname, sizeof(fname), "%s:style=bold", font_name);
|
snprintf(fname, sizeof(fname), "%s:style=bold", conf.font);
|
||||||
term.fonts[1] = font_from_name(fname);
|
term.fonts[1] = font_from_name(fname);
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s:style=italic", font_name);
|
snprintf(fname, sizeof(fname), "%s:style=italic", conf.font);
|
||||||
term.fonts[2] = font_from_name(fname);
|
term.fonts[2] = font_from_name(fname);
|
||||||
|
|
||||||
snprintf(fname, sizeof(fname), "%s:style=bold italic", font_name);
|
snprintf(fname, sizeof(fname), "%s:style=bold italic", conf.font);
|
||||||
term.fonts[3] = font_from_name(fname);
|
term.fonts[3] = font_from_name(fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -703,6 +707,8 @@ out:
|
||||||
close(term.kbd.repeat.pipe_read_fd);
|
close(term.kbd.repeat.pipe_read_fd);
|
||||||
close(term.kbd.repeat.pipe_write_fd);
|
close(term.kbd.repeat.pipe_write_fd);
|
||||||
|
|
||||||
|
config_free(conf);
|
||||||
|
|
||||||
cairo_debug_reset_static_data();
|
cairo_debug_reset_static_data();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ endforeach
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'foot',
|
'foot',
|
||||||
|
'config.c', 'config.h',
|
||||||
'commands.c', 'commands.h',
|
'commands.c', 'commands.h',
|
||||||
'csi.c', 'csi.h',
|
'csi.c', 'csi.h',
|
||||||
'font.c', 'font.h',
|
'font.c', 'font.h',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue