cli: Extract log argument parsing into cli_common

Move log argument parsing into `cli_common.c` as it's also useful for
other CLIs. Also add a NULL-check for the strdup() return value.

Change-Id: I9b1c9ae2e490edd3560b11b84fddd79e4d396e1d
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/72986
diff --git a/cli_classic.c b/cli_classic.c
index 701c3f5..711db5b 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -246,8 +246,8 @@
 
 	char *filename = NULL;
 	char *referencefile = NULL;
-	char *logfile = NULL;
 	char *tempstr = NULL;
+	struct log_args log_args = { FLASHPROG_MSG_INFO, FLASHPROG_MSG_DEBUG2, NULL };
 	struct flash_args flash_args = { 0 };
 	struct layout_args layout_args = { 0 };
 	struct layout_include_args *include_args = NULL;
@@ -314,9 +314,12 @@
 				exit(1);
 			break;
 		case 'V':
-			verbose_screen++;
-			if (verbose_screen > FLASHPROG_MSG_DEBUG2)
-				verbose_logfile = verbose_screen;
+		case 'o':
+			ret = cli_parse_log_args(&log_args, opt, optarg);
+			if (ret == 1)
+				cli_classic_abort_usage(NULL);
+			else if (ret)
+				exit(1);
 			break;
 		case 'E':
 			cli_classic_validate_singleop(&operation_specified);
@@ -379,17 +382,6 @@
 			cli_classic_usage(argv[0]);
 			exit(0);
 			break;
-		case 'o':
-			if (logfile) {
-				fprintf(stderr, "Warning: -o/--output specified multiple times.\n");
-				free(logfile);
-			}
-
-			logfile = strdup(optarg);
-			if (logfile[0] == '\0') {
-				cli_classic_abort_usage("No log filename specified.\n");
-			}
-			break;
 		case OPTION_PROGRESS:
 			show_progress = true;
 			break;
@@ -405,10 +397,10 @@
 		cli_classic_abort_usage(NULL);
 	if (referencefile && cli_check_filename(referencefile, "reference"))
 		cli_classic_abort_usage(NULL);
-	if (logfile && cli_check_filename(logfile, "log"))
+	if (log_args.logfile && open_logfile(log_args.logfile))
 		cli_classic_abort_usage(NULL);
-	if (logfile && open_logfile(logfile))
-		cli_classic_abort_usage(NULL);
+	verbose_screen = log_args.screen_level;
+	verbose_logfile = log_args.logfile_level;
 
 #if CONFIG_PRINT_WIKI == 1
 	if (list_supported_wiki) {
@@ -650,9 +642,9 @@
 	free(flash_args.prog_args);
 	free(flash_args.prog_name);
 	free(flash_args.chip);
+	free(log_args.logfile);
 	/* clean up global variables */
 	chip_to_probe = NULL;
-	free(logfile);
 	ret |= close_logfile();
 	return ret;
 }
diff --git a/cli_common.c b/cli_common.c
index a772057..787e47d 100644
--- a/cli_common.c
+++ b/cli_common.c
@@ -35,6 +35,34 @@
 	return 0;
 }
 
+int cli_parse_log_args(struct log_args *const args, const int opt, const char *const optarg)
+{
+	switch (opt) {
+	case OPTION_VERBOSE:
+		args->screen_level++;
+		if (args->screen_level > args->logfile_level)
+			args->logfile_level = args->screen_level;
+		break;
+	case OPTION_LOGFILE:
+		if (cli_check_filename(optarg, "log"))
+			return 1;
+
+		if (args->logfile) {
+			fprintf(stderr, "Warning: -o/--output specified multiple times.\n");
+			free(args->logfile);
+		}
+
+		args->logfile = strdup(optarg);
+		if (!args->logfile) {
+			fprintf(stderr, "Out of memory!\n");
+			return 2;
+		}
+		break;
+	}
+
+	return 0;
+}
+
 int cli_parse_flash_args(struct flash_args *const args, const int opt, const char *const optarg)
 {
 	switch (opt) {
diff --git a/include/cli.h b/include/cli.h
index 4ef264d..aec1a46 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -18,6 +18,8 @@
 #include "libflashprog.h"
 
 enum {
+	OPTION_VERBOSE = 'V',
+	OPTION_LOGFILE = 'o',
 	OPTION_CHIP = 'c',
 	OPTION_PROGRAMMER = 'p',
 	OPTION_LAYOUT = 'l',
@@ -32,6 +34,12 @@
 	OPTION_PROGRESS,
 };
 
+struct log_args {
+	enum flashprog_log_level screen_level;
+	enum flashprog_log_level logfile_level;
+	char *logfile;
+};
+
 struct flash_args {
 	char *chip;
 	char *prog_name;
@@ -47,6 +55,7 @@
 
 int cli_check_filename(const char *filename, const char *type);
 
+int cli_parse_log_args(struct log_args *, int opt, const char *optarg);
 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);
 int cli_process_layout_args(struct flashprog_layout **, struct flashprog_flashctx *, const struct layout_args *);