From 72ef8c3d6dc48b108c81e2d4ff6176fff579db5c Mon Sep 17 00:00:00 2001
From: Vito Caputo <vcaputo@pengaru.com>
Date: Wed, 25 May 2022 19:25:19 -0700
Subject: setup: return the desc for failed setting on error

This commit improves the error printed when cli-supplied args
fail, adding at least the key name to what used to be just a
stringified errno:

```
$ src/rototiller --module=shapes,scale=99

Shape type:
 0:   circle
 1: pinwheel
 2:  rhombus
 3:     star
Enter a value 0-3 [1 (pinwheel)]:
Fatal error: unable to use args for setting "scale": Invalid argument
$
```
---
 src/main.c  | 22 ++++++++++++++--------
 src/setup.c |  9 +++++++--
 src/setup.h |  2 +-
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/src/main.c b/src/main.c
index 8906327..122fdea 100644
--- a/src/main.c
+++ b/src/main.c
@@ -120,7 +120,8 @@ static int setup_video(til_settings_t *settings, til_setting_t **res_setting, co
 
 /* turn args into settings, automatically applying defaults if appropriate, or interactively if appropriate. */
 /* returns negative value on error, 0 when settings unchanged from args, 1 when changed */
-static int setup_from_args(til_args_t *args, setup_t *res_setup)
+/* on error, *res_failed_desc _may_ be assigned with something useful. */
+static int setup_from_args(til_args_t *args, setup_t *res_setup, const til_setting_desc_t **res_failed_desc)
 {
 	int	r = -ENOMEM, changes = 0;
 	setup_t	setup = {};
@@ -133,13 +134,13 @@ static int setup_from_args(til_args_t *args, setup_t *res_setup)
 	if (!setup.video)
 		goto _err;
 
-	r = setup_interactively(setup.module, til_module_setup, args->use_defaults, &setup.module_setup);
+	r = setup_interactively(setup.module, til_module_setup, args->use_defaults, &setup.module_setup, res_failed_desc);
 	if (r < 0)
 		goto _err;
 	if (r)
 		changes = 1;
 
-	r = setup_interactively(setup.video, setup_video, args->use_defaults, &setup.video_setup);
+	r = setup_interactively(setup.video, setup_video, args->use_defaults, &setup.video_setup, res_failed_desc);
 	if (r < 0)
 		goto _err;
 	if (r)
@@ -242,9 +243,10 @@ static void * rototiller_thread(void *_rt)
  */
 int main(int argc, const char *argv[])
 {
-	setup_t		setup = {};
-	til_args_t	args = {};
-	int		r;
+	const til_setting_desc_t	*failed_desc = NULL;
+	setup_t				setup = {};
+	til_args_t			args = {};
+	int				r;
 
 	exit_if((r = til_init()) < 0,
 		"unable to initialize libtil: %s", strerror(-r));
@@ -255,8 +257,12 @@ int main(int argc, const char *argv[])
 	if (args.help)
 		return print_help() < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 
-	exit_if((r = setup_from_args(&args, &setup)) < 0,
-		"unable to setup: %s", strerror(-r));
+	exit_if((r = setup_from_args(&args, &setup, &failed_desc)) < 0,
+		"unable to use args%s%s%s: %s",
+		failed_desc ? " for setting \"" : "",
+		failed_desc ? failed_desc->key : "",
+		failed_desc ? "\"" : "",
+		strerror(-r));
 
 	exit_if(!args.gogogo && r && print_setup_as_args(&setup) < 0,
 		"unable to print setup");
diff --git a/src/setup.c b/src/setup.c
index a5b1c70..e4c22f3 100644
--- a/src/setup.c
+++ b/src/setup.c
@@ -1,6 +1,7 @@
 #include <assert.h>
 #include <stdio.h>
 
+#include "setup.h"
 #include "til_settings.h"
 #include "til_setup.h"
 #include "til_util.h"
@@ -22,7 +23,7 @@ static int add_value(til_settings_t *settings, const char *key, const char *valu
 
 
 /* returns negative on error, otherwise number of additions made to settings */
-int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup), int defaults, til_setup_t **res_setup)
+int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup), int defaults, til_setup_t **res_setup, const til_setting_desc_t **res_failed_desc)
 {
 	unsigned			additions = 0;
 	char				buf[256] = "\n";
@@ -44,8 +45,12 @@ int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings
 		if (setting && !setting->desc) {
 			 /* XXX FIXME: this key as value exception is janky, make a helper to access the value or stop doing that. */
 			r = til_setting_desc_check(desc, setting->value ? : setting->key);
-			if (r < 0)
+			if (r < 0) {
+				/* TODO: send back desc to caller, caller must free. */
+				*res_failed_desc = desc;
+
 				return r;
+			}
 
 			/* XXX FIXME everything's constified necessitating this fuckery, revisit and cleanup later, prolly another til_settings helper */
 			((til_setting_t *)setting)->desc = desc;
diff --git a/src/setup.h b/src/setup.h
index 3ca501d..948b820 100644
--- a/src/setup.h
+++ b/src/setup.h
@@ -4,6 +4,6 @@
 #include "til_settings.h"
 #include "til_setup.h"
 
-int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup), int defaults, til_setup_t **res_setup);
+int setup_interactively(til_settings_t *settings, int (*setup_func)(til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup), int defaults, til_setup_t **res_setup, const til_setting_desc_t **res_failed_desc);
 
 #endif
-- 
cgit v1.2.3