From ac494e3f72e397aaf3245b0401bd1b963bd4ebd3 Mon Sep 17 00:00:00 2001 From: koekeishiya Date: Sun, 3 Mar 2019 22:24:14 +0100 Subject: #58 load/include additional config files --- src/parse.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/parse.h | 10 +++++++- src/skhd.c | 30 +++++++++++++--------- 3 files changed, 104 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/parse.c b/src/parse.c index 4e673f4..9f14389 100644 --- a/src/parse.c +++ b/src/parse.c @@ -402,6 +402,32 @@ void parse_option_blacklist(struct parser *parser) } } +void parse_option_load(struct parser *parser, struct token option) +{ + struct token filename_token = parser_previous(parser); + char *filename = copy_string_count(filename_token.text, filename_token.length); + debug("\t%s\n", filename); + + if (*filename != '/') { + char *directory = file_directory(parser->file); + + size_t directory_length = strlen(directory); + size_t filename_length = strlen(filename); + size_t total_length = directory_length + filename_length + 2; + + char *absolutepath = malloc(total_length * sizeof(char)); + snprintf(absolutepath, total_length, "%s/%s", directory, filename); + free(filename); + + filename = absolutepath; + } + + buf_push(parser->load_directives, ((struct load_directive) { + .file = filename, + .option = option + })); +} + void parse_option(struct parser *parser) { parser_match(parser, Token_Option); @@ -414,22 +440,26 @@ void parse_option(struct parser *parser) } else { parser_report_error(parser, option, "expected '[' followed by list of process names\n"); } + } else if (token_equals(option, "load")) { + if (parser_match(parser, Token_String)) { + debug("load :: #%d {\n", option.line); + parse_option_load(parser, option); + debug("}\n"); + } else { + parser_report_error(parser, option, "expected filename\n"); + } } else { parser_report_error(parser, option, "invalid option specified\n"); } } -void parse_config(struct parser *parser) +bool parse_config(struct parser *parser) { struct mode *mode; struct hotkey *hotkey; while (!parser_eof(parser)) { - if (parser->error) { - free_mode_map(parser->mode_map); - free_blacklist(parser->blacklst); - return; - } + if (parser->error) break; if ((parser_check(parser, Token_Identifier)) || (parser_check(parser, Token_Modifier)) || @@ -450,6 +480,14 @@ void parse_config(struct parser *parser) parser_report_error(parser, parser_peek(parser), "expected decl, modifier or key-literal\n"); } } + + if (parser->error) { + free_mode_map(parser->mode_map); + free_blacklist(parser->blacklst); + return false; + } + + return true; } struct hotkey * @@ -550,11 +588,43 @@ void parser_report_error(struct parser *parser, struct token token, const char * parser->error = true; } +void parser_do_directives(struct parser *parser, struct hotloader *hotloader) +{ + bool error = false; + + for (int i = 0; i < buf_len(parser->load_directives); ++i) { + struct load_directive load = parser->load_directives[i]; + + struct parser directive_parser; + if (parser_init(&directive_parser, parser->mode_map, parser->blacklst, load.file)) { + hotloader_add_file(hotloader, load.file); + + if (parse_config(&directive_parser)) { + parser_do_directives(&directive_parser, hotloader); + } else { + error = true; + } + parser_destroy(&directive_parser); + } else { + warn("skhd: could not open file '%s' from load directive #%d:%d\n", load.file, load.option.line, load.option.cursor); + } + + free(load.file); + } + buf_free(parser->load_directives); + + if (error) { + free_mode_map(parser->mode_map); + free_blacklist(parser->blacklst); + } +} + bool parser_init(struct parser *parser, struct table *mode_map, struct table *blacklst, char *file) { memset(parser, 0, sizeof(struct parser)); char *buffer = read_file(file); if (buffer) { + parser->file = file; parser->mode_map = mode_map; parser->blacklst = blacklst; tokenizer_init(&parser->tokenizer, buffer); diff --git a/src/parse.h b/src/parse.h index 95813c2..6576f7a 100644 --- a/src/parse.h +++ b/src/parse.h @@ -4,18 +4,26 @@ #include "tokenize.h" #include +struct load_directive +{ + char *file; + struct token option; +}; + struct table; struct parser { + char *file; struct token previous_token; struct token current_token; struct tokenizer tokenizer; struct table *mode_map; struct table *blacklst; + struct load_directive *load_directives; bool error; }; -void parse_config(struct parser *parser); +bool parse_config(struct parser *parser); struct hotkey *parse_keypress(struct parser *parser); struct token parser_peek(struct parser *parser); diff --git a/src/skhd.c b/src/skhd.c index ceea857..c90c4b6 100644 --- a/src/skhd.c +++ b/src/skhd.c @@ -51,16 +51,33 @@ global struct table mode_map; global struct table blacklst; global char *config_file; +internal HOTLOADER_CALLBACK(config_handler); + internal void parse_config_helper(char *absolutepath) { struct parser parser; if (parser_init(&parser, &mode_map, &blacklst, absolutepath)) { - parse_config(&parser); + hotloader_end(&hotloader); + hotloader_add_file(&hotloader, absolutepath); + + if (parse_config(&parser)) { + parser_do_directives(&parser, &hotloader); + } parser_destroy(&parser); + + if (hotloader_begin(&hotloader, config_handler)) { + debug("skhd: watching files for changes:\n", absolutepath); + for (int i = 0; i < hotloader.watch_count; ++i) { + debug("\t%s\n", hotloader.watch_list[i].file_info.absolutepath); + } + } else { + warn("skhd: could not start watcher.. hotloading is not enabled\n"); + } } else { warn("skhd: could not open file '%s'\n", absolutepath); } + current_mode = table_find(&mode_map, "default"); } @@ -70,7 +87,7 @@ internal HOTLOADER_CALLBACK(config_handler) debug("skhd: config-file has been modified.. reloading config\n"); free_mode_map(&mode_map); free_blacklist(&blacklst); - parse_config_helper(absolutepath); + parse_config_helper(config_file); END_TIMED_BLOCK(); } @@ -254,15 +271,6 @@ int main(int argc, char **argv) event_tap.mask = (1 << kCGEventKeyDown) | (1 << NX_SYSDEFINED); event_tap_begin(&event_tap, key_handler); END_SCOPED_TIMED_BLOCK(); - - BEGIN_SCOPED_TIMED_BLOCK("begin_hotloader"); - if (hotloader_add_file(&hotloader, config_file) && - hotloader_begin(&hotloader, config_handler)) { - debug("skhd: watching '%s' for changes\n", config_file); - } else { - warn("skhd: could not watch '%s'\n", config_file); - } - END_SCOPED_TIMED_BLOCK(); END_SCOPED_TIMED_BLOCK(); CFRunLoopRun(); -- cgit v1.2.3