Add option_parser_print_usage
Signed-off-by: Jim Ramsay <i.am@jimramsay.com>wayvncctl-polishing
parent
dcb23ebfe1
commit
104040291b
|
@ -50,11 +50,16 @@ struct option_parser {
|
||||||
void option_parser_init(struct option_parser* self,
|
void option_parser_init(struct option_parser* self,
|
||||||
const struct wv_option* options);
|
const struct wv_option* options);
|
||||||
|
|
||||||
|
void option_parser_print_usage(struct option_parser* self, FILE* stream);
|
||||||
|
|
||||||
int option_parser_print_arguments(struct option_parser* self, FILE* stream);
|
int option_parser_print_arguments(struct option_parser* self, FILE* stream);
|
||||||
|
|
||||||
void option_parser_print_options(struct option_parser* self, FILE* stream);
|
void option_parser_print_options(struct option_parser* self, FILE* stream);
|
||||||
|
|
||||||
int option_parser_parse(struct option_parser* self, int argc,
|
int option_parser_parse(struct option_parser* self, int argc,
|
||||||
const char* const* argv);
|
const char* const* argv);
|
||||||
|
|
||||||
const char* option_parser_get_value(const struct option_parser* self,
|
const char* option_parser_get_value(const struct option_parser* self,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
const char* option_parser_get_value_no_default(const struct option_parser* self,
|
||||||
|
const char* name);
|
||||||
|
|
|
@ -738,12 +738,9 @@ static int print_command_usage(struct ctl_client* self,
|
||||||
WARN("No such command");
|
WARN("No such command");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("Usage: wayvncctl [options] %s ", info->name);
|
printf("Usage: wayvncctl [options] %s", info->name);
|
||||||
for (int i = 0; i < cmd_options->n_opts; ++i)
|
option_parser_print_usage(cmd_options, stdout);
|
||||||
if (cmd_options->options[i].positional)
|
printf("\n\n");
|
||||||
printf("<%s> ", cmd_options->options[i].positional);
|
|
||||||
|
|
||||||
printf("[parameters]\n\n");
|
|
||||||
table_printer_indent_and_reflow_text(stdout, info->description, 80, 0, 0);
|
table_printer_indent_and_reflow_text(stdout, info->description, 80, 0, 0);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (option_parser_print_arguments(cmd_options, stdout))
|
if (option_parser_print_arguments(cmd_options, stdout))
|
||||||
|
|
30
src/main.c
30
src/main.c
|
@ -66,6 +66,9 @@
|
||||||
#define DEFAULT_ADDRESS "127.0.0.1"
|
#define DEFAULT_ADDRESS "127.0.0.1"
|
||||||
#define DEFAULT_PORT 5900
|
#define DEFAULT_PORT 5900
|
||||||
|
|
||||||
|
#define XSTR(x) STR(x)
|
||||||
|
#define STR(x) #x
|
||||||
|
|
||||||
#define MAYBE_UNUSED __attribute__((unused))
|
#define MAYBE_UNUSED __attribute__((unused))
|
||||||
|
|
||||||
struct wayvnc {
|
struct wayvnc {
|
||||||
|
@ -907,15 +910,14 @@ void on_capture_done(struct screencopy* sc)
|
||||||
|
|
||||||
int wayvnc_usage(struct option_parser* parser, FILE* stream, int rc)
|
int wayvnc_usage(struct option_parser* parser, FILE* stream, int rc)
|
||||||
{
|
{
|
||||||
static const char* usage =
|
fputs("Usage: wayvnc", stream);
|
||||||
"Usage: wayvnc [options] [<address> [<port>]]\n"
|
option_parser_print_usage(parser, stream);
|
||||||
"\n"
|
fputs("\n\n", stream);
|
||||||
"Starts a VNC server for $WAYLAND_DISPLAY";
|
fprintf(stream, "Starts a VNC server for $WAYLAND_DISPLAY\n\n");
|
||||||
fprintf(stream, "%s\n\n", usage);
|
|
||||||
if (option_parser_print_arguments(parser, stream))
|
if (option_parser_print_arguments(parser, stream))
|
||||||
fprintf(stream, "\n");
|
fputc('\n', stream);
|
||||||
option_parser_print_options(parser, stream);
|
option_parser_print_options(parser, stream);
|
||||||
fprintf(stream, "\n");
|
fputc('\n', stream);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1270,9 +1272,11 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
static const struct wv_option opts[] = {
|
static const struct wv_option opts[] = {
|
||||||
{ .positional = "address",
|
{ .positional = "address",
|
||||||
.help = "The IP address or unix socket path to listen on. Default: 127.0.0.1" },
|
.help = "The IP address or unix socket path to listen on.",
|
||||||
|
.default_ = DEFAULT_ADDRESS},
|
||||||
{ .positional = "port",
|
{ .positional = "port",
|
||||||
.help = "The TCP port to listen on. Default: 5900" },
|
.help = "The TCP port to listen on.",
|
||||||
|
.default_ = XSTR(DEFAULT_PORT)},
|
||||||
{ 'C', "config", "<path>",
|
{ 'C', "config", "<path>",
|
||||||
"Select a config file." },
|
"Select a config file." },
|
||||||
{ 'g', "gpu", NULL,
|
{ 'g', "gpu", NULL,
|
||||||
|
@ -1305,7 +1309,7 @@ int main(int argc, char* argv[])
|
||||||
.default_ = "warning" },
|
.default_ = "warning" },
|
||||||
{ 'h', "help", NULL,
|
{ 'h', "help", NULL,
|
||||||
"Get help (this text)." },
|
"Get help (this text)." },
|
||||||
{ '\0', NULL, NULL, NULL }
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct option_parser option_parser;
|
struct option_parser option_parser;
|
||||||
|
@ -1344,8 +1348,10 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
nvnc_set_log_level(log_level);
|
nvnc_set_log_level(log_level);
|
||||||
|
|
||||||
address = option_parser_get_value(&option_parser, "address");
|
// Only check for explicitly-set values here (defaults applied below)
|
||||||
const char* port_str = option_parser_get_value(&option_parser, "port");
|
address = option_parser_get_value_no_default(&option_parser, "address");
|
||||||
|
const char* port_str = option_parser_get_value_no_default(&option_parser,
|
||||||
|
"port");
|
||||||
if (port_str)
|
if (port_str)
|
||||||
port = atoi(port_str);
|
port = atoi(port_str);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
@ -105,6 +106,39 @@ void option_parser_print_options(struct option_parser* self, FILE* stream)
|
||||||
format_option(&printer, &self->options[i]);
|
format_option(&printer, &self->options[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_string_tolower(FILE* stream, const char *src)
|
||||||
|
{
|
||||||
|
for (const char* c = src; *c != '\0'; c++)
|
||||||
|
fprintf(stream, "%c", tolower(*c));
|
||||||
|
}
|
||||||
|
|
||||||
|
void option_parser_print_usage(struct option_parser* self, FILE* stream)
|
||||||
|
{
|
||||||
|
fprintf(stream, " [");
|
||||||
|
print_string_tolower(stream, self->name);
|
||||||
|
fprintf(stream, "]");
|
||||||
|
int optional_paren_count = 0;
|
||||||
|
for (int i = 0; i < self->n_opts; ++i) {
|
||||||
|
const struct wv_option* opt = &self->options[i];
|
||||||
|
if (!opt->positional)
|
||||||
|
continue;
|
||||||
|
const char* open = "<";
|
||||||
|
const char* close = ">";
|
||||||
|
if (opt->default_) {
|
||||||
|
open = "[";
|
||||||
|
close = ""; // Closed via optional_paren_count loop below
|
||||||
|
optional_paren_count++;
|
||||||
|
} else {
|
||||||
|
// Enforce there must be NO non-optional args after
|
||||||
|
// we've processed at least one optional arg
|
||||||
|
assert(optional_paren_count == 0);
|
||||||
|
}
|
||||||
|
fprintf(stream, " %s%s%s", open, opt->positional, close);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < optional_paren_count; ++i)
|
||||||
|
fprintf(stream, "]");
|
||||||
|
}
|
||||||
|
|
||||||
int option_parser_print_arguments(struct option_parser* self, FILE* stream)
|
int option_parser_print_arguments(struct option_parser* self, FILE* stream)
|
||||||
{
|
{
|
||||||
size_t max_arg = 0;
|
size_t max_arg = 0;
|
||||||
|
@ -168,6 +202,19 @@ static const struct wv_option* find_positional_option(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct wv_option* find_positional_option_by_name(
|
||||||
|
const struct option_parser* self, const char*name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < self->n_opts; ++i) {
|
||||||
|
const struct wv_option* opt = &self->options[i];
|
||||||
|
if (!opt->positional)
|
||||||
|
continue;
|
||||||
|
if (strcmp(opt->positional, name) == 0)
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int append_value(struct option_parser* self,
|
static int append_value(struct option_parser* self,
|
||||||
const struct wv_option* option, const char* value)
|
const struct wv_option* option, const char* value)
|
||||||
{
|
{
|
||||||
|
@ -317,7 +364,7 @@ int option_parser_parse(struct option_parser* self, int argc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* option_parser_get_value(const struct option_parser* self,
|
const char* option_parser_get_value_no_default(const struct option_parser* self,
|
||||||
const char* name)
|
const char* name)
|
||||||
{
|
{
|
||||||
const struct wv_option* opt;
|
const struct wv_option* opt;
|
||||||
|
@ -340,6 +387,18 @@ const char* option_parser_get_value(const struct option_parser* self,
|
||||||
return value->value;
|
return value->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* option_parser_get_value(const struct option_parser* self,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
const char* value = option_parser_get_value_no_default(self, name);
|
||||||
|
if (value)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
bool is_short = name[0] && !name[1];
|
||||||
|
const struct wv_option* opt;
|
||||||
if (is_short) {
|
if (is_short) {
|
||||||
opt = find_short_option(self, name[0]);
|
opt = find_short_option(self, name[0]);
|
||||||
if (opt)
|
if (opt)
|
||||||
|
@ -348,9 +407,10 @@ const char* option_parser_get_value(const struct option_parser* self,
|
||||||
opt = find_long_option(self, name);
|
opt = find_long_option(self, name);
|
||||||
if (opt)
|
if (opt)
|
||||||
return opt->default_;
|
return opt->default_;
|
||||||
|
opt = find_positional_option_by_name(self, name);
|
||||||
|
if (opt)
|
||||||
|
return opt->default_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add positional option?
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,13 +43,12 @@ struct wayvncctl {
|
||||||
|
|
||||||
static int wayvncctl_usage(FILE* stream, struct option_parser* options, int rc)
|
static int wayvncctl_usage(FILE* stream, struct option_parser* options, int rc)
|
||||||
{
|
{
|
||||||
static const char* usage =
|
fputs("Usage: wayvncctl", stream);
|
||||||
"Usage: wayvncctl [options] <command> [parameters]\n"
|
option_parser_print_usage(options, stream);
|
||||||
"\n"
|
fputs(" [parameters]\n\n", stream);
|
||||||
"Connects to and interacts with a running wayvnc instance.";
|
fputs("Connects to and interacts with a running wayvnc instance.\n\n", stream);
|
||||||
fprintf(stream, "%s\n\n", usage);
|
|
||||||
option_parser_print_options(options, stream);
|
option_parser_print_options(options, stream);
|
||||||
fprintf(stream, "\n");
|
fputc('\n', stream);
|
||||||
ctl_client_print_command_list(stream);
|
ctl_client_print_command_list(stream);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,13 @@ static const struct wv_option options[] = {
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct wv_option default_options[] = {
|
||||||
|
{ .positional = "first" },
|
||||||
|
{ .positional = "second", .default_ = "second_default" },
|
||||||
|
{ 'v', "value-option", "value", "Description of v", .default_ = "v_default" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
static int test_simple(void)
|
static int test_simple(void)
|
||||||
{
|
{
|
||||||
struct option_parser parser;
|
struct option_parser parser;
|
||||||
|
@ -227,6 +234,61 @@ static int test_subcommand_with_arguments(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_defaults_not_set(void)
|
||||||
|
{
|
||||||
|
struct option_parser parser;
|
||||||
|
option_parser_init(&parser, default_options);
|
||||||
|
const char* argv[] = {
|
||||||
|
"executable",
|
||||||
|
"pos 1",
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv));
|
||||||
|
ASSERT_STR_EQ("pos 1", option_parser_get_value(&parser, "first"));
|
||||||
|
|
||||||
|
ASSERT_STR_EQ("second_default", option_parser_get_value(&parser, "second"));
|
||||||
|
ASSERT_FALSE(option_parser_get_value_no_default(&parser, "second"));
|
||||||
|
|
||||||
|
ASSERT_STR_EQ("v_default", option_parser_get_value(&parser, "value-option"));
|
||||||
|
ASSERT_FALSE(option_parser_get_value_no_default(&parser, "value-option"));
|
||||||
|
ASSERT_STR_EQ("v_default", option_parser_get_value(&parser, "v"));
|
||||||
|
ASSERT_FALSE(option_parser_get_value_no_default(&parser, "v"));
|
||||||
|
|
||||||
|
ASSERT_INT_EQ(0, parser.remaining_argc);
|
||||||
|
ASSERT_FALSE(parser.remaining_argv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_defaults_overridden(void)
|
||||||
|
{
|
||||||
|
struct option_parser parser;
|
||||||
|
option_parser_init(&parser, default_options);
|
||||||
|
const char* argv[] = {
|
||||||
|
"executable",
|
||||||
|
"pos 1",
|
||||||
|
"pos 2",
|
||||||
|
"-v",
|
||||||
|
"v_set",
|
||||||
|
};
|
||||||
|
|
||||||
|
ASSERT_INT_EQ(0, option_parser_parse(&parser, ARRAY_SIZE(argv), argv));
|
||||||
|
ASSERT_STR_EQ("pos 1", option_parser_get_value(&parser, "first"));
|
||||||
|
|
||||||
|
ASSERT_STR_EQ("pos 2", option_parser_get_value(&parser, "second"));
|
||||||
|
ASSERT_STR_EQ("pos 2", option_parser_get_value_no_default(&parser, "second"));
|
||||||
|
|
||||||
|
ASSERT_STR_EQ("v_set", option_parser_get_value(&parser, "value-option"));
|
||||||
|
ASSERT_STR_EQ("v_set", option_parser_get_value_no_default(&parser, "value-option"));
|
||||||
|
ASSERT_STR_EQ("v_set", option_parser_get_value(&parser, "v"));
|
||||||
|
ASSERT_STR_EQ("v_set", option_parser_get_value_no_default(&parser, "v"));
|
||||||
|
|
||||||
|
ASSERT_INT_EQ(0, parser.remaining_argc);
|
||||||
|
ASSERT_FALSE(parser.remaining_argv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -246,5 +308,7 @@ int main()
|
||||||
RUN_TEST(test_missing_long_value);
|
RUN_TEST(test_missing_long_value);
|
||||||
RUN_TEST(test_subcommand_without_arguments);
|
RUN_TEST(test_subcommand_without_arguments);
|
||||||
RUN_TEST(test_subcommand_with_arguments);
|
RUN_TEST(test_subcommand_with_arguments);
|
||||||
|
RUN_TEST(test_defaults_not_set);
|
||||||
|
RUN_TEST(test_defaults_overridden);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue