From b7e009a98698c4ed81b16cbc274a3b47793c1bab Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 3 Jun 2017 23:02:46 +0200 Subject: Config parser --- artnet.c | 74 +++++++++++++++++++++++++++++++ artnet.h | 10 +++++ backend.c | 43 ++++++++++++++++++ backend.h | 2 + config.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.h | 1 + makefile | 7 ++- midi.c | 3 ++ midi.h | 2 + midimonster.c | 26 ++++++++++- midimonster.h | 16 ++++--- monster.cfg | 3 +- osc.c | 3 ++ osc.h | 2 + 14 files changed, 321 insertions(+), 9 deletions(-) create mode 100644 backend.c create mode 100644 backend.h create mode 100644 config.c create mode 100644 config.h create mode 100644 osc.c create mode 100644 osc.h diff --git a/artnet.c b/artnet.c index e69de29..a245cf1 100644 --- a/artnet.c +++ b/artnet.c @@ -0,0 +1,74 @@ +#include +#include "artnet.h" + +size_t ninstances = 0; +instance* instances = NULL; + +int artnet_init(){ + backend artnet = { + .name = "artnet", + .conf = artnet_configure, + .create = artnet_instance, + .conf_instance = artnet_configure_instance, + .channel = artnet_channel, + .handle = artnet_set, + .process = artnet_handle, + .shutdown = artnet_shutdown + }; + + //register backend + if(!mm_backend_register(artnet)){ + fprintf(stderr, "Failed to register ArtNet backend\n"); + return 1; + } + return 0; +} + +static int artnet_configure(char* option, char* value){ + fprintf(stderr, "ArtNet backend configured: %s -> %s\n", option, value); + return 0; +} + +static instance* artnet_instance(){ + fprintf(stderr, "Creating new ArtNet instance\n"); + instances = realloc(instances, (ninstances + 1) * sizeof(instance)); + if(!instances){ + fprintf(stderr, "Failed to allocate memory\n"); + ninstances = 0; + return NULL; + } + memset(instances + ninstances, 0, sizeof(instance)); + ninstances++; + return instances + (ninstances - 1); +} + +static int artnet_configure_instance(instance* instance, char* option, char* value){ + fprintf(stderr, "ArtNet instance configured: %s -> %s\n", option, value); + return 1; +} + +static channel* artnet_channel(instance* instance, char* spec){ + fprintf(stderr, "Parsing ArtNet channelspec %s\n", spec); + return NULL; +} + +static int artnet_set(size_t num, channel* c, channel_value* v){ + return 1; +} + +static int artnet_handle(size_t num, int* fd, void** data){ + return 1; +} + +static int artnet_shutdown(){ + size_t u; + + for(u = 0; u < ninstances; u++){ + mm_instance_free(instances + u); + } + free(instances); + ninstances = 0; + + fprintf(stderr, "ArtNet backend shut down\n"); + return 0; +} diff --git a/artnet.h b/artnet.h index e69de29..a7742f3 100644 --- a/artnet.h +++ b/artnet.h @@ -0,0 +1,10 @@ +#include "midimonster.h" + +int artnet_init(); +static int artnet_configure(char* option, char* value); +static int artnet_configure_instance(instance* instance, char* option, char* value); +static instance* artnet_instance(); +static channel* artnet_channel(instance* instance, char* spec); +static int artnet_set(size_t num, channel* c, channel_value* v); +static int artnet_handle(size_t num, int* fd, void** data); +static int artnet_shutdown(); diff --git a/backend.c b/backend.c new file mode 100644 index 0000000..e1e143f --- /dev/null +++ b/backend.c @@ -0,0 +1,43 @@ +#include +#include "midimonster.h" +#include "backend.h" + +static size_t nbackends = 0; +static backend* backends = NULL; + +backend* backend_match(char* name){ + size_t u; + for(u = 0; u < nbackends; u++){ + if(!strcmp(backends[u].name, name)){ + return backends + u; + } + } + return NULL; +} + +backend* mm_backend_register(backend b){ + if(!backend_match(b.name)){ + backends = realloc(backends, (nbackends + 1) * sizeof(backend)); + if(!backends){ + fprintf(stderr, "Failed to allocate memory\n"); + nbackends = 0; + return NULL; + } + backends[nbackends] = b; + nbackends++; + + fprintf(stderr, "Registered backend %s\n", b.name); + return backends + (nbackends - 1); + } + return NULL; +} + +int backends_stop(){ + size_t u; + for(u = 0; u < nbackends; u++){ + backends[u].shutdown(); + } + free(backends); + nbackends = 0; + return 0; +} diff --git a/backend.h b/backend.h new file mode 100644 index 0000000..5c844a7 --- /dev/null +++ b/backend.h @@ -0,0 +1,2 @@ +backend* backend_match(char* name); +int backends_stop(); diff --git a/config.c b/config.c new file mode 100644 index 0000000..de6767d --- /dev/null +++ b/config.c @@ -0,0 +1,138 @@ +#include +#include +#include "midimonster.h" +#include "config.h" +#include "backend.h" + +enum { + none, + backend_cfg, + instance_cfg, + map +} parser_state = none; + +backend* current_backend = NULL; +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; +} + +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; + } + + 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++; + + if(parser_state == backend_cfg && current_backend->conf(config_trim_line(line), config_trim_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, config_trim_line(line), config_trim_line(separator))){ + fprintf(stderr, "Failed to configure instance %s\n", current_instance->name); + goto bail; + } + else if(parser_state == map){ + //TODO map two channels + } + } + } + + rv = 0; +bail: + fclose(source); + free(line_raw); + return rv; +} + +void mm_instance_free(instance* inst){ + free(inst->name); + inst->name = NULL; + inst->backend = NULL; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..7cc2a42 --- /dev/null +++ b/config.h @@ -0,0 +1 @@ +int config_read(char* file); diff --git a/makefile b/makefile index dbef918..ec5238e 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,8 @@ LDLIBS = -lasound CFLAGS = -g -Wall -BACKENDS = artnet.o midi.o -OBJS = $(BACKENDS) +BACKENDS = artnet.o midi.o osc.o +OBJS = config.o backend.o $(BACKENDS) midimonster: midimonster.h $(OBJS) @@ -11,3 +11,6 @@ all: midimonster clean: $(RM) midimonster $(RM) $(OBJS) + +run: + valgrind --leak-check=full --show-leak-kinds=all ./midimonster diff --git a/midi.c b/midi.c index e69de29..c817bd2 100644 --- a/midi.c +++ b/midi.c @@ -0,0 +1,3 @@ +int midi_start(){ + return 1; +} diff --git a/midi.h b/midi.h index e69de29..eef2413 100644 --- a/midi.h +++ b/midi.h @@ -0,0 +1,2 @@ +#include "midimonster.h" +int midi_start(); diff --git a/midimonster.c b/midimonster.c index 58166d6..5d7ec7f 100644 --- a/midimonster.c +++ b/midimonster.c @@ -1,4 +1,11 @@ #include "midimonster.h" +#include "config.h" +#include "backend.h" + +//temporary prototypes +int artnet_init(); +int midi_init(); +int osc_init(); int usage(char* fn){ fprintf(stderr, "MIDIMonster v0.1\n"); @@ -8,15 +15,32 @@ int usage(char* fn){ } int main(int argc, char** argv){ + int rv = EXIT_FAILURE; char* cfg_file = DEFAULT_CFG; if(argc > 1){ cfg_file = argv[1]; } //initialize backends + //TODO replace this with loading shared objects + if(artnet_init() /*|| midi_init() || osc_init()*/){ + fprintf(stderr, "Failed to initialize a backend\n"); + goto bail; + } + //read config + if(config_read(cfg_file)){ + fprintf(stderr, "Failed to read configuration file %s\n", cfg_file); + backends_stop(); + return usage(argv[0]); + } + //wait for events + + rv = EXIT_SUCCESS; +bail: //free all data + backends_stop(); - return EXIT_SUCCESS; + return rv; } diff --git a/midimonster.h b/midimonster.h index 59c97eb..8c323f1 100644 --- a/midimonster.h +++ b/midimonster.h @@ -1,3 +1,5 @@ +#ifndef MIDIMONSTER_HEADER +#define MIDIMONSTER_HEADER #include #include #include @@ -8,12 +10,12 @@ struct _channel_value; struct _backend_channel; struct _backend_instance; -typedef int (*mmbackend_handle_event)(struct _backend_channel* c, struct _channel_value v); -typedef struct _backend_channel* (*mmbackend_parse_channel)(char* spec); -typedef int (*mmbackend_configure)(char* option, char* value); +typedef int (*mmbackend_handle_event)(size_t channels, struct _backend_channel* c, struct _channel_value* v); typedef struct _backend_instance* (*mmbackend_create_instance)(); -typedef int (*mmbackend_configure_instance)(char* option, char* value); -typedef int (*mmbackend_process_fd)(int fd, void** impl); +typedef struct _backend_channel* (*mmbackend_parse_channel)(struct _backend_instance* instance, char* spec); +typedef int (*mmbackend_configure)(char* option, char* value); +typedef int (*mmbackend_configure_instance)(struct _backend_instance* instance, char* option, char* value); +typedef int (*mmbackend_process_fd)(size_t fds, int* fd, void** impl); typedef int (*mmbackend_shutdown)(); typedef struct _channel_value { @@ -46,6 +48,7 @@ typedef struct _backend_channel { void* impl; } channel; +//FIXME might be replaced by struct pollfd typedef struct /*_mm_managed_fd*/ { int fd; backend* backend; @@ -55,3 +58,6 @@ typedef struct /*_mm_managed_fd*/ { backend* mm_backend_register(backend b); int mm_manage_fd(int fd, backend* b, int manage, void* impl); int mm_channel_event(channel* c, channel_value v); + +void mm_instance_free(instance* i); +#endif diff --git a/monster.cfg b/monster.cfg index 6391d40..8d3b0ad 100644 --- a/monster.cfg +++ b/monster.cfg @@ -23,4 +23,5 @@ net = 0 uni = 1 [map] - +artnet.231 = lc1.cc5 +artent.231 = osc.f/channel5/ toggle=127 diff --git a/osc.c b/osc.c new file mode 100644 index 0000000..040dd01 --- /dev/null +++ b/osc.c @@ -0,0 +1,3 @@ +int osc_start(){ + return 1; +} diff --git a/osc.h b/osc.h new file mode 100644 index 0000000..6cc321d --- /dev/null +++ b/osc.h @@ -0,0 +1,2 @@ +#include "midimonster.h" +int osc_start(); -- cgit v1.2.3