iomenu

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

commit 0a259537342b214215afbeb7625ba86142ba7e8f
parent b327379ab041e7fbd37f3246b1affe7014109135
Author: Josuah Demangeonā  ā µ <mail@josuah.net>
Date:   Mon, 13 Mar 2017 22:10:01 +0100

(broken) removing a lot of code

Diffstat:
MMakefile | 8+-------
Mbuffer.c | 52++++++++--------------------------------------------
Mdraw.c | 38++++++++++----------------------------
Minput.c | 12+-----------
Miomenu.1 | 5+++--
Aiomenu.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aiomenu.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dmain.c | 91-------------------------------------------------------------------------------
Dmain.h | 95-------------------------------------------------------------------------------
Dnohup.out | 92-------------------------------------------------------------------------------
Dutil.c | 73-------------------------------------------------------------------------
11 files changed, 218 insertions(+), 443 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,17 +1,11 @@ CFLAGS = -std=c89 -pedantic -Wall -Wextra -g -static -SRC = main.c buffer.c util.c draw.c input.c OBJ = ${SRC:.c=.o} MANPREFIX = $(PREFIX) all: clean iomenu -.c.o: - ${CC} -c ${CFLAGS} $< - -iomenu: ${OBJ} - ${CC} -o $@ ${OBJ} ${LDFLAGS} - rm -f *.o +iomenu: buffer.c draw.c input.c clean: rm -f iomenu ${OBJ} diff --git a/buffer.c b/buffer.c @@ -3,18 +3,18 @@ #include <stdlib.h> #include <string.h> -#include "main.h" +#include "iomenu.h" /* - * Fill the buffer apropriately with the lines and headers. + * Fill the buffer apropriately with the lines */ Buffer * fill_buffer(char *separator) { /* fill buffer with string */ char s[LINE_SIZE]; - Buffer *buffer = malloc(sizeof(Buffer)); + Line **buffer = malloc(sizeof(Line)); FILE *fp = stdin; int l; @@ -26,22 +26,13 @@ fill_buffer(char *separator) /* empty line in case no line come from stdin */ buffer->first = buffer->current = malloc(sizeof(Line)); - buffer->first->content = buffer->first->comment = ""; buffer->first->next = buffer->first->prev = NULL; buffer->last = NULL; /* read the file into a doubly linked list of lines */ - for (l = 1; fgets(s, LINE_SIZE, fp); buffer->total++, l++) { + for (l = 1; fgets(s, LINE_SIZE, fp); buffer->total++, l++) buffer->last = add_line(buffer, l, s, separator, buffer->last); - l = buffer->last->header ? 0 : l; - } - - /* prevent initial current line to be a header */ - buffer->current = buffer->first; - while (buffer->current->next && buffer->current->header) - buffer->current = buffer->current->next; - return buffer; } @@ -70,40 +61,16 @@ add_line(Buffer *buffer, int number, char *s, char *separator, Line *prev) } -/* - * Parse the line content to determine if it is a header and identify the - * separator if any. - */ Line * new_line(char *s, char *separator) { Line *line = malloc(sizeof(Line)); - char *sep = separator ? strstr(s, separator) : NULL; - int pos = sep ? (int) (sep - s) : (int) strlen(s) - 1; - - /* header is when separator is the first character of the line */ - line->header = (sep == s); /* strip trailing newline */ s[strlen(s) - 1] = '\0'; /* fill line->content */ - line->content = malloc((pos + 1) * sizeof(char)); - strncpy(line->content, s, pos); - - /* fill line->comment */ - line->comment = malloc((strlen(s) - pos) * sizeof(char)); - if (sep) { - strcpy(line->comment, s + pos + strlen(separator)); - } - - /* strip trailing whitespaces from line->content */ - for (pos--; pos > 0 && isspace(line->content[pos]); pos--) - line->content[pos] = '\0'; - - /* strip leading whitespaces from line->comment */ - for (pos = 0; isspace(line->comment[pos]); pos++); - line->comment += pos; + line->content = s; return line; } @@ -161,7 +128,7 @@ filter_lines(Buffer *buffer, int inc) buffer->current = line; } else if ((inc && line->matches) || (!inc && !line->matches)) { line->matches = match_line(line, tokv, tokc); - buffer->matching += line->header ? 0 : line->matches; + buffer->matching += line->matches; } line = line->next; @@ -177,9 +144,6 @@ match_line(Line *line, char **tokv, size_t tokc) { size_t i, match = 1, offset = 0; - if (line->header) - return 1; - for (i = 0; i < tokc && match; i++) match = !!strstr(line->content + offset, tokv[i]); @@ -193,7 +157,7 @@ match_line(Line *line, char **tokv, size_t tokc) Line * matching_prev(Line *line) { - while ((line = line->prev) && (!line->matches || line->header)); + while ((line = line->prev) && !line->matches); return line; } @@ -204,6 +168,6 @@ matching_prev(Line *line) Line * matching_next(Line *line) { - while ((line = line->next) && (!line->matches || line->header)); + while ((line = line->next) && !line->matches); return line; } diff --git a/draw.c b/draw.c @@ -3,7 +3,7 @@ #include <stdio.h> #include <sys/ioctl.h> -#include "main.h" +#include "iomenu.h" /* @@ -12,12 +12,10 @@ void draw_line(Line *line, int current, const int cols, Opt *opt) { - char *content = expand_tabs(line->content); - char *comment = expand_tabs(line->comment); char output[LINE_SIZE * sizeof(char)] = "\033[K"; int n = 0; - if (opt->line_numbers && !line->header) { + if (opt->line_numbers) { strcat(output, current ? "\033[1;37m" : "\033[1;30m"); sprintf(output + strlen(output), "%7d\033[m ", line->number); } else { @@ -25,34 +23,22 @@ draw_line(Line *line, int current, const int cols, Opt *opt) } n += 8; - /* highlight current line */ if (current) strcat(output, "\033[1;33m"); /* content */ - strncat(output, content, cols - n); - n += strlen(content); - - /* align comment */ - if (!line->header && line->comment[0] != '\0') { - /* MAX with '1' as \033[0C still move 1 to the right */ - sprintf(output + strlen(output), "\033[%dC", - MAX(1, 40 - n)); - n += MAX(1, 40 - n); - } else if (line->header) - - /* comment */ - strcat(output, "\033[1;30m"); - strncat(output, comment, cols - n); - n += strlen(comment); + strncat(output, line->content, cols - n); + n += strlen(line->content); + /* MAX with '1' as \033[0C still move 1 to the right */ + sprintf(output + strlen(output), "\033[%dC", + MAX(1, 40 - n)); + n += MAX(1, 40 - n); strcat(output, "\033[m\n"); fputs(output, stderr); - free(content); - free(comment); } @@ -137,8 +123,6 @@ draw_prompt(Buffer *buffer, int cols, Opt *opt) size_t i; int matching = buffer->matching; int total = buffer->total; - char *input = expand_tabs(buffer->input); - char *suggest = expand_tabs(buffer->current->content); /* for the '/' separator between the numbers */ cols--; @@ -153,8 +137,8 @@ draw_prompt(Buffer *buffer, int cols, Opt *opt) cols -= 2 + MAX(strlen(opt->prompt), 6); /* input without overflowing terminal width */ - for (i = 0; i < strlen(input) && cols > 0; cols--, i++) - fputc(input[i], stderr); + for (i = 0; i < strlen(buffer->input) && cols > 0; cols--, i++) + fputc(buffer->input[i], stderr); /* save the cursor position at the end of the input */ fputs("\033[s", stderr); @@ -171,6 +155,4 @@ draw_prompt(Buffer *buffer, int cols, Opt *opt) /* restore cursor position at the end of the input */ fputs("\033[m\033[u", stderr); - free(input); - free(suggest); } diff --git a/input.c b/input.c @@ -4,7 +4,7 @@ #include <string.h> #include <termios.h> -#include "main.h" +#include "iomenu.h" /* @@ -214,16 +214,6 @@ action_print_selection(Buffer *buffer, int return_input, Opt *opt) fputs("\r\033[K", stderr); - if (opt->print_header) { - for (line = buffer->current; line; line = line->prev) { - if (line->header) { - fputs(line->comment, stdout); - break; - } - } - fputc((int) '\t', stdout); - } - if (opt->print_number) { if (buffer->matching > 0) printf("%d\n", buffer->current->number); diff --git a/iomenu.1 b/iomenu.1 @@ -1,11 +1,12 @@ -.Dd $Mdocdate: October 16 2016 $ +.Dd Mars 16 2016 .Dt IOMENU 1 .Os +. .Sh NAME +. .Nm iomenu .Op Fl nNHksl . -. .Sh DESCRIPTION . The diff --git a/iomenu.c b/iomenu.c @@ -0,0 +1,128 @@ +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include <sys/ioctl.h> + +#include "iomenu.h" + + +/* + * Reset the terminal state and exit with error. + */ +void +die(const char *s) +{ + /* tcsetattr(STDIN_FILENO, TCSANOW, &termio_old); */ + fprintf(stderr, "%s\n", s); + exit(EXIT_FAILURE); +} + + +/* + * Set terminal to send one char at a time for interactive mode, and return the + * last terminal state. + */ +struct termios +set_terminal(int tty_fd) +{ + struct termios termio_old; + struct termios termio_new; + + /* set the terminal to send one key at a time. */ + + /* get the terminal's state */ + if (tcgetattr(tty_fd, &termio_old) < 0) + die("Can not get terminal attributes with tcgetattr()."); + + /* create a new modified state by switching the binary flags */ + termio_new = termio_old; + termio_new.c_lflag &= ~(ICANON | ECHO | IGNBRK); + + /* apply this state to current terminal now (TCSANOW) */ + tcsetattr(tty_fd, TCSANOW, &termio_new); + + return termio_old; +} + + +void +usage(void) +{ + fputs("usage: iomenu [-n] [-N] [-k key] [-s separator] ", stderr); + fputs("[-p prompt] [-l lines]\n", stderr); + + exit(EXIT_FAILURE); +} + + +int +main(int argc, char *argv[]) +{ + int i, exit_code, tty_fd = open("/dev/tty", O_RDWR); + Buffer *buffer = NULL; + Opt *opt = malloc(sizeof(Opt)); + + opt->line_numbers = 0; + opt->print_number = 0; + opt->validate_key = CONTROL('M'); + opt->separator = NULL; + opt->lines = 30; + opt->prompt = ""; + + /* command line arguments */ + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-' || strlen(argv[i]) != 2) + usage(); + + switch (argv[i][1]) { + case 'n': + opt->line_numbers = 1; + break; + case 'N': + opt->print_number = 1; + opt->line_numbers = 1; + break; + case 'k': + opt->validate_key = (argv[++i][0] == '^') ? + CONTROL(toupper(argv[i][1])): argv[i][0]; + break; + case 's': + opt->separator = argv[++i]; + break; + case 'l': + if (sscanf(argv[++i], "%d", &opt->lines) <= 0) + die("wrong number format after -l"); + break; + case 'p': + if (++i >= argc) + die("wrong string format after -p"); + opt->prompt = argv[i]; + break; + default: + usage(); + } + } + + /* command line arguments */ + buffer = fill_buffer(opt->separator); + + /* set the interface */ + draw_screen(buffer, tty_fd, opt); + + /* listen and interact to input */ + exit_code = input_get(buffer, tty_fd, opt); + + draw_clear(opt->lines); + + /* close files descriptors and pointers, and free memory */ + close(tty_fd); + free(opt); + free_buffer(buffer); + + return exit_code; +} diff --git a/iomenu.h b/iomenu.h @@ -0,0 +1,67 @@ +#define LINE_SIZE 1024 +#define OFFSET 5 +#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 MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) + + +/* + * Options from the command line, to pass to each function that need some + */ +typedef struct Opt { + int line_numbers; + int print_number; + char validate_key; + char *separator; + int lines; + char *prompt; +} Opt; + + +/* + * Line coming from stdin + */ +typedef struct Line { + char *content; /* sent as output and matched by input */ + int matches; /* whether it matches buffer's input */ +} Line; + + +/* iomenu */ + +void die(const char *); +struct termios set_terminal(int); +void usage(void); + + +/* buffer */ + +Buffer * fill_buffer(char *); +void free_buffer(Buffer *); +Line * add_line(Buffer *, int, char *, char *, Line *); +Line * new_line(char *, char *); +Line * matching_next(Line *); +Line * matching_prev(Line *); +int match_line(Line *, char **, size_t); +void filter_lines(Buffer *, int); + + +/* draw */ + +void draw_screen(Buffer *, int, Opt *); +void draw_clear(int); +void draw_line(Line *, int, int, Opt *); +void draw_lines(Buffer *, int, int, Opt *); +void draw_prompt(Buffer *, int, Opt *); + + +/* input */ + +int input_get(Buffer *, int, Opt *); +int input_key(FILE *, Buffer *, Opt *); +void action_jump(Buffer *, int); +void action_print_selection(Buffer *,int, Opt *); +void action_remove_word_input(Buffer *); +void action_add_character(Buffer *, char); diff --git a/main.c b/main.c @@ -1,91 +0,0 @@ -#include <ctype.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <termios.h> -#include <unistd.h> - -#include "main.h" - - -void -usage(void) -{ - fputs("usage: iomenu [-n] [-N] [-k key] [-s separator] ", stderr); - fputs("[-p prompt] [-l lines]\n", stderr); - - exit(EXIT_FAILURE); -} - - -int -main(int argc, char *argv[]) -{ - int i, exit_code, tty_fd = open("/dev/tty", O_RDWR); - Buffer *buffer = NULL; - Opt *opt = malloc(sizeof(Opt)); - - opt->line_numbers = 0; - opt->print_number = 0; - opt->validate_key = CONTROL('M'); - opt->separator = NULL; - opt->lines = 30; - opt->prompt = ""; - - /* command line arguments */ - for (i = 1; i < argc; i++) { - if (argv[i][0] != '-' || strlen(argv[i]) != 2) - usage(); - - switch (argv[i][1]) { - case 'n': - opt->line_numbers = 1; - break; - case 'N': - opt->print_number = 1; - opt->line_numbers = 1; - break; - case 'H': - opt->print_header = 1; - break; - case 'k': - opt->validate_key = (argv[++i][0] == '^') ? - CONTROL(toupper(argv[i][1])): argv[i][0]; - break; - case 's': - opt->separator = argv[++i]; - break; - case 'l': - if (sscanf(argv[++i], "%d", &opt->lines) <= 0) - die("wrong number format after -l"); - break; - case 'p': - if (++i >= argc) - die("wrong string format after -p"); - opt->prompt = argv[i]; - break; - default: - usage(); - } - } - - /* command line arguments */ - buffer = fill_buffer(opt->separator); - - /* set the interface */ - draw_screen(buffer, tty_fd, opt); - - /* listen and interact to input */ - exit_code = input_get(buffer, tty_fd, opt); - - draw_clear(opt->lines); - - /* close files descriptors and pointers, and free memory */ - close(tty_fd); - free(opt); - free_buffer(buffer); - - return exit_code; -} diff --git a/main.h b/main.h @@ -1,95 +0,0 @@ -#define LINE_SIZE 1024 -#define OFFSET 5 -#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 MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) - - -/* - * Options from the command line, to pass to each function that need some - */ -typedef struct Opt { - int line_numbers; - int print_number; - int print_header; - char validate_key; - char *separator; - int lines; - char *prompt; -} Opt; - - -/* - * Line coming from stdin, wrapped in a header. - */ -typedef struct Line { - char *content; /* sent as output and matched by input */ - char *comment; /* displayed at the right of the content */ - - int number; /* set here as order will not change */ - int matches; /* whether it matches buffer's input */ - int header; /* whether the line is a header */ - - struct Line *prev; /* doubly linked list structure */ - struct Line *next; -} Line; - - -/* - * Buffer containing a doubly linked list of headers - */ -typedef struct Buffer { - int total; /* total number of line in buffer */ - int matching; /* number lines matching the input */ - - char input[LINE_SIZE]; /* string from user's keyboard */ - - Line *current; /* selected line, highlighted */ - Line *first; /* boundaries of the linked list */ - Line *last; -} Buffer; - - -/* main */ - -void usage(void); - - -/* buffer */ - -Buffer * fill_buffer(char *); -void free_buffer(Buffer *); -Line * add_line(Buffer *, int, char *, char *, Line *); -Line * new_line(char *, char *); -Line * matching_next(Line *); -Line * matching_prev(Line *); -int match_line(Line *, char **, size_t); -void filter_lines(Buffer *, int); - - -/* draw */ - -void draw_screen(Buffer *, int, Opt *); -void draw_clear(int); -void draw_line(Line *, int, int, Opt *); -void draw_lines(Buffer *, int, int, Opt *); -void draw_prompt(Buffer *, int, Opt *); - - -/* input */ - -int input_get(Buffer *, int, Opt *); -int input_key(FILE *, Buffer *, Opt *); -void action_jump(Buffer *, int); -void action_print_selection(Buffer *,int, Opt *); -void action_remove_word_input(Buffer *); -void action_add_character(Buffer *, char); - - -/* util */ - -void die(const char *); -struct termios set_terminal(int); -char * expand_tabs(char *); diff --git a/nohup.out b/nohup.out @@ -1,92 +0,0 @@ -build: Installing tmux -checking for a BSD-compatible install... /usr/bin/install -c -checking whether build environment is sane... yes -checking for a thread-safe mkdir -p... /bin/mkdir -p -checking for gawk... no -checking for mawk... mawk -checking whether make sets $(MAKE)... yes -checking whether make supports nested variables... yes -checking build system type... x86_64-unknown-linux-gnu -checking host system type... x86_64-unknown-linux-gnu -checking for gcc... gcc -checking whether the C compiler works... yes -checking for C compiler default output file name... a.out -checking for suffix of executables... -checking whether we are cross compiling... no -checking for suffix of object files... o -checking whether we are using the GNU C compiler... yes -checking whether gcc accepts -g... yes -checking for gcc option to accept ISO C89... none needed -checking whether gcc understands -c and -o together... yes -checking for style of include used by make... GNU -checking dependency style of gcc... gcc3 -checking how to run the C preprocessor... gcc -E -checking for grep that handles long lines and -e... /bin/grep -checking for egrep... /bin/grep -E -checking for pkg-config... /usr/bin/pkg-config -checking pkg-config is at least version 0.9.0... yes -checking for glibc... yes -checking for ANSI C header files... yes -checking for sys/types.h... yes -checking for sys/stat.h... yes -checking for stdlib.h... yes -checking for string.h... yes -checking for memory.h... yes -checking for strings.h... yes -checking for inttypes.h... yes -checking for stdint.h... yes -checking for unistd.h... yes -checking bitstring.h usability... no -checking bitstring.h presence... no -checking for bitstring.h... no -checking dirent.h usability... yes -checking dirent.h presence... yes -checking for dirent.h... yes -checking fcntl.h usability... yes -checking fcntl.h presence... yes -checking for fcntl.h... yes -checking for inttypes.h... (cached) yes -checking libutil.h usability... no -checking libutil.h presence... no -checking for libutil.h... no -checking ndir.h usability... no -checking ndir.h presence... no -checking for ndir.h... no -checking paths.h usability... yes -checking paths.h presence... yes -checking for paths.h... yes -checking pty.h usability... yes -checking pty.h presence... yes -checking for pty.h... yes -checking for stdint.h... (cached) yes -checking sys/dir.h usability... yes -checking sys/dir.h presence... yes -checking for sys/dir.h... yes -checking sys/ndir.h usability... no -checking sys/ndir.h presence... no -checking for sys/ndir.h... no -checking sys/tree.h usability... no -checking sys/tree.h presence... no -checking for sys/tree.h... no -checking term.h usability... no -checking term.h presence... no -checking for term.h... no -checking util.h usability... no -checking util.h presence... no -checking for util.h... no -checking for library containing flock... none required -checking for dirfd... yes -checking for flock... yes -checking for prctl... yes -checking for sysconf... yes -checking for cfmakeraw... yes -checking for library containing clock_gettime... none required -checking for LIBEVENT... no -checking for library containing event_init... no -checking event.h usability... no -checking event.h presence... no -checking for event.h... no -configure: error: "libevent not found" -make: *** No rule to make target 'install'. Stop. -build: Updating index in /home/josuah/.local/tmux -build: Removing broken links from /home/josuah/.local diff --git a/util.c b/util.c @@ -1,73 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "main.h" - - -/* - * Reset the terminal state and exit with error. - */ -void -die(const char *s) -{ - /* tcsetattr(STDIN_FILENO, TCSANOW, &termio_old); */ - fprintf(stderr, "%s\n", s); - exit(EXIT_FAILURE); -} - - -/* - * Set terminal to send one char at a time for interactive mode, and return the - * last terminal state. - */ -struct termios -set_terminal(int tty_fd) -{ - struct termios termio_old; - struct termios termio_new; - - /* set the terminal to send one key at a time. */ - - /* get the terminal's state */ - if (tcgetattr(tty_fd, &termio_old) < 0) - die("Can not get terminal attributes with tcgetattr()."); - - /* create a new modified state by switching the binary flags */ - termio_new = termio_old; - termio_new.c_lflag &= ~(ICANON | ECHO | IGNBRK); - - /* apply this state to current terminal now (TCSANOW) */ - tcsetattr(tty_fd, TCSANOW, &termio_new); - - return termio_old; -} - - -/* - * Replace tab as a multiple of 8 spaces in a line. - * - * Allocates memory. - */ -char * -expand_tabs(char *line) -{ - size_t i, n; - char *converted = malloc(sizeof(char) * (strlen(line) * 8 + 1)); - - for (i = 0, n = 0; i < strlen(line); i++, n++) { - if (line[i] == '\t') { - for (; n == 0 || n % 8 != 0; n++) - converted[n] = ' '; - n--; - } else { - converted[n] = line[i]; - } - } - - converted[n] = '\0'; - - return converted; -}