#include #include #include "midimonster.h" #include "config.h" #include "backend.h" static enum { none, backend_cfg, instance_cfg, map } parser_state = none; static backend* current_backend = NULL; static instance* current_instance = NULL; static char* config_trim_line(char* in){ ssize_t u; //trim front for(; *in && !isgraph(*in); in++){ } //trim back for(u = strlen(in); u >= 0 && !isgraph(in[u]); u--){ in[u] = 0; } return in; } static int config_map(char* to, char* from){ char* chanspec_to = to, *chanspec_from = from; instance* instance_to = NULL, *instance_from = NULL; channel* channel_from = NULL, *channel_to = NULL; //separate channel spec from instance for(; *chanspec_to && *chanspec_to != '.'; chanspec_to++){ } for(; *chanspec_from && *chanspec_from != '.'; chanspec_from++){ } if(!*chanspec_to || !*chanspec_from){ fprintf(stderr, "Mapping does not contain a proper instance specification\n"); return 1; } //terminate *chanspec_to = *chanspec_from = 0; chanspec_to++; chanspec_from++; //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); return 1; } channel_from = instance_from->backend->channel(instance_from, chanspec_from); channel_to = instance_to->backend->channel(instance_to, chanspec_to); if(!channel_from || !channel_to){ fprintf(stderr, "Failed to parse channel specifications\n"); return 1; } return mm_map_channel(channel_from, channel_to); } int config_read(char* cfg_file){ int rv = 1; size_t line_alloc = 0; ssize_t status; char* line_raw = NULL, *line, *separator; FILE* source = fopen(cfg_file, "r"); if(!source){ fprintf(stderr, "Failed to open configuration file for reading\n"); return 1; } for(status = getline(&line_raw, &line_alloc, source); status >= 0; status = getline(&line_raw, &line_alloc, source)){ line = config_trim_line(line_raw); if(*line == ';' || strlen(line) == 0){ //skip comments continue; } 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); goto bail; } } 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); goto bail; } *separator = 0; separator++; current_backend = backend_match(line); if(!current_backend){ fprintf(stderr, "No such backend %s\n", line); goto bail; } if(instance_match(separator)){ fprintf(stderr, "Duplicate instance name %s\n", separator); goto bail; } current_instance = current_backend->create(); if(!current_instance){ fprintf(stderr, "Failed to instantiate backend %s\n", line); goto bail; } current_instance->name = strdup(separator); current_instance->backend = current_backend; fprintf(stderr, "Created %s instance %s\n", line, separator); } } else{ //pass to parser //find separator for(separator = line; *separator && *separator != '='; separator++){ } if(!*separator){ fprintf(stderr, "No assignment: %s\n", line); goto bail; } *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); goto bail; } 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); goto bail; } else if(parser_state == map){ if(config_map(line, separator)){ fprintf(stderr, "Failed to map channel\n"); goto bail; } } } } rv = 0; bail: fclose(source); free(line_raw); return rv; }