mirror of
https://github.com/onyx-and-iris/vmrcli.git
synced 2026-04-09 21:03:32 +00:00
add context struct, use it to pass around config + vmr object.
add length bound formatting to the token trace logging. patch bump
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
* @author Vincent Burel, Onyx and Iris (code@onyxandiris.online)
|
* @author Vincent Burel, Onyx and Iris (code@onyxandiris.online)
|
||||||
* @brief Functions for initializing the iVMR interface.
|
* @brief Functions for initializing the iVMR interface.
|
||||||
* Defines a single public function that returns a pointer to the interface.
|
* Defines a single public function that returns a pointer to the interface.
|
||||||
* @version 0.14.0
|
* @version 0.14.1
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Vincent Burel(c)2015-2021 All Rights Reserved
|
* @copyright Vincent Burel(c)2015-2021 All Rights Reserved
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @file util.c
|
* @file util.c
|
||||||
* @author Onyx and Iris (code@onyxandiris.online)
|
* @author Onyx and Iris (code@onyxandiris.online)
|
||||||
* @brief Utility functions.
|
* @brief Utility functions.
|
||||||
* @version 0.14.0
|
* @version 0.14.1
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2024
|
* @copyright Copyright (c) 2024
|
||||||
|
|||||||
132
src/vmrcli.c
132
src/vmrcli.c
@@ -2,7 +2,7 @@
|
|||||||
* @file vmrcli.c
|
* @file vmrcli.c
|
||||||
* @author Onyx and Iris (code@onyxandiris.online)
|
* @author Onyx and Iris (code@onyxandiris.online)
|
||||||
* @brief A Voicemeeter Remote Command Line Interface
|
* @brief A Voicemeeter Remote Command Line Interface
|
||||||
* @version 0.14.0
|
* @version 0.14.1
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2024
|
* @copyright Copyright (c) 2024
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
#define RES_SZ 512 /* Size of the buffer passed to VBVMR_GetParameterStringW */
|
#define RES_SZ 512 /* Size of the buffer passed to VBVMR_GetParameterStringW */
|
||||||
#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
|
#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
|
||||||
#define DELIMITERS " \t;,"
|
#define DELIMITERS " \t;,"
|
||||||
#define VERSION "0.14.0"
|
#define VERSION "0.14.1"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum The kind of values a get call may return.
|
* @enum The kind of values a get call may return.
|
||||||
@@ -64,16 +64,9 @@ struct result
|
|||||||
} val;
|
} val;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool eflag = false;
|
/**
|
||||||
|
* @struct A struct to hold the program configuration, set by CLI args
|
||||||
static void terminate(PT_VMR vmr, char *msg);
|
*/
|
||||||
static void usage();
|
|
||||||
static enum kind set_kind(char *kval);
|
|
||||||
static void interactive(PT_VMR vmr, bool with_prompt, char *delimiters);
|
|
||||||
static void parse_input(PT_VMR vmr, char *input, char *delimiters);
|
|
||||||
static void parse_command(PT_VMR vmr, char *command);
|
|
||||||
static void get(PT_VMR vmr, char *command, struct result *res);
|
|
||||||
|
|
||||||
struct config_t {
|
struct config_t {
|
||||||
bool mflag;
|
bool mflag;
|
||||||
bool sflag;
|
bool sflag;
|
||||||
@@ -82,10 +75,27 @@ struct config_t {
|
|||||||
bool iflag;
|
bool iflag;
|
||||||
bool with_prompt;
|
bool with_prompt;
|
||||||
bool fflag;
|
bool fflag;
|
||||||
|
bool eflag;
|
||||||
int log_level;
|
int log_level;
|
||||||
enum kind kind;
|
enum kind kind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct A struct to hold the program context, including the config and the iVMR interface pointer
|
||||||
|
*/
|
||||||
|
struct context_t {
|
||||||
|
struct config_t config;
|
||||||
|
PT_VMR vmr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void terminate(PT_VMR vmr, char *msg);
|
||||||
|
static void usage();
|
||||||
|
static enum kind set_kind(char *kval);
|
||||||
|
static void interactive(const struct context_t *context, char *delimiters);
|
||||||
|
static void parse_input(const struct context_t *context, char *input, char *delimiters);
|
||||||
|
static void parse_command(const struct context_t *context, char *command);
|
||||||
|
static void get(PT_VMR vmr, char *command, struct result *res);
|
||||||
|
|
||||||
int get_options(struct config_t *config, int argc, char *argv[])
|
int get_options(struct config_t *config, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
static const struct option options[] =
|
static const struct option options[] =
|
||||||
@@ -104,11 +114,6 @@ int get_options(struct config_t *config, int argc, char *argv[])
|
|||||||
{NULL, 0, NULL, 0 }
|
{NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
config->iflag = false;
|
|
||||||
config->mflag = false;
|
|
||||||
config->sflag = false;
|
|
||||||
config->cflag = false;
|
|
||||||
config->fflag = false;
|
|
||||||
config->with_prompt = true;
|
config->with_prompt = true;
|
||||||
config->log_level = LOG_WARN;
|
config->log_level = LOG_WARN;
|
||||||
config->kind = BANANAX64;
|
config->kind = BANANAX64;
|
||||||
@@ -170,7 +175,7 @@ int get_options(struct config_t *config, int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
eflag = true;
|
config->eflag = true;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
log_fatal("unknown option -- '%c'\n"
|
log_fatal("unknown option -- '%c'\n"
|
||||||
@@ -193,78 +198,73 @@ int get_options(struct config_t *config, int argc, char *argv[])
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct config_t config;
|
struct context_t context = {0};
|
||||||
int optind = get_options(&config, argc, argv);
|
int optind = get_options(&context.config, argc, argv);
|
||||||
|
|
||||||
if (argc == 1)
|
log_set_level(context.config.log_level);
|
||||||
{
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
log_set_level(config.log_level);
|
context.vmr = create_interface();
|
||||||
|
if (context.vmr == NULL)
|
||||||
PT_VMR vmr = create_interface();
|
|
||||||
if (vmr == NULL)
|
|
||||||
{
|
{
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
long rep = login(vmr, config.kind);
|
long rep = login(context.vmr, context.config.kind);
|
||||||
if (rep != 0)
|
if (rep != 0)
|
||||||
{
|
{
|
||||||
if (rep == -2)
|
if (rep == -2)
|
||||||
terminate(vmr, "Timeout logging into the API.");
|
terminate(context.vmr, "Timeout logging into the API.");
|
||||||
else
|
else
|
||||||
terminate(vmr, "Error logging into the Voicemeeter API");
|
terminate(context.vmr, "Error logging into the Voicemeeter API");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.mflag)
|
if (context.config.mflag)
|
||||||
{
|
{
|
||||||
run_voicemeeter(vmr, MACROBUTTONS);
|
run_voicemeeter(context.vmr, MACROBUTTONS);
|
||||||
log_info("MacroButtons app launched");
|
log_info("MacroButtons app launched");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.sflag)
|
if (context.config.sflag)
|
||||||
{
|
{
|
||||||
run_voicemeeter(vmr, STREAMERVIEW);
|
run_voicemeeter(context.vmr, STREAMERVIEW);
|
||||||
log_info("StreamerView app launched");
|
log_info("StreamerView app launched");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.cflag)
|
if (context.config.cflag)
|
||||||
{
|
{
|
||||||
set_parameter_string(vmr, "command.load", config.cvalue);
|
set_parameter_string(context.vmr, "command.load", context.config.cvalue);
|
||||||
log_info("Profile %s loaded", config.cvalue);
|
log_info("Profile %s loaded", context.config.cvalue);
|
||||||
Sleep(300);
|
Sleep(300);
|
||||||
clear(vmr, is_pdirty);
|
clear(context.vmr, is_pdirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *delimiter_ptr = DELIMITERS;
|
char *delimiter_ptr = DELIMITERS;
|
||||||
if (config.fflag)
|
if (context.config.fflag)
|
||||||
{
|
{
|
||||||
delimiter_ptr++; /* skip space delimiter */
|
delimiter_ptr++; /* skip space delimiter */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.iflag)
|
if (context.config.iflag)
|
||||||
{
|
{
|
||||||
puts("Interactive mode enabled. Enter 'Q' to exit.");
|
puts("Interactive mode enabled. Enter 'Q' to exit.");
|
||||||
interactive(vmr, config.with_prompt, delimiter_ptr);
|
interactive(&context, delimiter_ptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = optind; i < argc; ++i)
|
for (int i = optind; i < argc; ++i)
|
||||||
{
|
{
|
||||||
parse_input(vmr, argv[i], delimiter_ptr);
|
parse_input(&context, argv[i], delimiter_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rep = logout(vmr);
|
rep = logout(context.vmr);
|
||||||
if (rep != 0)
|
if (rep != 0)
|
||||||
{
|
{
|
||||||
terminate(vmr, "Error logging out of the Voicemeeter API");
|
terminate(context.vmr, "Error logging out of the Voicemeeter API");
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("Successfully logged out of the Voicemeeter API");
|
log_info("Successfully logged out of the Voicemeeter API");
|
||||||
free(vmr);
|
free(context.vmr);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,12 +318,12 @@ static enum kind set_kind(char *kval)
|
|||||||
* @param with_prompt If true, prints the interactive prompt '>>'
|
* @param with_prompt If true, prints the interactive prompt '>>'
|
||||||
* @param delimiters A string of delimiter characters to split each input line
|
* @param delimiters A string of delimiter characters to split each input line
|
||||||
*/
|
*/
|
||||||
static void interactive(PT_VMR vmr, bool with_prompt, char *delimiters)
|
static void interactive(const struct context_t *context, char *delimiters)
|
||||||
{
|
{
|
||||||
char input[MAX_LINE];
|
char input[MAX_LINE];
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (with_prompt)
|
if (context->config.with_prompt)
|
||||||
printf(">> ");
|
printf(">> ");
|
||||||
while (fgets(input, MAX_LINE, stdin) != NULL)
|
while (fgets(input, MAX_LINE, stdin) != NULL)
|
||||||
{
|
{
|
||||||
@@ -331,9 +331,9 @@ static void interactive(PT_VMR vmr, bool with_prompt, char *delimiters)
|
|||||||
if (len == 1 && toupper(input[0]) == 'Q')
|
if (len == 1 && toupper(input[0]) == 'Q')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
parse_input(vmr, input, delimiters);
|
parse_input(context, input, delimiters);
|
||||||
|
|
||||||
if (with_prompt)
|
if (context->config.with_prompt)
|
||||||
printf(">> ");
|
printf(">> ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,7 +371,7 @@ static bool add_char_to_token(char *token, size_t *token_len, char c, size_t max
|
|||||||
* @param input Each input line, from stdin or CLI args
|
* @param input Each input line, from stdin or CLI args
|
||||||
* @param delimiters A string of delimiter characters to split each input line
|
* @param delimiters A string of delimiter characters to split each input line
|
||||||
*/
|
*/
|
||||||
static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
static void parse_input(const struct context_t *context, char *input, char *delimiters)
|
||||||
{
|
{
|
||||||
if (is_comment(input))
|
if (is_comment(input))
|
||||||
return;
|
return;
|
||||||
@@ -405,7 +405,7 @@ static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
|||||||
if (token_length > 0)
|
if (token_length > 0)
|
||||||
{
|
{
|
||||||
token[token_length] = '\0';
|
token[token_length] = '\0';
|
||||||
parse_command(vmr, token);
|
parse_command(context, token);
|
||||||
token_length = 0;
|
token_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,8 +414,12 @@ static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
add_char_to_token(token, &token_length, *current, MAX_LINE);
|
if (!add_char_to_token(token, &token_length, *current, MAX_LINE))
|
||||||
log_trace("Added char '%c' to token, current token: '%s'", *current, token);
|
{
|
||||||
|
log_error("Input token exceeds maximum length of %d characters", MAX_LINE - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_trace("Added char '%c' to token, current token: '%.*s'", *current, (int)token_length, token);
|
||||||
}
|
}
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
@@ -423,7 +427,7 @@ static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
|||||||
if (token_length > 0)
|
if (token_length > 0)
|
||||||
{
|
{
|
||||||
token[token_length] = '\0';
|
token[token_length] = '\0';
|
||||||
parse_command(vmr, token);
|
parse_command(context, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +439,7 @@ static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
|||||||
* @param vmr Pointer to the iVMR interface
|
* @param vmr Pointer to the iVMR interface
|
||||||
* @param command Each token from the input line as its own command string
|
* @param command Each token from the input line as its own command string
|
||||||
*/
|
*/
|
||||||
static void parse_command(PT_VMR vmr, char *command)
|
static void parse_command(const struct context_t *context, char *command)
|
||||||
{
|
{
|
||||||
log_debug("Parsing %s", command);
|
log_debug("Parsing %s", command);
|
||||||
|
|
||||||
@@ -449,8 +453,8 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
struct quickcommand *qc_ptr = command_in_quickcommands(command, quickcommands, (int)COUNT_OF(quickcommands));
|
struct quickcommand *qc_ptr = command_in_quickcommands(command, quickcommands, (int)COUNT_OF(quickcommands));
|
||||||
if (qc_ptr != NULL)
|
if (qc_ptr != NULL)
|
||||||
{
|
{
|
||||||
set_parameters(vmr, qc_ptr->fullcommand);
|
set_parameters(context->vmr, qc_ptr->fullcommand);
|
||||||
if (eflag) {
|
if (context->config.eflag) {
|
||||||
printf("Setting %s\n", qc_ptr->fullcommand);
|
printf("Setting %s\n", qc_ptr->fullcommand);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -461,13 +465,13 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
command++;
|
command++;
|
||||||
struct result res = {.type = FLOAT_T};
|
struct result res = {.type = FLOAT_T};
|
||||||
|
|
||||||
get(vmr, command, &res);
|
get(context->vmr, command, &res);
|
||||||
if (res.type == FLOAT_T)
|
if (res.type == FLOAT_T)
|
||||||
{
|
{
|
||||||
if (res.val.f == 1 || res.val.f == 0)
|
if (res.val.f == 1 || res.val.f == 0)
|
||||||
{
|
{
|
||||||
set_parameter_float(vmr, command, 1 - res.val.f);
|
set_parameter_float(context->vmr, command, 1 - res.val.f);
|
||||||
if (eflag) {
|
if (context->config.eflag) {
|
||||||
printf("Toggling %s\n", command);
|
printf("Toggling %s\n", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -483,8 +487,8 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
|
|
||||||
if (add_quotes_if_needed(command, quoted_command, MAX_LINE))
|
if (add_quotes_if_needed(command, quoted_command, MAX_LINE))
|
||||||
{
|
{
|
||||||
set_parameters(vmr, quoted_command);
|
set_parameters(context->vmr, quoted_command);
|
||||||
if (eflag) {
|
if (context->config.eflag) {
|
||||||
printf("Setting %s\n", command);
|
printf("Setting %s\n", command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,7 +501,7 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
{
|
{
|
||||||
struct result res = {.type = FLOAT_T};
|
struct result res = {.type = FLOAT_T};
|
||||||
|
|
||||||
get(vmr, command, &res);
|
get(context->vmr, command, &res);
|
||||||
switch (res.type)
|
switch (res.type)
|
||||||
{
|
{
|
||||||
case FLOAT_T:
|
case FLOAT_T:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @file wrapper.c
|
* @file wrapper.c
|
||||||
* @author Onyx and Iris (code@onyxandiris.online)
|
* @author Onyx and Iris (code@onyxandiris.online)
|
||||||
* @brief Provides public functions that wrap the iVMR calls
|
* @brief Provides public functions that wrap the iVMR calls
|
||||||
* @version 0.14.0
|
* @version 0.14.1
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2024
|
* @copyright Copyright (c) 2024
|
||||||
|
|||||||
Reference in New Issue
Block a user