ast@cs.vu.nl (Andy Tanenbaum) (12/22/87)
/* more - terminal pager Author: Brandon S. Allbery */ /* Pager commands: * <space> display next page * <return> scroll up 1 line * q quit */ #define reverse() write(1, "\033[7m", 4) /* reverse video */ #define normal() write(1, "\033[m", 3) /* undo reverse() */ #define clearln() write(1, "\r\033[J", 4) /* clear line */ #define LINES 23 /* lines/screen (- 1 to retain last line) */ #define COLS 80 /* columns/line */ #define TABSTOP 8 /* tabstop expansion */ #include <sgtty.h> #include <signal.h> extern int byebye(); extern char *index(); int line = 0; /* current terminal line */ int col = 0; /* current terminal column */ int fd = -1; /* terminal file descriptor (/dev/tty) */ struct sgttyb ttymode; /* and the terminal modes */ char ibuf[1024]; /* input buffer */ char obuf[1024]; /* output buffer */ int ibl = 0; /* chars in input buffer */ int ibc = 0; /* position in input buffer */ int obc = 0; /* position in output buffer (== chars in) */ int isrewind = 0; /* flag: ' command -- next input() rewind */ int isdone = 0; /* flag: return EOF next read even if not */ main(argc, argv) char **argv; { char ch; int fd, arg; signal(SIGINT, byebye); fd = 0; cbreak(); if (argc < 2) while ((ch = input(fd)) != 0) output(ch); else for (arg = 1; argv[arg] != (char *) 0; arg++) { if ((fd = open(argv[arg], 0)) == -1) { write(1, "more: cannot open ", 18); write(1, argv[arg], strlen(argv[arg])); write(1, "\n", 1); nocbreak(); exit(1); } while ((ch = input(fd)) != 0) output(ch); close(fd); if (argv[arg + 1] != (char *) 0) { oflush(); if (isdone) { /* 'n' command */ reverse(); write(1, "*** Skipping to next file ***\n", 30); normal(); isdone = 0; } reverse(); write(1, "--More-- (Next file: ", 21); write(1, argv[arg + 1], strlen(argv[arg + 1])); write(1, ")", 1); normal(); switch (wtch()) { case ' ': case '\'': case 'n': case 'N': line = 0; break; case '\r': case '\n': line = LINES - 1; break; case 'q': case 'Q': clearln(); byebye(); } clearln(); } } oflush(); byebye(); } input(fd) { if (isdone) { ibl = 0; ibc = 0; return 0; } if (isrewind) { lseek(fd, 0L, 0); ibl = 0; ibc = 0; isrewind = 0; } if (ibc == ibl) { ibc = 0; if ((ibl = read(fd, ibuf, sizeof ibuf)) <= 0) return 0; } return ibuf[ibc++]; } output(c) char c; { if (obc == sizeof obuf) { lwrite(1, obuf, sizeof obuf); obc = 0; } if (!isrewind) obuf[obc++] = c; } oflush() { if (!isdone) lwrite(1, obuf, obc); obc = 0; } lwrite(fd, buf, len) char *buf; unsigned len; { unsigned here, start; char cmd; start = 0; here = 0; while (here != len) { cmd = '\0'; switch (buf[here++]) { case '\n': col = 0; if (++line == LINES) { write(fd, buf + start, here - start); reverse(); write(1, "--More--", 8); normal(); cmd = wtch(); clearln(); line = 0; start = here; } break; case '\r': col = 0; break; case '\b': if (col != 0) col--; else { line--; col = COLS - 1; } break; case '\t': do { col++; } while (col % TABSTOP != 0); break; default: if (++col == COLS) { col = 0; if (++line == LINES) { write(fd, buf + start, here - start); reverse(); write(1, "--More--", 8); normal(); cmd = wtch(); clearln(); line = 0; start = here; } } } switch (cmd) { case '\0': break; case ' ': line = 0; break; case '\r': case '\n': line = LINES - 1; break; case 'q': case 'Q': byebye(); case '\'': isrewind = 1; reverse(); write(1, "*** Back ***\n", 13); normal(); return; case 'n': case 'N': isdone = 1; return; default: break; } } if (here != start) write(fd, buf + start, here - start); } wtch() { char ch; do { read(fd, &ch, 1); } while (index(" \r\nqQ'nN", ch) == (char *) 0); return ch; } cbreak() { if (fd != -1) return; if ((fd = open("/dev/tty", 0)) == -1) { write(2, "OOPS -- can't open /dev/tty\n", 28); exit(1); } ioctl(fd, TIOCGETP, &ttymode); ttymode.sg_flags |= CBREAK; ttymode.sg_flags &= ~ECHO; ioctl(fd, TIOCSETP, &ttymode); /* NB: add TIOCSETN! */ } nocbreak() { if (fd == -1) return; ttymode.sg_flags &= ~CBREAK; ttymode.sg_flags |= ECHO; ioctl(fd, TIOCSETP, &ttymode); close(fd); fd = -1; } byebye() { nocbreak(); exit(0); }