summaryrefslogtreecommitdiff
path: root/src/setup.c
blob: 6c4a87f4f0ab2ebfc0c382df38af7cf2c53f3ec9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <assert.h>
#include <stdio.h>

#include "settings.h"
#include "util.h"

/* add key=value, but if key is NULL, use value as key. */
static int add_value(settings_t *settings, const char *key, const char *value)
{
	assert(settings);

	if (!key) {
		key = value;
		value = NULL;
	}

	assert(key);

	return settings_add_value(settings, key, value);
}


/* returns negative on error, otherwise number of additions made to settings */
int setup_interactively(settings_t *settings, int (*setup_func)(settings_t *settings, setting_desc_t **next), int defaults)
{
	unsigned	additions = 0;
	char		buf[256] = "\n";
	setting_desc_t	*next;
	int		r;

	assert(settings);
	assert(setup_func);

	/* TODO: regex and error handling */

	while ((r = setup_func(settings, &next)) > 0) {
		additions++;

		if (!defaults)
			puts("");

		if (next->values) {
			unsigned	i, preferred = 0;
			int		width = 0;

			for (i = 0; next->values[i]; i++) {
				int	len;

				len = strlen(next->values[i]);
				if (len > width)
					width = len;
			}

			/* multiple choice */
			if (!defaults)
				printf("Select %s:\n", next->name);

			for (i = 0; next->values[i]; i++) {
				if (!defaults)
					printf(" %u: %*s%s%s\n", i, width, next->values[i],
						next->annotations ? ": " : "",
						next->annotations ? next->annotations[i] : "");

				if (!strcmp(next->preferred, next->values[i]))
					preferred = i;
			}

			if (!defaults)
				printf("Enter a value 0-%u [%u (%s)]: ",
					i - 1, preferred, next->preferred);
		} else {
			/* arbitrarily typed input */
			if (!defaults)
				printf("%s [%s]: ", next->name, next->preferred);
		}

		if (!defaults) {
			fflush(stdout);
			fgets(buf, sizeof(buf), stdin);
		}

		if (*buf == '\n') {
			/* accept preferred */
			add_value(settings, next->key, next->preferred);
		} else {
			buf[strlen(buf) - 1] = '\0';

			if (next->values) {
				unsigned	i, j, found;

				/* multiple choice, map numeric input to values entry */
				if (sscanf(buf, "%u", &j) < 1) {
					printf("Invalid input: \"%s\"\n", buf);

					goto _next;
				}

				for (found = i = 0; next->values[i]; i++) {
					if (i == j) {
						add_value(settings, next->key, next->values[i]);
						found = 1;
						break;
					}
				}

				if (!found) {
					printf("Invalid option: %u outside of range [0-%u]\n",
						j, i - 1);

					goto _next;
				}

			} else {
				/* use typed input as setting, TODO: apply regex */
				add_value(settings, next->key, buf);
			}
		}

_next:
		setting_desc_free(next);
	}

	return r < 0 ? r : additions;
}
© All Rights Reserved