diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | more.c | 190 |
2 files changed, 106 insertions, 86 deletions
@@ -8,7 +8,7 @@ CC=c99 LD=$(CC) CFLAGS=-Wall -Wextra -Wpedantic -Werror -g LDFLAGS= -LDLIBS=-lcurses +LDLIBS= SRCDIR=. OBJDIR=. BINDIR=$(OBJDIR) @@ -23,18 +23,18 @@ */ #define _XOPEN_SOURCE 700 -#include <curses.h> #include <ctype.h> #include <errno.h> #include <libgen.h> #include <locale.h> #include <spawn.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/wait.h> -#include <term.h> +#include <termios.h> #include <unistd.h> #include <wordexp.h> @@ -55,11 +55,13 @@ struct more_file { int eof; }; -static int more_clear = 0; +typedef enum { DISABLE, ENABLE, CLEAR } more_clear_action; + +static struct termios more_term; static int more_fastexit = 0; static int more_backspace = 1; -static WINDOW *more_win = NULL; -static WINDOW *more_status = NULL; +static int more_lines = 24; +static FILE *more_in = NULL; enum { CTRL_B = 0x02, @@ -70,6 +72,34 @@ enum { CTRL_U = 0x15, }; +static void more_status(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +static void more_clear(more_clear_action action) +{ + static char clearcmd[64] = ""; + + if (action == ENABLE) { + FILE *p = popen("tput clear", "r"); + if (p == NULL) { + return; + } + fread(clearcmd, 1, sizeof(clearcmd), p); + fclose(p); + } + + if (clearcmd[0] == '\0') { + return; + } + + printf("%s", clearcmd); +} + static ssize_t more_getline(struct more_file *mf, size_t lineno) { if (mf->nlines <= lineno && mf->nlines != 0) { @@ -90,8 +120,6 @@ static ssize_t more_getline(struct more_file *mf, size_t lineno) return -1; } - printf("%s\r", mf->buf); - if (mf->nlines > 1) { mf->bytepos[mf->nlines - 1] = mf->bytepos[mf->nlines - 2] + strlen(mf->buf); } else { @@ -154,39 +182,38 @@ static void more_close(struct more_file *mf) static int more_printline(char *s) { - int ret = -1; - /* - if (strlen(s) == (size_t)COLS) { - s[COLS - 1] = '\0'; + static int columns = 0; + if (columns == 0) { + char *colenv = getenv("COLUMNS"); + columns = colenv ? atoi(colenv) : 80; } - */ - scrollok(more_win, FALSE); + int ret = -1; + for (size_t i = 0; s[i] != '\0'; i++) { int attr = 0; if (more_backspace && s[i + 1] == '\b') { if (s[i + 2] == '_') { - attr = A_UNDERLINE; + //attr = A_UNDERLINE; } else if (s[i + 2] == s[i]) { - attr = A_BOLD; + //attr = A_BOLD; } else { i++; continue; } } if (attr) { - wattron(more_win, attr); + //wattron(more_win, attr); } - waddch(more_win, s[i]); - if (i % COLS == 0) { + putchar(s[i]); + if (i % columns == 0) { ret++; } if (attr) { - wattroff(more_win, attr); + //wattroff(more_win, attr); i += 2; } } - scrollok(more_win, TRUE); return ret; } @@ -194,9 +221,9 @@ static int more_printline(char *s) static void more_refresh(struct more_file *mf) { int printed = 0; - wmove(more_win, 0, 0); + //wmove(more_win, 0, 0); - for (size_t i = mf->topline; i + printed < mf->topline + LINES; i++) { + for (size_t i = mf->topline; i + printed < mf->topline + more_lines; i++) { /* FIXME: account for long lines */ if (more_getline(mf, i) == -1) { @@ -205,15 +232,14 @@ static void more_refresh(struct more_file *mf) printed += more_printline(mf->buf); } - wrefresh(more_win); } static void more_scroll(struct more_file *mf, int count, int multiple) { int by = count ? count * multiple : multiple; - if (more_clear && abs(by) > LINES) { - clear(); + if (abs(by) > more_lines) { + more_clear(CLEAR); } if (by < 0) { @@ -224,7 +250,7 @@ static void more_scroll(struct more_file *mf, int count, int multiple) mf->topline += by; } if (by != 0) { - wscrl(more_win, by); + more_clear(CLEAR); more_refresh(mf); } return; @@ -232,17 +258,17 @@ static void more_scroll(struct more_file *mf, int count, int multiple) while (by-- > 0) { /* FIXME: account for long lines here, too */ - if (more_getline(mf, mf->topline + LINES) < 0) { + if (more_getline(mf, mf->topline + more_lines) < 0) { break; } mf->topline++; - wprintw(more_win, "%s", mf->buf); + more_printline(mf->buf); } } static void mark(struct more_file *mf) { - int c = wgetch(more_status); + int c = fgetc(more_in); if (islower(c)) { mf->mark[c - 'a'] = mf->topline; } @@ -250,7 +276,7 @@ static void mark(struct more_file *mf) static void jump(struct more_file *mf) { - int c = wgetch(more_status); + int c = fgetc(more_in); if (islower(c)) { mf->topline = mf->mark[c - 'a']; more_refresh(mf); @@ -262,7 +288,7 @@ static void more_help(void) char path[L_tmpnam + 1]; FILE *f = fopen(tmpnam(path), "w"); if (f == NULL) { - wprintw(more_status, "error creating help: %s", strerror(errno)); + fprintf(stderr, "error creating help: %s", strerror(errno)); return; } @@ -336,8 +362,6 @@ static void more_invoke_editor(struct more_file *mf) argv[2] = NULL; } - def_prog_mode(); - reset_shell_mode(); pid_t pid; if (posix_spawnp(&pid, editor, NULL, NULL, argv, environ) == 0) { size_t line = mf->topline; @@ -346,23 +370,20 @@ static void more_invoke_editor(struct more_file *mf) more_open(mf); mf->topline = line; } else { - wprintw(more_status, "%s %s: %s\n", editor, mf->path, + fprintf(stderr, "%s %s: %s\n", editor, mf->path, strerror(errno)); } - - reset_prog_mode(); } static struct more_file more_examine(struct more_file *mf) { - wprintw(more_status, "e"); + //wprintw(more_status, "e"); char filename[1024]; - wgetnstr(more_status, filename, sizeof(filename)); - wclear(more_status); + fgets(filename, sizeof(filename), more_in); wordexp_t we = { 0 }; if (wordexp(filename, &we, WRDE_NOCMD) != 0) { - wprintw(more_status, "couldn't expand %s", filename); + fprintf(stderr, "couldn't expand %s", filename); return *mf; } @@ -374,7 +395,7 @@ static struct more_file more_examine(struct more_file *mf) wordfree(&we); if (we.we_wordc > 1) { - wprintw(more_status, "not opening multiple files"); + fprintf(stderr, "not opening multiple files"); return *mf; } @@ -385,7 +406,7 @@ static struct more_file more_examine(struct more_file *mf) /* struct more_file ret = more_open(filename); if (ret.f == NULL) { - wprintw(more_status, "%s: %s", filename, strerror(errno)); + fprintf(stderr, "%s: %s", filename, strerror(errno)); return *mf; } @@ -411,8 +432,6 @@ static struct more_file * more_next(struct more_file *mf, int n) } more_open(mf); - wclear(more_win); - wmove(more_win, 0, 0); more_refresh(mf); return mf; } @@ -428,19 +447,19 @@ static int more(struct more_file *mf) int count = 0; while (mf) { - int at_eof = (mf->eof && (mf->topline + LINES >= mf->nlines)); - wmove(more_status, 0, 0); + int at_eof = (mf->eof && (mf->topline + more_lines >= mf->nlines)); + //wmove(more_status, 0, 0); if (at_eof) { if (more_fastexit && mf->next == NULL) { return 0; } - wprintw(more_status, "%s <EOF>", mf->path); + more_status("%s <EOF>", mf->path); } - int c = wgetch(more_status); - wclear(more_status); + int c = fgetc(more_in); switch (c) { case EOF: + perror("fgetc"); exit(2); break; @@ -456,7 +475,7 @@ static int more(struct more_file *mf) } if (count == 0) { - count = LINES - 1; + count = more_lines - 1; } more_scroll(mf, count, 1); break; @@ -464,13 +483,13 @@ static int more(struct more_file *mf) case 'b': case CTRL_B: if (count == 0) { - count = LINES - 1; + count = more_lines - 1; } more_scroll(mf, count, -1); break; case ' ': - count = count ? count : LINES - 1; + count = count ? count : more_lines - 1; /* FALLTHRU */ case 'j': case '\n': @@ -491,7 +510,7 @@ static int more(struct more_file *mf) mf = more_next(mf, 1); break; } - more_scroll(mf, count, (LINES - 1) / 2); + more_scroll(mf, count, (more_lines - 1) / 2); break; case 's': @@ -499,12 +518,12 @@ static int more(struct more_file *mf) mf = more_next(mf, 1); } count = count ? count : 1; - more_scroll(mf, LINES - 1 + count, 1); + more_scroll(mf, more_lines - 1 + count, 1); break; case 'u': case CTRL_U: - more_scroll(mf, count, -(LINES - 1) / 2); + more_scroll(mf, count, -(more_lines - 1) / 2); break; case 'G': @@ -521,7 +540,7 @@ static int more(struct more_file *mf) /* FALLTHRU */ case 'r': case CTRL_L: - wclear(more_win); + more_clear(CLEAR); more_refresh(mf); break; @@ -550,10 +569,10 @@ static int more(struct more_file *mf) break; case ':': - waddch(more_status, c); - int c2 = wgetch(more_status); - - wprintw(more_status, "\b \b"); + //waddch(more_status, c); + ; + int c2 = fgetc(more_in); + //wprintw(more_status, "\b \b"); switch (c2) { case 'e': @@ -586,11 +605,11 @@ static int more(struct more_file *mf) case '=': case CTRL_G: - wprintw(more_status, "%s; File %d/%d; Line %zd; Byte %zd/%zd; %zd%%", mf->path, 0, 0, mf->topline, mf->bytepos[mf->topline], mf->nbytes, 100 * mf->bytepos[mf->topline] / mf->nbytes); + more_status("%s; File %d/%d; Line %zd; Byte %zd/%zd; %zd%%", mf->path, 0, 0, mf->topline, mf->bytepos[mf->topline], mf->nbytes, 100 * mf->bytepos[mf->topline] / mf->nbytes); break; case 'Z': - if (wgetch(more_status) != 'Z') { + if (fgetc(more_in) != 'Z') { break; } /* FALLTHRU */ @@ -616,8 +635,6 @@ static int more(struct more_file *mf) if (!isdigit(c)) { count = 0; } - - wrefresh(more_win); } return 0; @@ -706,7 +723,7 @@ static int more_cat(const char *path, void (*loop)(FILE *)) static void more_exit(void) { - endwin(); + tcsetattr(fileno(more_in), TCSANOW, &more_term); } int main(int argc, char *argv[]) @@ -722,7 +739,7 @@ int main(int argc, char *argv[]) while ((c = getopt(argc, argv, "ceisun:p:t:")) != -1) { switch (c) { case 'c': - more_clear = 1; + more_clear(ENABLE); break; case 'e': @@ -742,7 +759,7 @@ int main(int argc, char *argv[]) break; case 'n': - setenv("LINES", optarg, 1); + more_lines = atoi(optarg); break; case 'p': @@ -767,30 +784,33 @@ int main(int argc, char *argv[]) return ret; } - if (newterm(NULL, stdout, stderr) == NULL) { - FILE *tty = fopen("/dev/tty", "r"); - if (tty == NULL) { - perror("more: couldn't open terminal"); - return 1; - } - if (newterm(NULL, stdout, tty) == NULL) { - perror("more: couldn't open terminal"); - return 1; - } + more_in = stderr; + if (1 || read(fileno(more_in), NULL, 0) == -1) { + more_in = fopen("/dev/tty", "r"); } - cbreak(); - atexit(more_exit); + setbuf(more_in, NULL); + tcgetattr(fileno(more_in), &more_term); + struct termios tinit = more_term; + tinit.c_lflag &= ~(ECHO | ICANON); + tinit.c_cc[VMIN] = 1; + tinit.c_cc[VTIME] = 0; + tcsetattr(fileno(more_in), TCSANOW, &tinit); + + if (more_in == NULL) { + perror("more: can't read commands"); + return 1; + } - more_win = newwin(LINES - 1, 0, 0, 0); - scrollok(more_win, TRUE); - more_status = newwin(1, 0, LINES - 1, 0); - touchwin(stdscr); + atexit(more_exit); - if (more_clear) { - clear(); + char *lines = getenv("LINES"); + if (lines) { + more_lines = atoi(lines); } + more_clear(CLEAR); + struct more_file *head = NULL; do { struct more_file *mf = calloc(1, sizeof(*mf)); |