From 921ce069a4770fbadad7bb4e806361e857469409 Mon Sep 17 00:00:00 2001 From: cbdev Date: Mon, 21 Jun 2021 22:03:17 +0200 Subject: Repository cleanup --- config.c | 708 --------------------------------------------------------------- 1 file changed, 708 deletions(-) delete mode 100644 config.c (limited to 'config.c') diff --git a/config.c b/config.c deleted file mode 100644 index c1c3124..0000000 --- a/config.c +++ /dev/null @@ -1,708 +0,0 @@ -#include -#include -#include -#include -#ifndef _WIN32 -#include -#endif - -#define BACKEND_NAME "core/cfg" -#include "midimonster.h" -#include "config.h" -#include "backend.h" - -static enum { - none, - backend_cfg, - instance_cfg, - map -} parser_state = none; - -typedef enum { - map_ltr, - map_rtl, - map_bidir -} map_type; - -static backend* current_backend = NULL; -static instance* current_instance = NULL; -static size_t noverrides = 0; -static config_override* overrides = NULL; - -#ifdef _WIN32 -#define GETLINE_BUFFER 4096 - -static ssize_t getline(char** line, size_t* alloc, FILE* stream){ - size_t bytes_read = 0; - char c; - //sanity checks - if(!line || !alloc || !stream){ - return -1; - } - - //allocate buffer if none provided - if(!*line || !*alloc){ - *alloc = GETLINE_BUFFER; - *line = calloc(GETLINE_BUFFER, sizeof(char)); - if(!*line){ - fprintf(stderr, "Failed to allocate memory\n"); - return -1; - } - } - - if(feof(stream)){ - return -1; - } - - for(c = fgetc(stream); 1; c = fgetc(stream)){ - //end of buffer, resize - if(bytes_read == (*alloc) - 1){ - *alloc += GETLINE_BUFFER; - *line = realloc(*line, (*alloc) * sizeof(char)); - if(!*line){ - fprintf(stderr, "Failed to allocate memory\n"); - return -1; - } - } - - //store character - (*line)[bytes_read] = c; - - //end of line - if(feof(stream) || c == '\n'){ - //terminate string - (*line)[bytes_read + 1] = 0; - return bytes_read; - } - - //input broken - if(ferror(stream)){ - return -1; - } - - bytes_read++; - } -} -#endif - -static char* config_trim_line(char* in){ - ssize_t n; - //trim front - for(; *in && !isgraph(*in); in++){ - } - - //trim back - for(n = strlen(in); n >= 0 && !isgraph(in[n]); n--){ - in[n] = 0; - } - - return in; -} - -static int config_glob_parse_range(channel_glob* glob, char* spec, size_t length){ - //FIXME might want to allow negative delimiters at some point - char* parse_offset = NULL; - glob->type = glob_range; - - //first interval member - glob->limits.u64[0] = strtoul(spec, &parse_offset, 10); - if(!parse_offset || parse_offset - spec >= length || strncmp(parse_offset, "..", 2)){ - return 1; - } - - parse_offset += 2; - //second interval member - glob->limits.u64[1] = strtoul(parse_offset, &parse_offset, 10); - if(!parse_offset || parse_offset - spec != length || *parse_offset != '}'){ - return 1; - } - - //calculate number of channels within interval - if(glob->limits.u64[0] < glob->limits.u64[1]){ - glob->values = glob->limits.u64[1] - glob->limits.u64[0] + 1; - } - else if(glob->limits.u64[0] > glob->limits.u64[1]){ - glob->values = glob->limits.u64[0] - glob->limits.u64[1] + 1; - } - else{ - glob->values = 1; - } - - return 0; -} - -static int config_glob_parse_list(channel_glob* glob, char* spec, size_t length){ - size_t u = 0; - glob->type = glob_list; - glob->values = 1; - - //count number of values in list - for(u = 0; u < length; u++){ - if(spec[u] == ','){ - glob->values++; - } - } - return 0; -} - -static int config_glob_parse(channel_glob* glob, char* spec, size_t length){ - size_t u = 0; - - //detect glob type - for(u = 0; u < length; u++){ - if(length - u > 2 && !strncmp(spec + u, "..", 2)){ - DBGPF("Detected glob %.*s as range type", (int) length, spec); - return config_glob_parse_range(glob, spec, length); - } - else if(spec[u] == ','){ - DBGPF("Detected glob %.*s as list type", (int) length, spec); - return config_glob_parse_list(glob, spec, length); - } - } - - LOGPF("Failed to detect glob type for spec %.*s", (int) length, spec); - return 1; -} - -static int config_glob_scan(instance* inst, channel_spec* spec){ - char* glob_start = spec->spec, *glob_end = NULL; - size_t u; - - //assume a spec is one channel as default - spec->channels = 1; - - //scan and mark globs - for(glob_start = strchr(glob_start, '{'); glob_start; glob_start = strchr(glob_start, '{')){ - glob_end = strchr(glob_start, '}'); - if(!glob_end){ - fprintf(stderr, "Failed to parse channel spec, unterminated glob: %s\n", spec->spec); - return 1; - } - - spec->glob = realloc(spec->glob, (spec->globs + 1) * sizeof(channel_glob)); - if(!spec->glob){ - fprintf(stderr, "Failed to allocate memory\n"); - return 1; - } - - spec->glob[spec->globs].offset[0] = glob_start - spec->spec; - spec->glob[spec->globs].offset[1] = glob_end - spec->spec; - spec->globs++; - - //skip this opening brace - glob_start++; - } - - //try to parse globs internally - spec->internal = 1; - for(u = 0; u < spec->globs; u++){ - if(config_glob_parse(spec->glob + u, - spec->spec + spec->glob[u].offset[0] + 1, - spec->glob[u].offset[1] - spec->glob[u].offset[0] - 1)){ - spec->internal = 0; - break; - } - } - if(!spec->internal){ - //TODO try to parse globs externally - fprintf(stderr, "Failed to parse glob %" PRIsize_t " in %s internally\n", u + 1, spec->spec); - return 1; - } - - //calculate channel total - for(u = 0; u < spec->globs; u++){ - spec->channels *= spec->glob[u].values; - } - return 0; -} - -static ssize_t config_glob_resolve_range(char* spec, size_t length, channel_glob* glob, uint64_t n){ - uint64_t current_value = glob->limits.u64[0] + (n % glob->values); - //if counting down - if(glob->limits.u64[0] > glob->limits.u64[1]){ - current_value = glob->limits.u64[0] - (n % glob->values); - } - - //write out value - return snprintf(spec, length, "%" PRIu64, current_value); -} - -static ssize_t config_glob_resolve_list(char* spec, size_t length, channel_glob* glob, uint64_t n){ - uint64_t current_replacement = 0; - size_t replacement_length = 0; - char* source = spec + 1; - n %= glob->values; - - //find start of replacement value - DBGPF("Searching instance %" PRIu64 " of spec %.*s", n, (int) length, spec); - for(current_replacement = 0; current_replacement < n; current_replacement++){ - for(; source[0] != ','; source++){ - } - source++; - } - - //calculate replacement length - for(; source[replacement_length] != ',' && source[replacement_length] != '}'; replacement_length++){ - } - - //write out new value - memmove(spec, source, replacement_length); - return replacement_length; -} - -static channel* config_glob_resolve(instance* inst, channel_spec* spec, uint64_t n, uint8_t map_direction){ - size_t glob = 0, glob_length; - ssize_t bytes = 0; - channel* result = NULL; - char* resolved_spec = strdup(spec->spec); - - if(!resolved_spec){ - LOG("Failed to allocate memory"); - return NULL; - } - - //TODO if not internal, try to resolve externally - //iterate and resolve globs - for(glob = spec->globs; glob > 0; glob--){ - glob_length = spec->glob[glob - 1].offset[1] - spec->glob[glob - 1].offset[0]; - - switch(spec->glob[glob - 1].type){ - case glob_range: - bytes = config_glob_resolve_range(resolved_spec + spec->glob[glob - 1].offset[0], - glob_length, - spec->glob + (glob - 1), - n); - break; - case glob_list: - bytes = config_glob_resolve_list(resolved_spec + spec->glob[glob - 1].offset[0], - glob_length, - spec->glob + (glob - 1), - n); - break; - } - - n /= spec->glob[glob - 1].values; - - //move trailing data - if(bytes > 0 && bytes < glob_length){ - memmove(resolved_spec + spec->glob[glob - 1].offset[0] + bytes, - resolved_spec + spec->glob[glob - 1].offset[1] + 1, - strlen(spec->spec) - spec->glob[glob - 1].offset[1]); - } - else{ - LOGPF("Failure parsing glob spec %s", resolved_spec); - goto bail; - } - } - - DBGPF("Resolved spec %s to %s", spec->spec, resolved_spec); - result = inst->backend->channel(inst, resolved_spec, map_direction); - if(spec->globs && !result){ - LOGPF("Failed to match multichannel evaluation %s to a channel", resolved_spec); - } - -bail: - free(resolved_spec); - return result; -} - -static int config_map(char* to_raw, char* from_raw){ - //create a copy because the original pointer may be used multiple times - char* to = strdup(to_raw), *from = strdup(from_raw); - channel_spec spec_to = { - .spec = to - }, spec_from = { - .spec = from - }; - instance* instance_to = NULL, *instance_from = NULL; - channel* channel_from = NULL, *channel_to = NULL; - uint64_t n = 0; - int rv = 1; - - if(!from || !to){ - free(from); - free(to); - fprintf(stderr, "Failed to allocate memory\n"); - return 1; - } - - //separate channel spec from instance - for(; *(spec_to.spec) && *(spec_to.spec) != '.'; spec_to.spec++){ - } - - for(; *(spec_from.spec) && *(spec_from.spec) != '.'; spec_from.spec++){ - } - - if(!spec_from.spec[0] || !spec_to.spec[0]){ - fprintf(stderr, "Mapping does not contain a proper instance specification\n"); - goto done; - } - - //terminate - spec_from.spec[0] = spec_to.spec[0] = 0; - spec_from.spec++; - spec_to.spec++; - - //find matching instances - instance_to = instance_match(to); - instance_from = instance_match(from); - - if(!instance_to || !instance_from){ - fprintf(stderr, "No such instance %s\n", instance_from ? to : from); - goto done; - } - - //scan for globs - if(config_glob_scan(instance_to, &spec_to) - || config_glob_scan(instance_from, &spec_from)){ - goto done; - } - - if((spec_to.channels != spec_from.channels && spec_from.channels != 1 && spec_to.channels != 1) - || spec_to.channels == 0 - || spec_from.channels == 0){ - fprintf(stderr, "Multi-channel specification size mismatch: %s.%s (%" PRIsize_t " channels) - %s.%s (%" PRIsize_t " channels)\n", - instance_from->name, - spec_from.spec, - spec_from.channels, - instance_to->name, - spec_to.spec, - spec_to.channels); - goto done; - } - - //iterate, resolve globs and map - rv = 0; - for(n = 0; !rv && n < max(spec_from.channels, spec_to.channels); n++){ - channel_from = config_glob_resolve(instance_from, &spec_from, min(n, spec_from.channels), mmchannel_input); - channel_to = config_glob_resolve(instance_to, &spec_to, min(n, spec_to.channels), mmchannel_output); - - if(!channel_from || !channel_to){ - rv = 1; - goto done; - } - rv |= mm_map_channel(channel_from, channel_to); - } - -done: - free(spec_from.glob); - free(spec_to.glob); - free(from); - free(to); - return rv; -} - -static int config_line(char* line){ - map_type mapping_type = map_rtl; - char* separator = NULL; - size_t u; - - line = config_trim_line(line); - if(*line == ';' || strlen(line) == 0){ - //skip comments - return 0; - } - if(*line == '[' && line[strlen(line) - 1] == ']'){ - if(!strncmp(line, "[backend ", 9)){ - //backend configuration - parser_state = backend_cfg; - line[strlen(line) - 1] = 0; - current_backend = backend_match(line + 9); - - if(!current_backend){ - fprintf(stderr, "Cannot configure unknown backend %s\n", line + 9); - return 1; - } - - //apply overrides - for(u = 0; u < noverrides; u++){ - if(!overrides[u].handled && overrides[u].type == override_backend - && !strcmp(overrides[u].target, current_backend->name)){ - if(current_backend->conf(overrides[u].option, overrides[u].value)){ - fprintf(stderr, "Configuration override for %s failed for backend %s\n", - overrides[u].option, current_backend->name); - return 1; - } - overrides[u].handled = 1; - } - } - } - else if(!strncmp(line, "[include ", 9)){ - line[strlen(line) - 1] = 0; - return config_read(line + 9); - } - else if(!strcmp(line, "[map]")){ - //mapping configuration - parser_state = map; - } - else{ - //backend instance configuration - parser_state = instance_cfg; - - //trim braces - line[strlen(line) - 1] = 0; - line++; - - //find separating space and terminate - for(separator = line; *separator && *separator != ' '; separator++){ - } - if(!*separator){ - fprintf(stderr, "No instance name specified for backend %s\n", line); - return 1; - } - *separator = 0; - separator++; - - current_backend = backend_match(line); - if(!current_backend){ - fprintf(stderr, "No such backend %s\n", line); - return 1; - } - - if(instance_match(separator)){ - fprintf(stderr, "Duplicate instance name %s\n", separator); - return 1; - } - - //validate instance name - if(strchr(separator, ' ') || strchr(separator, '.')){ - fprintf(stderr, "Invalid instance name %s\n", separator); - return 1; - } - - current_instance = mm_instance(current_backend); - if(!current_instance){ - return 1; - } - - if(current_backend->create(current_instance)){ - fprintf(stderr, "Failed to create %s instance %s\n", line, separator); - return 1; - } - - current_instance->name = strdup(separator); - current_instance->backend = current_backend; - fprintf(stderr, "Created %s instance %s\n", line, separator); - - //apply overrides - for(u = 0; u < noverrides; u++){ - if(!overrides[u].handled && overrides[u].type == override_instance - && !strcmp(overrides[u].target, current_instance->name)){ - if(current_backend->conf_instance(current_instance, overrides[u].option, overrides[u].value)){ - fprintf(stderr, "Configuration override for %s failed for instance %s\n", - overrides[u].option, current_instance->name); - return 1; - } - overrides[u].handled = 1; - } - } - } - } - else if(parser_state == map){ - mapping_type = map_rtl; - //find separator - for(separator = line; *separator && *separator != '<' && *separator != '>'; separator++){ - } - - switch(*separator){ - case '>': - mapping_type = map_ltr; - //fall through - case '<': //default - *separator = 0; - separator++; - break; - case 0: - default: - fprintf(stderr, "Not a channel mapping: %s\n", line); - return 1; - } - - if((mapping_type == map_ltr && *separator == '<') - || (mapping_type == map_rtl && *separator == '>')){ - mapping_type = map_bidir; - separator++; - } - - line = config_trim_line(line); - separator = config_trim_line(separator); - - if(mapping_type == map_ltr || mapping_type == map_bidir){ - if(config_map(separator, line)){ - fprintf(stderr, "Failed to map channel %s to %s\n", line, separator); - return 1; - } - } - if(mapping_type == map_rtl || mapping_type == map_bidir){ - if(config_map(line, separator)){ - fprintf(stderr, "Failed to map channel %s to %s\n", separator, line); - return 1; - } - } - } - else{ - //pass to parser - //find separator - separator = strchr(line, '='); - if(!separator){ - fprintf(stderr, "Not an assignment (currently expecting %s configuration): %s\n", line, (parser_state == backend_cfg) ? "backend" : "instance"); - return 1; - } - - *separator = 0; - separator++; - line = config_trim_line(line); - separator = config_trim_line(separator); - - if(parser_state == backend_cfg && current_backend->conf(line, separator)){ - fprintf(stderr, "Failed to configure backend %s\n", current_backend->name); - return 1; - } - else if(parser_state == instance_cfg && current_backend->conf_instance(current_instance, line, separator)){ - fprintf(stderr, "Failed to configure instance %s\n", current_instance->name); - return 1; - } - } - - return 0; -} - -int config_read(char* cfg_filepath){ - int rv = 1; - size_t line_alloc = 0; - ssize_t status; - FILE* source = NULL; - char* line_raw = NULL; - - //create heap copy of file name because original might be in readonly memory - char* source_dir = strdup(cfg_filepath), *source_file = NULL, original_dir[PATH_MAX * 2] = ""; - #ifdef _WIN32 - char path_separator = '\\'; - #else - char path_separator = '/'; - #endif - - if(!source_dir){ - fprintf(stderr, "Failed to allocate memory\n"); - return 1; - } - - //change working directory to the one containing the configuration file so relative paths work as expected - source_file = strrchr(source_dir, path_separator); - if(source_file){ - *source_file = 0; - source_file++; - - if(!getcwd(original_dir, sizeof(original_dir))){ - fprintf(stderr, "Failed to read current working directory: %s\n", strerror(errno)); - goto bail; - } - - if(chdir(source_dir)){ - fprintf(stderr, "Failed to change to configuration file directory %s: %s\n", source_dir, strerror(errno)); - goto bail; - } - } - else{ - source_file = source_dir; - } - - fprintf(stderr, "Reading configuration file %s\n", cfg_filepath); - source = fopen(source_file, "r"); - - if(!source){ - fprintf(stderr, "Failed to open %s for reading\n", cfg_filepath); - goto bail; - } - - for(status = getline(&line_raw, &line_alloc, source); status >= 0; status = getline(&line_raw, &line_alloc, source)){ - if(config_line(line_raw)){ - goto bail; - } - } - - //TODO check whether all overrides have been applied - - rv = 0; -bail: - //change back to previous directory to allow recursive configuration file parsing - if(source_file && source_dir != source_file){ - chdir(original_dir); - } - - free(source_dir); - if(source){ - fclose(source); - } - free(line_raw); - return rv; -} - -int config_add_override(override_type type, char* data_raw){ - int rv = 1; - //heap a copy because the original data is probably not writable - char* data = strdup(data_raw); - - if(!data){ - fprintf(stderr, "Failed to allocate memory\n"); - goto bail; - } - - char* option = strchr(data, '.'); - char* value = strchr(data, '='); - - if(!option || !value){ - fprintf(stderr, "Override %s is not a valid assignment\n", data_raw); - goto bail; - } - - //terminate strings - *option = 0; - option++; - - *value = 0; - value++; - - config_override new = { - .type = type, - .handled = 0, - .target = strdup(config_trim_line(data)), - .option = strdup(config_trim_line(option)), - .value = strdup(config_trim_line(value)) - }; - - if(!new.target || !new.option || !new.value){ - fprintf(stderr, "Failed to allocate memory\n"); - goto bail; - } - - overrides = realloc(overrides, (noverrides + 1) * sizeof(config_override)); - if(!overrides){ - noverrides = 0; - fprintf(stderr, "Failed to allocate memory\n"); - goto bail; - } - overrides[noverrides] = new; - noverrides++; - - rv = 0; -bail: - free(data); - return rv; -} - -void config_free(){ - size_t u; - - for(u = 0; u < noverrides; u++){ - free(overrides[u].target); - free(overrides[u].option); - free(overrides[u].value); - } - - noverrides = 0; - free(overrides); - overrides = NULL; - - parser_state = none; -} -- cgit v1.2.3