Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse-options: option validation and mutual exclusivity #68

Open
brandon1024 opened this issue Mar 7, 2021 · 0 comments
Open

parse-options: option validation and mutual exclusivity #68

brandon1024 opened this issue Mar 7, 2021 · 0 comments

Comments

@brandon1024
Copy link
Owner

brandon1024 commented Mar 7, 2021

An annoying byproduct of the current parse-options implementation is the need for validation after the argument list has been parsed. For instance, some options might only apply to certain subcommands, so the caller needs to check that all of the result values are correct and make sense.

I've been recently trying to think of ways that we could improve this, grouping option specs in a more hierarchical manner. If we can organize our options specs in that way, we might be able to handle automated argument validation and printing usage strings.

The basic idea will be to introduce a new structure that accepts a top-level option (which could be a subcommand or any type of option), and arrays of sub-options. An implementation might look like this:

	int gpg_pass_fd = -1;
	char *gpg_pass_file = NULL;
	char *gpg_pass = NULL;

	int show_help = 0;
	int show_version = 0;

	const struct option_spec common_opts[] = {
			OPT_LONG_INT("passphrase-fd", "read passphrase from file descriptor", &gpg_pass_fd),
			OPT_LONG_STRING("passphrase-file", "file", "read passphrase from file", &gpg_pass_file),
			OPT_LONG_STRING("passphrase", "pass", "use string as passphrase", &gpg_pass),
			OPT_END()
	};
	const struct option_group gc_option_groups[] = {
			{
				.top = OPT_CMD("channel", "create and manage communication channels", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_CMD("message", "create messages", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_CMD("publish", "publish messages to the remote server", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_CMD("get", "download messages", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_CMD("read", "display, format and read messages", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_CMD("import-key", "import a GPG key into the current channel", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_CMD("config", "configure a channel", NULL),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_BOOL('h', "help", "show usage and exit", &show_help),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}, {
				.top = OPT_BOOL('v', "version", "output version information and exit", &show_version),
				.sub_options = NULL,
				.sub_groups = NULL,
				.common_options = common_opts
			}
	};

One hard requirement is to stick to static allocation. This will help ensure that the solution is clean and not prone to memory leaks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant