jcs
/subtext
/amendments
/387
settings: Make struct_editor use session_menu
Take args for menu additions, and use numbers for struct members
instead of letters
jcs made amendment 387 about 1 year ago
--- settings.c Mon Mar 6 17:09:53 2023
+++ settings.c Fri Mar 10 20:11:33 2023
@@ -17,6 +17,7 @@
#include <stdio.h>
#include <string.h>
+#include "ansi.h"
#include "subtext.h"
#include "db.h"
#include "focusable.h"
@@ -44,263 +45,265 @@ void view_editor_save(struct focusable *focusable, Eve
short
struct_editor(struct session *s, const struct struct_field *fields,
- const size_t nfields, void *data, size_t dsize, void **result,
+ const size_t nfields, const struct session_menu_option *extra_opts,
+ size_t nextra_opts, void *data, size_t dsize, void **result,
char *title, char *prompt)
{
+ static const struct session_menu_option opts[] = {
+ { '#', "", "Edit setting [#]" },
+ { 's', "Ss", "Save and return to main menu" },
+ { 'q', "QqXx", "Discard changes and return to main menu" },
+ { '?', "?", "List menu options" },
+ };
+ struct session_menu_option *dopts = NULL, *opt;
const struct struct_field *sf;
long lval;
char co, initial[20];
char *input = NULL, *new_data;
- short n, i, sval;
- bool found, any_changes = false;
+ size_t nopts;
+ short n, j, i, sval, on, ret;
+ bool any_changes, done, show_list;
unsigned short c;
- session_printf(s, "{{B}}Editor: %s{{/B}}\r\n", title);
- session_flush(s);
-
new_data = xmalloc(dsize);
if (new_data == NULL)
goto done;
memcpy(new_data, data, dsize);
+
+ nopts = nitems(opts) + nextra_opts;
+ dopts = xcalloc(sizeof(struct session_menu_option), nopts);
+ if (dopts == NULL)
+ return;
+ if (extra_opts != NULL)
+ memcpy(dopts, extra_opts,
+ sizeof(struct session_menu_option) * nextra_opts);
+ memcpy(dopts + nextra_opts, opts, sizeof(opts));
+
+ session_printf(s, "{{B}}Editor: %s{{/B}}\r\n", title);
+ session_flush(s);
+
+ any_changes = false;
+ show_list = true;
+ done = false;
+ ret = -1;
-print_options:
- for (n = 0; n < nfields; n++) {
- sf = &fields[n];
-
- if (n > 9)
- co = 'A' + (n - 10);
- else
- co = '0' + n;
-
- session_printf(s, "{{B}}%c{{/B}}: %s [", co, sf->name);
-
- switch (sf->type) {
- case CONFIG_TYPE_STRING:
- session_printf(s, "%s", new_data + sf->off);
- break;
- case CONFIG_TYPE_PASSWORD:
- i = strlen(new_data + sf->off);
- while (i) {
- session_output(s, "*", 1);
- i--;
+ while (!done && !s->ending) {
+ if (show_list) {
+ for (n = 0; n < nfields; n++) {
+ sf = &fields[n];
+
+ session_printf(s, "{{B}}%d{{/B}}: %s [", n + 1, sf->name);
+
+ switch (sf->type) {
+ case CONFIG_TYPE_STRING:
+ session_printf(s, "%s", new_data + sf->off);
+ break;
+ case CONFIG_TYPE_PASSWORD:
+ i = strlen(new_data + sf->off);
+ while (i) {
+ session_output(s, "*", 1);
+ i--;
+ }
+ break;
+ case CONFIG_TYPE_SHORT:
+ sval = CHARS_TO_SHORT(new_data[sf->off],
+ new_data[sf->off + 1]);
+ session_printf(s, "%d", sval);
+ break;
+ case CONFIG_TYPE_LONG:
+ lval = CHARS_TO_LONG(new_data[sf->off],
+ new_data[sf->off + 1], new_data[sf->off + 2],
+ new_data[sf->off + 3]);
+ session_printf(s, "%ld", lval);
+ break;
+ case CONFIG_TYPE_BOOLEAN:
+ session_printf(s, "%s",
+ new_data[sf->off] == 0 ? "false" : "true");
+ break;
+ case CONFIG_TYPE_IP: {
+ char ip_str[16];
+ lval = CHARS_TO_LONG(new_data[sf->off],
+ new_data[sf->off + 1], new_data[sf->off + 2],
+ new_data[sf->off + 3]);
+ if (lval == 0)
+ session_printf(s, "0.0.0.0");
+ else {
+ long2ip(lval, ip_str);
+ session_printf(s, "%s", ip_str);
+ }
+ break;
+ }
+ }
+
+ session_printf(s, "]\r\n");
}
- break;
- case CONFIG_TYPE_SHORT:
- sval = CHARS_TO_SHORT(new_data[sf->off], new_data[sf->off + 1]);
- session_printf(s, "%d", sval);
- break;
- case CONFIG_TYPE_LONG:
- lval = CHARS_TO_LONG(new_data[sf->off], new_data[sf->off + 1],
- new_data[sf->off + 2], new_data[sf->off + 3]);
- session_printf(s, "%ld", lval);
- break;
- case CONFIG_TYPE_BOOLEAN:
- session_printf(s, "%s",
- new_data[sf->off] == 0 ? "false" : "true");
- break;
- case CONFIG_TYPE_IP: {
- char ip_str[16];
- lval = CHARS_TO_LONG(new_data[sf->off], new_data[sf->off + 1],
- new_data[sf->off + 2], new_data[sf->off + 3]);
- if (lval == 0)
- session_printf(s, "0.0.0.0");
- else {
- long2ip(lval, ip_str);
- session_printf(s, "%s", ip_str);
- }
- break;
}
- }
- session_printf(s, "]\r\n");
- }
-
- session_printf(s, "{{B}}S{{/B}}: Save and return to main menu\r\n");
- session_printf(s, "{{B}}Q{{/B}}: Discard changes and return to main menu\r\n");
- session_printf(s, "{{B}}?{{/B}}: Print menu of options\r\n");
+ c = session_menu(s, NULL, prompt, dopts, nopts, show_list,
+ "Option #", &on);
+ show_list = false;
- for (;;) {
- session_printf(s, "{{B}}%s>{{/B}} ", prompt);
- session_flush(s);
-
-get_menu_option:
- c = session_input_char(s);
- if (s->ending) {
- any_changes = false;
+ switch (c) {
+ case 's':
goto done;
- }
- if (c == '\r' || c == 0 || c > 255)
- goto get_menu_option;
-
- session_printf(s, "%c\r\n", c);
- session_flush(s);
-
- if (c == '?')
- goto print_options;
- if (c == 'S' || c == 's')
- break;
- if (c == 'Q' || c == 'q') {
+ case 'q':
any_changes = false;
goto done;
- }
-
- found = false;
- sf = NULL;
- for (n = 0; n < nfields; n++) {
- sf = &fields[n];
-
- if (n <= 9 && c == '0' + n) {
- found = true;
+ case '?':
+ show_list = true;
+ break;
+ case '#':
+ if (on < 1 || on > nfields) {
+ session_printf(s, "Invalid option\r\n");
+ session_flush(s);
break;
}
- if (n > 9 && (c == 'A' + (n - 10) || c == 'a' + (n - 10))) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- session_printf(s, "Invalid option ({{B}}?{{/B}} for help)\r\n");
- session_flush(s);
- continue;
- }
+ sf = &fields[on - 1];
get_input:
- session_printf(s, "{{B}}%s:{{/B}} ", sf->name);
- session_flush(s);
-
- switch (sf->type) {
- case CONFIG_TYPE_STRING:
- case CONFIG_TYPE_PASSWORD:
- input = session_field_input(s, sf->max, 50, new_data + sf->off,
- false, (sf->type == CONFIG_TYPE_PASSWORD ? '*' : 0));
- session_output(s, "\r\n", 2);
+ session_printf(s, "{{B}}%s:{{/B}} ", sf->name);
session_flush(s);
- if (input == NULL || s->ending)
+
+ switch (sf->type) {
+ case CONFIG_TYPE_STRING:
+ case CONFIG_TYPE_PASSWORD:
+ input = session_field_input(s, sf->max, 50,
+ new_data + sf->off, false,
+ (sf->type == CONFIG_TYPE_PASSWORD ? '*' : 0));
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+ if (input == NULL || s->ending)
+ break;
+
+ if (strlen(input) >= sf->max) {
+ session_printf(s,
+ "%s is too long (%d max, ^C to cancel)", sf->name,
+ sf->max - 1);
+ xfree(&input);
+ goto get_input;
+ }
+ strlcpy(new_data + sf->off, input, sf->max);
+ any_changes = true;
break;
-
- if (strlen(input) >= sf->max) {
- session_printf(s,
- "%s is too long (%d max, ^C to cancel)", sf->name,
- sf->max - 1);
- xfree(&input);
- goto get_input;
- }
- strlcpy(new_data + sf->off, input, sf->max);
- any_changes = true;
- break;
- case CONFIG_TYPE_SHORT:
- case CONFIG_TYPE_LONG:
- if (sf->type == CONFIG_TYPE_LONG) {
+ case CONFIG_TYPE_SHORT:
+ case CONFIG_TYPE_LONG:
+ if (sf->type == CONFIG_TYPE_LONG) {
+ lval = CHARS_TO_LONG(new_data[sf->off],
+ new_data[sf->off + 1], new_data[sf->off + 2],
+ new_data[sf->off + 3]);
+ snprintf(initial, sizeof(initial), "%ld", lval);
+ } else {
+ sval = CHARS_TO_SHORT(new_data[sf->off],
+ new_data[sf->off + 1]);
+ snprintf(initial, sizeof(initial), "%d", sval);
+ }
+ input = session_field_input(s, 10, 10, initial, false, 0);
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+ if (input == NULL || s->ending)
+ break;
+
+ lval = atol(input);
+ if (lval < sf->min) {
+ session_printf(s,
+ "%s must be %ld or higher (^C to cancel)\r\n",
+ sf->name, sf->min);
+ xfree(&input);
+ goto get_input;
+ }
+ if (lval > sf->max) {
+ session_printf(s,
+ "%s must be %lu or less (^C to cancel)\r\n",
+ sf->name, sf->max);
+ xfree(&input);
+ goto get_input;
+ }
+ if (sf->type == CONFIG_TYPE_LONG) {
+ new_data[sf->off] = (lval >> 24) & 0xff;
+ new_data[sf->off + 1] = (lval >> 16) & 0xff;
+ new_data[sf->off + 2] = (lval >> 8) & 0xff;
+ new_data[sf->off + 3] = lval & 0xff;
+ } else {
+ sval = lval;
+ new_data[sf->off] = (sval >> 8) & 0xff;
+ new_data[sf->off + 1] = sval & 0xff;
+ }
+ any_changes = true;
+ break;
+ case CONFIG_TYPE_BOOLEAN:
+ if (new_data[sf->off])
+ session_printf(s, "[Y/n] ");
+ else
+ session_printf(s, "[y/N] ");
+ session_flush(s);
+
+ for (;;) {
+ c = session_input_char(s);
+ if (s->ending)
+ break;
+ if (c == '\r' && new_data[sf->off])
+ c = 'y';
+ else if (c == '\r' && new_data[sf->off] == 0)
+ c = 'n';
+ if (c == 'y' || c == 'Y') {
+ new_data[sf->off] = 1;
+ any_changes = true;
+ session_printf(s, "%c\r\n", c);
+ break;
+ }
+ if (c == 'n' || c == 'N') {
+ new_data[sf->off] = 0;
+ any_changes = true;
+ session_printf(s, "%c\r\n", c);
+ break;
+ }
+ }
+ break;
+ case CONFIG_TYPE_IP: {
+ char ip_str[16];
lval = CHARS_TO_LONG(new_data[sf->off],
new_data[sf->off + 1], new_data[sf->off + 2],
new_data[sf->off + 3]);
- snprintf(initial, sizeof(initial), "%ld", lval);
- } else {
- sval = CHARS_TO_SHORT(new_data[sf->off],
- new_data[sf->off + 1]);
- snprintf(initial, sizeof(initial), "%d", sval);
- }
- input = session_field_input(s, 10, 10, initial, false, 0);
- session_output(s, "\r\n", 2);
- session_flush(s);
- if (input == NULL || s->ending)
- break;
-
- lval = atol(input);
- if (lval < sf->min) {
- session_printf(s,
- "%s must be %ld or higher (^C to cancel)\r\n", sf->name,
- sf->min);
- xfree(&input);
- goto get_input;
- }
- if (lval > sf->max) {
- session_printf(s,
- "%s must be %lu or less (^C to cancel)\r\n", sf->name,
- sf->max);
- xfree(&input);
- goto get_input;
- }
- if (sf->type == CONFIG_TYPE_LONG) {
+ if (lval == 0)
+ snprintf(initial, sizeof(initial), "0.0.0.0");
+ else {
+ long2ip(lval, ip_str);
+ snprintf(initial, sizeof(initial), "%s", ip_str);
+ }
+
+ input = session_field_input(s, 16, 16, initial, false, 0);
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+ if (input == NULL || s->ending)
+ break;
+
+ if (input[0] == '\0') {
+ lval = 0;
+ xfree(&input);
+ } else {
+ lval = ip2long(input);
+ xfree(&input);
+ if (lval == 0) {
+ session_printf(s,
+ "Invalid IP address (^C to cancel)\r\n");
+ goto get_input;
+ }
+ }
new_data[sf->off] = (lval >> 24) & 0xff;
new_data[sf->off + 1] = (lval >> 16) & 0xff;
new_data[sf->off + 2] = (lval >> 8) & 0xff;
new_data[sf->off + 3] = lval & 0xff;
- } else {
- sval = lval;
- new_data[sf->off] = (sval >> 8) & 0xff;
- new_data[sf->off + 1] = sval & 0xff;
+ any_changes = true;
+ break;
}
- any_changes = true;
- break;
- case CONFIG_TYPE_BOOLEAN:
- if (new_data[sf->off])
- session_printf(s, "[Y/n] ");
- else
- session_printf(s, "[y/N] ");
- session_flush(s);
-
- for (;;) {
- c = session_input_char(s);
- if (s->ending)
- break;
- if (c == '\r' && new_data[sf->off])
- c = 'y';
- else if (c == '\r' && new_data[sf->off] == 0)
- c = 'n';
- if (c == 'y' || c == 'Y') {
- new_data[sf->off] = 1;
- any_changes = true;
- session_printf(s, "%c\r\n", c);
- break;
- }
- if (c == 'n' || c == 'N') {
- new_data[sf->off] = 0;
- any_changes = true;
- session_printf(s, "%c\r\n", c);
- break;
- }
}
break;
- case CONFIG_TYPE_IP: {
- char ip_str[16];
- lval = CHARS_TO_LONG(new_data[sf->off], new_data[sf->off + 1],
- new_data[sf->off + 2], new_data[sf->off + 3]);
- if (lval == 0)
- snprintf(initial, sizeof(initial), "0.0.0.0");
- else {
- long2ip(lval, ip_str);
- snprintf(initial, sizeof(initial), "%s", ip_str);
- }
-
- input = session_field_input(s, 16, 16, initial, false, 0);
- session_output(s, "\r\n", 2);
- session_flush(s);
- if (input == NULL || s->ending)
- break;
-
- if (input[0] == '\0') {
- lval = 0;
- xfree(&input);
- } else {
- lval = ip2long(input);
- xfree(&input);
- if (lval == 0) {
- session_printf(s,
- "Invalid IP address (^C to cancel)\r\n");
- goto get_input;
- }
- }
- new_data[sf->off] = (lval >> 24) & 0xff;
- new_data[sf->off + 1] = (lval >> 16) & 0xff;
- new_data[sf->off + 2] = (lval >> 8) & 0xff;
- new_data[sf->off + 3] = lval & 0xff;
- any_changes = true;
+ default:
+ ret = c;
+ done = true;
break;
}
- }
if (s->ending) {
any_changes = false;
@@ -308,14 +311,16 @@ get_input:
}
}
-done:
+done:
+ xfree(&dopts);
+
if (any_changes) {
*result = new_data;
return 0;
} else {
xfree(&new_data);
*result = NULL;
- return -1;
+ return ret;
}
}
--- settings.h Mon Mar 6 17:09:30 2023
+++ settings.h Fri Mar 10 15:22:18 2023
@@ -37,7 +37,8 @@ struct struct_field {
};
short struct_editor(struct session *s, const struct struct_field *fields,
- const size_t nfields, void *data, size_t dsize, void **result,
+ const size_t nfields, const struct session_menu_option *extra_opts,
+ size_t nextra_opts, void *data, size_t dsize, void **result,
char *title, char *prompt);
void view_editor_show(size_t id, char *title);