iomenu

interactive text selection menu
Log | Files | Refs | README | LICENSE

commit b69d6f5982f4c2b96f8dee1369c48180ed31b035
parent afbe8d1e4630f1e1ca5f55d8f2a61ef63956494c
Author: Josuah Demangeon <mail@josuah.net>
Date:   Thu,  2 Nov 2017 01:09:48 +0100

linux kernel coding style -> BSD

Diffstat:
MLICENSE | 12+++++-------
Mbuffer.c | 65+++++++++++++++++++++++++++++++++++++++++++++++------------------
Mbuffer.h | 6+++---
Mcontrol.c | 35+++++++++++++++++++++++++++--------
Mcontrol.h | 8++++----
Mdisplay.c | 26+++++++++++++++++++++-----
Mdisplay.h | 4++--
Miomenu.h | 28++++++++++++++--------------
Mmain.c | 58++++++++++++++++++++++++++++++++++++++++++----------------
Mmain.h | 2+-
Mutf8.c | 5+----
Mutf8.h | 12++++++------
12 files changed, 173 insertions(+), 88 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -1,15 +1,13 @@ -ISC Licence +Copyright (c) 2017 Josuah Demangeon <mail@josuah.net> -Copyright (c) 2017 by Josuah Demangeon - -Permission to use, copy, modify, and/or distribute this software for any +Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED “AS IS” AND ISC DISCLAIMS ALL WARRANTIES +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY -SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/buffer.c b/buffer.c @@ -11,6 +11,10 @@ #include "main.h" #include "control.h" +/* + * Keep the line if it match every token (in no particular order, and allowed to + * be overlapping). + */ static int match_line(char *line, char **tokv, int tokc) { @@ -22,10 +26,15 @@ match_line(char *line, char **tokv, int tokc) return 1; } +/* + * As we use a single buffer for the whole stdin, we only need to free it once + * and it will free all the lines. + */ void free_lines(void) { - extern char **linev; + extern char **linev; + extern char **matchv; if (linev) { free(linev[0]); @@ -35,14 +44,20 @@ free_lines(void) free(matchv); } +/* + * Split a buffer into an array of lines, without allocating memory for every + * line, but using the input buffer and replacing characters. + */ void split_lines(char *buf) { - extern char **linev; - extern int linec; - char *b; - char **lv; - char **mv; + extern char **linev; + extern char **matchv; + extern int linec; + + char *b; + char **lv; + char **mv; linec = 0; b = buf; @@ -64,15 +79,20 @@ split_lines(char *buf) } } +/* + * Read stdin in a single malloc-ed buffer, realloc-ed to twice its size every + * time the previous buffer is filled. + */ void read_stdin(void) { - size_t size = BUFSIZ; - size_t len; - size_t off; - char *buf; - char *b; + size_t size; + size_t len; + size_t off; + char *buf; + char *b; + size = BUFSIZ; off = 0; buf = malloc(size); while ((len = read(STDIN_FILENO, buf + off, size - off)) > 0) { @@ -90,17 +110,26 @@ read_stdin(void) split_lines(buf); } +/* + * First split input into token, then match every token independently against + * every line. The matching lines fills matchv. + */ void filter(void) { - extern char **linev; - extern int current; - int tokc; - int n; - char **tokv = NULL; - char *s; - char buf[sizeof (input)]; + extern char **linev; + extern char **matchv; + extern int linec; + extern int matchc; + extern int current; + + int tokc; + int n; + char **tokv; + char *s; + char buf[sizeof (input)]; + tokv = NULL; current = 0; strcpy(buf, input); tokc = 0; diff --git a/buffer.h b/buffer.h @@ -1,3 +1,3 @@ -void free_lines (void); -void read_stdin (void); -void filter(void); +void free_lines(void); +void read_stdin(void); +void filter(void); diff --git a/control.c b/control.c @@ -11,14 +11,17 @@ #include "control.h" #include "display.h" -#define CTL(char) ((char) ^ 0x40) -#define ALT(char) ((char) + 0x80) -#define CSI(char) ((char) + 0x80 + 0x80) +#define CTL(char) ((char) ^ 0x40) +#define ALT(char) ((char) + 0x80) +#define CSI(char) ((char) + 0x80 + 0x80) void move(signed int sign) { - int i; + extern char **matchv; + extern int matchc; + + int i; for (i = current + sign; 0 <= i && i < matchc; i += sign) { if (!opt['#'] || matchv[i][0] != '#') { @@ -31,9 +34,13 @@ move(signed int sign) static void move_page(signed int sign) { - int i; - int rows = ws.ws_row - 1; + extern struct winsize ws; + extern int matchc; + + int i; + int rows; + rows = ws.ws_row - 1; i = current - current % rows + rows * sign; if (!(0 <= i && i < matchc)) return; @@ -44,6 +51,8 @@ move_page(signed int sign) static void remove_word() { + extern char input[LINE_MAX]; + int len; int i; @@ -59,6 +68,8 @@ remove_word() static void add_char(char c) { + extern char input[LINE_MAX]; + int len; len = strlen(input); @@ -69,9 +80,17 @@ add_char(char c) filter(); } +/* + * Big case table, that calls itself back for with ALT (aka ESC), CSI + * (aka ESC + [). These last two have values above the range of ASCII. + */ int key(int k) { + extern char **matchv; + extern char input[LINE_MAX]; + extern int linec; + top: switch (k) { case CTL('C'): @@ -99,14 +118,14 @@ top: case CSI('5'): /* page up */ if (fgetc(stdin) != '~') break; - /* fallthrough */ + /* FALLTHROUGH */ case ALT('v'): move_page(-1); break; case CSI('6'): /* page down */ if (fgetc(stdin) != '~') break; - /* fallthrough */ + /* FALLTHROUGH */ case CTL('V'): move_page(+1); break; diff --git a/control.h b/control.h @@ -1,4 +1,4 @@ -int prev_page (int); -int next_page (int); -void move (signed int); -int key (int); +int prev_page(int); +int next_page(int); +void move(signed int); +int key(int); diff --git a/display.c b/display.c @@ -11,6 +11,8 @@ static char * format(char *str, int cols) { + extern struct winsize ws; + int col = 0; long rune = 0; char *fmt = formatted; @@ -42,6 +44,8 @@ format(char *str, int cols) static void print_line(char *line, int cur) { + extern struct winsize ws; + if (opt['#'] && line[0] == '#') { format(line + 1, ws.ws_col - 1); fprintf(stderr, "\n\x1b[1m %s\x1b[m", formatted); @@ -57,12 +61,20 @@ print_line(char *line, int cur) void print_screen(void) { - char **m; - int p; - int i; - int cols = ws.ws_col - 1; - int rows = ws.ws_row - 1; + extern struct winsize ws; + extern char **matchv; + extern char *prompt; + extern char input[LINE_MAX]; + extern int matchc; + char **m; + int p; + int i; + int cols; + int rows; + + cols = ws.ws_col - 1; + rows = ws.ws_row - 1; p = 0; i = current - current % rows; m = matchv + i; @@ -85,6 +97,10 @@ print_screen(void) void print_selection(void) { + extern char **matchv; + extern char input[LINE_MAX]; + extern int matchc; + char **match; if (opt['#']) { diff --git a/display.h b/display.h @@ -1,2 +1,2 @@ -void print_screen (void); -void print_selection (void); +void print_screen(void); +void print_selection(void); diff --git a/iomenu.h b/iomenu.h @@ -1,18 +1,18 @@ -#ifndef SIGWINCH -#define SIGWINCH 28 +#ifndef SIGWINCH +#define SIGWINCH 28 #endif -#define MARGIN 30 +#define MARGIN 30 -#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) -extern struct winsize ws; -extern char **linev; -extern int linec; -extern char **matchv; -extern int matchc; -extern char *prompt; -extern char input[LINE_MAX]; -extern char formatted[LINE_MAX * 8]; -extern int current; -extern int opt[128]; +extern struct winsize ws; +extern char **linev; +extern int linec; +extern char **matchv; +extern int matchc; +extern char *prompt; +extern char input[LINE_MAX]; +extern char formatted[LINE_MAX * 8]; +extern int current; +extern int opt[128]; diff --git a/main.c b/main.c @@ -15,20 +15,23 @@ #include "control.h" #include "display.h" -static struct termios termios; -static int ttyfd; - -struct winsize ws; -char **linev = NULL; -int linec = 0; -char **matchv = NULL; -int matchc = 0; -char *prompt = ""; -char input[LINE_MAX]; -char formatted[LINE_MAX * 8]; -int current = 0; -int opt[128]; +static struct termios termios; +static int ttyfd; +struct winsize ws; +char **linev = NULL; +int linec = 0; +char **matchv = NULL; +int matchc = 0; +char *prompt = ""; +char input[LINE_MAX]; +char formatted[LINE_MAX * 8]; +int current = 0; +int opt[128]; + +/* + * Free the structures, reset the terminal state and exit with an error message. + */ void die(const char *s) { @@ -39,10 +42,13 @@ die(const char *s) exit(EXIT_FAILURE); } +/* + * Set terminal in raw mode. + */ static void set_terminal(void) { - struct termios new; + struct termios new; fputs("\x1b[s\x1b[?1049h\x1b[H", stderr); if (tcgetattr(ttyfd, &termios) < 0 || tcgetattr(ttyfd, &new) < 0) { @@ -53,6 +59,9 @@ set_terminal(void) tcsetattr(ttyfd, TCSANOW, &new); } +/* + * Take terminal out of raw mode. + */ static void reset_terminal(void) { @@ -60,9 +69,14 @@ reset_terminal(void) tcsetattr(ttyfd, TCSANOW, &termios); } +/* + * Redraw the whole screen on window resize. + */ static void sigwinch() { + extern struct winsize ws; + if (ioctl(ttyfd, TIOCGWINSZ, &ws) < 0) die("ioctl"); print_screen(); @@ -72,13 +86,18 @@ sigwinch() static void usage(void) { - fputs("iomenu [-#] [-p prompt]\n", stderr); + fputs("usage: iomenu [-#] [-p prompt]\n", stderr); exit(EXIT_FAILURE); } +/* + * XXX: switch to getopt. + */ static void parse_opt(int argc, char *argv[]) { + extern char *prompt; + memset(opt, 0, 128 * sizeof (int)); for (argv++, argc--; argc > 0; argv++, argc--) { if (argv[0][0] != '-') @@ -98,10 +117,17 @@ parse_opt(int argc, char *argv[]) } } +/* + * Read stdin in a buffer, filling a table of lines, then re-open stdin to + * /dev/tty for an interactive (raw) session to let the user filter and select + * one line by searching words within stdin. This was inspired from dmenu. + */ int main(int argc, char *argv[]) { - int exit_code; + extern char input[LINE_MAX]; + + int exit_code; parse_opt(argc, argv); read_stdin(); diff --git a/main.h b/main.h @@ -1 +1 @@ -void die (const char *); +void die(const char *); diff --git a/utf8.c b/utf8.c @@ -1,7 +1,3 @@ -#include <stddef.h> - -#include "utf8.h" - /* * ASCII all have a leading '0' byte: * @@ -27,6 +23,7 @@ */ #include <ctype.h> +#include <stddef.h> #include <stdlib.h> #include <string.h> diff --git a/utf8.h b/utf8.h @@ -1,6 +1,6 @@ -size_t utf8_len (char *); -size_t rune_len (long); -size_t utf8_to_rune (long *, char *); -int utf8_is_unicode (long); -int utf8_check (char *); -int utf8_is_print (long); +size_t utf8_len(char *); +size_t rune_len(long); +size_t utf8_to_rune(long *, char *); +int utf8_is_unicode(long); +int utf8_check(char *); +int utf8_is_print(long);