c89 - iomenu - interactive terminal-based selection menu HTML git clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- DIR commit f979f7c13ea6a13dfda617bc70e2e4cff9bd3879 DIR parent 831d075aa676cd1905db7374143f296b211ae4e5 HTML Author: Josuah Demangeon <mail@josuah.net> Date: Sun, 16 Apr 2017 13:03:15 +0200 c89 Diffstat: M Makefile | 2 +- M iomenu.1 | 4 +++- M iomenu.c | 101 +++++++++++++++++++------------ 3 files changed, 67 insertions(+), 40 deletions(-) --- DIR diff --git a/Makefile b/Makefile @@ -1,4 +1,4 @@ -CFLAGS = -std=c99 -Wpedantic -Wall -Wextra -g # -static +CFLAGS = -std=c89 -Wpedantic -Wall -Wextra -g # -static OBJ = ${SRC:.c=.o} all: clean iomenu DIR diff --git a/iomenu.1 b/iomenu.1 @@ -14,7 +14,9 @@ . . .Nm -.Op Fl tbs +.Op Fl t +.Op Fl b +.Op Fl s .Op Fl l Ar lines .Op Fl p Ar prompt . DIR diff --git a/iomenu.c b/iomenu.c @@ -12,19 +12,20 @@ #define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */ -#define CONTROL(char) (char ^ 0x40) -#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define CONTROL(char) (char ^ 0x40) +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + static struct winsize ws; static struct termios termios; int tty_fd; -static int current = 0, offset = 0, prev = 0, next = 0; -static int linec = 0, matchc = 0; -static char **linev = NULL, **matchv = NULL; -static char input[BUFSIZ], formatted[BUFSIZ * 8]; -static int opt_tb = 0, opt_l = 255; -static char *opt_p = "", opt_s = '\0'; +static int current = 0, offset = 0, prev = 0, next = 0; +static int linec = 0, matchc = 0; +static char **linev = NULL, **matchv = NULL; +static char input[BUFSIZ], formatted[BUFSIZ * 8]; +static int opt_tb = 0, opt_l = 255, opt_h = 0; +static char *argv0, *opt_p = "", opt_s = '\0'; static void @@ -87,8 +88,10 @@ reset_terminal(void) extern struct termios termios; extern struct winsize ws; + int i; + /* clear terminal */ - for (int i = 0; i < opt_l + 1; i++) + for (i = 0; i < opt_l + 1; i++) fputs("\r\033[K\n", stderr); /* reset cursor position */ @@ -136,20 +139,18 @@ read_lines(void) } -/* - * Prepare a string for printing. - */ static char * format(char *str, int cols) { extern char formatted[BUFSIZ * 8]; - int j = 0; + int i, j; - for (int i = 0; str[i] && j < cols; i++) { + for (i = j = 0; str[i] && j < cols; i++) { if (str[i] == '\t') { - for (int t = (j + 7) % 8 + 1; t > 0 && j < cols; t--) + int t = (j + 7) % 8 + 1; + while (t-- > 0 && j < cols) formatted[j++] = ' '; } else if (isprint(str[i])) { @@ -172,10 +173,9 @@ print_lines(int count) extern int opt_l; extern char opt_s; - int p = 0; /* amount of lines printed */ - offset = current / count * count; + int printed = 0, i = current / count * count; - for (int i = offset; p < count && i < matchc; p++, i++) { + while (printed++ < count && i < matchc) { char *s = format(matchv[i], ws.ws_col - 1); if (opt_s && matchv[i][0] == '#') { @@ -185,9 +185,11 @@ print_lines(int count) } else { fprintf(stderr, "\n\033[K %s\033[m", s); } + + i++; } - while (p++ < count) + while (printed++ < count) fputs("\n\033[K", stderr); } @@ -197,12 +199,12 @@ print_screen(void) { extern char formatted[BUFSIZ * 8]; - int cols = ws.ws_col - 1; + int cols = ws.ws_col - 1, i; + int count = MIN(opt_l, ws.ws_row - 1); fputs("\r\033[K", stderr); /* items */ - int count = MIN(opt_l, ws.ws_row - 1); print_lines(count); fprintf(stderr, "\033[%dA", count); @@ -212,7 +214,7 @@ print_screen(void) if (opt_p[0] != '\0') { format(opt_p, cols); fputs("\033[30;47m ", stderr); - for (int i = 0; formatted[i]; i++) + for (i = 0; formatted[i]; i++) fputc(formatted[i], stderr); fputs(" \033[m", stderr); cols -= strlen(formatted) + 1; @@ -233,8 +235,8 @@ match_line(char *line, char **tokv, int tokc) if (opt_s && line[0] == opt_s) return 2; - for (int i = 0; i < tokc; i++) - if (strstr(line, tokv[i]) == NULL) + while (tokc-- > 0) + if (strstr(line, tokv[tokc]) == NULL) return 0; return 1; @@ -247,7 +249,9 @@ move_line(signed int count) extern int current; extern char **matchv; - for (int i = current + count; 0 <= i && i < matchc; i += count) { + int i; + + for (i = current + count; 0 <= i && i < matchc; i += count) { if (!opt_s || matchv[i][0] != opt_s) { current = i; break; @@ -260,7 +264,7 @@ static void filter_lines(void) { char **tokv = NULL, *s, buffer[sizeof (input)]; - int tokc = 0, n = 0; + int tokc = 0, n = 0, i; current = offset = prev = next = 0; @@ -279,7 +283,7 @@ filter_lines(void) } matchc = 0; - for (int i = 0; i < linec; i++) + for (i = 0; i < linec; i++) if (match_line(linev[i], tokv, tokc)) matchv[matchc++] = linev[i]; @@ -293,13 +297,13 @@ filter_lines(void) static void remove_word_input() { - int len = strlen(input) - 1; + int len = strlen(input) - 1, i; - for (int i = len; i >= 0 && isspace(input[i]); i--) + for (i = len; i >= 0 && isspace(input[i]); i--) input[i] = '\0'; len = strlen(input) - 1; - for (int i = len; i >= 0 && !isspace(input[i]); i--) + for (i = len; i >= 0 && !isspace(input[i]); i--) input[i] = '\0'; filter_lines(); @@ -326,13 +330,28 @@ print_selection(void) extern int current; extern char **matchv, input[BUFSIZ]; - fputs("\r\033[K", stderr); + /* header */ + if (opt_h && opt_s) { + char **match = matchv + current; + while (--match >= matchv) { + if ((*match)[0] == opt_s) { + fputs(*match, stdout); + break; + } + } + + putchar('\t'); + } + + /* input or selection */ if (matchc == 0 || (opt_s && matchv[current][0] == opt_s)) { puts(input); } else { puts(matchv[current]); } + + fputs("\r\033[K", stderr); } @@ -415,7 +434,7 @@ input_get(void) static void usage(void) { - fputs("usage: iomenu [-b] [-t] [-s] [-l lines] [-p prompt]\n", stderr); + fprintf(stderr, "%s [-b] [-t] [-s] [-l lines] [-p prompt]\n", argv0); exit(EXIT_FAILURE); } @@ -429,13 +448,14 @@ main(int argc, char *argv[]) int exit_code; - for (int i = 1; i < argc; i++) { - if (argv[i][0] != '-' || strlen(argv[i]) != 2) + for (argv0 = argv[0], argv++, argc--; argc > 0; argv++, argc++) { + if ((*argv)[0] != '-' || (*argv)[1] == '\0' || (*argv)[2] != '\0') usage(); - switch (argv[i][1]) { + switch ((*argv)[1]) { case 'l': - if (++i >= argc || sscanf(argv[i], "%d", &opt_l) <= 0) + argv++; argc--; + if (argc == 0 || sscanf(*argv, "%d", &opt_l) <= 0) usage(); break; @@ -443,15 +463,20 @@ main(int argc, char *argv[]) case 'b': opt_tb = 'b'; break; case 'p': - if (++i >= argc) + argc--; argv++; + if (argc == 0) usage(); - opt_p = argv[i]; + opt_p = *argv; break; case 's': opt_s = '#'; break; + case 'h': + opt_h = 1; + break; + default: usage(); }