cli: Extract layout argument parsing into cli_common

Move the parsing logic for layout sources into the new function
cli_parse_layout_args(). This way it can be shared with other CLIs.

Signed-off-by: Nico Huber <nico.h@gmx.de>

Change-Id: Idcbb136d31477cdb0aebec4af0c4cbc873f26011
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/72984
Tested-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Nico Huber <nico.h@gmx.de>
diff --git a/cli_classic.c b/cli_classic.c
index 680fdef..7ee3b07 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -97,18 +97,6 @@
 	}
 }
 
-static int check_filename(char *filename, const char *type)
-{
-	if (!filename || (filename[0] == '\0')) {
-		fprintf(stderr, "Error: No %s file specified.\n", type);
-		return 1;
-	}
-	/* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
-	if (filename[0] == '-' && filename[1] != '\0')
-		fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
-	return 0;
-}
-
 /* Ensure a file is open by means of fstat */
 static bool check_file(FILE *file)
 {
@@ -212,7 +200,7 @@
 	int opt, i, j;
 	int startchip = -1, chipcount = 0, option_index = 0;
 	int operation_specified = 0;
-	bool force = false, ifd = false, fmap = false;
+	bool force = false;
 #if CONFIG_PRINT_WIKI == 1
 	bool list_supported_wiki = false;
 #endif
@@ -258,11 +246,10 @@
 
 	char *filename = NULL;
 	char *referencefile = NULL;
-	char *layoutfile = NULL;
-	char *fmapfile = NULL;
 	char *logfile = NULL;
 	char *tempstr = NULL;
 	struct flash_args flash_args = { 0 };
+	struct layout_args layout_args = { 0 };
 	struct layout_include_args *include_args = NULL;
 
 	/*
@@ -338,42 +325,15 @@
 		case 'f':
 			force = true;
 			break;
-		case 'l':
-			if (layoutfile)
-				cli_classic_abort_usage("Error: --layout specified more than once. Aborting.\n");
-			if (ifd)
-				cli_classic_abort_usage("Error: --layout and --ifd both specified. Aborting.\n");
-			if (fmap)
-				cli_classic_abort_usage("Error: --layout and --fmap-file both specified. Aborting.\n");
-			layoutfile = strdup(optarg);
-			break;
+		case OPTION_LAYOUT:
 		case OPTION_IFD:
-			if (layoutfile)
-				cli_classic_abort_usage("Error: --layout and --ifd both specified. Aborting.\n");
-			if (fmap)
-				cli_classic_abort_usage("Error: --fmap-file and --ifd both specified. Aborting.\n");
-			ifd = true;
-			break;
-		case OPTION_FMAP_FILE:
-			if (fmap)
-				cli_classic_abort_usage("Error: --fmap or --fmap-file specified "
-					"more than once. Aborting.\n");
-			if (ifd)
-				cli_classic_abort_usage("Error: --fmap-file and --ifd both specified. Aborting.\n");
-			if (layoutfile)
-				cli_classic_abort_usage("Error: --fmap-file and --layout both specified. Aborting.\n");
-			fmapfile = strdup(optarg);
-			fmap = true;
-			break;
 		case OPTION_FMAP:
-			if (fmap)
-				cli_classic_abort_usage("Error: --fmap or --fmap-file specified "
-					"more than once. Aborting.\n");
-			if (ifd)
-				cli_classic_abort_usage("Error: --fmap and --ifd both specified. Aborting.\n");
-			if (layoutfile)
-				cli_classic_abort_usage("Error: --layout and --fmap both specified. Aborting.\n");
-			fmap = true;
+		case OPTION_FMAP_FILE:
+			ret = cli_parse_layout_args(&layout_args, opt, optarg);
+			if (ret == 1)
+				cli_classic_abort_usage(NULL);
+			else if (ret)
+				exit(1);
 			break;
 		case 'i':
 			tempstr = strdup(optarg);
@@ -441,15 +401,11 @@
 
 	if (optind < argc)
 		cli_classic_abort_usage("Error: Extra parameter found.\n");
-	if ((read_it | write_it | verify_it) && check_filename(filename, "image"))
+	if ((read_it | write_it | verify_it) && cli_check_filename(filename, "image"))
 		cli_classic_abort_usage(NULL);
-	if (layoutfile && check_filename(layoutfile, "layout"))
+	if (referencefile && cli_check_filename(referencefile, "reference"))
 		cli_classic_abort_usage(NULL);
-	if (fmapfile && check_filename(fmapfile, "fmap"))
-		cli_classic_abort_usage(NULL);
-	if (referencefile && check_filename(referencefile, "reference"))
-		cli_classic_abort_usage(NULL);
-	if (logfile && check_filename(logfile, "log"))
+	if (logfile && cli_check_filename(logfile, "log"))
 		cli_classic_abort_usage(NULL);
 	if (logfile && open_logfile(logfile))
 		cli_classic_abort_usage(NULL);
@@ -476,12 +432,13 @@
 	}
 	msg_gdbg("\n");
 
-	if (layoutfile && layout_from_file(&layout, layoutfile)) {
+	if (layout_args.layoutfile && layout_from_file(&layout, layout_args.layoutfile)) {
 		ret = 1;
 		goto out;
 	}
 
-	if (!ifd && !fmap && process_include_args(layout, include_args)) {
+	if (!layout_args.ifd && !layout_args.fmap && !layout_args.fmapfile &&
+	    process_include_args(layout, include_args)) {
 		ret = 1;
 		goto out;
 	}
@@ -646,14 +603,14 @@
 		goto out_shutdown;
 	}
 
-	if (ifd && (flashprog_layout_read_from_ifd(&layout, fill_flash, NULL, 0) ||
-			   process_include_args(layout, include_args))) {
+	if (layout_args.ifd && (flashprog_layout_read_from_ifd(&layout, fill_flash, NULL, 0) ||
+							process_include_args(layout, include_args))) {
 		ret = 1;
 		goto out_shutdown;
-	} else if (fmap && fmapfile) {
+	} else if (layout_args.fmapfile) {
 		struct stat s;
-		if (stat(fmapfile, &s) != 0) {
-			msg_gerr("Failed to stat fmapfile \"%s\"\n", fmapfile);
+		if (stat(layout_args.fmapfile, &s) != 0) {
+			msg_gerr("Failed to stat fmapfile \"%s\"\n", layout_args.fmapfile);
 			ret = 1;
 			goto out_shutdown;
 		}
@@ -665,7 +622,7 @@
 			goto out_shutdown;
 		}
 
-		if (read_buf_from_file(fmapfile_buffer, fmapfile_size, fmapfile)) {
+		if (read_buf_from_file(fmapfile_buffer, fmapfile_size, layout_args.fmapfile)) {
 			ret = 1;
 			free(fmapfile_buffer);
 			goto out_shutdown;
@@ -678,8 +635,8 @@
 			goto out_shutdown;
 		}
 		free(fmapfile_buffer);
-	} else if (fmap && (flashprog_layout_read_fmap_from_rom(&layout, fill_flash, 0,
-				flashprog_flash_getsize(fill_flash)) || process_include_args(layout, include_args))) {
+	} else if (layout_args.fmap && (flashprog_layout_read_fmap_from_rom(&layout, fill_flash, 0,
+			flashprog_flash_getsize(fill_flash)) || process_include_args(layout, include_args))) {
 		ret = 1;
 		goto out_shutdown;
 	}
@@ -728,9 +685,9 @@
 
 	cleanup_include_args(&include_args);
 	free(filename);
-	free(fmapfile);
 	free(referencefile);
-	free(layoutfile);
+	free(layout_args.fmapfile);
+	free(layout_args.layoutfile);
 	free(flash_args.prog_args);
 	free(flash_args.prog_name);
 	free(flash_args.chip);
diff --git a/cli_common.c b/cli_common.c
index c364efa..64bb38a 100644
--- a/cli_common.c
+++ b/cli_common.c
@@ -22,6 +22,18 @@
 #include "flash.h"
 #include "cli.h"
 
+int cli_check_filename(const char *const filename, const char *const type)
+{
+	if (!filename || (filename[0] == '\0')) {
+		fprintf(stderr, "Error: No %s file specified.\n", type);
+		return 1;
+	}
+	/* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
+	if (filename[0] == '-' && filename[1] != '\0')
+		fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
+	return 0;
+}
+
 int cli_parse_flash_args(struct flash_args *const args, const int opt, const char *const optarg)
 {
 	switch (opt) {
@@ -60,6 +72,45 @@
 	return 0;
 }
 
+int cli_parse_layout_args(struct layout_args *const args, const int opt, const char *const optarg)
+{
+	if (args->layoutfile || args->ifd || args->fmap || args->fmapfile) {
+		fprintf(stderr, "Error: Only one layout source may be specified.\n");
+		return 1;
+	}
+
+	switch (opt) {
+	case OPTION_LAYOUT:
+		if (cli_check_filename(optarg, "layout"))
+			return 1;
+
+		args->layoutfile = strdup(optarg);
+		if (!args->layoutfile) {
+			fprintf(stderr, "Out of memory!\n");
+			return 2;
+		}
+		break;
+	case OPTION_IFD:
+		args->ifd = true;
+		break;
+	case OPTION_FMAP:
+		args->fmap = true;
+		break;
+	case OPTION_FMAP_FILE:
+		if (cli_check_filename(optarg, "fmap"))
+			return 1;
+
+		args->fmapfile = strdup(optarg);
+		if (!args->fmapfile) {
+			fprintf(stderr, "Out of memory!\n");
+			return 2;
+		}
+		break;
+	}
+
+	return 0;
+}
+
 void print_chip_support_status(const struct flashchip *chip)
 {
 	if (chip->feature_bits & FEATURE_OTP) {
diff --git a/include/cli.h b/include/cli.h
index fb55191..b243f1d 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -18,6 +18,7 @@
 enum {
 	OPTION_CHIP = 'c',
 	OPTION_PROGRAMMER = 'p',
+	OPTION_LAYOUT = 'l',
 
 	/* Options below have only long option names, i.e. no single char: */
 	OPTION_IFD = 0x0100,
@@ -35,6 +36,16 @@
 	char *prog_args;
 };
 
+struct layout_args {
+	bool ifd;
+	bool fmap;
+	char *fmapfile;
+	char *layoutfile;
+};
+
+int cli_check_filename(const char *filename, const char *type);
+
 int cli_parse_flash_args(struct flash_args *, int opt, const char *optarg);
+int cli_parse_layout_args(struct layout_args *, int opt, const char *optarg);
 
 #endif