summaryrefslogtreecommitdiff
path: root/more.c
diff options
context:
space:
mode:
Diffstat (limited to 'more.c')
-rw-r--r--more.c87
1 files changed, 84 insertions, 3 deletions
diff --git a/more.c b/more.c
index 0894e75..8028263 100644
--- a/more.c
+++ b/more.c
@@ -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);