#include "kpl.h" static kpl_config default_config = { .argc = -1, .main_module_arg_index = -1, .argv = NULL, .module_extension = ".kpl", .flags = 0, .io = { .queue_pow = KPL_IO_QUEUE_POW_DEFAULT }, .thread = { .count = -1 } }; void kpl_config_init(kpl_config *config) { memcpy(config, &default_config, sizeof(kpl_config)); } typedef int32_t kpl_arg_match_fn(const char *match_str, const int32_t match_str_index, kpl_config *config); typedef struct { const char *match_str, *help_message; kpl_arg_match_fn *arg_match_fn; } kpl_arg_match; static int32_t kpl_arg_match_module_extension(const char *match_str, const int32_t match_str_index, kpl_config *config) { config->module_extension = match_str + match_str_index; return KPL_EXIT_CODE_SUCCESS; } static int32_t kpl_arg_match_eval(const char *match_str, const int32_t match_str_index, kpl_config *config) { (void) match_str; (void) match_str_index; config->flags |= KPL_CONFIG_FLAG_EVAL; return KPL_EXIT_CODE_SUCCESS; } static int32_t kpl_arg_match_repl(const char *match_str, const int32_t match_str_index, kpl_config *config) { (void) match_str; (void) match_str_index; config->flags |= KPL_CONFIG_FLAG_REPL; return KPL_EXIT_CODE_SUCCESS; } static int32_t kpl_arg_match_io_queue_pow(const char *match_str, const int32_t match_str_index, kpl_config *config) { int32_t queue_pow = atoi(match_str + match_str_index); if (queue_pow < KPL_IO_QUEUE_POW_MIN || queue_pow > KPL_IO_QUEUE_POW_MAX) return KPL_EXIT_CODE_ERROR; config->io.queue_pow = queue_pow; return KPL_EXIT_CODE_SUCCESS; } static int32_t kpl_arg_match_thread_count(const char *match_str, const int32_t match_str_index, kpl_config *config) { int32_t thread_count = atoi(match_str + match_str_index); if (!thread_count) return KPL_EXIT_CODE_ERROR; config->thread.count = thread_count; return KPL_EXIT_CODE_SUCCESS; } static int32_t kpl_arg_match_help(const char *match_str, const int32_t match_str_index, kpl_config *config); static kpl_arg_match arg_match_array[] = { { .match_str = "--module-extension=", .help_message="[WORD], Change the module extension for imports (default .kpl)", .arg_match_fn = kpl_arg_match_module_extension }, { .match_str = "--eval", .help_message = " [STRING...], Evaluate next argument(s) as modules", .arg_match_fn = kpl_arg_match_eval }, { .match_str = "--io-queue-pow=", .help_message = "[NUMBER], Power of two for calculating the size of the io_uring queue", .arg_match_fn = kpl_arg_match_io_queue_pow }, { .match_str = "--thread-count=", .help_message = "[NUMBER], Number of running threads, minimum is 1", .arg_match_fn = kpl_arg_match_thread_count }, { .match_str = "--repl", .help_message = ", Start (R)ead, (E)valuate, (P)rint, (L)oop", .arg_match_fn = kpl_arg_match_repl }, { .match_str = "--help", .help_message = ", Show help", .arg_match_fn = kpl_arg_match_help }, { .match_str = NULL, .help_message = NULL, .arg_match_fn = NULL } }; static int32_t kpl_arg_match_help(const char *match_str, const int32_t match_str_index, kpl_config *config) { (void) match_str; (void) match_str_index; printf("\nUsage " KPL_COLOR(BOLD) "%s" KPL_COLOR(RESET) KPL_COLOR(WHITE) " [OPTIONS] [MODULE]" KPL_COLOR(RESET) KPL_COLOR(BOLD) "%s\n\n" KPL_COLOR(RESET), config->argv[0], config->module_extension); printf("Where " KPL_COLOR(WHITE) "[OPTIONS]" KPL_COLOR(RESET) " are:\n"); const kpl_arg_match *match_array = arg_match_array; while (match_array->match_str) { printf(KPL_COLOR(LIGHT_YELLOW) "\t%s" KPL_COLOR(RESET) "%s\n", match_array->match_str, match_array->help_message); match_array++; } putchar('\n'); return KPL_EXIT_CODE_HELP; } static bool kpl_valid_match_str_index(const char *match_str_array, const char *match_str_arg, int32_t match_str_index) { return match_str_array[match_str_index] && match_str_array[match_str_index] == match_str_arg[match_str_index]; } static bool kpl_valid_match_str(const char *match_str_array, const char *match_str_arg, int32_t match_str_index) { return !match_str_array[match_str_index] && (!match_str_arg[match_str_index] || (match_str_arg[match_str_index] && match_str_array[match_str_index - 1] == '=')); } bool kpl_config_valid_module_exension(kpl_config *config, const char *module_name) { size_t name_length = strlen(module_name), module_extension_length = strlen(config->module_extension); return name_length > module_extension_length && strcmp(module_name + name_length - module_extension_length, config->module_extension) == 0; } int32_t kpl_config_parse_args(kpl_config *config, const int32_t argc, const char *argv[]) { config->argc = argc; config->argv = argv; if (argc == 1) { printf(KPL_COLOR(LIGHT_RED) "\nNo Module Specified\n" KPL_COLOR(RESET)); return kpl_arg_match_help(NULL, 0, config); } int32_t arg_index = 1; while (arg_index < argc && !config->flags) { int32_t match_str_index = 0; const char *match_str_arg = argv[arg_index]; const kpl_arg_match *match_array = arg_match_array; while (match_array->match_str) { while (kpl_valid_match_str_index(match_array->match_str, match_str_arg, match_str_index)) match_str_index++; if (kpl_valid_match_str(match_array->match_str, match_str_arg, match_str_index)) { int32_t exit_status = match_array->arg_match_fn(match_str_arg, match_str_index, config); if (exit_status != KPL_EXIT_CODE_SUCCESS) { if (exit_status == KPL_EXIT_CODE_ERROR) printf(KPL_COLOR(LIGHT_RED) "\nInvalid Option: " KPL_COLOR(BOLD) "%s\n" KPL_COLOR(RESET), match_str_arg); return exit_status; } break; } match_str_index = 0; match_array++; } if (!match_array->match_str) break; arg_index++; } config->main_module_arg_index = arg_index; if (config->flags) { if ((config->flags & KPL_CONFIG_FLAG_EVAL) && argc - arg_index < 1) { printf(KPL_COLOR(LIGHT_RED) "\nInvalid EVAL\n" KPL_COLOR(RESET)); return kpl_arg_match_help(NULL, 0, config); } if ((config->flags & KPL_CONFIG_FLAG_REPL) && argc != arg_index) { printf(KPL_COLOR(LIGHT_RED) "\nInvalid REPL\n" KPL_COLOR(RESET)); return kpl_arg_match_help(NULL, 0, config); } return KPL_EXIT_CODE_SUCCESS; } if (!kpl_config_valid_module_exension(config, argv[arg_index])) { printf(KPL_COLOR(LIGHT_RED) "\nInvalid " KPL_COLOR(RESET) KPL_COLOR(WHITE) "[OPTION]/[MODULE]: " KPL_COLOR(RESET) KPL_COLOR2(BOLD, LIGHT_RED) "%s\n" KPL_COLOR(RESET), argv[arg_index]); return kpl_arg_match_help(NULL, 0, config); } return KPL_EXIT_CODE_SUCCESS; }