Start implementing struct flashprog_programmer

Our libflashprog API was already prepared for a programmer level context
stored in an opaque `struct flashprog_programmer`. We start filling this
struct with a pointer to the programmer driver (entry in the programmer
table) and a mutable copy of the parameter string.

Change-Id: If9a795627b1e50ea6006569e723f400ff337be20
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.sourcearcade.org/c/flashprog/+/72525
diff --git a/cli_classic.c b/cli_classic.c
index 1ffe4dd..79159c3 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -594,10 +594,11 @@
 		}
 	}
 
-	if (programmer_init(prog, pparam)) {
+	struct flashprog_programmer *flashprog;
+	if (flashprog_programmer_init(&flashprog, prog->name, pparam)) {
 		msg_perr("Error: Programmer initialization failed.\n");
 		ret = 1;
-		goto out_shutdown;
+		goto out;
 	}
 	tempstr = flashbuses_to_text(get_buses_supported());
 	msg_pdbg("The following protocols are supported: %s.\n", tempstr);
@@ -789,7 +790,7 @@
 	flashprog_layout_release(layout);
 
 out_shutdown:
-	flashprog_programmer_shutdown(NULL);
+	flashprog_programmer_shutdown(flashprog);
 out:
 	for (i = 0; i < chipcount; i++) {
 		flashprog_layout_release(flashes[i].default_layout);
diff --git a/flashprog.c b/flashprog.c
index a9bba8f..e8ab305 100644
--- a/flashprog.c
+++ b/flashprog.c
@@ -130,15 +130,16 @@
 	return rc;
 }
 
-int programmer_init(const struct programmer_entry *prog, const char *param)
+int programmer_init(struct flashprog_programmer *const prog)
 {
 	int ret;
 
-	if (prog == NULL) {
+	if (prog == NULL || prog->driver == NULL) {
 		msg_perr("Invalid programmer specified!\n");
 		return -1;
 	}
-	programmer = prog;
+	programmer = prog->driver;
+	programmer_param = prog->param;
 	/* Initialize all programmer specific data. */
 	/* Default to unlimited decode sizes. */
 	max_rom_decode = (const struct decode_sizes) {
@@ -154,16 +155,6 @@
 	/* Default to allowing writes. Broken programmers set this to 0. */
 	programmer_may_write = true;
 
-	if (param) {
-		programmer_param = strdup(param);
-		if (!programmer_param) {
-			msg_perr("Out of memory!\n");
-			return ERROR_FATAL;
-		}
-	} else {
-		programmer_param = NULL;
-	}
-
 	msg_pdbg("Initializing %s programmer\n", programmer->name);
 	ret = programmer->init();
 	if (programmer_param && strlen(programmer_param)) {
@@ -182,7 +173,6 @@
 			ret = ERROR_FATAL;
 		}
 	}
-	free(programmer_param);
 	programmer_param = NULL;
 	return ret;
 }
@@ -192,7 +182,7 @@
  * require a call to programmer_init() (afterwards).
  *
  * @return The OR-ed result values of all shutdown functions (i.e. 0 on success). */
-int programmer_shutdown(void)
+int programmer_shutdown(struct flashprog_programmer *const prog)
 {
 	int ret = 0;
 
diff --git a/include/programmer.h b/include/programmer.h
index 286516d..f45aab9 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -95,8 +95,13 @@
 extern const struct programmer_entry programmer_usbblaster_spi;
 extern const struct programmer_entry programmer_dirtyjtag_spi;
 
-int programmer_init(const struct programmer_entry *prog, const char *param);
-int programmer_shutdown(void);
+struct flashprog_programmer {
+	const struct programmer_entry *driver;
+	char *param; /* TODO: Replace with flashprog_cfg (cf. flashrom/master) */
+};
+
+int programmer_init(struct flashprog_programmer *);
+int programmer_shutdown(struct flashprog_programmer *);
 
 struct bitbang_spi_master {
 	/* Note that CS# is active low, so val=0 means the chip is active. */
diff --git a/libflashprog.c b/libflashprog.c
index ea1142d..a7f15b5 100644
--- a/libflashprog.c
+++ b/libflashprog.c
@@ -143,7 +143,33 @@
 		msg_ginfo(".\n");
 		return 1;
 	}
-	return programmer_init(programmer_table[prog], prog_param);
+
+	*flashprog = malloc(sizeof(**flashprog));
+	if (!*flashprog) {
+		msg_gerr("Out of memory!\n");
+		return 1;
+	}
+
+	(*flashprog)->driver = programmer_table[prog];
+	if (prog_param) {
+		(*flashprog)->param = strdup(prog_param);
+		if (!(*flashprog)->param) {
+			msg_gerr("Out of memory!\n");
+			goto _free_err;
+		}
+	} else {
+		(*flashprog)->param = NULL;
+	}
+
+	if (programmer_init(*flashprog))
+		goto _free_err;
+
+	return 0;
+
+_free_err:
+	free((*flashprog)->param);
+	free(*flashprog);
+	return 1;
 }
 
 /**
@@ -154,7 +180,10 @@
  */
 int flashprog_programmer_shutdown(struct flashprog_programmer *const flashprog)
 {
-	return programmer_shutdown();
+	if (programmer_shutdown(flashprog))
+		return 1;
+	free(flashprog);
+	return 0;
 }
 
 /* TODO: flashprog_programmer_capabilities()? */