add config file implementation
This commit is contained in:
parent
f4aa263368
commit
c85bbd8f09
296
src/config.c
296
src/config.c
@ -1,10 +1,15 @@
|
||||
#include "config.h"
|
||||
#include "wm.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void wm_cfg_init_def(Config *config)
|
||||
{
|
||||
@ -104,39 +109,308 @@ void wm_configfile_init(ConfigFile *config, const char *filename)
|
||||
assert(filename);
|
||||
|
||||
strncpy(config->file_path, filename, PATH_MAX);
|
||||
const size_t size = CONFIG_ARGC_MAX*CONFIG_ARGLEN_MAX;
|
||||
|
||||
ConfigCommand commands[] = {
|
||||
(ConfigCommand) {.string = "border_color", .arg_count = 1},
|
||||
(ConfigCommand) {.string = "focused_border_color", .arg_count = 1},
|
||||
(ConfigCommand) {.string = "border_width", .arg_count = 1},
|
||||
(ConfigCommand) {.string = "keybind", .arg_count = 0},
|
||||
(ConfigCommand) {.string = "focus_on_motion", .arg_count = 1},
|
||||
(ConfigCommand) {.string = "border_color", .arg_count = 1,
|
||||
.cfg_var_offset[0] = offsetof(Config, border_col),
|
||||
.argc = 0},
|
||||
|
||||
(ConfigCommand) {.string = "focused_border_color", .arg_count = 1,
|
||||
.cfg_var_offset[0] = offsetof(Config, focused_border_col),
|
||||
.argc = 0},
|
||||
|
||||
(ConfigCommand) {.string = "border_width", .arg_count = 1,
|
||||
.cfg_var_offset[0] = offsetof(Config, border_width),
|
||||
.argc = 0},
|
||||
|
||||
(ConfigCommand) {.string = "keybind", .arg_count = 0,
|
||||
.cfg_var_offset[0] = -1,
|
||||
.argc = 0},
|
||||
|
||||
(ConfigCommand) {.string = "focus_on_motion", .arg_count = 1,
|
||||
.cfg_var_offset[0] = offsetof(Config, focus_on_motion),
|
||||
.argc = 0},
|
||||
};
|
||||
|
||||
config->command_count = sizeof(commands) / sizeof (commands[0]);
|
||||
config->available_commands = calloc(sizeof(commands), 0);
|
||||
DEBUG_PRINT("command_count: %ld\n", config->command_count);
|
||||
for (size_t i = 0; i < config->command_count; i++) {
|
||||
wm_configcommand_init(&commands[i]);
|
||||
}
|
||||
|
||||
config->available_commands = calloc(config->command_count, sizeof(ConfigCommand));
|
||||
memcpy(config->available_commands, commands, sizeof(commands));
|
||||
}
|
||||
|
||||
void wm_configfile_read(ConfigFile *config)
|
||||
void wm_configfile_free(ConfigFile *config)
|
||||
{
|
||||
for (size_t i = 0; i < config->command_count; i++) {
|
||||
wm_configcommand_free(&config->available_commands[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void wm_configfile_read(ConfigFile *cfile, Config *config)
|
||||
{
|
||||
assert(config);
|
||||
assert(cfile);
|
||||
|
||||
FILE *fp = fopen(config->file_path, "r");
|
||||
FILE *fp = fopen(cfile->file_path, "r");
|
||||
|
||||
if (!fp) {
|
||||
fprintf(stderr, "wm: could not open config file: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const int max_line_len = 4096;
|
||||
const int max_line_len = 8192;
|
||||
char line[max_line_len];
|
||||
char argv[CONFIG_ARGC_MAX][CONFIG_ARGLEN_MAX];
|
||||
size_t line_index = 0;
|
||||
ConfigCommand command = {0};
|
||||
wm_configcommand_init(&command);
|
||||
|
||||
while(fgets(line, max_line_len, fp) != NULL) {
|
||||
// comment
|
||||
if (line[0] == '#')
|
||||
line_index++;
|
||||
|
||||
ParserResult result = wm_configfile_parse_line(cfile, config, line, &command);
|
||||
if (!result.success) {
|
||||
fprintf(stderr, "wm: could not parse line %ld of config file %s: %s\n",
|
||||
line_index, cfile->file_path, result.message);
|
||||
continue;
|
||||
}
|
||||
|
||||
wm_configcommand_argv_parse(&command);
|
||||
wm_config_apply_command(config, &command);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
wm_configcommand_free(&command);
|
||||
}
|
||||
|
||||
void wm_config_apply_command(Config *config, ConfigCommand *command)
|
||||
{
|
||||
void *arg = NULL;
|
||||
|
||||
switch (command->arg_type) {
|
||||
case TYPE_INTEGER:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
*(int*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].i;
|
||||
}
|
||||
return;
|
||||
case TYPE_UNSIGNED_INTEGER:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
*(unsigned int*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].ui;
|
||||
}
|
||||
return;
|
||||
case TYPE_BOOL:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
*(bool*)((char*)config + (command->cfg_var_offset[i])) = command->args[i].i;
|
||||
}
|
||||
return;
|
||||
case TYPE_KEYBIND:
|
||||
// TODO
|
||||
wm_config_parse_bind_command(command);
|
||||
case TYPE_STRING:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX);
|
||||
memcpy((char*)(config + (command->cfg_var_offset)[i]), command->argv[i], len);
|
||||
}
|
||||
return;
|
||||
case TYPE_FLOAT:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
*(float*)((char*)config + (command->cfg_var_offset[i])) = atof(command->argv[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config,
|
||||
char* line, ConfigCommand *command)
|
||||
{
|
||||
char *token = strtok(line, " ");
|
||||
bool matched_command = false;
|
||||
ParserResult result;
|
||||
|
||||
// comment
|
||||
if (line[0] == '#')
|
||||
return (ParserResult) {.success = true, .message = ""};
|
||||
|
||||
// empty line
|
||||
if (line[0] == '\n')
|
||||
return (ParserResult) {.success = true, .message = ""};
|
||||
|
||||
// try to match command
|
||||
for (size_t i = 0; i < cfile->command_count; i++) {
|
||||
if (strncmp(cfile->available_commands[i].string, token,
|
||||
CONFIG_COMMAND_MAX_LEN) == 0) {
|
||||
wm_configcommand_copy(command, &cfile->available_commands[i]);
|
||||
matched_command = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched_command) {
|
||||
PARSER_RETURN(result, false, "Unknown config command: %s\n", token);
|
||||
}
|
||||
|
||||
DEBUG_PRINT("matched command: %s\n", command->string);
|
||||
|
||||
// read arguments
|
||||
while (true) {
|
||||
token = strtok(NULL, " ");
|
||||
DEBUG_PRINT("token: %s\n", token);
|
||||
|
||||
if (token != NULL) {
|
||||
command->argc++;
|
||||
|
||||
if (strnlen(token, CONFIG_ARGLEN_MAX) == CONFIG_ARGLEN_MAX) {
|
||||
PARSER_RETURN(result, false,
|
||||
"Argument length exceeded maximum of %d characters\n",
|
||||
CONFIG_ARGLEN_MAX);
|
||||
}
|
||||
|
||||
if (command->argc >= CONFIG_ARGC_MAX) {
|
||||
PARSER_RETURN(result, false,
|
||||
"Maximum number of arguments (%d) exceeded\n",
|
||||
CONFIG_ARGC_MAX);
|
||||
}
|
||||
|
||||
if (command->argc > command->arg_count) {
|
||||
PARSER_RETURN(result, false, "Too many arguments to command %s\n",
|
||||
command->string);
|
||||
}
|
||||
|
||||
strncpy(command->argv[command->argc-1], token, CONFIG_ARGLEN_MAX);
|
||||
}
|
||||
|
||||
// end of args
|
||||
if (token == NULL) {
|
||||
if (command->argc < command->arg_count) {
|
||||
PARSER_RETURN(result, false, "Missing arguments from command %s\n",
|
||||
command->string);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (ParserResult) {.success = true, .message = ""};
|
||||
}
|
||||
|
||||
void wm_configcommand_init(ConfigCommand *command)
|
||||
{
|
||||
assert(command);
|
||||
|
||||
command->argv = calloc(CONFIG_ARGC_MAX, sizeof(void*));
|
||||
command->args = calloc(CONFIG_ARGC_MAX, sizeof(Arg));
|
||||
|
||||
for (size_t i = 0; i < CONFIG_ARGC_MAX; i++) {
|
||||
command->argv[i] = calloc(CONFIG_ARGLEN_MAX, 1);
|
||||
command->args[i].s = calloc(CONFIG_ARGLEN_MAX, 1);
|
||||
command->args[i].sl = calloc(CONFIG_ARGC_MAX, sizeof(char*));
|
||||
|
||||
for (size_t j = 0; j < CONFIG_ARGC_MAX; j++) {
|
||||
command->args[i].sl[j] = calloc(CONFIG_ARGLEN_MAX, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wm_configcommand_copy(ConfigCommand *dest, const ConfigCommand *src)
|
||||
{
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
memcpy(dest->string, src->string, CONFIG_COMMAND_MAX_LEN);
|
||||
dest->arg_count = src->arg_count;
|
||||
memcpy(dest->cfg_var_offset, src->cfg_var_offset, CONFIG_ARGC_MAX*sizeof(off_t));
|
||||
dest->arg_type = src->arg_type;
|
||||
dest->argc = src->argc;
|
||||
|
||||
for (size_t i = 0; i < CONFIG_ARGC_MAX; i++) {
|
||||
memcpy(dest->argv[i], src->argv[i], CONFIG_ARGLEN_MAX);
|
||||
memcpy(dest->args[i].s, src->args[i].s, CONFIG_ARGLEN_MAX);
|
||||
|
||||
for (size_t j = 0; j < CONFIG_ARGC_MAX; j++) {
|
||||
memcpy(dest->args[i].sl[j], src->args[i].sl[j], CONFIG_ARGLEN_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wm_configcommand_argv_parse(ConfigCommand *command)
|
||||
{
|
||||
switch (command->arg_type) {
|
||||
case TYPE_INTEGER:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
command->args[i].i = atoi(command->argv[i]);
|
||||
}
|
||||
return;
|
||||
case TYPE_UNSIGNED_INTEGER:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
command->args[i].ui = atoi(command->argv[i]);
|
||||
}
|
||||
return;
|
||||
case TYPE_BOOL:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
command->args[i].i = atobool(command->argv[i]);
|
||||
}
|
||||
return;
|
||||
case TYPE_KEYBIND:
|
||||
// todo
|
||||
wm_config_parse_bind_command(command);
|
||||
case TYPE_STRING:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
size_t len = strnlen(command->argv[i], CONFIG_ARGLEN_MAX);
|
||||
command->args[i].count = len;
|
||||
memcpy(command->args[i].s, command->argv[i], len);
|
||||
}
|
||||
return;
|
||||
case TYPE_FLOAT:
|
||||
for (size_t i = 0; i < command->argc; i++) {
|
||||
command->args[i].f = atof(command->argv[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void wm_configcommand_free(ConfigCommand *command)
|
||||
{
|
||||
assert(command);
|
||||
|
||||
command->argc = 0;
|
||||
|
||||
for (size_t i = 0; i < CONFIG_ARGC_MAX; i++) {
|
||||
free(command->argv[i]);
|
||||
free(command->args[i].s);
|
||||
|
||||
for (size_t j = 0; j < CONFIG_ARGC_MAX; j++) {
|
||||
free(command->args[i].sl[j]);
|
||||
}
|
||||
|
||||
free(command->args[i].sl);
|
||||
}
|
||||
|
||||
free(command->argv);
|
||||
free(command->args);
|
||||
}
|
||||
|
||||
bool atobool(char *arr)
|
||||
{
|
||||
for (size_t i = 0; i <strnlen(arr, CONFIG_ARGLEN_MAX); i++) {
|
||||
arr[i] = tolower(arr[i]);
|
||||
}
|
||||
|
||||
if ((strncmp(arr, "true", CONFIG_ARGLEN_MAX) == 0) ||
|
||||
(strncmp(arr, "yes", CONFIG_ARGLEN_MAX) == 0))
|
||||
return true;
|
||||
|
||||
if ((strncmp(arr, "false", CONFIG_ARGLEN_MAX) == 0) ||
|
||||
(strncmp(arr, "no", CONFIG_ARGLEN_MAX) == 0))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO
|
||||
Keybind wm_config_parse_bind_command(ConfigCommand *command)
|
||||
{
|
||||
|
||||
}
|
||||
|
43
src/config.h
43
src/config.h
@ -5,8 +5,17 @@
|
||||
#include <stdbool.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/X.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define CONFIG_COMMAND_MAX_LEN 128
|
||||
#define CONFIG_PARSERRESULT_MAX 1024
|
||||
#define CONFIG_ARGC_MAX 16
|
||||
#define CONFIG_ARGLEN_MAX 256
|
||||
|
||||
#define PARSER_RETURN(result, _success, fmt, ...) \
|
||||
do { (result).success = (_success); \
|
||||
snprintf((result).message, CONFIG_PARSERRESULT_MAX, \
|
||||
(fmt), ##__VA_ARGS__); return (result);} while (0);
|
||||
|
||||
typedef struct Client Client;
|
||||
typedef struct Wm Wm;
|
||||
@ -16,6 +25,7 @@ typedef struct Keybind Keybind;
|
||||
struct Arg {
|
||||
int i;
|
||||
unsigned int ui;
|
||||
float f;
|
||||
Client *c;
|
||||
char* s;
|
||||
char **sl;
|
||||
@ -30,9 +40,28 @@ struct Keybind {
|
||||
Arg args;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TYPE_INTEGER,
|
||||
TYPE_UNSIGNED_INTEGER,
|
||||
TYPE_BOOL,
|
||||
TYPE_STRING,
|
||||
TYPE_KEYBIND,
|
||||
TYPE_FLOAT,
|
||||
} CommandArgType;
|
||||
|
||||
typedef struct {
|
||||
bool success;
|
||||
char message[CONFIG_PARSERRESULT_MAX];
|
||||
} ParserResult;
|
||||
|
||||
typedef struct {
|
||||
char string[CONFIG_COMMAND_MAX_LEN];
|
||||
size_t arg_count;
|
||||
off_t cfg_var_offset[CONFIG_ARGC_MAX];
|
||||
CommandArgType arg_type;
|
||||
size_t argc;
|
||||
char **argv;
|
||||
Arg *args;
|
||||
} ConfigCommand;
|
||||
|
||||
typedef struct {
|
||||
@ -45,7 +74,7 @@ typedef struct {
|
||||
float ms_p;
|
||||
char *border_col;
|
||||
char *focused_border_col;
|
||||
unsigned char border_width;
|
||||
unsigned int border_width;
|
||||
Keybind *keybinds;
|
||||
int kb_count;
|
||||
bool focus_on_motion;
|
||||
@ -54,6 +83,16 @@ typedef struct {
|
||||
void wm_cfg_init_def(Config *config);
|
||||
void wm_keybinds_init_def(Config *config);
|
||||
void wm_configfile_init(ConfigFile *config, const char *path);
|
||||
void wm_configfile_read(ConfigFile *config);
|
||||
void wm_configfile_free(ConfigFile *config);
|
||||
void wm_configfile_read(ConfigFile *cfile, Config *config);
|
||||
void wm_config_apply_command(Config *config, ConfigCommand *command);
|
||||
ParserResult wm_configfile_parse_line(const ConfigFile *cfile, Config *config,
|
||||
char* line, ConfigCommand *command);
|
||||
void wm_configcommand_init(ConfigCommand *command);
|
||||
void wm_configcommand_copy(ConfigCommand *dest, const ConfigCommand *src);
|
||||
void wm_configcommand_argv_parse(ConfigCommand *command);
|
||||
void wm_configcommand_free(ConfigCommand *command);
|
||||
bool atobool(char *arr);
|
||||
Keybind wm_config_parse_bind_command(ConfigCommand *command);
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user