iomenu

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

commit 2743c784dbce7910cbec895c42a723f06fa7b620
parent e24cea688e69bd009ef52ea40891a0a386b881ea
Author: Josuah Demangeon <mail@josuah.net>
Date:   Sun, 29 Oct 2017 22:05:58 +0100

split into multiple files

Diffstat:
MMakefile | 4+++-
Abuffer.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuffer.h | 3+++
Acontrol.c | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrol.h | 4++++
Adisplay.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adisplay.h | 2++
Diomenu.c | 543-------------------------------------------------------------------------------
Aiomenu.core | 0
Amain.c | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain.h | 29+++++++++++++++++++++++++++++
Mutf8.c | 13+++++--------
Mutf8.h | 12++++++------
13 files changed, 556 insertions(+), 558 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ CFLAGS = -std=c89 -Wpedantic -Wall -Wextra -g -D_POSIX_C_SOURCE=200809L -OBJ = iomenu.o utf8.o +OBJ = buffer.o control.o display.o main.o utf8.o all: iomenu @@ -15,3 +15,5 @@ install: iomenu cp *.1 $(PREFIX)/share/man/man1 mkdir -p $(PREFIX)/bin cp iomenu $(PREFIX)/bin + +.PHONY: all clean install diff --git a/buffer.c b/buffer.c @@ -0,0 +1,93 @@ +#include "buffer.h" + +static char * +read_line(FILE *fp) +{ + char *line; + size_t len; + + line = malloc(LINE_MAX + 1); + if (!(fgets(line, LINE_MAX, fp))) { + free(line); + return NULL; + } + + len = strlen(line); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + + return (line); +} + +static int +match_line(char *line, char **tokv, int tokc) +{ + if (opt['#'] && line[0] == '#') + return 2; + while (tokc-- > 0) + if (strstr(line, tokv[tokc]) == NULL) + return 0; + + return 1; +} + +void +free_lines(void) +{ + if (linev) { + for (; linec > 0; linec--) + free(linev[linec - 1]); + free(linev); + } + if (matchv) + free(matchv); +} + +void +read_stdin(void) +{ + int size = 0; + + while (1) { + if (linec >= size) { + size += BUFSIZ; + linev = realloc(linev, sizeof (char **) * size); + matchv = realloc(matchv, sizeof (char **) * size); + if (!linev || !matchv) + die("realloc"); + } + if ((linev[linec] = read_line(stdin)) == NULL) + break; + linec++; + matchc++; + } +} + +void +filter(void) +{ + int tokc = 0; + int n = 0; + int i; + char **tokv = NULL; + char *s; + char buffer[sizeof (input)]; + + current = offset = next = 0; + strcpy(buffer, input); + for (s = strtok(buffer, " "); s; s = strtok(NULL, " "), tokc++) { + if (tokc >= n) { + tokv = realloc(tokv, ++n * sizeof (*tokv)); + if (tokv == NULL) + die("realloc"); + } + tokv[tokc] = s; + } + matchc = 0; + for (i = 0; i < linec; i++) + if (match_line(linev[i], tokv, tokc)) + matchv[matchc++] = linev[i]; + free(tokv); + if (opt['#'] && matchv[current][0] == '#') + move(+1); +} diff --git a/buffer.h b/buffer.h @@ -0,0 +1,3 @@ +void free_lines (void); +void read_stdin (void); +void filter(void); diff --git a/control.c b/control.c @@ -0,0 +1,169 @@ +#include "control.h" + +#define CTL(char) ((char) ^ 0x40) +#define ALT(char) ((char) + 0x80) +#define CSI(char) ((char) + 0x80 + 0x80) + +static size_t +width(char *s) +{ + int width = 0; + + while (*s) { + if (*s++ == '\t') + width += 8 - (width % 8); + else + width++; + } + + return width; +} + +int +prev_page(int pos) +{ + int col, cols = ws.ws_col - MARGIN - 4; + + pos -= pos > 0 ? 1 : 0; + for (col = 0; pos > 0; pos--) + if ((col += width(matchv[pos]) + 2) > cols) + return pos + 1; + return pos; +} + +int +next_page(int pos) +{ + int col, cols = ws.ws_col - MARGIN - 4; + + for (col = 0; pos < matchc; pos++) + if ((col += width(matchv[pos]) + 2) > cols) + return pos; + return pos; +} + +void +move(signed int sign) +{ + int i; + + for (i = current + sign; 0 <= i && i < matchc; i += sign) { + if (!opt['#'] || matchv[i][0] != '#') { + current = i; + break; + } + } +} + +static void +move_page(signed int sign) +{ + int i; + + if (opt['l'] <= 0) { + if (sign > 0) { + offset = current = next; + next = next_page(next); + } else if (sign < 0) { + next = offset; + offset = current = prev_page(offset); + } + } else { + i = current - current % rows + rows * sign; + if (!(0 < i && i < matchc)) + return; + current = i - 1; + move(+1); + } +} + +static void +remove_word() +{ + int len; + int i; + + len = strlen(input) - 1; + for (i = len; i >= 0 && isspace(input[i]); i--) + input[i] = '\0'; + len = strlen(input) - 1; + for (i = len; i >= 0 && !isspace(input[i]); i--) + input[i] = '\0'; + filter(); +} + +static void +add_char(char c) +{ + int len; + + len = strlen(input); + if (isprint(c)) { + input[len] = c; + input[len + 1] = '\0'; + } + filter(); +} + +int +key(int k) +{ +top: + switch (k) { + case CTL('C'): + return EXIT_FAILURE; + case CTL('U'): + input[0] = '\0'; + filter(); + break; + case CTL('W'): + remove_word(); + break; + case 127: + case CTL('H'): /* backspace */ + input[strlen(input) - 1] = '\0'; + filter(); + break; + case CSI('A'): /* up */ + case CTL('P'): + move(-1); + break; + case CSI('B'): /* down */ + case CTL('N'): + move(+1); + break; + case CSI('5'): /* page up */ + if (fgetc(stdin) != '~') + break; + /* fallthrough */ + case ALT('v'): + move_page(-1); + break; + case CSI('6'): /* page down */ + if (fgetc(stdin) != '~') + break; + /* fallthrough */ + case CTL('V'): + move_page(+1); + break; + case CTL('I'): /* tab */ + if (linec > 0) + strcpy(input, matchv[current]); + filter(); + break; + case CTL('J'): /* enter */ + case CTL('M'): + print_selection(); + return EXIT_SUCCESS; + case ALT('['): + k = CSI(fgetc(stdin)); + goto top; + case 0x1b: /* escape / alt */ + k = ALT(fgetc(stdin)); + goto top; + default: + add_char((char) k); + } + + return CONTINUE; +} diff --git a/control.h b/control.h @@ -0,0 +1,4 @@ +int prev_page (int); +int next_page (int); +void move (signed int); +int key (int); diff --git a/display.c b/display.c @@ -0,0 +1,119 @@ +#include "display.h" + +static char * +format(char *str, int cols) +{ + int col = 0; + long rune = 0; + char *fmt = formatted; + + while (*str && col < cols) { + if (*str == '\t') { + int t = 8 - col % 8; + while (t-- && col < cols) { + *fmt++ = ' '; + col++; + } + str++; + } else if (utf8_to_rune(&rune, str) && rune_is_print(rune)) { + int i = utf8_len(str); + while (i--) + *fmt++ = *str++; + col++; + } else { + *fmt++ = '?'; + col++; + str++; + } + } + *fmt = '\0'; + + return formatted; +} + +static void +print_lines(void) +{ + int printed = 0, i = current - current % rows; + + for (; printed < rows && i < matchc; i++, printed++) { + fprintf(stderr, + opt['#'] && matchv[i][0] == '#' ? + "\n\x1b[1m\x1b[K %s\x1b[m" : + i == current ? + "\n\x1b[47;30m\x1b[K %s\x1b[m" : + "\n\x1b[K %s", + format(matchv[i], ws.ws_col - 1) + ); + } + while (printed++ < rows) + fputs("\n\x1b[K", stderr); + fprintf(stderr, "\x1b[%dA\r\x1b[K", rows); +} + +static void +print_segments(void) +{ + int i; + + if (current < offset) { + next = offset; + offset = prev_page(offset); + } else if (current >= next) { + offset = next; + next = next_page(offset); + } + fprintf(stderr, "\r\x1b[K\x1b[%dC", MARGIN); + fputs(offset > 0 ? "< " : " ", stderr); + for (i = offset; i < next && i < matchc; i++) { + fprintf(stderr, + opt['#'] && matchv[i][0] == '#' ? "\x1b[1m %s \x1b[m" : + i == current ? "\x1b[7m %s \x1b[m" : " %s ", + format(matchv[i], ws.ws_col - 1) + ); + } + if (next < matchc) + fprintf(stderr, "\x1b[%dC\b>", ws.ws_col - MARGIN); + fputc('\r', stderr); +} + +void +print_screen(void) +{ + int cols = ws.ws_col - 1; + + if (opt['l'] > 0) + print_lines(); + else + print_segments(); + if (*prompt) { + format(prompt, cols - 2); + fprintf(stderr, "\x1b[30;47m %s \x1b[m", formatted); + cols -= strlen(formatted) + 2; + } + fputc(' ', stderr); + fputs(format(input, cols), stderr); + fflush(stderr); +} + +void +print_selection(void) +{ + char **match; + + if (opt['#']) { + match = matchv + current; + while (--match >= matchv) { + if ((*match)[0] == '#') { + fputs(*match + 1, stdout); + break; + } + } + putchar('\t'); + } + if (matchc == 0 || (opt['#'] && matchv[current][0] == '#')) + puts(input); + else + puts(matchv[current]); + fputs("\r\x1b[K", stderr); +} diff --git a/display.h b/display.h @@ -0,0 +1,2 @@ +void print_screen (void); +void print_selection (void); diff --git a/iomenu.c b/iomenu.c @@ -1,543 +0,0 @@ -#include <ctype.h> -#include <fcntl.h> -#include <limits.h> -#include <locale.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include <sys/ioctl.h> - -#include "utf8.h" - -#ifndef SIGWINCH -#define SIGWINCH 28 -#endif -#define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */ -#define MARGIN 30 /* space for the input before the horizontal list */ - -#define CTL(char) (char ^ 0x40) -#define ALT(char) (char + 0x80) -#define CSI(char) (char + 0x80 + 0x80) -#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) - -static struct winsize ws; -static struct termios termios; -static int ttyfd; -static int current = 0, offset = 0, next = 0; -static int linec = 0, matchc = 0; -static char **linev = NULL, **matchv = NULL; -static char input[LINE_MAX], formatted[LINE_MAX * 8]; -static int opt[128], rows = 0; -static char *prompt = ""; - -static void -free_lines(void) -{ - if (linev) { - for (; linec > 0; linec--) - free(linev[linec - 1]); - free(linev); - } - if (matchv) - free(matchv); -} - -static void -die(const char *s) -{ - tcsetattr(ttyfd, TCSANOW, &termios); - close(ttyfd); - free_lines(); - perror(s); - exit(EXIT_FAILURE); -} - -static char * -read_line(FILE *fp) -{ - char *line; - size_t len; - - line = malloc(LINE_MAX + 1); - if (!(fgets(line, LINE_MAX, fp))) { - free(line); - return NULL; - } - - len = strlen(line); - if (len > 0 && line[len - 1] == '\n') - line[len - 1] = '\0'; - - return (line); -} - -static void -read_stdin(void) -{ - int size = 0; - - while (1) { - if (linec >= size) { - size += BUFSIZ; - linev = realloc(linev, sizeof (char **) * size); - matchv = realloc(matchv, sizeof (char **) * size); - if (!linev || !matchv) - die("realloc"); - } - if ((linev[linec] = read_line(stdin)) == NULL) - break; - linec++; - matchc++; - } -} - -static void -set_terminal(void) -{ - struct termios new; - - /* save currentsor postition */ - fputs("\x1b[s", stderr); - - /* save attributes to `termios` */ - if (tcgetattr(ttyfd, &termios) < 0 || tcgetattr(ttyfd, &new) < 0) { - perror("tcgetattr"); - exit(EXIT_FAILURE); - } - - /* change to raw mode */ - new.c_lflag &= ~(ICANON | ECHO | IGNBRK | IEXTEN | ISIG); - tcsetattr(ttyfd, TCSANOW, &new); -} - -static void -reset_terminal(void) -{ - int i; - - /* clear terminal */ - for (i = 0; i < rows + 1; i++) - fputs("\r\x1b[K\n", stderr); - - /* reset currentsor position */ - fputs("\x1b[u", stderr); - - tcsetattr(ttyfd, TCSANOW, &termios); -} - -static size_t -width(char *s) -{ - int width = 0; - - while (*s) { - if (*s++ == '\t') - width += 8 - (width % 8); - else - width++; - } - - return width; -} - -static int -prev_page(int pos) -{ - int col, cols = ws.ws_col - MARGIN - 4; - - pos -= pos > 0 ? 1 : 0; - for (col = 0; pos > 0; pos--) - if ((col += width(matchv[pos]) + 2) > cols) - return pos + 1; - return pos; -} - -static int -next_page(int pos) -{ - int col, cols = ws.ws_col - MARGIN - 4; - - for (col = 0; pos < matchc; pos++) - if ((col += width(matchv[pos]) + 2) > cols) - return pos; - return pos; -} - -static void -move(signed int sign) -{ - int i; - - for (i = current + sign; 0 <= i && i < matchc; i += sign) { - if (!opt['#'] || matchv[i][0] != '#') { - current = i; - break; - } - } -} - -static void -move_page(signed int sign) -{ - int i; - - if (opt['l'] <= 0) { - if (sign > 0) { - offset = current = next; - next = next_page(next); - } else if (sign < 0) { - next = offset; - offset = current = prev_page(offset); - } - } else { - i = current - current % rows + rows * sign; - if (!(0 < i && i < matchc)) - return; - current = i - 1; - move(+1); - } -} - -static char * -format(char *str, int cols) -{ - int col = 0; - long rune = 0; - char *fmt = formatted; - - while (*str && col < cols) { - if (*str == '\t') { - int t = 8 - col % 8; - while (t-- && col < cols) { - *fmt++ = ' '; - col++; - } - str++; - } else if (utf8_to_rune(&rune, str) && rune_is_print(rune)) { - int i = utf8_len(str); - while (i--) - *fmt++ = *str++; - col++; - } else { - *fmt++ = '?'; - col++; - str++; - } - } - *fmt = '\0'; - - return formatted; -} - -static void -print_lines(void) -{ - int printed = 0, i = current - current % rows; - - for (; printed < rows && i < matchc; i++, printed++) { - fprintf(stderr, - opt['#'] && matchv[i][0] == '#' ? - "\n\x1b[1m\x1b[K %s\x1b[m" : - i == current ? - "\n\x1b[47;30m\x1b[K %s\x1b[m" : - "\n\x1b[K %s", - format(matchv[i], ws.ws_col - 1) - ); - } - while (printed++ < rows) - fputs("\n\x1b[K", stderr); - fprintf(stderr, "\x1b[%dA\r\x1b[K", rows); -} - -static void -print_segments(void) -{ - int i; - - if (current < offset) { - next = offset; - offset = prev_page(offset); - } else if (current >= next) { - offset = next; - next = next_page(offset); - } - fprintf(stderr, "\r\x1b[K\x1b[%dC", MARGIN); - fputs(offset > 0 ? "< " : " ", stderr); - for (i = offset; i < next && i < matchc; i++) { - fprintf(stderr, - opt['#'] && matchv[i][0] == '#' ? "\x1b[1m %s \x1b[m" : - i == current ? "\x1b[7m %s \x1b[m" : " %s ", - format(matchv[i], ws.ws_col - 1) - ); - } - if (next < matchc) - fprintf(stderr, "\x1b[%dC\b>", ws.ws_col - MARGIN); - fputc('\r', stderr); -} - -static void -print_screen(void) -{ - int cols = ws.ws_col - 1; - - if (opt['l'] > 0) - print_lines(); - else - print_segments(); - if (*prompt) { - format(prompt, cols - 2); - fprintf(stderr, "\x1b[30;47m %s \x1b[m", formatted); - cols -= strlen(formatted) + 2; - } - fputc(' ', stderr); - fputs(format(input, cols), stderr); - fflush(stderr); -} - -static int -match_line(char *line, char **tokv, int tokc) -{ - if (opt['#'] && line[0] == '#') - return 2; - while (tokc-- > 0) - if (strstr(line, tokv[tokc]) == NULL) - return 0; - - return 1; -} - -static void -filter(void) -{ - int tokc = 0; - int n = 0; - int i; - char **tokv = NULL; - char *s; - char buffer[sizeof (input)]; - - current = offset = next = 0; - strcpy(buffer, input); - for (s = strtok(buffer, " "); s; s = strtok(NULL, " "), tokc++) { - if (tokc >= n) { - tokv = realloc(tokv, ++n * sizeof (*tokv)); - if (tokv == NULL) - die("realloc"); - } - tokv[tokc] = s; - } - matchc = 0; - for (i = 0; i < linec; i++) - if (match_line(linev[i], tokv, tokc)) - matchv[matchc++] = linev[i]; - free(tokv); - if (opt['#'] && matchv[current][0] == '#') - move(+1); -} - -static void -remove_word() -{ - int len; - int i; - - len = strlen(input) - 1; - for (i = len; i >= 0 && isspace(input[i]); i--) - input[i] = '\0'; - len = strlen(input) - 1; - for (i = len; i >= 0 && !isspace(input[i]); i--) - input[i] = '\0'; - filter(); -} - -static void -add_char(char key) -{ - int len; - - len = strlen(input); - if (isprint(key)) { - input[len] = key; - input[len + 1] = '\0'; - } - filter(); -} - -static void -print_selection(void) -{ - char **match; - - if (opt['#']) { - match = matchv + current; - while (--match >= matchv) { - if ((*match)[0] == '#') { - fputs(*match + 1, stdout); - break; - } - } - putchar('\t'); - } - if (matchc == 0 || (opt['#'] && matchv[current][0] == '#')) - puts(input); - else - puts(matchv[current]); - fputs("\r\x1b[K", stderr); -} - -static int -key(int key) -{ -top: - switch (key) { - - case CTL('C'): - return EXIT_FAILURE; - - case CTL('U'): - input[0] = '\0'; - filter(); - break; - - case CTL('W'): - remove_word(); - break; - - case 127: - case CTL('H'): /* backspace */ - input[strlen(input) - 1] = '\0'; - filter(); - break; - - case CSI('A'): /* up */ - case CTL('P'): - move(-1); - break; - - case CSI('B'): /* down */ - case CTL('N'): - move(+1); - break; - - case CSI('5'): /* page up */ - if (fgetc(stdin) != '~') - break; - /* fallthrough */ - - case ALT('v'): - move_page(-1); - break; - - case CSI('6'): /* page down */ - if (fgetc(stdin) != '~') - break; - /* fallthrough */ - - case CTL('V'): - move_page(+1); - break; - - case CTL('I'): /* tab */ - if (linec > 0) - strcpy(input, matchv[current]); - filter(); - break; - - case CTL('J'): /* enter */ - case CTL('M'): - print_selection(); - return EXIT_SUCCESS; - - case ALT('['): - key = CSI(fgetc(stdin)); - goto top; - - case 0x1b: /* escape / alt */ - key = ALT(fgetc(stdin)); - goto top; - - default: - add_char((char) key); - } - - return CONTINUE; -} - -static void -sigwinch() -{ - if (ioctl(ttyfd, TIOCGWINSZ, &ws) < 0) - die("ioctl"); - rows = MIN(opt['l'], ws.ws_row - 1); - print_screen(); - signal(SIGWINCH, sigwinch); -} - -static void -usage(void) -{ - fputs("iomenu [-#] [-l lines] [-p prompt]\n", stderr); - exit(EXIT_FAILURE); -} - -static void -parse_opt(int argc, char *argv[]) -{ - memset(opt, 0, 128 * sizeof (int)); - opt['l'] = 255; - for (argv++, argc--; argc > 0; argv++, argc--) { - if (argv[0][0] != '-') - usage(); - switch ((*argv)[1]) { - case 'l': - if (!--argc || sscanf(*++argv, "%d", &opt['l']) <= 0) - usage(); - break; - case 'p': - if (!--argc) - usage(); - prompt = *++argv; - break; - case '#': - opt['#'] = 1; - break; - case 's': - if (!--argc) - usage(); - opt['s'] = (int) **++argv; - break; - default: - usage(); - } - } -} - -int -main(int argc, char *argv[]) -{ - int exit_code; - - parse_opt(argc, argv); - read_stdin(); - filter(); - if (!freopen("/dev/tty", "r", stdin)) - die("freopen /dev/tty"); - if (!freopen("/dev/tty", "w", stderr)) - die("freopen /dev/tty"); - ttyfd = open("/dev/tty", O_RDWR); - set_terminal(); - sigwinch(); - input[0] = '\0'; - while ((exit_code = key(fgetc(stdin))) == CONTINUE) - print_screen(); - print_screen(); - reset_terminal(); - close(ttyfd); - free_lines(); - - return exit_code; -} diff --git a/iomenu.core b/iomenu.core Binary files differ. diff --git a/main.c b/main.c @@ -0,0 +1,123 @@ +#include "main.h" + +static struct termios termios; +static int ttyfd; + +void +die(const char *s) +{ + tcsetattr(ttyfd, TCSANOW, &termios); + close(ttyfd); + free_lines(); + perror(s); + exit(EXIT_FAILURE); +} + +static void +set_terminal(void) +{ + struct termios new; + + /* save currentsor postition */ + fputs("\x1b[s", stderr); + + /* save attributes to `termios` */ + if (tcgetattr(ttyfd, &termios) < 0 || tcgetattr(ttyfd, &new) < 0) { + perror("tcgetattr"); + exit(EXIT_FAILURE); + } + + /* change to raw mode */ + new.c_lflag &= ~(ICANON | ECHO | IGNBRK | IEXTEN | ISIG); + tcsetattr(ttyfd, TCSANOW, &new); +} + +static void +reset_terminal(void) +{ + int i; + + /* clear terminal */ + for (i = 0; i < rows + 1; i++) + fputs("\r\x1b[K\n", stderr); + + /* reset currentsor position */ + fputs("\x1b[u", stderr); + + tcsetattr(ttyfd, TCSANOW, &termios); +} + +static void +sigwinch() +{ + if (ioctl(ttyfd, TIOCGWINSZ, &ws) < 0) + die("ioctl"); + rows = MIN(opt['l'], ws.ws_row - 1); + print_screen(); + signal(SIGWINCH, sigwinch); +} + +static void +usage(void) +{ + fputs("iomenu [-#] [-l lines] [-p prompt]\n", stderr); + exit(EXIT_FAILURE); +} + +static void +parse_opt(int argc, char *argv[]) +{ + memset(opt, 0, 128 * sizeof (int)); + opt['l'] = 255; + for (argv++, argc--; argc > 0; argv++, argc--) { + if (argv[0][0] != '-') + usage(); + switch ((*argv)[1]) { + case 'l': + if (!--argc || sscanf(*++argv, "%d", &opt['l']) <= 0) + usage(); + break; + case 'p': + if (!--argc) + usage(); + prompt = *++argv; + break; + case '#': + opt['#'] = 1; + break; + case 's': + if (!--argc) + usage(); + opt['s'] = (int) **++argv; + break; + default: + usage(); + } + } +} + +int +main(int argc, char *argv[]) +{ + int exit_code; + + parse_opt(argc, argv); + read_stdin(); + filter(); + if (!freopen("/dev/tty", "r", stdin)) + die("freopen /dev/tty"); + if (!freopen("/dev/tty", "w", stderr)) + die("freopen /dev/tty"); + ttyfd = open("/dev/tty", O_RDWR); + set_terminal(); + sigwinch(); + input[0] = '\0'; + while ((exit_code = key(fgetc(stdin))) == CONTINUE) + print_screen(); + print_screen(); + reset_terminal(); + close(ttyfd); + free_lines(); + + return exit_code; +} diff --git a/main.h b/main.h @@ -0,0 +1,29 @@ +#ifndef SIGWINCH +#define SIGWINCH 28 +#endif + +#define CONTINUE (EXIT_SUCCESS + EXIT_FAILURE + 1) +#define MARGIN 30 + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) + +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 offset = 0; +int next = 0; +int opt[128]; +int rows = 0; + +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); diff --git a/utf8.c b/utf8.c @@ -1,3 +1,5 @@ +#include "utf8.h" + /* * ASCII all have a leading '0' byte: * @@ -28,7 +30,6 @@ #include "utf8.h" - /* * Return the number of bytes in rune for the `n` next char in `s`, * or 0 if ti is misencoded. @@ -56,20 +57,18 @@ utf8_len(char *s) return len; } - /* * Return the number of bytes required to encode `rune` into UTF-8, or * 0 if rune is too long. */ size_t -rune_len(long r) +utf8_rune_len(long r) { return (r <= 0x0000007f) ? 1 : (r <= 0x000007ff) ? 2 : (r <= 0x0000ffff) ? 3 : (r <= 0x001fffff) ? 4 : (r <= 0x03ffffff) ? 5 : (r <= 0x7fffffff) ? 6 : 0; } - /* * Sets 'r' to a rune corresponding to the firsts 'n' bytes of 's'. * @@ -92,13 +91,12 @@ utf8_to_rune(long *r, char *s) *r = (*r << 6) | (*s++ & 0x3f); /* 10xxxxxx */ /* overlong sequences */ - if (rune_len(*r) != len) + if (utf8_rune_len(*r) != len) return 0; return len; } - /* * Returns 1 if the rune is a valid unicode code point and 0 if not. */ @@ -119,7 +117,6 @@ rune_is_unicode(long r) ); } - /* * Return 1 if '*s' is correctly encoded in UTF-8 with allowed Unicode * code points. @@ -146,7 +143,7 @@ utf8_check(char *s) * Return 1 if the rune is a printable character, and 0 otherwise. */ int -rune_is_print(long r) +utf8_is_print(long r) { return (0x1f < r && r != 0x7f && r < 0x80) || 0x9f < r; } 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 rune_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);