-
Notifications
You must be signed in to change notification settings - Fork 50
/
midimonster.c
156 lines (137 loc) · 3.56 KB
/
midimonster.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <string.h>
#include <signal.h>
#include <stdarg.h>
#ifndef _WIN32
#define MM_API __attribute__((visibility("default")))
#else
#define MM_API __attribute__((dllexport))
#endif
#define BACKEND_NAME "cli"
#include "midimonster.h"
#include "core/core.h"
#include "core/config.h"
volatile static sig_atomic_t shutdown_requested = 0;
MM_API int log_printf(int level, char* module, char* fmt, ...){
int rv = 0;
va_list args;
va_start(args, fmt);
fprintf(stderr, "%s%s\t", level ? "debug/" : "", module);
rv = vfprintf(stderr, fmt, args);
va_end(args);
return rv;
}
static void signal_handler(int signum){
shutdown_requested = 1;
}
static void version(){
printf("MIDIMonster %s\n", MIDIMONSTER_VERSION);
}
static int usage(char* fn){
version();
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t%s [<options>] <configfile>\n", fn);
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, "\t-v,--version - show version\n");
fprintf(stderr, "\t-b <backend> - override backend options (can be used multiple times)\n");
fprintf(stderr, "\t-i <instance> - override instance options (can be used multiple times)\n");
fprintf(stderr, "\t-h,--help - show this usage info\n");
fprintf(stderr, "\nInstance/Backend options format:\n");
fprintf(stderr, "<instance/backend>.<option>=<value>\n");
return EXIT_FAILURE;
}
static int platform_initialize(){
#ifdef _WIN32
unsigned error_mode = SetErrorMode(0);
SetErrorMode(error_mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
#endif
return 0;
}
static int platform_shutdown(){
#ifdef _WIN32
DWORD processes;
if(GetConsoleProcessList(&processes, 1) == 1){
fprintf(stderr, "\nMIDIMonster is the last process in this console, please press any key to exit\n");
HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(input, 0);
FlushConsoleInputBuffer(input);
WaitForSingleObject(input, INFINITE);
}
#endif
return 0;
}
static int args_parse(int argc, char** argv, char** cfg_file){
size_t u;
for(u = 1; u < argc; u++){
if(!strcmp(argv[u], "-v") || !strcmp(argv[u], "--version")){
version();
return 1;
}
else if(!strcmp(argv[u], "-h") || !strcmp(argv[u], "--help")){
usage(argv[0]);
return 1;
}
else if(!strcmp(argv[u], "-i")){
if(!argv[u + 1]){
fprintf(stderr, "Missing instance override specification\n");
return 1;
}
if(config_add_override(override_instance, argv[u + 1])){
return 1;
}
u++;
}
else if(!strcmp(argv[u], "-b")){
if(!argv[u + 1]){
fprintf(stderr, "Missing backend override specification\n");
return 1;
}
if(config_add_override(override_backend, argv[u + 1])){
return 1;
}
u++;
}
else{
//if nothing else matches, it's probably the configuration file
*cfg_file = argv[u];
}
}
return 0;
}
int main(int argc, char** argv){
int rv = EXIT_FAILURE;
char* cfg_file = DEFAULT_CFG;
//parse commandline arguments
if(args_parse(argc, argv, &cfg_file)){
return EXIT_FAILURE;
}
version();
if(platform_initialize()){
fprintf(stderr, "Failed to perform platform-specific initialization\n");
return EXIT_FAILURE;
}
//initialize backends
if(core_initialize()){
goto bail;
}
//read config
if(config_read(cfg_file)){
fprintf(stderr, "Failed to parse master configuration file %s\n", cfg_file);
core_shutdown();
return (usage(argv[0]) | platform_shutdown());
}
//start core
if(core_start()){
goto bail;
}
signal(SIGINT, signal_handler);
//run the core loop
while(!shutdown_requested){
if(core_iteration()){
goto bail;
}
}
rv = EXIT_SUCCESS;
bail:
core_shutdown();
return rv;
}