aboutsummaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..b416d7a
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,293 @@
+#include "config.h"
+
+#include "buffers.h"
+#include "ccdjit.h"
+#include "common.h"
+#include "ecex.h"
+#include "eval.h"
+#include "util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef int (*ecex_config_init_fn)(ecex_t *ed);
+
+typedef struct host_symbol {
+ const char *name;
+ void *addr;
+} host_symbol_t;
+
+void ecex_print_ccdjit_error(ccdjit_context *ctx) {
+ const ccdjit_diagnostic *diag = ccdjit_context_last_error(ctx);
+
+ if (!diag) {
+ fprintf(stderr, "ccdjit: unknown error\n");
+ return;
+ }
+
+ fprintf(stderr,
+ "ccdjit error [%s] %s:%d:%d: %s\n",
+ diag->phase ? diag->phase : "?",
+ diag->filename ? diag->filename : "<input>",
+ diag->line,
+ diag->column,
+ diag->message ? diag->message : "(no message)");
+
+ if (diag->source_line) fprintf(stderr, "%s\n", diag->source_line);
+ if (diag->caret_line) fprintf(stderr, "%s\n", diag->caret_line);
+}
+
+#define HOST_SYMBOL(fn) { #fn, (void *)(fn) }
+
+static const host_symbol_t host_symbols[] = {
+ HOST_SYMBOL(ecex_current_buffer),
+ HOST_SYMBOL(ecex_create_buffer),
+ HOST_SYMBOL(ecex_find_buffer),
+ HOST_SYMBOL(ecex_switch_buffer),
+ HOST_SYMBOL(ecex_next_buffer),
+ HOST_SYMBOL(ecex_previous_buffer),
+ HOST_SYMBOL(ecex_current_window),
+ HOST_SYMBOL(ecex_window_count),
+ HOST_SYMBOL(ecex_split_window_vertically),
+ HOST_SYMBOL(ecex_split_window_horizontally),
+ HOST_SYMBOL(ecex_other_window),
+ HOST_SYMBOL(ecex_previous_window),
+ HOST_SYMBOL(ecex_delete_window),
+ HOST_SYMBOL(ecex_delete_other_windows),
+ HOST_SYMBOL(ecex_kill_buffer),
+
+ HOST_SYMBOL(ecex_register_command),
+ HOST_SYMBOL(ecex_execute_command),
+ HOST_SYMBOL(ecex_bind_key),
+ HOST_SYMBOL(ecex_lookup_key),
+ HOST_SYMBOL(ecex_define_major_mode),
+ HOST_SYMBOL(ecex_major_mode_by_name),
+ HOST_SYMBOL(ecex_major_mode_name),
+ HOST_SYMBOL(ecex_buffer_set_major_mode),
+ HOST_SYMBOL(ecex_buffer_set_major_mode_by_name),
+ HOST_SYMBOL(ecex_buffer_major_mode_name),
+ HOST_SYMBOL(ecex_bind_mode_key),
+ HOST_SYMBOL(ecex_lookup_key_for_buffer),
+ HOST_SYMBOL(ecex_key_sequence_has_prefix_for_buffer),
+ HOST_SYMBOL(ecex_auto_set_major_mode),
+ HOST_SYMBOL(ecex_list_commands),
+ HOST_SYMBOL(ecex_list_buffers),
+ HOST_SYMBOL(ecex_create_interactive_buffer),
+ HOST_SYMBOL(ecex_interactive_append_line),
+ HOST_SYMBOL(ecex_interactive_activate_current_line),
+ HOST_SYMBOL(ecex_find_file),
+ HOST_SYMBOL(ecex_save_current_buffer),
+ HOST_SYMBOL(ecex_write_current_buffer),
+ HOST_SYMBOL(ecex_request_prompt),
+ HOST_SYMBOL(ecex_clear_prompt_request),
+ HOST_SYMBOL(ecex_complete_command),
+ HOST_SYMBOL(ecex_eval_source),
+ HOST_SYMBOL(ecex_eval_current_buffer),
+ HOST_SYMBOL(ecex_eval_current_line),
+ HOST_SYMBOL(ecex_eval_current_region),
+ HOST_SYMBOL(ecex_eval_file),
+ HOST_SYMBOL(ecex_eval_rerun_last),
+
+ HOST_SYMBOL(ecex_set_font),
+ HOST_SYMBOL(ecex_get_font_size),
+ HOST_SYMBOL(ecex_set_font_size),
+ HOST_SYMBOL(ecex_adjust_font_size),
+ HOST_SYMBOL(ecex_set_bg_color),
+ HOST_SYMBOL(ecex_set_fg_color),
+ HOST_SYMBOL(ecex_set_status_bg_color),
+ HOST_SYMBOL(ecex_set_status_fg_color),
+ HOST_SYMBOL(ecex_set_status_border_color),
+ HOST_SYMBOL(ecex_set_cursor_color),
+ HOST_SYMBOL(ecex_set_region_bg_color),
+ HOST_SYMBOL(ecex_set_minibuffer_bg_color),
+ HOST_SYMBOL(ecex_set_minibuffer_fg_color),
+ HOST_SYMBOL(ecex_set_completion_fg_color),
+ HOST_SYMBOL(ecex_set_completion_enabled),
+ HOST_SYMBOL(ecex_set_interactive_highlight_bg_color),
+ HOST_SYMBOL(ecex_set_interactive_highlight_fg_color),
+
+ HOST_SYMBOL(buffer_clear),
+ HOST_SYMBOL(buffer_set_text),
+ HOST_SYMBOL(buffer_insert),
+ HOST_SYMBOL(buffer_insert_at),
+ HOST_SYMBOL(buffer_append),
+ HOST_SYMBOL(buffer_prepend),
+ HOST_SYMBOL(buffer_insert_char),
+ HOST_SYMBOL(buffer_insert_char_at),
+ HOST_SYMBOL(buffer_delete_range),
+ HOST_SYMBOL(buffer_delete_selection),
+ HOST_SYMBOL(buffer_replace_selection),
+ HOST_SYMBOL(buffer_backspace),
+ HOST_SYMBOL(buffer_delete_forward),
+ HOST_SYMBOL(buffer_kill_line),
+
+ HOST_SYMBOL(buffer_set_point),
+ HOST_SYMBOL(buffer_move_left),
+ HOST_SYMBOL(buffer_move_right),
+ HOST_SYMBOL(buffer_move_up),
+ HOST_SYMBOL(buffer_move_down),
+ HOST_SYMBOL(buffer_move_word_left),
+ HOST_SYMBOL(buffer_move_word_right),
+ HOST_SYMBOL(buffer_move_beginning_of_line),
+ HOST_SYMBOL(buffer_move_end_of_line),
+ HOST_SYMBOL(buffer_move_beginning_of_buffer),
+ HOST_SYMBOL(buffer_move_end_of_buffer),
+
+ HOST_SYMBOL(buffer_set_mark),
+ HOST_SYMBOL(buffer_clear_mark),
+ HOST_SYMBOL(buffer_has_selection),
+ HOST_SYMBOL(buffer_selection_range),
+
+ HOST_SYMBOL(buffer_line_start_at),
+ HOST_SYMBOL(buffer_line_end_at),
+ HOST_SYMBOL(buffer_current_line_start),
+ HOST_SYMBOL(buffer_current_line_end),
+ HOST_SYMBOL(buffer_current_column),
+ HOST_SYMBOL(buffer_current_line_number),
+ HOST_SYMBOL(buffer_line_count),
+ HOST_SYMBOL(buffer_substring),
+ HOST_SYMBOL(buffer_current_line_copy),
+
+ HOST_SYMBOL(buffer_load_file),
+ HOST_SYMBOL(buffer_save),
+ HOST_SYMBOL(buffer_save_as),
+ HOST_SYMBOL(buffer_set_interactive),
+ HOST_SYMBOL(buffer_is_interactive),
+ HOST_SYMBOL(buffer_clear_interactive_actions),
+ HOST_SYMBOL(buffer_add_interactive_action),
+ HOST_SYMBOL(buffer_interactive_action_at_line),
+};
+
+#undef HOST_SYMBOL
+
+int ecex_register_host_symbols(ccdjit_context *ctx) {
+ for (size_t i = 0; i < ECEX_ARRAY_LEN(host_symbols); i++) {
+ if (ccdjit_context_register_symbol(ctx,
+ host_symbols[i].name,
+ host_symbols[i].addr) != 0) {
+ fprintf(stderr, "ecex: failed to register symbol: %s\n", host_symbols[i].name);
+ ecex_print_ccdjit_error(ctx);
+ return ECEX_ERR;
+ }
+ }
+
+ return ECEX_OK;
+}
+
+static int add_include_path(ccdjit_context *ctx, const char *path) {
+ if (ccdjit_context_add_include_path(ctx, path) == 0) return ECEX_OK;
+
+ fprintf(stderr, "ecex: failed to add include path: %s\n", path);
+ ecex_print_ccdjit_error(ctx);
+ return ECEX_ERR;
+}
+
+int ecex_add_ccdjit_include_paths(ccdjit_context *ctx) {
+ if (add_include_path(ctx, "include") != ECEX_OK) return ECEX_ERR;
+ if (add_include_path(ctx, "../include") != ECEX_OK) return ECEX_ERR;
+
+ const char *env_include = getenv("ECEX_INCLUDE");
+ if (env_include && env_include[0]) {
+ if (add_include_path(ctx, env_include) != ECEX_OK) return ECEX_ERR;
+ }
+
+ return ECEX_OK;
+}
+
+static char *make_config_source_with_forced_main(const char *path) {
+ size_t source_size = 0;
+ char *source = ecex_read_entire_file(path, &source_size);
+ if (!source) return NULL;
+
+ const char *forced_main =
+ "\n"
+ "\n"
+ "int main(int argc, char **argv) {\n"
+ " (void)argc;\n"
+ " (void)argv;\n"
+ " return ecex_config_init((ecex_t *)0);\n"
+ "}\n";
+
+ size_t forced_main_len = strlen(forced_main);
+ char *combined = malloc(source_size + forced_main_len + 1);
+ if (!combined) {
+ free(source);
+ return NULL;
+ }
+
+ memcpy(combined, source, source_size);
+ memcpy(combined + source_size, forced_main, forced_main_len + 1);
+
+ free(source);
+ return combined;
+}
+
+int ecex_load_c_config(ecex_t *ed, const char *path) {
+ if (!ed || !path) return ECEX_ERR;
+
+ ccdjit_context *ctx = ccdjit_context_new(NULL);
+ if (!ctx) {
+ fprintf(stderr, "ecex: failed to create ccdjit context\n");
+ return ECEX_ERR;
+ }
+
+ if (ecex_add_ccdjit_include_paths(ctx) != ECEX_OK || ecex_register_host_symbols(ctx) != ECEX_OK) {
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ char *source = make_config_source_with_forced_main(path);
+ if (!source) {
+ fprintf(stderr, "ecex: failed to read or prepare config: %s\n", path);
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ ccdjit_module *module = NULL;
+ if (ccdjit_compile_string(ctx, source, path, &module) != 0) {
+ fprintf(stderr, "ecex: failed to compile config: %s\n", path);
+ ecex_print_ccdjit_error(ctx);
+ free(source);
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ free(source);
+
+ ecex_config_init_fn init =
+ (ecex_config_init_fn)ccdjit_module_symbol(module, "ecex_config_init");
+
+ if (!init) {
+ fprintf(stderr, "ecex: config missing function: ecex_config_init\n");
+ ecex_print_ccdjit_error(ctx);
+ ccdjit_module_free(module);
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ int result = init(ed);
+ if (result != 0) {
+ fprintf(stderr, "ecex: config init failed with code: %d\n", result);
+ ccdjit_module_free(module);
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ if (ecex_keep_jit_module(ed, module) != ECEX_OK) {
+ fprintf(stderr, "ecex: failed to retain config module\n");
+ ccdjit_module_free(module);
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ if (ecex_set_config_path(ed, path) != ECEX_OK) {
+ fprintf(stderr, "ecex: failed to remember config path: %s\n", path);
+ ccdjit_context_free(ctx);
+ return ECEX_ERR;
+ }
+
+ ccdjit_context_free(ctx);
+ fprintf(stderr, "ecex: loaded config: %s\n", path);
+ return ECEX_OK;
+}