diff options
Diffstat (limited to 'more.c')
-rw-r--r-- | more.c | 87 |
1 files changed, 84 insertions, 3 deletions
@@ -8,6 +8,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #include <sys/wait.h> #include <term.h> #include <unistd.h> @@ -31,9 +32,86 @@ enum { static int more(const char *); +ssize_t more_getline(struct more_file *mf, size_t lineno) +{ + if (mf->nlines <= lineno && mf->nlines != 0) { + fsetpos(mf->f, &(mf->tlines[mf->nlines - 1])); + getline(&(mf->buf), &(mf->nbuf), mf->f); + } + + while (mf->nlines <= lineno) { + mf->nlines++; + mf->tlines = realloc(mf->tlines, mf->nlines * sizeof(*mf->tlines)); + mf->bytepos = realloc(mf->bytepos, mf->nlines * sizeof(*mf->bytepos)); + + fgetpos(mf->f, &(mf->tlines[mf->nlines - 1])); + + if (getline(&(mf->buf), &(mf->nbuf), mf->f) == -1) { + return -1; + } + + if (mf->nlines > 1) { + mf->bytepos[mf->nlines - 1] = mf->bytepos[mf->nlines - 2] + strlen(mf->buf); + } else { + mf->bytepos[0] = 0; + } + + if (mf->backing != mf->f) { + fgetpos(mf->backing, &(mf->tlines[mf->nlines - 1])); + fputs(mf->buf, mf->backing); + } + } + + fsetpos(mf->backing, &(mf->tlines[lineno])); + return getline(&(mf->buf), &(mf->nbuf), mf->backing); +} + +struct more_file more_open(const char *path) +{ + struct more_file mf = { + .f = stdin, + }; + + if (strcmp(path, "-")) { + mf.f = fopen(path, "r"); + if (!mf.f) { + fprintf(stderr, "more: %s: %s\r\n", path, strerror(errno)); + return mf; + } + } + + fpos_t pos; + if (fgetpos(mf.f, &pos) != 0) { + mf.backing = tmpfile(); + } else { + mf.backing = mf.f; + struct stat st; + fstat(fileno(mf.f), &st); + mf.nbytes = st.st_size; + } + mf.path = strdup(path); + + return mf; +} + +void more_close(struct more_file *mf) +{ + if (mf->backing != mf->f) { + fclose(mf->backing); + } + + if (mf->f != stdin) { + fclose(mf->f); + } + + free(mf->tlines); + free(mf->buf); + free(mf->path); +} + static void more_refresh(struct more_file *mf) { - for (size_t i = mf->topline; i < mf->topline + LINES - 1; i++) { + for (size_t i = mf->topline; i < mf->topline + LINES; i++) { /* FIXME: account for long lines */ if (more_getline(mf, i) == -1) { @@ -60,11 +138,14 @@ static void more_scroll(struct more_file *mf, int count, int multiple) mf->topline += by; } more_refresh(mf); - } else while (by-- >= 0) { + return; + } + + while (by-- >= 0) { /* FIXME: account for long lines here, too */ mf->topline++; - if (more_getline(mf, mf->topline + LINES - 1) < 0) { + if (more_getline(mf, mf->topline + LINES) < 0) { break; } wprintw(more_win, "%s", mf->buf); |