"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Josh Rickmar <joshrickmar@outlook.com>
Subject:
Cleanup of mutually exclusive flag errors
To:
gameoftrees@openbsd.org
Date:
Sat, 12 Dec 2020 14:58:42 -0500

Download raw body.

Thread
This adds a struct and some functions to detect and deal with mutually
exclusive flags presented by the user during the histedit and ref
commands, which allows the removal of many manual flag checks.

Other commands don't have flag sets with so many mutually exclusive
options, so it didn't seem worthwhile to use the new mechanism there.

The histedit command was the only one where these mutually exclusive
flag errors reported the command in use, so to be consistent with the
rest of the commands, only the options are told, without repeating the
command name.

This diff fixes an issue I missed during my earlier histedit -f patch
where it did not error when histedit -f and -F were used together.

ok?

diff refs/heads/main refs/heads/excl_flags
blob - 7bdd9e142a5f26254c73c308684bb6d6da95ef20
blob + 0fe7688b582029de5b762c10881d9c14fd9abd4e
--- got/got.c
+++ got/got.c
@@ -83,6 +83,11 @@ struct got_cmd {
 	const char	*cmd_alias;
 };
 
+struct got_exclusive_flags {
+	int		count;
+	char		flags[2];
+};
+
 __dead static void	usage(int, int);
 __dead static void	usage_init(void);
 __dead static void	usage_import(void);
@@ -140,6 +145,11 @@ static const struct got_error*		cmd_unstage(int, char 
 static const struct got_error*		cmd_cat(int, char *[]);
 static const struct got_error*		cmd_info(int, char *[]);
 
+static void	mark_mutually_exclusive_flag(struct got_exclusive_flags *,
+		    char);
+__dead static void err_mutually_exclusive_flags(char, char);
+static void	check_mutually_exclusive_flags(struct got_exclusive_flags *);
+
 static struct got_cmd got_commands[] = {
 	{ "init",	cmd_init,	usage_init,	"" },
 	{ "import",	cmd_import,	usage_import,	"im" },
@@ -326,7 +336,29 @@ apply_unveil(const char *repo_path, int repo_read_only
 	return NULL;
 }
 
+static void
+mark_mutually_exclusive_flag(struct got_exclusive_flags *excl, char ch)
+{
+	if (excl->count == 1 && ch == excl->flags[0])
+		return;
+	if (excl->count < 2)
+		excl->flags[excl->count++] = ch;
+}
+
 __dead static void
+err_mutually_exclusive_flags(char ch1, char ch2)
+{
+	errx(1, "-%c and -%c options are mutually exclusive", ch1, ch2);
+}
+
+static void
+check_mutually_exclusive_flags(struct got_exclusive_flags *excl)
+{
+	if (excl->flags[1] != 0)
+		err_mutually_exclusive_flags(excl->flags[0], excl->flags[1]);
+}
+
+__dead static void
 usage_init(void)
 {
 	fprintf(stderr, "usage: %s init repository-path\n", getprogname());
@@ -5164,16 +5196,21 @@ cmd_ref(int argc, char *argv[])
 	struct got_worktree *worktree = NULL;
 	char *cwd = NULL, *repo_path = NULL;
 	int ch, do_list = 0, do_delete = 0;
+	struct got_exclusive_flags excl_flags;
 	const char *obj_arg = NULL, *symref_target= NULL;
 	char *refname = NULL;
 
+	memset(&excl_flags, 0, sizeof(excl_flags));
+
 	while ((ch = getopt(argc, argv, "c:dr:ls:")) != -1) {
 		switch (ch) {
 		case 'c':
 			obj_arg = optarg;
+			mark_mutually_exclusive_flag(&excl_flags, ch);
 			break;
 		case 'd':
 			do_delete = 1;
+			mark_mutually_exclusive_flag(&excl_flags, ch);
 			break;
 		case 'r':
 			repo_path = realpath(optarg, NULL);
@@ -5181,12 +5218,15 @@ cmd_ref(int argc, char *argv[])
 				return got_error_from_errno2("realpath",
 				    optarg);
 			got_path_strip_trailing_slashes(repo_path);
+			/* -r is not exclusive with any other flags */
 			break;
 		case 'l':
 			do_list = 1;
+			mark_mutually_exclusive_flag(&excl_flags, ch);
 			break;
 		case 's':
 			symref_target = optarg;
+			mark_mutually_exclusive_flag(&excl_flags, ch);
 			break;
 		default:
 			usage_ref();
@@ -5194,22 +5234,11 @@ cmd_ref(int argc, char *argv[])
 		}
 	}
 
-	if (obj_arg && do_list)
-		errx(1, "-c and -l options are mutually exclusive");
-	if (obj_arg && do_delete)
-		errx(1, "-c and -d options are mutually exclusive");
-	if (obj_arg && symref_target)
-		errx(1, "-c and -s options are mutually exclusive");
-	if (symref_target && do_delete)
-		errx(1, "-s and -d options are mutually exclusive");
-	if (symref_target && do_list)
-		errx(1, "-s and -l options are mutually exclusive");
-	if (do_delete && do_list)
-		errx(1, "-d and -l options are mutually exclusive");
-
 	argc -= optind;
 	argv += optind;
 
+	check_mutually_exclusive_flags(&excl_flags);
+
 	if (do_list) {
 		if (argc != 0 && argc != 1)
 			usage_ref();
@@ -8578,6 +8607,7 @@ cmd_histedit(int argc, char *argv[])
 	struct got_update_progress_arg upa;
 	int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
 	int edit_logmsg_only = 0, fold_only = 0;
+	struct got_exclusive_flags excl_flags;
 	const char *edit_script_path = NULL;
 	unsigned char rebase_status = GOT_STATUS_NO_CHANGE;
 	struct got_object_id_queue commits;
@@ -8591,8 +8621,11 @@ cmd_histedit(int argc, char *argv[])
 	TAILQ_INIT(&histedit_cmds);
 	TAILQ_INIT(&merged_paths);
 	memset(&upa, 0, sizeof(upa));
+	memset(&excl_flags, 0, sizeof(excl_flags));
 
 	while ((ch = getopt(argc, argv, "acfF:m")) != -1) {
+		/* all flags are mutually exclusive */
+		mark_mutually_exclusive_flag(&excl_flags, ch);
 		switch (ch) {
 		case 'a':
 			abort_edit = 1;
@@ -8623,20 +8656,7 @@ cmd_histedit(int argc, char *argv[])
 	    "unveil", NULL) == -1)
 		err(1, "pledge");
 #endif
-	if (abort_edit && continue_edit)
-		errx(1, "histedit's -a and -c options are mutually exclusive");
-	if (edit_script_path && edit_logmsg_only)
-		errx(1, "histedit's -F and -m options are mutually exclusive");
-	if (abort_edit && edit_logmsg_only)
-		errx(1, "histedit's -a and -m options are mutually exclusive");
-	if (continue_edit && edit_logmsg_only)
-		errx(1, "histedit's -c and -m options are mutually exclusive");
-	if (abort_edit && fold_only)
-		errx(1, "histedit's -a and -f options are mutually exclusive");
-	if (continue_edit && fold_only)
-		errx(1, "histedit's -c and -f options are mutually exclusive");
-	if (fold_only && edit_logmsg_only)
-		errx(1, "histedit's -f and -m options are mutually exclusive");
+	check_mutually_exclusive_flags(&excl_flags);
 	if (argc != 0)
 		usage_histedit();